[libvirt] [PATCH 2/3] storage: Create common file/dir pool backend helpers
Olga Krishtal
okrishtal at virtuozzo.com
Tue Jan 24 16:18:42 UTC 2017
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 at 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
More information about the libvir-list
mailing list