[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