[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