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