[libvirt] [PATCH v2 0/5] storage: Virtuozzo storage backend for storage pool

This series of patches support pool and volume management within Virtuozzo Storage. Virtuozzo Storage is a highly-available distributed software defined storage with built-in replication and disaster recovery. More information about vzstorage can be found here: https://openvz.org/Virtuozzo_Storage
From client's point of view it looks like network attached storage (NFS or GlusterFS). It supports the same volume formats as directory, nfs. Default format ifor volume is raw. Because of such similarities all a lot of functions from storage backend fs can be used with no change: all functions that deals with volumes and pool refresh function.
From the other hand, Virtuozzo storage demands special packages like vstorage-client to be installed. So all functions that work with it are in separate file.
v2: - resplitted patches - all functions to work with Virtuozzo storage are in separate file - added possibility to mout cluster for pool for ures/with specific perms. - added documetation Olga Krishtal (5): storage: adds with_storage_vstorage buils option storage: vstorage empty backend storage: vstorage pool operations storage: added vstorage pool backend volume functions storage: vstorage pool documentation and simple test configure.ac | 5 + docs/formatstorage.html.in | 7 +- docs/schemas/storagepool.rng | 21 + docs/storage.html.in | 28 +- include/libvirt/libvirt-storage.h | 1 + m4/virt-storage-vstorage.m4 | 73 +++ po/POTFILES.in | 1 + src/Makefile.am | 9 + src/conf/storage_conf.c | 17 +- src/conf/storage_conf.h | 1 + src/storage/storage_backend.c | 6 + src/storage/storage_backend_vstorage.c | 888 ++++++++++++++++++++++++++ src/storage/storage_backend_vstorage.h | 27 + src/storage/storage_driver.c | 2 + tests/storagepoolxml2xmlin/pool-vstorage.xml | 10 + tests/storagepoolxml2xmlout/pool-vstorage.xml | 18 + tests/storagepoolxml2xmltest.c | 3 + tools/virsh-pool.c | 3 + tools/virsh.c | 3 + 19 files changed, 1118 insertions(+), 5 deletions(-) create mode 100644 m4/virt-storage-vstorage.m4 create mode 100644 src/storage/storage_backend_vstorage.c create mode 100644 src/storage/storage_backend_vstorage.h create mode 100644 tests/storagepoolxml2xmlin/pool-vstorage.xml create mode 100644 tests/storagepoolxml2xmlout/pool-vstorage.xml -- 1.8.3.1

This patch only adds --with-storage-vstorage build option. In order to use vstorage as a backend for storage pool vstorage tools should be installed. Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- configure.ac | 4 +++ m4/virt-storage-vstorage.m4 | 73 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 m4/virt-storage-vstorage.m4 diff --git a/configure.ac b/configure.ac index c67ba79..2cc378d 100644 --- a/configure.ac +++ b/configure.ac @@ -570,6 +570,7 @@ LIBVIRT_STORAGE_ARG_RBD LIBVIRT_STORAGE_ARG_SHEEPDOG LIBVIRT_STORAGE_ARG_GLUSTER LIBVIRT_STORAGE_ARG_ZFS +LIBVIRT_STORAGE_ARG_VSTORAGE if test "$with_libvirtd" = "no"; then with_storage_dir=no @@ -583,6 +584,7 @@ if test "$with_libvirtd" = "no"; then with_storage_sheepdog=no with_storage_gluster=no with_storage_zfs=no + with_storage_vstorage=no fi dnl storage-fs does not work on MacOS X @@ -602,6 +604,7 @@ LIBVIRT_STORAGE_CHECK_RBD LIBVIRT_STORAGE_CHECK_SHEEPDOG LIBVIRT_STORAGE_CHECK_GLUSTER LIBVIRT_STORAGE_CHECK_ZFS +LIBVIRT_STORAGE_CHECK_VSTORAGE if test "$with_storage_fs" = "yes" || test "$with_storage_gluster" = "yes"; then @@ -944,6 +947,7 @@ LIBVIRT_STORAGE_RESULT_RBD LIBVIRT_STORAGE_RESULT_SHEEPDOG LIBVIRT_STORAGE_RESULT_GLUSTER LIBVIRT_STORAGE_RESULT_ZFS +LIBVIRT_STORAGE_RESULT_VSTORAGE AC_MSG_NOTICE([]) AC_MSG_NOTICE([Security Drivers]) AC_MSG_NOTICE([]) diff --git a/m4/virt-storage-vstorage.m4 b/m4/virt-storage-vstorage.m4 new file mode 100644 index 0000000..8a926c8 --- /dev/null +++ b/m4/virt-storage-vstorage.m4 @@ -0,0 +1,73 @@ +dnl The storage vstorage check +dnl +dnl Copyright (C) 2016 Parallels IP Holdings GmbH, Inc. +dnl +dnl This library is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Lesser General Public +dnl License as published by the Free Software Foundation; either +dnl version 2.1 of the License, or (at your option) any later version. +dnl +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Lesser General Public License for more details. +dnl +dnl You should have received a copy of the GNU Lesser General Public +dnl License along with this library. If not, see +dnl <http://www.gnu.org/licenses/>. +dnl + + +AC_DEFUN([LIBVIRT_STORAGE_ARG_VSTORAGE], [ + LIBVIRT_ARG_WITH_FEATURE([STORAGE_VSTORAGE], + [Virtuozzo Storage backend for the storage driver], + [check]) +]) + +AC_DEFUN([LIBVIRT_STORAGE_CHECK_VSTORAGE], [ + if test "$with_storage_vstorage" = "yes" || + test "$with_storage_vstorage" = "check"; then + AC_PATH_PROG([VSTORAGE], [vstorage], [], [$LIBVIRT_SBIN_PATH]) + AC_PATH_PROG([VSTORAGE_MOUNT], [vstorage-mount], [], [$LIBVIRT_SBIN_PATH]) + AC_PATH_PROG([UMOUNT], [umount], [], [$LIBVIRT_SBIN_PATH]) + + if test "$with_storage_vstorage" = "yes"; then + if test -z "$VSTORAGE" || test -z "$VSTORAGE_MOUNT"; then + AC_MSG_ERROR([We need vstorage and vstorage-mount tool for Vstorage storage driver]); + fi + if test -z "$UMOUNT" ; then + AC_MSG_ERROR([We need umount for Vstorage storage driver]); + fi + else + if test -z "$VSTORAGE" ; then + with_storage_vstorage=no + fi + if test -z "$VSTORAGE_MOUNT" ; then + with_storage_vstorage=no + fi + if test -z "$UMOUNT" ; then + with_storage_vstorage=no + fi + + if test "$with_storage_fs" = "check" ; then + with_storage_vstorage=yes + fi + fi + + if test "$with_storage_vstorage" = "yes" ; then + AC_DEFINE_UNQUOTED([WITH_STORAGE_VSTORAGE], 1, + [whether Vstorage backend for storage driver is enabled]) + AC_DEFINE_UNQUOTED([VSTORAGE], ["$VSTORAGE"], + [Location or name of the vstorage client tool]) + AC_DEFINE_UNQUOTED([VSTORAGE_MOUNT], ["$VSTORAGE_MOUNT"], + [Location or name of the vstorage mount tool]) + AC_DEFINE_UNQUOTED([UMOUNT], ["$UMOUNT"], + [Location or name of the umount programm]) + fi + fi + AM_CONDITIONAL([WITH_STORAGE_VSTORAGE], [test "$with_storage_vstorage" = "yes"]) +]) + +AC_DEFUN([LIBVIRT_STORAGE_RESULT_VSTORAGE], [ + LIBVIRT_RESULT([Virtuozzo storage], [$with_storage_vstorage]) +]) -- 1.8.3.1

s/buils/build On 01/17/2017 09:10 AM, Olga Krishtal wrote:
This patch only adds --with-storage-vstorage build option. In order to use vstorage as a backend for storage pool vstorage tools should be installed.
Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- configure.ac | 4 +++ m4/virt-storage-vstorage.m4 | 73 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 m4/virt-storage-vstorage.m4
Seems reasonable to me - although I'm no expert at this stuff. Since this doesn't make sense without patch 2/5 - I'll merge before pushing, but thank you for separating for easier review. The new commit message will be "Introduce Virtuozzo vstorage backend" and commit message altered. ACK... John

On Tue, Jan 17, 2017 at 17:10:55 +0300, Olga Krishtal wrote:
This patch only adds --with-storage-vstorage build option. In order to use vstorage as a backend for storage pool vstorage tools should be installed.
Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- configure.ac | 4 +++ m4/virt-storage-vstorage.m4 | 73 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 m4/virt-storage-vstorage.m4
[...]
@@ -0,0 +1,73 @@ +dnl The storage vstorage check +dnl +dnl Copyright (C) 2016 Parallels IP Holdings GmbH, Inc.
This does not make sense. Is this company a GmbH or an Inc ?
+dnl +dnl This library is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Lesser General Public +dnl License as published by the Free Software Foundation; either +dnl version 2.1 of the License, or (at your option) any later version. +dnl +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Lesser General Public License for more details. +dnl +dnl You should have received a copy of the GNU Lesser General Public +dnl License along with this library. If not, see +dnl <http://www.gnu.org/licenses/>. +dnl

On 27/01/17 12:09, Peter Krempa wrote:
On Tue, Jan 17, 2017 at 17:10:55 +0300, Olga Krishtal wrote:
This patch only adds --with-storage-vstorage build option. In order to use vstorage as a backend for storage pool vstorage tools should be installed.
Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- configure.ac | 4 +++ m4/virt-storage-vstorage.m4 | 73 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 m4/virt-storage-vstorage.m4 [...]
@@ -0,0 +1,73 @@ +dnl The storage vstorage check +dnl +dnl Copyright (C) 2016 Parallels IP Holdings GmbH, Inc. This does not make sense. Is this company a GmbH or an Inc ?
Parallels IP Holdings GmbH - this is correct
+dnl +dnl This library is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Lesser General Public +dnl License as published by the Free Software Foundation; either +dnl version 2.1 of the License, or (at your option) any later version. +dnl +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Lesser General Public License for more details. +dnl +dnl You should have received a copy of the GNU Lesser General Public +dnl License along with this library. If not, see +dnl <http://www.gnu.org/licenses/>. +dnl
-- Best regards, Olga

On Fri, Jan 27, 2017 at 12:31:03 +0300, Olga Krishtal wrote:
On 27/01/17 12:09, Peter Krempa wrote:
On Tue, Jan 17, 2017 at 17:10:55 +0300, Olga Krishtal wrote:
This patch only adds --with-storage-vstorage build option. In order to use vstorage as a backend for storage pool vstorage tools should be installed.
Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- configure.ac | 4 +++ m4/virt-storage-vstorage.m4 | 73 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 m4/virt-storage-vstorage.m4 [...]
@@ -0,0 +1,73 @@ +dnl The storage vstorage check +dnl +dnl Copyright (C) 2016 Parallels IP Holdings GmbH, Inc. This does not make sense. Is this company a GmbH or an Inc ?
Parallels IP Holdings GmbH - this is correct
By the way, copying a file and than changing copyright information actually breaks the copyright. This is the case for this file, since there's a typo left from the 'fs' storage code that I'm going to send a patch for in a while. Also the leftover "Inc" from changing Red Hat to Parallels .. is a second clue.

On Fri, Jan 27, 2017 at 12:31:03 +0300, Olga Krishtal wrote:
On 27/01/17 12:09, Peter Krempa wrote:
On Tue, Jan 17, 2017 at 17:10:55 +0300, Olga Krishtal wrote:
This patch only adds --with-storage-vstorage build option. In order to use vstorage as a backend for storage pool vstorage tools should be installed.
Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- configure.ac | 4 +++ m4/virt-storage-vstorage.m4 | 73 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 m4/virt-storage-vstorage.m4 [...]
@@ -0,0 +1,73 @@ +dnl The storage vstorage check +dnl +dnl Copyright (C) 2016 Parallels IP Holdings GmbH, Inc. This does not make sense. Is this company a GmbH or an Inc ? Parallels IP Holdings GmbH - this is correct By the way, copying a file and than changing copyright information actually breaks the copyright.
This is the case for this file, since there's a typo left from the 'fs' storage code that I'm going to send a patch for in a while. Also the leftover "Inc" from changing Red Hat to Parallels .. is a second clue. Huh, I guess when we the new file is created the copyright should be
On 27/01/17 12:37, Peter Krempa wrote: present, isn't it? But there is no an example clean license text. =( I need to be more attentive. Do I need to send patch? -- Best regards, Olga

