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