Fix cloning of raw, sparse volumes

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>
This commit is contained in:
Prerna Saxena 2015-06-26 17:13:26 +05:30 committed by Ján Tomko
parent e30297b096
commit dd519a294b
2 changed files with 14 additions and 14 deletions

View File

@ -342,7 +342,7 @@ virStorageBackendCreateBlockFrom(virConnectPtr conn ATTRIBUTE_UNUSED,
goto cleanup; goto cleanup;
} }
remain = vol->target.allocation; remain = vol->target.capacity;
if (inputvol) { if (inputvol) {
int res = virStorageBackendCopyToFD(vol, inputvol, int res = virStorageBackendCopyToFD(vol, inputvol,
@ -401,6 +401,12 @@ createRawFile(int fd, virStorageVolDefPtr vol,
int ret = 0; int ret = 0;
unsigned long long pos = 0; unsigned long long pos = 0;
/* If the new allocation is lower than the capacity of the original 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 /* Seek to the final size, so the capacity is available upfront
* for progress reporting */ * for progress reporting */
if (ftruncate(fd, vol->target.capacity) < 0) { 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 * to writing zeroes block by block in case fallocate isn't
* available, and since we're going to copy data from another * available, and since we're going to copy data from another
* file it doesn't make sense to write the file twice. */ * 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) { if (fallocate(fd, 0, 0, vol->target.allocation) == 0) {
need_alloc = false; need_alloc = false;
} else if (errno != ENOSYS && errno != EOPNOTSUPP) { } else if (errno != ENOSYS && errno != EOPNOTSUPP) {
@ -433,21 +439,20 @@ createRawFile(int fd, virStorageVolDefPtr vol,
} }
#endif #endif
if (inputvol) { 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 /* allow zero blocks to be skipped if we've requested sparse
* allocation (allocation < capacity) or we have already * allocation (allocation < capacity) or we have already
* been able to allocate the required space. */ * been able to allocate the required space. */
bool want_sparse = !need_alloc ||
(vol->target.allocation < inputvol->target.capacity);
ret = virStorageBackendCopyToFD(vol, inputvol, fd, &remain, ret = virStorageBackendCopyToFD(vol, inputvol, fd, &remain,
want_sparse, reflink_copy); !need_alloc, reflink_copy);
if (ret < 0) if (ret < 0)
goto cleanup; 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) { if (need_alloc) {

View File

@ -1978,11 +1978,6 @@ storageVolCreateXMLFrom(virStoragePoolPtr obj,
if (newvol->target.capacity < origvol->target.capacity) if (newvol->target.capacity < origvol->target.capacity)
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) { if (!backend->buildVolFrom) {
virReportError(VIR_ERR_NO_SUPPORT, virReportError(VIR_ERR_NO_SUPPORT,
"%s", _("storage pool does not support" "%s", _("storage pool does not support"