Added general defenitions for vstorage pool backend Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- include/libvirt/libvirt-storage.h | 1 + po/POTFILES.in | 1 + src/Makefile.am | 9 +++++++++ src/conf/storage_conf.c | 17 ++++++++++++++++- src/conf/storage_conf.h | 1 + src/storage/storage_backend.c | 6 ++++++ src/storage/storage_backend_vstorage.c | 16 ++++++++++++++++ src/storage/storage_backend_vstorage.h | 28 ++++++++++++++++++++++++++++ src/storage/storage_driver.c | 2 ++ tools/virsh-pool.c | 3 +++ tools/virsh.c | 3 +++ 11 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 src/storage/storage_backend_vstorage.c create mode 100644 src/storage/storage_backend_vstorage.h diff --git a/include/libvirt/libvirt-storage.h b/include/libvirt/libvirt-storage.h index 8a861e4..45ec720 100644 --- a/include/libvirt/libvirt-storage.h +++ b/include/libvirt/libvirt-storage.h @@ -240,6 +240,7 @@ typedef enum { VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG = 1 << 15, VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER = 1 << 16, VIR_CONNECT_LIST_STORAGE_POOLS_ZFS = 1 << 17, + VIR_CONNECT_LIST_STORAGE_POOLS_VSTORAGE = 1 << 18, } virConnectListAllStoragePoolsFlags; int virConnectListAllStoragePools(virConnectPtr conn, diff --git a/po/POTFILES.in b/po/POTFILES.in index 59efd91..b4fac0e 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -175,6 +175,7 @@ src/storage/storage_backend_mpath.c src/storage/storage_backend_rbd.c src/storage/storage_backend_scsi.c src/storage/storage_backend_sheepdog.c +src/storage/storage_backend_vstorage.c src/storage/storage_backend_zfs.c src/storage/storage_driver.c src/test/test_driver.c diff --git a/src/Makefile.am b/src/Makefile.am index 21a78e0..78e64f2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1005,6 +1005,10 @@ STORAGE_DRIVER_GLUSTER_SOURCES = \ STORAGE_DRIVER_ZFS_SOURCES = \ storage/storage_backend_zfs.h storage/storage_backend_zfs.c +STORAGE_DRIVER_VSTORAGE_SOURCES = \ + storage/storage_backend_vstorage.h \ + storage/storage_backend_vstorage.c + STORAGE_HELPER_DISK_SOURCES = \ storage/parthelper.c @@ -1712,6 +1716,10 @@ if WITH_STORAGE_ZFS libvirt_driver_storage_impl_la_SOURCES += $(STORAGE_DRIVER_ZFS_SOURCES) endif WITH_STORAGE_ZFS +if WITH_STORAGE_VSTORAGE +libvirt_driver_storage_impl_la_SOURCES += $(STORAGE_DRIVER_VSTORAGE_SOURCES) +endif WITH_STORAGE_VSTORAGE + if WITH_NODE_DEVICES # Needed to keep automake quiet about conditionals if WITH_DRIVER_MODULES @@ -1923,6 +1931,7 @@ EXTRA_DIST += \ $(STORAGE_DRIVER_SHEEPDOG_SOURCES) \ $(STORAGE_DRIVER_GLUSTER_SOURCES) \ $(STORAGE_DRIVER_ZFS_SOURCES) \ + $(STORAGE_DRIVER_VSTORAGE_SOURCES) \ $(NODE_DEVICE_DRIVER_SOURCES) \ $(NODE_DEVICE_DRIVER_HAL_SOURCES) \ $(NODE_DEVICE_DRIVER_UDEV_SOURCES) \ diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index c53f080..c9b93aa 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -60,7 +60,8 @@ VIR_ENUM_IMPL(virStoragePool, "dir", "fs", "netfs", "logical", "disk", "iscsi", "scsi", "mpath", "rbd", - "sheepdog", "gluster", "zfs") + "sheepdog", "gluster", "zfs", + "vstorage") VIR_ENUM_IMPL(virStoragePoolFormatFileSystem, VIR_STORAGE_POOL_FS_LAST, @@ -274,6 +275,16 @@ static virStoragePoolTypeInfo poolTypeInfo[] = { .defaultFormat = VIR_STORAGE_FILE_RAW, }, }, + {.poolType = VIR_STORAGE_POOL_VSTORAGE, + .poolOptions = { + .flags = VIR_STORAGE_POOL_SOURCE_NAME, + }, + .volOptions = { + .defaultFormat = VIR_STORAGE_FILE_RAW, + .formatFromString = virStorageVolumeFormatFromString, + .formatToString = virStorageFileFormatTypeToString, + }, + }, }; @@ -2611,6 +2622,10 @@ virStoragePoolSourceFindDuplicate(virConnectPtr conn, /* Only one mpath pool is valid per host */ matchpool = pool; break; + case VIR_STORAGE_POOL_VSTORAGE: + if (STREQ(pool->def->source.name, def->source.name)) + matchpool = pool; + break; case VIR_STORAGE_POOL_RBD: case VIR_STORAGE_POOL_LAST: break; diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h index b35471d..e952f5f 100644 --- a/src/conf/storage_conf.h +++ b/src/conf/storage_conf.h @@ -95,6 +95,7 @@ typedef enum { VIR_STORAGE_POOL_SHEEPDOG, /* Sheepdog device */ VIR_STORAGE_POOL_GLUSTER, /* Gluster device */ VIR_STORAGE_POOL_ZFS, /* ZFS */ + VIR_STORAGE_POOL_VSTORAGE, /* Virtuozzo Storage */ VIR_STORAGE_POOL_LAST, } virStoragePoolType; diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c index 18433e9..207a534 100644 --- a/src/storage/storage_backend.c +++ b/src/storage/storage_backend.c @@ -103,6 +103,9 @@ #if WITH_STORAGE_ZFS # include "storage_backend_zfs.h" #endif +#if WITH_STORAGE_VSTORAGE +# include "storage_backend_vstorage.h" +#endif #define VIR_FROM_THIS VIR_FROM_STORAGE @@ -143,6 +146,9 @@ static virStorageBackendPtr backends[] = { #if WITH_STORAGE_ZFS &virStorageBackendZFS, #endif +#if WITH_STORAGE_VSTORAGE + &virStorageBackendVstorage, +#endif NULL }; diff --git a/src/storage/storage_backend_vstorage.c b/src/storage/storage_backend_vstorage.c new file mode 100644 index 0000000..3a57385 --- /dev/null +++ b/src/storage/storage_backend_vstorage.c @@ -0,0 +1,16 @@ +#include <config.h> + +#include "viralloc.h" +#include "virerror.h" +#include "virfile.h" +#include "storage_backend_vstorage.h" +#include "virlog.h" +#include "virstring.h" + +#define VIR_FROM_THIS VIR_FROM_STORAGE + +VIR_LOG_INIT("storage.storage_backend_vstorage"); + +virStorageBackend virStorageBackendVstorage = { + .type = VIR_STORAGE_POOL_VSTORAGE, +}; diff --git a/src/storage/storage_backend_vstorage.h b/src/storage/storage_backend_vstorage.h new file mode 100644 index 0000000..262e454 --- /dev/null +++ b/src/storage/storage_backend_vstorage.h @@ -0,0 +1,28 @@ +/* + * storage_backend_vstorage.h: storage backend for Virtuozzo storage + * handling + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#ifndef __VIR_STORAGE_BACKEND_VSTORAGE_H__ +# define __VIR_STORAGE_BACKEND_VSTORAGE_H__ + +# include "storage_backend.h" + +extern virStorageBackend virStorageBackendVstorage; + +#endif /* __VIR_STORAGE_BACKEND_VSTORAGE_H__ */ diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index 8f1d3f0..257af80 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -1618,6 +1618,7 @@ storageVolLookupByPath(virConnectPtr conn, case VIR_STORAGE_POOL_ISCSI: case VIR_STORAGE_POOL_SCSI: case VIR_STORAGE_POOL_MPATH: + case VIR_STORAGE_POOL_VSTORAGE: stable_path = virStorageBackendStablePath(pool, cleanpath, false); @@ -3501,6 +3502,7 @@ virStorageTranslateDiskSourcePool(virConnectPtr conn, case VIR_STORAGE_POOL_DISK: case VIR_STORAGE_POOL_SCSI: case VIR_STORAGE_POOL_ZFS: + case VIR_STORAGE_POOL_VSTORAGE: if (!(def->src->path = virStorageVolGetPath(vol))) goto cleanup; diff --git a/tools/virsh-pool.c b/tools/virsh-pool.c index 6806b7a..f766be6 100644 --- a/tools/virsh-pool.c +++ b/tools/virsh-pool.c @@ -1166,6 +1166,9 @@ cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) case VIR_STORAGE_POOL_ZFS: flags |= VIR_CONNECT_LIST_STORAGE_POOLS_ZFS; break; + case VIR_STORAGE_POOL_VSTORAGE: + flags |= VIR_CONNECT_LIST_STORAGE_POOLS_VSTORAGE; + break; case VIR_STORAGE_POOL_LAST: break; } diff --git a/tools/virsh.c b/tools/virsh.c index 1068447..7eb51ab 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -648,6 +648,9 @@ virshShowVersion(vshControl *ctl ATTRIBUTE_UNUSED) #ifdef WITH_STORAGE_ZFS vshPrint(ctl, " ZFS"); #endif +#ifdef WITH_STORAGE_VSTORAGE + vshPrint(ctl, "Virtuozzo Storage"); +#endif vshPrint(ctl, "\n"); vshPrint(ctl, "%s", _(" Miscellaneous:")); -- 1.8.3.1

On 01/17/2017 09:10 AM, Olga Krishtal wrote:
Added general defenitions for vstorage pool backend
definitions
Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- include/libvirt/libvirt-storage.h | 1 + po/POTFILES.in | 1 + src/Makefile.am | 9 +++++++++ src/conf/storage_conf.c | 17 ++++++++++++++++- src/conf/storage_conf.h | 1 + src/storage/storage_backend.c | 6 ++++++ src/storage/storage_backend_vstorage.c | 16 ++++++++++++++++ src/storage/storage_backend_vstorage.h | 28 ++++++++++++++++++++++++++++ src/storage/storage_driver.c | 2 ++ tools/virsh-pool.c | 3 +++ tools/virsh.c | 3 +++ 11 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 src/storage/storage_backend_vstorage.c create mode 100644 src/storage/storage_backend_vstorage.h
FWIW: The could be conflicts w/ pkrempa's series to move the bulk of storage_backend.c into src/util/storage_util.c. I'm watching both and can make appropriate adjustments
diff --git a/include/libvirt/libvirt-storage.h b/include/libvirt/libvirt-storage.h index 8a861e4..45ec720 100644 --- a/include/libvirt/libvirt-storage.h +++ b/include/libvirt/libvirt-storage.h @@ -240,6 +240,7 @@ typedef enum { VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG = 1 << 15, VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER = 1 << 16, VIR_CONNECT_LIST_STORAGE_POOLS_ZFS = 1 << 17, + VIR_CONNECT_LIST_STORAGE_POOLS_VSTORAGE = 1 << 18, } virConnectListAllStoragePoolsFlags;
int virConnectListAllStoragePools(virConnectPtr conn, diff --git a/po/POTFILES.in b/po/POTFILES.in index 59efd91..b4fac0e 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -175,6 +175,7 @@ src/storage/storage_backend_mpath.c src/storage/storage_backend_rbd.c src/storage/storage_backend_scsi.c src/storage/storage_backend_sheepdog.c +src/storage/storage_backend_vstorage.c src/storage/storage_backend_zfs.c src/storage/storage_driver.c src/test/test_driver.c
This causes a syntax-check failure for *this* patch because there's nothing to translate in it yet, it belongs in the next patch... Causes syntax-check failure. I will adjust before pushing
diff --git a/src/Makefile.am b/src/Makefile.am index 21a78e0..78e64f2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1005,6 +1005,10 @@ STORAGE_DRIVER_GLUSTER_SOURCES = \ STORAGE_DRIVER_ZFS_SOURCES = \ storage/storage_backend_zfs.h storage/storage_backend_zfs.c
+STORAGE_DRIVER_VSTORAGE_SOURCES = \ + storage/storage_backend_vstorage.h \ + storage/storage_backend_vstorage.c +
It seems the \ should be aligned as they are for others (uses <tabs> too - I usually just cut-n-paste the previous line and alter the name). I will adjust before pushing.
STORAGE_HELPER_DISK_SOURCES = \ storage/parthelper.c
@@ -1712,6 +1716,10 @@ if WITH_STORAGE_ZFS libvirt_driver_storage_impl_la_SOURCES += $(STORAGE_DRIVER_ZFS_SOURCES) endif WITH_STORAGE_ZFS
+if WITH_STORAGE_VSTORAGE +libvirt_driver_storage_impl_la_SOURCES += $(STORAGE_DRIVER_VSTORAGE_SOURCES) +endif WITH_STORAGE_VSTORAGE + if WITH_NODE_DEVICES # Needed to keep automake quiet about conditionals if WITH_DRIVER_MODULES @@ -1923,6 +1931,7 @@ EXTRA_DIST += \ $(STORAGE_DRIVER_SHEEPDOG_SOURCES) \ $(STORAGE_DRIVER_GLUSTER_SOURCES) \ $(STORAGE_DRIVER_ZFS_SOURCES) \ + $(STORAGE_DRIVER_VSTORAGE_SOURCES) \
Again more alignment stuff. Make it all look similar. I can change. Use of <tabs> too The remainder seems OK ACK w/ adjustments and I'll push once pkrempa's series is in. John
$(NODE_DEVICE_DRIVER_SOURCES) \ $(NODE_DEVICE_DRIVER_HAL_SOURCES) \ $(NODE_DEVICE_DRIVER_UDEV_SOURCES) \ diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index c53f080..c9b93aa 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -60,7 +60,8 @@ VIR_ENUM_IMPL(virStoragePool, "dir", "fs", "netfs", "logical", "disk", "iscsi", "scsi", "mpath", "rbd", - "sheepdog", "gluster", "zfs") + "sheepdog", "gluster", "zfs", + "vstorage")
VIR_ENUM_IMPL(virStoragePoolFormatFileSystem, VIR_STORAGE_POOL_FS_LAST, @@ -274,6 +275,16 @@ static virStoragePoolTypeInfo poolTypeInfo[] = { .defaultFormat = VIR_STORAGE_FILE_RAW, }, }, + {.poolType = VIR_STORAGE_POOL_VSTORAGE, + .poolOptions = { + .flags = VIR_STORAGE_POOL_SOURCE_NAME, + }, + .volOptions = { + .defaultFormat = VIR_STORAGE_FILE_RAW, + .formatFromString = virStorageVolumeFormatFromString, + .formatToString = virStorageFileFormatTypeToString, + }, + }, };
@@ -2611,6 +2622,10 @@ virStoragePoolSourceFindDuplicate(virConnectPtr conn, /* Only one mpath pool is valid per host */ matchpool = pool; break; + case VIR_STORAGE_POOL_VSTORAGE: + if (STREQ(pool->def->source.name, def->source.name)) + matchpool = pool; + break; case VIR_STORAGE_POOL_RBD: case VIR_STORAGE_POOL_LAST: break; diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h index b35471d..e952f5f 100644 --- a/src/conf/storage_conf.h +++ b/src/conf/storage_conf.h @@ -95,6 +95,7 @@ typedef enum { VIR_STORAGE_POOL_SHEEPDOG, /* Sheepdog device */ VIR_STORAGE_POOL_GLUSTER, /* Gluster device */ VIR_STORAGE_POOL_ZFS, /* ZFS */ + VIR_STORAGE_POOL_VSTORAGE, /* Virtuozzo Storage */
VIR_STORAGE_POOL_LAST, } virStoragePoolType; diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c index 18433e9..207a534 100644 --- a/src/storage/storage_backend.c +++ b/src/storage/storage_backend.c @@ -103,6 +103,9 @@ #if WITH_STORAGE_ZFS # include "storage_backend_zfs.h" #endif +#if WITH_STORAGE_VSTORAGE +# include "storage_backend_vstorage.h" +#endif
#define VIR_FROM_THIS VIR_FROM_STORAGE
@@ -143,6 +146,9 @@ static virStorageBackendPtr backends[] = { #if WITH_STORAGE_ZFS &virStorageBackendZFS, #endif +#if WITH_STORAGE_VSTORAGE + &virStorageBackendVstorage, +#endif NULL };
diff --git a/src/storage/storage_backend_vstorage.c b/src/storage/storage_backend_vstorage.c new file mode 100644 index 0000000..3a57385 --- /dev/null +++ b/src/storage/storage_backend_vstorage.c @@ -0,0 +1,16 @@ +#include <config.h> + +#include "viralloc.h" +#include "virerror.h" +#include "virfile.h" +#include "storage_backend_vstorage.h" +#include "virlog.h" +#include "virstring.h" + +#define VIR_FROM_THIS VIR_FROM_STORAGE + +VIR_LOG_INIT("storage.storage_backend_vstorage"); + +virStorageBackend virStorageBackendVstorage = { + .type = VIR_STORAGE_POOL_VSTORAGE, +}; diff --git a/src/storage/storage_backend_vstorage.h b/src/storage/storage_backend_vstorage.h new file mode 100644 index 0000000..262e454 --- /dev/null +++ b/src/storage/storage_backend_vstorage.h @@ -0,0 +1,28 @@ +/* + * storage_backend_vstorage.h: storage backend for Virtuozzo storage + * handling + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#ifndef __VIR_STORAGE_BACKEND_VSTORAGE_H__ +# define __VIR_STORAGE_BACKEND_VSTORAGE_H__ + +# include "storage_backend.h" + +extern virStorageBackend virStorageBackendVstorage; + +#endif /* __VIR_STORAGE_BACKEND_VSTORAGE_H__ */ diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index 8f1d3f0..257af80 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -1618,6 +1618,7 @@ storageVolLookupByPath(virConnectPtr conn, case VIR_STORAGE_POOL_ISCSI: case VIR_STORAGE_POOL_SCSI: case VIR_STORAGE_POOL_MPATH: + case VIR_STORAGE_POOL_VSTORAGE: stable_path = virStorageBackendStablePath(pool, cleanpath, false); @@ -3501,6 +3502,7 @@ virStorageTranslateDiskSourcePool(virConnectPtr conn, case VIR_STORAGE_POOL_DISK: case VIR_STORAGE_POOL_SCSI: case VIR_STORAGE_POOL_ZFS: + case VIR_STORAGE_POOL_VSTORAGE: if (!(def->src->path = virStorageVolGetPath(vol))) goto cleanup;
diff --git a/tools/virsh-pool.c b/tools/virsh-pool.c index 6806b7a..f766be6 100644 --- a/tools/virsh-pool.c +++ b/tools/virsh-pool.c @@ -1166,6 +1166,9 @@ cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) case VIR_STORAGE_POOL_ZFS: flags |= VIR_CONNECT_LIST_STORAGE_POOLS_ZFS; break; + case VIR_STORAGE_POOL_VSTORAGE: + flags |= VIR_CONNECT_LIST_STORAGE_POOLS_VSTORAGE; + break; case VIR_STORAGE_POOL_LAST: break; } diff --git a/tools/virsh.c b/tools/virsh.c index 1068447..7eb51ab 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -648,6 +648,9 @@ virshShowVersion(vshControl *ctl ATTRIBUTE_UNUSED) #ifdef WITH_STORAGE_ZFS vshPrint(ctl, " ZFS"); #endif +#ifdef WITH_STORAGE_VSTORAGE + vshPrint(ctl, "Virtuozzo Storage"); +#endif vshPrint(ctl, "\n");
vshPrint(ctl, "%s", _(" Miscellaneous:"));

