[libvirt] [PATCH 0/3] Support --allocate and --shrink for vol-resize

https://bugzilla.redhat.com/show_bug.cgi?id=804516 Though the bug's title is about the document, but I prefer to implement it instead of changing document. Those two flags were added long time ago, but never implemented, it's not good to say they are not supported now while they were already exposed outside. A few examples of vol-resize with the patches: 1) Create 5M a parse vol % dd of=/var/lib/libvirt/images/sparse.raw bs=1k seek=5120 count=0 0+0 records in 0+0 records out 0 bytes (0 B) copied, 7.904e-06 s, 0.0 kB/s % ./tools/virsh pool-refresh default Pool default refreshed %s ./tools/virsh vol-info /var/lib/libvirt/images/sparse.raw Name: sparse.raw Type: file Capacity: 5.00 MiB Allocation: 0.00 B 2) Resize the vol to 6M with --allocate, I.E. The capacity (5M - 6M) is preallocated. % ./tools/virsh vol-resize /var/lib/libvirt/images/sparse.raw 6M --allocate Size of volume 'sparse.raw' successfully changed to 6M % ./tools/virsh vol-info /var/lib/libvirt/images/sparse.raw Name: sparse.raw Type: file Capacity: 6.00 MiB Allocation: 1.00 MiB 3) Resize the vol to 7M without --allocate. I.E. The new 1M capacity (6M - 7M) is sparse. % ./tools/virsh vol-resize /var/lib/libvirt/images/sparse.raw 7M Size of volume 'sparse.raw' successfully changed to 7M %s ./tools/virsh vol-info /var/lib/libvirt/images/sparse.raw Name: sparse.raw Type: file Capacity: 7.00 MiB Allocation: 1.00 MiB 3) Resize the vol to 8M with --allocate, I.E. The new 1 M capacity (7M - 8M) is preallocated % ./tools/virsh vol-resize /var/lib/libvirt/images/sparse.raw 8M --allocate Size of volume 'sparse.raw' successfully changed to 8M % ./tools/virsh vol-info /var/lib/libvirt/images/sparse.raw Name: sparse.raw Type: file Capacity: 8.00 MiB Allocation: 2.00 MiB ====== Now the parse file's allocation is like: 0 5 6 7 8 ----------------------------------------------------------------- | zero | allocated | zero | allocated | ----------------------------------------------------------------- %s ./tools/virsh vol-resize /var/lib/libvirt/images/sparse.raw 6M --shrink Size of volume 'sparse.raw' successfully changed to 6M %s ./tools/virsh vol-info /var/lib/libvirt/images/sparse.raw Name: sparse.raw Type: file Capacity: 6.00 MiB Allocation: 1.00 MiB ===== The vol still get 1M preallocate space kept, expected. Osier Yang (3): storage: Support preallocate the new capacity for vol-resize storage: Forbid to shrink the vol's capacity if no --shrink is specified storage: Allow --shrink for raw type volume of fs pool src/storage/storage_backend_fs.c | 22 ++++++++++++++++++---- src/storage/storage_driver.c | 12 +++++++++++- src/util/virstoragefile.c | 39 ++++++++++++++++++++++++++++++++++++--- src/util/virstoragefile.h | 6 +++++- 4 files changed, 70 insertions(+), 9 deletions(-) -- 1.8.1.4

