[libvirt] [PATCH v2 4/5] storage: added vstorage pool backend volume functions

Olga Krishtal okrishtal at virtuozzo.com
Thu Jan 19 14:25:10 UTC 2017


On 19/01/17 00:04, John Ferlan wrote:
>
> On 01/17/2017 09:10 AM, Olga Krishtal wrote:
>> Vstorage operates with volumes the same way as
>> directory pool and netfs pool. We use the same functions.
>>
>> Signed-off-by: Olga Krishtal <okrishtal at virtuozzo.com>
>> ---
>>   src/storage/storage_backend_vstorage.c | 342 +++++++++++++++++++++++++++++++++
>>   1 file changed, 342 insertions(+)
>>
> Similar to 3/5 - create common functions in storage_backend or the new
> storage_util.c from pkrempa's patches.
>
> It's easy enough for me to do so I'll take care of it...
>
>
> John

Thanks
>> diff --git a/src/storage/storage_backend_vstorage.c b/src/storage/storage_backend_vstorage.c
>> index 8332f4d..65b5ae0 100644
>> --- a/src/storage/storage_backend_vstorage.c
>> +++ b/src/storage/storage_backend_vstorage.c
>> @@ -534,6 +534,339 @@ virStorageBackendVzRefresh(virConnectPtr conn ATTRIBUTE_UNUSED,
>>       return ret;
>>   }
>>   
>> +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
>> +_virStorageBackendVzVolBuild(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
>> +virStorageBackendVzVolBuild(virConnectPtr conn,
>> +                            virStoragePoolObjPtr pool,
>> +                            virStorageVolDefPtr vol,
>> +                            unsigned int flags)
>> +{
>> +    virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA |
>> +                  VIR_STORAGE_VOL_CREATE_REFLINK,
>> +                  -1);
>> +
>> +    return _virStorageBackendVzVolBuild(conn, pool, vol, NULL, flags);
>> +}
>> +
>> +/*
>> + * Create a storage vol using 'inputvol' as input
>> + */
>> +static int
>> +virStorageBackendVzVolBuildFrom(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 _virStorageBackendVzVolBuild(conn, pool, vol, inputvol, flags);
>> +}
>> +
>> +/**
>> + * 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
>> +virStorageBackendVzVolCreate(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);
>> +}
>> +
>> +/* 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
>> +virStorageBackendVzLoadDefaultSecrets(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
>> +virStorageBackendVzVolRefresh(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 virStorageBackendVzLoadDefaultSecrets(conn, vol);
>> +}
>> +
>> +static int
>> +virStorageBackendVzResizeQemuImg(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
>> +virStorageBackendVzVolResize(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 virStorageBackendVzResizeQemuImg(vol->target.path,
>> +                                               capacity);
>> +    }
>> +}
>> +
>> +/**
>> + * Remove a volume - no support for BLOCK and NETWORK yet
>> + */
>> +static int
>> +virStorageBackendVzVolDelete(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;
>> +}
>> +
>>   virStorageBackend virStorageBackendVstorage = {
>>       .type = VIR_STORAGE_POOL_VSTORAGE,
>>   
>> @@ -543,4 +876,13 @@ virStorageBackend virStorageBackendVstorage = {
>>       .deletePool = virStorageBackendVzDelete,
>>       .refreshPool = virStorageBackendVzRefresh,
>>       .checkPool = virStorageBackendVzCheck,
>> +    .buildVol = virStorageBackendVzVolBuild,
>> +    .buildVolFrom = virStorageBackendVzVolBuildFrom,
>> +    .createVol = virStorageBackendVzVolCreate,
>> +    .refreshVol = virStorageBackendVzVolRefresh,
>> +    .deleteVol = virStorageBackendVzVolDelete,
>> +    .resizeVol = virStorageBackendVzVolResize,
>> +    .uploadVol = virStorageBackendVolUploadLocal,
>> +    .downloadVol = virStorageBackendVolDownloadLocal,
>> +    .wipeVol = virStorageBackendVolWipeLocal,
>>   };
>>


-- 
Best regards,
Olga




More information about the libvir-list mailing list