On 19/01/17 00:00, John Ferlan wrote: > > On 01/17/2017 09:10 AM, Olga Krishtal wrote: >> Added general defenitions for vstorage pool backend > definitions > >> Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> >> --- >> include/libvirt/libvirt-storage.h | 1 + >> po/POTFILES.in | 1 + >> src/Makefile.am | 9 +++++++++ >> src/conf/storage_conf.c | 17 ++++++++++++++++- >> src/conf/storage_conf.h | 1 + >> src/storage/storage_backend.c | 6 ++++++ >> src/storage/storage_backend_vstorage.c | 16 ++++++++++++++++ >> src/storage/storage_backend_vstorage.h | 28 ++++++++++++++++++++++++++++ >> src/storage/storage_driver.c | 2 ++ >> tools/virsh-pool.c | 3 +++ >> tools/virsh.c | 3 +++ >> 11 files changed, 86 insertions(+), 1 deletion(-) >> create mode 100644 src/storage/storage_backend_vstorage.c >> create mode 100644 src/storage/storage_backend_vstorage.h >> > FWIW: The could be conflicts w/ pkrempa's series to move the bulk of > storage_backend.c into src/util/storage_util.c. I'm watching both and > can make appropriate adjustments > > >> diff --git a/include/libvirt/libvirt-storage.h b/include/libvirt/libvirt-storage.h >> index 8a861e4..45ec720 100644 >> --- a/include/libvirt/libvirt-storage.h >> +++ b/include/libvirt/libvirt-storage.h >> @@ -240,6 +240,7 @@ typedef enum { >> VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG = 1 << 15, >> VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER = 1 << 16, >> VIR_CONNECT_LIST_STORAGE_POOLS_ZFS = 1 << 17, >> + VIR_CONNECT_LIST_STORAGE_POOLS_VSTORAGE = 1 << 18, >> } virConnectListAllStoragePoolsFlags; >> >> int virConnectListAllStoragePools(virConnectPtr conn, >> diff --git a/po/POTFILES.in b/po/POTFILES.in >> index 59efd91..b4fac0e 100644 >> --- a/po/POTFILES.in >> +++ b/po/POTFILES.in >> @@ -175,6 +175,7 @@ src/storage/storage_backend_mpath.c >> src/storage/storage_backend_rbd.c >> src/storage/storage_backend_scsi.c >> src/storage/storage_backend_sheepdog.c >> +src/storage/storage_backend_vstorage.c >> src/storage/storage_backend_zfs.c >> src/storage/storage_driver.c >> src/test/test_driver.c > This causes a syntax-check failure for *this* patch because there's > nothing to translate in it yet, it belongs in the next patch... Causes > syntax-check failure. > > I will adjust before pushing > >> diff --git a/src/Makefile.am b/src/Makefile.am >> index 21a78e0..78e64f2 100644 >> --- a/src/Makefile.am >> +++ b/src/Makefile.am >> @@ -1005,6 +1005,10 @@ STORAGE_DRIVER_GLUSTER_SOURCES = \ >> STORAGE_DRIVER_ZFS_SOURCES = \ >> storage/storage_backend_zfs.h storage/storage_backend_zfs.c >> >> +STORAGE_DRIVER_VSTORAGE_SOURCES = \ >> + storage/storage_backend_vstorage.h \ >> + storage/storage_backend_vstorage.c >> + > It seems the \ should be aligned as they are for others (uses <tabs> too > - I usually just cut-n-paste the previous line and alter the name). > > I will adjust before pushing. > > >> STORAGE_HELPER_DISK_SOURCES = \ >> storage/parthelper.c >> >> @@ -1712,6 +1716,10 @@ if WITH_STORAGE_ZFS >> libvirt_driver_storage_impl_la_SOURCES += $(STORAGE_DRIVER_ZFS_SOURCES) >> endif WITH_STORAGE_ZFS >> >> +if WITH_STORAGE_VSTORAGE >> +libvirt_driver_storage_impl_la_SOURCES += $(STORAGE_DRIVER_VSTORAGE_SOURCES) >> +endif WITH_STORAGE_VSTORAGE >> + >> if WITH_NODE_DEVICES >> # Needed to keep automake quiet about conditionals >> if WITH_DRIVER_MODULES >> @@ -1923,6 +1931,7 @@ EXTRA_DIST += \ >> $(STORAGE_DRIVER_SHEEPDOG_SOURCES) \ >> $(STORAGE_DRIVER_GLUSTER_SOURCES) \ >> $(STORAGE_DRIVER_ZFS_SOURCES) \ >> + $(STORAGE_DRIVER_VSTORAGE_SOURCES) \ > Again more alignment stuff. Make it all look similar. I can change. Use > of <tabs> too > > The remainder seems OK > > ACK w/ adjustments and I'll push once pkrempa's series is in. > > John > >> $(NODE_DEVICE_DRIVER_SOURCES) \ >> $(NODE_DEVICE_DRIVER_HAL_SOURCES) \ >> $(NODE_DEVICE_DRIVER_UDEV_SOURCES) \ >> diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c >> index c53f080..c9b93aa 100644 >> --- a/src/conf/storage_conf.c >> +++ b/src/conf/storage_conf.c >> @@ -60,7 +60,8 @@ VIR_ENUM_IMPL(virStoragePool, >> "dir", "fs", "netfs", >> "logical", "disk", "iscsi", >> "scsi", "mpath", "rbd", >> - "sheepdog", "gluster", "zfs") >> + "sheepdog", "gluster", "zfs", >> + "vstorage") >> >> VIR_ENUM_IMPL(virStoragePoolFormatFileSystem, >> VIR_STORAGE_POOL_FS_LAST, >> @@ -274,6 +275,16 @@ static virStoragePoolTypeInfo poolTypeInfo[] = { >> .defaultFormat = VIR_STORAGE_FILE_RAW, >> }, >> }, >> + {.poolType = VIR_STORAGE_POOL_VSTORAGE, >> + .poolOptions = { >> + .flags = VIR_STORAGE_POOL_SOURCE_NAME, >> + }, >> + .volOptions = { >> + .defaultFormat = VIR_STORAGE_FILE_RAW, >> + .formatFromString = virStorageVolumeFormatFromString, >> + .formatToString = virStorageFileFormatTypeToString, >> + }, >> + }, >> }; >> >> >> @@ -2611,6 +2622,10 @@ virStoragePoolSourceFindDuplicate(virConnectPtr conn, >> /* Only one mpath pool is valid per host */ >> matchpool = pool; >> break; >> + case VIR_STORAGE_POOL_VSTORAGE: >> + if (STREQ(pool->def->source.name, def->source.name)) >> + matchpool = pool; >> + break; >> case VIR_STORAGE_POOL_RBD: >> case VIR_STORAGE_POOL_LAST: >> break; >> diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h >> index b35471d..e952f5f 100644 >> --- a/src/conf/storage_conf.h >> +++ b/src/conf/storage_conf.h >> @@ -95,6 +95,7 @@ typedef enum { >> VIR_STORAGE_POOL_SHEEPDOG, /* Sheepdog device */ >> VIR_STORAGE_POOL_GLUSTER, /* Gluster device */ >> VIR_STORAGE_POOL_ZFS, /* ZFS */ >> + VIR_STORAGE_POOL_VSTORAGE, /* Virtuozzo Storage */ >> >> VIR_STORAGE_POOL_LAST, >> } virStoragePoolType; >> diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c >> index 18433e9..207a534 100644 >> --- a/src/storage/storage_backend.c >> +++ b/src/storage/storage_backend.c >> @@ -103,6 +103,9 @@ >> #if WITH_STORAGE_ZFS >> # include "storage_backend_zfs.h" >> #endif >> +#if WITH_STORAGE_VSTORAGE >> +# include "storage_backend_vstorage.h" >> +#endif >> >> #define VIR_FROM_THIS VIR_FROM_STORAGE >> >> @@ -143,6 +146,9 @@ static virStorageBackendPtr backends[] = { >> #if WITH_STORAGE_ZFS >> &virStorageBackendZFS, >> #endif >> +#if WITH_STORAGE_VSTORAGE >> + &virStorageBackendVstorage, >> +#endif >> NULL >> }; >> >> diff --git a/src/storage/storage_backend_vstorage.c b/src/storage/storage_backend_vstorage.c >> new file mode 100644 >> index 0000000..3a57385 >> --- /dev/null >> +++ b/src/storage/storage_backend_vstorage.c >> @@ -0,0 +1,16 @@ >> +#include <config.h> >> + >> +#include "viralloc.h" >> +#include "virerror.h" >> +#include "virfile.h" >> +#include "storage_backend_vstorage.h" >> +#include "virlog.h" >> +#include "virstring.h" >> + >> +#define VIR_FROM_THIS VIR_FROM_STORAGE >> + >> +VIR_LOG_INIT("storage.storage_backend_vstorage"); >> + >> +virStorageBackend virStorageBackendVstorage = { >> + .type = VIR_STORAGE_POOL_VSTORAGE, >> +}; >> diff --git a/src/storage/storage_backend_vstorage.h b/src/storage/storage_backend_vstorage.h >> new file mode 100644 >> index 0000000..262e454 >> --- /dev/null >> +++ b/src/storage/storage_backend_vstorage.h >> @@ -0,0 +1,28 @@ >> +/* >> + * storage_backend_vstorage.h: storage backend for Virtuozzo storage >> + * handling >> + * >> + * This library is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU Lesser General Public >> + * License as published by the Free Software Foundation; either >> + * version 2.1 of the License, or (at your option) any later version. >> + * >> + * This library is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >> + * Lesser General Public License for more details. >> + * >> + * You should have received a copy of the GNU Lesser General Public >> + * License along with this library. If not, see >> + * <http://www.gnu.org/licenses/>. >> + * >> + */ >> + >> +#ifndef __VIR_STORAGE_BACKEND_VSTORAGE_H__ >> +# define __VIR_STORAGE_BACKEND_VSTORAGE_H__ >> + >> +# include "storage_backend.h" >> + >> +extern virStorageBackend virStorageBackendVstorage; >> + >> +#endif /* __VIR_STORAGE_BACKEND_VSTORAGE_H__ */ >> diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c >> index 8f1d3f0..257af80 100644 >> --- a/src/storage/storage_driver.c >> +++ b/src/storage/storage_driver.c >> @@ -1618,6 +1618,7 @@ storageVolLookupByPath(virConnectPtr conn, >> case VIR_STORAGE_POOL_ISCSI: >> case VIR_STORAGE_POOL_SCSI: >> case VIR_STORAGE_POOL_MPATH: >> + case VIR_STORAGE_POOL_VSTORAGE: >> stable_path = virStorageBackendStablePath(pool, >> cleanpath, >> false); >> @@ -3501,6 +3502,7 @@ virStorageTranslateDiskSourcePool(virConnectPtr conn, >> case VIR_STORAGE_POOL_DISK: >> case VIR_STORAGE_POOL_SCSI: >> case VIR_STORAGE_POOL_ZFS: >> + case VIR_STORAGE_POOL_VSTORAGE: >> if (!(def->src->path = virStorageVolGetPath(vol))) >> goto cleanup; >> >> diff --git a/tools/virsh-pool.c b/tools/virsh-pool.c >> index 6806b7a..f766be6 100644 >> --- a/tools/virsh-pool.c >> +++ b/tools/virsh-pool.c >> @@ -1166,6 +1166,9 @@ cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) >> case VIR_STORAGE_POOL_ZFS: >> flags |= VIR_CONNECT_LIST_STORAGE_POOLS_ZFS; >> break; >> + case VIR_STORAGE_POOL_VSTORAGE: >> + flags |= VIR_CONNECT_LIST_STORAGE_POOLS_VSTORAGE; >> + break; >> case VIR_STORAGE_POOL_LAST: >> break; >> } >> diff --git a/tools/virsh.c b/tools/virsh.c >> index 1068447..7eb51ab 100644 >> --- a/tools/virsh.c >> +++ b/tools/virsh.c >> @@ -648,6 +648,9 @@ virshShowVersion(vshControl *ctl ATTRIBUTE_UNUSED) >> #ifdef WITH_STORAGE_ZFS >> vshPrint(ctl, " ZFS"); >> #endif >> +#ifdef WITH_STORAGE_VSTORAGE >> + vshPrint(ctl, "Virtuozzo Storage"); >> +#endif >> vshPrint(ctl, "\n"); >> >> vshPrint(ctl, "%s", _(" Miscellaneous:")); >> Ok -- Best regards, Olga

Added create/define/etc pool operations for vstorage backend. The vstorage storage pool looks like netfs ones. Due to this some of pool/volume functions were taken with no changes: refresh pool function. Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- src/storage/storage_backend_vstorage.c | 530 +++++++++++++++++++++++++++++++++ 1 file changed, 530 insertions(+) diff --git a/src/storage/storage_backend_vstorage.c b/src/storage/storage_backend_vstorage.c index 3a57385..8332f4d 100644 --- a/src/storage/storage_backend_vstorage.c +++ b/src/storage/storage_backend_vstorage.c @@ -6,11 +6,541 @@ #include "storage_backend_vstorage.h" #include "virlog.h" #include "virstring.h" +#include <mntent.h> +#include <pwd.h> +#include <grp.h> +#include <sys/statvfs.h> +#include <sys/stat.h> +#include <fcntl.h> #define VIR_FROM_THIS VIR_FROM_STORAGE +#define VIR_STORAGE_VOL_FS_OPEN_FLAGS (VIR_STORAGE_VOL_OPEN_DEFAULT | \ + VIR_STORAGE_VOL_OPEN_DIR) +#define VIR_STORAGE_VOL_FS_PROBE_FLAGS (VIR_STORAGE_VOL_FS_OPEN_FLAGS | \ + VIR_STORAGE_VOL_OPEN_NOERROR) + + + VIR_LOG_INIT("storage.storage_backend_vstorage"); +/** + * @conn connection to report errors against + * @pool storage pool to build + * @flags controls the pool formatting behaviour + * + * + * If no flag is set, it only makes the directory; + * If VIR_STORAGE_POOL_BUILD_NO_OVERWRITE set, it determines if + * the directory exists and if yes - we use it. Otherwise - the new one + * will be created. + * If VIR_STORAGE_POOL_BUILD_OVERWRITE is set, the dircetory for pool + * will used but the content and permissions will be updated + * + * Returns 0 on success, -1 on error + */ + +static int +virStorageBackendVzPoolBuild(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool, + unsigned int flags) +{ + int ret = -1; + char *parent = NULL; + char *p = NULL; + mode_t mode; + unsigned int dir_create_flags; + + virCheckFlags(VIR_STORAGE_POOL_BUILD_OVERWRITE | + VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, ret); + + VIR_EXCLUSIVE_FLAGS_GOTO(VIR_STORAGE_POOL_BUILD_OVERWRITE, + VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, + error); + + if (VIR_STRDUP(parent, pool->def->target.path) < 0) + goto error; + if (!(p = strrchr(parent, '/'))) { + virReportError(VIR_ERR_INVALID_ARG, + _("path '%s' is not absolute"), + pool->def->target.path); + goto error; + } + + if (p != parent) { + /* assure all directories in the path prior to the final dir + * exist, with default uid/gid/mode. */ + *p = '\0'; + if (virFileMakePath(parent) < 0) { + virReportSystemError(errno, _("cannot create path '%s'"), + parent); + goto error; + } + } + + dir_create_flags = VIR_DIR_CREATE_ALLOW_EXIST; + mode = pool->def->target.perms.mode; + + if (mode == (mode_t) -1 && !virFileExists(pool->def->target.path)) + mode = VIR_STORAGE_DEFAULT_POOL_PERM_MODE; + + /* Now create the final dir in the path with the uid/gid/mode + * requested in the config. If the dir already exists, just set + * the perms. */ + if (virDirCreate(pool->def->target.path, + mode, + pool->def->target.perms.uid, + pool->def->target.perms.gid, + dir_create_flags) < 0) + goto error; + + /* Delete directory content if flag is set*/ + if (flags & VIR_STORAGE_POOL_BUILD_OVERWRITE) + if (virFileDeleteTree(pool->def->target.path)) + goto error; + + ret = 0; + + error: + VIR_FREE(parent); + return ret; +} + +static int +virStorageBackendVzPoolStart(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool) +{ + int ret = -1; + virCommandPtr cmd = NULL; + char *grp_name = NULL; + char *usr_name = NULL; + char *mode = NULL; + + /* Check the permissions */ + if (pool->def->target.perms.mode == (mode_t) - 1) + pool->def->target.perms.mode = VIR_STORAGE_DEFAULT_POOL_PERM_MODE; + if (pool->def->target.perms.uid == (uid_t) -1) + pool->def->target.perms.uid = geteuid(); + if (pool->def->target.perms.gid == (gid_t) -1) + pool->def->target.perms.gid = getegid(); + + /* Convert ids to names because vstorage uses names */ + + grp_name = virGetGroupName(pool->def->target.perms.gid); + if (!grp_name) + return -1; + + usr_name = virGetUserName(pool->def->target.perms.uid); + if (!usr_name) + return -1; + + if (virAsprintf(&mode, "%o", pool->def->target.perms.mode) < 0) + return -1; + + cmd = virCommandNewArgList(VSTORAGE_MOUNT, + "-c", pool->def->source.name, + pool->def->target.path, + "-m", mode, + "-g", grp_name, "-u", usr_name, + NULL); + + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; + ret = 0; + + cleanup: + virCommandFree(cmd); + VIR_FREE(mode); + VIR_FREE(grp_name); + VIR_FREE(usr_name); + return ret; +} + +static int +virStorageBackendVzIsMounted(virStoragePoolObjPtr pool) +{ + int ret = -1; + char *src = NULL; + FILE *mtab; + struct mntent ent; + char buf[1024]; + char *cluster = NULL; + + if (virAsprintf(&cluster, "vstorage://%s", pool->def->source.name) < 0) + return -1; + + if ((mtab = fopen(_PATH_MOUNTED, "r")) == NULL) { + virReportSystemError(errno, + _("cannot read mount list '%s'"), + _PATH_MOUNTED); + goto cleanup; + } + + while ((getmntent_r(mtab, &ent, buf, sizeof(buf))) != NULL) { + + if (STREQ(ent.mnt_dir, pool->def->target.path) && + STREQ(ent.mnt_fsname, cluster)) { + ret = 1; + goto cleanup; + } + + VIR_FREE(src); + } + + ret = 0; + + cleanup: + VIR_FORCE_FCLOSE(mtab); + VIR_FREE(src); + VIR_FREE(cluster); + return ret; +} + +static int +virStorageBackendVzUmount(virStoragePoolObjPtr pool) +{ + virCommandPtr cmd = NULL; + int ret = -1; + int rc; + + /* Short-circuit if already unmounted */ + if ((rc = virStorageBackendVzIsMounted(pool)) != 1) + return rc; + + cmd = virCommandNewArgList(UMOUNT, + pool->def->target.path, + NULL); + + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; + + ret = 0; + cleanup: + virCommandFree(cmd); + return ret; +} + +static int +virStorageBackendVzPoolStop(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool) +{ + if (virStorageBackendVzUmount(pool) < 0) + return -1; + + return 0; +} + +/** + * @conn connection to report errors against + * @pool storage pool to delete + * + * Deletes vstorage based storage pool. + * At this moment vstorage is in umounted state - so we do not + * need to delete volumes first. + * Returns 0 on success, -1 on error + */ +static int +virStorageBackendVzDelete(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool, + unsigned int flags) +{ + virCheckFlags(0, -1); + + if (rmdir(pool->def->target.path) < 0) { + virReportSystemError(errno, + _("failed to remove pool '%s'"), + pool->def->target.path); + return -1; + } + + return 0; +} + +/* + * Check wether the cluster is mounted + */ +static int +virStorageBackendVzCheck(virStoragePoolObjPtr pool, + bool *isActive) +{ + int ret = -1; + *isActive = false; + if ((ret = virStorageBackendVzIsMounted(pool)) != 0) { + if (ret < 0) + return -1; + *isActive = true; + } + + return 0; +} + +/* All the underlying functions were directly copied from + * filesystem backend with no changes. + */ + +static int +virStorageBackendProbeTarget(virStorageSourcePtr target, + virStorageEncryptionPtr *encryption) +{ + int backingStoreFormat; + int fd = -1; + int ret = -1; + int rc; + virStorageSourcePtr meta = NULL; + struct stat sb; + + if (encryption) + *encryption = NULL; + + if ((rc = virStorageBackendVolOpen(target->path, &sb, + VIR_STORAGE_VOL_FS_PROBE_FLAGS)) < 0) + return rc; /* Take care to propagate rc, it is not always -1 */ + fd = rc; + + if (virStorageBackendUpdateVolTargetInfoFD(target, fd, &sb) < 0) + goto cleanup; + + if (S_ISDIR(sb.st_mode)) { + if (virStorageBackendIsPloopDir(target->path)) { + if (virStorageBackendRedoPloopUpdate(target, &sb, &fd, + VIR_STORAGE_VOL_FS_PROBE_FLAGS) < 0) + goto cleanup; + } else { + target->format = VIR_STORAGE_FILE_DIR; + ret = 0; + goto cleanup; + } + } + + if (!(meta = virStorageFileGetMetadataFromFD(target->path, + fd, + VIR_STORAGE_FILE_AUTO, + &backingStoreFormat))) + goto cleanup; + + if (meta->backingStoreRaw) { + if (!(target->backingStore = virStorageSourceNewFromBacking(meta))) + goto cleanup; + + target->backingStore->format = backingStoreFormat; + + /* XXX: Remote storage doesn't play nicely with volumes backed by + * remote storage. To avoid trouble, just fake the backing store is RAW + * and put the string from the metadata as the path of the target. */ + if (!virStorageSourceIsLocalStorage(target->backingStore)) { + virStorageSourceFree(target->backingStore); + + if (VIR_ALLOC(target->backingStore) < 0) + goto cleanup; + + target->backingStore->type = VIR_STORAGE_TYPE_NETWORK; + target->backingStore->path = meta->backingStoreRaw; + meta->backingStoreRaw = NULL; + target->backingStore->format = VIR_STORAGE_FILE_RAW; + } + + if (target->backingStore->format == VIR_STORAGE_FILE_AUTO) { + if ((rc = virStorageFileProbeFormat(target->backingStore->path, + -1, -1)) < 0) { + /* If the backing file is currently unavailable or is + * accessed via remote protocol only log an error, fake the + * format as RAW and continue. Returning -1 here would + * disable the whole storage pool, making it unavailable for + * even maintenance. */ + target->backingStore->format = VIR_STORAGE_FILE_RAW; + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot probe backing volume format: %s"), + target->backingStore->path); + } else { + target->backingStore->format = rc; + } + } + } + + target->format = meta->format; + + /* Default to success below this point */ + ret = 0; + + if (meta->capacity) + target->capacity = meta->capacity; + + if (encryption && meta->encryption) { + *encryption = meta->encryption; + meta->encryption = NULL; + + /* XXX ideally we'd fill in secret UUID here + * but we cannot guarantee 'conn' is non-NULL + * at this point in time :-( So we only fill + * in secrets when someone first queries a vol + */ + } + + virBitmapFree(target->features); + target->features = meta->features; + meta->features = NULL; + + if (meta->compat) { + VIR_FREE(target->compat); + target->compat = meta->compat; + meta->compat = NULL; + } + + cleanup: + VIR_FORCE_CLOSE(fd); + virStorageSourceFree(meta); + return ret; + +} + +/** + * The same as for fs/dir storage pools + * Iterate over the pool's directory and enumerate all disk images + * within it. This is non-recursive. + */ + +static int +virStorageBackendVzRefresh(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool) +{ + DIR *dir; + struct dirent *ent; + struct statvfs sb; + struct stat statbuf; + virStorageVolDefPtr vol = NULL; + virStorageSourcePtr target = NULL; + int direrr; + int fd = -1, ret = -1; + + if (virDirOpen(&dir, pool->def->target.path) < 0) + goto cleanup; + + while ((direrr = virDirRead(dir, &ent, pool->def->target.path)) > 0) { + int err; + + if (virStringHasControlChars(ent->d_name)) { + VIR_WARN("Ignoring file with control characters under '%s'", + pool->def->target.path); + continue; + } + + if (VIR_ALLOC(vol) < 0) + goto cleanup; + + if (VIR_STRDUP(vol->name, ent->d_name) < 0) + goto cleanup; + + vol->type = VIR_STORAGE_VOL_FILE; + vol->target.format = VIR_STORAGE_FILE_RAW; /* Real value is filled in during probe */ + if (virAsprintf(&vol->target.path, "%s/%s", + pool->def->target.path, + vol->name) == -1) + goto cleanup; + + if (VIR_STRDUP(vol->key, vol->target.path) < 0) + goto cleanup; + + if ((err = virStorageBackendProbeTarget(&vol->target, + &vol->target.encryption)) < 0) { + if (err == -2) { + /* Silently ignore non-regular files, + * eg 'lost+found', dangling symbolic link */ + virStorageVolDefFree(vol); + vol = NULL; + continue; + } else if (err == -3) { + /* The backing file is currently unavailable, its format is not + * explicitly specified, the probe to auto detect the format + * failed: continue with faked RAW format, since AUTO will + * break virStorageVolTargetDefFormat() generating the line + * <format type='...'/>. */ + } else { + goto cleanup; + } + } + + /* directory based volume */ + if (vol->target.format == VIR_STORAGE_FILE_DIR) + vol->type = VIR_STORAGE_VOL_DIR; + + if (vol->target.format == VIR_STORAGE_FILE_PLOOP) + vol->type = VIR_STORAGE_VOL_PLOOP; + + if (vol->target.backingStore) { + ignore_value(virStorageBackendUpdateVolTargetInfo(vol->target.backingStore, + false, + VIR_STORAGE_VOL_OPEN_DEFAULT, 0)); + /* If this failed, the backing file is currently unavailable, + * the capacity, allocation, owner, group and mode are unknown. + * An error message was raised, but we just continue. */ + } + + if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0) + goto cleanup; + } + if (direrr < 0) + goto cleanup; + VIR_DIR_CLOSE(dir); + vol = NULL; + + if (VIR_ALLOC(target)) + goto cleanup; + + if ((fd = open(pool->def->target.path, O_RDONLY)) < 0) { + virReportSystemError(errno, + _("cannot open path '%s'"), + pool->def->target.path); + goto cleanup; + } + + if (fstat(fd, &statbuf) < 0) { + virReportSystemError(errno, + _("cannot stat path '%s'"), + pool->def->target.path); + goto cleanup; + } + + if (virStorageBackendUpdateVolTargetInfoFD(target, fd, &statbuf) < 0) + goto cleanup; + + /* VolTargetInfoFD doesn't update capacity correctly for the pool case */ + if (statvfs(pool->def->target.path, &sb) < 0) { + virReportSystemError(errno, + _("cannot statvfs path '%s'"), + pool->def->target.path); + goto cleanup; + } + + pool->def->capacity = ((unsigned long long)sb.f_frsize * + (unsigned long long)sb.f_blocks); + pool->def->available = ((unsigned long long)sb.f_bfree * + (unsigned long long)sb.f_frsize); + pool->def->allocation = pool->def->capacity - pool->def->available; + + pool->def->target.perms.mode = target->perms->mode; + pool->def->target.perms.uid = target->perms->uid; + pool->def->target.perms.gid = target->perms->gid; + VIR_FREE(pool->def->target.perms.label); + if (VIR_STRDUP(pool->def->target.perms.label, target->perms->label) < 0) + goto cleanup; + + ret = 0; + cleanup: + VIR_DIR_CLOSE(dir); + VIR_FORCE_CLOSE(fd); + virStorageVolDefFree(vol); + virStorageSourceFree(target); + if (ret < 0) + virStoragePoolObjClearVols(pool); + return ret; +} virStorageBackend virStorageBackendVstorage = { .type = VIR_STORAGE_POOL_VSTORAGE, + + .buildPool = virStorageBackendVzPoolBuild, + .startPool = virStorageBackendVzPoolStart, + .stopPool = virStorageBackendVzPoolStop, + .deletePool = virStorageBackendVzDelete, + .refreshPool = virStorageBackendVzRefresh, + .checkPool = virStorageBackendVzCheck, }; -- 1.8.3.1

On 01/17/2017 09:10 AM, Olga Krishtal wrote:
Added create/define/etc pool operations for vstorage backend.
The vstorage storage pool looks like netfs ones. Due to this some of pool/volume functions were taken with no changes: refresh pool function.
Not exactly what I was expecting - perhaps I didn't explain well enough. I was hoping you would create common API helpers and call from *_fs.c and *_vstorage.c. Of course, this is where that set of changes would start overlapping with a what pkrempa is doing by creating a common storage_util.c (currently the common place would be storage_backend.c) [1]. Since I'm watching [1] and I'd like for you to see progress here, I can create the common functions once [1] is completed - which should be soon. I'll mark places below with [2] for your reference.
Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- src/storage/storage_backend_vstorage.c | 530 +++++++++++++++++++++++++++++++++ 1 file changed, 530 insertions(+)
diff --git a/src/storage/storage_backend_vstorage.c b/src/storage/storage_backend_vstorage.c index 3a57385..8332f4d 100644 --- a/src/storage/storage_backend_vstorage.c +++ b/src/storage/storage_backend_vstorage.c @@ -6,11 +6,541 @@ #include "storage_backend_vstorage.h" #include "virlog.h" #include "virstring.h" +#include <mntent.h> +#include <pwd.h> +#include <grp.h>
+#include <sys/statvfs.h> +#include <sys/stat.h> +#include <fcntl.h>
[2] These 3 won't be necessary...
#define VIR_FROM_THIS VIR_FROM_STORAGE
+#define VIR_STORAGE_VOL_FS_OPEN_FLAGS (VIR_STORAGE_VOL_OPEN_DEFAULT | \ + VIR_STORAGE_VOL_OPEN_DIR) +#define VIR_STORAGE_VOL_FS_PROBE_FLAGS (VIR_STORAGE_VOL_FS_OPEN_FLAGS | \ + VIR_STORAGE_VOL_OPEN_NOERROR)
[2] These flags move to storage_backend.h near where VIR_STORAGE_VOL_OPEN_DEFAULT is defined...
+ + +
Some strange spacing here. I think if you move the VIR_LOG_INIT up betwen the #define's and have the right spacing it'll be OK.
VIR_LOG_INIT("storage.storage_backend_vstorage");
Need at least an empty line between
+/** + * @conn connection to report errors against + * @pool storage pool to build + * @flags controls the pool formatting behaviour + * + * + * If no flag is set, it only makes the directory; + * If VIR_STORAGE_POOL_BUILD_NO_OVERWRITE set, it determines if + * the directory exists and if yes - we use it. Otherwise - the new one + * will be created. + * If VIR_STORAGE_POOL_BUILD_OVERWRITE is set, the dircetory for pool + * will used but the content and permissions will be update
see [3]
+ * + * Returns 0 on success, -1 on error + */ + +static int +virStorageBackendVzPoolBuild(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool, + unsigned int flags) +{
[2 - snip most into virStorageBackendBuildFileDirCommon()] keep: unsigned int dir_create_flags = 0;
+ int ret = -1; + char *parent = NULL; + char *p = NULL; + mode_t mode; + unsigned int dir_create_flags; + + virCheckFlags(VIR_STORAGE_POOL_BUILD_OVERWRITE | + VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, ret); + + VIR_EXCLUSIVE_FLAGS_GOTO(VIR_STORAGE_POOL_BUILD_OVERWRITE, + VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, + error); + + if (VIR_STRDUP(parent, pool->def->target.path) < 0) + goto error; + if (!(p = strrchr(parent, '/'))) { + virReportError(VIR_ERR_INVALID_ARG, + _("path '%s' is not absolute"), + pool->def->target.path); + goto error; + } + + if (p != parent) { + /* assure all directories in the path prior to the final dir + * exist, with default uid/gid/mode. */ + *p = '\0'; + if (virFileMakePath(parent) < 0) { + virReportSystemError(errno, _("cannot create path '%s'"), + parent); + goto error; + } + } + + dir_create_flags = VIR_DIR_CREATE_ALLOW_EXIST; + mode = pool->def->target.perms.mode; + + if (mode == (mode_t) -1 && !virFileExists(pool->def->target.path)) + mode = VIR_STORAGE_DEFAULT_POOL_PERM_MODE; + + /* Now create the final dir in the path with the uid/gid/mode + * requested in the config. If the dir already exists, just set + * the perms. */ + if (virDirCreate(pool->def->target.path, + mode, + pool->def->target.perms.uid, + pool->def->target.perms.gid, + dir_create_flags) < 0) + goto error;
[2 end snip]
+ + /* Delete directory content if flag is set*/
should be "set */"
+ if (flags & VIR_STORAGE_POOL_BUILD_OVERWRITE) + if (virFileDeleteTree(pool->def->target.path)) + goto error;
[3] This block doesn't make sense in light of the virDirCreate just above *and* the intro comments. If you want to support [NO_]OVERWRITE, then prior to calling the common function we can play with flags, thus you end up with just: if (flags & VIR_STORAGE_POOL_BUILD_OVERWRITE) dir_create_flags |= VIR_DIR_CREATE_ALLOW_EXIST; return virStorageBackendBuildFileDirCommon(pool, dir_create_flags); The *_fs.c code would be unsigned int dir_create_flags = VIR_DIR_CREATE_ALLOW_EXIST; ... if (virStorageBackendBuildFileDirCommon(pool, dir_create_flags) < 0) goto error; ... and the common code would receive dir_create_flags The comments would then need to be updated a bit... If you have a suggestion or would prefer to just follow the *_fs.c model - I can adjust that too - let me know.
+ + ret = 0; + + error: + VIR_FREE(parent); + return ret; +} + +static int +virStorageBackendVzPoolStart(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool) +{ + int ret = -1; + virCommandPtr cmd = NULL; + char *grp_name = NULL; + char *usr_name = NULL; + char *mode = NULL; + + /* Check the permissions */ + if (pool->def->target.perms.mode == (mode_t) - 1) + pool->def->target.perms.mode = VIR_STORAGE_DEFAULT_POOL_PERM_MODE; + if (pool->def->target.perms.uid == (uid_t) -1) + pool->def->target.perms.uid = geteuid(); + if (pool->def->target.perms.gid == (gid_t) -1) + pool->def->target.perms.gid = getegid(); + + /* Convert ids to names because vstorage uses names */ + + grp_name = virGetGroupName(pool->def->target.perms.gid); + if (!grp_name) + return -1; + + usr_name = virGetUserName(pool->def->target.perms.uid); + if (!usr_name) + return -1;
Leak grp_name
+ + if (virAsprintf(&mode, "%o", pool->def->target.perms.mode) < 0) + return -1;
Leak grp_name, usr_name Each of these changes to a goto cleanup;
+ + cmd = virCommandNewArgList(VSTORAGE_MOUNT, + "-c", pool->def->source.name, + pool->def->target.path, + "-m", mode, + "-g", grp_name, "-u", usr_name, + NULL); + + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; + ret = 0; + + cleanup: + virCommandFree(cmd); + VIR_FREE(mode); + VIR_FREE(grp_name); + VIR_FREE(usr_name); + return ret; +} + +static int +virStorageBackendVzIsMounted(virStoragePoolObjPtr pool) +{ + int ret = -1; + char *src = NULL;
Never used - I'll remove
+ FILE *mtab; + struct mntent ent; + char buf[1024]; + char *cluster = NULL; + + if (virAsprintf(&cluster, "vstorage://%s", pool->def->source.name) < 0) + return -1; + + if ((mtab = fopen(_PATH_MOUNTED, "r")) == NULL) { + virReportSystemError(errno, + _("cannot read mount list '%s'"), + _PATH_MOUNTED); + goto cleanup; + } + + while ((getmntent_r(mtab, &ent, buf, sizeof(buf))) != NULL) { + + if (STREQ(ent.mnt_dir, pool->def->target.path) && + STREQ(ent.mnt_fsname, cluster)) { + ret = 1; + goto cleanup; + } + + VIR_FREE(src); + } + + ret = 0; + + cleanup: + VIR_FORCE_FCLOSE(mtab); + VIR_FREE(src); + VIR_FREE(cluster); + return ret; +} + +static int +virStorageBackendVzUmount(virStoragePoolObjPtr pool) +{ + virCommandPtr cmd = NULL; + int ret = -1; + int rc; + + /* Short-circuit if already unmounted */ + if ((rc = virStorageBackendVzIsMounted(pool)) != 1) + return rc; +
[2] The following has commonality with _fs.c - use "return virStorageBackendUmountCommon(pool);"
+ cmd = virCommandNewArgList(UMOUNT, + pool->def->target.path, + NULL); + + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; + + ret = 0; + cleanup: + virCommandFree(cmd); + return ret; +} + +static int +virStorageBackendVzPoolStop(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool) +{ + if (virStorageBackendVzUmount(pool) < 0) + return -1; + + return 0; +} + +/** + * @conn connection to report errors against + * @pool storage pool to delete + * + * Deletes vstorage based storage pool. + * At this moment vstorage is in umounted state - so we do not + * need to delete volumes first. + * Returns 0 on success, -1 on error + */ +static int +virStorageBackendVzDelete(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool, + unsigned int flags) +{ + virCheckFlags(0, -1);
[2] This could be a return virStorageBackendDeleteDirCommon(pool);
+ + if (rmdir(pool->def->target.path) < 0) { + virReportSystemError(errno, + _("failed to remove pool '%s'"), + pool->def->target.path); + return -1; + } + + return 0; +} + +/* + * Check wether the cluster is mounted
whether
+ */ +static int +virStorageBackendVzCheck(virStoragePoolObjPtr pool, + bool *isActive) +{ + int ret = -1; + *isActive = false; + if ((ret = virStorageBackendVzIsMounted(pool)) != 0) { + if (ret < 0) + return -1; + *isActive = true; + } + + return 0; +} +
[2 - start] - This whole hunk moves to common module
+/* All the underlying functions were directly copied from + * filesystem backend with no changes. + */ + +static int +virStorageBackendProbeTarget(virStorageSourcePtr target, + virStorageEncryptionPtr *encryption) +{ + int backingStoreFormat; + int fd = -1; + int ret = -1; + int rc; + virStorageSourcePtr meta = NULL; + struct stat sb; + + if (encryption) + *encryption = NULL; + + if ((rc = virStorageBackendVolOpen(target->path, &sb, + VIR_STORAGE_VOL_FS_PROBE_FLAGS)) < 0) + return rc; /* Take care to propagate rc, it is not always -1 */ + fd = rc; + + if (virStorageBackendUpdateVolTargetInfoFD(target, fd, &sb) < 0) + goto cleanup; + + if (S_ISDIR(sb.st_mode)) { + if (virStorageBackendIsPloopDir(target->path)) { + if (virStorageBackendRedoPloopUpdate(target, &sb, &fd, + VIR_STORAGE_VOL_FS_PROBE_FLAGS) < 0) + goto cleanup; + } else { + target->format = VIR_STORAGE_FILE_DIR; + ret = 0; + goto cleanup; + } + } + + if (!(meta = virStorageFileGetMetadataFromFD(target->path, + fd, + VIR_STORAGE_FILE_AUTO, + &backingStoreFormat))) + goto cleanup; + + if (meta->backingStoreRaw) { + if (!(target->backingStore = virStorageSourceNewFromBacking(meta))) + goto cleanup; + + target->backingStore->format = backingStoreFormat; + + /* XXX: Remote storage doesn't play nicely with volumes backed by + * remote storage. To avoid trouble, just fake the backing store is RAW + * and put the string from the metadata as the path of the target. */ + if (!virStorageSourceIsLocalStorage(target->backingStore)) { + virStorageSourceFree(target->backingStore); + + if (VIR_ALLOC(target->backingStore) < 0) + goto cleanup; + + target->backingStore->type = VIR_STORAGE_TYPE_NETWORK; + target->backingStore->path = meta->backingStoreRaw; + meta->backingStoreRaw = NULL; + target->backingStore->format = VIR_STORAGE_FILE_RAW; + } + + if (target->backingStore->format == VIR_STORAGE_FILE_AUTO) { + if ((rc = virStorageFileProbeFormat(target->backingStore->path, + -1, -1)) < 0) { + /* If the backing file is currently unavailable or is + * accessed via remote protocol only log an error, fake the + * format as RAW and continue. Returning -1 here would + * disable the whole storage pool, making it unavailable for + * even maintenance. */ + target->backingStore->format = VIR_STORAGE_FILE_RAW; + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot probe backing volume format: %s"), + target->backingStore->path); + } else { + target->backingStore->format = rc; + } + } + } + + target->format = meta->format; + + /* Default to success below this point */ + ret = 0; + + if (meta->capacity) + target->capacity = meta->capacity; + + if (encryption && meta->encryption) { + *encryption = meta->encryption; + meta->encryption = NULL; + + /* XXX ideally we'd fill in secret UUID here + * but we cannot guarantee 'conn' is non-NULL + * at this point in time :-( So we only fill + * in secrets when someone first queries a vol + */ + } + + virBitmapFree(target->features); + target->features = meta->features; + meta->features = NULL; + + if (meta->compat) { + VIR_FREE(target->compat); + target->compat = meta->compat; + meta->compat = NULL; + } + + cleanup: + VIR_FORCE_CLOSE(fd); + virStorageSourceFree(meta); + return ret; + +}
[2] - end
+ +/** + * The same as for fs/dir storage pools + * Iterate over the pool's directory and enumerate all disk images + * within it. This is non-recursive. + */
Scratch the comment
+ +static int +virStorageBackendVzRefresh(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool) +{
[2] all the code moves: return virStorageBackendRefreshFileDirCommon(pool);
+ DIR *dir; + struct dirent *ent; + struct statvfs sb; + struct stat statbuf; + virStorageVolDefPtr vol = NULL; + virStorageSourcePtr target = NULL; + int direrr; + int fd = -1, ret = -1; + + if (virDirOpen(&dir, pool->def->target.path) < 0) + goto cleanup; + + while ((direrr = virDirRead(dir, &ent, pool->def->target.path)) > 0) { + int err; + + if (virStringHasControlChars(ent->d_name)) { + VIR_WARN("Ignoring file with control characters under '%s'", + pool->def->target.path); + continue; + } + + if (VIR_ALLOC(vol) < 0) + goto cleanup; + + if (VIR_STRDUP(vol->name, ent->d_name) < 0) + goto cleanup; + + vol->type = VIR_STORAGE_VOL_FILE; + vol->target.format = VIR_STORAGE_FILE_RAW; /* Real value is filled in during probe */ + if (virAsprintf(&vol->target.path, "%s/%s", + pool->def->target.path, + vol->name) == -1) + goto cleanup; + + if (VIR_STRDUP(vol->key, vol->target.path) < 0) + goto cleanup; + + if ((err = virStorageBackendProbeTarget(&vol->target, + &vol->target.encryption)) < 0) { + if (err == -2) { + /* Silently ignore non-regular files, + * eg 'lost+found', dangling symbolic link */ + virStorageVolDefFree(vol); + vol = NULL; + continue; + } else if (err == -3) { + /* The backing file is currently unavailable, its format is not + * explicitly specified, the probe to auto detect the format + * failed: continue with faked RAW format, since AUTO will + * break virStorageVolTargetDefFormat() generating the line + * <format type='...'/>. */ + } else { + goto cleanup; + } + } + + /* directory based volume */ + if (vol->target.format == VIR_STORAGE_FILE_DIR) + vol->type = VIR_STORAGE_VOL_DIR; + + if (vol->target.format == VIR_STORAGE_FILE_PLOOP) + vol->type = VIR_STORAGE_VOL_PLOOP; + + if (vol->target.backingStore) { + ignore_value(virStorageBackendUpdateVolTargetInfo(vol->target.backingStore, + false, + VIR_STORAGE_VOL_OPEN_DEFAULT, 0));
NB: I had a patch here today - this is why cut/copy/paste is not preferred...
+ /* If this failed, the backing file is currently unavailable, + * the capacity, allocation, owner, group and mode are unknown. + * An error message was raised, but we just continue. */ + } + + if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0) + goto cleanup; + } + if (direrr < 0) + goto cleanup; + VIR_DIR_CLOSE(dir); + vol = NULL; + + if (VIR_ALLOC(target)) + goto cleanup; + + if ((fd = open(pool->def->target.path, O_RDONLY)) < 0) { + virReportSystemError(errno, + _("cannot open path '%s'"), + pool->def->target.path); + goto cleanup; + } + + if (fstat(fd, &statbuf) < 0) { + virReportSystemError(errno, + _("cannot stat path '%s'"), + pool->def->target.path); + goto cleanup; + } + + if (virStorageBackendUpdateVolTargetInfoFD(target, fd, &statbuf) < 0) + goto cleanup; + + /* VolTargetInfoFD doesn't update capacity correctly for the pool case */ + if (statvfs(pool->def->target.path, &sb) < 0) { + virReportSystemError(errno, + _("cannot statvfs path '%s'"), + pool->def->target.path); + goto cleanup; + } + + pool->def->capacity = ((unsigned long long)sb.f_frsize * + (unsigned long long)sb.f_blocks); + pool->def->available = ((unsigned long long)sb.f_bfree * + (unsigned long long)sb.f_frsize); + pool->def->allocation = pool->def->capacity - pool->def->available; + + pool->def->target.perms.mode = target->perms->mode; + pool->def->target.perms.uid = target->perms->uid; + pool->def->target.perms.gid = target->perms->gid; + VIR_FREE(pool->def->target.perms.label); + if (VIR_STRDUP(pool->def->target.perms.label, target->perms->label) < 0) + goto cleanup; + + ret = 0; + cleanup: + VIR_DIR_CLOSE(dir); + VIR_FORCE_CLOSE(fd); + virStorageVolDefFree(vol); + virStorageSourceFree(target); + if (ret < 0) + virStoragePoolObjClearVols(pool); + return ret; +}
[2 - end] Once this is all done - this file is much shorter and you gain the benefit of any adjustments to the common code - which will happen... and this code wouldn't be updated... I'll make the updates though - it won't happen overnight - should be by the end of the week. John
virStorageBackend virStorageBackendVstorage = { .type = VIR_STORAGE_POOL_VSTORAGE, + + .buildPool = virStorageBackendVzPoolBuild, + .startPool = virStorageBackendVzPoolStart, + .stopPool = virStorageBackendVzPoolStop, + .deletePool = virStorageBackendVzDelete, + .refreshPool = virStorageBackendVzRefresh, + .checkPool = virStorageBackendVzCheck, };

On 19/01/17 00:04, John Ferlan wrote:
On 01/17/2017 09:10 AM, Olga Krishtal wrote:
Added create/define/etc pool operations for vstorage backend.
The vstorage storage pool looks like netfs ones. Due to this some of pool/volume functions were taken with no changes: refresh pool function. Not exactly what I was expecting - perhaps I didn't explain well enough. I was hoping you would create common API helpers and call from *_fs.c and *_vstorage.c.
Of course, this is where that set of changes would start overlapping with a what pkrempa is doing by creating a common storage_util.c (currently the common place would be storage_backend.c) [1].
Since I'm watching [1] and I'd like for you to see progress here, I can create the common functions once [1] is completed - which should be soon. I'll mark places below with [2] for your reference.
I will follow changes
Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- src/storage/storage_backend_vstorage.c | 530 +++++++++++++++++++++++++++++++++ 1 file changed, 530 insertions(+)
diff --git a/src/storage/storage_backend_vstorage.c b/src/storage/storage_backend_vstorage.c index 3a57385..8332f4d 100644 --- a/src/storage/storage_backend_vstorage.c +++ b/src/storage/storage_backend_vstorage.c @@ -6,11 +6,541 @@ #include "storage_backend_vstorage.h" #include "virlog.h" #include "virstring.h" +#include <mntent.h> +#include <pwd.h> +#include <grp.h> +#include <sys/statvfs.h> +#include <sys/stat.h> +#include <fcntl.h> [2] These 3 won't be necessary...
#define VIR_FROM_THIS VIR_FROM_STORAGE
+#define VIR_STORAGE_VOL_FS_OPEN_FLAGS (VIR_STORAGE_VOL_OPEN_DEFAULT | \ + VIR_STORAGE_VOL_OPEN_DIR) +#define VIR_STORAGE_VOL_FS_PROBE_FLAGS (VIR_STORAGE_VOL_FS_OPEN_FLAGS | \ + VIR_STORAGE_VOL_OPEN_NOERROR)
[2] These flags move to storage_backend.h near where VIR_STORAGE_VOL_OPEN_DEFAULT is defined...
+ + + Some strange spacing here. I think if you move the VIR_LOG_INIT up betwen the #define's and have the right spacing it'll be OK.
VIR_LOG_INIT("storage.storage_backend_vstorage"); Need at least an empty line between
+/** + * @conn connection to report errors against + * @pool storage pool to build + * @flags controls the pool formatting behaviour + * + * + * If no flag is set, it only makes the directory; + * If VIR_STORAGE_POOL_BUILD_NO_OVERWRITE set, it determines if + * the directory exists and if yes - we use it. Otherwise - the new one + * will be created. + * If VIR_STORAGE_POOL_BUILD_OVERWRITE is set, the dircetory for pool + * will used but the content and permissions will be update see [3]
+ * + * Returns 0 on success, -1 on error + */ + +static int +virStorageBackendVzPoolBuild(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool, + unsigned int flags) +{ [2 - snip most into virStorageBackendBuildFileDirCommon()]
keep: unsigned int dir_create_flags = 0;
+ int ret = -1; + char *parent = NULL; + char *p = NULL; + mode_t mode; + unsigned int dir_create_flags; + + virCheckFlags(VIR_STORAGE_POOL_BUILD_OVERWRITE | + VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, ret); + + VIR_EXCLUSIVE_FLAGS_GOTO(VIR_STORAGE_POOL_BUILD_OVERWRITE, + VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, + error); + + if (VIR_STRDUP(parent, pool->def->target.path) < 0) + goto error; + if (!(p = strrchr(parent, '/'))) { + virReportError(VIR_ERR_INVALID_ARG, + _("path '%s' is not absolute"), + pool->def->target.path); + goto error; + } + + if (p != parent) { + /* assure all directories in the path prior to the final dir + * exist, with default uid/gid/mode. */ + *p = '\0'; + if (virFileMakePath(parent) < 0) { + virReportSystemError(errno, _("cannot create path '%s'"), + parent); + goto error; + } + } + + dir_create_flags = VIR_DIR_CREATE_ALLOW_EXIST; + mode = pool->def->target.perms.mode; + + if (mode == (mode_t) -1 && !virFileExists(pool->def->target.path)) + mode = VIR_STORAGE_DEFAULT_POOL_PERM_MODE; + + /* Now create the final dir in the path with the uid/gid/mode + * requested in the config. If the dir already exists, just set + * the perms. */ + if (virDirCreate(pool->def->target.path, + mode, + pool->def->target.perms.uid, + pool->def->target.perms.gid, + dir_create_flags) < 0) + goto error; [2 end snip]
+ + /* Delete directory content if flag is set*/ should be "set */"
+ if (flags & VIR_STORAGE_POOL_BUILD_OVERWRITE) + if (virFileDeleteTree(pool->def->target.path)) + goto error; [3] This block doesn't make sense in light of the virDirCreate just above *and* the intro comments.
If you want to support [NO_]OVERWRITE, then prior to calling the common function we can play with flags, thus you end up with just:
if (flags & VIR_STORAGE_POOL_BUILD_OVERWRITE) dir_create_flags |= VIR_DIR_CREATE_ALLOW_EXIST;
return virStorageBackendBuildFileDirCommon(pool, dir_create_flags);
The *_fs.c code would be
unsigned int dir_create_flags = VIR_DIR_CREATE_ALLOW_EXIST; ...
if (virStorageBackendBuildFileDirCommon(pool, dir_create_flags) < 0) goto error; ...
and the common code would receive dir_create_flags
The comments would then need to be updated a bit... If you have a suggestion or would prefer to just follow the *_fs.c model - I can adjust that too - let me know.
follow the *_fs.c model seems more reasonable
+ + ret = 0; + + error: + VIR_FREE(parent); + return ret; +} + +static int +virStorageBackendVzPoolStart(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool) +{ + int ret = -1; + virCommandPtr cmd = NULL; + char *grp_name = NULL; + char *usr_name = NULL; + char *mode = NULL; + + /* Check the permissions */ + if (pool->def->target.perms.mode == (mode_t) - 1) + pool->def->target.perms.mode = VIR_STORAGE_DEFAULT_POOL_PERM_MODE; + if (pool->def->target.perms.uid == (uid_t) -1) + pool->def->target.perms.uid = geteuid(); + if (pool->def->target.perms.gid == (gid_t) -1) + pool->def->target.perms.gid = getegid(); + + /* Convert ids to names because vstorage uses names */ + + grp_name = virGetGroupName(pool->def->target.perms.gid); + if (!grp_name) + return -1; + + usr_name = virGetUserName(pool->def->target.perms.uid); + if (!usr_name) + return -1; Leak grp_name
+ + if (virAsprintf(&mode, "%o", pool->def->target.perms.mode) < 0) + return -1; Leak grp_name, usr_name
Each of these changes to a goto cleanup;
+ + cmd = virCommandNewArgList(VSTORAGE_MOUNT, + "-c", pool->def->source.name, + pool->def->target.path, + "-m", mode, + "-g", grp_name, "-u", usr_name, + NULL); + + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; + ret = 0; + + cleanup: + virCommandFree(cmd); + VIR_FREE(mode); + VIR_FREE(grp_name); + VIR_FREE(usr_name); + return ret; +} + +static int +virStorageBackendVzIsMounted(virStoragePoolObjPtr pool) +{ + int ret = -1; + char *src = NULL; Never used - I'll remove
+ FILE *mtab; + struct mntent ent; + char buf[1024]; + char *cluster = NULL; + + if (virAsprintf(&cluster, "vstorage://%s", pool->def->source.name) < 0) + return -1; + + if ((mtab = fopen(_PATH_MOUNTED, "r")) == NULL) { + virReportSystemError(errno, + _("cannot read mount list '%s'"), + _PATH_MOUNTED); + goto cleanup; + } + + while ((getmntent_r(mtab, &ent, buf, sizeof(buf))) != NULL) { + + if (STREQ(ent.mnt_dir, pool->def->target.path) && + STREQ(ent.mnt_fsname, cluster)) { + ret = 1; + goto cleanup; + } + + VIR_FREE(src); + } + + ret = 0; + + cleanup: + VIR_FORCE_FCLOSE(mtab); + VIR_FREE(src); + VIR_FREE(cluster); + return ret; +} + +static int +virStorageBackendVzUmount(virStoragePoolObjPtr pool) +{ + virCommandPtr cmd = NULL; + int ret = -1; + int rc; + + /* Short-circuit if already unmounted */ + if ((rc = virStorageBackendVzIsMounted(pool)) != 1) + return rc; + [2] The following has commonality with _fs.c - use "return virStorageBackendUmountCommon(pool);"
+ cmd = virCommandNewArgList(UMOUNT, + pool->def->target.path, + NULL); + + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; + + ret = 0; + cleanup: + virCommandFree(cmd); + return ret; +} + +static int +virStorageBackendVzPoolStop(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool) +{ + if (virStorageBackendVzUmount(pool) < 0) + return -1; + + return 0; +} + +/** + * @conn connection to report errors against + * @pool storage pool to delete + * + * Deletes vstorage based storage pool. + * At this moment vstorage is in umounted state - so we do not + * need to delete volumes first. + * Returns 0 on success, -1 on error + */ +static int +virStorageBackendVzDelete(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool, + unsigned int flags) +{ + virCheckFlags(0, -1); [2] This could be a return virStorageBackendDeleteDirCommon(pool);
+ + if (rmdir(pool->def->target.path) < 0) { + virReportSystemError(errno, + _("failed to remove pool '%s'"), + pool->def->target.path); + return -1; + } + + return 0; +} + +/* + * Check wether the cluster is mounted whether
+ */ +static int +virStorageBackendVzCheck(virStoragePoolObjPtr pool, + bool *isActive) +{ + int ret = -1; + *isActive = false; + if ((ret = virStorageBackendVzIsMounted(pool)) != 0) { + if (ret < 0) + return -1; + *isActive = true; + } + + return 0; +} + [2 - start] - This whole hunk moves to common module
+/* All the underlying functions were directly copied from + * filesystem backend with no changes. + */ + +static int +virStorageBackendProbeTarget(virStorageSourcePtr target, + virStorageEncryptionPtr *encryption) +{ + int backingStoreFormat; + int fd = -1; + int ret = -1; + int rc; + virStorageSourcePtr meta = NULL; + struct stat sb; + + if (encryption) + *encryption = NULL; + + if ((rc = virStorageBackendVolOpen(target->path, &sb, + VIR_STORAGE_VOL_FS_PROBE_FLAGS)) < 0) + return rc; /* Take care to propagate rc, it is not always -1 */ + fd = rc; + + if (virStorageBackendUpdateVolTargetInfoFD(target, fd, &sb) < 0) + goto cleanup; + + if (S_ISDIR(sb.st_mode)) { + if (virStorageBackendIsPloopDir(target->path)) { + if (virStorageBackendRedoPloopUpdate(target, &sb, &fd, + VIR_STORAGE_VOL_FS_PROBE_FLAGS) < 0) + goto cleanup; + } else { + target->format = VIR_STORAGE_FILE_DIR; + ret = 0; + goto cleanup; + } + } + + if (!(meta = virStorageFileGetMetadataFromFD(target->path, + fd, + VIR_STORAGE_FILE_AUTO, + &backingStoreFormat))) + goto cleanup; + + if (meta->backingStoreRaw) { + if (!(target->backingStore = virStorageSourceNewFromBacking(meta))) + goto cleanup; + + target->backingStore->format = backingStoreFormat; + + /* XXX: Remote storage doesn't play nicely with volumes backed by + * remote storage. To avoid trouble, just fake the backing store is RAW + * and put the string from the metadata as the path of the target. */ + if (!virStorageSourceIsLocalStorage(target->backingStore)) { + virStorageSourceFree(target->backingStore); + + if (VIR_ALLOC(target->backingStore) < 0) + goto cleanup; + + target->backingStore->type = VIR_STORAGE_TYPE_NETWORK; + target->backingStore->path = meta->backingStoreRaw; + meta->backingStoreRaw = NULL; + target->backingStore->format = VIR_STORAGE_FILE_RAW; + } + + if (target->backingStore->format == VIR_STORAGE_FILE_AUTO) { + if ((rc = virStorageFileProbeFormat(target->backingStore->path, + -1, -1)) < 0) { + /* If the backing file is currently unavailable or is + * accessed via remote protocol only log an error, fake the + * format as RAW and continue. Returning -1 here would + * disable the whole storage pool, making it unavailable for + * even maintenance. */ + target->backingStore->format = VIR_STORAGE_FILE_RAW; + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot probe backing volume format: %s"), + target->backingStore->path); + } else { + target->backingStore->format = rc; + } + } + } + + target->format = meta->format; + + /* Default to success below this point */ + ret = 0; + + if (meta->capacity) + target->capacity = meta->capacity; + + if (encryption && meta->encryption) { + *encryption = meta->encryption; + meta->encryption = NULL; + + /* XXX ideally we'd fill in secret UUID here + * but we cannot guarantee 'conn' is non-NULL + * at this point in time :-( So we only fill + * in secrets when someone first queries a vol + */ + } + + virBitmapFree(target->features); + target->features = meta->features; + meta->features = NULL; + + if (meta->compat) { + VIR_FREE(target->compat); + target->compat = meta->compat; + meta->compat = NULL; + } + + cleanup: + VIR_FORCE_CLOSE(fd); + virStorageSourceFree(meta); + return ret; + +} [2] - end
+ +/** + * The same as for fs/dir storage pools + * Iterate over the pool's directory and enumerate all disk images + * within it. This is non-recursive. + */ Scratch the comment
+ +static int +virStorageBackendVzRefresh(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool) +{ [2] all the code moves:
return virStorageBackendRefreshFileDirCommon(pool);
+ DIR *dir; + struct dirent *ent; + struct statvfs sb; + struct stat statbuf; + virStorageVolDefPtr vol = NULL; + virStorageSourcePtr target = NULL; + int direrr; + int fd = -1, ret = -1; + + if (virDirOpen(&dir, pool->def->target.path) < 0) + goto cleanup; + + while ((direrr = virDirRead(dir, &ent, pool->def->target.path)) > 0) { + int err; + + if (virStringHasControlChars(ent->d_name)) { + VIR_WARN("Ignoring file with control characters under '%s'", + pool->def->target.path); + continue; + } + + if (VIR_ALLOC(vol) < 0) + goto cleanup; + + if (VIR_STRDUP(vol->name, ent->d_name) < 0) + goto cleanup; + + vol->type = VIR_STORAGE_VOL_FILE; + vol->target.format = VIR_STORAGE_FILE_RAW; /* Real value is filled in during probe */ + if (virAsprintf(&vol->target.path, "%s/%s", + pool->def->target.path, + vol->name) == -1) + goto cleanup; + + if (VIR_STRDUP(vol->key, vol->target.path) < 0) + goto cleanup; + + if ((err = virStorageBackendProbeTarget(&vol->target, + &vol->target.encryption)) < 0) { + if (err == -2) { + /* Silently ignore non-regular files, + * eg 'lost+found', dangling symbolic link */ + virStorageVolDefFree(vol); + vol = NULL; + continue; + } else if (err == -3) { + /* The backing file is currently unavailable, its format is not + * explicitly specified, the probe to auto detect the format + * failed: continue with faked RAW format, since AUTO will + * break virStorageVolTargetDefFormat() generating the line + * <format type='...'/>. */ + } else { + goto cleanup; + } + } + + /* directory based volume */ + if (vol->target.format == VIR_STORAGE_FILE_DIR) + vol->type = VIR_STORAGE_VOL_DIR; + + if (vol->target.format == VIR_STORAGE_FILE_PLOOP) + vol->type = VIR_STORAGE_VOL_PLOOP; + + if (vol->target.backingStore) { + ignore_value(virStorageBackendUpdateVolTargetInfo(vol->target.backingStore, + false, + VIR_STORAGE_VOL_OPEN_DEFAULT, 0)); NB: I had a patch here today - this is why cut/copy/paste is not preferred...
+ /* If this failed, the backing file is currently unavailable, + * the capacity, allocation, owner, group and mode are unknown. + * An error message was raised, but we just continue. */ + } + + if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0) + goto cleanup; + } + if (direrr < 0) + goto cleanup; + VIR_DIR_CLOSE(dir); + vol = NULL; + + if (VIR_ALLOC(target)) + goto cleanup; + + if ((fd = open(pool->def->target.path, O_RDONLY)) < 0) { + virReportSystemError(errno, + _("cannot open path '%s'"), + pool->def->target.path); + goto cleanup; + } + + if (fstat(fd, &statbuf) < 0) { + virReportSystemError(errno, + _("cannot stat path '%s'"), + pool->def->target.path); + goto cleanup; + } + + if (virStorageBackendUpdateVolTargetInfoFD(target, fd, &statbuf) < 0) + goto cleanup; + + /* VolTargetInfoFD doesn't update capacity correctly for the pool case */ + if (statvfs(pool->def->target.path, &sb) < 0) { + virReportSystemError(errno, + _("cannot statvfs path '%s'"), + pool->def->target.path); + goto cleanup; + } + + pool->def->capacity = ((unsigned long long)sb.f_frsize * + (unsigned long long)sb.f_blocks); + pool->def->available = ((unsigned long long)sb.f_bfree * + (unsigned long long)sb.f_frsize); + pool->def->allocation = pool->def->capacity - pool->def->available; + + pool->def->target.perms.mode = target->perms->mode; + pool->def->target.perms.uid = target->perms->uid; + pool->def->target.perms.gid = target->perms->gid; + VIR_FREE(pool->def->target.perms.label); + if (VIR_STRDUP(pool->def->target.perms.label, target->perms->label) < 0) + goto cleanup; + + ret = 0; + cleanup: + VIR_DIR_CLOSE(dir); + VIR_FORCE_CLOSE(fd); + virStorageVolDefFree(vol); + virStorageSourceFree(target); + if (ret < 0) + virStoragePoolObjClearVols(pool); + return ret; +} [2 - end]
Once this is all done - this file is much shorter and you gain the benefit of any adjustments to the common code - which will happen... and this code wouldn't be updated...
I'll make the updates though - it won't happen overnight - should be by the end of the week.
John
virStorageBackend virStorageBackendVstorage = { .type = VIR_STORAGE_POOL_VSTORAGE, + + .buildPool = virStorageBackendVzPoolBuild, + .startPool = virStorageBackendVzPoolStart, + .stopPool = virStorageBackendVzPoolStop, + .deletePool = virStorageBackendVzDelete, + .refreshPool = virStorageBackendVzRefresh, + .checkPool = virStorageBackendVzCheck, };
-- Best regards, Olga

[...]
If you want to support [NO_]OVERWRITE, then prior to calling the common function we can play with flags, thus you end up with just:
if (flags & VIR_STORAGE_POOL_BUILD_OVERWRITE) dir_create_flags |= VIR_DIR_CREATE_ALLOW_EXIST;
return virStorageBackendBuildFileDirCommon(pool, dir_create_flags);
The *_fs.c code would be
unsigned int dir_create_flags = VIR_DIR_CREATE_ALLOW_EXIST; ...
if (virStorageBackendBuildFileDirCommon(pool, dir_create_flags) < 0) goto error; ...
and the common code would receive dir_create_flags
The comments would then need to be updated a bit... If you have a suggestion or would prefer to just follow the *_fs.c model - I can adjust that too - let me know.
follow the *_fs.c model seems more reasonable
OK - the flags are really there only for the FS pool (they are not used for the netfs or dir). So for the VZ pool I'll only check that they aren't provided, IOW: virCheckFlags(0, -1); Just so you're aware, here's my plan of action. I've posted three patches which will make a couple of the *_fs.c pool API's common/local and *all* of the *_fs.c volume API's local. I've followed the naming of the exist vir*Backend*Local APIs (upload, download, and wipe): http://www.redhat.com/archives/libvir-list/2017-January/msg00928.html Once that series is ACK'd/pushed - I'll update these changes to follow on. In the end there will be 4 patches and they will be much smaller than what's here now. John

Vstorage operates with volumes the same way as directory pool and netfs pool. We use the same functions. Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- 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

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@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
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, };

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@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

Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- docs/formatstorage.html.in | 7 ++++--- docs/schemas/storagepool.rng | 21 ++++++++++++++++++++ docs/storage.html.in | 28 ++++++++++++++++++++++++++- tests/storagepoolxml2xmlin/pool-vstorage.xml | 10 ++++++++++ tests/storagepoolxml2xmlout/pool-vstorage.xml | 18 +++++++++++++++++ tests/storagepoolxml2xmltest.c | 3 +++ 6 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 tests/storagepoolxml2xmlin/pool-vstorage.xml create mode 100644 tests/storagepoolxml2xmlout/pool-vstorage.xml diff --git a/docs/formatstorage.html.in b/docs/formatstorage.html.in index f6887ae..3c39266 100644 --- a/docs/formatstorage.html.in +++ b/docs/formatstorage.html.in @@ -24,8 +24,9 @@ (<span class="since">since 0.9.13</span>), <code>sheepdog</code> (<span class="since">since 0.10.0</span>), <code>gluster</code> (<span class="since">since - 1.2.0</span>) or <code>zfs</code> (<span class="since">since - 1.2.8</span>). This corresponds to the + 1.2.0</span>), <code>zfs</code> (<span class="since">since + 1.2.8</span>) or <code>vstorage</code> (<span class="since">since + 3.0.0</span>). This corresponds to the storage backend drivers listed further along in this document. </p> <h3><a name="StoragePoolFirst">General metadata</a></h3> @@ -124,7 +125,7 @@ <dt><code>device</code></dt> <dd>Provides the source for pools backed by physical devices (pool types <code>fs</code>, <code>logical</code>, <code>disk</code>, - <code>iscsi</code>, <code>zfs</code>). + <code>iscsi</code>, <code>zfs</code>, <code>vstorage</code>). May be repeated multiple times depending on backend driver. Contains a required attribute <code>path</code> which is either the fully qualified path to the block device node or for <code>iscsi</code> diff --git a/docs/schemas/storagepool.rng b/docs/schemas/storagepool.rng index 49d212f..c5d13a8 100644 --- a/docs/schemas/storagepool.rng +++ b/docs/schemas/storagepool.rng @@ -24,6 +24,7 @@ <ref name='poolsheepdog'/> <ref name='poolgluster'/> <ref name='poolzfs'/> + <ref name='poolvstorage'> </choice> </element> </define> @@ -173,6 +174,18 @@ </interleave> </define> + <define name='poolvstorage'> + <attribute name='type'> + <value>vstorage</value> + </attribute> + <interleave> + <ref name='commonmetadata'/> + <ref name='sizing'/> + <ref name='sourcevstorage'/> + <ref name='target'/> + </interleave> + </define> + <define name='sourceinfovendor'> <interleave> <optional> @@ -373,6 +386,14 @@ </element> </define> + <define name='sourcevstorage'> + <element name='source'> + <interleave> + <ref name='sourceinfoname'/> + </interleave> + </element> + </define> + <define name='sourcefmtfs'> <optional> <element name='format'> diff --git a/docs/storage.html.in b/docs/storage.html.in index 2e5b65e..26d21df 100644 --- a/docs/storage.html.in +++ b/docs/storage.html.in @@ -120,6 +120,9 @@ <li> <a href="#StorageBackendZFS">ZFS backend</a> </li> + <li> + <a href="#StorageBackendVstorage">Virtuozzo storage backend</a> + </li> </ul> <h2><a name="StorageBackendDir">Directory pool</a></h2> @@ -791,6 +794,29 @@ <p> The ZFS volume pool does not use the volume format type element. </p> - + <h2><a name="StorageBackendVstorage">Vstorage pools</a></h2> + <p> + This provides a pool based on Virtuozzo storage. Virtuozzo Storage is highly-avaliable + distributed software-defined storage with build-in replication and disaster recovery. + (More detailed information about storage and its managment can be found here: + <a href="https://openvz.org/Virtuozzo_Storage">Virtuozzo Storage</a>). + </p> + <p>Please refer to the Virtuozzo Storage documentation for details on a storage managment + and usage.</p> + <h3>Example pool input</h3> + <p>In order to create storage pool with Virtuozzo Storage bakend you have to provide + cluster name and be authorized within this cluster.</p> + <pre> +<pool type="vstorage"> + <name>myvstoragepool</name> + <source> + <name>clustername</name> + </source> + <target> + <path>/mnt/clustername</path> + </target> +</pool></pre> + <h3>Valid volume format types</h3> + <p>The valid volume types are the same as for the directory pool type.</p> </body> </html> diff --git a/tests/storagepoolxml2xmlin/pool-vstorage.xml b/tests/storagepoolxml2xmlin/pool-vstorage.xml new file mode 100644 index 0000000..31e36a2 --- /dev/null +++ b/tests/storagepoolxml2xmlin/pool-vstorage.xml @@ -0,0 +1,10 @@ +<pool type="vstorage"> + <name>vstorage</name> + <uuid>cfd270f9-acc7-4394-8685-4977eb318171</uuid> + <source> + <name>vzstorage-cluster</name> + </source> + <target> + <path>/mnt/vstorage_cluster</path> + </target> +</pool> diff --git a/tests/storagepoolxml2xmlout/pool-vstorage.xml b/tests/storagepoolxml2xmlout/pool-vstorage.xml new file mode 100644 index 0000000..8b2aecb --- /dev/null +++ b/tests/storagepoolxml2xmlout/pool-vstorage.xml @@ -0,0 +1,18 @@ +<pool type='vstorage'> + <name>vstorage</name> + <uuid>cfd270f9-acc7-4394-8685-4977eb318171</uuid> + <capacity unit='bytes'>0</capacity> + <allocation unit='bytes'>0</allocation> + <available unit='bytes'>0</available> + <source> + <name>vstorage-cluster</name> + </source> + <target> + <path>/mnt/vstorage-cluster</path> + <permissions> + <mode>0755</mode> + <owner>-1</owner> + <group>-1</group> + </permissions> + </target> +</pool> diff --git a/tests/storagepoolxml2xmltest.c b/tests/storagepoolxml2xmltest.c index 2e1e811..98a8449 100644 --- a/tests/storagepoolxml2xmltest.c +++ b/tests/storagepoolxml2xmltest.c @@ -104,6 +104,9 @@ mymain(void) #ifdef WITH_STORAGE_RBD DO_TEST("pool-rbd"); #endif +#ifdef WITH_STORAGE_VSTORAGE + DO_TEST("pool-vstorage"); +#endif return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -- 1.8.3.1

On 01/17/2017 09:10 AM, Olga Krishtal wrote:
Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- docs/formatstorage.html.in | 7 ++++--- docs/schemas/storagepool.rng | 21 ++++++++++++++++++++ docs/storage.html.in | 28 ++++++++++++++++++++++++++- tests/storagepoolxml2xmlin/pool-vstorage.xml | 10 ++++++++++ tests/storagepoolxml2xmlout/pool-vstorage.xml | 18 +++++++++++++++++ tests/storagepoolxml2xmltest.c | 3 +++ 6 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 tests/storagepoolxml2xmlin/pool-vstorage.xml create mode 100644 tests/storagepoolxml2xmlout/pool-vstorage.xml
diff --git a/docs/formatstorage.html.in b/docs/formatstorage.html.in index f6887ae..3c39266 100644 --- a/docs/formatstorage.html.in +++ b/docs/formatstorage.html.in @@ -24,8 +24,9 @@ (<span class="since">since 0.9.13</span>), <code>sheepdog</code> (<span class="since">since 0.10.0</span>), <code>gluster</code> (<span class="since">since - 1.2.0</span>) or <code>zfs</code> (<span class="since">since - 1.2.8</span>). This corresponds to the + 1.2.0</span>), <code>zfs</code> (<span class="since">since + 1.2.8</span>) or <code>vstorage</code> (<span class="since">since + 3.0.0</span>). This corresponds to the
3.1.0
storage backend drivers listed further along in this document. </p> <h3><a name="StoragePoolFirst">General metadata</a></h3> @@ -124,7 +125,7 @@ <dt><code>device</code></dt> <dd>Provides the source for pools backed by physical devices (pool types <code>fs</code>, <code>logical</code>, <code>disk</code>, - <code>iscsi</code>, <code>zfs</code>). + <code>iscsi</code>, <code>zfs</code>, <code>vstorage</code>). May be repeated multiple times depending on backend driver. Contains a required attribute <code>path</code> which is either the fully qualified path to the block device node or for <code>iscsi</code> diff --git a/docs/schemas/storagepool.rng b/docs/schemas/storagepool.rng index 49d212f..c5d13a8 100644 --- a/docs/schemas/storagepool.rng +++ b/docs/schemas/storagepool.rng @@ -24,6 +24,7 @@ <ref name='poolsheepdog'/> <ref name='poolgluster'/> <ref name='poolzfs'/> + <ref name='poolvstorage'>
'poolvstorage'/> make check fails otherwise in one of the schema tests.
</choice> </element> </define> @@ -173,6 +174,18 @@ </interleave> </define>
+ <define name='poolvstorage'> + <attribute name='type'> + <value>vstorage</value> + </attribute> + <interleave> + <ref name='commonmetadata'/> + <ref name='sizing'/> + <ref name='sourcevstorage'/> + <ref name='target'/> + </interleave> + </define> + <define name='sourceinfovendor'> <interleave> <optional> @@ -373,6 +386,14 @@ </element> </define>
+ <define name='sourcevstorage'> + <element name='source'> + <interleave> + <ref name='sourceinfoname'/> + </interleave> + </element> + </define> + <define name='sourcefmtfs'> <optional> <element name='format'> diff --git a/docs/storage.html.in b/docs/storage.html.in index 2e5b65e..26d21df 100644 --- a/docs/storage.html.in +++ b/docs/storage.html.in @@ -120,6 +120,9 @@ <li> <a href="#StorageBackendZFS">ZFS backend</a> </li> + <li> + <a href="#StorageBackendVstorage">Virtuozzo storage backend</a> + </li> </ul>
<h2><a name="StorageBackendDir">Directory pool</a></h2> @@ -791,6 +794,29 @@ <p> The ZFS volume pool does not use the volume format type element. </p> - + <h2><a name="StorageBackendVstorage">Vstorage pools</a></h2> + <p> + This provides a pool based on Virtuozzo storage. Virtuozzo Storage is highly-avaliable
is a highly available
+ distributed software-defined storage with build-in replication and disaster recovery.
built-in
+ (More detailed information about storage and its managment can be found here:
s/(// management
+ <a href="https://openvz.org/Virtuozzo_Storage">Virtuozzo Storage</a>). + </p> + <p>Please refer to the Virtuozzo Storage documentation for details on a storage managment
management
+ and usage.</p> + <h3>Example pool input</h3> + <p>In order to create storage pool with Virtuozzo Storage bakend you have to provide
backend
+ cluster name and be authorized within this cluster.</p>
the cluster
+ <pre>
All the lines are really long - try to stay within 80 chars...
+<pool type="vstorage"> + <name>myvstoragepool</name> + <source> + <name>clustername</name> + </source> + <target> + <path>/mnt/clustername</path> + </target> +</pool></pre> + <h3>Valid volume format types</h3> + <p>The valid volume types are the same as for the directory pool type.</p>
s/ type// Once pkrempa's changes are in - I'll make the adjustments and push. I'll also add a news.xml entry - which is new since our last review... John
</body> </html> diff --git a/tests/storagepoolxml2xmlin/pool-vstorage.xml b/tests/storagepoolxml2xmlin/pool-vstorage.xml new file mode 100644 index 0000000..31e36a2 --- /dev/null +++ b/tests/storagepoolxml2xmlin/pool-vstorage.xml @@ -0,0 +1,10 @@ +<pool type="vstorage"> + <name>vstorage</name> + <uuid>cfd270f9-acc7-4394-8685-4977eb318171</uuid> + <source> + <name>vzstorage-cluster</name> + </source> + <target> + <path>/mnt/vstorage_cluster</path> + </target> +</pool> diff --git a/tests/storagepoolxml2xmlout/pool-vstorage.xml b/tests/storagepoolxml2xmlout/pool-vstorage.xml new file mode 100644 index 0000000..8b2aecb --- /dev/null +++ b/tests/storagepoolxml2xmlout/pool-vstorage.xml @@ -0,0 +1,18 @@ +<pool type='vstorage'> + <name>vstorage</name> + <uuid>cfd270f9-acc7-4394-8685-4977eb318171</uuid> + <capacity unit='bytes'>0</capacity> + <allocation unit='bytes'>0</allocation> + <available unit='bytes'>0</available> + <source> + <name>vstorage-cluster</name> + </source> + <target> + <path>/mnt/vstorage-cluster</path> + <permissions> + <mode>0755</mode> + <owner>-1</owner> + <group>-1</group> + </permissions> + </target> +</pool> diff --git a/tests/storagepoolxml2xmltest.c b/tests/storagepoolxml2xmltest.c index 2e1e811..98a8449 100644 --- a/tests/storagepoolxml2xmltest.c +++ b/tests/storagepoolxml2xmltest.c @@ -104,6 +104,9 @@ mymain(void) #ifdef WITH_STORAGE_RBD DO_TEST("pool-rbd"); #endif +#ifdef WITH_STORAGE_VSTORAGE + DO_TEST("pool-vstorage"); +#endif
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; }

On 19/01/17 00:04, John Ferlan wrote:
On 01/17/2017 09:10 AM, Olga Krishtal wrote:
Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- docs/formatstorage.html.in | 7 ++++--- docs/schemas/storagepool.rng | 21 ++++++++++++++++++++ docs/storage.html.in | 28 ++++++++++++++++++++++++++- tests/storagepoolxml2xmlin/pool-vstorage.xml | 10 ++++++++++ tests/storagepoolxml2xmlout/pool-vstorage.xml | 18 +++++++++++++++++ tests/storagepoolxml2xmltest.c | 3 +++ 6 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 tests/storagepoolxml2xmlin/pool-vstorage.xml create mode 100644 tests/storagepoolxml2xmlout/pool-vstorage.xml
diff --git a/docs/formatstorage.html.in b/docs/formatstorage.html.in index f6887ae..3c39266 100644 --- a/docs/formatstorage.html.in +++ b/docs/formatstorage.html.in @@ -24,8 +24,9 @@ (<span class="since">since 0.9.13</span>), <code>sheepdog</code> (<span class="since">since 0.10.0</span>), <code>gluster</code> (<span class="since">since - 1.2.0</span>) or <code>zfs</code> (<span class="since">since - 1.2.8</span>). This corresponds to the + 1.2.0</span>), <code>zfs</code> (<span class="since">since + 1.2.8</span>) or <code>vstorage</code> (<span class="since">since + 3.0.0</span>). This corresponds to the 3.1.0
storage backend drivers listed further along in this document. </p> <h3><a name="StoragePoolFirst">General metadata</a></h3> @@ -124,7 +125,7 @@ <dt><code>device</code></dt> <dd>Provides the source for pools backed by physical devices (pool types <code>fs</code>, <code>logical</code>, <code>disk</code>, - <code>iscsi</code>, <code>zfs</code>). + <code>iscsi</code>, <code>zfs</code>, <code>vstorage</code>). May be repeated multiple times depending on backend driver. Contains a required attribute <code>path</code> which is either the fully qualified path to the block device node or for <code>iscsi</code> diff --git a/docs/schemas/storagepool.rng b/docs/schemas/storagepool.rng index 49d212f..c5d13a8 100644 --- a/docs/schemas/storagepool.rng +++ b/docs/schemas/storagepool.rng @@ -24,6 +24,7 @@ <ref name='poolsheepdog'/> <ref name='poolgluster'/> <ref name='poolzfs'/> + <ref name='poolvstorage'>
'poolvstorage'/>
make check fails otherwise in one of the schema tests.
</choice> </element> </define> @@ -173,6 +174,18 @@ </interleave> </define>
+ <define name='poolvstorage'> + <attribute name='type'> + <value>vstorage</value> + </attribute> + <interleave> + <ref name='commonmetadata'/> + <ref name='sizing'/> + <ref name='sourcevstorage'/> + <ref name='target'/> + </interleave> + </define> + <define name='sourceinfovendor'> <interleave> <optional> @@ -373,6 +386,14 @@ </element> </define>
+ <define name='sourcevstorage'> + <element name='source'> + <interleave> + <ref name='sourceinfoname'/> + </interleave> + </element> + </define> + <define name='sourcefmtfs'> <optional> <element name='format'> diff --git a/docs/storage.html.in b/docs/storage.html.in index 2e5b65e..26d21df 100644 --- a/docs/storage.html.in +++ b/docs/storage.html.in @@ -120,6 +120,9 @@ <li> <a href="#StorageBackendZFS">ZFS backend</a> </li> + <li> + <a href="#StorageBackendVstorage">Virtuozzo storage backend</a> + </li> </ul>
<h2><a name="StorageBackendDir">Directory pool</a></h2> @@ -791,6 +794,29 @@ <p> The ZFS volume pool does not use the volume format type element. </p> - + <h2><a name="StorageBackendVstorage">Vstorage pools</a></h2> + <p> + This provides a pool based on Virtuozzo storage. Virtuozzo Storage is highly-avaliable
is a highly available
+ distributed software-defined storage with build-in replication and disaster recovery. built-in
+ (More detailed information about storage and its managment can be found here: s/(//
management
+ <a href="https://openvz.org/Virtuozzo_Storage">Virtuozzo Storage</a>). + </p> + <p>Please refer to the Virtuozzo Storage documentation for details on a storage managment management
+ and usage.</p> + <h3>Example pool input</h3> + <p>In order to create storage pool with Virtuozzo Storage bakend you have to provide backend
+ cluster name and be authorized within this cluster.</p> the cluster
+ <pre> All the lines are really long - try to stay within 80 chars...
+<pool type="vstorage"> + <name>myvstoragepool</name> + <source> + <name>clustername</name> + </source> + <target> + <path>/mnt/clustername</path> + </target> +</pool></pre> + <h3>Valid volume format types</h3> + <p>The valid volume types are the same as for the directory pool type.</p> s/ type//
Once pkrempa's changes are in - I'll make the adjustments and push.
I'll also add a news.xml entry - which is new since our last review...
John
</body> </html> diff --git a/tests/storagepoolxml2xmlin/pool-vstorage.xml b/tests/storagepoolxml2xmlin/pool-vstorage.xml new file mode 100644 index 0000000..31e36a2 --- /dev/null +++ b/tests/storagepoolxml2xmlin/pool-vstorage.xml @@ -0,0 +1,10 @@ +<pool type="vstorage"> + <name>vstorage</name> + <uuid>cfd270f9-acc7-4394-8685-4977eb318171</uuid> + <source> + <name>vzstorage-cluster</name> + </source> + <target> + <path>/mnt/vstorage_cluster</path> + </target> +</pool> diff --git a/tests/storagepoolxml2xmlout/pool-vstorage.xml b/tests/storagepoolxml2xmlout/pool-vstorage.xml new file mode 100644 index 0000000..8b2aecb --- /dev/null +++ b/tests/storagepoolxml2xmlout/pool-vstorage.xml @@ -0,0 +1,18 @@ +<pool type='vstorage'> + <name>vstorage</name> + <uuid>cfd270f9-acc7-4394-8685-4977eb318171</uuid> + <capacity unit='bytes'>0</capacity> + <allocation unit='bytes'>0</allocation> + <available unit='bytes'>0</available> + <source> + <name>vstorage-cluster</name> + </source> + <target> + <path>/mnt/vstorage-cluster</path> + <permissions> + <mode>0755</mode> + <owner>-1</owner> + <group>-1</group> + </permissions> + </target> +</pool> diff --git a/tests/storagepoolxml2xmltest.c b/tests/storagepoolxml2xmltest.c index 2e1e811..98a8449 100644 --- a/tests/storagepoolxml2xmltest.c +++ b/tests/storagepoolxml2xmltest.c @@ -104,6 +104,9 @@ mymain(void) #ifdef WITH_STORAGE_RBD DO_TEST("pool-rbd"); #endif +#ifdef WITH_STORAGE_VSTORAGE + DO_TEST("pool-vstorage"); +#endif
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; }
Will fix -- Best regards, Olga