The document for "vol-resize" says the new capacity will be sparse unless "--allocate" is specified, however, the "--allocate" flag is never implemented. This implements the "--allocate" flag for fs backend's raw type volume, based on posix_fallocate and the syscall SYS_fallocate. --- src/storage/storage_backend_fs.c | 19 +++++++++++++++---- src/storage/storage_driver.c | 3 ++- src/util/virstoragefile.c | 38 +++++++++++++++++++++++++++++++++++--- src/util/virstoragefile.h | 5 ++++- 4 files changed, 56 insertions(+), 9 deletions(-) diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index 1379f17..78f5d53 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -1245,13 +1245,24 @@ virStorageBackendFileSystemVolResize(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long long capacity, unsigned int flags) { - virCheckFlags(0, -1); + virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE, -1); + + bool pre_allocate = flags & VIR_STORAGE_VOL_RESIZE_ALLOCATE; + + if (vol->target.format == VIR_STORAGE_FILE_RAW) { + return virStorageFileResize(vol->target.path, capacity, + vol->capacity, pre_allocate); + } else { + if (pre_allocate) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("preallocate is only supported for raw " + "type volume")); + return -1; + } - if (vol->target.format == VIR_STORAGE_FILE_RAW) - return virStorageFileResize(vol->target.path, capacity); - else return virStorageBackendFilesystemResizeQemuImg(vol->target.path, capacity); + } } virStorageBackend virStorageBackendDirectory = { diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index a2b0c21..e7516eb 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -1761,7 +1761,8 @@ storageVolResize(virStorageVolPtr obj, unsigned long long abs_capacity; int ret = -1; - virCheckFlags(VIR_STORAGE_VOL_RESIZE_DELTA, -1); + virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE | + VIR_STORAGE_VOL_RESIZE_DELTA, -1); storageDriverLock(driver); pool = virStoragePoolObjFindByName(&driver->pools, obj->pool); diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index f0e9114..e42eb77 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -45,6 +45,9 @@ #include "virendian.h" #include "virstring.h" #include "virutil.h" +#if HAVE_SYS_SYSCALL_H +# include <sys/syscall.h> +#endif #define VIR_FROM_THIS VIR_FROM_STORAGE @@ -1038,19 +1041,48 @@ virStorageFileFreeMetadata(virStorageFileMetadata *meta) * Change the capacity of the raw storage file at 'path'. */ int -virStorageFileResize(const char *path, unsigned long long capacity) +virStorageFileResize(const char *path, + unsigned long long capacity, + unsigned long long orig_capacity, + bool pre_allocate) { int fd = -1; int ret = -1; + int rc; + off_t offset = orig_capacity; + off_t len = capacity - orig_capacity; if ((fd = open(path, O_RDWR)) < 0) { virReportSystemError(errno, _("Unable to open '%s'"), path); goto cleanup; } - if (ftruncate(fd, capacity) < 0) { - virReportSystemError(errno, _("Failed to truncate file '%s'"), path); + if (pre_allocate) { +#if HAVE_POSIX_FALLOCATE + if ((rc = posix_fallocate(fd, offset, len)) != 0) { + virReportSystemError(rc, + _("Failed to pre-allocate space for " + "file '%s'"), path); + goto cleanup; + } +#elif HAVE_SYS_SYSCALL_H && defined(SYS_fallocate) + if (syscall(SYS_fallocate, fd, 0, offset, len) != 0) { + virReportSystemError(errno, + _("Failed to preallocate space for " + "file 'path'"), path); + goto cleanup; + } +#else + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("preallocate is not supported on this platform")) goto cleanup; +#endif + } else { + if (ftruncate(fd, capacity) < 0) { + virReportSystemError(errno, + _("Failed to truncate file '%s'"), path); + goto cleanup; + } } if (VIR_CLOSE(fd) < 0) { diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h index ffe7a54..c195c9a 100644 --- a/src/util/virstoragefile.h +++ b/src/util/virstoragefile.h @@ -89,7 +89,10 @@ const char *virStorageFileChainLookup(virStorageFileMetadataPtr chain, void virStorageFileFreeMetadata(virStorageFileMetadataPtr meta); -int virStorageFileResize(const char *path, unsigned long long capacity); +int virStorageFileResize(const char *path, + unsigned long long capacity, + unsigned long long orig_capacity, + bool pre_allocate); enum { VIR_STORAGE_FILE_SHFS_NFS = (1 << 0), -- 1.8.1.4

