[libvirt] [PATCHv4 0/2] Fix cloning of sparse raw volumes

v3: https://www.redhat.com/archives/libvir-list/2015-June/msg01422.html v4: * introduces a new no-op patch changing the calculation of remaining allocation * allows partial allocation of new volumes on systems without fallocate Ján Tomko (1): Rewrite allocation tracking when cloning volumes Prerna Saxena (1): Fix cloning of raw, sparse volumes src/storage/storage_backend.c | 29 ++++++++++++++++++----------- src/storage/storage_driver.c | 5 ----- 2 files changed, 18 insertions(+), 16 deletions(-) -- 2.3.6

Instead of storing the remaining bytes, store the position of the first unallocated byte. This will allow changing the amount of bytes copied by virStorageBackendCopyToFD without changing the safezero call. No functional impact. --- src/storage/storage_backend.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c index ce59f63..c71545c 100644 --- a/src/storage/storage_backend.c +++ b/src/storage/storage_backend.c @@ -399,7 +399,7 @@ createRawFile(int fd, virStorageVolDefPtr vol, { bool need_alloc = true; int ret = 0; - unsigned long long remain; + unsigned long long pos = 0; /* Seek to the final size, so the capacity is available upfront * for progress reporting */ @@ -433,9 +433,9 @@ createRawFile(int fd, virStorageVolDefPtr vol, } #endif - remain = vol->target.allocation; if (inputvol) { + unsigned long long remain = vol->target.allocation; /* allow zero blocks to be skipped if we've requested sparse * allocation (allocation < capacity) or we have already * been able to allocate the required space. */ @@ -446,10 +446,12 @@ createRawFile(int fd, virStorageVolDefPtr vol, want_sparse, reflink_copy); if (ret < 0) goto cleanup; + + pos = vol->target.allocation - remain; } - if (remain && need_alloc) { - if (safezero(fd, vol->target.allocation - remain, remain) < 0) { + if (need_alloc) { + if (safezero(fd, pos, vol->target.allocation - pos) < 0) { ret = -errno; virReportSystemError(errno, _("cannot fill file '%s'"), vol->target.path); -- 2.3.6

From: Prerna Saxena <prerna@linux.vnet.ibm.com> When virsh vol-clone is attempted on a raw file where capacity > allocation, the resulting cloned volume has a size that matches the virtual-size of the parent; in place of matching its actual, disk size. This patch fixes the cloned disk to have same _allocated_size_ as the parent file from which it was cloned. Ref: http://www.redhat.com/archives/libvir-list/2015-May/msg00050.html Also fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1130739 Signed-off-by: Prerna Saxena <prerna@linux.vnet.ibm.com> Signed-off-by: Ján Tomko <jtomko@redhat.com> --- src/storage/storage_backend.c | 23 ++++++++++++++--------- src/storage/storage_driver.c | 5 ----- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c index c71545c..bab81e3 100644 --- a/src/storage/storage_backend.c +++ b/src/storage/storage_backend.c @@ -342,7 +342,7 @@ virStorageBackendCreateBlockFrom(virConnectPtr conn ATTRIBUTE_UNUSED, goto cleanup; } - remain = vol->target.allocation; + remain = vol->target.capacity; if (inputvol) { int res = virStorageBackendCopyToFD(vol, inputvol, @@ -401,6 +401,12 @@ createRawFile(int fd, virStorageVolDefPtr vol, int ret = 0; unsigned long long pos = 0; + /* If the new allocation is lower than the capacity of the orignal file, + * the cloned volume will be sparse */ + if (inputvol && + vol->target.allocation < inputvol->target.capacity) + need_alloc = false; + /* Seek to the final size, so the capacity is available upfront * for progress reporting */ if (ftruncate(fd, vol->target.capacity) < 0) { @@ -420,7 +426,7 @@ createRawFile(int fd, virStorageVolDefPtr vol, * to writing zeroes block by block in case fallocate isn't * available, and since we're going to copy data from another * file it doesn't make sense to write the file twice. */ - if (vol->target.allocation) { + if (vol->target.allocation && need_alloc) { if (fallocate(fd, 0, 0, vol->target.allocation) == 0) { need_alloc = false; } else if (errno != ENOSYS && errno != EOPNOTSUPP) { @@ -433,21 +439,20 @@ createRawFile(int fd, virStorageVolDefPtr vol, } #endif - if (inputvol) { - unsigned long long remain = vol->target.allocation; + unsigned long long remain = inputvol->target.capacity; /* allow zero blocks to be skipped if we've requested sparse * allocation (allocation < capacity) or we have already * been able to allocate the required space. */ - bool want_sparse = !need_alloc || - (vol->target.allocation < inputvol->target.capacity); - ret = virStorageBackendCopyToFD(vol, inputvol, fd, &remain, - want_sparse, reflink_copy); + !need_alloc, reflink_copy); if (ret < 0) goto cleanup; - pos = vol->target.allocation - remain; + /* If the new allocation is greater than the original capacity, + * but fallocate failed, fill the rest with zeroes. + */ + pos = inputvol->target.capacity - remain; } if (need_alloc) { diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index e600514..ba27acf 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -1975,11 +1975,6 @@ storageVolCreateXMLFrom(virStoragePoolPtr obj, if (newvol->target.capacity < origvol->target.capacity) newvol->target.capacity = origvol->target.capacity; - /* Make sure allocation is at least as large as the destination cap, - * to make absolutely sure we copy all possible contents */ - if (newvol->target.allocation < origvol->target.capacity) - newvol->target.allocation = origvol->target.capacity; - if (!backend->buildVolFrom) { virReportError(VIR_ERR_NO_SUPPORT, "%s", _("storage pool does not support" -- 2.3.6

On 07/03/2015 09:54 AM, Ján Tomko wrote:
From: Prerna Saxena <prerna@linux.vnet.ibm.com>
When virsh vol-clone is attempted on a raw file where capacity > allocation, the resulting cloned volume has a size that matches the virtual-size of the parent; in place of matching its actual, disk size. This patch fixes the cloned disk to have same _allocated_size_ as the parent file from which it was cloned.
Ref: http://www.redhat.com/archives/libvir-list/2015-May/msg00050.html
Also fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1130739
Signed-off-by: Prerna Saxena <prerna@linux.vnet.ibm.com> Signed-off-by: Ján Tomko <jtomko@redhat.com> --- src/storage/storage_backend.c | 23 ++++++++++++++--------- src/storage/storage_driver.c | 5 ----- 2 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c index c71545c..bab81e3 100644 --- a/src/storage/storage_backend.c +++ b/src/storage/storage_backend.c @@ -342,7 +342,7 @@ virStorageBackendCreateBlockFrom(virConnectPtr conn ATTRIBUTE_UNUSED, goto cleanup; }
- remain = vol->target.allocation; + remain = vol->target.capacity;
if (inputvol) { int res = virStorageBackendCopyToFD(vol, inputvol, @@ -401,6 +401,12 @@ createRawFile(int fd, virStorageVolDefPtr vol, int ret = 0; unsigned long long pos = 0;
+ /* If the new allocation is lower than the capacity of the orignal file,
s/orignal/original ACK series John
+ * the cloned volume will be sparse */ + if (inputvol && + vol->target.allocation < inputvol->target.capacity) + need_alloc = false; + /* Seek to the final size, so the capacity is available upfront * for progress reporting */ if (ftruncate(fd, vol->target.capacity) < 0) { @@ -420,7 +426,7 @@ createRawFile(int fd, virStorageVolDefPtr vol, * to writing zeroes block by block in case fallocate isn't * available, and since we're going to copy data from another * file it doesn't make sense to write the file twice. */ - if (vol->target.allocation) { + if (vol->target.allocation && need_alloc) { if (fallocate(fd, 0, 0, vol->target.allocation) == 0) { need_alloc = false; } else if (errno != ENOSYS && errno != EOPNOTSUPP) { @@ -433,21 +439,20 @@ createRawFile(int fd, virStorageVolDefPtr vol, } #endif
- if (inputvol) { - unsigned long long remain = vol->target.allocation; + unsigned long long remain = inputvol->target.capacity; /* allow zero blocks to be skipped if we've requested sparse * allocation (allocation < capacity) or we have already * been able to allocate the required space. */ - bool want_sparse = !need_alloc || - (vol->target.allocation < inputvol->target.capacity); - ret = virStorageBackendCopyToFD(vol, inputvol, fd, &remain, - want_sparse, reflink_copy); + !need_alloc, reflink_copy); if (ret < 0) goto cleanup;
- pos = vol->target.allocation - remain; + /* If the new allocation is greater than the original capacity, + * but fallocate failed, fill the rest with zeroes. + */ + pos = inputvol->target.capacity - remain; }
if (need_alloc) { diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index e600514..ba27acf 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -1975,11 +1975,6 @@ storageVolCreateXMLFrom(virStoragePoolPtr obj, if (newvol->target.capacity < origvol->target.capacity) newvol->target.capacity = origvol->target.capacity;
- /* Make sure allocation is at least as large as the destination cap, - * to make absolutely sure we copy all possible contents */ - if (newvol->target.allocation < origvol->target.capacity) - newvol->target.allocation = origvol->target.capacity; - if (!backend->buildVolFrom) { virReportError(VIR_ERR_NO_SUPPORT, "%s", _("storage pool does not support"
participants (2)
-
John Ferlan
-
Ján Tomko