On 01/17/2017 09:10 AM, Olga Krishtal wrote:
This series of patches support pool and volume management within Virtuozzo Storage. Virtuozzo Storage is a highly-available distributed software defined storage with built-in replication and disaster recovery. More information about vzstorage can be found here: https://openvz.org/Virtuozzo_Storage
From client's point of view it looks like network attached storage (NFS or GlusterFS). It supports the same volume formats as directory, nfs. Default format ifor volume is raw. Because of such similarities all a lot of functions from storage backend fs can be used with no change: all functions that deals with volumes and pool refresh function.
From the other hand, Virtuozzo storage demands special packages like vstorage-client to be installed. So all functions that work with it are in separate file.
v2: - resplitted patches - all functions to work with Virtuozzo storage are in separate file - added possibility to mout cluster for pool for ures/with specific perms. - added documetation
Olga Krishtal (5): storage: adds with_storage_vstorage buils option storage: vstorage empty backend storage: vstorage pool operations storage: added vstorage pool backend volume functions storage: vstorage pool documentation and simple test
configure.ac | 5 + docs/formatstorage.html.in | 7 +- docs/schemas/storagepool.rng | 21 + docs/storage.html.in | 28 +- include/libvirt/libvirt-storage.h | 1 + m4/virt-storage-vstorage.m4 | 73 +++ po/POTFILES.in | 1 + src/Makefile.am | 9 + src/conf/storage_conf.c | 17 +- src/conf/storage_conf.h | 1 + src/storage/storage_backend.c | 6 + src/storage/storage_backend_vstorage.c | 888 ++++++++++++++++++++++++++ src/storage/storage_backend_vstorage.h | 27 + src/storage/storage_driver.c | 2 + tests/storagepoolxml2xmlin/pool-vstorage.xml | 10 + tests/storagepoolxml2xmlout/pool-vstorage.xml | 18 + tests/storagepoolxml2xmltest.c | 3 + tools/virsh-pool.c | 3 + tools/virsh.c | 3 + 19 files changed, 1118 insertions(+), 5 deletions(-) create mode 100644 m4/virt-storage-vstorage.m4 create mode 100644 src/storage/storage_backend_vstorage.c create mode 100644 src/storage/storage_backend_vstorage.h create mode 100644 tests/storagepoolxml2xmlin/pool-vstorage.xml create mode 100644 tests/storagepoolxml2xmlout/pool-vstorage.xml
This series with the adjustments I made as a result of the series I posted related to moving API's to storage_util is now pushed. I believe I got the right things merged - please double check though so we can make adjustments sooner rather than later. That is grab the top, compile, test, etc. as I don't have VSTORAGE pools installed so the changes don't do much for me! John