On 31.05.2013 07:16, Osier Yang wrote:
The document for "vol-resize" says the new capacity will be sparse unless "--allocate" is specified, however, the "--allocate" flag is never implemented. This implements the "--allocate" flag for fs backend's raw type volume, based on posix_fallocate and the syscall SYS_fallocate. --- src/storage/storage_backend_fs.c | 19 +++++++++++++++---- src/storage/storage_driver.c | 3 ++- src/util/virstoragefile.c | 38 +++++++++++++++++++++++++++++++++++--- src/util/virstoragefile.h | 5 ++++- 4 files changed, 56 insertions(+), 9 deletions(-)
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index 1379f17..78f5d53 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -1245,13 +1245,24 @@ virStorageBackendFileSystemVolResize(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long long capacity, unsigned int flags) { - virCheckFlags(0, -1); + virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE, -1); + + bool pre_allocate = flags & VIR_STORAGE_VOL_RESIZE_ALLOCATE; + + if (vol->target.format == VIR_STORAGE_FILE_RAW) { + return virStorageFileResize(vol->target.path, capacity, + vol->capacity, pre_allocate); + } else { + if (pre_allocate) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("preallocate is only supported for raw " + "type volume")); + return -1; + }
- if (vol->target.format == VIR_STORAGE_FILE_RAW) - return virStorageFileResize(vol->target.path, capacity); - else return virStorageBackendFilesystemResizeQemuImg(vol->target.path, capacity); + } }
virStorageBackend virStorageBackendDirectory = { diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index a2b0c21..e7516eb 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -1761,7 +1761,8 @@ storageVolResize(virStorageVolPtr obj, unsigned long long abs_capacity; int ret = -1;
- virCheckFlags(VIR_STORAGE_VOL_RESIZE_DELTA, -1); + virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE | + VIR_STORAGE_VOL_RESIZE_DELTA, -1);
storageDriverLock(driver); pool = virStoragePoolObjFindByName(&driver->pools, obj->pool); diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index f0e9114..e42eb77 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -45,6 +45,9 @@ #include "virendian.h" #include "virstring.h" #include "virutil.h" +#if HAVE_SYS_SYSCALL_H +# include <sys/syscall.h> +#endif
#define VIR_FROM_THIS VIR_FROM_STORAGE
@@ -1038,19 +1041,48 @@ virStorageFileFreeMetadata(virStorageFileMetadata *meta) * Change the capacity of the raw storage file at 'path'. */ int -virStorageFileResize(const char *path, unsigned long long capacity) +virStorageFileResize(const char *path, + unsigned long long capacity, + unsigned long long orig_capacity, + bool pre_allocate) { int fd = -1; int ret = -1; + int rc; + off_t offset = orig_capacity; + off_t len = capacity - orig_capacity;
if ((fd = open(path, O_RDWR)) < 0) { virReportSystemError(errno, _("Unable to open '%s'"), path); goto cleanup; }
- if (ftruncate(fd, capacity) < 0) { - virReportSystemError(errno, _("Failed to truncate file '%s'"), path); + if (pre_allocate) { +#if HAVE_POSIX_FALLOCATE + if ((rc = posix_fallocate(fd, offset, len)) != 0) { + virReportSystemError(rc, + _("Failed to pre-allocate space for " + "file '%s'"), path); + goto cleanup; + } +#elif HAVE_SYS_SYSCALL_H && defined(SYS_fallocate) + if (syscall(SYS_fallocate, fd, 0, offset, len) != 0) { + virReportSystemError(errno, + _("Failed to preallocate space for " + "file 'path'"), path);
fails synax-check. s/path/%s/
+ goto cleanup; + } +#else + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("preallocate is not supported on this platform")) goto cleanup; +#endif + } else { + if (ftruncate(fd, capacity) < 0) { + virReportSystemError(errno, + _("Failed to truncate file '%s'"), path); + goto cleanup; + } }
if (VIR_CLOSE(fd) < 0) { diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h index ffe7a54..c195c9a 100644 --- a/src/util/virstoragefile.h +++ b/src/util/virstoragefile.h @@ -89,7 +89,10 @@ const char *virStorageFileChainLookup(virStorageFileMetadataPtr chain,
void virStorageFileFreeMetadata(virStorageFileMetadataPtr meta);
-int virStorageFileResize(const char *path, unsigned long long capacity); +int virStorageFileResize(const char *path, + unsigned long long capacity, + unsigned long long orig_capacity, + bool pre_allocate);
enum { VIR_STORAGE_FILE_SHFS_NFS = (1 << 0),
ACK Michal

As the document for "virsh-resize" says: <...> Attempts to shrink the volume will fail unless I<--shrink> is present; </...> This makes sense as it at least prevent the user shrinking the important data of volume without a notice. --- src/storage/storage_driver.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index e7516eb..858aeca 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -1762,7 +1762,8 @@ storageVolResize(virStorageVolPtr obj, int ret = -1; virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE | - VIR_STORAGE_VOL_RESIZE_DELTA, -1); + VIR_STORAGE_VOL_RESIZE_DELTA | + VIR_STORAGE_VOL_RESIZE_SHRINK, -1); storageDriverLock(driver); pool = virStoragePoolObjFindByName(&driver->pools, obj->pool); @@ -1814,6 +1815,14 @@ storageVolResize(virStorageVolPtr obj, goto out; } + if (abs_capacity < vol->capacity && + !(flags & VIR_STORAGE_VOL_RESIZE_SHRINK)) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("Can't shrink capacity below current " + "capacity with shrink flag explicitly specified")); + goto out; + } + if (abs_capacity > vol->capacity + pool->def->available) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("Not enough space left on storage pool")); -- 1.8.1.4

On 31.05.2013 07:16, Osier Yang wrote:
As the document for "virsh-resize" says: <...> Attempts to shrink the volume will fail unless I<--shrink> is present; </...>
This makes sense as it at least prevent the user shrinking the important data of volume without a notice. --- src/storage/storage_driver.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index e7516eb..858aeca 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -1762,7 +1762,8 @@ storageVolResize(virStorageVolPtr obj, int ret = -1;
virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE | - VIR_STORAGE_VOL_RESIZE_DELTA, -1); + VIR_STORAGE_VOL_RESIZE_DELTA | + VIR_STORAGE_VOL_RESIZE_SHRINK, -1);
storageDriverLock(driver); pool = virStoragePoolObjFindByName(&driver->pools, obj->pool); @@ -1814,6 +1815,14 @@ storageVolResize(virStorageVolPtr obj, goto out; }
+ if (abs_capacity < vol->capacity && + !(flags & VIR_STORAGE_VOL_RESIZE_SHRINK)) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("Can't shrink capacity below current " + "capacity with shrink flag explicitly specified")); + goto out; + } + if (abs_capacity > vol->capacity + pool->def->available) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("Not enough space left on storage pool"));
ACK Michal

