[libvirt] [PATCH 0/3] Move FS Storage Backend API's to storage_util

While reviewing the Virtuozzo backend changes it became apparent that my initial review comments weren't fully understood. Rather than going back and forth more on this, I figured I'd take the plunge and make the "preparations". Also since the storage_util is the new dumping ground, I went there. It also already has the API's for the storage backend upload, download, and wipe - so these patches add a few more from the pool class and the rest of the volume class. FWIW: Rather than just making and bundling the changes with the Virtuozzo changes, I figured I'd post them separately just in case someone has agita over the API/helper name changes. John Ferlan (3): storage: Move the virStorageBackendFileSystem{Start|Stop} API's storage: Create common file/dir pool backend helpers storage: Create common file/dir volume backend helpers src/storage/storage_backend.c | 1 + src/storage/storage_backend_fs.c | 827 +++------------------------------- src/storage/storage_util.c | 931 ++++++++++++++++++++++++++++++++++----- src/storage/storage_util.h | 79 ++-- 4 files changed, 924 insertions(+), 914 deletions(-) -- 2.7.4

Just moving code around with minor adjustment to have the Stop code combine with the Unmount code since all the Stop code did was call the Unmount code. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/storage/storage_backend.c | 1 + src/storage/storage_backend_fs.c | 74 +++++++++++++++------------------------- 2 files changed, 29 insertions(+), 46 deletions(-) diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c index 92b08a2..8291fd5 100644 --- a/src/storage/storage_backend.c +++ b/src/storage/storage_backend.c @@ -171,6 +171,7 @@ virStorageFileBackendForTypeInternal(int type, virStorageFileBackendPtr + virStorageFileBackendForType(int type, int protocol) { diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index 15b3599..67e36be 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -536,16 +536,43 @@ virStorageBackendFileSystemMount(virStoragePoolObjPtr pool) return ret; } + /** + * @conn connection to report errors against + * @pool storage pool to start + * + * Starts a directory or FS based storage pool. The underlying source + * device will be mounted for FS based pools. + * + * Returns 0 on success, -1 on error + */ +static int +virStorageBackendFileSystemStart(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool) +{ + if (pool->def->type != VIR_STORAGE_POOL_DIR && + virStorageBackendFileSystemMount(pool) < 0) + return -1; + + return 0; +} + + +/** + * @conn connection to report errors against * @pool storage pool to unmount * + * Stops a file storage pool. The underlying source device is unmounted + * for FS based pools. Any cached data about volumes is released. + * * Ensure that a FS storage pool is not mounted on its target location. * If already unmounted, this is a no-op. * * Returns 0 if successfully unmounted, -1 on error */ static int -virStorageBackendFileSystemUnmount(virStoragePoolObjPtr pool) +virStorageBackendFileSystemStop(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool) { virCommandPtr cmd = NULL; int ret = -1; @@ -598,29 +625,6 @@ virStorageBackendFileSystemCheck(virStoragePoolObjPtr pool, return 0; } -#if WITH_STORAGE_FS -/** - * @conn connection to report errors against - * @pool storage pool to start - * - * Starts a directory or FS based storage pool. The underlying source - * device will be mounted for FS based pools. - * - * Returns 0 on success, -1 on error - */ -static int -virStorageBackendFileSystemStart(virConnectPtr conn ATTRIBUTE_UNUSED, - virStoragePoolObjPtr pool) -{ - if (pool->def->type != VIR_STORAGE_POOL_DIR && - virStorageBackendFileSystemMount(pool) < 0) - return -1; - - return 0; -} -#endif /* WITH_STORAGE_FS */ - - /* some platforms don't support mkfs */ #ifdef MKFS static int @@ -948,28 +952,6 @@ virStorageBackendFileSystemRefresh(virConnectPtr conn ATTRIBUTE_UNUSED, /** * @conn connection to report errors against - * @pool storage pool to stop - * - * Stops a file storage pool. The underlying source device is unmounted - * for FS based pools. Any cached data about volumes is released. - * - * Returns 0 on success, -1 on error. - */ -#if WITH_STORAGE_FS -static int -virStorageBackendFileSystemStop(virConnectPtr conn ATTRIBUTE_UNUSED, - virStoragePoolObjPtr pool) -{ - if (virStorageBackendFileSystemUnmount(pool) < 0) - return -1; - - return 0; -} -#endif /* WITH_STORAGE_FS */ - - -/** - * @conn connection to report errors against * @pool storage pool to delete * * Delete a directory based storage pool -- 2.7.4

On 21/01/17 20:23, John Ferlan wrote:
Just moving code around with minor adjustment to have the Stop code combine with the Unmount code since all the Stop code did was call the Unmount code.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/storage/storage_backend.c | 1 + src/storage/storage_backend_fs.c | 74 +++++++++++++++------------------------- 2 files changed, 29 insertions(+), 46 deletions(-)
diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c index 92b08a2..8291fd5 100644 --- a/src/storage/storage_backend.c +++ b/src/storage/storage_backend.c @@ -171,6 +171,7 @@ virStorageFileBackendForTypeInternal(int type,
virStorageFileBackendPtr + I guess this change is unnecessary. virStorageFileBackendForType(int type, int protocol) { diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index 15b3599..67e36be 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -536,16 +536,43 @@ virStorageBackendFileSystemMount(virStoragePoolObjPtr pool) return ret; }
+ /** + * @conn connection to report errors against + * @pool storage pool to start + * + * Starts a directory or FS based storage pool. The underlying source + * device will be mounted for FS based pools. + * + * Returns 0 on success, -1 on error + */ +static int +virStorageBackendFileSystemStart(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool) +{ + if (pool->def->type != VIR_STORAGE_POOL_DIR && + virStorageBackendFileSystemMount(pool) < 0) + return -1; + + return 0; +} + + +/** + * @conn connection to report errors against * @pool storage pool to unmount * + * Stops a file storage pool. The underlying source device is unmounted + * for FS based pools. Any cached data about volumes is released. + * * Ensure that a FS storage pool is not mounted on its target location. * If already unmounted, this is a no-op. * * Returns 0 if successfully unmounted, -1 on error */ static int -virStorageBackendFileSystemUnmount(virStoragePoolObjPtr pool) +virStorageBackendFileSystemStop(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool) { virCommandPtr cmd = NULL; int ret = -1; @@ -598,29 +625,6 @@ virStorageBackendFileSystemCheck(virStoragePoolObjPtr pool, return 0; }
-#if WITH_STORAGE_FS -/** - * @conn connection to report errors against - * @pool storage pool to start - * - * Starts a directory or FS based storage pool. The underlying source - * device will be mounted for FS based pools. - * - * Returns 0 on success, -1 on error - */ -static int -virStorageBackendFileSystemStart(virConnectPtr conn ATTRIBUTE_UNUSED, - virStoragePoolObjPtr pool) -{ - if (pool->def->type != VIR_STORAGE_POOL_DIR && - virStorageBackendFileSystemMount(pool) < 0) - return -1; - - return 0; -} -#endif /* WITH_STORAGE_FS */ - - /* some platforms don't support mkfs */ #ifdef MKFS static int @@ -948,28 +952,6 @@ virStorageBackendFileSystemRefresh(virConnectPtr conn ATTRIBUTE_UNUSED,
/** * @conn connection to report errors against - * @pool storage pool to stop - * - * Stops a file storage pool. The underlying source device is unmounted - * for FS based pools. Any cached data about volumes is released. - * - * Returns 0 on success, -1 on error. - */ -#if WITH_STORAGE_FS -static int -virStorageBackendFileSystemStop(virConnectPtr conn ATTRIBUTE_UNUSED, - virStoragePoolObjPtr pool) -{ - if (virStorageBackendFileSystemUnmount(pool) < 0) - return -1; - - return 0; -} -#endif /* WITH_STORAGE_FS */ - - -/** - * @conn connection to report errors against * @pool storage pool to delete * * Delete a directory based storage pool ACK
-- Best regards, Olga

Move some pool functions to storage_util to create local/common helpers using the same naming syntax as the existing upload, download, and wipe virStorageBackend*Local API's. In the process of doing so, found a few API's that can now become local to storage_util. In order to distinguish between local/external - I changed the names of the now local only ones from "virStorageBackend..." to just "storageBackend..." Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/storage/storage_backend_fs.c | 383 ++--------------------------------- src/storage/storage_util.c | 420 ++++++++++++++++++++++++++++++++++++--- src/storage/storage_util.h | 37 ++-- 3 files changed, 432 insertions(+), 408 deletions(-) diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index 67e36be..6f331d6 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -23,11 +23,9 @@ #include <config.h> -#include <sys/statvfs.h> #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> -#include <dirent.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> @@ -53,126 +51,6 @@ VIR_LOG_INIT("storage.storage_backend_fs"); -#define VIR_STORAGE_VOL_FS_OPEN_FLAGS (VIR_STORAGE_VOL_OPEN_DEFAULT | \ - VIR_STORAGE_VOL_OPEN_DIR) -#define VIR_STORAGE_VOL_FS_PROBE_FLAGS (VIR_STORAGE_VOL_FS_OPEN_FLAGS | \ - VIR_STORAGE_VOL_OPEN_NOERROR) - -static int -virStorageBackendProbeTarget(virStorageSourcePtr target, - virStorageEncryptionPtr *encryption) -{ - int backingStoreFormat; - int fd = -1; - int ret = -1; - int rc; - virStorageSourcePtr meta = NULL; - struct stat sb; - - if (encryption) - *encryption = NULL; - - if ((rc = virStorageBackendVolOpen(target->path, &sb, - VIR_STORAGE_VOL_FS_PROBE_FLAGS)) < 0) - return rc; /* Take care to propagate rc, it is not always -1 */ - fd = rc; - - if (virStorageBackendUpdateVolTargetInfoFD(target, fd, &sb) < 0) - goto cleanup; - - if (S_ISDIR(sb.st_mode)) { - if (virStorageBackendIsPloopDir(target->path)) { - if (virStorageBackendRedoPloopUpdate(target, &sb, &fd, - VIR_STORAGE_VOL_FS_PROBE_FLAGS) < 0) - goto cleanup; - } else { - target->format = VIR_STORAGE_FILE_DIR; - ret = 0; - goto cleanup; - } - } - - if (!(meta = virStorageFileGetMetadataFromFD(target->path, - fd, - VIR_STORAGE_FILE_AUTO, - &backingStoreFormat))) - goto cleanup; - - if (meta->backingStoreRaw) { - if (!(target->backingStore = virStorageSourceNewFromBacking(meta))) - goto cleanup; - - target->backingStore->format = backingStoreFormat; - - /* XXX: Remote storage doesn't play nicely with volumes backed by - * remote storage. To avoid trouble, just fake the backing store is RAW - * and put the string from the metadata as the path of the target. */ - if (!virStorageSourceIsLocalStorage(target->backingStore)) { - virStorageSourceFree(target->backingStore); - - if (VIR_ALLOC(target->backingStore) < 0) - goto cleanup; - - target->backingStore->type = VIR_STORAGE_TYPE_NETWORK; - target->backingStore->path = meta->backingStoreRaw; - meta->backingStoreRaw = NULL; - target->backingStore->format = VIR_STORAGE_FILE_RAW; - } - - if (target->backingStore->format == VIR_STORAGE_FILE_AUTO) { - if ((rc = virStorageFileProbeFormat(target->backingStore->path, - -1, -1)) < 0) { - /* If the backing file is currently unavailable or is - * accessed via remote protocol only log an error, fake the - * format as RAW and continue. Returning -1 here would - * disable the whole storage pool, making it unavailable for - * even maintenance. */ - target->backingStore->format = VIR_STORAGE_FILE_RAW; - virReportError(VIR_ERR_INTERNAL_ERROR, - _("cannot probe backing volume format: %s"), - target->backingStore->path); - } else { - target->backingStore->format = rc; - } - } - } - - target->format = meta->format; - - /* Default to success below this point */ - ret = 0; - - if (meta->capacity) - target->capacity = meta->capacity; - - if (encryption && meta->encryption) { - *encryption = meta->encryption; - meta->encryption = NULL; - - /* XXX ideally we'd fill in secret UUID here - * but we cannot guarantee 'conn' is non-NULL - * at this point in time :-( So we only fill - * in secrets when someone first queries a vol - */ - } - - virBitmapFree(target->features); - target->features = meta->features; - meta->features = NULL; - - if (meta->compat) { - VIR_FREE(target->compat); - target->compat = meta->compat; - meta->compat = NULL; - } - - cleanup: - VIR_FORCE_CLOSE(fd); - virStorageSourceFree(meta); - return ret; - -} - #if WITH_STORAGE_FS # include <mntent.h> @@ -574,8 +452,6 @@ static int virStorageBackendFileSystemStop(virConnectPtr conn ATTRIBUTE_UNUSED, virStoragePoolObjPtr pool) { - virCommandPtr cmd = NULL; - int ret = -1; int rc; if (virStorageBackendFileSystemIsValid(pool) < 0) @@ -585,17 +461,7 @@ virStorageBackendFileSystemStop(virConnectPtr conn ATTRIBUTE_UNUSED, if ((rc = virStorageBackendFileSystemIsMounted(pool)) != 1) return rc; - cmd = virCommandNewArgList(UMOUNT, - pool->def->target.path, - NULL); - - if (virCommandRun(cmd, NULL) < 0) - goto cleanup; - - ret = 0; - cleanup: - virCommandFree(cmd); - return ret; + return virStorageBackendUmountLocal(pool); } #endif /* WITH_STORAGE_FS */ @@ -742,237 +608,18 @@ virStorageBackendFileSystemBuild(virConnectPtr conn ATTRIBUTE_UNUSED, virStoragePoolObjPtr pool, unsigned int flags) { - int ret = -1; - char *parent = NULL; - char *p = NULL; - mode_t mode; - bool needs_create_as_uid; - unsigned int dir_create_flags; - virCheckFlags(VIR_STORAGE_POOL_BUILD_OVERWRITE | - VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, ret); + VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, -1); - VIR_EXCLUSIVE_FLAGS_GOTO(VIR_STORAGE_POOL_BUILD_OVERWRITE, - VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, - error); + VIR_EXCLUSIVE_FLAGS_RET(VIR_STORAGE_POOL_BUILD_OVERWRITE, + VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, + -1); - if (VIR_STRDUP(parent, pool->def->target.path) < 0) - goto error; - if (!(p = strrchr(parent, '/'))) { - virReportError(VIR_ERR_INVALID_ARG, - _("path '%s' is not absolute"), - pool->def->target.path); - goto error; - } - - if (p != parent) { - /* assure all directories in the path prior to the final dir - * exist, with default uid/gid/mode. */ - *p = '\0'; - if (virFileMakePath(parent) < 0) { - virReportSystemError(errno, _("cannot create path '%s'"), - parent); - goto error; - } - } - - dir_create_flags = VIR_DIR_CREATE_ALLOW_EXIST; - needs_create_as_uid = (pool->def->type == VIR_STORAGE_POOL_NETFS); - mode = pool->def->target.perms.mode; - - if (mode == (mode_t) -1 && - (needs_create_as_uid || !virFileExists(pool->def->target.path))) - mode = VIR_STORAGE_DEFAULT_POOL_PERM_MODE; - if (needs_create_as_uid) - dir_create_flags |= VIR_DIR_CREATE_AS_UID; - - /* Now create the final dir in the path with the uid/gid/mode - * requested in the config. If the dir already exists, just set - * the perms. */ - if (virDirCreate(pool->def->target.path, - mode, - pool->def->target.perms.uid, - pool->def->target.perms.gid, - dir_create_flags) < 0) - goto error; - - if (flags != 0) { - ret = virStorageBackendMakeFileSystem(pool, flags); - } else { - ret = 0; - } - - error: - VIR_FREE(parent); - return ret; -} - - -/** - * Iterate over the pool's directory and enumerate all disk images - * within it. This is non-recursive. - */ -static int -virStorageBackendFileSystemRefresh(virConnectPtr conn ATTRIBUTE_UNUSED, - virStoragePoolObjPtr pool) -{ - DIR *dir; - struct dirent *ent; - struct statvfs sb; - struct stat statbuf; - virStorageVolDefPtr vol = NULL; - virStorageSourcePtr target = NULL; - int direrr; - int fd = -1, ret = -1; - - if (virDirOpen(&dir, pool->def->target.path) < 0) - goto cleanup; - - while ((direrr = virDirRead(dir, &ent, pool->def->target.path)) > 0) { - int err; - - if (virStringHasControlChars(ent->d_name)) { - VIR_WARN("Ignoring file with control characters under '%s'", - pool->def->target.path); - continue; - } - - if (VIR_ALLOC(vol) < 0) - goto cleanup; - - if (VIR_STRDUP(vol->name, ent->d_name) < 0) - goto cleanup; - - vol->type = VIR_STORAGE_VOL_FILE; - vol->target.format = VIR_STORAGE_FILE_RAW; /* Real value is filled in during probe */ - if (virAsprintf(&vol->target.path, "%s/%s", - pool->def->target.path, - vol->name) == -1) - goto cleanup; - - if (VIR_STRDUP(vol->key, vol->target.path) < 0) - goto cleanup; - - if ((err = virStorageBackendProbeTarget(&vol->target, - &vol->target.encryption)) < 0) { - if (err == -2) { - /* Silently ignore non-regular files, - * eg 'lost+found', dangling symbolic link */ - virStorageVolDefFree(vol); - vol = NULL; - continue; - } else if (err == -3) { - /* The backing file is currently unavailable, its format is not - * explicitly specified, the probe to auto detect the format - * failed: continue with faked RAW format, since AUTO will - * break virStorageVolTargetDefFormat() generating the line - * <format type='...'/>. */ - } else { - goto cleanup; - } - } - - /* directory based volume */ - if (vol->target.format == VIR_STORAGE_FILE_DIR) - vol->type = VIR_STORAGE_VOL_DIR; - - if (vol->target.format == VIR_STORAGE_FILE_PLOOP) - vol->type = VIR_STORAGE_VOL_PLOOP; - - if (vol->target.backingStore) { - ignore_value(virStorageBackendUpdateVolTargetInfo(VIR_STORAGE_VOL_FILE, - vol->target.backingStore, - false, - VIR_STORAGE_VOL_OPEN_DEFAULT, 0)); - /* If this failed, the backing file is currently unavailable, - * the capacity, allocation, owner, group and mode are unknown. - * An error message was raised, but we just continue. */ - } - - if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0) - goto cleanup; - } - if (direrr < 0) - goto cleanup; - VIR_DIR_CLOSE(dir); - vol = NULL; - - if (VIR_ALLOC(target)) - goto cleanup; - - if ((fd = open(pool->def->target.path, O_RDONLY)) < 0) { - virReportSystemError(errno, - _("cannot open path '%s'"), - pool->def->target.path); - goto cleanup; - } - - if (fstat(fd, &statbuf) < 0) { - virReportSystemError(errno, - _("cannot stat path '%s'"), - pool->def->target.path); - goto cleanup; - } - - if (virStorageBackendUpdateVolTargetInfoFD(target, fd, &statbuf) < 0) - goto cleanup; - - /* VolTargetInfoFD doesn't update capacity correctly for the pool case */ - if (statvfs(pool->def->target.path, &sb) < 0) { - virReportSystemError(errno, - _("cannot statvfs path '%s'"), - pool->def->target.path); - goto cleanup; - } - - pool->def->capacity = ((unsigned long long)sb.f_frsize * - (unsigned long long)sb.f_blocks); - pool->def->available = ((unsigned long long)sb.f_bfree * - (unsigned long long)sb.f_frsize); - pool->def->allocation = pool->def->capacity - pool->def->available; - - pool->def->target.perms.mode = target->perms->mode; - pool->def->target.perms.uid = target->perms->uid; - pool->def->target.perms.gid = target->perms->gid; - VIR_FREE(pool->def->target.perms.label); - if (VIR_STRDUP(pool->def->target.perms.label, target->perms->label) < 0) - goto cleanup; - - ret = 0; - cleanup: - VIR_DIR_CLOSE(dir); - VIR_FORCE_CLOSE(fd); - virStorageVolDefFree(vol); - virStorageSourceFree(target); - if (ret < 0) - virStoragePoolObjClearVols(pool); - return ret; -} - - -/** - * @conn connection to report errors against - * @pool storage pool to delete - * - * Delete a directory based storage pool - * - * Returns 0 on success, -1 on error - */ -static int -virStorageBackendFileSystemDelete(virConnectPtr conn ATTRIBUTE_UNUSED, - virStoragePoolObjPtr pool, - unsigned int flags) -{ - virCheckFlags(0, -1); - - /* XXX delete all vols first ? */ - - if (rmdir(pool->def->target.path) < 0) { - virReportSystemError(errno, - _("failed to remove pool '%s'"), - pool->def->target.path); + if (virStorageBackendBuildLocal(pool) < 0) return -1; - } + + if (flags != 0) + return virStorageBackendMakeFileSystem(pool, flags); return 0; } @@ -1319,8 +966,8 @@ virStorageBackend virStorageBackendDirectory = { .buildPool = virStorageBackendFileSystemBuild, .checkPool = virStorageBackendFileSystemCheck, - .refreshPool = virStorageBackendFileSystemRefresh, - .deletePool = virStorageBackendFileSystemDelete, + .refreshPool = virStorageBackendRefreshLocal, + .deletePool = virStorageBackendDeleteLocal, .buildVol = virStorageBackendFileSystemVolBuild, .buildVolFrom = virStorageBackendFileSystemVolBuildFrom, .createVol = virStorageBackendFileSystemVolCreate, @@ -1339,9 +986,9 @@ virStorageBackend virStorageBackendFileSystem = { .buildPool = virStorageBackendFileSystemBuild, .checkPool = virStorageBackendFileSystemCheck, .startPool = virStorageBackendFileSystemStart, - .refreshPool = virStorageBackendFileSystemRefresh, + .refreshPool = virStorageBackendRefreshLocal, .stopPool = virStorageBackendFileSystemStop, - .deletePool = virStorageBackendFileSystemDelete, + .deletePool = virStorageBackendDeleteLocal, .buildVol = virStorageBackendFileSystemVolBuild, .buildVolFrom = virStorageBackendFileSystemVolBuildFrom, .createVol = virStorageBackendFileSystemVolCreate, @@ -1359,9 +1006,9 @@ virStorageBackend virStorageBackendNetFileSystem = { .checkPool = virStorageBackendFileSystemCheck, .startPool = virStorageBackendFileSystemStart, .findPoolSources = virStorageBackendFileSystemNetFindPoolSources, - .refreshPool = virStorageBackendFileSystemRefresh, + .refreshPool = virStorageBackendRefreshLocal, .stopPool = virStorageBackendFileSystemStop, - .deletePool = virStorageBackendFileSystemDelete, + .deletePool = virStorageBackendDeleteLocal, .buildVol = virStorageBackendFileSystemVolBuild, .buildVolFrom = virStorageBackendFileSystemVolBuildFrom, .createVol = virStorageBackendFileSystemVolCreate, diff --git a/src/storage/storage_util.c b/src/storage/storage_util.c index e16c1a4..6c2678d 100644 --- a/src/storage/storage_util.c +++ b/src/storage/storage_util.c @@ -26,6 +26,7 @@ #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> +#include <sys/statvfs.h> #include <sys/param.h> #include <dirent.h> #include "dirname.h" @@ -1675,8 +1676,8 @@ virStorageBackendVolOpen(const char *path, struct stat *sb, /* virStorageIsPloop function checks whether given directory is ploop volume's * directory. */ -bool -virStorageBackendIsPloopDir(char *path) +static bool +storageBackendIsPloopDir(char *path) { bool ret = false; char *root = NULL; @@ -1702,9 +1703,9 @@ virStorageBackendIsPloopDir(char *path) * and etc. we need to perform virStorageBackendVolOpen and * virStorageBackendUpdateVolTargetFd once again. */ -int -virStorageBackendRedoPloopUpdate(virStorageSourcePtr target, struct stat *sb, - int *fd, unsigned int flags) +static int +storageBackendRedoPloopUpdate(virStorageSourcePtr target, struct stat *sb, + int *fd, unsigned int flags) { char *path = NULL; int ret = -1; @@ -1723,7 +1724,7 @@ virStorageBackendRedoPloopUpdate(virStorageSourcePtr target, struct stat *sb, } /* - * virStorageBackendUpdateVolTargetInfo + * storageBackendUpdateVolTargetInfo * @voltype: Volume type * @target: target definition ptr of volume to update * @withBlockVolFormat: true if caller determined a block file @@ -1736,12 +1737,12 @@ virStorageBackendRedoPloopUpdate(virStorageSourcePtr target, struct stat *sb, * open error occurred. It is up to the caller to handle. A -2 may also * be returned if the caller passed a readflagsflag. */ -int -virStorageBackendUpdateVolTargetInfo(virStorageVolType voltype, - virStorageSourcePtr target, - bool withBlockVolFormat, - unsigned int openflags, - unsigned int readflags) +static int +storageBackendUpdateVolTargetInfo(virStorageVolType voltype, + virStorageSourcePtr target, + bool withBlockVolFormat, + unsigned int openflags, + unsigned int readflags) { int ret, fd = -1; struct stat sb; @@ -1758,9 +1759,9 @@ virStorageBackendUpdateVolTargetInfo(virStorageVolType voltype, if ((voltype == VIR_STORAGE_VOL_FILE || voltype == VIR_STORAGE_VOL_BLOCK) && target->format != VIR_STORAGE_FILE_NONE) { if (S_ISDIR(sb.st_mode)) { - if (virStorageBackendIsPloopDir(target->path)) { - if ((ret = virStorageBackendRedoPloopUpdate(target, &sb, &fd, - openflags)) < 0) + if (storageBackendIsPloopDir(target->path)) { + if ((ret = storageBackendRedoPloopUpdate(target, &sb, &fd, + openflags)) < 0) goto cleanup; target->format = VIR_STORAGE_FILE_PLOOP; } else { @@ -1826,19 +1827,19 @@ virStorageBackendUpdateVolInfo(virStorageVolDefPtr vol, { int ret; - if ((ret = virStorageBackendUpdateVolTargetInfo(vol->type, - &vol->target, - withBlockVolFormat, - openflags, readflags)) < 0) + if ((ret = storageBackendUpdateVolTargetInfo(vol->type, + &vol->target, + withBlockVolFormat, + openflags, readflags)) < 0) return ret; if (vol->target.backingStore && - (ret = virStorageBackendUpdateVolTargetInfo(VIR_STORAGE_VOL_FILE, - vol->target.backingStore, - withBlockVolFormat, - VIR_STORAGE_VOL_OPEN_DEFAULT | - VIR_STORAGE_VOL_OPEN_NOERROR, - readflags) < 0)) + (ret = storageBackendUpdateVolTargetInfo(VIR_STORAGE_VOL_FILE, + vol->target.backingStore, + withBlockVolFormat, + VIR_STORAGE_VOL_OPEN_DEFAULT | + VIR_STORAGE_VOL_OPEN_NOERROR, + readflags) < 0)) return ret; return 0; @@ -2408,6 +2409,118 @@ virStorageBackendVolWipeLocal(virConnectPtr conn ATTRIBUTE_UNUSED, /** + * @pool: storage pool to build + * @dir_create_flags: flags for directory creation + * + * Common code to build a directory based storage pool + * + * Returns 0 on success, -1 on failure + */ +int +virStorageBackendBuildLocal(virStoragePoolObjPtr pool) +{ + int ret = -1; + char *parent = NULL; + char *p = NULL; + mode_t mode; + bool needs_create_as_uid; + unsigned int dir_create_flags; + + if (VIR_STRDUP(parent, pool->def->target.path) < 0) + goto cleanup; + if (!(p = strrchr(parent, '/'))) { + virReportError(VIR_ERR_INVALID_ARG, + _("path '%s' is not absolute"), + pool->def->target.path); + goto cleanup; + } + + if (p != parent) { + /* assure all directories in the path prior to the final dir + * exist, with default uid/gid/mode. */ + *p = '\0'; + if (virFileMakePath(parent) < 0) { + virReportSystemError(errno, _("cannot create path '%s'"), + parent); + goto cleanup; + } + } + + dir_create_flags = VIR_DIR_CREATE_ALLOW_EXIST; + needs_create_as_uid = (pool->def->type == VIR_STORAGE_POOL_NETFS); + mode = pool->def->target.perms.mode; + + if (mode == (mode_t) -1 && + (needs_create_as_uid || !virFileExists(pool->def->target.path))) + mode = VIR_STORAGE_DEFAULT_POOL_PERM_MODE; + if (needs_create_as_uid) + dir_create_flags |= VIR_DIR_CREATE_AS_UID; + + /* Now create the final dir in the path with the uid/gid/mode + * requested in the config. If the dir already exists, just set + * the perms. */ + if (virDirCreate(pool->def->target.path, + mode, + pool->def->target.perms.uid, + pool->def->target.perms.gid, + dir_create_flags) < 0) + goto cleanup; + + ret = 0; + + cleanup: + VIR_FREE(parent); + return ret; +} + + +int +virStorageBackendUmountLocal(virStoragePoolObjPtr pool) +{ + int ret = -1; + virCommandPtr cmd = virCommandNewArgList(UMOUNT, pool->def->target.path, + NULL); + + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virCommandFree(cmd); + return ret; +} + + +/** + * @conn connection to report errors against + * @pool storage pool to delete + * + * Delete a directory based storage pool + * + * Returns 0 on success, -1 on error + */ +int +virStorageBackendDeleteLocal(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool, + unsigned int flags) +{ + virCheckFlags(0, -1); + + /* XXX delete all vols first ? */ + + if (rmdir(pool->def->target.path) < 0) { + virReportSystemError(errno, + _("failed to remove pool '%s'"), + pool->def->target.path); + return -1; + } + + return 0; +} + + +/** * virStorageBackendFindGlusterPoolSources: * @host: host to detect volumes on * @pooltype: src->format is set to this value @@ -2919,6 +3032,263 @@ virStorageBackendDeviceIsEmpty(const char *devpath, } +static int +storageBackendProbeTarget(virStorageSourcePtr target, + virStorageEncryptionPtr *encryption) +{ + int backingStoreFormat; + int fd = -1; + int ret = -1; + int rc; + virStorageSourcePtr meta = NULL; + struct stat sb; + + if (encryption) + *encryption = NULL; + + if ((rc = virStorageBackendVolOpen(target->path, &sb, + VIR_STORAGE_VOL_FS_PROBE_FLAGS)) < 0) + return rc; /* Take care to propagate rc, it is not always -1 */ + fd = rc; + + if (virStorageBackendUpdateVolTargetInfoFD(target, fd, &sb) < 0) + goto cleanup; + + if (S_ISDIR(sb.st_mode)) { + if (storageBackendIsPloopDir(target->path)) { + if (storageBackendRedoPloopUpdate(target, &sb, &fd, + VIR_STORAGE_VOL_FS_PROBE_FLAGS) < 0) + goto cleanup; + } else { + target->format = VIR_STORAGE_FILE_DIR; + ret = 0; + goto cleanup; + } + } + + if (!(meta = virStorageFileGetMetadataFromFD(target->path, + fd, + VIR_STORAGE_FILE_AUTO, + &backingStoreFormat))) + goto cleanup; + + if (meta->backingStoreRaw) { + if (!(target->backingStore = virStorageSourceNewFromBacking(meta))) + goto cleanup; + + target->backingStore->format = backingStoreFormat; + + /* XXX: Remote storage doesn't play nicely with volumes backed by + * remote storage. To avoid trouble, just fake the backing store is RAW + * and put the string from the metadata as the path of the target. */ + if (!virStorageSourceIsLocalStorage(target->backingStore)) { + virStorageSourceFree(target->backingStore); + + if (VIR_ALLOC(target->backingStore) < 0) + goto cleanup; + + target->backingStore->type = VIR_STORAGE_TYPE_NETWORK; + target->backingStore->path = meta->backingStoreRaw; + meta->backingStoreRaw = NULL; + target->backingStore->format = VIR_STORAGE_FILE_RAW; + } + + if (target->backingStore->format == VIR_STORAGE_FILE_AUTO) { + if ((rc = virStorageFileProbeFormat(target->backingStore->path, + -1, -1)) < 0) { + /* If the backing file is currently unavailable or is + * accessed via remote protocol only log an error, fake the + * format as RAW and continue. Returning -1 here would + * disable the whole storage pool, making it unavailable for + * even maintenance. */ + target->backingStore->format = VIR_STORAGE_FILE_RAW; + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot probe backing volume format: %s"), + target->backingStore->path); + } else { + target->backingStore->format = rc; + } + } + } + + target->format = meta->format; + + /* Default to success below this point */ + ret = 0; + + if (meta->capacity) + target->capacity = meta->capacity; + + if (encryption && meta->encryption) { + *encryption = meta->encryption; + meta->encryption = NULL; + + /* XXX ideally we'd fill in secret UUID here + * but we cannot guarantee 'conn' is non-NULL + * at this point in time :-( So we only fill + * in secrets when someone first queries a vol + */ + } + + virBitmapFree(target->features); + target->features = meta->features; + meta->features = NULL; + + if (meta->compat) { + VIR_FREE(target->compat); + target->compat = meta->compat; + meta->compat = NULL; + } + + cleanup: + VIR_FORCE_CLOSE(fd); + virStorageSourceFree(meta); + return ret; +} + + +/** + * Iterate over the pool's directory and enumerate all disk images + * within it. This is non-recursive. + */ +int +virStorageBackendRefreshLocal(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool) +{ + DIR *dir; + struct dirent *ent; + struct statvfs sb; + struct stat statbuf; + virStorageVolDefPtr vol = NULL; + virStorageSourcePtr target = NULL; + int direrr; + int fd = -1, ret = -1; + + if (virDirOpen(&dir, pool->def->target.path) < 0) + goto cleanup; + + while ((direrr = virDirRead(dir, &ent, pool->def->target.path)) > 0) { + int err; + + if (virStringHasControlChars(ent->d_name)) { + VIR_WARN("Ignoring file with control characters under '%s'", + pool->def->target.path); + continue; + } + + if (VIR_ALLOC(vol) < 0) + goto cleanup; + + if (VIR_STRDUP(vol->name, ent->d_name) < 0) + goto cleanup; + + vol->type = VIR_STORAGE_VOL_FILE; + vol->target.format = VIR_STORAGE_FILE_RAW; /* Real value is filled in during probe */ + if (virAsprintf(&vol->target.path, "%s/%s", + pool->def->target.path, + vol->name) == -1) + goto cleanup; + + if (VIR_STRDUP(vol->key, vol->target.path) < 0) + goto cleanup; + + if ((err = storageBackendProbeTarget(&vol->target, + &vol->target.encryption)) < 0) { + if (err == -2) { + /* Silently ignore non-regular files, + * eg 'lost+found', dangling symbolic link */ + virStorageVolDefFree(vol); + vol = NULL; + continue; + } else if (err == -3) { + /* The backing file is currently unavailable, its format is not + * explicitly specified, the probe to auto detect the format + * failed: continue with faked RAW format, since AUTO will + * break virStorageVolTargetDefFormat() generating the line + * <format type='...'/>. */ + } else { + goto cleanup; + } + } + + /* directory based volume */ + if (vol->target.format == VIR_STORAGE_FILE_DIR) + vol->type = VIR_STORAGE_VOL_DIR; + + if (vol->target.format == VIR_STORAGE_FILE_PLOOP) + vol->type = VIR_STORAGE_VOL_PLOOP; + + if (vol->target.backingStore) { + ignore_value(storageBackendUpdateVolTargetInfo(VIR_STORAGE_VOL_FILE, + vol->target.backingStore, + false, + VIR_STORAGE_VOL_OPEN_DEFAULT, 0)); + /* If this failed, the backing file is currently unavailable, + * the capacity, allocation, owner, group and mode are unknown. + * An error message was raised, but we just continue. */ + } + + if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0) + goto cleanup; + } + if (direrr < 0) + goto cleanup; + VIR_DIR_CLOSE(dir); + vol = NULL; + + if (VIR_ALLOC(target)) + goto cleanup; + + if ((fd = open(pool->def->target.path, O_RDONLY)) < 0) { + virReportSystemError(errno, + _("cannot open path '%s'"), + pool->def->target.path); + goto cleanup; + } + + if (fstat(fd, &statbuf) < 0) { + virReportSystemError(errno, + _("cannot stat path '%s'"), + pool->def->target.path); + goto cleanup; + } + + if (virStorageBackendUpdateVolTargetInfoFD(target, fd, &statbuf) < 0) + goto cleanup; + + /* VolTargetInfoFD doesn't update capacity correctly for the pool case */ + if (statvfs(pool->def->target.path, &sb) < 0) { + virReportSystemError(errno, + _("cannot statvfs path '%s'"), + pool->def->target.path); + goto cleanup; + } + + pool->def->capacity = ((unsigned long long)sb.f_frsize * + (unsigned long long)sb.f_blocks); + pool->def->available = ((unsigned long long)sb.f_bfree * + (unsigned long long)sb.f_frsize); + pool->def->allocation = pool->def->capacity - pool->def->available; + + pool->def->target.perms.mode = target->perms->mode; + pool->def->target.perms.uid = target->perms->uid; + pool->def->target.perms.gid = target->perms->gid; + VIR_FREE(pool->def->target.perms.label); + if (VIR_STRDUP(pool->def->target.perms.label, target->perms->label) < 0) + goto cleanup; + + ret = 0; + cleanup: + VIR_DIR_CLOSE(dir); + VIR_FORCE_CLOSE(fd); + virStorageVolDefFree(vol); + virStorageSourceFree(target); + if (ret < 0) + virStoragePoolObjClearVols(pool); + return ret; +} + + static char * virStorageBackendSCSISerial(const char *dev) { diff --git a/src/storage/storage_util.h b/src/storage/storage_util.h index e127381..f5a1b5b 100644 --- a/src/storage/storage_util.h +++ b/src/storage/storage_util.h @@ -49,20 +49,10 @@ int virStorageBackendCreatePloop(virConnectPtr conn, int virStoragePloopResize(virStorageVolDefPtr vol, unsigned long long capacity); -int virStorageBackendRedoPloopUpdate(virStorageSourcePtr target, - struct stat *sb, int *fd, - unsigned int flags); -bool virStorageBackendIsPloopDir(char *path); - virStorageBackendBuildVolFrom virStorageBackendGetBuildVolFromFunction(virStorageVolDefPtr vol, virStorageVolDefPtr inputvol); -int virStorageBackendFindGlusterPoolSources(const char *host, - int pooltype, - virStoragePoolSourceListPtr list, - bool report); - int virStorageBackendVolUploadLocal(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol, @@ -84,6 +74,23 @@ int virStorageBackendVolWipeLocal(virConnectPtr conn, unsigned int algorithm, unsigned int flags); +/* Local/Common Storage Pool Backend APIs */ +int virStorageBackendBuildLocal(virStoragePoolObjPtr pool); + +int virStorageBackendUmountLocal(virStoragePoolObjPtr pool); + +int virStorageBackendDeleteLocal(virConnectPtr conn, + virStoragePoolObjPtr pool, + unsigned int flags); + +int virStorageBackendRefreshLocal(virConnectPtr conn, + virStoragePoolObjPtr pool); + +int virStorageBackendFindGlusterPoolSources(const char *host, + int pooltype, + virStoragePoolSourceListPtr list, + bool report); + bool virStorageBackendDeviceIsEmpty(const char *devpath, const char *format, bool writelabel); @@ -110,6 +117,11 @@ enum { # define VIR_STORAGE_VOL_OPEN_DEFAULT (VIR_STORAGE_VOL_OPEN_REG |\ VIR_STORAGE_VOL_OPEN_BLOCK) +# define VIR_STORAGE_VOL_FS_OPEN_FLAGS (VIR_STORAGE_VOL_OPEN_DEFAULT | \ + VIR_STORAGE_VOL_OPEN_DIR) +# define VIR_STORAGE_VOL_FS_PROBE_FLAGS (VIR_STORAGE_VOL_FS_OPEN_FLAGS | \ + VIR_STORAGE_VOL_OPEN_NOERROR) + int virStorageBackendVolOpen(const char *path, struct stat *sb, unsigned int flags) ATTRIBUTE_RETURN_CHECK @@ -122,11 +134,6 @@ int virStorageBackendUpdateVolInfo(virStorageVolDefPtr vol, bool withBlockVolFormat, unsigned int openflags, unsigned int readflags); -int virStorageBackendUpdateVolTargetInfo(virStorageVolType voltype, - virStorageSourcePtr target, - bool withBlockVolFormat, - unsigned int openflags, - unsigned int readflags); int virStorageBackendUpdateVolTargetInfoFD(virStorageSourcePtr target, int fd, struct stat *sb); -- 2.7.4

On 21/01/17 20:23, John Ferlan wrote:
Move some pool functions to storage_util to create local/common helpers using the same naming syntax as the existing upload, download, and wipe virStorageBackend*Local API's.
In the process of doing so, found a few API's that can now become local to storage_util. In order to distinguish between local/external - I changed the names of the now local only ones from "virStorageBackend..." to just "storageBackend..."
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/storage/storage_backend_fs.c | 383 ++--------------------------------- src/storage/storage_util.c | 420 ++++++++++++++++++++++++++++++++++++--- src/storage/storage_util.h | 37 ++-- 3 files changed, 432 insertions(+), 408 deletions(-)
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index 67e36be..6f331d6 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -23,11 +23,9 @@
#include <config.h>
-#include <sys/statvfs.h> #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> -#include <dirent.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> @@ -53,126 +51,6 @@
VIR_LOG_INIT("storage.storage_backend_fs");
-#define VIR_STORAGE_VOL_FS_OPEN_FLAGS (VIR_STORAGE_VOL_OPEN_DEFAULT | \ - VIR_STORAGE_VOL_OPEN_DIR) -#define VIR_STORAGE_VOL_FS_PROBE_FLAGS (VIR_STORAGE_VOL_FS_OPEN_FLAGS | \ - VIR_STORAGE_VOL_OPEN_NOERROR) - -static int -virStorageBackendProbeTarget(virStorageSourcePtr target, - virStorageEncryptionPtr *encryption) -{ - int backingStoreFormat; - int fd = -1; - int ret = -1; - int rc; - virStorageSourcePtr meta = NULL; - struct stat sb; - - if (encryption) - *encryption = NULL; - - if ((rc = virStorageBackendVolOpen(target->path, &sb, - VIR_STORAGE_VOL_FS_PROBE_FLAGS)) < 0) - return rc; /* Take care to propagate rc, it is not always -1 */ - fd = rc; - - if (virStorageBackendUpdateVolTargetInfoFD(target, fd, &sb) < 0) - goto cleanup; - - if (S_ISDIR(sb.st_mode)) { - if (virStorageBackendIsPloopDir(target->path)) { - if (virStorageBackendRedoPloopUpdate(target, &sb, &fd, - VIR_STORAGE_VOL_FS_PROBE_FLAGS) < 0) - goto cleanup; - } else { - target->format = VIR_STORAGE_FILE_DIR; - ret = 0; - goto cleanup; - } - } - - if (!(meta = virStorageFileGetMetadataFromFD(target->path, - fd, - VIR_STORAGE_FILE_AUTO, - &backingStoreFormat))) - goto cleanup; - - if (meta->backingStoreRaw) { - if (!(target->backingStore = virStorageSourceNewFromBacking(meta))) - goto cleanup; - - target->backingStore->format = backingStoreFormat; - - /* XXX: Remote storage doesn't play nicely with volumes backed by - * remote storage. To avoid trouble, just fake the backing store is RAW - * and put the string from the metadata as the path of the target. */ - if (!virStorageSourceIsLocalStorage(target->backingStore)) { - virStorageSourceFree(target->backingStore); - - if (VIR_ALLOC(target->backingStore) < 0) - goto cleanup; - - target->backingStore->type = VIR_STORAGE_TYPE_NETWORK; - target->backingStore->path = meta->backingStoreRaw; - meta->backingStoreRaw = NULL; - target->backingStore->format = VIR_STORAGE_FILE_RAW; - } - - if (target->backingStore->format == VIR_STORAGE_FILE_AUTO) { - if ((rc = virStorageFileProbeFormat(target->backingStore->path, - -1, -1)) < 0) { - /* If the backing file is currently unavailable or is - * accessed via remote protocol only log an error, fake the - * format as RAW and continue. Returning -1 here would - * disable the whole storage pool, making it unavailable for - * even maintenance. */ - target->backingStore->format = VIR_STORAGE_FILE_RAW; - virReportError(VIR_ERR_INTERNAL_ERROR, - _("cannot probe backing volume format: %s"), - target->backingStore->path); - } else { - target->backingStore->format = rc; - } - } - } - - target->format = meta->format; - - /* Default to success below this point */ - ret = 0; - - if (meta->capacity) - target->capacity = meta->capacity; - - if (encryption && meta->encryption) { - *encryption = meta->encryption; - meta->encryption = NULL; - - /* XXX ideally we'd fill in secret UUID here - * but we cannot guarantee 'conn' is non-NULL - * at this point in time :-( So we only fill - * in secrets when someone first queries a vol - */ - } - - virBitmapFree(target->features); - target->features = meta->features; - meta->features = NULL; - - if (meta->compat) { - VIR_FREE(target->compat); - target->compat = meta->compat; - meta->compat = NULL; - } - - cleanup: - VIR_FORCE_CLOSE(fd); - virStorageSourceFree(meta); - return ret; - -} - #if WITH_STORAGE_FS
# include <mntent.h> @@ -574,8 +452,6 @@ static int virStorageBackendFileSystemStop(virConnectPtr conn ATTRIBUTE_UNUSED, virStoragePoolObjPtr pool) { - virCommandPtr cmd = NULL; - int ret = -1; int rc;
if (virStorageBackendFileSystemIsValid(pool) < 0) @@ -585,17 +461,7 @@ virStorageBackendFileSystemStop(virConnectPtr conn ATTRIBUTE_UNUSED, if ((rc = virStorageBackendFileSystemIsMounted(pool)) != 1) return rc;
- cmd = virCommandNewArgList(UMOUNT, - pool->def->target.path, - NULL); - - if (virCommandRun(cmd, NULL) < 0) - goto cleanup; - - ret = 0; - cleanup: - virCommandFree(cmd); - return ret; + return virStorageBackendUmountLocal(pool); } #endif /* WITH_STORAGE_FS */
@@ -742,237 +608,18 @@ virStorageBackendFileSystemBuild(virConnectPtr conn ATTRIBUTE_UNUSED, virStoragePoolObjPtr pool, unsigned int flags) { - int ret = -1; - char *parent = NULL; - char *p = NULL; - mode_t mode; - bool needs_create_as_uid; - unsigned int dir_create_flags; - virCheckFlags(VIR_STORAGE_POOL_BUILD_OVERWRITE | - VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, ret); + VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, -1);
- VIR_EXCLUSIVE_FLAGS_GOTO(VIR_STORAGE_POOL_BUILD_OVERWRITE, - VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, - error); + VIR_EXCLUSIVE_FLAGS_RET(VIR_STORAGE_POOL_BUILD_OVERWRITE, + VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, + -1);
- if (VIR_STRDUP(parent, pool->def->target.path) < 0) - goto error; - if (!(p = strrchr(parent, '/'))) { - virReportError(VIR_ERR_INVALID_ARG, - _("path '%s' is not absolute"), - pool->def->target.path); - goto error; - } - - if (p != parent) { - /* assure all directories in the path prior to the final dir - * exist, with default uid/gid/mode. */ - *p = '\0'; - if (virFileMakePath(parent) < 0) { - virReportSystemError(errno, _("cannot create path '%s'"), - parent); - goto error; - } - } - - dir_create_flags = VIR_DIR_CREATE_ALLOW_EXIST; - needs_create_as_uid = (pool->def->type == VIR_STORAGE_POOL_NETFS); - mode = pool->def->target.perms.mode; - - if (mode == (mode_t) -1 && - (needs_create_as_uid || !virFileExists(pool->def->target.path))) - mode = VIR_STORAGE_DEFAULT_POOL_PERM_MODE; - if (needs_create_as_uid) - dir_create_flags |= VIR_DIR_CREATE_AS_UID; - - /* Now create the final dir in the path with the uid/gid/mode - * requested in the config. If the dir already exists, just set - * the perms. */ - if (virDirCreate(pool->def->target.path, - mode, - pool->def->target.perms.uid, - pool->def->target.perms.gid, - dir_create_flags) < 0) - goto error; - - if (flags != 0) { - ret = virStorageBackendMakeFileSystem(pool, flags); - } else { - ret = 0; - } - - error: - VIR_FREE(parent); - return ret; -} - - -/** - * Iterate over the pool's directory and enumerate all disk images - * within it. This is non-recursive. - */ -static int -virStorageBackendFileSystemRefresh(virConnectPtr conn ATTRIBUTE_UNUSED, - virStoragePoolObjPtr pool) -{ - DIR *dir; - struct dirent *ent; - struct statvfs sb; - struct stat statbuf; - virStorageVolDefPtr vol = NULL; - virStorageSourcePtr target = NULL; - int direrr; - int fd = -1, ret = -1; - - if (virDirOpen(&dir, pool->def->target.path) < 0) - goto cleanup; - - while ((direrr = virDirRead(dir, &ent, pool->def->target.path)) > 0) { - int err; - - if (virStringHasControlChars(ent->d_name)) { - VIR_WARN("Ignoring file with control characters under '%s'", - pool->def->target.path); - continue; - } - - if (VIR_ALLOC(vol) < 0) - goto cleanup; - - if (VIR_STRDUP(vol->name, ent->d_name) < 0) - goto cleanup; - - vol->type = VIR_STORAGE_VOL_FILE; - vol->target.format = VIR_STORAGE_FILE_RAW; /* Real value is filled in during probe */ - if (virAsprintf(&vol->target.path, "%s/%s", - pool->def->target.path, - vol->name) == -1) - goto cleanup; - - if (VIR_STRDUP(vol->key, vol->target.path) < 0) - goto cleanup; - - if ((err = virStorageBackendProbeTarget(&vol->target, - &vol->target.encryption)) < 0) { - if (err == -2) { - /* Silently ignore non-regular files, - * eg 'lost+found', dangling symbolic link */ - virStorageVolDefFree(vol); - vol = NULL; - continue; - } else if (err == -3) { - /* The backing file is currently unavailable, its format is not - * explicitly specified, the probe to auto detect the format - * failed: continue with faked RAW format, since AUTO will - * break virStorageVolTargetDefFormat() generating the line - * <format type='...'/>. */ - } else { - goto cleanup; - } - } - - /* directory based volume */ - if (vol->target.format == VIR_STORAGE_FILE_DIR) - vol->type = VIR_STORAGE_VOL_DIR; - - if (vol->target.format == VIR_STORAGE_FILE_PLOOP) - vol->type = VIR_STORAGE_VOL_PLOOP; - - if (vol->target.backingStore) { - ignore_value(virStorageBackendUpdateVolTargetInfo(VIR_STORAGE_VOL_FILE, - vol->target.backingStore, - false, - VIR_STORAGE_VOL_OPEN_DEFAULT, 0)); - /* If this failed, the backing file is currently unavailable, - * the capacity, allocation, owner, group and mode are unknown. - * An error message was raised, but we just continue. */ - } - - if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0) - goto cleanup; - } - if (direrr < 0) - goto cleanup; - VIR_DIR_CLOSE(dir); - vol = NULL; - - if (VIR_ALLOC(target)) - goto cleanup; - - if ((fd = open(pool->def->target.path, O_RDONLY)) < 0) { - virReportSystemError(errno, - _("cannot open path '%s'"), - pool->def->target.path); - goto cleanup; - } - - if (fstat(fd, &statbuf) < 0) { - virReportSystemError(errno, - _("cannot stat path '%s'"), - pool->def->target.path); - goto cleanup; - } - - if (virStorageBackendUpdateVolTargetInfoFD(target, fd, &statbuf) < 0) - goto cleanup; - - /* VolTargetInfoFD doesn't update capacity correctly for the pool case */ - if (statvfs(pool->def->target.path, &sb) < 0) { - virReportSystemError(errno, - _("cannot statvfs path '%s'"), - pool->def->target.path); - goto cleanup; - } - - pool->def->capacity = ((unsigned long long)sb.f_frsize * - (unsigned long long)sb.f_blocks); - pool->def->available = ((unsigned long long)sb.f_bfree * - (unsigned long long)sb.f_frsize); - pool->def->allocation = pool->def->capacity - pool->def->available; - - pool->def->target.perms.mode = target->perms->mode; - pool->def->target.perms.uid = target->perms->uid; - pool->def->target.perms.gid = target->perms->gid; - VIR_FREE(pool->def->target.perms.label); - if (VIR_STRDUP(pool->def->target.perms.label, target->perms->label) < 0) - goto cleanup; - - ret = 0; - cleanup: - VIR_DIR_CLOSE(dir); - VIR_FORCE_CLOSE(fd); - virStorageVolDefFree(vol); - virStorageSourceFree(target); - if (ret < 0) - virStoragePoolObjClearVols(pool); - return ret; -} - - -/** - * @conn connection to report errors against - * @pool storage pool to delete - * - * Delete a directory based storage pool - * - * Returns 0 on success, -1 on error - */ -static int -virStorageBackendFileSystemDelete(virConnectPtr conn ATTRIBUTE_UNUSED, - virStoragePoolObjPtr pool, - unsigned int flags) -{ - virCheckFlags(0, -1); - - /* XXX delete all vols first ? */ - - if (rmdir(pool->def->target.path) < 0) { - virReportSystemError(errno, - _("failed to remove pool '%s'"), - pool->def->target.path); + if (virStorageBackendBuildLocal(pool) < 0) return -1; - } + + if (flags != 0) + return virStorageBackendMakeFileSystem(pool, flags);
return 0; } @@ -1319,8 +966,8 @@ virStorageBackend virStorageBackendDirectory = {
.buildPool = virStorageBackendFileSystemBuild, .checkPool = virStorageBackendFileSystemCheck, - .refreshPool = virStorageBackendFileSystemRefresh, - .deletePool = virStorageBackendFileSystemDelete, + .refreshPool = virStorageBackendRefreshLocal, + .deletePool = virStorageBackendDeleteLocal, .buildVol = virStorageBackendFileSystemVolBuild, .buildVolFrom = virStorageBackendFileSystemVolBuildFrom, .createVol = virStorageBackendFileSystemVolCreate, @@ -1339,9 +986,9 @@ virStorageBackend virStorageBackendFileSystem = { .buildPool = virStorageBackendFileSystemBuild, .checkPool = virStorageBackendFileSystemCheck, .startPool = virStorageBackendFileSystemStart, - .refreshPool = virStorageBackendFileSystemRefresh, + .refreshPool = virStorageBackendRefreshLocal, .stopPool = virStorageBackendFileSystemStop, - .deletePool = virStorageBackendFileSystemDelete, + .deletePool = virStorageBackendDeleteLocal, .buildVol = virStorageBackendFileSystemVolBuild, .buildVolFrom = virStorageBackendFileSystemVolBuildFrom, .createVol = virStorageBackendFileSystemVolCreate, @@ -1359,9 +1006,9 @@ virStorageBackend virStorageBackendNetFileSystem = { .checkPool = virStorageBackendFileSystemCheck, .startPool = virStorageBackendFileSystemStart, .findPoolSources = virStorageBackendFileSystemNetFindPoolSources, - .refreshPool = virStorageBackendFileSystemRefresh, + .refreshPool = virStorageBackendRefreshLocal, .stopPool = virStorageBackendFileSystemStop, - .deletePool = virStorageBackendFileSystemDelete, + .deletePool = virStorageBackendDeleteLocal, .buildVol = virStorageBackendFileSystemVolBuild, .buildVolFrom = virStorageBackendFileSystemVolBuildFrom, .createVol = virStorageBackendFileSystemVolCreate, diff --git a/src/storage/storage_util.c b/src/storage/storage_util.c index e16c1a4..6c2678d 100644 --- a/src/storage/storage_util.c +++ b/src/storage/storage_util.c @@ -26,6 +26,7 @@ #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> +#include <sys/statvfs.h> #include <sys/param.h> #include <dirent.h> #include "dirname.h" @@ -1675,8 +1676,8 @@ virStorageBackendVolOpen(const char *path, struct stat *sb, /* virStorageIsPloop function checks whether given directory is ploop volume's * directory. */ -bool -virStorageBackendIsPloopDir(char *path) +static bool +storageBackendIsPloopDir(char *path) { bool ret = false; char *root = NULL; @@ -1702,9 +1703,9 @@ virStorageBackendIsPloopDir(char *path) * and etc. we need to perform virStorageBackendVolOpen and * virStorageBackendUpdateVolTargetFd once again. */ -int -virStorageBackendRedoPloopUpdate(virStorageSourcePtr target, struct stat *sb, - int *fd, unsigned int flags) +static int +storageBackendRedoPloopUpdate(virStorageSourcePtr target, struct stat *sb, + int *fd, unsigned int flags) { char *path = NULL; int ret = -1; @@ -1723,7 +1724,7 @@ virStorageBackendRedoPloopUpdate(virStorageSourcePtr target, struct stat *sb, }
/* - * virStorageBackendUpdateVolTargetInfo + * storageBackendUpdateVolTargetInfo * @voltype: Volume type * @target: target definition ptr of volume to update * @withBlockVolFormat: true if caller determined a block file @@ -1736,12 +1737,12 @@ virStorageBackendRedoPloopUpdate(virStorageSourcePtr target, struct stat *sb, * open error occurred. It is up to the caller to handle. A -2 may also * be returned if the caller passed a readflagsflag. */ -int -virStorageBackendUpdateVolTargetInfo(virStorageVolType voltype, - virStorageSourcePtr target, - bool withBlockVolFormat, - unsigned int openflags, - unsigned int readflags) +static int +storageBackendUpdateVolTargetInfo(virStorageVolType voltype, + virStorageSourcePtr target, + bool withBlockVolFormat, + unsigned int openflags, + unsigned int readflags) { int ret, fd = -1; struct stat sb; @@ -1758,9 +1759,9 @@ virStorageBackendUpdateVolTargetInfo(virStorageVolType voltype, if ((voltype == VIR_STORAGE_VOL_FILE || voltype == VIR_STORAGE_VOL_BLOCK) && target->format != VIR_STORAGE_FILE_NONE) { if (S_ISDIR(sb.st_mode)) { - if (virStorageBackendIsPloopDir(target->path)) { - if ((ret = virStorageBackendRedoPloopUpdate(target, &sb, &fd, - openflags)) < 0) + if (storageBackendIsPloopDir(target->path)) { + if ((ret = storageBackendRedoPloopUpdate(target, &sb, &fd, + openflags)) < 0) goto cleanup; target->format = VIR_STORAGE_FILE_PLOOP; } else { @@ -1826,19 +1827,19 @@ virStorageBackendUpdateVolInfo(virStorageVolDefPtr vol, { int ret;
- if ((ret = virStorageBackendUpdateVolTargetInfo(vol->type, - &vol->target, - withBlockVolFormat, - openflags, readflags)) < 0) + if ((ret = storageBackendUpdateVolTargetInfo(vol->type, + &vol->target, + withBlockVolFormat, + openflags, readflags)) < 0) return ret;
if (vol->target.backingStore && - (ret = virStorageBackendUpdateVolTargetInfo(VIR_STORAGE_VOL_FILE, - vol->target.backingStore, - withBlockVolFormat, - VIR_STORAGE_VOL_OPEN_DEFAULT | - VIR_STORAGE_VOL_OPEN_NOERROR, - readflags) < 0)) + (ret = storageBackendUpdateVolTargetInfo(VIR_STORAGE_VOL_FILE, + vol->target.backingStore, + withBlockVolFormat, + VIR_STORAGE_VOL_OPEN_DEFAULT | + VIR_STORAGE_VOL_OPEN_NOERROR, + readflags) < 0)) return ret;
return 0; @@ -2408,6 +2409,118 @@ virStorageBackendVolWipeLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
/** + * @pool: storage pool to build + * @dir_create_flags: flags for directory creation + * + * Common code to build a directory based storage pool + * + * Returns 0 on success, -1 on failure + */ +int +virStorageBackendBuildLocal(virStoragePoolObjPtr pool) +{ + int ret = -1; + char *parent = NULL; + char *p = NULL; + mode_t mode; + bool needs_create_as_uid; + unsigned int dir_create_flags; + + if (VIR_STRDUP(parent, pool->def->target.path) < 0) + goto cleanup; + if (!(p = strrchr(parent, '/'))) { + virReportError(VIR_ERR_INVALID_ARG, + _("path '%s' is not absolute"), + pool->def->target.path); + goto cleanup; + } + + if (p != parent) { + /* assure all directories in the path prior to the final dir + * exist, with default uid/gid/mode. */ + *p = '\0'; + if (virFileMakePath(parent) < 0) { + virReportSystemError(errno, _("cannot create path '%s'"), + parent); + goto cleanup; + } + } + + dir_create_flags = VIR_DIR_CREATE_ALLOW_EXIST; + needs_create_as_uid = (pool->def->type == VIR_STORAGE_POOL_NETFS); + mode = pool->def->target.perms.mode; + + if (mode == (mode_t) -1 && + (needs_create_as_uid || !virFileExists(pool->def->target.path))) + mode = VIR_STORAGE_DEFAULT_POOL_PERM_MODE; + if (needs_create_as_uid) + dir_create_flags |= VIR_DIR_CREATE_AS_UID; + + /* Now create the final dir in the path with the uid/gid/mode + * requested in the config. If the dir already exists, just set + * the perms. */ + if (virDirCreate(pool->def->target.path, + mode, + pool->def->target.perms.uid, + pool->def->target.perms.gid, + dir_create_flags) < 0) + goto cleanup; + + ret = 0; + + cleanup: + VIR_FREE(parent); + return ret; +} + + +int +virStorageBackendUmountLocal(virStoragePoolObjPtr pool) +{ + int ret = -1; + virCommandPtr cmd = virCommandNewArgList(UMOUNT, pool->def->target.path, + NULL); + + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virCommandFree(cmd); + return ret; +} + + +/** + * @conn connection to report errors against + * @pool storage pool to delete + * + * Delete a directory based storage pool + * + * Returns 0 on success, -1 on error + */ +int +virStorageBackendDeleteLocal(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool, + unsigned int flags) +{ + virCheckFlags(0, -1); + + /* XXX delete all vols first ? */ + + if (rmdir(pool->def->target.path) < 0) { + virReportSystemError(errno, + _("failed to remove pool '%s'"), + pool->def->target.path); + return -1; + } + + return 0; +} + + +/** * virStorageBackendFindGlusterPoolSources: * @host: host to detect volumes on * @pooltype: src->format is set to this value @@ -2919,6 +3032,263 @@ virStorageBackendDeviceIsEmpty(const char *devpath, }
+static int +storageBackendProbeTarget(virStorageSourcePtr target, + virStorageEncryptionPtr *encryption) +{ + int backingStoreFormat; + int fd = -1; + int ret = -1; + int rc; + virStorageSourcePtr meta = NULL; + struct stat sb; + + if (encryption) + *encryption = NULL; + + if ((rc = virStorageBackendVolOpen(target->path, &sb, + VIR_STORAGE_VOL_FS_PROBE_FLAGS)) < 0) + return rc; /* Take care to propagate rc, it is not always -1 */ + fd = rc; + + if (virStorageBackendUpdateVolTargetInfoFD(target, fd, &sb) < 0) + goto cleanup; + + if (S_ISDIR(sb.st_mode)) { + if (storageBackendIsPloopDir(target->path)) { + if (storageBackendRedoPloopUpdate(target, &sb, &fd, + VIR_STORAGE_VOL_FS_PROBE_FLAGS) < 0) + goto cleanup; + } else { + target->format = VIR_STORAGE_FILE_DIR; + ret = 0; + goto cleanup; + } + } + + if (!(meta = virStorageFileGetMetadataFromFD(target->path, + fd, + VIR_STORAGE_FILE_AUTO, + &backingStoreFormat))) + goto cleanup; + + if (meta->backingStoreRaw) { + if (!(target->backingStore = virStorageSourceNewFromBacking(meta))) + goto cleanup; + + target->backingStore->format = backingStoreFormat; + + /* XXX: Remote storage doesn't play nicely with volumes backed by + * remote storage. To avoid trouble, just fake the backing store is RAW + * and put the string from the metadata as the path of the target. */ + if (!virStorageSourceIsLocalStorage(target->backingStore)) { + virStorageSourceFree(target->backingStore); + + if (VIR_ALLOC(target->backingStore) < 0) + goto cleanup; + + target->backingStore->type = VIR_STORAGE_TYPE_NETWORK; + target->backingStore->path = meta->backingStoreRaw; + meta->backingStoreRaw = NULL; + target->backingStore->format = VIR_STORAGE_FILE_RAW; + } + + if (target->backingStore->format == VIR_STORAGE_FILE_AUTO) { + if ((rc = virStorageFileProbeFormat(target->backingStore->path, + -1, -1)) < 0) { + /* If the backing file is currently unavailable or is + * accessed via remote protocol only log an error, fake the + * format as RAW and continue. Returning -1 here would + * disable the whole storage pool, making it unavailable for + * even maintenance. */ + target->backingStore->format = VIR_STORAGE_FILE_RAW; + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot probe backing volume format: %s"), + target->backingStore->path); + } else { + target->backingStore->format = rc; + } + } + } + + target->format = meta->format; + + /* Default to success below this point */ + ret = 0; + + if (meta->capacity) + target->capacity = meta->capacity; + + if (encryption && meta->encryption) { + *encryption = meta->encryption; + meta->encryption = NULL; + + /* XXX ideally we'd fill in secret UUID here + * but we cannot guarantee 'conn' is non-NULL + * at this point in time :-( So we only fill + * in secrets when someone first queries a vol + */ + } + + virBitmapFree(target->features); + target->features = meta->features; + meta->features = NULL; + + if (meta->compat) { + VIR_FREE(target->compat); + target->compat = meta->compat; + meta->compat = NULL; + } + + cleanup: + VIR_FORCE_CLOSE(fd); + virStorageSourceFree(meta); + return ret; +} + + +/** + * Iterate over the pool's directory and enumerate all disk images + * within it. This is non-recursive. + */ +int +virStorageBackendRefreshLocal(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool) +{ + DIR *dir; + struct dirent *ent; + struct statvfs sb; + struct stat statbuf; + virStorageVolDefPtr vol = NULL; + virStorageSourcePtr target = NULL; + int direrr; + int fd = -1, ret = -1; + + if (virDirOpen(&dir, pool->def->target.path) < 0) + goto cleanup; + + while ((direrr = virDirRead(dir, &ent, pool->def->target.path)) > 0) { + int err; + + if (virStringHasControlChars(ent->d_name)) { + VIR_WARN("Ignoring file with control characters under '%s'", + pool->def->target.path); + continue; + } + + if (VIR_ALLOC(vol) < 0) + goto cleanup; + + if (VIR_STRDUP(vol->name, ent->d_name) < 0) + goto cleanup; + + vol->type = VIR_STORAGE_VOL_FILE; + vol->target.format = VIR_STORAGE_FILE_RAW; /* Real value is filled in during probe */ + if (virAsprintf(&vol->target.path, "%s/%s", + pool->def->target.path, + vol->name) == -1) + goto cleanup; + + if (VIR_STRDUP(vol->key, vol->target.path) < 0) + goto cleanup; + + if ((err = storageBackendProbeTarget(&vol->target, + &vol->target.encryption)) < 0) { + if (err == -2) { + /* Silently ignore non-regular files, + * eg 'lost+found', dangling symbolic link */ + virStorageVolDefFree(vol); + vol = NULL; + continue; + } else if (err == -3) { + /* The backing file is currently unavailable, its format is not + * explicitly specified, the probe to auto detect the format + * failed: continue with faked RAW format, since AUTO will + * break virStorageVolTargetDefFormat() generating the line + * <format type='...'/>. */ + } else { + goto cleanup; + } + } + + /* directory based volume */ + if (vol->target.format == VIR_STORAGE_FILE_DIR) + vol->type = VIR_STORAGE_VOL_DIR; + + if (vol->target.format == VIR_STORAGE_FILE_PLOOP) + vol->type = VIR_STORAGE_VOL_PLOOP; + + if (vol->target.backingStore) { + ignore_value(storageBackendUpdateVolTargetInfo(VIR_STORAGE_VOL_FILE, + vol->target.backingStore, + false, + VIR_STORAGE_VOL_OPEN_DEFAULT, 0)); + /* If this failed, the backing file is currently unavailable, + * the capacity, allocation, owner, group and mode are unknown. + * An error message was raised, but we just continue. */ + } + + if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0) + goto cleanup; + } + if (direrr < 0) + goto cleanup; + VIR_DIR_CLOSE(dir); + vol = NULL; + + if (VIR_ALLOC(target)) + goto cleanup; + + if ((fd = open(pool->def->target.path, O_RDONLY)) < 0) { + virReportSystemError(errno, + _("cannot open path '%s'"), + pool->def->target.path); + goto cleanup; + } + + if (fstat(fd, &statbuf) < 0) { + virReportSystemError(errno, + _("cannot stat path '%s'"), + pool->def->target.path); + goto cleanup; + } + + if (virStorageBackendUpdateVolTargetInfoFD(target, fd, &statbuf) < 0) + goto cleanup; + + /* VolTargetInfoFD doesn't update capacity correctly for the pool case */ + if (statvfs(pool->def->target.path, &sb) < 0) { + virReportSystemError(errno, + _("cannot statvfs path '%s'"), + pool->def->target.path); + goto cleanup; + } + + pool->def->capacity = ((unsigned long long)sb.f_frsize * + (unsigned long long)sb.f_blocks); + pool->def->available = ((unsigned long long)sb.f_bfree * + (unsigned long long)sb.f_frsize); + pool->def->allocation = pool->def->capacity - pool->def->available; + + pool->def->target.perms.mode = target->perms->mode; + pool->def->target.perms.uid = target->perms->uid; + pool->def->target.perms.gid = target->perms->gid; + VIR_FREE(pool->def->target.perms.label); + if (VIR_STRDUP(pool->def->target.perms.label, target->perms->label) < 0) + goto cleanup; + + ret = 0; + cleanup: + VIR_DIR_CLOSE(dir); + VIR_FORCE_CLOSE(fd); + virStorageVolDefFree(vol); + virStorageSourceFree(target); + if (ret < 0) + virStoragePoolObjClearVols(pool); + return ret; +} + + static char * virStorageBackendSCSISerial(const char *dev) { diff --git a/src/storage/storage_util.h b/src/storage/storage_util.h index e127381..f5a1b5b 100644 --- a/src/storage/storage_util.h +++ b/src/storage/storage_util.h @@ -49,20 +49,10 @@ int virStorageBackendCreatePloop(virConnectPtr conn, int virStoragePloopResize(virStorageVolDefPtr vol, unsigned long long capacity);
-int virStorageBackendRedoPloopUpdate(virStorageSourcePtr target, - struct stat *sb, int *fd, - unsigned int flags); -bool virStorageBackendIsPloopDir(char *path); - virStorageBackendBuildVolFrom virStorageBackendGetBuildVolFromFunction(virStorageVolDefPtr vol, virStorageVolDefPtr inputvol);
-int virStorageBackendFindGlusterPoolSources(const char *host, - int pooltype, - virStoragePoolSourceListPtr list, - bool report); - int virStorageBackendVolUploadLocal(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol, @@ -84,6 +74,23 @@ int virStorageBackendVolWipeLocal(virConnectPtr conn, unsigned int algorithm, unsigned int flags);
+/* Local/Common Storage Pool Backend APIs */ +int virStorageBackendBuildLocal(virStoragePoolObjPtr pool); + +int virStorageBackendUmountLocal(virStoragePoolObjPtr pool); + +int virStorageBackendDeleteLocal(virConnectPtr conn, + virStoragePoolObjPtr pool, + unsigned int flags); + +int virStorageBackendRefreshLocal(virConnectPtr conn, + virStoragePoolObjPtr pool); + +int virStorageBackendFindGlusterPoolSources(const char *host, + int pooltype, + virStoragePoolSourceListPtr list, + bool report); + bool virStorageBackendDeviceIsEmpty(const char *devpath, const char *format, bool writelabel); @@ -110,6 +117,11 @@ enum { # define VIR_STORAGE_VOL_OPEN_DEFAULT (VIR_STORAGE_VOL_OPEN_REG |\ VIR_STORAGE_VOL_OPEN_BLOCK)
+# define VIR_STORAGE_VOL_FS_OPEN_FLAGS (VIR_STORAGE_VOL_OPEN_DEFAULT | \ + VIR_STORAGE_VOL_OPEN_DIR) +# define VIR_STORAGE_VOL_FS_PROBE_FLAGS (VIR_STORAGE_VOL_FS_OPEN_FLAGS | \ + VIR_STORAGE_VOL_OPEN_NOERROR) + int virStorageBackendVolOpen(const char *path, struct stat *sb, unsigned int flags) ATTRIBUTE_RETURN_CHECK @@ -122,11 +134,6 @@ int virStorageBackendUpdateVolInfo(virStorageVolDefPtr vol, bool withBlockVolFormat, unsigned int openflags, unsigned int readflags); -int virStorageBackendUpdateVolTargetInfo(virStorageVolType voltype, - virStorageSourcePtr target, - bool withBlockVolFormat, - unsigned int openflags, - unsigned int readflags); int virStorageBackendUpdateVolTargetInfoFD(virStorageSourcePtr target, int fd, struct stat *sb);
ACK -- Best regards, Olga

John Ferlan wrote:
Move some pool functions to storage_util to create local/common helpers using the same naming syntax as the existing upload, download, and wipe virStorageBackend*Local API's.
In the process of doing so, found a few API's that can now become local to storage_util. In order to distinguish between local/external - I changed the names of the now local only ones from "virStorageBackend..." to just "storageBackend..."
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/storage/storage_backend_fs.c | 383 ++--------------------------------- src/storage/storage_util.c | 420 ++++++++++++++++++++++++++++++++++++--- src/storage/storage_util.h | 37 ++-- 3 files changed, 432 insertions(+), 408 deletions(-)
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c
...
+int +virStorageBackendUmountLocal(virStoragePoolObjPtr pool) +{ + int ret = -1; + virCommandPtr cmd = virCommandNewArgList(UMOUNT, pool->def->target.path, + NULL); + + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virCommandFree(cmd); + return ret; +}
This fails to build if the fs storage backend is not enabled: gmake[3]: Entering directory '/usr/home/novel/code/libvirt/src' CC storage/libvirt_driver_storage_impl_la-storage_util.lo storage/storage_util.c:2810:46: error: use of undeclared identifier 'UMOUNT' virCommandPtr cmd = virCommandNewArgList(UMOUNT, pool->def->target.path, ^ 1 error generated. gmake[3]: *** [Makefile:9325: storage/libvirt_driver_storage_impl_la-storage_util.lo] Error 1 Because UMOUNT is only checked in m4/virt-storage-fs.m4. So I guess it either needs to be moved back to storage_backend_fs.c (which is unlikely because I guess you moved that for a reason) or the UMOUNT check moved to some more generic place. Roman Bogorodskiy

On 01/26/2017 11:39 AM, Roman Bogorodskiy wrote:
John Ferlan wrote:
Move some pool functions to storage_util to create local/common helpers using the same naming syntax as the existing upload, download, and wipe virStorageBackend*Local API's.
In the process of doing so, found a few API's that can now become local to storage_util. In order to distinguish between local/external - I changed the names of the now local only ones from "virStorageBackend..." to just "storageBackend..."
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/storage/storage_backend_fs.c | 383 ++--------------------------------- src/storage/storage_util.c | 420 ++++++++++++++++++++++++++++++++++++--- src/storage/storage_util.h | 37 ++-- 3 files changed, 432 insertions(+), 408 deletions(-)
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c
...
+int +virStorageBackendUmountLocal(virStoragePoolObjPtr pool) +{ + int ret = -1; + virCommandPtr cmd = virCommandNewArgList(UMOUNT, pool->def->target.path, + NULL); + + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virCommandFree(cmd); + return ret; +}
This fails to build if the fs storage backend is not enabled:
gmake[3]: Entering directory '/usr/home/novel/code/libvirt/src' CC storage/libvirt_driver_storage_impl_la-storage_util.lo storage/storage_util.c:2810:46: error: use of undeclared identifier 'UMOUNT' virCommandPtr cmd = virCommandNewArgList(UMOUNT, pool->def->target.path, ^ 1 error generated. gmake[3]: *** [Makefile:9325: storage/libvirt_driver_storage_impl_la-storage_util.lo] Error 1
Because UMOUNT is only checked in m4/virt-storage-fs.m4. So I guess it either needs to be moved back to storage_backend_fs.c (which is unlikely because I guess you moved that for a reason) or the UMOUNT check moved to some more generic place.
Roman Bogorodskiy
Yep - our internal builds caught it too - just formulating a patch now and will send/push shortly. Sorry - John

Move all the volume functions to storage_util to create local/common helpers using the same naming syntax as the existing upload, download, and wipe virStorageBackend*Local API's. In the process of doing so, found more API's that can now become local to storage_util. In order to distinguish between local/external - I changed the names of the now local only ones from "virStorageBackend..." to just "storageBackend..." Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/storage/storage_backend_fs.c | 372 ++-------------------------- src/storage/storage_util.c | 511 ++++++++++++++++++++++++++++++++------- src/storage/storage_util.h | 44 ++-- 3 files changed, 465 insertions(+), 462 deletions(-) diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index 6f331d6..9710648 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -625,342 +625,6 @@ virStorageBackendFileSystemBuild(virConnectPtr conn ATTRIBUTE_UNUSED, } -/** - * Set up a volume definition to be added to a pool's volume list, but - * don't do any file creation or allocation. By separating the two processes, - * we allow allocation progress reporting (by polling the volume's 'info' - * function), and can drop the parent pool lock during the (slow) allocation. - */ -static int -virStorageBackendFileSystemVolCreate(virConnectPtr conn ATTRIBUTE_UNUSED, - virStoragePoolObjPtr pool, - virStorageVolDefPtr vol) -{ - - if (vol->target.format == VIR_STORAGE_FILE_DIR) - vol->type = VIR_STORAGE_VOL_DIR; - else if (vol->target.format == VIR_STORAGE_FILE_PLOOP) - vol->type = VIR_STORAGE_VOL_PLOOP; - else - vol->type = VIR_STORAGE_VOL_FILE; - - /* Volumes within a directory pools are not recursive; do not - * allow escape to ../ or a subdir */ - if (strchr(vol->name, '/')) { - virReportError(VIR_ERR_OPERATION_INVALID, - _("volume name '%s' cannot contain '/'"), vol->name); - return -1; - } - - VIR_FREE(vol->target.path); - if (virAsprintf(&vol->target.path, "%s/%s", - pool->def->target.path, - vol->name) == -1) - return -1; - - if (virFileExists(vol->target.path)) { - virReportError(VIR_ERR_OPERATION_INVALID, - _("volume target path '%s' already exists"), - vol->target.path); - return -1; - } - - VIR_FREE(vol->key); - return VIR_STRDUP(vol->key, vol->target.path); -} - -static int createFileDir(virConnectPtr conn ATTRIBUTE_UNUSED, - virStoragePoolObjPtr pool, - virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol, - unsigned int flags) -{ - int err; - - virCheckFlags(0, -1); - - if (inputvol) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", - _("cannot copy from volume to a directory volume")); - return -1; - } - - if (vol->target.backingStore) { - virReportError(VIR_ERR_NO_SUPPORT, "%s", - _("backing storage not supported for directories volumes")); - return -1; - } - - - if ((err = virDirCreate(vol->target.path, - (vol->target.perms->mode == (mode_t) -1 ? - VIR_STORAGE_DEFAULT_VOL_PERM_MODE : - vol->target.perms->mode), - vol->target.perms->uid, - vol->target.perms->gid, - (pool->def->type == VIR_STORAGE_POOL_NETFS - ? VIR_DIR_CREATE_AS_UID : 0))) < 0) { - return -1; - } - - return 0; -} - -static int -_virStorageBackendFileSystemVolBuild(virConnectPtr conn, - virStoragePoolObjPtr pool, - virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol, - unsigned int flags) -{ - virStorageBackendBuildVolFrom create_func; - - if (inputvol) { - if (vol->target.encryption != NULL) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - "%s", _("storage pool does not support " - "building encrypted volumes from " - "other volumes")); - return -1; - } - create_func = virStorageBackendGetBuildVolFromFunction(vol, - inputvol); - if (!create_func) - return -1; - } else if (vol->target.format == VIR_STORAGE_FILE_RAW && - vol->target.encryption == NULL) { - create_func = virStorageBackendCreateRaw; - } else if (vol->target.format == VIR_STORAGE_FILE_DIR) { - create_func = createFileDir; - } else if (vol->target.format == VIR_STORAGE_FILE_PLOOP) { - create_func = virStorageBackendCreatePloop; - } else { - create_func = virStorageBackendCreateQemuImg; - } - - if (create_func(conn, pool, vol, inputvol, flags) < 0) - return -1; - return 0; -} - -/** - * Allocate a new file as a volume. This is either done directly - * for raw/sparse files, or by calling qemu-img for - * special kinds of files - */ -static int -virStorageBackendFileSystemVolBuild(virConnectPtr conn, - virStoragePoolObjPtr pool, - virStorageVolDefPtr vol, - unsigned int flags) -{ - virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA | - VIR_STORAGE_VOL_CREATE_REFLINK, - -1); - - return _virStorageBackendFileSystemVolBuild(conn, pool, vol, NULL, flags); -} - -/* - * Create a storage vol using 'inputvol' as input - */ -static int -virStorageBackendFileSystemVolBuildFrom(virConnectPtr conn, - virStoragePoolObjPtr pool, - virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol, - unsigned int flags) -{ - virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA | - VIR_STORAGE_VOL_CREATE_REFLINK, - -1); - - return _virStorageBackendFileSystemVolBuild(conn, pool, vol, inputvol, flags); -} - -/** - * Remove a volume - no support for BLOCK and NETWORK yet - */ -static int -virStorageBackendFileSystemVolDelete(virConnectPtr conn ATTRIBUTE_UNUSED, - virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, - virStorageVolDefPtr vol, - unsigned int flags) -{ - virCheckFlags(0, -1); - - switch ((virStorageVolType) vol->type) { - case VIR_STORAGE_VOL_FILE: - case VIR_STORAGE_VOL_DIR: - if (virFileRemove(vol->target.path, vol->target.perms->uid, - vol->target.perms->gid) < 0) { - /* Silently ignore failures where the vol has already gone away */ - if (errno != ENOENT) { - if (vol->type == VIR_STORAGE_VOL_FILE) - virReportSystemError(errno, - _("cannot unlink file '%s'"), - vol->target.path); - else - virReportSystemError(errno, - _("cannot remove directory '%s'"), - vol->target.path); - return -1; - } - } - break; - case VIR_STORAGE_VOL_PLOOP: - if (virFileDeleteTree(vol->target.path) < 0) - return -1; - break; - case VIR_STORAGE_VOL_BLOCK: - case VIR_STORAGE_VOL_NETWORK: - case VIR_STORAGE_VOL_NETDIR: - case VIR_STORAGE_VOL_LAST: - virReportError(VIR_ERR_NO_SUPPORT, - _("removing block or network volumes is not supported: %s"), - vol->target.path); - return -1; - } - return 0; -} - - -/* virStorageBackendFileSystemLoadDefaultSecrets: - * @conn: Connection pointer to fetch secret - * @vol: volume being refreshed - * - * If the volume had a secret generated, we need to regenerate the - * encryption secret information - * - * Returns 0 if no secret or secret setup was successful, - * -1 on failures w/ error message set - */ -static int -virStorageBackendFileSystemLoadDefaultSecrets(virConnectPtr conn, - virStorageVolDefPtr vol) -{ - virSecretPtr sec; - virStorageEncryptionSecretPtr encsec = NULL; - - if (!vol->target.encryption || vol->target.encryption->nsecrets != 0) - return 0; - - /* The encryption secret for qcow2 and luks volumes use the path - * to the volume, so look for a secret with the path. If not found, - * then we cannot generate the secret after a refresh (or restart). - * This may be the case if someone didn't follow instructions and created - * a usage string that although matched with the secret usage string, - * didn't contain the path to the volume. We won't error in that case, - * but we also cannot find the secret. */ - if (!(sec = virSecretLookupByUsage(conn, VIR_SECRET_USAGE_TYPE_VOLUME, - vol->target.path))) - return 0; - - if (VIR_ALLOC_N(vol->target.encryption->secrets, 1) < 0 || - VIR_ALLOC(encsec) < 0) { - VIR_FREE(vol->target.encryption->secrets); - virObjectUnref(sec); - return -1; - } - - vol->target.encryption->nsecrets = 1; - vol->target.encryption->secrets[0] = encsec; - - encsec->type = VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE; - encsec->seclookupdef.type = VIR_SECRET_LOOKUP_TYPE_UUID; - virSecretGetUUID(sec, encsec->seclookupdef.u.uuid); - virObjectUnref(sec); - - return 0; -} - - -/** - * Update info about a volume's capacity/allocation - */ -static int -virStorageBackendFileSystemVolRefresh(virConnectPtr conn, - virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, - virStorageVolDefPtr vol) -{ - int ret; - - /* Refresh allocation / capacity / permissions info in case its changed */ - if ((ret = virStorageBackendUpdateVolInfo(vol, false, - VIR_STORAGE_VOL_FS_OPEN_FLAGS, - 0)) < 0) - return ret; - - /* Load any secrets if possible */ - return virStorageBackendFileSystemLoadDefaultSecrets(conn, vol); -} - -static int -virStorageBackendFilesystemResizeQemuImg(const char *path, - unsigned long long capacity) -{ - int ret = -1; - char *img_tool; - virCommandPtr cmd = NULL; - - img_tool = virFindFileInPath("qemu-img"); - if (!img_tool) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("unable to find qemu-img")); - return -1; - } - - /* Round capacity as qemu-img resize errors out on sizes which are not - * a multiple of 512 */ - capacity = VIR_ROUND_UP(capacity, 512); - - cmd = virCommandNew(img_tool); - virCommandAddArgList(cmd, "resize", path, NULL); - virCommandAddArgFormat(cmd, "%llu", capacity); - - ret = virCommandRun(cmd, NULL); - - VIR_FREE(img_tool); - virCommandFree(cmd); - - return ret; -} - -/** - * Resize a volume - */ -static int -virStorageBackendFileSystemVolResize(virConnectPtr conn ATTRIBUTE_UNUSED, - virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, - virStorageVolDefPtr vol, - unsigned long long capacity, - unsigned int flags) -{ - virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE | - VIR_STORAGE_VOL_RESIZE_SHRINK, -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->target.allocation, pre_allocate); - } else if (vol->target.format == VIR_STORAGE_FILE_PLOOP) { - return virStoragePloopResize(vol, capacity); - } else { - if (pre_allocate) { - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("preallocate is only supported for raw " - "type volume")); - return -1; - } - - return virStorageBackendFilesystemResizeQemuImg(vol->target.path, - capacity); - } -} - - virStorageBackend virStorageBackendDirectory = { .type = VIR_STORAGE_POOL_DIR, @@ -968,12 +632,12 @@ virStorageBackend virStorageBackendDirectory = { .checkPool = virStorageBackendFileSystemCheck, .refreshPool = virStorageBackendRefreshLocal, .deletePool = virStorageBackendDeleteLocal, - .buildVol = virStorageBackendFileSystemVolBuild, - .buildVolFrom = virStorageBackendFileSystemVolBuildFrom, - .createVol = virStorageBackendFileSystemVolCreate, - .refreshVol = virStorageBackendFileSystemVolRefresh, - .deleteVol = virStorageBackendFileSystemVolDelete, - .resizeVol = virStorageBackendFileSystemVolResize, + .buildVol = virStorageBackendVolBuildLocal, + .buildVolFrom = virStorageBackendVolBuildFromLocal, + .createVol = virStorageBackendVolCreateLocal, + .refreshVol = virStorageBackendVolRefreshLocal, + .deleteVol = virStorageBackendVolDeleteLocal, + .resizeVol = virStorageBackendVolResizeLocal, .uploadVol = virStorageBackendVolUploadLocal, .downloadVol = virStorageBackendVolDownloadLocal, .wipeVol = virStorageBackendVolWipeLocal, @@ -989,12 +653,12 @@ virStorageBackend virStorageBackendFileSystem = { .refreshPool = virStorageBackendRefreshLocal, .stopPool = virStorageBackendFileSystemStop, .deletePool = virStorageBackendDeleteLocal, - .buildVol = virStorageBackendFileSystemVolBuild, - .buildVolFrom = virStorageBackendFileSystemVolBuildFrom, - .createVol = virStorageBackendFileSystemVolCreate, - .refreshVol = virStorageBackendFileSystemVolRefresh, - .deleteVol = virStorageBackendFileSystemVolDelete, - .resizeVol = virStorageBackendFileSystemVolResize, + .buildVol = virStorageBackendVolBuildLocal, + .buildVolFrom = virStorageBackendVolBuildFromLocal, + .createVol = virStorageBackendVolCreateLocal, + .refreshVol = virStorageBackendVolRefreshLocal, + .deleteVol = virStorageBackendVolDeleteLocal, + .resizeVol = virStorageBackendVolResizeLocal, .uploadVol = virStorageBackendVolUploadLocal, .downloadVol = virStorageBackendVolDownloadLocal, .wipeVol = virStorageBackendVolWipeLocal, @@ -1009,12 +673,12 @@ virStorageBackend virStorageBackendNetFileSystem = { .refreshPool = virStorageBackendRefreshLocal, .stopPool = virStorageBackendFileSystemStop, .deletePool = virStorageBackendDeleteLocal, - .buildVol = virStorageBackendFileSystemVolBuild, - .buildVolFrom = virStorageBackendFileSystemVolBuildFrom, - .createVol = virStorageBackendFileSystemVolCreate, - .refreshVol = virStorageBackendFileSystemVolRefresh, - .deleteVol = virStorageBackendFileSystemVolDelete, - .resizeVol = virStorageBackendFileSystemVolResize, + .buildVol = virStorageBackendVolBuildLocal, + .buildVolFrom = virStorageBackendVolBuildFromLocal, + .createVol = virStorageBackendVolCreateLocal, + .refreshVol = virStorageBackendVolRefreshLocal, + .deleteVol = virStorageBackendVolDeleteLocal, + .resizeVol = virStorageBackendVolResizeLocal, .uploadVol = virStorageBackendVolUploadLocal, .downloadVol = virStorageBackendVolDownloadLocal, .wipeVol = virStorageBackendVolWipeLocal, diff --git a/src/storage/storage_util.c b/src/storage/storage_util.c index 6c2678d..fbe1844 100644 --- a/src/storage/storage_util.c +++ b/src/storage/storage_util.c @@ -222,11 +222,11 @@ virStorageBackendCopyToFD(virStorageVolDefPtr vol, } static int -virStorageBackendCreateBlockFrom(virConnectPtr conn ATTRIBUTE_UNUSED, - virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, - virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol, - unsigned int flags) +storageBackendCreateBlockFrom(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, + virStorageVolDefPtr vol, + virStorageVolDefPtr inputvol, + unsigned int flags) { int fd = -1; int ret = -1; @@ -389,12 +389,12 @@ createRawFile(int fd, virStorageVolDefPtr vol, return ret; } -int -virStorageBackendCreateRaw(virConnectPtr conn ATTRIBUTE_UNUSED, - virStoragePoolObjPtr pool, - virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol, - unsigned int flags) +static int +storageBackendCreateRaw(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + virStorageVolDefPtr inputvol, + unsigned int flags) { int ret = -1; int fd = -1; @@ -692,12 +692,12 @@ virStorageBackendCreateExecCommand(virStoragePoolObjPtr pool, /* Create ploop directory with ploop image and DiskDescriptor.xml * if function fails to create image file the directory will be deleted.*/ -int -virStorageBackendCreatePloop(virConnectPtr conn ATTRIBUTE_UNUSED, - virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, - virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol, - unsigned int flags) +static int +storageBackendCreatePloop(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, + virStorageVolDefPtr vol, + virStorageVolDefPtr inputvol, + unsigned int flags) { int ret = -1; virCommandPtr cmd = NULL; @@ -767,9 +767,10 @@ virStorageBackendCreatePloop(virConnectPtr conn ATTRIBUTE_UNUSED, return ret; } -int -virStoragePloopResize(virStorageVolDefPtr vol, - unsigned long long capacity) + +static int +storagePloopResize(virStorageVolDefPtr vol, + unsigned long long capacity) { int ret = -1; virCommandPtr cmd = NULL; @@ -875,9 +876,9 @@ struct _virStorageBackendQemuImgInfo { static int -virStorageBackendCreateQemuImgOpts(virStorageEncryptionInfoDefPtr enc, - char **opts, - struct _virStorageBackendQemuImgInfo info) +storageBackendCreateQemuImgOpts(virStorageEncryptionInfoDefPtr enc, + char **opts, + struct _virStorageBackendQemuImgInfo info) { virBuffer buf = VIR_BUFFER_INITIALIZER; @@ -927,7 +928,7 @@ virStorageBackendCreateQemuImgOpts(virStorageEncryptionInfoDefPtr enc, } -/* virStorageBackendCreateQemuImgCheckEncryption: +/* storageBackendCreateQemuImgCheckEncryption: * @format: format of file found * @conn: pointer to connection * @vol: pointer to volume def @@ -937,10 +938,10 @@ virStorageBackendCreateQemuImgOpts(virStorageEncryptionInfoDefPtr enc, * Returns 0 on success, -1 on failure w/ error set */ static int -virStorageBackendCreateQemuImgCheckEncryption(int format, - const char *type, - virConnectPtr conn, - virStorageVolDefPtr vol) +storageBackendCreateQemuImgCheckEncryption(int format, + const char *type, + virConnectPtr conn, + virStorageVolDefPtr vol) { virStorageEncryptionPtr enc = vol->target.encryption; @@ -996,8 +997,8 @@ virStorageBackendCreateQemuImgCheckEncryption(int format, static int -virStorageBackendCreateQemuImgSetInput(virStorageVolDefPtr inputvol, - struct _virStorageBackendQemuImgInfo *info) +storageBackendCreateQemuImgSetInput(virStorageVolDefPtr inputvol, + struct _virStorageBackendQemuImgInfo *info) { if (!(info->inputPath = inputvol->target.path)) { virReportError(VIR_ERR_INVALID_ARG, "%s", @@ -1021,10 +1022,10 @@ virStorageBackendCreateQemuImgSetInput(virStorageVolDefPtr inputvol, static int -virStorageBackendCreateQemuImgSetBacking(virStoragePoolObjPtr pool, - virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol, - struct _virStorageBackendQemuImgInfo *info) +storageBackendCreateQemuImgSetBacking(virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + virStorageVolDefPtr inputvol, + struct _virStorageBackendQemuImgInfo *info) { int accessRetCode = -1; char *absolutePath = NULL; @@ -1086,10 +1087,10 @@ virStorageBackendCreateQemuImgSetBacking(virStoragePoolObjPtr pool, static int -virStorageBackendCreateQemuImgSetOptions(virCommandPtr cmd, - int imgformat, - virStorageEncryptionInfoDefPtr enc, - struct _virStorageBackendQemuImgInfo info) +storageBackendCreateQemuImgSetOptions(virCommandPtr cmd, + int imgformat, + virStorageEncryptionInfoDefPtr enc, + struct _virStorageBackendQemuImgInfo info) { char *opts = NULL; @@ -1097,7 +1098,7 @@ virStorageBackendCreateQemuImgSetOptions(virCommandPtr cmd, imgformat >= QEMU_IMG_BACKING_FORMAT_OPTIONS_COMPAT) info.compat = "0.10"; - if (virStorageBackendCreateQemuImgOpts(enc, &opts, info) < 0) + if (storageBackendCreateQemuImgOpts(enc, &opts, info) < 0) return -1; if (opts) virCommandAddArgList(cmd, "-o", opts, NULL); @@ -1113,9 +1114,9 @@ virStorageBackendCreateQemuImgSetOptions(virCommandPtr cmd, * NB: format=raw is assumed */ static int -virStorageBackendCreateQemuImgSecretObject(virCommandPtr cmd, - virStorageVolDefPtr vol, - struct _virStorageBackendQemuImgInfo *info) +storageBackendCreateQemuImgSecretObject(virCommandPtr cmd, + virStorageVolDefPtr vol, + struct _virStorageBackendQemuImgInfo *info) { virBuffer buf = VIR_BUFFER_INITIALIZER; char *commandStr = NULL; @@ -1218,17 +1219,16 @@ virStorageBackendCreateQemuImgCmdFromVol(virConnectPtr conn, } if (inputvol && - virStorageBackendCreateQemuImgSetInput(inputvol, &info) < 0) + storageBackendCreateQemuImgSetInput(inputvol, &info) < 0) return NULL; if (vol->target.backingStore && - virStorageBackendCreateQemuImgSetBacking(pool, vol, inputvol, - &info) < 0) + storageBackendCreateQemuImgSetBacking(pool, vol, inputvol, &info) < 0) return NULL; if (info.encryption && - virStorageBackendCreateQemuImgCheckEncryption(info.format, type, - conn, vol) < 0) + storageBackendCreateQemuImgCheckEncryption(info.format, type, + conn, vol) < 0) return NULL; @@ -1253,7 +1253,7 @@ virStorageBackendCreateQemuImgCmdFromVol(virConnectPtr conn, if (info.format == VIR_STORAGE_FILE_RAW && vol->target.encryption != NULL && vol->target.encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS) { - if (virStorageBackendCreateQemuImgSecretObject(cmd, vol, &info) < 0) { + if (storageBackendCreateQemuImgSecretObject(cmd, vol, &info) < 0) { VIR_FREE(info.secretAlias); virCommandFree(cmd); return NULL; @@ -1261,8 +1261,7 @@ virStorageBackendCreateQemuImgCmdFromVol(virConnectPtr conn, enc = &vol->target.encryption->encinfo; } - if (virStorageBackendCreateQemuImgSetOptions(cmd, imgformat, - enc, info) < 0) { + if (storageBackendCreateQemuImgSetOptions(cmd, imgformat, enc, info) < 0) { VIR_FREE(info.secretAlias); virCommandFree(cmd); return NULL; @@ -1280,9 +1279,9 @@ virStorageBackendCreateQemuImgCmdFromVol(virConnectPtr conn, static char * -virStorageBackendCreateQemuImgSecretPath(virConnectPtr conn, - virStoragePoolObjPtr pool, - virStorageVolDefPtr vol) +storageBackendCreateQemuImgSecretPath(virConnectPtr conn, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol) { virStorageEncryptionPtr enc = vol->target.encryption; char *secretPath = NULL; @@ -1349,12 +1348,12 @@ virStorageBackendCreateQemuImgSecretPath(virConnectPtr conn, } -int -virStorageBackendCreateQemuImg(virConnectPtr conn, - virStoragePoolObjPtr pool, - virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol, - unsigned int flags) +static int +storageBackendCreateQemuImg(virConnectPtr conn, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + virStorageVolDefPtr inputvol, + unsigned int flags) { int ret = -1; char *create_tool; @@ -1380,7 +1379,7 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, vol->target.encryption && vol->target.encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS) { if (!(secretPath = - virStorageBackendCreateQemuImgSecretPath(conn, pool, vol))) + storageBackendCreateQemuImgSecretPath(conn, pool, vol))) goto cleanup; } @@ -1418,15 +1417,15 @@ virStorageBackendGetBuildVolFromFunction(virStorageVolDefPtr vol, (inputvol->type == VIR_STORAGE_VOL_FILE && (inputvol->target.format != VIR_STORAGE_FILE_RAW || inputvol->target.encryption != NULL))) { - return virStorageBackendCreateQemuImg; + return storageBackendCreateQemuImg; } if (vol->type == VIR_STORAGE_VOL_PLOOP) - return virStorageBackendCreatePloop; + return storageBackendCreatePloop; if (vol->type == VIR_STORAGE_VOL_BLOCK) - return virStorageBackendCreateBlockFrom; + return storageBackendCreateBlockFrom; else - return virStorageBackendCreateRaw; + return storageBackendCreateRaw; } @@ -2008,6 +2007,340 @@ virStorageBackendStablePath(virStoragePoolObjPtr pool, return stablepath; } +/* Common/Local File System/Directory Volume API's */ +static int +createFileDir(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + virStorageVolDefPtr inputvol, + unsigned int flags) +{ + int err; + + virCheckFlags(0, -1); + + if (inputvol) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("cannot copy from volume to a directory volume")); + return -1; + } + + if (vol->target.backingStore) { + virReportError(VIR_ERR_NO_SUPPORT, "%s", + _("backing storage not supported for directories volumes")); + return -1; + } + + + if ((err = virDirCreate(vol->target.path, + (vol->target.perms->mode == (mode_t) -1 ? + VIR_STORAGE_DEFAULT_VOL_PERM_MODE : + vol->target.perms->mode), + vol->target.perms->uid, + vol->target.perms->gid, + (pool->def->type == VIR_STORAGE_POOL_NETFS + ? VIR_DIR_CREATE_AS_UID : 0))) < 0) { + return -1; + } + + return 0; +} + + +/** + * Set up a volume definition to be added to a pool's volume list, but + * don't do any file creation or allocation. By separating the two processes, + * we allow allocation progress reporting (by polling the volume's 'info' + * function), and can drop the parent pool lock during the (slow) allocation. + */ +int +virStorageBackendVolCreateLocal(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol) +{ + if (vol->target.format == VIR_STORAGE_FILE_DIR) + vol->type = VIR_STORAGE_VOL_DIR; + else if (vol->target.format == VIR_STORAGE_FILE_PLOOP) + vol->type = VIR_STORAGE_VOL_PLOOP; + else + vol->type = VIR_STORAGE_VOL_FILE; + + /* Volumes within a directory pools are not recursive; do not + * allow escape to ../ or a subdir */ + if (strchr(vol->name, '/')) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("volume name '%s' cannot contain '/'"), vol->name); + return -1; + } + + VIR_FREE(vol->target.path); + if (virAsprintf(&vol->target.path, "%s/%s", + pool->def->target.path, + vol->name) == -1) + return -1; + + if (virFileExists(vol->target.path)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("volume target path '%s' already exists"), + vol->target.path); + return -1; + } + + VIR_FREE(vol->key); + return VIR_STRDUP(vol->key, vol->target.path); +} + + +static int +storageBackendVolBuildLocal(virConnectPtr conn, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + virStorageVolDefPtr inputvol, + unsigned int flags) +{ + virStorageBackendBuildVolFrom create_func; + + if (inputvol) { + if (vol->target.encryption != NULL) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + "%s", _("storage pool does not support " + "building encrypted volumes from " + "other volumes")); + return -1; + } + if (!(create_func = + virStorageBackendGetBuildVolFromFunction(vol, inputvol))) + return -1; + } else if (vol->target.format == VIR_STORAGE_FILE_RAW && + vol->target.encryption == NULL) { + create_func = storageBackendCreateRaw; + } else if (vol->target.format == VIR_STORAGE_FILE_DIR) { + create_func = createFileDir; + } else if (vol->target.format == VIR_STORAGE_FILE_PLOOP) { + create_func = storageBackendCreatePloop; + } else { + create_func = storageBackendCreateQemuImg; + } + + if (create_func(conn, pool, vol, inputvol, flags) < 0) + return -1; + return 0; +} + + +/** + * Allocate a new file as a volume. This is either done directly + * for raw/sparse files, or by calling qemu-img for + * special kinds of files + */ +int +virStorageBackendVolBuildLocal(virConnectPtr conn, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + unsigned int flags) +{ + return storageBackendVolBuildLocal(conn, pool, vol, NULL, flags); +} + + +/* + * Create a storage vol using 'inputvol' as input + */ +int +virStorageBackendVolBuildFromLocal(virConnectPtr conn, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + virStorageVolDefPtr inputvol, + unsigned int flags) +{ + return storageBackendVolBuildLocal(conn, pool, vol, inputvol, flags); +} + + +/** + * Remove a volume - no support for BLOCK and NETWORK yet + */ +int +virStorageBackendVolDeleteLocal(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, + virStorageVolDefPtr vol, + unsigned int flags) +{ + virCheckFlags(0, -1); + + switch ((virStorageVolType) vol->type) { + case VIR_STORAGE_VOL_FILE: + case VIR_STORAGE_VOL_DIR: + if (virFileRemove(vol->target.path, vol->target.perms->uid, + vol->target.perms->gid) < 0) { + /* Silently ignore failures where the vol has already gone away */ + if (errno != ENOENT) { + if (vol->type == VIR_STORAGE_VOL_FILE) + virReportSystemError(errno, + _("cannot unlink file '%s'"), + vol->target.path); + else + virReportSystemError(errno, + _("cannot remove directory '%s'"), + vol->target.path); + return -1; + } + } + break; + case VIR_STORAGE_VOL_PLOOP: + if (virFileDeleteTree(vol->target.path) < 0) + return -1; + break; + case VIR_STORAGE_VOL_BLOCK: + case VIR_STORAGE_VOL_NETWORK: + case VIR_STORAGE_VOL_NETDIR: + case VIR_STORAGE_VOL_LAST: + virReportError(VIR_ERR_NO_SUPPORT, + _("removing block or network volumes is not supported: %s"), + vol->target.path); + return -1; + } + return 0; +} + + +/* storageBackendLoadDefaultSecrets: + * @conn: Connection pointer to fetch secret + * @vol: volume being refreshed + * + * If the volume had a secret generated, we need to regenerate the + * encryption secret information + * + * Returns 0 if no secret or secret setup was successful, + * -1 on failures w/ error message set + */ +static int +storageBackendLoadDefaultSecrets(virConnectPtr conn, + virStorageVolDefPtr vol) +{ + virSecretPtr sec; + virStorageEncryptionSecretPtr encsec = NULL; + + if (!vol->target.encryption || vol->target.encryption->nsecrets != 0) + return 0; + + /* The encryption secret for qcow2 and luks volumes use the path + * to the volume, so look for a secret with the path. If not found, + * then we cannot generate the secret after a refresh (or restart). + * This may be the case if someone didn't follow instructions and created + * a usage string that although matched with the secret usage string, + * didn't contain the path to the volume. We won't error in that case, + * but we also cannot find the secret. */ + if (!(sec = virSecretLookupByUsage(conn, VIR_SECRET_USAGE_TYPE_VOLUME, + vol->target.path))) + return 0; + + if (VIR_ALLOC_N(vol->target.encryption->secrets, 1) < 0 || + VIR_ALLOC(encsec) < 0) { + VIR_FREE(vol->target.encryption->secrets); + virObjectUnref(sec); + return -1; + } + + vol->target.encryption->nsecrets = 1; + vol->target.encryption->secrets[0] = encsec; + + encsec->type = VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE; + encsec->seclookupdef.type = VIR_SECRET_LOOKUP_TYPE_UUID; + virSecretGetUUID(sec, encsec->seclookupdef.u.uuid); + virObjectUnref(sec); + + return 0; +} + + +/** + * Update info about a volume's capacity/allocation + */ +int +virStorageBackendVolRefreshLocal(virConnectPtr conn, + virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, + virStorageVolDefPtr vol) +{ + int ret; + + /* Refresh allocation / capacity / permissions info in case its changed */ + if ((ret = virStorageBackendUpdateVolInfo(vol, false, + VIR_STORAGE_VOL_FS_OPEN_FLAGS, + 0)) < 0) + return ret; + + /* Load any secrets if possible */ + return storageBackendLoadDefaultSecrets(conn, vol); +} + + +static int +storageBackendResizeQemuImg(const char *path, + unsigned long long capacity) +{ + int ret = -1; + char *img_tool; + virCommandPtr cmd = NULL; + + img_tool = virFindFileInPath("qemu-img"); + if (!img_tool) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("unable to find qemu-img")); + return -1; + } + + /* Round capacity as qemu-img resize errors out on sizes which are not + * a multiple of 512 */ + capacity = VIR_ROUND_UP(capacity, 512); + + cmd = virCommandNew(img_tool); + virCommandAddArgList(cmd, "resize", path, NULL); + virCommandAddArgFormat(cmd, "%llu", capacity); + + ret = virCommandRun(cmd, NULL); + + VIR_FREE(img_tool); + virCommandFree(cmd); + + return ret; +} + + +/** + * Resize a volume + */ +int +virStorageBackendVolResizeLocal(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, + virStorageVolDefPtr vol, + unsigned long long capacity, + unsigned int flags) +{ + virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE | + VIR_STORAGE_VOL_RESIZE_SHRINK, -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->target.allocation, pre_allocate); + } else if (vol->target.format == VIR_STORAGE_FILE_PLOOP) { + return storagePloopResize(vol, capacity); + } else { + if (pre_allocate) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("preallocate is only supported for raw " + "type volume")); + return -1; + } + + return storageBackendResizeQemuImg(vol->target.path, capacity); + } +} + + /* * Check whether the ploop image has snapshots. * return: -1 - failed to check @@ -2015,7 +2348,7 @@ virStorageBackendStablePath(virStoragePoolObjPtr pool, * 1 - at least one snapshot */ static int -virStorageBackendPloopHasSnapshots(char *path) +storageBackendPloopHasSnapshots(char *path) { virCommandPtr cmd = NULL; char *output = NULL; @@ -2049,6 +2382,7 @@ virStorageBackendPloopHasSnapshots(char *path) return ret; } + int virStorageBackendVolUploadLocal(virConnectPtr conn ATTRIBUTE_UNUSED, virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, @@ -2070,7 +2404,7 @@ virStorageBackendVolUploadLocal(virConnectPtr conn ATTRIBUTE_UNUSED, * when volUpload is fully finished. */ if (vol->target.format == VIR_STORAGE_FILE_PLOOP) { /* Fail if the volume contains snapshots or we failed to check it.*/ - has_snap = virStorageBackendPloopHasSnapshots(vol->target.path); + has_snap = storageBackendPloopHasSnapshots(vol->target.path); if (has_snap < 0) { goto cleanup; } else if (!has_snap) { @@ -2111,7 +2445,7 @@ virStorageBackendVolDownloadLocal(virConnectPtr conn ATTRIBUTE_UNUSED, virCheckFlags(0, -1); if (vol->target.format == VIR_STORAGE_FILE_PLOOP) { - has_snap = virStorageBackendPloopHasSnapshots(vol->target.path); + has_snap = storageBackendPloopHasSnapshots(vol->target.path); if (has_snap < 0) { goto cleanup; } else if (!has_snap) { @@ -2149,9 +2483,9 @@ virStorageBackendVolDownloadLocal(virConnectPtr conn ATTRIBUTE_UNUSED, * appear as if it were zero-filled. */ static int -virStorageBackendVolZeroSparseFileLocal(const char *path, - off_t size, - int fd) +storageBackendVolZeroSparseFileLocal(const char *path, + off_t size, + int fd) { if (ftruncate(fd, 0) < 0) { virReportSystemError(errno, @@ -2174,10 +2508,10 @@ virStorageBackendVolZeroSparseFileLocal(const char *path, static int -virStorageBackendWipeLocal(const char *path, - int fd, - unsigned long long wipe_len, - size_t writebuf_length) +storageBackendWipeLocal(const char *path, + int fd, + unsigned long long wipe_len, + size_t writebuf_length) { int ret = -1, written = 0; unsigned long long remaining = 0; @@ -2232,9 +2566,9 @@ virStorageBackendWipeLocal(const char *path, static int -virStorageBackendVolWipeLocalFile(const char *path, - unsigned int algorithm, - unsigned long long allocation) +storageBackendVolWipeLocalFile(const char *path, + unsigned int algorithm, + unsigned long long allocation) { int ret = -1, fd = -1; const char *alg_char = NULL; @@ -2307,12 +2641,9 @@ virStorageBackendVolWipeLocalFile(const char *path, ret = 0; } else { if (S_ISREG(st.st_mode) && st.st_blocks < (st.st_size / DEV_BSIZE)) { - ret = virStorageBackendVolZeroSparseFileLocal(path, st.st_size, fd); + ret = storageBackendVolZeroSparseFileLocal(path, st.st_size, fd); } else { - ret = virStorageBackendWipeLocal(path, - fd, - allocation, - st.st_blksize); + ret = storageBackendWipeLocal(path, fd, allocation, st.st_blksize); } if (ret < 0) goto cleanup; @@ -2326,8 +2657,8 @@ virStorageBackendVolWipeLocalFile(const char *path, static int -virStorageBackendVolWipePloop(virStorageVolDefPtr vol, - unsigned int algorithm) +storageBackendVolWipePloop(virStorageVolDefPtr vol, + unsigned int algorithm) { virCommandPtr cmd = NULL; char *target_path = NULL; @@ -2349,9 +2680,8 @@ virStorageBackendVolWipePloop(virStorageVolDefPtr vol, if (virAsprintf(&disk_desc, "%s/DiskDescriptor.xml", vol->target.path) < 0) goto cleanup; - if (virStorageBackendVolWipeLocalFile(target_path, - algorithm, - vol->target.allocation) < 0) + if (storageBackendVolWipeLocalFile(target_path, algorithm, + vol->target.allocation) < 0) goto cleanup; if (virFileRemove(disk_desc, 0, 0) < 0) { @@ -2397,11 +2727,10 @@ virStorageBackendVolWipeLocal(virConnectPtr conn ATTRIBUTE_UNUSED, vol->target.path, algorithm); if (vol->target.format == VIR_STORAGE_FILE_PLOOP) { - ret = virStorageBackendVolWipePloop(vol, algorithm); + ret = storageBackendVolWipePloop(vol, algorithm); } else { - ret = virStorageBackendVolWipeLocalFile(vol->target.path, - algorithm, - vol->target.allocation); + ret = storageBackendVolWipeLocalFile(vol->target.path, algorithm, + vol->target.allocation); } return ret; diff --git a/src/storage/storage_util.h b/src/storage/storage_util.h index f5a1b5b..49df530 100644 --- a/src/storage/storage_util.h +++ b/src/storage/storage_util.h @@ -28,30 +28,39 @@ # include "storage_backend.h" /* File creation/cloning functions used for cloning between backends */ -int virStorageBackendCreateRaw(virConnectPtr conn, - virStoragePoolObjPtr pool, - virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol, - unsigned int flags); +virStorageBackendBuildVolFrom +virStorageBackendGetBuildVolFromFunction(virStorageVolDefPtr vol, + virStorageVolDefPtr inputvol); + +int virStorageBackendVolCreateLocal(virConnectPtr conn, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol); -int virStorageBackendCreateQemuImg(virConnectPtr conn, +int virStorageBackendVolBuildLocal(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol, unsigned int flags); -int virStorageBackendCreatePloop(virConnectPtr conn, - virStoragePoolObjPtr pool, - virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol, - unsigned int flags); +int virStorageBackendVolBuildFromLocal(virConnectPtr conn, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + virStorageVolDefPtr inputvol, + unsigned int flags); + +int virStorageBackendVolDeleteLocal(virConnectPtr conn, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + unsigned int flags); -int virStoragePloopResize(virStorageVolDefPtr vol, - unsigned long long capacity); +int virStorageBackendVolRefreshLocal(virConnectPtr conn, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol); -virStorageBackendBuildVolFrom -virStorageBackendGetBuildVolFromFunction(virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol); +int virStorageBackendVolResizeLocal(virConnectPtr conn, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + unsigned long long capacity, + unsigned int flags); int virStorageBackendVolUploadLocal(virConnectPtr conn, virStoragePoolObjPtr pool, @@ -60,6 +69,7 @@ int virStorageBackendVolUploadLocal(virConnectPtr conn, unsigned long long offset, unsigned long long len, unsigned int flags); + int virStorageBackendVolDownloadLocal(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol, -- 2.7.4

On 21/01/17 20:23, John Ferlan wrote:
Move all the volume functions to storage_util to create local/common helpers using the same naming syntax as the existing upload, download, and wipe virStorageBackend*Local API's.
In the process of doing so, found more API's that can now become local to storage_util. In order to distinguish between local/external - I changed the names of the now local only ones from "virStorageBackend..." to just "storageBackend..."
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/storage/storage_backend_fs.c | 372 ++-------------------------- src/storage/storage_util.c | 511 ++++++++++++++++++++++++++++++++------- src/storage/storage_util.h | 44 ++-- 3 files changed, 465 insertions(+), 462 deletions(-)
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index 6f331d6..9710648 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -625,342 +625,6 @@ virStorageBackendFileSystemBuild(virConnectPtr conn ATTRIBUTE_UNUSED, }
-/** - * Set up a volume definition to be added to a pool's volume list, but - * don't do any file creation or allocation. By separating the two processes, - * we allow allocation progress reporting (by polling the volume's 'info' - * function), and can drop the parent pool lock during the (slow) allocation. - */ -static int -virStorageBackendFileSystemVolCreate(virConnectPtr conn ATTRIBUTE_UNUSED, - virStoragePoolObjPtr pool, - virStorageVolDefPtr vol) -{ - - if (vol->target.format == VIR_STORAGE_FILE_DIR) - vol->type = VIR_STORAGE_VOL_DIR; - else if (vol->target.format == VIR_STORAGE_FILE_PLOOP) - vol->type = VIR_STORAGE_VOL_PLOOP; - else - vol->type = VIR_STORAGE_VOL_FILE; - - /* Volumes within a directory pools are not recursive; do not - * allow escape to ../ or a subdir */ - if (strchr(vol->name, '/')) { - virReportError(VIR_ERR_OPERATION_INVALID, - _("volume name '%s' cannot contain '/'"), vol->name); - return -1; - } - - VIR_FREE(vol->target.path); - if (virAsprintf(&vol->target.path, "%s/%s", - pool->def->target.path, - vol->name) == -1) - return -1; - - if (virFileExists(vol->target.path)) { - virReportError(VIR_ERR_OPERATION_INVALID, - _("volume target path '%s' already exists"), - vol->target.path); - return -1; - } - - VIR_FREE(vol->key); - return VIR_STRDUP(vol->key, vol->target.path); -} - -static int createFileDir(virConnectPtr conn ATTRIBUTE_UNUSED, - virStoragePoolObjPtr pool, - virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol, - unsigned int flags) -{ - int err; - - virCheckFlags(0, -1); - - if (inputvol) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", - _("cannot copy from volume to a directory volume")); - return -1; - } - - if (vol->target.backingStore) { - virReportError(VIR_ERR_NO_SUPPORT, "%s", - _("backing storage not supported for directories volumes")); - return -1; - } - - - if ((err = virDirCreate(vol->target.path, - (vol->target.perms->mode == (mode_t) -1 ? - VIR_STORAGE_DEFAULT_VOL_PERM_MODE : - vol->target.perms->mode), - vol->target.perms->uid, - vol->target.perms->gid, - (pool->def->type == VIR_STORAGE_POOL_NETFS - ? VIR_DIR_CREATE_AS_UID : 0))) < 0) { - return -1; - } - - return 0; -} - -static int -_virStorageBackendFileSystemVolBuild(virConnectPtr conn, - virStoragePoolObjPtr pool, - virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol, - unsigned int flags) -{ - virStorageBackendBuildVolFrom create_func; - - if (inputvol) { - if (vol->target.encryption != NULL) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - "%s", _("storage pool does not support " - "building encrypted volumes from " - "other volumes")); - return -1; - } - create_func = virStorageBackendGetBuildVolFromFunction(vol, - inputvol); - if (!create_func) - return -1; - } else if (vol->target.format == VIR_STORAGE_FILE_RAW && - vol->target.encryption == NULL) { - create_func = virStorageBackendCreateRaw; - } else if (vol->target.format == VIR_STORAGE_FILE_DIR) { - create_func = createFileDir; - } else if (vol->target.format == VIR_STORAGE_FILE_PLOOP) { - create_func = virStorageBackendCreatePloop; - } else { - create_func = virStorageBackendCreateQemuImg; - } - - if (create_func(conn, pool, vol, inputvol, flags) < 0) - return -1; - return 0; -} - -/** - * Allocate a new file as a volume. This is either done directly - * for raw/sparse files, or by calling qemu-img for - * special kinds of files - */ -static int -virStorageBackendFileSystemVolBuild(virConnectPtr conn, - virStoragePoolObjPtr pool, - virStorageVolDefPtr vol, - unsigned int flags) -{ - virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA | - VIR_STORAGE_VOL_CREATE_REFLINK, - -1); - - return _virStorageBackendFileSystemVolBuild(conn, pool, vol, NULL, flags); -} - -/* - * Create a storage vol using 'inputvol' as input - */ -static int -virStorageBackendFileSystemVolBuildFrom(virConnectPtr conn, - virStoragePoolObjPtr pool, - virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol, - unsigned int flags) -{ - virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA | - VIR_STORAGE_VOL_CREATE_REFLINK, - -1); - - return _virStorageBackendFileSystemVolBuild(conn, pool, vol, inputvol, flags); -} - -/** - * Remove a volume - no support for BLOCK and NETWORK yet - */ -static int -virStorageBackendFileSystemVolDelete(virConnectPtr conn ATTRIBUTE_UNUSED, - virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, - virStorageVolDefPtr vol, - unsigned int flags) -{ - virCheckFlags(0, -1); - - switch ((virStorageVolType) vol->type) { - case VIR_STORAGE_VOL_FILE: - case VIR_STORAGE_VOL_DIR: - if (virFileRemove(vol->target.path, vol->target.perms->uid, - vol->target.perms->gid) < 0) { - /* Silently ignore failures where the vol has already gone away */ - if (errno != ENOENT) { - if (vol->type == VIR_STORAGE_VOL_FILE) - virReportSystemError(errno, - _("cannot unlink file '%s'"), - vol->target.path); - else - virReportSystemError(errno, - _("cannot remove directory '%s'"), - vol->target.path); - return -1; - } - } - break; - case VIR_STORAGE_VOL_PLOOP: - if (virFileDeleteTree(vol->target.path) < 0) - return -1; - break; - case VIR_STORAGE_VOL_BLOCK: - case VIR_STORAGE_VOL_NETWORK: - case VIR_STORAGE_VOL_NETDIR: - case VIR_STORAGE_VOL_LAST: - virReportError(VIR_ERR_NO_SUPPORT, - _("removing block or network volumes is not supported: %s"), - vol->target.path); - return -1; - } - return 0; -} - - -/* virStorageBackendFileSystemLoadDefaultSecrets: - * @conn: Connection pointer to fetch secret - * @vol: volume being refreshed - * - * If the volume had a secret generated, we need to regenerate the - * encryption secret information - * - * Returns 0 if no secret or secret setup was successful, - * -1 on failures w/ error message set - */ -static int -virStorageBackendFileSystemLoadDefaultSecrets(virConnectPtr conn, - virStorageVolDefPtr vol) -{ - virSecretPtr sec; - virStorageEncryptionSecretPtr encsec = NULL; - - if (!vol->target.encryption || vol->target.encryption->nsecrets != 0) - return 0; - - /* The encryption secret for qcow2 and luks volumes use the path - * to the volume, so look for a secret with the path. If not found, - * then we cannot generate the secret after a refresh (or restart). - * This may be the case if someone didn't follow instructions and created - * a usage string that although matched with the secret usage string, - * didn't contain the path to the volume. We won't error in that case, - * but we also cannot find the secret. */ - if (!(sec = virSecretLookupByUsage(conn, VIR_SECRET_USAGE_TYPE_VOLUME, - vol->target.path))) - return 0; - - if (VIR_ALLOC_N(vol->target.encryption->secrets, 1) < 0 || - VIR_ALLOC(encsec) < 0) { - VIR_FREE(vol->target.encryption->secrets); - virObjectUnref(sec); - return -1; - } - - vol->target.encryption->nsecrets = 1; - vol->target.encryption->secrets[0] = encsec; - - encsec->type = VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE; - encsec->seclookupdef.type = VIR_SECRET_LOOKUP_TYPE_UUID; - virSecretGetUUID(sec, encsec->seclookupdef.u.uuid); - virObjectUnref(sec); - - return 0; -} - - -/** - * Update info about a volume's capacity/allocation - */ -static int -virStorageBackendFileSystemVolRefresh(virConnectPtr conn, - virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, - virStorageVolDefPtr vol) -{ - int ret; - - /* Refresh allocation / capacity / permissions info in case its changed */ - if ((ret = virStorageBackendUpdateVolInfo(vol, false, - VIR_STORAGE_VOL_FS_OPEN_FLAGS, - 0)) < 0) - return ret; - - /* Load any secrets if possible */ - return virStorageBackendFileSystemLoadDefaultSecrets(conn, vol); -} - -static int -virStorageBackendFilesystemResizeQemuImg(const char *path, - unsigned long long capacity) -{ - int ret = -1; - char *img_tool; - virCommandPtr cmd = NULL; - - img_tool = virFindFileInPath("qemu-img"); - if (!img_tool) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("unable to find qemu-img")); - return -1; - } - - /* Round capacity as qemu-img resize errors out on sizes which are not - * a multiple of 512 */ - capacity = VIR_ROUND_UP(capacity, 512); - - cmd = virCommandNew(img_tool); - virCommandAddArgList(cmd, "resize", path, NULL); - virCommandAddArgFormat(cmd, "%llu", capacity); - - ret = virCommandRun(cmd, NULL); - - VIR_FREE(img_tool); - virCommandFree(cmd); - - return ret; -} - -/** - * Resize a volume - */ -static int -virStorageBackendFileSystemVolResize(virConnectPtr conn ATTRIBUTE_UNUSED, - virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, - virStorageVolDefPtr vol, - unsigned long long capacity, - unsigned int flags) -{ - virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE | - VIR_STORAGE_VOL_RESIZE_SHRINK, -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->target.allocation, pre_allocate); - } else if (vol->target.format == VIR_STORAGE_FILE_PLOOP) { - return virStoragePloopResize(vol, capacity); - } else { - if (pre_allocate) { - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("preallocate is only supported for raw " - "type volume")); - return -1; - } - - return virStorageBackendFilesystemResizeQemuImg(vol->target.path, - capacity); - } -} - - virStorageBackend virStorageBackendDirectory = { .type = VIR_STORAGE_POOL_DIR,
@@ -968,12 +632,12 @@ virStorageBackend virStorageBackendDirectory = { .checkPool = virStorageBackendFileSystemCheck, .refreshPool = virStorageBackendRefreshLocal, .deletePool = virStorageBackendDeleteLocal, - .buildVol = virStorageBackendFileSystemVolBuild, - .buildVolFrom = virStorageBackendFileSystemVolBuildFrom, - .createVol = virStorageBackendFileSystemVolCreate, - .refreshVol = virStorageBackendFileSystemVolRefresh, - .deleteVol = virStorageBackendFileSystemVolDelete, - .resizeVol = virStorageBackendFileSystemVolResize, + .buildVol = virStorageBackendVolBuildLocal, + .buildVolFrom = virStorageBackendVolBuildFromLocal, + .createVol = virStorageBackendVolCreateLocal, + .refreshVol = virStorageBackendVolRefreshLocal, + .deleteVol = virStorageBackendVolDeleteLocal, + .resizeVol = virStorageBackendVolResizeLocal, .uploadVol = virStorageBackendVolUploadLocal, .downloadVol = virStorageBackendVolDownloadLocal, .wipeVol = virStorageBackendVolWipeLocal, @@ -989,12 +653,12 @@ virStorageBackend virStorageBackendFileSystem = { .refreshPool = virStorageBackendRefreshLocal, .stopPool = virStorageBackendFileSystemStop, .deletePool = virStorageBackendDeleteLocal, - .buildVol = virStorageBackendFileSystemVolBuild, - .buildVolFrom = virStorageBackendFileSystemVolBuildFrom, - .createVol = virStorageBackendFileSystemVolCreate, - .refreshVol = virStorageBackendFileSystemVolRefresh, - .deleteVol = virStorageBackendFileSystemVolDelete, - .resizeVol = virStorageBackendFileSystemVolResize, + .buildVol = virStorageBackendVolBuildLocal, + .buildVolFrom = virStorageBackendVolBuildFromLocal, + .createVol = virStorageBackendVolCreateLocal, + .refreshVol = virStorageBackendVolRefreshLocal, + .deleteVol = virStorageBackendVolDeleteLocal, + .resizeVol = virStorageBackendVolResizeLocal, .uploadVol = virStorageBackendVolUploadLocal, .downloadVol = virStorageBackendVolDownloadLocal, .wipeVol = virStorageBackendVolWipeLocal, @@ -1009,12 +673,12 @@ virStorageBackend virStorageBackendNetFileSystem = { .refreshPool = virStorageBackendRefreshLocal, .stopPool = virStorageBackendFileSystemStop, .deletePool = virStorageBackendDeleteLocal, - .buildVol = virStorageBackendFileSystemVolBuild, - .buildVolFrom = virStorageBackendFileSystemVolBuildFrom, - .createVol = virStorageBackendFileSystemVolCreate, - .refreshVol = virStorageBackendFileSystemVolRefresh, - .deleteVol = virStorageBackendFileSystemVolDelete, - .resizeVol = virStorageBackendFileSystemVolResize, + .buildVol = virStorageBackendVolBuildLocal, + .buildVolFrom = virStorageBackendVolBuildFromLocal, + .createVol = virStorageBackendVolCreateLocal, + .refreshVol = virStorageBackendVolRefreshLocal, + .deleteVol = virStorageBackendVolDeleteLocal, + .resizeVol = virStorageBackendVolResizeLocal, .uploadVol = virStorageBackendVolUploadLocal, .downloadVol = virStorageBackendVolDownloadLocal, .wipeVol = virStorageBackendVolWipeLocal, diff --git a/src/storage/storage_util.c b/src/storage/storage_util.c index 6c2678d..fbe1844 100644 --- a/src/storage/storage_util.c +++ b/src/storage/storage_util.c @@ -222,11 +222,11 @@ virStorageBackendCopyToFD(virStorageVolDefPtr vol, }
static int -virStorageBackendCreateBlockFrom(virConnectPtr conn ATTRIBUTE_UNUSED, - virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, - virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol, - unsigned int flags) +storageBackendCreateBlockFrom(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, + virStorageVolDefPtr vol, + virStorageVolDefPtr inputvol, + unsigned int flags) { int fd = -1; int ret = -1; @@ -389,12 +389,12 @@ createRawFile(int fd, virStorageVolDefPtr vol, return ret; }
-int -virStorageBackendCreateRaw(virConnectPtr conn ATTRIBUTE_UNUSED, - virStoragePoolObjPtr pool, - virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol, - unsigned int flags) +static int +storageBackendCreateRaw(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + virStorageVolDefPtr inputvol, + unsigned int flags) { int ret = -1; int fd = -1; @@ -692,12 +692,12 @@ virStorageBackendCreateExecCommand(virStoragePoolObjPtr pool,
/* Create ploop directory with ploop image and DiskDescriptor.xml * if function fails to create image file the directory will be deleted.*/ -int -virStorageBackendCreatePloop(virConnectPtr conn ATTRIBUTE_UNUSED, - virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, - virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol, - unsigned int flags) +static int +storageBackendCreatePloop(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, + virStorageVolDefPtr vol, + virStorageVolDefPtr inputvol, + unsigned int flags) { int ret = -1; virCommandPtr cmd = NULL; @@ -767,9 +767,10 @@ virStorageBackendCreatePloop(virConnectPtr conn ATTRIBUTE_UNUSED, return ret; }
-int -virStoragePloopResize(virStorageVolDefPtr vol, - unsigned long long capacity) + +static int +storagePloopResize(virStorageVolDefPtr vol, + unsigned long long capacity) { int ret = -1; virCommandPtr cmd = NULL; @@ -875,9 +876,9 @@ struct _virStorageBackendQemuImgInfo {
static int -virStorageBackendCreateQemuImgOpts(virStorageEncryptionInfoDefPtr enc, - char **opts, - struct _virStorageBackendQemuImgInfo info) +storageBackendCreateQemuImgOpts(virStorageEncryptionInfoDefPtr enc, + char **opts, + struct _virStorageBackendQemuImgInfo info) { virBuffer buf = VIR_BUFFER_INITIALIZER;
@@ -927,7 +928,7 @@ virStorageBackendCreateQemuImgOpts(virStorageEncryptionInfoDefPtr enc, }
-/* virStorageBackendCreateQemuImgCheckEncryption: +/* storageBackendCreateQemuImgCheckEncryption: * @format: format of file found * @conn: pointer to connection * @vol: pointer to volume def @@ -937,10 +938,10 @@ virStorageBackendCreateQemuImgOpts(virStorageEncryptionInfoDefPtr enc, * Returns 0 on success, -1 on failure w/ error set */ static int -virStorageBackendCreateQemuImgCheckEncryption(int format, - const char *type, - virConnectPtr conn, - virStorageVolDefPtr vol) +storageBackendCreateQemuImgCheckEncryption(int format, + const char *type, + virConnectPtr conn, + virStorageVolDefPtr vol) { virStorageEncryptionPtr enc = vol->target.encryption;
@@ -996,8 +997,8 @@ virStorageBackendCreateQemuImgCheckEncryption(int format,
static int -virStorageBackendCreateQemuImgSetInput(virStorageVolDefPtr inputvol, - struct _virStorageBackendQemuImgInfo *info) +storageBackendCreateQemuImgSetInput(virStorageVolDefPtr inputvol, + struct _virStorageBackendQemuImgInfo *info) { if (!(info->inputPath = inputvol->target.path)) { virReportError(VIR_ERR_INVALID_ARG, "%s", @@ -1021,10 +1022,10 @@ virStorageBackendCreateQemuImgSetInput(virStorageVolDefPtr inputvol,
static int -virStorageBackendCreateQemuImgSetBacking(virStoragePoolObjPtr pool, - virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol, - struct _virStorageBackendQemuImgInfo *info) +storageBackendCreateQemuImgSetBacking(virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + virStorageVolDefPtr inputvol, + struct _virStorageBackendQemuImgInfo *info) { int accessRetCode = -1; char *absolutePath = NULL; @@ -1086,10 +1087,10 @@ virStorageBackendCreateQemuImgSetBacking(virStoragePoolObjPtr pool,
static int -virStorageBackendCreateQemuImgSetOptions(virCommandPtr cmd, - int imgformat, - virStorageEncryptionInfoDefPtr enc, - struct _virStorageBackendQemuImgInfo info) +storageBackendCreateQemuImgSetOptions(virCommandPtr cmd, + int imgformat, + virStorageEncryptionInfoDefPtr enc, + struct _virStorageBackendQemuImgInfo info) { char *opts = NULL;
@@ -1097,7 +1098,7 @@ virStorageBackendCreateQemuImgSetOptions(virCommandPtr cmd, imgformat >= QEMU_IMG_BACKING_FORMAT_OPTIONS_COMPAT) info.compat = "0.10";
- if (virStorageBackendCreateQemuImgOpts(enc, &opts, info) < 0) + if (storageBackendCreateQemuImgOpts(enc, &opts, info) < 0) return -1; if (opts) virCommandAddArgList(cmd, "-o", opts, NULL); @@ -1113,9 +1114,9 @@ virStorageBackendCreateQemuImgSetOptions(virCommandPtr cmd, * NB: format=raw is assumed */ static int -virStorageBackendCreateQemuImgSecretObject(virCommandPtr cmd, - virStorageVolDefPtr vol, - struct _virStorageBackendQemuImgInfo *info) +storageBackendCreateQemuImgSecretObject(virCommandPtr cmd, + virStorageVolDefPtr vol, + struct _virStorageBackendQemuImgInfo *info) { virBuffer buf = VIR_BUFFER_INITIALIZER; char *commandStr = NULL; @@ -1218,17 +1219,16 @@ virStorageBackendCreateQemuImgCmdFromVol(virConnectPtr conn, }
if (inputvol && - virStorageBackendCreateQemuImgSetInput(inputvol, &info) < 0) + storageBackendCreateQemuImgSetInput(inputvol, &info) < 0) return NULL;
if (vol->target.backingStore && - virStorageBackendCreateQemuImgSetBacking(pool, vol, inputvol, - &info) < 0) + storageBackendCreateQemuImgSetBacking(pool, vol, inputvol, &info) < 0) return NULL;
if (info.encryption && - virStorageBackendCreateQemuImgCheckEncryption(info.format, type, - conn, vol) < 0) + storageBackendCreateQemuImgCheckEncryption(info.format, type, + conn, vol) < 0) return NULL;
@@ -1253,7 +1253,7 @@ virStorageBackendCreateQemuImgCmdFromVol(virConnectPtr conn, if (info.format == VIR_STORAGE_FILE_RAW && vol->target.encryption != NULL && vol->target.encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS) { - if (virStorageBackendCreateQemuImgSecretObject(cmd, vol, &info) < 0) { + if (storageBackendCreateQemuImgSecretObject(cmd, vol, &info) < 0) { VIR_FREE(info.secretAlias); virCommandFree(cmd); return NULL; @@ -1261,8 +1261,7 @@ virStorageBackendCreateQemuImgCmdFromVol(virConnectPtr conn, enc = &vol->target.encryption->encinfo; }
- if (virStorageBackendCreateQemuImgSetOptions(cmd, imgformat, - enc, info) < 0) { + if (storageBackendCreateQemuImgSetOptions(cmd, imgformat, enc, info) < 0) { VIR_FREE(info.secretAlias); virCommandFree(cmd); return NULL; @@ -1280,9 +1279,9 @@ virStorageBackendCreateQemuImgCmdFromVol(virConnectPtr conn,
static char * -virStorageBackendCreateQemuImgSecretPath(virConnectPtr conn, - virStoragePoolObjPtr pool, - virStorageVolDefPtr vol) +storageBackendCreateQemuImgSecretPath(virConnectPtr conn, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol) { virStorageEncryptionPtr enc = vol->target.encryption; char *secretPath = NULL; @@ -1349,12 +1348,12 @@ virStorageBackendCreateQemuImgSecretPath(virConnectPtr conn, }
-int -virStorageBackendCreateQemuImg(virConnectPtr conn, - virStoragePoolObjPtr pool, - virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol, - unsigned int flags) +static int +storageBackendCreateQemuImg(virConnectPtr conn, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + virStorageVolDefPtr inputvol, + unsigned int flags) { int ret = -1; char *create_tool; @@ -1380,7 +1379,7 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, vol->target.encryption && vol->target.encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS) { if (!(secretPath = - virStorageBackendCreateQemuImgSecretPath(conn, pool, vol))) + storageBackendCreateQemuImgSecretPath(conn, pool, vol))) goto cleanup; }
@@ -1418,15 +1417,15 @@ virStorageBackendGetBuildVolFromFunction(virStorageVolDefPtr vol, (inputvol->type == VIR_STORAGE_VOL_FILE && (inputvol->target.format != VIR_STORAGE_FILE_RAW || inputvol->target.encryption != NULL))) { - return virStorageBackendCreateQemuImg; + return storageBackendCreateQemuImg; }
if (vol->type == VIR_STORAGE_VOL_PLOOP) - return virStorageBackendCreatePloop; + return storageBackendCreatePloop; if (vol->type == VIR_STORAGE_VOL_BLOCK) - return virStorageBackendCreateBlockFrom; + return storageBackendCreateBlockFrom; else - return virStorageBackendCreateRaw; + return storageBackendCreateRaw; }
@@ -2008,6 +2007,340 @@ virStorageBackendStablePath(virStoragePoolObjPtr pool, return stablepath; }
+/* Common/Local File System/Directory Volume API's */ +static int +createFileDir(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + virStorageVolDefPtr inputvol, + unsigned int flags) +{ + int err; + + virCheckFlags(0, -1); + + if (inputvol) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("cannot copy from volume to a directory volume")); + return -1; + } + + if (vol->target.backingStore) { + virReportError(VIR_ERR_NO_SUPPORT, "%s", + _("backing storage not supported for directories volumes")); + return -1; + } + + + if ((err = virDirCreate(vol->target.path, + (vol->target.perms->mode == (mode_t) -1 ? + VIR_STORAGE_DEFAULT_VOL_PERM_MODE : + vol->target.perms->mode), + vol->target.perms->uid, + vol->target.perms->gid, + (pool->def->type == VIR_STORAGE_POOL_NETFS + ? VIR_DIR_CREATE_AS_UID : 0))) < 0) { + return -1; + } + + return 0; +} + + +/** + * Set up a volume definition to be added to a pool's volume list, but + * don't do any file creation or allocation. By separating the two processes, + * we allow allocation progress reporting (by polling the volume's 'info' + * function), and can drop the parent pool lock during the (slow) allocation. + */ +int +virStorageBackendVolCreateLocal(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol) +{ + if (vol->target.format == VIR_STORAGE_FILE_DIR) + vol->type = VIR_STORAGE_VOL_DIR; + else if (vol->target.format == VIR_STORAGE_FILE_PLOOP) + vol->type = VIR_STORAGE_VOL_PLOOP; + else + vol->type = VIR_STORAGE_VOL_FILE; + + /* Volumes within a directory pools are not recursive; do not + * allow escape to ../ or a subdir */ + if (strchr(vol->name, '/')) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("volume name '%s' cannot contain '/'"), vol->name); + return -1; + } + + VIR_FREE(vol->target.path); + if (virAsprintf(&vol->target.path, "%s/%s", + pool->def->target.path, + vol->name) == -1) + return -1; + + if (virFileExists(vol->target.path)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("volume target path '%s' already exists"), + vol->target.path); + return -1; + } + + VIR_FREE(vol->key); + return VIR_STRDUP(vol->key, vol->target.path); +} + + +static int +storageBackendVolBuildLocal(virConnectPtr conn, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + virStorageVolDefPtr inputvol, + unsigned int flags) +{ + virStorageBackendBuildVolFrom create_func; + + if (inputvol) { + if (vol->target.encryption != NULL) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + "%s", _("storage pool does not support " + "building encrypted volumes from " + "other volumes")); + return -1; + } + if (!(create_func = + virStorageBackendGetBuildVolFromFunction(vol, inputvol))) + return -1; + } else if (vol->target.format == VIR_STORAGE_FILE_RAW && + vol->target.encryption == NULL) { + create_func = storageBackendCreateRaw; + } else if (vol->target.format == VIR_STORAGE_FILE_DIR) { + create_func = createFileDir; + } else if (vol->target.format == VIR_STORAGE_FILE_PLOOP) { + create_func = storageBackendCreatePloop; + } else { + create_func = storageBackendCreateQemuImg; + } + + if (create_func(conn, pool, vol, inputvol, flags) < 0) + return -1; + return 0; +} + + +/** + * Allocate a new file as a volume. This is either done directly + * for raw/sparse files, or by calling qemu-img for + * special kinds of files + */ +int +virStorageBackendVolBuildLocal(virConnectPtr conn, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + unsigned int flags) +{ + return storageBackendVolBuildLocal(conn, pool, vol, NULL, flags); +} + + +/* + * Create a storage vol using 'inputvol' as input + */ +int +virStorageBackendVolBuildFromLocal(virConnectPtr conn, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + virStorageVolDefPtr inputvol, + unsigned int flags) +{ + return storageBackendVolBuildLocal(conn, pool, vol, inputvol, flags); +} + + +/** + * Remove a volume - no support for BLOCK and NETWORK yet + */ +int +virStorageBackendVolDeleteLocal(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, + virStorageVolDefPtr vol, + unsigned int flags) +{ + virCheckFlags(0, -1); + + switch ((virStorageVolType) vol->type) { + case VIR_STORAGE_VOL_FILE: + case VIR_STORAGE_VOL_DIR: + if (virFileRemove(vol->target.path, vol->target.perms->uid, + vol->target.perms->gid) < 0) { + /* Silently ignore failures where the vol has already gone away */ + if (errno != ENOENT) { + if (vol->type == VIR_STORAGE_VOL_FILE) + virReportSystemError(errno, + _("cannot unlink file '%s'"), + vol->target.path); + else + virReportSystemError(errno, + _("cannot remove directory '%s'"), + vol->target.path); + return -1; + } + } + break; + case VIR_STORAGE_VOL_PLOOP: + if (virFileDeleteTree(vol->target.path) < 0) + return -1; + break; + case VIR_STORAGE_VOL_BLOCK: + case VIR_STORAGE_VOL_NETWORK: + case VIR_STORAGE_VOL_NETDIR: + case VIR_STORAGE_VOL_LAST: + virReportError(VIR_ERR_NO_SUPPORT, + _("removing block or network volumes is not supported: %s"), + vol->target.path); + return -1; + } + return 0; +} + + +/* storageBackendLoadDefaultSecrets: + * @conn: Connection pointer to fetch secret + * @vol: volume being refreshed + * + * If the volume had a secret generated, we need to regenerate the + * encryption secret information + * + * Returns 0 if no secret or secret setup was successful, + * -1 on failures w/ error message set + */ +static int +storageBackendLoadDefaultSecrets(virConnectPtr conn, + virStorageVolDefPtr vol) +{ + virSecretPtr sec; + virStorageEncryptionSecretPtr encsec = NULL; + + if (!vol->target.encryption || vol->target.encryption->nsecrets != 0) + return 0; + + /* The encryption secret for qcow2 and luks volumes use the path + * to the volume, so look for a secret with the path. If not found, + * then we cannot generate the secret after a refresh (or restart). + * This may be the case if someone didn't follow instructions and created + * a usage string that although matched with the secret usage string, + * didn't contain the path to the volume. We won't error in that case, + * but we also cannot find the secret. */ + if (!(sec = virSecretLookupByUsage(conn, VIR_SECRET_USAGE_TYPE_VOLUME, + vol->target.path))) + return 0; + + if (VIR_ALLOC_N(vol->target.encryption->secrets, 1) < 0 || + VIR_ALLOC(encsec) < 0) { + VIR_FREE(vol->target.encryption->secrets); + virObjectUnref(sec); + return -1; + } + + vol->target.encryption->nsecrets = 1; + vol->target.encryption->secrets[0] = encsec; + + encsec->type = VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE; + encsec->seclookupdef.type = VIR_SECRET_LOOKUP_TYPE_UUID; + virSecretGetUUID(sec, encsec->seclookupdef.u.uuid); + virObjectUnref(sec); + + return 0; +} + + +/** + * Update info about a volume's capacity/allocation + */ +int +virStorageBackendVolRefreshLocal(virConnectPtr conn, + virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, + virStorageVolDefPtr vol) +{ + int ret; + + /* Refresh allocation / capacity / permissions info in case its changed */ + if ((ret = virStorageBackendUpdateVolInfo(vol, false, + VIR_STORAGE_VOL_FS_OPEN_FLAGS, + 0)) < 0) + return ret; + + /* Load any secrets if possible */ + return storageBackendLoadDefaultSecrets(conn, vol); +} + + +static int +storageBackendResizeQemuImg(const char *path, + unsigned long long capacity) +{ + int ret = -1; + char *img_tool; + virCommandPtr cmd = NULL; + + img_tool = virFindFileInPath("qemu-img"); + if (!img_tool) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("unable to find qemu-img")); + return -1; + } + + /* Round capacity as qemu-img resize errors out on sizes which are not + * a multiple of 512 */ + capacity = VIR_ROUND_UP(capacity, 512); + + cmd = virCommandNew(img_tool); + virCommandAddArgList(cmd, "resize", path, NULL); + virCommandAddArgFormat(cmd, "%llu", capacity); + + ret = virCommandRun(cmd, NULL); + + VIR_FREE(img_tool); + virCommandFree(cmd); + + return ret; +} + + +/** + * Resize a volume + */ +int +virStorageBackendVolResizeLocal(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, + virStorageVolDefPtr vol, + unsigned long long capacity, + unsigned int flags) +{ + virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE | + VIR_STORAGE_VOL_RESIZE_SHRINK, -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->target.allocation, pre_allocate); + } else if (vol->target.format == VIR_STORAGE_FILE_PLOOP) { + return storagePloopResize(vol, capacity); + } else { + if (pre_allocate) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("preallocate is only supported for raw " + "type volume")); + return -1; + } + + return storageBackendResizeQemuImg(vol->target.path, capacity); + } +} + + /* * Check whether the ploop image has snapshots. * return: -1 - failed to check @@ -2015,7 +2348,7 @@ virStorageBackendStablePath(virStoragePoolObjPtr pool, * 1 - at least one snapshot */ static int -virStorageBackendPloopHasSnapshots(char *path) +storageBackendPloopHasSnapshots(char *path) { virCommandPtr cmd = NULL; char *output = NULL; @@ -2049,6 +2382,7 @@ virStorageBackendPloopHasSnapshots(char *path) return ret; }
+ int virStorageBackendVolUploadLocal(virConnectPtr conn ATTRIBUTE_UNUSED, virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, @@ -2070,7 +2404,7 @@ virStorageBackendVolUploadLocal(virConnectPtr conn ATTRIBUTE_UNUSED, * when volUpload is fully finished. */ if (vol->target.format == VIR_STORAGE_FILE_PLOOP) { /* Fail if the volume contains snapshots or we failed to check it.*/ - has_snap = virStorageBackendPloopHasSnapshots(vol->target.path); + has_snap = storageBackendPloopHasSnapshots(vol->target.path); if (has_snap < 0) { goto cleanup; } else if (!has_snap) { @@ -2111,7 +2445,7 @@ virStorageBackendVolDownloadLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
virCheckFlags(0, -1); if (vol->target.format == VIR_STORAGE_FILE_PLOOP) { - has_snap = virStorageBackendPloopHasSnapshots(vol->target.path); + has_snap = storageBackendPloopHasSnapshots(vol->target.path); if (has_snap < 0) { goto cleanup; } else if (!has_snap) { @@ -2149,9 +2483,9 @@ virStorageBackendVolDownloadLocal(virConnectPtr conn ATTRIBUTE_UNUSED, * appear as if it were zero-filled. */ static int -virStorageBackendVolZeroSparseFileLocal(const char *path, - off_t size, - int fd) +storageBackendVolZeroSparseFileLocal(const char *path, + off_t size, + int fd) { if (ftruncate(fd, 0) < 0) { virReportSystemError(errno, @@ -2174,10 +2508,10 @@ virStorageBackendVolZeroSparseFileLocal(const char *path,
static int -virStorageBackendWipeLocal(const char *path, - int fd, - unsigned long long wipe_len, - size_t writebuf_length) +storageBackendWipeLocal(const char *path, + int fd, + unsigned long long wipe_len, + size_t writebuf_length) { int ret = -1, written = 0; unsigned long long remaining = 0; @@ -2232,9 +2566,9 @@ virStorageBackendWipeLocal(const char *path,
static int -virStorageBackendVolWipeLocalFile(const char *path, - unsigned int algorithm, - unsigned long long allocation) +storageBackendVolWipeLocalFile(const char *path, + unsigned int algorithm, + unsigned long long allocation) { int ret = -1, fd = -1; const char *alg_char = NULL; @@ -2307,12 +2641,9 @@ virStorageBackendVolWipeLocalFile(const char *path, ret = 0; } else { if (S_ISREG(st.st_mode) && st.st_blocks < (st.st_size / DEV_BSIZE)) { - ret = virStorageBackendVolZeroSparseFileLocal(path, st.st_size, fd); + ret = storageBackendVolZeroSparseFileLocal(path, st.st_size, fd); } else { - ret = virStorageBackendWipeLocal(path, - fd, - allocation, - st.st_blksize); + ret = storageBackendWipeLocal(path, fd, allocation, st.st_blksize); } if (ret < 0) goto cleanup; @@ -2326,8 +2657,8 @@ virStorageBackendVolWipeLocalFile(const char *path,
static int -virStorageBackendVolWipePloop(virStorageVolDefPtr vol, - unsigned int algorithm) +storageBackendVolWipePloop(virStorageVolDefPtr vol, + unsigned int algorithm) { virCommandPtr cmd = NULL; char *target_path = NULL; @@ -2349,9 +2680,8 @@ virStorageBackendVolWipePloop(virStorageVolDefPtr vol, if (virAsprintf(&disk_desc, "%s/DiskDescriptor.xml", vol->target.path) < 0) goto cleanup;
- if (virStorageBackendVolWipeLocalFile(target_path, - algorithm, - vol->target.allocation) < 0) + if (storageBackendVolWipeLocalFile(target_path, algorithm, + vol->target.allocation) < 0) goto cleanup;
if (virFileRemove(disk_desc, 0, 0) < 0) { @@ -2397,11 +2727,10 @@ virStorageBackendVolWipeLocal(virConnectPtr conn ATTRIBUTE_UNUSED, vol->target.path, algorithm);
if (vol->target.format == VIR_STORAGE_FILE_PLOOP) { - ret = virStorageBackendVolWipePloop(vol, algorithm); + ret = storageBackendVolWipePloop(vol, algorithm); } else { - ret = virStorageBackendVolWipeLocalFile(vol->target.path, - algorithm, - vol->target.allocation); + ret = storageBackendVolWipeLocalFile(vol->target.path, algorithm, + vol->target.allocation); }
return ret; diff --git a/src/storage/storage_util.h b/src/storage/storage_util.h index f5a1b5b..49df530 100644 --- a/src/storage/storage_util.h +++ b/src/storage/storage_util.h @@ -28,30 +28,39 @@ # include "storage_backend.h"
/* File creation/cloning functions used for cloning between backends */ -int virStorageBackendCreateRaw(virConnectPtr conn, - virStoragePoolObjPtr pool, - virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol, - unsigned int flags); +virStorageBackendBuildVolFrom +virStorageBackendGetBuildVolFromFunction(virStorageVolDefPtr vol, + virStorageVolDefPtr inputvol); + +int virStorageBackendVolCreateLocal(virConnectPtr conn, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol);
-int virStorageBackendCreateQemuImg(virConnectPtr conn, +int virStorageBackendVolBuildLocal(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol, unsigned int flags);
-int virStorageBackendCreatePloop(virConnectPtr conn, - virStoragePoolObjPtr pool, - virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol, - unsigned int flags); +int virStorageBackendVolBuildFromLocal(virConnectPtr conn, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + virStorageVolDefPtr inputvol, + unsigned int flags); + +int virStorageBackendVolDeleteLocal(virConnectPtr conn, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + unsigned int flags);
-int virStoragePloopResize(virStorageVolDefPtr vol, - unsigned long long capacity); +int virStorageBackendVolRefreshLocal(virConnectPtr conn, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol);
-virStorageBackendBuildVolFrom -virStorageBackendGetBuildVolFromFunction(virStorageVolDefPtr vol, - virStorageVolDefPtr inputvol); +int virStorageBackendVolResizeLocal(virConnectPtr conn, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + unsigned long long capacity, + unsigned int flags);
int virStorageBackendVolUploadLocal(virConnectPtr conn, virStoragePoolObjPtr pool, @@ -60,6 +69,7 @@ int virStorageBackendVolUploadLocal(virConnectPtr conn, unsigned long long offset, unsigned long long len, unsigned int flags); + int virStorageBackendVolDownloadLocal(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol,
ACK -- Best regards, Olga
participants (3)
-
John Ferlan
-
Olga Krishtal
-
Roman Bogorodskiy