On 26/01/17 19:24, John Ferlan wrote:
On 01/17/2017 09:10 AM, Olga Krishtal wrote:
This series of patches support pool and volume management within Virtuozzo Storage. Virtuozzo Storage is a highly-available distributed software defined storage with built-in replication and disaster recovery. More information about vzstorage can be found here: https://openvz.org/Virtuozzo_Storage
From client's point of view it looks like network attached storage (NFS or GlusterFS). It supports the same volume formats as directory, nfs. Default format ifor volume is raw. Because of such similarities all a lot of functions from storage backend fs can be used with no change: all functions that deals with volumes and pool refresh function.
From the other hand, Virtuozzo storage demands special packages like vstorage-client to be installed. So all functions that work with it are in separate file.
v2: - resplitted patches - all functions to work with Virtuozzo storage are in separate file - added possibility to mout cluster for pool for ures/with specific perms. - added documetation
Olga Krishtal (5): storage: adds with_storage_vstorage buils option storage: vstorage empty backend storage: vstorage pool operations storage: added vstorage pool backend volume functions storage: vstorage pool documentation and simple test
configure.ac | 5 + docs/formatstorage.html.in | 7 +- docs/schemas/storagepool.rng | 21 + docs/storage.html.in | 28 +- include/libvirt/libvirt-storage.h | 1 + m4/virt-storage-vstorage.m4 | 73 +++ po/POTFILES.in | 1 + src/Makefile.am | 9 + src/conf/storage_conf.c | 17 +- src/conf/storage_conf.h | 1 + src/storage/storage_backend.c | 6 + src/storage/storage_backend_vstorage.c | 888 ++++++++++++++++++++++++++ src/storage/storage_backend_vstorage.h | 27 + src/storage/storage_driver.c | 2 + tests/storagepoolxml2xmlin/pool-vstorage.xml | 10 + tests/storagepoolxml2xmlout/pool-vstorage.xml | 18 + tests/storagepoolxml2xmltest.c | 3 + tools/virsh-pool.c | 3 + tools/virsh.c | 3 + 19 files changed, 1118 insertions(+), 5 deletions(-) create mode 100644 m4/virt-storage-vstorage.m4 create mode 100644 src/storage/storage_backend_vstorage.c create mode 100644 src/storage/storage_backend_vstorage.h create mode 100644 tests/storagepoolxml2xmlin/pool-vstorage.xml create mode 100644 tests/storagepoolxml2xmlout/pool-vstorage.xml
This series with the adjustments I made as a result of the series I posted related to moving API's to storage_util is now pushed. I believe I got the right things merged - please double check though so we can make adjustments sooner rather than later. That is grab the top, compile, test, etc. as I don't have VSTORAGE pools installed so the changes don't do much for me!
John
Thanks a lot John! For taking part of my job =) I have checked vstorage (start, build, create volume, etc) and sent small fix. -- Best regards, Olga

[...]
This series with the adjustments I made as a result of the series I posted related to moving API's to storage_util is now pushed. I believe I got the right things merged - please double check though so we can make adjustments sooner rather than later. That is grab the top, compile, test, etc. as I don't have VSTORAGE pools installed so the changes don't do much for me!
John
Thanks a lot John! For taking part of my job =)
I have checked vstorage (start, build, create volume, etc) and sent small fix.
My assumption the Unmount vs. Umount (my typo).... In any case, as it turns out the Umount API broke a Freebsd build, so I had to modify both _fs and _vstorage in order to just move the UMOUNT call back into their own Stop API's rather than calling the generic API. Built properly for me w/ _FS defined... Just making sure the --without-storage-fs build works properly - that'll take a few moments. John
participants (3)
-
John Ferlan
-
Olga Krishtal
-
Peter Krempa