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(a)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