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@xxxxxxxxxxxxx> > --- > 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 > 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, > }; > -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list