There is no need to use posix_fallocate or SYS_fallocate to shrink the volume, ftruncate can do the work. qemu-img/kvm-img supports to shrink the volume itself. --- src/storage/storage_backend_fs.c | 7 +++++-- src/util/virstoragefile.c | 5 +++-- src/util/virstoragefile.h | 3 ++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index 78f5d53..cdfa66f 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -1245,13 +1245,16 @@ virStorageBackendFileSystemVolResize(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long long capacity, unsigned int flags) { - virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE, -1); + virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE | + VIR_STORAGE_VOL_RESIZE_SHRINK, -1); bool pre_allocate = flags & VIR_STORAGE_VOL_RESIZE_ALLOCATE; + bool shrink = flags & VIR_STORAGE_VOL_RESIZE_SHRINK; if (vol->target.format == VIR_STORAGE_FILE_RAW) { return virStorageFileResize(vol->target.path, capacity, - vol->capacity, pre_allocate); + vol->capacity, pre_allocate, + shrink); } else { if (pre_allocate) { virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index e42eb77..25614df 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -1044,7 +1044,8 @@ int virStorageFileResize(const char *path, unsigned long long capacity, unsigned long long orig_capacity, - bool pre_allocate) + bool pre_allocate, + bool shrink) { int fd = -1; int ret = -1; @@ -1057,7 +1058,7 @@ virStorageFileResize(const char *path, goto cleanup; } - if (pre_allocate) { + if (pre_allocate && !shrink) { #if HAVE_POSIX_FALLOCATE if ((rc = posix_fallocate(fd, offset, len)) != 0) { virReportSystemError(rc, diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h index c195c9a..46fe9ba 100644 --- a/src/util/virstoragefile.h +++ b/src/util/virstoragefile.h @@ -92,7 +92,8 @@ void virStorageFileFreeMetadata(virStorageFileMetadataPtr meta); int virStorageFileResize(const char *path, unsigned long long capacity, unsigned long long orig_capacity, - bool pre_allocate); + bool pre_allocate, + bool shrink); enum { VIR_STORAGE_FILE_SHFS_NFS = (1 << 0), -- 1.8.1.4

On 31.05.2013 07:16, Osier Yang wrote:
There is no need to use posix_fallocate or SYS_fallocate to shrink the volume, ftruncate can do the work. qemu-img/kvm-img supports to shrink the volume itself. --- src/storage/storage_backend_fs.c | 7 +++++-- src/util/virstoragefile.c | 5 +++-- src/util/virstoragefile.h | 3 ++- 3 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index 78f5d53..cdfa66f 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -1245,13 +1245,16 @@ virStorageBackendFileSystemVolResize(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long long capacity, unsigned int flags) { - virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE, -1); + virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE | + VIR_STORAGE_VOL_RESIZE_SHRINK, -1);
bool pre_allocate = flags & VIR_STORAGE_VOL_RESIZE_ALLOCATE; + bool shrink = flags & VIR_STORAGE_VOL_RESIZE_SHRINK;
if (vol->target.format == VIR_STORAGE_FILE_RAW) { return virStorageFileResize(vol->target.path, capacity, - vol->capacity, pre_allocate); + vol->capacity, pre_allocate, + shrink); } else { if (pre_allocate) { virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index e42eb77..25614df 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -1044,7 +1044,8 @@ int virStorageFileResize(const char *path, unsigned long long capacity, unsigned long long orig_capacity, - bool pre_allocate) + bool pre_allocate, + bool shrink) { int fd = -1; int ret = -1; @@ -1057,7 +1058,7 @@ virStorageFileResize(const char *path, goto cleanup; }
- if (pre_allocate) { + if (pre_allocate && !shrink) { #if HAVE_POSIX_FALLOCATE if ((rc = posix_fallocate(fd, offset, len)) != 0) { virReportSystemError(rc, diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h index c195c9a..46fe9ba 100644 --- a/src/util/virstoragefile.h +++ b/src/util/virstoragefile.h @@ -92,7 +92,8 @@ void virStorageFileFreeMetadata(virStorageFileMetadataPtr meta); int virStorageFileResize(const char *path, unsigned long long capacity, unsigned long long orig_capacity, - bool pre_allocate); + bool pre_allocate, + bool shrink);
Having two booleans is doable. But if we ever introduce yet another boolean argument, we should turn them into @flags then. Moreover, @shrink looks orthogonal to @pre_allocate to me. Aren't they?
enum { VIR_STORAGE_FILE_SHFS_NFS = (1 << 0),

On 04/06/13 23:19, Michal Privoznik wrote:
On 31.05.2013 07:16, Osier Yang wrote:
There is no need to use posix_fallocate or SYS_fallocate to shrink the volume, ftruncate can do the work. qemu-img/kvm-img supports to shrink the volume itself. --- src/storage/storage_backend_fs.c | 7 +++++-- src/util/virstoragefile.c | 5 +++-- src/util/virstoragefile.h | 3 ++- 3 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index 78f5d53..cdfa66f 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -1245,13 +1245,16 @@ virStorageBackendFileSystemVolResize(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long long capacity, unsigned int flags) { - virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE, -1); + virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE | + VIR_STORAGE_VOL_RESIZE_SHRINK, -1);
bool pre_allocate = flags & VIR_STORAGE_VOL_RESIZE_ALLOCATE; + bool shrink = flags & VIR_STORAGE_VOL_RESIZE_SHRINK;
if (vol->target.format == VIR_STORAGE_FILE_RAW) { return virStorageFileResize(vol->target.path, capacity, - vol->capacity, pre_allocate); + vol->capacity, pre_allocate, + shrink); } else { if (pre_allocate) { virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index e42eb77..25614df 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -1044,7 +1044,8 @@ int virStorageFileResize(const char *path, unsigned long long capacity, unsigned long long orig_capacity, - bool pre_allocate) + bool pre_allocate, + bool shrink) { int fd = -1; int ret = -1; @@ -1057,7 +1058,7 @@ virStorageFileResize(const char *path, goto cleanup; }
- if (pre_allocate) { + if (pre_allocate && !shrink) { #if HAVE_POSIX_FALLOCATE if ((rc = posix_fallocate(fd, offset, len)) != 0) { virReportSystemError(rc, diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h index c195c9a..46fe9ba 100644 --- a/src/util/virstoragefile.h +++ b/src/util/virstoragefile.h @@ -92,7 +92,8 @@ void virStorageFileFreeMetadata(virStorageFileMetadataPtr meta); int virStorageFileResize(const char *path, unsigned long long capacity, unsigned long long orig_capacity, - bool pre_allocate); + bool pre_allocate, + bool shrink); Having two booleans is doable. But if we ever introduce yet another boolean argument, we should turn them into @flags then. Moreover, @shrink looks orthogonal to @pre_allocate to me. Aren't they?
Flags is nicer, and they are orthogonal, v2 is posted, and I have pushed 1/3 and 2/3, thanks. Osier

There is no need to use posix_fallocate or SYS_fallocate to shrink the volume, ftruncate can do the work. qemu-img/kvm-img supports to shrink the volume itself. And instead of bool arguments, this introduces virStorageFileResizeFlags enum. --- src/storage/storage_backend_fs.c | 18 ++++++++++++++---- src/util/virstoragefile.c | 5 +++-- src/util/virstoragefile.h | 7 ++++++- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index b1efa50..e55148c 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -1246,15 +1246,25 @@ virStorageBackendFileSystemVolResize(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long long capacity, unsigned int flags) { - virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE, -1); + unsigned int resize_flags = 0; + bool preallocate = false; - bool pre_allocate = flags & VIR_STORAGE_VOL_RESIZE_ALLOCATE; + virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE | + VIR_STORAGE_VOL_RESIZE_SHRINK, -1); + + if (flags & VIR_STORAGE_VOL_RESIZE_ALLOCATE) { + resize_flags |= VIR_STORAGE_FILE_RESIZE_PREALLOCATE; + preallocate = true; + } + + if (flags & VIR_STORAGE_VOL_RESIZE_SHRINK) + resize_flags |= VIR_STORAGE_FILE_RESIZE_SHRINK; if (vol->target.format == VIR_STORAGE_FILE_RAW) { return virStorageFileResize(vol->target.path, capacity, - vol->capacity, pre_allocate); + vol->capacity, resize_flags); } else { - if (pre_allocate) { + if (preallocate) { virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", _("preallocate is only supported for raw " "type volume")); diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index bf668c8..9e085d4 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -1044,7 +1044,7 @@ int virStorageFileResize(const char *path, unsigned long long capacity, unsigned long long orig_capacity, - bool pre_allocate) + unsigned int flags) { int fd = -1; int ret = -1; @@ -1057,7 +1057,8 @@ virStorageFileResize(const char *path, goto cleanup; } - if (pre_allocate) { + if (flags & VIR_STORAGE_FILE_RESIZE_PREALLOCATE && + !(flags & VIR_STORAGE_FILE_RESIZE_SHRINK)) { #if HAVE_POSIX_FALLOCATE if ((rc = posix_fallocate(fd, offset, len)) != 0) { virReportSystemError(rc, diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h index c195c9a..1cf90ce 100644 --- a/src/util/virstoragefile.h +++ b/src/util/virstoragefile.h @@ -89,10 +89,15 @@ const char *virStorageFileChainLookup(virStorageFileMetadataPtr chain, void virStorageFileFreeMetadata(virStorageFileMetadataPtr meta); +enum { + VIR_STORAGE_FILE_RESIZE_PREALLOCATE = 1 << 0, + VIR_STORAGE_FILE_RESIZE_SHRINK = 1 << 1, +} virStorageFileResizeFlags; + int virStorageFileResize(const char *path, unsigned long long capacity, unsigned long long orig_capacity, - bool pre_allocate); + unsigned int flags); enum { VIR_STORAGE_FILE_SHFS_NFS = (1 << 0), -- 1.8.1.4
participants (2)
-
Michal Privoznik
-
Osier Yang