[libvirt] [PATCH RFC v3 00/15] FSPool: backend directory

Hi everyone, we would like to propose the first implementation of fspool with directory backend according to previous discussions: https://www.redhat.com/archives/libvir-list/2016-April/msg01941.html https://www.redhat.com/archives/libvir-list/2016-May/msg00208.html https://www.redhat.com/archives/libvir-list/2016-September/msg00463.html Filesystem pools is a facility to manage filesystems resources similar to how storage pools manages volume resources.The manageble unit is a single filesystem, so fspool items have only one type - dir (storage pools can manage files, block devices, etc). However, backends for fspools can be different. This series introduses the simplest backend - host directory. API mostly follows storage pool API: we can create fspool, build it, populate with items. Moreover, to create filesystem pool we need some storage. So, all structures to describe storage that will hold fspool is borrowed from storage pool ones. The same is true for functions that work with them. As it was mentioned before - here we present directory backend for fspool. To mangae fspools and items we tried to use as much functionality from storage pool (directory and fs backend) as possible. The first 3 patches - is preparational refactoring. Both storage pool and fspool reside upon some storage, so there is a good chance to use the same code for describing storage source and functions that work with it. All reusable code is moved virpoolcommon.c/.h It would be great if you share you thoughts about such changes. Because what we trying to achive - is to have less copy/paste and to have separate drivers for storage pools and filesystem pools. All other patches is devoted to fspool implementation and is presented according libvirt recommendations. Uploading/downloading operations are not defined yet as it is not obvious how to make it properly. I guess we can use some kind of tar to make a stream from a filesystem. Please share you thoughts on this particular issue. v2: - renamed Fs to FS - in configure.ac script macro m4 is used - updates docs - created simple tests - updated virsh.pod - added information abot fspool in fotmatfs.html v3: - in this version storage pool code is reused - resplitted patches - fixed some errors Olga Krishtal (15): storage pools: refactoring of basic structs storage pools: functions refactoring storage pools: refactoring of fs backend FSPool: defining the public API FSPool: defining the internal API FSpool: implementing the public API FSPool: added access control objects and permissions FSPool: added --with-fs compilation option FSPool: implementation of remote protocol FSPool: added configuration description virsh: filesystem pools commands FSPool: empty implementation of driver methods FSPool: driver methods implementation FSPool: directory backend inplementation FSPool: Tests and documentation configure.ac | 6 + daemon/Makefile.am | 4 + daemon/libvirtd.c | 9 + daemon/remote.c | 35 + docs/formatfs.html.in | 206 ++ docs/fspool.html.in | 41 + docs/schemas/fsitem.rng | 66 + docs/schemas/fspool.rng | 82 + docs/sitemap.html.in | 4 + include/libvirt/libvirt-fs.h | 254 +++ include/libvirt/libvirt-storage.h | 5 +- include/libvirt/libvirt.h | 1 + include/libvirt/virterror.h | 7 + m4/virt-driver-fspool.m4 | 43 + po/POTFILES.in | 7 + src/Makefile.am | 59 +- src/access/viraccessdriver.h | 15 + src/access/viraccessdrivernop.c | 21 + src/access/viraccessdriverpolkit.c | 47 + src/access/viraccessdriverstack.c | 50 + src/access/viraccessmanager.c | 32 + src/access/viraccessmanager.h | 11 +- src/access/viraccessperm.c | 15 +- src/access/viraccessperm.h | 126 ++ src/check-driverimpls.pl | 2 + src/conf/fs_conf.c | 1479 ++++++++++++++ src/conf/fs_conf.h | 262 +++ src/conf/storage_conf.c | 162 -- src/conf/storage_conf.h | 137 +- src/datatypes.c | 150 ++ src/datatypes.h | 60 +- src/driver-fs.h | 193 ++ src/driver.h | 3 + src/fs/fs_backend.h | 94 + src/fs/fs_backend_dir.c | 290 +++ src/fs/fs_backend_dir.h | 8 + src/fs/fs_driver.c | 2044 ++++++++++++++++++++ src/fs/fs_driver.h | 10 + src/libvirt-fs.c | 1555 +++++++++++++++ src/libvirt.c | 30 +- src/libvirt_private.syms | 58 +- src/libvirt_public.syms | 46 + src/remote/remote_driver.c | 66 + src/remote/remote_protocol.x | 466 ++++- src/remote_protocol-structs | 165 ++ src/rpc/gendispatch.pl | 23 +- src/storage/storage_backend.h | 1 - src/storage/storage_backend_fs.c | 74 +- src/util/virerror.c | 37 + src/util/virpoolcommon.c | 212 ++ src/util/virpoolcommon.h | 189 ++ src/util/virstoragefile.c | 73 + src/util/virstoragefile.h | 3 + tests/Makefile.am | 12 + tests/fsitemxml2xmlin/item.xml | 13 + tests/fsitemxml2xmlout/item.xml | 13 + tests/fsitemxml2xmltest.c | 105 + .../dir-missing-target-path-invalid.xml | 12 + tests/fspoolxml2xmlin/fspool-dir.xml | 16 + tests/fspoolxml2xmlout/fspool-dir.xml | 16 + tests/fspoolxml2xmltest.c | 81 + tools/Makefile.am | 2 + tools/virsh-fsitem.c | 1293 +++++++++++++ tools/virsh-fsitem.h | 39 + tools/virsh-fspool.c | 1574 +++++++++++++++ tools/virsh-fspool.h | 38 + tools/virsh.c | 4 + tools/virsh.h | 9 + tools/virsh.pod | 252 ++- 69 files changed, 12128 insertions(+), 389 deletions(-) create mode 100644 docs/formatfs.html.in create mode 100644 docs/fspool.html.in create mode 100644 docs/schemas/fsitem.rng create mode 100644 docs/schemas/fspool.rng create mode 100644 include/libvirt/libvirt-fs.h create mode 100644 m4/virt-driver-fspool.m4 create mode 100644 src/conf/fs_conf.c create mode 100644 src/conf/fs_conf.h create mode 100644 src/driver-fs.h create mode 100644 src/fs/fs_backend.h create mode 100644 src/fs/fs_backend_dir.c create mode 100644 src/fs/fs_backend_dir.h create mode 100644 src/fs/fs_driver.c create mode 100644 src/fs/fs_driver.h create mode 100644 src/libvirt-fs.c create mode 100644 src/util/virpoolcommon.c create mode 100644 src/util/virpoolcommon.h create mode 100644 tests/fsitemxml2xmlin/item.xml create mode 100644 tests/fsitemxml2xmlout/item.xml create mode 100644 tests/fsitemxml2xmltest.c create mode 100644 tests/fspoolschemadata/dir-missing-target-path-invalid.xml create mode 100644 tests/fspoolxml2xmlin/fspool-dir.xml create mode 100644 tests/fspoolxml2xmlout/fspool-dir.xml create mode 100644 tests/fspoolxml2xmltest.c create mode 100644 tools/virsh-fsitem.c create mode 100644 tools/virsh-fsitem.h create mode 100644 tools/virsh-fspool.c create mode 100644 tools/virsh-fspool.h -- 1.8.3.1

This is the first patch in fspool patchest. FSPool and storage pools has a lot in common, however we want to have separate drivers for its managment. We want to use almost all storage pool descriptional structures for filesystem pool. All common structs is moved to virpoolcommon.h Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- include/libvirt/libvirt-storage.h | 5 +- src/Makefile.am | 5 +- src/conf/storage_conf.h | 126 +++-------------------------- src/datatypes.h | 4 +- src/util/virpoolcommon.h | 166 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 184 insertions(+), 122 deletions(-) create mode 100644 src/util/virpoolcommon.h diff --git a/include/libvirt/libvirt-storage.h b/include/libvirt/libvirt-storage.h index 0974f6e..8572685 100644 --- a/include/libvirt/libvirt-storage.h +++ b/include/libvirt/libvirt-storage.h @@ -34,7 +34,7 @@ * * a virStoragePool is a private structure representing a storage pool */ -typedef struct _virStoragePool virStoragePool; +typedef struct _virPoolCommon virStoragePool; /** * virStoragePoolPtr: @@ -44,7 +44,6 @@ typedef struct _virStoragePool virStoragePool; */ typedef virStoragePool *virStoragePoolPtr; - typedef enum { VIR_STORAGE_POOL_INACTIVE = 0, /* Not running */ VIR_STORAGE_POOL_BUILDING = 1, /* Initializing pool, not available */ @@ -104,7 +103,7 @@ typedef virStoragePoolInfo *virStoragePoolInfoPtr; * * a virStorageVol is a private structure representing a storage volume */ -typedef struct _virStorageVol virStorageVol; +typedef struct _virItemCommon virStorageVol; /** * virStorageVolPtr: diff --git a/src/Makefile.am b/src/Makefile.am index 8ee5567..f8d4a5b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -170,7 +170,7 @@ UTIL_SOURCES = \ util/virstats.c util/virstats.h \ util/virstorageencryption.c util/virstorageencryption.h \ util/virstoragefile.c util/virstoragefile.h \ - util/virstring.h util/virstring.c \ + util/virstring.h util/virstring.c \ util/virsysinfo.c util/virsysinfo.h \ util/virsystemd.c util/virsystemd.h \ util/virthread.c util/virthread.h \ @@ -185,7 +185,8 @@ UTIL_SOURCES = \ util/viruuid.c util/viruuid.h \ util/virxdrdefs.h \ util/virxml.c util/virxml.h \ - $(NULL) + util/virpoolcommon.h \ + $(NULL) EXTRA_DIST += $(srcdir)/util/keymaps.csv $(srcdir)/util/virkeycode-mapgen.py diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h index 185ae5e..8a9a789 100644 --- a/src/conf/storage_conf.h +++ b/src/conf/storage_conf.h @@ -27,6 +27,7 @@ # include "internal.h" # include "virstorageencryption.h" # include "virstoragefile.h" +# include "virpoolcommon.h" # include "virbitmap.h" # include "virthread.h" # include "device_conf.h" @@ -58,7 +59,6 @@ struct _virStorageVolSource { * backend for partition type creation */ }; - typedef struct _virStorageVolDef virStorageVolDef; typedef virStorageVolDef *virStorageVolDefPtr; struct _virStorageVolDef { @@ -73,6 +73,7 @@ struct _virStorageVolDef { virStorageSource target; }; + typedef struct _virStorageVolDefList virStorageVolDefList; typedef virStorageVolDefList *virStorageVolDefListPtr; struct _virStorageVolDefList { @@ -112,12 +113,8 @@ typedef enum { /* * For remote pools, info on how to reach the host */ -typedef struct _virStoragePoolSourceHost virStoragePoolSourceHost; +typedef virPoolSourceHost virStoragePoolSourceHost; typedef virStoragePoolSourceHost *virStoragePoolSourceHostPtr; -struct _virStoragePoolSourceHost { - char *name; - int port; -}; /* @@ -142,127 +139,27 @@ struct _virStoragePoolSourceDeviceExtent { int type; /* virStorageFreeType */ }; -typedef struct _virStoragePoolSourceInitiatorAttr virStoragePoolSourceInitiatorAttr; -struct _virStoragePoolSourceInitiatorAttr { - char *iqn; /* Initiator IQN */ -}; - /* * Pools can be backed by one or more devices, and some * allow us to track free space on underlying devices. */ -typedef struct _virStoragePoolSourceDevice virStoragePoolSourceDevice; +typedef virPoolSourceDevice virStoragePoolSourceDevice; typedef virStoragePoolSourceDevice *virStoragePoolSourceDevicePtr; -struct _virStoragePoolSourceDevice { - int nfreeExtent; - virStoragePoolSourceDeviceExtentPtr freeExtents; - char *path; - int format; /* Pool specific source format */ - int part_separator; /* enum virTristateSwitch */ - - /* When the source device is a physical disk, - * the geometry data is needed - */ - struct _geometry { - int cylinders; - int heads; - int sectors; - } geometry; -}; -typedef enum { - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_DEFAULT = 0, - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST, - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST, - - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_LAST, -} virStoragePoolSourceAdapterType; -VIR_ENUM_DECL(virStoragePoolSourceAdapter) - -typedef struct _virStoragePoolSourceAdapter virStoragePoolSourceAdapter; +typedef virPoolSourceAdapter virStoragePoolSourceAdapter; typedef virStoragePoolSourceAdapter *virStoragePoolSourceAdapterPtr; -struct _virStoragePoolSourceAdapter { - int type; /* virStoragePoolSourceAdapterType */ - - union { - struct { - char *name; - virPCIDeviceAddress parentaddr; /* host address */ - int unique_id; - bool has_parent; - } scsi_host; - struct { - char *parent; - char *wwnn; - char *wwpn; - int managed; /* enum virTristateSwitch */ - } fchost; - } data; -}; -typedef struct _virStoragePoolSource virStoragePoolSource; +typedef virPoolSource virStoragePoolSource; typedef virStoragePoolSource *virStoragePoolSourcePtr; -struct _virStoragePoolSource { - /* An optional (maybe multiple) host(s) */ - size_t nhost; - virStoragePoolSourceHostPtr hosts; - - /* And either one or more devices ... */ - size_t ndevice; - virStoragePoolSourceDevicePtr devices; - - /* Or a directory */ - char *dir; - - /* Or an adapter */ - virStoragePoolSourceAdapter adapter; - /* Or a name */ - char *name; - - /* Initiator IQN */ - virStoragePoolSourceInitiatorAttr initiator; - - /* Authentication information */ - virStorageAuthDefPtr auth; - - /* Vendor of the source */ - char *vendor; - - /* Product name of the source*/ - char *product; - - /* Pool type specific format such as filesystem type, - * or lvm version, etc. - */ - int format; -}; - -typedef struct _virStoragePoolTarget virStoragePoolTarget; +typedef virPoolTarget virStoragePoolTarget; typedef virStoragePoolTarget *virStoragePoolTargetPtr; -struct _virStoragePoolTarget { - char *path; /* Optional local filesystem mapping */ - virStoragePerms perms; /* Default permissions for volumes */ -}; -typedef struct _virStoragePoolDef virStoragePoolDef; +typedef virPoolDef virStoragePoolDef; typedef virStoragePoolDef *virStoragePoolDefPtr; -struct _virStoragePoolDef { - char *name; - unsigned char uuid[VIR_UUID_BUFLEN]; - int type; /* virStoragePoolType */ - - unsigned long long allocation; /* bytes */ - unsigned long long capacity; /* bytes */ - unsigned long long available; /* bytes */ - - virStoragePoolSource source; - virStoragePoolTarget target; -}; typedef struct _virStoragePoolObj virStoragePoolObj; typedef virStoragePoolObj *virStoragePoolObjPtr; - struct _virStoragePoolObj { virMutex lock; @@ -272,9 +169,8 @@ struct _virStoragePoolObj { int autostart; unsigned int asyncjobs; - virStoragePoolDefPtr def; - virStoragePoolDefPtr newDef; - + virPoolDefPtr def; + virPoolDefPtr newDef; virStorageVolDefList volumes; }; @@ -307,7 +203,7 @@ typedef virStoragePoolSourceList *virStoragePoolSourceListPtr; struct _virStoragePoolSourceList { int type; unsigned int nsources; - virStoragePoolSourcePtr sources; + virPoolSourcePtr sources; }; typedef bool (*virStoragePoolObjListFilter)(virConnectPtr conn, diff --git a/src/datatypes.h b/src/datatypes.h index 2b6adb4..1eaf4c6 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -561,7 +561,7 @@ struct _virInterface { * * Internal structure associated to a storage pool */ -struct _virStoragePool { +struct _virPoolCommon { virObject object; virConnectPtr conn; /* pointer back to the connection */ char *name; /* the storage pool external name */ @@ -580,7 +580,7 @@ struct _virStoragePool { * * Internal structure associated to a storage volume */ -struct _virStorageVol { +struct _virItemCommon { virObject object; virConnectPtr conn; /* pointer back to the connection */ char *pool; /* Pool name of owner */ diff --git a/src/util/virpoolcommon.h b/src/util/virpoolcommon.h new file mode 100644 index 0000000..d54de36 --- /dev/null +++ b/src/util/virpoolcommon.h @@ -0,0 +1,166 @@ +/* + * virpoolcommon.h: utility to operate common parts in storage pools and + * filesystem pools + * + * 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_POOL_COMMON_H__ +# define __VIR_POOL_COMMON_H__ + +# include "virstoragefile.h" +# include "virthread.h" +# include "virpci.h" + +/* + * For remote pools, info on how to reach the host + */ +typedef struct _virPoolSourceHost virPoolSourceHost; +typedef virPoolSourceHost *virPoolSourceHostPtr; +struct _virPoolSourceHost { + char *name; + int port; +}; + +/* + * Available extents on the underlying storage + */ +typedef struct _virPoolSourceDeviceExtent virPoolSourceDeviceExtent; +typedef virPoolSourceDeviceExtent *virPoolSourceDeviceExtentPtr; +struct _virPoolSourceDeviceExtent { + unsigned long long start; + unsigned long long end; + int type; /* virStorageFreeType */ +}; + +/* + * Pools can be backed by one or more devices, and some + * allow us to track free space on underlying devices. + */ +typedef struct _virPoolSourceDevice virPoolSourceDevice; +typedef virPoolSourceDevice *virPoolSourceDevicePtr; +struct _virPoolSourceDevice { + int nfreeExtent; + virPoolSourceDeviceExtentPtr freeExtents; + char *path; + int format; /* Pool specific source format */ + int part_separator; /* enum virTristateSwitch */ + + /* When the source device is a physical disk, + * the geometry data is needed + */ + struct _geometry { + int cylinders; + int heads; + int sectors; + } geometry; +}; + +typedef enum { + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_DEFAULT = 0, + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST, + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST, + + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_LAST, +} virStoragePoolSourceAdapterType; +VIR_ENUM_DECL(virStoragePoolSourceAdapter) + +typedef struct _virPoolSourceAdapter virPoolSourceAdapter; +typedef virPoolSourceAdapter *virPoolSourceAdapterPtr; +struct _virPoolSourceAdapter { + int type; /* virStoragePoolSourceAdapterType */ + + union { + struct { + char *name; + virPCIDeviceAddress parentaddr; /* host address */ + int unique_id; + bool has_parent; + } scsi_host; + struct { + char *parent; + char *wwnn; + char *wwpn; + int managed; /* enum virTristateSwitch */ + } fchost; + } data; +}; + +typedef struct _virPoolSourceInitiatorAttr virPoolSourceInitiatorAttr; +struct _virPoolSourceInitiatorAttr { + char *iqn; /* Initiator IQN */ +}; + +typedef struct _virPoolSource virPoolSource; +typedef virPoolSource *virPoolSourcePtr; +struct _virPoolSource { + /* An optional (maybe multiple) host(s) */ + size_t nhost; + virPoolSourceHostPtr hosts; + + /* And either one or more devices ... */ + size_t ndevice; + virPoolSourceDevicePtr devices; + + /* Or a directory */ + char *dir; + + /* Or an adapter */ + virPoolSourceAdapter adapter; + + /* Or a name */ + char *name; + + /* Initiator IQN */ + virPoolSourceInitiatorAttr initiator; + + /* Authentication information */ + virStorageAuthDefPtr auth; + + /* Vendor of the source */ + char *vendor; + + /* Product name of the source*/ + char *product; + + /* Pool type specific format such as filesystem type, + * or lvm version, etc. + */ + int format; +}; + +typedef struct _virPoolTarget virPoolTarget; +typedef virPoolTarget *virPoolTargetPtr; +struct _virPoolTarget { + char *path; /* Optional local filesystem mapping */ + virStoragePerms perms; /* Default permissions for volumes/items */ +}; + +typedef struct _virPoolDef virPoolDef; +typedef virPoolDef *virPoolDefPtr; +struct _virPoolDef { + char *name; + unsigned char uuid[VIR_UUID_BUFLEN]; + int type; /* virStoragePoolType */ + + unsigned long long allocation; /* bytes */ + unsigned long long capacity; /* bytes */ + unsigned long long available; /* bytes */ + + virPoolSource source; + virPoolTarget target; +}; +# endif /* __VIR_POOL_COMMON_H__ */ -- 1.8.3.1

On 12/02/2016 10:38 AM, Olga Krishtal wrote:
This is the first patch in fspool patchest. FSPool and storage pools has a lot in common, however we want to have separate drivers for its managment.
We want to use almost all storage pool descriptional structures for filesystem pool. All common structs is moved to virpoolcommon.h
More simply stated - for what's going to be I think a bit more complex than originally thought... The changes would be extracting out common pool mgmt code into their own API's so that they can be used by future patches (eg. the File System Storage Driver).
Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- include/libvirt/libvirt-storage.h | 5 +- src/Makefile.am | 5 +- src/conf/storage_conf.h | 126 +++-------------------------- src/datatypes.h | 4 +- src/util/virpoolcommon.h | 166 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 184 insertions(+), 122 deletions(-) create mode 100644 src/util/virpoolcommon.h
Patch fails "make syntax-check" preprocessor_indentation cppi: src/util/virpoolcommon.h: line 166: not properly indented maint.mk: incorrect preprocessor indentation cfg.mk:684: recipe for target 'sc_preprocessor_indentation' failed make: *** [sc_preprocessor_indentation] Error 1 Which is the last "# endif" in the file. ... First and most important, thanks for taking this on - it's going to be bumpy, but I think if we take it piece by piece that will be better in the long run. Also on the horizon is a need for a common pool structure for vGPU's - I think Laine will find having a common pool structure quite helpful for that work. While I understand why you're providing all the patches, I'm going to only focus on the first three for now. I'd prefer to agree on the infrastructure first, then add the fspool code. Hopefully that makes the mean time between patch series shorter, too. I see the first few patches as a means to create a common pool infrastructure. I think this is the right path, although I think you swung too far in that direction with what you've done. The new nomenclature doesn't need the "common" in the name/structures either. It's just "virpool.h" and "virpool.c" and it manages structures commonly used for pools. Currently it's just the block storage driver that needs it, but you're adding fspool which will be a file system storage driver. Just the first couple of patches have spawned off a few more ideas and a few "pre" patches... I really think it would be better to create the new structures and API's in one patch. Just keep track of wh This patch definitely can be further split... I think if you copy/paste code from one place to another and rename functions, fix comments, etc. and essentially set up the common pool code, then subsequent patches would just remove code. You can always note in the commit message where code was sourced from... Also remember, you're trying to hit a moving target. The storage pool/volume code is constantly changing - if you try to do everything at once there's bound to be conflicts. I already of some with what's here and in the subsequent patches. I also have other commitments so larger series will languish ;-) - reviews can take considerable time.
diff --git a/include/libvirt/libvirt-storage.h b/include/libvirt/libvirt-storage.h index 0974f6e..8572685 100644 --- a/include/libvirt/libvirt-storage.h +++ b/include/libvirt/libvirt-storage.h
You need to be very careful with changes here. The problem being existing code that may rely on _virStoragePool or _virStorageVol. We can always add, but it's the change that causes issues. That's why stuff got moved into datatypes.h because that's not the external API. In any case, there is an example - search on virBlkioParameter
@@ -34,7 +34,7 @@ * * a virStoragePool is a private structure representing a storage pool */ -typedef struct _virStoragePool virStoragePool; +typedef struct _virPoolCommon virStoragePool;
I think it would be just _virPool, but, what you have won't work. I believe you'd need something like: /* As of 3.x.x the _virPool was introduced to generalize a block * storage pool. This allows for backwards compatibility. */ # define _virStoragePool _virPool typedef struct _virPool virStoragePool That way anything that has _virStoragePool will/should do the right thing...
/** * virStoragePoolPtr: @@ -44,7 +44,6 @@ typedef struct _virStoragePool virStoragePool; */ typedef virStoragePool *virStoragePoolPtr;
-
Unnecessary whitespace adjustment.
typedef enum { VIR_STORAGE_POOL_INACTIVE = 0, /* Not running */ VIR_STORAGE_POOL_BUILDING = 1, /* Initializing pool, not available */ @@ -104,7 +103,7 @@ typedef virStoragePoolInfo *virStoragePoolInfoPtr; * * a virStorageVol is a private structure representing a storage volume */ -typedef struct _virStorageVol virStorageVol; +typedef struct _virItemCommon virStorageVol;
Similar issue here - that virItemCommon should be changed to something like "virPoolElement"
/** * virStorageVolPtr: diff --git a/src/Makefile.am b/src/Makefile.am index 8ee5567..f8d4a5b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -170,7 +170,7 @@ UTIL_SOURCES = \ util/virstats.c util/virstats.h \ util/virstorageencryption.c util/virstorageencryption.h \ util/virstoragefile.c util/virstoragefile.h \ - util/virstring.h util/virstring.c \ + util/virstring.h util/virstring.c \
?? Loss of whitespace?
util/virsysinfo.c util/virsysinfo.h \ util/virsystemd.c util/virsystemd.h \ util/virthread.c util/virthread.h \ @@ -185,7 +185,8 @@ UTIL_SOURCES = \ util/viruuid.c util/viruuid.h \ util/virxdrdefs.h \ util/virxml.c util/virxml.h \ - $(NULL) + util/virpoolcommon.h \
I think this should be util/virpool.h
+ $(NULL)
The $(NULL) should line up properly caveat emptor: I'm not a Makefile expert - not even close, but I would also think there would need to be rules to ensure proper rebuilds when/if virpool.h changes as well. Whatever depends upon it, such as STORAGE_CONF_SOURCES.
EXTRA_DIST += $(srcdir)/util/keymaps.csv $(srcdir)/util/virkeycode-mapgen.py
diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h index 185ae5e..8a9a789 100644 --- a/src/conf/storage_conf.h +++ b/src/conf/storage_conf.h
NB: Changes in here would be done after we settle on the common pool structures...
@@ -27,6 +27,7 @@ # include "internal.h" # include "virstorageencryption.h" # include "virstoragefile.h" +# include "virpoolcommon.h" # include "virbitmap.h" # include "virthread.h" # include "device_conf.h" @@ -58,7 +59,6 @@ struct _virStorageVolSource { * backend for partition type creation */ };
-
Loss of whitespace
typedef struct _virStorageVolDef virStorageVolDef; typedef virStorageVolDef *virStorageVolDefPtr; struct _virStorageVolDef { @@ -73,6 +73,7 @@ struct _virStorageVolDef { virStorageSource target; };
+
Add of whitespace - it's just a consistency thing - it has nothing to do with the changes and IMO should not be done.
typedef struct _virStorageVolDefList virStorageVolDefList; typedef virStorageVolDefList *virStorageVolDefListPtr; struct _virStorageVolDefList { @@ -112,12 +113,8 @@ typedef enum { /* * For remote pools, info on how to reach the host */ -typedef struct _virStoragePoolSourceHost virStoragePoolSourceHost; +typedef virPoolSourceHost virStoragePoolSourceHost; typedef virStoragePoolSourceHost *virStoragePoolSourceHostPtr; -struct _virStoragePoolSourceHost { - char *name; - int port; -};
This would be common
/* @@ -142,127 +139,27 @@ struct _virStoragePoolSourceDeviceExtent { int type; /* virStorageFreeType */ };
-typedef struct _virStoragePoolSourceInitiatorAttr virStoragePoolSourceInitiatorAttr; -struct _virStoragePoolSourceInitiatorAttr { - char *iqn; /* Initiator IQN */ -}; -
I don't see this as common... It's SCSI pool specific
/* * Pools can be backed by one or more devices, and some * allow us to track free space on underlying devices. */ -typedef struct _virStoragePoolSourceDevice virStoragePoolSourceDevice; +typedef virPoolSourceDevice virStoragePoolSourceDevice; typedef virStoragePoolSourceDevice *virStoragePoolSourceDevicePtr; -struct _virStoragePoolSourceDevice {
Not sure totally removing works - some of this data is storage specific, while other parts would be more common. See my thoughts at the bottom.
- int nfreeExtent; - virStoragePoolSourceDeviceExtentPtr freeExtents; - char *path; - int format; /* Pool specific source format */ - int part_separator; /* enum virTristateSwitch */ - - /* When the source device is a physical disk, - * the geometry data is needed - */ - struct _geometry { - int cylinders; - int heads; - int sectors; - } geometry; -};
BTW: I think you should make a storage_conf.h specific geometry structure as a separate patch prior to *any* other changes and send that patch. eg. typedef struct _virStoragePoolGeometry virStoragePoolGeometry; typedef struct virStoragePoolGeometry *virStoragePoolGeometryPtr; struct _virStoragePoolGeometry { int cylinders; int heads; int sectors; }; ... Then instead of _geometry inline: virStoragePoolGeometry geometry;
-typedef enum { - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_DEFAULT = 0, - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST, - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST, - - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_LAST, -} virStoragePoolSourceAdapterType; -VIR_ENUM_DECL(virStoragePoolSourceAdapter) -
This is SCSI storage pool specific
-typedef struct _virStoragePoolSourceAdapter virStoragePoolSourceAdapter; +typedef virPoolSourceAdapter virStoragePoolSourceAdapter; typedef virStoragePoolSourceAdapter *virStoragePoolSourceAdapterPtr; -struct _virStoragePoolSourceAdapter { - int type; /* virStoragePoolSourceAdapterType */ - - union { - struct { - char *name; - virPCIDeviceAddress parentaddr; /* host address */ - int unique_id; - bool has_parent; - } scsi_host; - struct { - char *parent; - char *wwnn; - char *wwpn; - int managed; /* enum virTristateSwitch */ - } fchost; - } data; -};
This is SCSI storage pool specific. scsi_host and fchost are _scsi backend specific constructs.
-typedef struct _virStoragePoolSource virStoragePoolSource; +typedef virPoolSource virStoragePoolSource; typedef virStoragePoolSource *virStoragePoolSourcePtr; -struct _virStoragePoolSource {
So some of this is storage specific and some could be considered common I suppose.
- /* An optional (maybe multiple) host(s) */ - size_t nhost; - virStoragePoolSourceHostPtr hosts;
Common - a generic pool could have host elements
- - /* And either one or more devices ... */ - size_t ndevice; - virStoragePoolSourceDevicePtr devices;
Common - a generic pool could have some sort of device elements
- - /* Or a directory */ - char *dir;
Common
- - /* Or an adapter */ - virStoragePoolSourceAdapter adapter;
Specific
- /* Or a name */ - char *name;
Common
- - /* Initiator IQN */ - virStoragePoolSourceInitiatorAttr initiator;
Specific
- - /* Authentication information */ - virStorageAuthDefPtr auth;
Common, but the name needs to change to something like "virPoolAuthDefPtr" (that could be a separate pre patch).
- - /* Vendor of the source */ - char *vendor;
Common
- - /* Product name of the source*/ - char *product;
Common
- - /* Pool type specific format such as filesystem type, - * or lvm version, etc. - */ - int format;
This is actually specific to 4 pool types fs, netfs, disk, and logical For the fs/netfs it's the file system format type while for disk and logical it's the partition format type... I have more ideas at the end.
-};
And of course while reviewing this I saw something wrong in the formatstorage.html page... A storage pool doesn't have timestamps nor does it have encryption (<sigh> ... sent a patch to resolve).
- -typedef struct _virStoragePoolTarget virStoragePoolTarget; +typedef virPoolTarget virStoragePoolTarget; typedef virStoragePoolTarget *virStoragePoolTargetPtr; -struct _virStoragePoolTarget { - char *path; /* Optional local filesystem mapping */ - virStoragePerms perms; /* Default permissions for volumes */ -};
Looks like it could be common, although virStoragePerms could change to something like virPoolPathPerms. Also instead of moving it to virstoragefile.c - add it to the virpool common code with the adjusted name. I could see a "need" for a pool element to have some sort of permissions/label'ing required. Anything with a path...
-typedef struct _virStoragePoolDef virStoragePoolDef; +typedef virPoolDef virStoragePoolDef; typedef virStoragePoolDef *virStoragePoolDefPtr; -struct _virStoragePoolDef {
I think some of this is common while other parts are specific
- char *name; - unsigned char uuid[VIR_UUID_BUFLEN];
Definitely common
- int type; /* virStoragePoolType */
Is specific and common...
- - unsigned long long allocation; /* bytes */ - unsigned long long capacity; /* bytes */ - unsigned long long available; /* bytes */
Storage specific - could make some sort of structure to hold all 3 in order to share the data...
- - virStoragePoolSource source; - virStoragePoolTarget target;
'source' uses the adjusted struct above, while target should be able to be just common
-};
typedef struct _virStoragePoolObj virStoragePoolObj; typedef virStoragePoolObj *virStoragePoolObjPtr; - struct _virStoragePoolObj { virMutex lock;
@@ -272,9 +169,8 @@ struct _virStoragePoolObj { int autostart; unsigned int asyncjobs;
- virStoragePoolDefPtr def; - virStoragePoolDefPtr newDef; - + virPoolDefPtr def; + virPoolDefPtr newDef;
After a few hours of reviewing and writing some comments, I came back to this change.... I think this is the magic place where things will get interesting... If you "consider" _virStoragePoolObj to be common, you get "_virPoolObj" which would need to be defined in virpool.h. It would look a bit like: struct _virPoolObj { virObjectLockable parent; virMutex lock; virPoolDefPtr def; virPoolDefPtr newDef; void *privateData; void (*privateDataFreeFunc)(void *); }; where the "privateData" in this case would be the "rest" of this virStoragePoolObj: struct _virStoragePoolPrivateObj { char *configFile; char *autostartLink; bool active; int autostart; unsigned int asyncjobs; virStorageVolDefList volumes; }; at least for the block storage pool. It could be different for the FS storage... and even more different for anything else. The key being - the virpool.c is managing the memory and calls to free come in the form of callbacks. It gets really confusing; however, the good news is I've recently done object creation in this manner in "virsecretobj", so I think that might be a good example for you to use. Although the secretobjs don't have the need (yet) for private data like you would for pools. You can look at the virDomainObj to see how it manages the privateData. If this is just overload, let me know - I can help here. You'd just be gated on me creating the infrastructure. I think you can look at the rest of this, but with my new information - I'd have to rethink how much applies <sigh>.
virStorageVolDefList volumes; };
@@ -307,7 +203,7 @@ typedef virStoragePoolSourceList *virStoragePoolSourceListPtr; struct _virStoragePoolSourceList { int type; unsigned int nsources; - virStoragePoolSourcePtr sources; + virPoolSourcePtr sources; };
typedef bool (*virStoragePoolObjListFilter)(virConnectPtr conn, diff --git a/src/datatypes.h b/src/datatypes.h index 2b6adb4..1eaf4c6 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -561,7 +561,7 @@ struct _virInterface { * * Internal structure associated to a storage pool
s/storage// IOW: This is an internal structure to describe a pool.
*/ -struct _virStoragePool { +struct _virPoolCommon {
s/Common// IOW: Just "_virPool {"
virObject object; virConnectPtr conn; /* pointer back to the connection */ char *name; /* the storage pool external name */
@@ -580,7 +580,7 @@ struct _virStoragePool { * * Internal structure associated to a storage volume
s/storage volume/pool element/
*/ -struct _virStorageVol { +struct _virItemCommon {
Similar comments/issues, although I really don't like the "_virItem" as a name. How about "_virPoolElement"?
virObject object; virConnectPtr conn; /* pointer back to the connection */ char *pool; /* Pool name of owner */
Be careful to check comments of the structures - remove {S|s}torage and {V|v}vol[ume]
diff --git a/src/util/virpoolcommon.h b/src/util/virpoolcommon.h new file mode 100644 index 0000000..d54de36 --- /dev/null +++ b/src/util/virpoolcommon.h @@ -0,0 +1,166 @@ +/* + * virpoolcommon.h: utility to operate common parts in storage pools and + * filesystem pools
Even better how about just a purely "common" pool format. Would initially be for storage pools, but eventually for the fspool. I also see a use for something else on the horizon - a graphics (vgpu) pool. I also think this should just be virpool.h - the common would be a given.
+ * + * 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_POOL_COMMON_H__ +# define __VIR_POOL_COMMON_H__
Changing name to just virpool.h adjust the above macros too.
+ +# include "virstoragefile.h"
But you wouldn't be including virstoragefile - that would be done elsewhere by code including this virpool.h that would also need virstoragefile.h
+# include "virthread.h"
Why was this needed?
+# include "virpci.h"
I think virpci.h won't be necessary either...
+ +/* + * For remote pools, info on how to reach the host + */ +typedef struct _virPoolSourceHost virPoolSourceHost; +typedef virPoolSourceHost *virPoolSourceHostPtr; +struct _virPoolSourceHost { + char *name; + int port; +}; + +/* + * Available extents on the underlying storage + */ +typedef struct _virPoolSourceDeviceExtent virPoolSourceDeviceExtent; +typedef virPoolSourceDeviceExtent *virPoolSourceDeviceExtentPtr; +struct _virPoolSourceDeviceExtent { + unsigned long long start; + unsigned long long end; + int type; /* virStorageFreeType */ +};
NB: The above hunk is block storage specific for the disk backend and thus wouldn't have/need a common structure.
+ +/* + * Pools can be backed by one or more devices, and some + * allow us to track free space on underlying devices. + */ +typedef struct _virPoolSourceDevice virPoolSourceDevice; +typedef virPoolSourceDevice *virPoolSourceDevicePtr; +struct _virPoolSourceDevice {
So part of this *isn't* common, it's specific - you could create a common structure and then a block storage specific that includes the common parts
+ int nfreeExtent; + virPoolSourceDeviceExtentPtr freeExtents;
The above two are Storage specific
+ char *path; + int format; /* Pool specific source format */
These would be common
+ int part_separator; /* enum virTristateSwitch */ +
Very specific to a disk pool for *a* specific case as a result of multipath devices being able to use "user friendly names" or not.
+ /* When the source device is a physical disk, + * the geometry data is needed + */ + struct _geometry { + int cylinders; + int heads; + int sectors; + } geometry; +};
Specific to the disk pool.
+ +typedef enum { + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_DEFAULT = 0, + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST, + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST, + + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_LAST, +} virStoragePoolSourceAdapterType; +VIR_ENUM_DECL(virStoragePoolSourceAdapter)
This would be SCSI storage pool specific and not for common file.
+ +typedef struct _virPoolSourceAdapter virPoolSourceAdapter; +typedef virPoolSourceAdapter *virPoolSourceAdapterPtr; +struct _virPoolSourceAdapter { + int type; /* virStoragePoolSourceAdapterType */ + + union { + struct { + char *name; + virPCIDeviceAddress parentaddr; /* host address */ + int unique_id; + bool has_parent; + } scsi_host; + struct { + char *parent; + char *wwnn; + char *wwpn; + int managed; /* enum virTristateSwitch */ + } fchost; + } data; +};
The above is SCSI storage specific.
+ +typedef struct _virPoolSourceInitiatorAttr virPoolSourceInitiatorAttr; +struct _virPoolSourceInitiatorAttr { + char *iqn; /* Initiator IQN */ +};
Same here, SCSI storage
+ +typedef struct _virPoolSource virPoolSource; +typedef virPoolSource *virPoolSourcePtr; +struct _virPoolSource {
See my comment earlier regarding which is common and specific - this becomes the common stuff, but it's easier for me to just point out below all the structs, so see the end...
+ /* An optional (maybe multiple) host(s) */ + size_t nhost; + virPoolSourceHostPtr hosts; + + /* And either one or more devices ... */ + size_t ndevice; + virPoolSourceDevicePtr devices; + + /* Or a directory */ + char *dir; + + /* Or an adapter */ + virPoolSourceAdapter adapter; + + /* Or a name */ + char *name; + + /* Initiator IQN */ + virPoolSourceInitiatorAttr initiator; + + /* Authentication information */ + virStorageAuthDefPtr auth; + + /* Vendor of the source */ + char *vendor; + + /* Product name of the source*/ + char *product; + + /* Pool type specific format such as filesystem type, + * or lvm version, etc. + */ + int format; +}; + +typedef struct _virPoolTarget virPoolTarget; +typedef virPoolTarget *virPoolTargetPtr; +struct _virPoolTarget { + char *path; /* Optional local filesystem mapping */ + virStoragePerms perms; /* Default permissions for volumes/items */ +};
This seems generic, although the comments need some tweaking to be more generic. A 'path' to the pool target... The virStoragePerms could become virPoolPathPerms with the virStoragePerms struct being your guide.
+ +typedef struct _virPoolDef virPoolDef; +typedef virPoolDef *virPoolDefPtr; +struct _virPoolDef { + char *name; + unsigned char uuid[VIR_UUID_BUFLEN]; + int type; /* virStoragePoolType */
s/Storage// I'm conflicted over how to use type... and of course there would need to be a virPoolType list which would initially just be "BLOCK_STORAGE", but would eventually have "FILESYSTEM_STORAGE" (and down the road VGPU_DEVICES).
+ + unsigned long long allocation; /* bytes */ + unsigned long long capacity; /* bytes */ + unsigned long long available; /* bytes */ +
These would be "storage" related, but less so common type data. They're all "sizing" elements and could also be their own storage specific structure.
+ virPoolSource source; + virPoolTarget target; +}; +# endif /* __VIR_POOL_COMMON_H__ */
What follows is my thoughts for various structures. I would think you have it fresh in your mind where the exact overlap is. These would be "virpool.h" type structures (left out some details): typedef enum { VIR_POOL_BLOCK_STORAGE, VIR_POOL_LAST, } virPoolType; struct _virPoolDef { int type; /* virPoolType */ char *name; unsigned char uuid[VIR_UUID_BUFLEN]; virPoolSource source; virPoolTarget target; }; BTW: I'm conflicted over the virPoolType since I'm not sure how it would be used other than to save it. We cannot use the virStoragePoolType enum's because those would be specific to the block storage pool... I'd suspect that FS struct _virPoolSource { /* One or more host definitions */ size_t nhost; virPoolSourceHostPtr hosts; /* Authentication information */ virStorageAuthDefPtr auth; /* One or more devices */ size_t nsrcpath; virPoolSourcePathPtr srcpaths; /* Name of the source */ char *name; /* Vendor of the source */ char *vendor; /* Product name of the source */ char *product; }; typedef enum { VIR_POOL_SOURCE_DIR, VIR_POOL_SOURCE_DEVICE, VIR_POOL_SOURCE_NAME, VIR_POOL_LAST, } virPoolSourcePathType; struct _virPoolSourcePath { virPoolSourcePathType sourcetype; char *path; }; NB: Turns out 'logical' can have both 'device' and 'name', but "name" ends up being something we can add to a logical specific structure. Also 'gluster' can have both 'dir' and 'name', but it seems name is primary when both are used (see tests/*xmlin/*pool*gluster*.xml). Still the key is they are all paths of some sort: <dir path='$PATH'> <device path='$PATH'> where <device> it could be a path to a BLOCK device (/dev/) or it could be an iSCSI initiator string (and thus SOURCE_NAME being used...). Search on "<dir" or "<device" in tests/*xmlin/*pool*.xml struct _virPoolSourceHost { char *name; int port; }; struct _virPoolAuthDef { char *username; char *secrettype; /* <secret type='%s' for disk source */ int authType; /* virStorageAuthType */ virSecretLookupTypeDef seclookupdef; }; struct _virPoolTarget { char *path; /* Optional path to target */ virPoolPathPerms perms; /* Default permissions for path */ }; struct _virPoolPathPerms { mode_t mode; uid_t uid; gid_t gid; char *label; } Below here would be storage_conf.h type adjustments: struct _virStoragePoolDef { virPoolDef pool; virStoragePoolType storagetype; virStoragePoolSizes size; /* Based on storagetype, a subdata could be allocated to have/save * storagetype specific data */ void *subdata; /* vir*StoragePoolDefPtr */ /* In order to make life easy - format will be defined here * although it's only used by the some pools (fs, netfs, * disk, and logical via virStoragePoolFormat* enums */ int format; /* virStoragePoolFormat* */ }; struct _virStoragePoolSizes { unsigned long long allocation; /* bytes */ unsigned long long capacity; /* bytes */ unsigned long long available; /* bytes */ }; struct _virSCSIStoragePoolDef { virStoragePoolSourceAdapter adapter; virStoragePoolSourceInitiatorAttr initiator; }; struct _virDiskStoragePoolDef { int nfreeExtent; virDiskStoragePoolDeviceExtentPtr freeExtents; virStoragePoolGeometry geometry; int part_separator; /* enum virTristateSwitch */ }; struct _virDiskStoragePoolDeviceExtent { unsigned long long start; unsigned long long end; int type; /* virStorageFreeType */ }; NB: Gluster wouldn't need a pool specific data - it would just use the "name" and "dir" separately. Also, I think there's other patches that will want to have multiple gluster paths, so this (more or less) allows for that. I probably left out some structures, but I hope this makes sense... Yes, it's going to be painful to make the switchover. That's why I suggest taking it slowly and not trying to pile on all the FSPool changes along. John

Hi, John. I needed some time to think over everything that you have written. Thanks a lot. With all this new information we have more freedom for changes and refactoring. I dig through storage_conf.h file once with all ideas you have and tried to use them. It would be easier for me if we agree about virpool structs. The other changes depends on it. Some moments are left unclear to me, so I have written down virpool.h with comments and questions. If you agree, please write Ok or smth else. /* Pool element description */ Lets use PoolUnit instead PoolElement: typedef struct _virPoolUnitDef virPoolUnitDef; typedef virPoolUnitDef *virPoolUnitDefPtr; struct _virPoolUnitDef { char *name; char *key; bool building; unsigned int in_use; void* UnitTypeDef /* the same as privateData for virConnectPtr. Stores internal information about pool unit */ }; Eg, 3 fields from virStorageVolDef: int type; virStorageVolSource source; virStorageSource target; typedef struct _virPoolUnitDefList virPoolUnitDefList; typedef virPoolUnitDefList *virPoolUnitDefListPtr; struct _virPoolUnitDefList { size_t count; virPoolUnitDefPtr *obj }; /* General information about pool source */ Why do we need this information in general part for pool of any kind? As I understand this structure is used when storage is remote or I am missing smth? typedef struct _virPoolSourceHost virPoolSourceHost; typedef virPoolSourceHost *virPoolSourceHostPtr; struct _virPoolSourceHost { char *name; int port; }; I think it should be somewhere in private part, because you have mentioned some other type of pool - vGPU, are you sure that authorization will be the same? Otherwise, what is virPoolAuth for general pool description? typedef struct _virPoolAuthDef virPoolAuthDef; typedef virPoolAuthDef *virPoolAuthDefPtr; struct _virPoolAuthDef { char *username; char *secrettype; /* <secret type='%s' for disk source */ int authType; /* virStorageAuthType */ virSecretLookupTypeDef seclookupdef; }; typedef enum { VIR_POOL_SOURCE_DIR, VIR_POOL_SOURCE_DEVICE, VIR_POOL_SOURCE_NAME, VIR_POOL_LAST, } typedef struct _virPoolSourcePath virPoolSourcePath; typedef virPoolSourcePath *virPoolSourcePathPtr; struct _virPoolSourcePath { virPoolSourcePathType sourcetype; char *path; }; typedef struct _virPoolSource virPoolSource; typedef virPoolSource *virPoolSourcePtr; struct _virPoolSource{ /* One or more host definitions */ size_t nhost; virPoolSourceHostPtr hosts; /* Authentication information */ virPoolAuthDefPtr auth; /*Not sure about it. We need authorization */ /* when we have to authorize in storage, but in Pool? */ /* One or more devices */ size_t nsrcpath; virPoolSourcePathPtr srcpaths; /* Name of the source */ May be we can use it for device name like in virPoolSourcePath char *name; /* Vendor of the source */ char *vendor; /* Product name of the source */ char *product; }; typedef struct _virPoolPathPerms virPoolPathPerms; typedef virPoolPathPerms *virPoolPathPermsPtr; struct _virPoolPathPerms { mode_t mode; uid_t uid; gid_t gid; char *label; } typedef struct _virPoolTarget virPoolTarget; typedef virPoolTarget *virPoolTargetPtr; struct _virPoolTarget{ What will be general description for path field? char *path; /* Optional path to target */ virPoolPathPerms perms; /* Default permissions for path */ }; typedef struct _virPoolDef virPoolDef; typedef virPoolDef *virPoolDefPtr; struct _virPoolDef { char *name; unsigned char uuid[VIR_UUID_BUFLEN]; virPoolSource source; virPoolTarget target; }; typedef struct _virPoolObj virPoolObj; typedef virPoolObj *virPoolObjPtr; struct _virPoolObj { virMutex lock; char *configFile; char *autostartLink; bool active; int autostart; unsigned int asyncjobs; virPoolDefPtr def; virPoolDefPtr newDef; virPoolUnitDefList elements; }; typedef struct _virPoolObjList virPoolObjList; typedef virPoolObjList *virPoolObjListPtr; struct _virPoolObjList { size_t count; virPoolObjPtr *objs; }; And some of functions prototype: void virPoolSourceClear(virPoolSourcePtr source); void virPoolSourceFree(virPoolSourcePtr source); void virPoolDefFree(virPoolDefPtr def); void virPoolObjFree(virPoolObjPtr pool); void virPoolObjListFree(virPoolObjListPtr pools); void virPoolObjRemove(virPoolObjListPtr pools, virPoolObjPtr pool); void virPoolObjLock(virPoolObjPtr obj); void virPoolObjUnlock(virPoolObjPtr obj); On 08/12/16 02:43, John Ferlan wrote: On 12/02/2016 10:38 AM, Olga Krishtal wrote: This is the first patch in fspool patchest. FSPool and storage pools has a lot in common, however we want to have separate drivers for its managment. We want to use almost all storage pool descriptional structures for filesystem pool. All common structs is moved to virpoolcommon.h More simply stated - for what's going to be I think a bit more complex than originally thought... The changes would be extracting out common pool mgmt code into their own API's so that they can be used by future patches (eg. the File System Storage Driver). Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com><mailto:okrishtal@virtuozzo.com> --- include/libvirt/libvirt-storage.h | 5 +- src/Makefile.am | 5 +- src/conf/storage_conf.h | 126 +++-------------------------- src/datatypes.h | 4 +- src/util/virpoolcommon.h | 166 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 184 insertions(+), 122 deletions(-) create mode 100644 src/util/virpoolcommon.h Patch fails "make syntax-check" preprocessor_indentation cppi: src/util/virpoolcommon.h: line 166: not properly indented maint.mk: incorrect preprocessor indentation cfg.mk:684: recipe for target 'sc_preprocessor_indentation' failed make: *** [sc_preprocessor_indentation] Error 1 Which is the last "# endif" in the file. Now I see, it is cppi that fails. I guess I did not have this test installed. That is the problem that I always have! May be all others failures with syntax-check is because of it. ... First and most important, thanks for taking this on - it's going to be bumpy, but I think if we take it piece by piece that will be better in the long run. Also on the horizon is a need for a common pool structure for vGPU's - I think Laine will find having a common pool structure quite helpful for that work. While I understand why you're providing all the patches, I'm going to only focus on the first three for now. I'd prefer to agree on the infrastructure first, then add the fspool code. Hopefully that makes the mean time between patch series shorter, too. I see the first few patches as a means to create a common pool infrastructure. I think this is the right path, although I think you swung too far in that direction with what you've done. The new nomenclature doesn't need the "common" in the name/structures either. It's just "virpool.h" and "virpool.c" and it manages structures commonly used for pools. Currently it's just the block storage driver that needs it, but you're adding fspool which will be a file system storage driver. Just the first couple of patches have spawned off a few more ideas and a few "pre" patches... I really think it would be better to create the new structures and API's in one patch. Just keep track of wh This patch definitely can be further split... I think if you copy/paste code from one place to another and rename functions, fix comments, etc. and essentially set up the common pool code, then subsequent patches would just remove code. You can always note in the commit message where code was sourced from... Also remember, you're trying to hit a moving target. The storage pool/volume code is constantly changing - if you try to do everything at once there's bound to be conflicts. I already of some with what's here and in the subsequent patches. I also have other commitments so larger series will languish ;-) - reviews can take considerable time. diff --git a/include/libvirt/libvirt-storage.h b/include/libvirt/libvirt-storage.h index 0974f6e..8572685 100644 --- a/include/libvirt/libvirt-storage.h +++ b/include/libvirt/libvirt-storage.h You need to be very careful with changes here. The problem being existing code that may rely on _virStoragePool or _virStorageVol. We can always add, but it's the change that causes issues. That's why stuff got moved into datatypes.h because that's not the external API. In any case, there is an example - search on virBlkioParameter @@ -34,7 +34,7 @@ * * a virStoragePool is a private structure representing a storage pool */ -typedef struct _virStoragePool virStoragePool; +typedef struct _virPoolCommon virStoragePool; I think it would be just _virPool, but, what you have won't work. I believe you'd need something like: /* As of 3.x.x the _virPool was introduced to generalize a block * storage pool. This allows for backwards compatibility. */ # define _virStoragePool _virPool typedef struct _virPool virStoragePool That way anything that has _virStoragePool will/should do the right thing... I see. I was not quite sure that everyone will agree to accept such change. So I decided to use virStoragePool as a base and to have a union in case fspools will need smth specific. But if it is OK. That I am totally in. /** * virStoragePoolPtr: @@ -44,7 +44,6 @@ typedef struct _virStoragePool virStoragePool; */ typedef virStoragePool *virStoragePoolPtr; - Unnecessary whitespace adjustment. typedef enum { VIR_STORAGE_POOL_INACTIVE = 0, /* Not running */ VIR_STORAGE_POOL_BUILDING = 1, /* Initializing pool, not available */ @@ -104,7 +103,7 @@ typedef virStoragePoolInfo *virStoragePoolInfoPtr; * * a virStorageVol is a private structure representing a storage volume */ -typedef struct _virStorageVol virStorageVol; +typedef struct _virItemCommon virStorageVol; Similar issue here - that virItemCommon should be changed to something like "virPoolElement" /** * virStorageVolPtr: diff --git a/src/Makefile.am b/src/Makefile.am index 8ee5567..f8d4a5b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -170,7 +170,7 @@ UTIL_SOURCES = \ util/virstats.c util/virstats.h \ util/virstorageencryption.c util/virstorageencryption.h \ util/virstoragefile.c util/virstoragefile.h \ - util/virstring.h util/virstring.c \ + util/virstring.h util/virstring.c \ ?? Loss of whitespace? util/virsysinfo.c util/virsysinfo.h \ util/virsystemd.c util/virsystemd.h \ util/virthread.c util/virthread.h \ @@ -185,7 +185,8 @@ UTIL_SOURCES = \ util/viruuid.c util/viruuid.h \ util/virxdrdefs.h \ util/virxml.c util/virxml.h \ - $(NULL) + util/virpoolcommon.h \ I think this should be util/virpool.h + $(NULL) The $(NULL) should line up properly caveat emptor: I'm not a Makefile expert - not even close, but I would also think there would need to be rules to ensure proper rebuilds when/if virpool.h changes as well. Whatever depends upon it, such as STORAGE_CONF_SOURCES. EXTRA_DIST += $(srcdir)/util/keymaps.csv $(srcdir)/util/virkeycode-mapgen.py diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h index 185ae5e..8a9a789 100644 --- a/src/conf/storage_conf.h +++ b/src/conf/storage_conf.h NB: Changes in here would be done after we settle on the common pool structures... @@ -27,6 +27,7 @@ # include "internal.h" # include "virstorageencryption.h" # include "virstoragefile.h" +# include "virpoolcommon.h" # include "virbitmap.h" # include "virthread.h" # include "device_conf.h" @@ -58,7 +59,6 @@ struct _virStorageVolSource { * backend for partition type creation */ }; - Loss of whitespace typedef struct _virStorageVolDef virStorageVolDef; typedef virStorageVolDef *virStorageVolDefPtr; struct _virStorageVolDef { @@ -73,6 +73,7 @@ struct _virStorageVolDef { virStorageSource target; }; + Add of whitespace - it's just a consistency thing - it has nothing to do with the changes and IMO should not be done. typedef struct _virStorageVolDefList virStorageVolDefList; typedef virStorageVolDefList *virStorageVolDefListPtr; struct _virStorageVolDefList { @@ -112,12 +113,8 @@ typedef enum { /* * For remote pools, info on how to reach the host */ -typedef struct _virStoragePoolSourceHost virStoragePoolSourceHost; +typedef virPoolSourceHost virStoragePoolSourceHost; typedef virStoragePoolSourceHost *virStoragePoolSourceHostPtr; -struct _virStoragePoolSourceHost { - char *name; - int port; -}; This would be common /* @@ -142,127 +139,27 @@ struct _virStoragePoolSourceDeviceExtent { int type; /* virStorageFreeType */ }; -typedef struct _virStoragePoolSourceInitiatorAttr virStoragePoolSourceInitiatorAttr; -struct _virStoragePoolSourceInitiatorAttr { - char *iqn; /* Initiator IQN */ -}; - I don't see this as common... It's SCSI pool specific /* * Pools can be backed by one or more devices, and some * allow us to track free space on underlying devices. */ -typedef struct _virStoragePoolSourceDevice virStoragePoolSourceDevice; +typedef virPoolSourceDevice virStoragePoolSourceDevice; typedef virStoragePoolSourceDevice *virStoragePoolSourceDevicePtr; -struct _virStoragePoolSourceDevice { Not sure totally removing works - some of this data is storage specific, while other parts would be more common. See my thoughts at the bottom. - int nfreeExtent; - virStoragePoolSourceDeviceExtentPtr freeExtents; - char *path; - int format; /* Pool specific source format */ - int part_separator; /* enum virTristateSwitch */ - - /* When the source device is a physical disk, - * the geometry data is needed - */ - struct _geometry { - int cylinders; - int heads; - int sectors; - } geometry; -}; BTW: I think you should make a storage_conf.h specific geometry structure as a separate patch prior to *any* other changes and send that patch. eg. typedef struct _virStoragePoolGeometry virStoragePoolGeometry; typedef struct virStoragePoolGeometry *virStoragePoolGeometryPtr; struct _virStoragePoolGeometry { int cylinders; int heads; int sectors; }; ... Then instead of _geometry inline: virStoragePoolGeometry geometry; -typedef enum { - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_DEFAULT = 0, - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST, - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST, - - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_LAST, -} virStoragePoolSourceAdapterType; -VIR_ENUM_DECL(virStoragePoolSourceAdapter) - This is SCSI storage pool specific -typedef struct _virStoragePoolSourceAdapter virStoragePoolSourceAdapter; +typedef virPoolSourceAdapter virStoragePoolSourceAdapter; typedef virStoragePoolSourceAdapter *virStoragePoolSourceAdapterPtr; -struct _virStoragePoolSourceAdapter { - int type; /* virStoragePoolSourceAdapterType */ - - union { - struct { - char *name; - virPCIDeviceAddress parentaddr; /* host address */ - int unique_id; - bool has_parent; - } scsi_host; - struct { - char *parent; - char *wwnn; - char *wwpn; - int managed; /* enum virTristateSwitch */ - } fchost; - } data; -}; This is SCSI storage pool specific. scsi_host and fchost are _scsi backend specific constructs. -typedef struct _virStoragePoolSource virStoragePoolSource; +typedef virPoolSource virStoragePoolSource; typedef virStoragePoolSource *virStoragePoolSourcePtr; -struct _virStoragePoolSource { So some of this is storage specific and some could be considered common I suppose. - /* An optional (maybe multiple) host(s) */ - size_t nhost; - virStoragePoolSourceHostPtr hosts; Common - a generic pool could have host elements - - /* And either one or more devices ... */ - size_t ndevice; - virStoragePoolSourceDevicePtr devices; Common - a generic pool could have some sort of device elements - - /* Or a directory */ - char *dir; Common - - /* Or an adapter */ - virStoragePoolSourceAdapter adapter; Specific - /* Or a name */ - char *name; Common - - /* Initiator IQN */ - virStoragePoolSourceInitiatorAttr initiator; Specific - - /* Authentication information */ - virStorageAuthDefPtr auth; Common, but the name needs to change to something like "virPoolAuthDefPtr" (that could be a separate pre patch). - - /* Vendor of the source */ - char *vendor; Common - - /* Product name of the source*/ - char *product; Common - - /* Pool type specific format such as filesystem type, - * or lvm version, etc. - */ - int format; This is actually specific to 4 pool types fs, netfs, disk, and logical For the fs/netfs it's the file system format type while for disk and logical it's the partition format type... I have more ideas at the end. -}; And of course while reviewing this I saw something wrong in the formatstorage.html page... A storage pool doesn't have timestamps nor does it have encryption (<sigh> ... sent a patch to resolve). - -typedef struct _virStoragePoolTarget virStoragePoolTarget; +typedef virPoolTarget virStoragePoolTarget; typedef virStoragePoolTarget *virStoragePoolTargetPtr; -struct _virStoragePoolTarget { - char *path; /* Optional local filesystem mapping */ - virStoragePerms perms; /* Default permissions for volumes */ -}; Looks like it could be common, although virStoragePerms could change to something like virPoolPathPerms. Also instead of moving it to virstoragefile.c - add it to the virpool common code with the adjusted name. I could see a "need" for a pool element to have some sort of permissions/label'ing required. Anything with a path... -typedef struct _virStoragePoolDef virStoragePoolDef; +typedef virPoolDef virStoragePoolDef; typedef virStoragePoolDef *virStoragePoolDefPtr; -struct _virStoragePoolDef { I think some of this is common while other parts are specific - char *name; - unsigned char uuid[VIR_UUID_BUFLEN]; Definitely common - int type; /* virStoragePoolType */ Is specific and common... - - unsigned long long allocation; /* bytes */ - unsigned long long capacity; /* bytes */ - unsigned long long available; /* bytes */ Storage specific - could make some sort of structure to hold all 3 in order to share the data... - - virStoragePoolSource source; - virStoragePoolTarget target; 'source' uses the adjusted struct above, while target should be able to be just common -}; typedef struct _virStoragePoolObj virStoragePoolObj; typedef virStoragePoolObj *virStoragePoolObjPtr; - struct _virStoragePoolObj { virMutex lock; @@ -272,9 +169,8 @@ struct _virStoragePoolObj { int autostart; unsigned int asyncjobs; - virStoragePoolDefPtr def; - virStoragePoolDefPtr newDef; - + virPoolDefPtr def; + virPoolDefPtr newDef; After a few hours of reviewing and writing some comments, I came back to this change.... I think this is the magic place where things will get interesting... If you "consider" _virStoragePoolObj to be common, you get "_virPoolObj" which would need to be defined in virpool.h. It would look a bit like: struct _virPoolObj { virObjectLockable parent; virMutex lock; virPoolDefPtr def; virPoolDefPtr newDef; void *privateData; void (*privateDataFreeFunc)(void *); }; where the "privateData" in this case would be the "rest" of this virStoragePoolObj: struct _virStoragePoolPrivateObj { char *configFile; char *autostartLink; bool active; int autostart; unsigned int asyncjobs; virStorageVolDefList volumes; }; at least for the block storage pool. It could be different for the FS storage... and even more different for anything else. The key being - the virpool.c is managing the memory and calls to free come in the form of callbacks. It gets really confusing; however, the good news is I've recently done object creation in this manner in "virsecretobj", so I think that might be a good example for you to use. Although the secretobjs don't have the need (yet) for private data like you would for pools. You can look at the virDomainObj to see how it manages the privateData. If this is just overload, let me know - I can help here. You'd just be gated on me creating the infrastructure. I think you can look at the rest of this, but with my new information - I'd have to rethink how much applies <sigh>. virStorageVolDefList volumes; }; @@ -307,7 +203,7 @@ typedef virStoragePoolSourceList *virStoragePoolSourceListPtr; struct _virStoragePoolSourceList { int type; unsigned int nsources; - virStoragePoolSourcePtr sources; + virPoolSourcePtr sources; }; typedef bool (*virStoragePoolObjListFilter)(virConnectPtr conn, diff --git a/src/datatypes.h b/src/datatypes.h index 2b6adb4..1eaf4c6 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -561,7 +561,7 @@ struct _virInterface { * * Internal structure associated to a storage pool s/storage// IOW: This is an internal structure to describe a pool. */ -struct _virStoragePool { +struct _virPoolCommon { s/Common// IOW: Just "_virPool {" virObject object; virConnectPtr conn; /* pointer back to the connection */ char *name; /* the storage pool external name */ @@ -580,7 +580,7 @@ struct _virStoragePool { * * Internal structure associated to a storage volume s/storage volume/pool element/ */ -struct _virStorageVol { +struct _virItemCommon { Similar comments/issues, although I really don't like the "_virItem" as a name. How about "_virPoolElement"? virObject object; virConnectPtr conn; /* pointer back to the connection */ char *pool; /* Pool name of owner */ Be careful to check comments of the structures - remove {S|s}torage and {V|v}vol[ume] diff --git a/src/util/virpoolcommon.h b/src/util/virpoolcommon.h new file mode 100644 index 0000000..d54de36 --- /dev/null +++ b/src/util/virpoolcommon.h @@ -0,0 +1,166 @@ +/* + * virpoolcommon.h: utility to operate common parts in storage pools and + * filesystem pools Even better how about just a purely "common" pool format. Would initially be for storage pools, but eventually for the fspool. I also see a use for something else on the horizon - a graphics (vgpu) pool. I also think this should just be virpool.h - the common would be a given. + * + * 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/><http://www.gnu.org/licenses/>. + * + */ + +#ifndef __VIR_POOL_COMMON_H__ +# define __VIR_POOL_COMMON_H__ Changing name to just virpool.h adjust the above macros too. + +# include "virstoragefile.h" But you wouldn't be including virstoragefile - that would be done elsewhere by code including this virpool.h that would also need virstoragefile.h +# include "virthread.h" Why was this needed? +# include "virpci.h" I think virpci.h won't be necessary either... + +/* + * For remote pools, info on how to reach the host + */ +typedef struct _virPoolSourceHost virPoolSourceHost; +typedef virPoolSourceHost *virPoolSourceHostPtr; +struct _virPoolSourceHost { + char *name; + int port; +}; + +/* + * Available extents on the underlying storage + */ +typedef struct _virPoolSourceDeviceExtent virPoolSourceDeviceExtent; +typedef virPoolSourceDeviceExtent *virPoolSourceDeviceExtentPtr; +struct _virPoolSourceDeviceExtent { + unsigned long long start; + unsigned long long end; + int type; /* virStorageFreeType */ +}; NB: The above hunk is block storage specific for the disk backend and thus wouldn't have/need a common structure. + +/* + * Pools can be backed by one or more devices, and some + * allow us to track free space on underlying devices. + */ +typedef struct _virPoolSourceDevice virPoolSourceDevice; +typedef virPoolSourceDevice *virPoolSourceDevicePtr; +struct _virPoolSourceDevice { So part of this *isn't* common, it's specific - you could create a common structure and then a block storage specific that includes the common parts + int nfreeExtent; + virPoolSourceDeviceExtentPtr freeExtents; The above two are Storage specific + char *path; + int format; /* Pool specific source format */ These would be common + int part_separator; /* enum virTristateSwitch */ + Very specific to a disk pool for *a* specific case as a result of multipath devices being able to use "user friendly names" or not. + /* When the source device is a physical disk, + * the geometry data is needed + */ + struct _geometry { + int cylinders; + int heads; + int sectors; + } geometry; +}; Specific to the disk pool. + +typedef enum { + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_DEFAULT = 0, + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST, + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST, + + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_LAST, +} virStoragePoolSourceAdapterType; +VIR_ENUM_DECL(virStoragePoolSourceAdapter) This would be SCSI storage pool specific and not for common file. + +typedef struct _virPoolSourceAdapter virPoolSourceAdapter; +typedef virPoolSourceAdapter *virPoolSourceAdapterPtr; +struct _virPoolSourceAdapter { + int type; /* virStoragePoolSourceAdapterType */ + + union { + struct { + char *name; + virPCIDeviceAddress parentaddr; /* host address */ + int unique_id; + bool has_parent; + } scsi_host; + struct { + char *parent; + char *wwnn; + char *wwpn; + int managed; /* enum virTristateSwitch */ + } fchost; + } data; +}; The above is SCSI storage specific. + +typedef struct _virPoolSourceInitiatorAttr virPoolSourceInitiatorAttr; +struct _virPoolSourceInitiatorAttr { + char *iqn; /* Initiator IQN */ +}; Same here, SCSI storage + +typedef struct _virPoolSource virPoolSource; +typedef virPoolSource *virPoolSourcePtr; +struct _virPoolSource { See my comment earlier regarding which is common and specific - this becomes the common stuff, but it's easier for me to just point out below all the structs, so see the end... + /* An optional (maybe multiple) host(s) */ + size_t nhost; + virPoolSourceHostPtr hosts; + + /* And either one or more devices ... */ + size_t ndevice; + virPoolSourceDevicePtr devices; + + /* Or a directory */ + char *dir; + + /* Or an adapter */ + virPoolSourceAdapter adapter; + + /* Or a name */ + char *name; + + /* Initiator IQN */ + virPoolSourceInitiatorAttr initiator; + + /* Authentication information */ + virStorageAuthDefPtr auth; + + /* Vendor of the source */ + char *vendor; + + /* Product name of the source*/ + char *product; + + /* Pool type specific format such as filesystem type, + * or lvm version, etc. + */ + int format; +}; + +typedef struct _virPoolTarget virPoolTarget; +typedef virPoolTarget *virPoolTargetPtr; +struct _virPoolTarget { + char *path; /* Optional local filesystem mapping */ + virStoragePerms perms; /* Default permissions for volumes/items */ +}; This seems generic, although the comments need some tweaking to be more generic. A 'path' to the pool target... The virStoragePerms could become virPoolPathPerms with the virStoragePerms struct being your guide. + +typedef struct _virPoolDef virPoolDef; +typedef virPoolDef *virPoolDefPtr; +struct _virPoolDef { + char *name; + unsigned char uuid[VIR_UUID_BUFLEN]; + int type; /* virStoragePoolType */ s/Storage// I'm conflicted over how to use type... and of course there would need to be a virPoolType list which would initially just be "BLOCK_STORAGE", but would eventually have "FILESYSTEM_STORAGE" (and down the road VGPU_DEVICES). + + unsigned long long allocation; /* bytes */ + unsigned long long capacity; /* bytes */ + unsigned long long available; /* bytes */ + These would be "storage" related, but less so common type data. They're all "sizing" elements and could also be their own storage specific structure. + virPoolSource source; + virPoolTarget target; +}; +# endif /* __VIR_POOL_COMMON_H__ */ What follows is my thoughts for various structures. I would think you have it fresh in your mind where the exact overlap is. These would be "virpool.h" type structures (left out some details): typedef enum { VIR_POOL_BLOCK_STORAGE, VIR_POOL_LAST, } virPoolType; struct _virPoolDef { int type; /* virPoolType */ char *name; unsigned char uuid[VIR_UUID_BUFLEN]; virPoolSource source; virPoolTarget target; }; BTW: I'm conflicted over the virPoolType since I'm not sure how it would be used other than to save it. We cannot use the virStoragePoolType enum's because those would be specific to the block storage pool... I'd suspect that FS struct _virPoolSource { /* One or more host definitions */ size_t nhost; virPoolSourceHostPtr hosts; /* Authentication information */ virStorageAuthDefPtr auth; /* One or more devices */ size_t nsrcpath; virPoolSourcePathPtr srcpaths; /* Name of the source */ char *name; /* Vendor of the source */ char *vendor; /* Product name of the source */ char *product; }; typedef enum { VIR_POOL_SOURCE_DIR, VIR_POOL_SOURCE_DEVICE, VIR_POOL_SOURCE_NAME, VIR_POOL_LAST, } virPoolSourcePathType; struct _virPoolSourcePath { virPoolSourcePathType sourcetype; char *path; }; NB: Turns out 'logical' can have both 'device' and 'name', but "name" ends up being something we can add to a logical specific structure. Also 'gluster' can have both 'dir' and 'name', but it seems name is primary when both are used (see tests/*xmlin/*pool*gluster*.xml). Still the key is they are all paths of some sort: <dir path='$PATH'> <device path='$PATH'> where <device> it could be a path to a BLOCK device (/dev/) or it could be an iSCSI initiator string (and thus SOURCE_NAME being used...). Search on "<dir" or "<device" in tests/*xmlin/*pool*.xml struct _virPoolSourceHost { char *name; int port; }; struct _virPoolAuthDef { char *username; char *secrettype; /* <secret type='%s' for disk source */ int authType; /* virStorageAuthType */ virSecretLookupTypeDef seclookupdef; }; struct _virPoolTarget { char *path; /* Optional path to target */ virPoolPathPerms perms; /* Default permissions for path */ }; struct _virPoolPathPerms { mode_t mode; uid_t uid; gid_t gid; char *label; } Below here would be storage_conf.h type adjustments: struct _virStoragePoolDef { virPoolDef pool; virStoragePoolType storagetype; virStoragePoolSizes size; /* Based on storagetype, a subdata could be allocated to have/save * storagetype specific data */ void *subdata; /* vir*StoragePoolDefPtr */ /* In order to make life easy - format will be defined here * although it's only used by the some pools (fs, netfs, * disk, and logical via virStoragePoolFormat* enums */ int format; /* virStoragePoolFormat* */ }; struct _virStoragePoolSizes { unsigned long long allocation; /* bytes */ unsigned long long capacity; /* bytes */ unsigned long long available; /* bytes */ }; struct _virSCSIStoragePoolDef { virStoragePoolSourceAdapter adapter; virStoragePoolSourceInitiatorAttr initiator; }; struct _virDiskStoragePoolDef { int nfreeExtent; virDiskStoragePoolDeviceExtentPtr freeExtents; virStoragePoolGeometry geometry; int part_separator; /* enum virTristateSwitch */ }; struct _virDiskStoragePoolDeviceExtent { unsigned long long start; unsigned long long end; int type; /* virStorageFreeType */ }; NB: Gluster wouldn't need a pool specific data - it would just use the "name" and "dir" separately. Also, I think there's other patches that will want to have multiple gluster paths, so this (more or less) allows for that. I probably left out some structures, but I hope this makes sense... Yes, it's going to be painful to make the switchover. That's why I suggest taking it slowly and not trying to pile on all the FSPool changes along. John -- Best regards, Olga

On 12/15/2016 12:16 PM, Olga Krishtal wrote:
Hi, John. I needed some time to think over everything that you have written. Thanks a lot.
Yeah - I got too wordy, but this type of change caused me to think about other possible consumers too.
With all this new information we have more freedom for changes and refactoring.
Like I thought I mentioned - this set of changes seem to have gone too far in the direction of common code. Of course the original set of changes was too much cut-n-paste for my taste. There has to be a happy medium - that's what we need to find. I usually do that by figuring out what I'll need, creating generic structs/code and slowly moving things. Even if the generic structs start in the specific code - they can be moved. I would think at this point you know what you eventually need in the fspool driver - so that's where to start.
I dig through storage_conf.h file once with all ideas you have and tried to use them. It would be easier for me if we agree about virpool structs. The other changes depends on it.
Sure to a degree. Some of this ends up being trial and error... or prototyping some changes to see what will and won't work. Trying to do this conceptually in email is difficult too, especially with other things going on. Again, create smaller patches that have the end goal.
Some moments are left unclear to me, so I have written down virpool.h with comments and questions. If you agree, please write Ok or smth else.
After sending I kept thinking about things "in the background". I took a pass at trying to extract/abstract just the pool concept and suffice to say it's a bit overwhelming. It's possible - it just has to be done carefully. Essentially though if you take the concept of a PoolObj to a different level of abstraction - it's a very common thing - there are domain, network, secret, storage, etc. that all use the objects code to build up a list or hash table of objects that point at 'def' data. In any case at this time I don't think that level of abstraction would be necessary for what you're trying to accomplish. And if I do come up with something - I would hope it'll be easy to merge in what you have.
/* Pool element description */ Lets use PoolUnit instead PoolElement:
Not a fan of Unit... This could just be _virPoolDef while the consumer of this would be _virStorageBlockPoolDef and _virStorageFSPoolDef.
typedef struct _virPoolUnitDef virPoolUnitDef; typedef virPoolUnitDef *virPoolUnitDefPtr; struct _virPoolUnitDef { char *name; char *key; bool building; unsigned int in_use;
void* UnitTypeDef /* the same as privateData for virConnectPtr. Stores internal information about pool unit */ };
Why *name in both PoolUnitDef and PoolDef? I think uuid should be here. There should be a 'voltype' field here... Changing the name will dig out code that's using it. As I found with the 'virStorageSource' "type" field there were a couple of source.target.type field users where source.target.type is not filled in. I have some patches to address that in a branch, but I'm waiting on other reviews to be completed before posting. Not sure I like UnitTypeDef - the common usage is privateData. Oh and you'd need a "void (*privateDataFreeFunc)(void *);". Might also need a few more things, but seems to be a good start.
Eg, 3 fields from virStorageVolDef: int type; virStorageVolSource source; virStorageSource target;
typedef struct _virPoolUnitDefList virPoolUnitDefList; typedef virPoolUnitDefList *virPoolUnitDefListPtr; struct _virPoolUnitDefList { size_t count; virPoolUnitDefPtr *obj };
I don't think *List is the way to go, but since that's the model today - we can stick with it until I can work up something better. Lists work well when there's 1-10 elements on the List, but as more elements are added the search times exponentially increase. I think HashTable's are the better option (Domains, Secrets, Networks, and DomainSnapshot use them). See the virDomainObjList for a model. In any case, why are there voldefs in a list? Is this some sort of backing store listing for the same volume object? Or was this meant to be the volume object list?
/* General information about pool source */
Why do we need this information in general part for pool of any kind?
This structure manages how a domain views the storage. It is quite confusing and you have to pay close attention to the usage.
As I understand this structure is used when storage is remote or I am missing smth?
Yes, this is essentially for remote/network storage
typedef struct _virPoolSourceHost virPoolSourceHost; typedef virPoolSourceHost *virPoolSourceHostPtr; struct _virPoolSourceHost { char *name; int port;
};
For purposes of what you're trying to accomplish - it can be block storage specific unless you feel fspools would/could use NFS or would have their own need for a network structure.
I think it should be somewhere in private part, because you have mentioned some other type of pool - vGPU, are you sure that authorization will be the same?
A vGPU would be something local and shouldn't need auth. A vGPU is something new dealing with graphics where there will be a need to have a pool of vGPU's to choose from much the same way there is storage.
Otherwise, what is virPoolAuth for general pool description?
typedef struct _virPoolAuthDef virPoolAuthDef; typedef virPoolAuthDef *virPoolAuthDefPtr; struct _virPoolAuthDef { char *username; char *secrettype; /* <secret type='%s' for disk source */ int authType; /* virStorageAuthType */ virSecretLookupTypeDef seclookupdef; };
secrets are usually associated with remote storage; however, they're also something for local only as evidenced by the LUKS encryption secret. We could start as a private thing, but it could be moved as well. Again, depends on the implementation. Of course I've got the vzstorage pool concepts floating in and out of consciousness - tough to focus on one over the other!
typedef enum {
VIR_POOL_SOURCE_DIR, VIR_POOL_SOURCE_DEVICE,
VIR_POOL_SOURCE_NAME,
VIR_POOL_LAST, }
typedef struct _virPoolSourcePath virPoolSourcePath; typedef virPoolSourcePath *virPoolSourcePathPtr; struct _virPoolSourcePath { virPoolSourcePathType sourcetype; char *path; };
typedef struct _virPoolSource virPoolSource; typedef virPoolSource *virPoolSourcePtr; struct _virPoolSource{ /* One or more host definitions */ size_t nhost; virPoolSourceHostPtr hosts;
/* Authentication information */ virPoolAuthDefPtr auth; /*Not sure about it. We need authorization */ /* when we have to authorize in storage, but in Pool? */ /* One or more devices */ size_t nsrcpath; virPoolSourcePathPtr srcpaths;
/* Name of the source */ May be we can use it for device name like in virPoolSourcePath char *name;
/* Vendor of the source */ char *vendor;
/* Product name of the source */ char *product; };
I have come to realize that mucking in virStorageSource I think is going to require a the structure to become private with a bunch of accessors to fields. Too much code today knows the structure and makes use of it. I started working through doing something like that as a result of other changes I've been posting related to storage source data. The biggest offender in peeking at the StorageSource is the path to the storage.
typedef struct _virPoolPathPerms virPoolPathPerms; typedef virPoolPathPerms *virPoolPathPermsPtr; struct _virPoolPathPerms { mode_t mode; uid_t uid; gid_t gid; char *label; }
typedef struct _virPoolTarget virPoolTarget; typedef virPoolTarget *virPoolTargetPtr; struct _virPoolTarget{ What will be general description for path field? char *path; /* Optional path to target */ virPoolPathPerms perms; /* Default permissions for path */ };
http://libvirt.org/formatstorage.html Target elements, path. There are virStorageSource fields that aren't used for 'target' storage... But there's virStorageSourcePtr used for backingStore... You have to follow code paths to understand usage.
typedef struct _virPoolDef virPoolDef; typedef virPoolDef *virPoolDefPtr; struct _virPoolDef { char *name; unsigned char uuid[VIR_UUID_BUFLEN];
virPoolSource source; virPoolTarget target; };
typedef struct _virPoolObj virPoolObj; typedef virPoolObj *virPoolObjPtr; struct _virPoolObj { virMutex lock;
^^ Should use the virObjectLockable object... Yes requires some 'other' adjustments...
char *configFile; char *autostartLink; bool active; int autostart; unsigned int asyncjobs;
virPoolDefPtr def; virPoolDefPtr newDef;
virPoolUnitDefList elements;
you'd have to call this 'units' instead of 'elements', which is why I said "Elements" at first.
};
typedef struct _virPoolObjList virPoolObjList; typedef virPoolObjList *virPoolObjListPtr; struct _virPoolObjList { size_t count; virPoolObjPtr *objs; };
Again, a hash table will be better... I think there's perhaps : _virPoolDef -> Common pool definition with private data pointers _virStorageBlockPoolDef -> Consumer of _virPoolDef as private data _virStorageFSPoolDef -> Consumer of _virPoolDef as private data _virPoolObj -> Common pool object with private data pointer _virStorageBlockPoolObj -> Consumer of _virPoolObj private data _virStorageFSPoolObj -> Consumer of _virPoolObj _virPoolObjList-> Common pool object list manipulation and search API I see no need (yet) for a StorageBlock or StoragePool object list. The ObjList is a table of objects with common reference/lookup functions. The tricky part there is the filtering API's currently used for various lookup APIs in order to pull out specific "types" of objects. The PoolObj some common stuff (def, newdef, some flags, locking) as well as a privateData for specific stuff. It would also have a 'def' that could describe the common lookup of uuid/name. The PoolDef is mostly private just to allow for easier lookups - that would copy the 'def' uuid/name fields
And some of functions prototype: void virPoolSourceClear(virPoolSourcePtr source); void virPoolSourceFree(virPoolSourcePtr source); void virPoolDefFree(virPoolDefPtr def); void virPoolObjFree(virPoolObjPtr pool); void virPoolObjListFree(virPoolObjListPtr pools); void virPoolObjRemove(virPoolObjListPtr pools, virPoolObjPtr pool); void virPoolObjLock(virPoolObjPtr obj); void virPoolObjUnlock(virPoolObjPtr obj);
FWIW: At the higher abstraction level the driver (StoragePool) is responsible to managing some sort of list or table of objects. Using cscope's egrep search capabilities - "^struct vir.*ObjList" returns 8 such instances. Of those 4 use a counted list (Interface, NodeDevice, NWFilter, StoragePool) and 4 use a hash table (Network, DomainSnapshot, Domain, Secret). Each ObjList would manage the _vir*Obj element corresponding to it (cscope egrep "^struct vir.*Obj {". Each of those Objects has commonality (parent/lock, def, newDef, state bits, privateData, privateDataFreeFunc). For example, search on consumers of "*ObjListNew()" type calls or anything that could be found by a cscope egrep of "^struct vir.*ObjList". There's quite a bit of cut-n-paste there. In any case, the previous 3 paragraphs are something on my radar, but I figured I'd share...
On 08/12/16 02:43, John Ferlan wrote:
On 12/02/2016 10:38 AM, Olga Krishtal wrote:
This is the first patch in fspool patchest. FSPool and storage pools has a lot in common, however we want to have separate drivers for its managment.
We want to use almost all storage pool descriptional structures for filesystem pool. All common structs is moved to virpoolcommon.h
More simply stated - for what's going to be I think a bit more complex than originally thought... The changes would be extracting out common pool mgmt code into their own API's so that they can be used by future patches (eg. the File System Storage Driver).
Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- include/libvirt/libvirt-storage.h | 5 +- src/Makefile.am | 5 +- src/conf/storage_conf.h | 126 +++-------------------------- src/datatypes.h | 4 +- src/util/virpoolcommon.h | 166 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 184 insertions(+), 122 deletions(-) create mode 100644 src/util/virpoolcommon.h
Patch fails "make syntax-check"
preprocessor_indentation cppi: src/util/virpoolcommon.h: line 166: not properly indented maint.mk: incorrect preprocessor indentation cfg.mk:684: recipe for target 'sc_preprocessor_indentation' failed make: *** [sc_preprocessor_indentation] Error 1
Which is the last "# endif" in the file.
Now I see, it is cppi that fails. I guess I did not have this test installed. That is the problem that I always have! May be all others failures with syntax-check is because of it.
Yeah - there's stuff I've found along the way like this too... Usually when something like this is discovered we try to make sure there's some sort of requirement added into the build system so that everyone would see the issue and not just those that have already tripped across it. I think that's where those Requires/BuildRequires come from - been a while since I thought about it though.
...
First and most important, thanks for taking this on - it's going to be bumpy, but I think if we take it piece by piece that will be better in the long run. Also on the horizon is a need for a common pool structure for vGPU's - I think Laine will find having a common pool structure quite helpful for that work.
While I understand why you're providing all the patches, I'm going to only focus on the first three for now. I'd prefer to agree on the infrastructure first, then add the fspool code. Hopefully that makes the mean time between patch series shorter, too.
I see the first few patches as a means to create a common pool infrastructure. I think this is the right path, although I think you swung too far in that direction with what you've done.
The new nomenclature doesn't need the "common" in the name/structures either. It's just "virpool.h" and "virpool.c" and it manages structures commonly used for pools. Currently it's just the block storage driver that needs it, but you're adding fspool which will be a file system storage driver.
Just the first couple of patches have spawned off a few more ideas and a few "pre" patches... I really think it would be better to create the new structures and API's in one patch. Just keep track of wh
This patch definitely can be further split... I think if you copy/paste code from one place to another and rename functions, fix comments, etc. and essentially set up the common pool code, then subsequent patches would just remove code. You can always note in the commit message where code was sourced from...
Also remember, you're trying to hit a moving target. The storage pool/volume code is constantly changing - if you try to do everything at once there's bound to be conflicts. I already of some with what's here and in the subsequent patches. I also have other commitments so larger series will languish ;-) - reviews can take considerable time.
diff --git a/include/libvirt/libvirt-storage.h b/include/libvirt/libvirt-storage.h index 0974f6e..8572685 100644 --- a/include/libvirt/libvirt-storage.h +++ b/include/libvirt/libvirt-storage.h You need to be very careful with changes here. The problem being existing code that may rely on _virStoragePool or _virStorageVol. We can always add, but it's the change that causes issues. That's why stuff got moved into datatypes.h because that's not the external API.
In any case, there is an example - search on virBlkioParameter
@@ -34,7 +34,7 @@ * * a virStoragePool is a private structure representing a storage pool */ -typedef struct _virStoragePool virStoragePool; +typedef struct _virPoolCommon virStoragePool; I think it would be just _virPool, but, what you have won't work. I believe you'd need something like:
/* As of 3.x.x the _virPool was introduced to generalize a block * storage pool. This allows for backwards compatibility. */ # define _virStoragePool _virPool typedef struct _virPool virStoragePool
That way anything that has _virStoragePool will/should do the right thing...
I see. I was not quite sure that everyone will agree to accept such change. So I decided to use virStoragePool as a base and to have a union in case fspools will need smth specific. But if it is OK. That I am totally in.
The point I was making is changing from _virStoragePool to _virPoolCommon won't necessary fly without the ability to have some sort of definition. The usage of "_virPool" instead of "_virCommonPool" is my nomenclature. The example I referenced is how BlkioParameter did the changeover. I think it will work fine, but the details are something that are only known once someone jumps into the pool and starts swimming or sinking (a metaphor for the heap of trouble you get yourself into once you start actually coding things). John
/** * virStoragePoolPtr: @@ -44,7 +44,6 @@ typedef struct _virStoragePool virStoragePool; */ typedef virStoragePool *virStoragePoolPtr;
-
Unnecessary whitespace adjustment.
typedef enum { VIR_STORAGE_POOL_INACTIVE = 0, /* Not running */ VIR_STORAGE_POOL_BUILDING = 1, /* Initializing pool, not available */ @@ -104,7 +103,7 @@ typedef virStoragePoolInfo *virStoragePoolInfoPtr; * * a virStorageVol is a private structure representing a storage volume */ -typedef struct _virStorageVol virStorageVol; +typedef struct _virItemCommon virStorageVol; Similar issue here - that virItemCommon should be changed to something like "virPoolElement"
/** * virStorageVolPtr: diff --git a/src/Makefile.am b/src/Makefile.am index 8ee5567..f8d4a5b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -170,7 +170,7 @@ UTIL_SOURCES = \ util/virstats.c util/virstats.h \ util/virstorageencryption.c util/virstorageencryption.h \ util/virstoragefile.c util/virstoragefile.h \ - util/virstring.h util/virstring.c \ + util/virstring.h util/virstring.c \ ?? Loss of whitespace?
util/virsysinfo.c util/virsysinfo.h \ util/virsystemd.c util/virsystemd.h \ util/virthread.c util/virthread.h \ @@ -185,7 +185,8 @@ UTIL_SOURCES = \ util/viruuid.c util/viruuid.h \ util/virxdrdefs.h \ util/virxml.c util/virxml.h \ - $(NULL) + util/virpoolcommon.h \
I think this should be util/virpool.h
+ $(NULL) The $(NULL) should line up properly
caveat emptor: I'm not a Makefile expert - not even close, but I would also think there would need to be rules to ensure proper rebuilds when/if virpool.h changes as well. Whatever depends upon it, such as STORAGE_CONF_SOURCES.
EXTRA_DIST += $(srcdir)/util/keymaps.csv $(srcdir)/util/virkeycode-mapgen.py
diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h index 185ae5e..8a9a789 100644 --- a/src/conf/storage_conf.h +++ b/src/conf/storage_conf.h
NB: Changes in here would be done after we settle on the common pool structures...
@@ -27,6 +27,7 @@ # include "internal.h" # include "virstorageencryption.h" # include "virstoragefile.h" +# include "virpoolcommon.h" # include "virbitmap.h" # include "virthread.h" # include "device_conf.h" @@ -58,7 +59,6 @@ struct _virStorageVolSource { * backend for partition type creation */ };
- Loss of whitespace
typedef struct _virStorageVolDef virStorageVolDef; typedef virStorageVolDef *virStorageVolDefPtr; struct _virStorageVolDef { @@ -73,6 +73,7 @@ struct _virStorageVolDef { virStorageSource target; };
+ Add of whitespace - it's just a consistency thing - it has nothing to do with the changes and IMO should not be done.
typedef struct _virStorageVolDefList virStorageVolDefList; typedef virStorageVolDefList *virStorageVolDefListPtr; struct _virStorageVolDefList { @@ -112,12 +113,8 @@ typedef enum { /* * For remote pools, info on how to reach the host */ -typedef struct _virStoragePoolSourceHost virStoragePoolSourceHost; +typedef virPoolSourceHost virStoragePoolSourceHost; typedef virStoragePoolSourceHost *virStoragePoolSourceHostPtr; -struct _virStoragePoolSourceHost { - char *name; - int port; -};
This would be common
/* @@ -142,127 +139,27 @@ struct _virStoragePoolSourceDeviceExtent { int type; /* virStorageFreeType */ };
-typedef struct _virStoragePoolSourceInitiatorAttr virStoragePoolSourceInitiatorAttr; -struct _virStoragePoolSourceInitiatorAttr { - char *iqn; /* Initiator IQN */ -}; -
I don't see this as common... It's SCSI pool specific
/* * Pools can be backed by one or more devices, and some * allow us to track free space on underlying devices. */ -typedef struct _virStoragePoolSourceDevice virStoragePoolSourceDevice; +typedef virPoolSourceDevice virStoragePoolSourceDevice; typedef virStoragePoolSourceDevice *virStoragePoolSourceDevicePtr; -struct _virStoragePoolSourceDevice { Not sure totally removing works - some of this data is storage specific, while other parts would be more common. See my thoughts at the bottom.
- int nfreeExtent; - virStoragePoolSourceDeviceExtentPtr freeExtents; - char *path; - int format; /* Pool specific source format */ - int part_separator; /* enum virTristateSwitch */ - - /* When the source device is a physical disk, - * the geometry data is needed - */ - struct _geometry { - int cylinders; - int heads; - int sectors; - } geometry; -}; BTW: I think you should make a storage_conf.h specific geometry structure as a separate patch prior to *any* other changes and send that patch.
eg. typedef struct _virStoragePoolGeometry virStoragePoolGeometry; typedef struct virStoragePoolGeometry *virStoragePoolGeometryPtr; struct _virStoragePoolGeometry { int cylinders; int heads; int sectors; };
... Then instead of _geometry inline:
virStoragePoolGeometry geometry;
-typedef enum { - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_DEFAULT = 0, - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST, - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST, - - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_LAST, -} virStoragePoolSourceAdapterType; -VIR_ENUM_DECL(virStoragePoolSourceAdapter) -
This is SCSI storage pool specific -typedef struct _virStoragePoolSourceAdapter virStoragePoolSourceAdapter; +typedef virPoolSourceAdapter virStoragePoolSourceAdapter; typedef virStoragePoolSourceAdapter *virStoragePoolSourceAdapterPtr; -struct _virStoragePoolSourceAdapter { - int type; /* virStoragePoolSourceAdapterType */ - - union { - struct { - char *name; - virPCIDeviceAddress parentaddr; /* host address */ - int unique_id; - bool has_parent; - } scsi_host; - struct { - char *parent; - char *wwnn; - char *wwpn; - int managed; /* enum virTristateSwitch */ - } fchost; - } data; -}; This is SCSI storage pool specific. scsi_host and fchost are _scsi backend specific constructs.
-typedef struct _virStoragePoolSource virStoragePoolSource; +typedef virPoolSource virStoragePoolSource; typedef virStoragePoolSource *virStoragePoolSourcePtr; -struct _virStoragePoolSource {
So some of this is storage specific and some could be considered common I suppose.
- /* An optional (maybe multiple) host(s) */ - size_t nhost; - virStoragePoolSourceHostPtr hosts; Common - a generic pool could have host elements
- - /* And either one or more devices ... */ - size_t ndevice; - virStoragePoolSourceDevicePtr devices; Common - a generic pool could have some sort of device elements
- - /* Or a directory */ - char *dir; Common
- - /* Or an adapter */ - virStoragePoolSourceAdapter adapter; Specific
- /* Or a name */ - char *name;
Common
- - /* Initiator IQN */ - virStoragePoolSourceInitiatorAttr initiator; Specific
- - /* Authentication information */ - virStorageAuthDefPtr auth; Common, but the name needs to change to something like "virPoolAuthDefPtr" (that could be a separate pre patch).
- - /* Vendor of the source */ - char *vendor; Common
- - /* Product name of the source*/ - char *product; Common
- - /* Pool type specific format such as filesystem type, - * or lvm version, etc. - */ - int format; This is actually specific to 4 pool types fs, netfs, disk, and logical For the fs/netfs it's the file system format type while for disk and logical it's the partition format type... I have more ideas at the end.
-}; And of course while reviewing this I saw something wrong in the formatstorage.html page... A storage pool doesn't have timestamps nor does it have encryption (<sigh> ... sent a patch to resolve).
- -typedef struct _virStoragePoolTarget virStoragePoolTarget; +typedef virPoolTarget virStoragePoolTarget; typedef virStoragePoolTarget *virStoragePoolTargetPtr; -struct _virStoragePoolTarget { - char *path; /* Optional local filesystem mapping */ - virStoragePerms perms; /* Default permissions for volumes */ -}; Looks like it could be common, although virStoragePerms could change to something like virPoolPathPerms. Also instead of moving it to virstoragefile.c - add it to the virpool common code with the adjusted name. I could see a "need" for a pool element to have some sort of permissions/label'ing required. Anything with a path...
-typedef struct _virStoragePoolDef virStoragePoolDef; +typedef virPoolDef virStoragePoolDef; typedef virStoragePoolDef *virStoragePoolDefPtr; -struct _virStoragePoolDef {
I think some of this is common while other parts are specific
- char *name; - unsigned char uuid[VIR_UUID_BUFLEN]; Definitely common
- int type; /* virStoragePoolType */ Is specific and common...
- - unsigned long long allocation; /* bytes */ - unsigned long long capacity; /* bytes */ - unsigned long long available; /* bytes */ Storage specific - could make some sort of structure to hold all 3 in order to share the data...
- - virStoragePoolSource source; - virStoragePoolTarget target; 'source' uses the adjusted struct above, while target should be able to be just common
-};
typedef struct _virStoragePoolObj virStoragePoolObj; typedef virStoragePoolObj *virStoragePoolObjPtr; - struct _virStoragePoolObj { virMutex lock;
@@ -272,9 +169,8 @@ struct _virStoragePoolObj { int autostart; unsigned int asyncjobs;
- virStoragePoolDefPtr def; - virStoragePoolDefPtr newDef; - + virPoolDefPtr def; + virPoolDefPtr newDef; After a few hours of reviewing and writing some comments, I came back to this change.... I think this is the magic place where things will get interesting...
If you "consider" _virStoragePoolObj to be common, you get "_virPoolObj" which would need to be defined in virpool.h. It would look a bit like:
struct _virPoolObj { virObjectLockable parent; virMutex lock;
virPoolDefPtr def; virPoolDefPtr newDef;
void *privateData; void (*privateDataFreeFunc)(void *); };
where the "privateData" in this case would be the "rest" of this virStoragePoolObj:
struct _virStoragePoolPrivateObj { char *configFile; char *autostartLink; bool active; int autostart; unsigned int asyncjobs; virStorageVolDefList volumes; };
at least for the block storage pool. It could be different for the FS storage... and even more different for anything else.
The key being - the virpool.c is managing the memory and calls to free come in the form of callbacks. It gets really confusing; however, the good news is I've recently done object creation in this manner in "virsecretobj", so I think that might be a good example for you to use. Although the secretobjs don't have the need (yet) for private data like you would for pools. You can look at the virDomainObj to see how it manages the privateData.
If this is just overload, let me know - I can help here. You'd just be gated on me creating the infrastructure. I think you can look at the rest of this, but with my new information - I'd have to rethink how much applies <sigh>.
virStorageVolDefList volumes; };
@@ -307,7 +203,7 @@ typedef virStoragePoolSourceList *virStoragePoolSourceListPtr; struct _virStoragePoolSourceList { int type; unsigned int nsources; - virStoragePoolSourcePtr sources; + virPoolSourcePtr sources; };
typedef bool (*virStoragePoolObjListFilter)(virConnectPtr conn, diff --git a/src/datatypes.h b/src/datatypes.h index 2b6adb4..1eaf4c6 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -561,7 +561,7 @@ struct _virInterface { * * Internal structure associated to a storage pool
s/storage//
IOW: This is an internal structure to describe a pool.
*/ -struct _virStoragePool { +struct _virPoolCommon { s/Common//
IOW: Just "_virPool {"
virObject object; virConnectPtr conn; /* pointer back to the connection */ char *name; /* the storage pool external name */ @@ -580,7 +580,7 @@ struct _virStoragePool { * * Internal structure associated to a storage volume
s/storage volume/pool element/
*/ -struct _virStorageVol { +struct _virItemCommon { Similar comments/issues, although I really don't like the "_virItem" as a name. How about "_virPoolElement"?
virObject object; virConnectPtr conn; /* pointer back to the connection */ char *pool; /* Pool name of owner */
Be careful to check comments of the structures - remove {S|s}torage and {V|v}vol[ume]
diff --git a/src/util/virpoolcommon.h b/src/util/virpoolcommon.h new file mode 100644 index 0000000..d54de36 --- /dev/null +++ b/src/util/virpoolcommon.h @@ -0,0 +1,166 @@ +/* + * virpoolcommon.h: utility to operate common parts in storage pools and + * filesystem pools Even better how about just a purely "common" pool format. Would initially be for storage pools, but eventually for the fspool. I also see a use for something else on the horizon - a graphics (vgpu) pool.
I also think this should just be virpool.h - the common would be a given.
+ * + * 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_POOL_COMMON_H__ +# define __VIR_POOL_COMMON_H__ Changing name to just virpool.h adjust the above macros too.
+ +# include "virstoragefile.h" But you wouldn't be including virstoragefile - that would be done elsewhere by code including this virpool.h that would also need virstoragefile.h
+# include "virthread.h" Why was this needed?
+# include "virpci.h" I think virpci.h won't be necessary either...
+ +/* + * For remote pools, info on how to reach the host + */ +typedef struct _virPoolSourceHost virPoolSourceHost; +typedef virPoolSourceHost *virPoolSourceHostPtr; +struct _virPoolSourceHost { + char *name; + int port; +}; + +/* + * Available extents on the underlying storage + */ +typedef struct _virPoolSourceDeviceExtent virPoolSourceDeviceExtent; +typedef virPoolSourceDeviceExtent *virPoolSourceDeviceExtentPtr; +struct _virPoolSourceDeviceExtent { + unsigned long long start; + unsigned long long end; + int type; /* virStorageFreeType */ +}; NB: The above hunk is block storage specific for the disk backend and thus wouldn't have/need a common structure.
+ +/* + * Pools can be backed by one or more devices, and some + * allow us to track free space on underlying devices. + */ +typedef struct _virPoolSourceDevice virPoolSourceDevice; +typedef virPoolSourceDevice *virPoolSourceDevicePtr; +struct _virPoolSourceDevice { So part of this *isn't* common, it's specific - you could create a common structure and then a block storage specific that includes the common parts
+ int nfreeExtent; + virPoolSourceDeviceExtentPtr freeExtents; The above two are Storage specific
+ char *path; + int format; /* Pool specific source format */ These would be common
+ int part_separator; /* enum virTristateSwitch */ + Very specific to a disk pool for *a* specific case as a result of multipath devices being able to use "user friendly names" or not.
+ /* When the source device is a physical disk, + * the geometry data is needed + */ + struct _geometry { + int cylinders; + int heads; + int sectors; + } geometry; +}; Specific to the disk pool.
+ +typedef enum { + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_DEFAULT = 0, + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST, + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST, + + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_LAST, +} virStoragePoolSourceAdapterType; +VIR_ENUM_DECL(virStoragePoolSourceAdapter) This would be SCSI storage pool specific and not for common file.
+ +typedef struct _virPoolSourceAdapter virPoolSourceAdapter; +typedef virPoolSourceAdapter *virPoolSourceAdapterPtr; +struct _virPoolSourceAdapter { + int type; /* virStoragePoolSourceAdapterType */ + + union { + struct { + char *name; + virPCIDeviceAddress parentaddr; /* host address */ + int unique_id; + bool has_parent; + } scsi_host; + struct { + char *parent; + char *wwnn; + char *wwpn; + int managed; /* enum virTristateSwitch */ + } fchost; + } data; +}; The above is SCSI storage specific.
+ +typedef struct _virPoolSourceInitiatorAttr virPoolSourceInitiatorAttr; +struct _virPoolSourceInitiatorAttr { + char *iqn; /* Initiator IQN */ +}; Same here, SCSI storage
+ +typedef struct _virPoolSource virPoolSource; +typedef virPoolSource *virPoolSourcePtr; +struct _virPoolSource { See my comment earlier regarding which is common and specific - this becomes the common stuff, but it's easier for me to just point out below all the structs, so see the end...
+ /* An optional (maybe multiple) host(s) */ + size_t nhost; + virPoolSourceHostPtr hosts; + + /* And either one or more devices ... */ + size_t ndevice; + virPoolSourceDevicePtr devices; + + /* Or a directory */ + char *dir; + + /* Or an adapter */ + virPoolSourceAdapter adapter; + + /* Or a name */ + char *name; + + /* Initiator IQN */ + virPoolSourceInitiatorAttr initiator; + + /* Authentication information */ + virStorageAuthDefPtr auth; + + /* Vendor of the source */ + char *vendor; + + /* Product name of the source*/ + char *product; + + /* Pool type specific format such as filesystem type, + * or lvm version, etc. + */ + int format; +}; + +typedef struct _virPoolTarget virPoolTarget; +typedef virPoolTarget *virPoolTargetPtr; +struct _virPoolTarget { + char *path; /* Optional local filesystem mapping */ + virStoragePerms perms; /* Default permissions for volumes/items */ +}; This seems generic, although the comments need some tweaking to be more generic. A 'path' to the pool target... The virStoragePerms could become virPoolPathPerms with the virStoragePerms struct being your guide.
+ +typedef struct _virPoolDef virPoolDef; +typedef virPoolDef *virPoolDefPtr; +struct _virPoolDef { + char *name; + unsigned char uuid[VIR_UUID_BUFLEN]; + int type; /* virStoragePoolType */ s/Storage//
I'm conflicted over how to use type... and of course there would need to be a virPoolType list which would initially just be "BLOCK_STORAGE", but would eventually have "FILESYSTEM_STORAGE" (and down the road VGPU_DEVICES).
+ + unsigned long long allocation; /* bytes */ + unsigned long long capacity; /* bytes */ + unsigned long long available; /* bytes */ + These would be "storage" related, but less so common type data. They're all "sizing" elements and could also be their own storage specific structure.
+ virPoolSource source; + virPoolTarget target; +}; +# endif /* __VIR_POOL_COMMON_H__ */
What follows is my thoughts for various structures. I would think you have it fresh in your mind where the exact overlap is.
These would be "virpool.h" type structures (left out some details):
typedef enum { VIR_POOL_BLOCK_STORAGE,
VIR_POOL_LAST, } virPoolType;
struct _virPoolDef { int type; /* virPoolType */ char *name; unsigned char uuid[VIR_UUID_BUFLEN]; virPoolSource source; virPoolTarget target; };
BTW: I'm conflicted over the virPoolType since I'm not sure how it would be used other than to save it. We cannot use the virStoragePoolType enum's because those would be specific to the block storage pool... I'd suspect that FS
struct _virPoolSource { /* One or more host definitions */ size_t nhost; virPoolSourceHostPtr hosts;
/* Authentication information */ virStorageAuthDefPtr auth;
/* One or more devices */ size_t nsrcpath; virPoolSourcePathPtr srcpaths;
/* Name of the source */ char *name;
/* Vendor of the source */ char *vendor;
/* Product name of the source */ char *product; };
typedef enum { VIR_POOL_SOURCE_DIR, VIR_POOL_SOURCE_DEVICE, VIR_POOL_SOURCE_NAME,
VIR_POOL_LAST, } virPoolSourcePathType;
struct _virPoolSourcePath { virPoolSourcePathType sourcetype; char *path; };
NB: Turns out 'logical' can have both 'device' and 'name', but "name" ends up being something we can add to a logical specific structure. Also 'gluster' can have both 'dir' and 'name', but it seems name is primary when both are used (see tests/*xmlin/*pool*gluster*.xml).
Still the key is they are all paths of some sort:
<dir path='$PATH'> <device path='$PATH'>
where <device> it could be a path to a BLOCK device (/dev/) or it could be an iSCSI initiator string (and thus SOURCE_NAME being used...). Search on "<dir" or "<device" in tests/*xmlin/*pool*.xml
struct _virPoolSourceHost { char *name; int port; };
struct _virPoolAuthDef { char *username; char *secrettype; /* <secret type='%s' for disk source */ int authType; /* virStorageAuthType */ virSecretLookupTypeDef seclookupdef; };
struct _virPoolTarget { char *path; /* Optional path to target */ virPoolPathPerms perms; /* Default permissions for path */ };
struct _virPoolPathPerms { mode_t mode; uid_t uid; gid_t gid; char *label; }
Below here would be storage_conf.h type adjustments:
struct _virStoragePoolDef { virPoolDef pool; virStoragePoolType storagetype;
virStoragePoolSizes size;
/* Based on storagetype, a subdata could be allocated to have/save * storagetype specific data */ void *subdata; /* vir*StoragePoolDefPtr */
/* In order to make life easy - format will be defined here * although it's only used by the some pools (fs, netfs, * disk, and logical via virStoragePoolFormat* enums */ int format; /* virStoragePoolFormat* */ };
struct _virStoragePoolSizes { unsigned long long allocation; /* bytes */ unsigned long long capacity; /* bytes */ unsigned long long available; /* bytes */ };
struct _virSCSIStoragePoolDef { virStoragePoolSourceAdapter adapter; virStoragePoolSourceInitiatorAttr initiator; };
struct _virDiskStoragePoolDef { int nfreeExtent; virDiskStoragePoolDeviceExtentPtr freeExtents; virStoragePoolGeometry geometry; int part_separator; /* enum virTristateSwitch */ };
struct _virDiskStoragePoolDeviceExtent { unsigned long long start; unsigned long long end; int type; /* virStorageFreeType */ };
NB: Gluster wouldn't need a pool specific data - it would just use the "name" and "dir" separately. Also, I think there's other patches that will want to have multiple gluster paths, so this (more or less) allows for that.
I probably left out some structures, but I hope this makes sense... Yes, it's going to be painful to make the switchover. That's why I suggest taking it slowly and not trying to pile on all the FSPool changes along.
John
-- Best regards, Olga

On 20/12/16 20:18, John Ferlan wrote:
On 12/15/2016 12:16 PM, Olga Krishtal wrote:
Hi, John. I needed some time to think over everything that you have written. Thanks a lot. Yeah - I got too wordy, but this type of change caused me to think about other possible consumers too.
With all this new information we have more freedom for changes and refactoring. Like I thought I mentioned - this set of changes seem to have gone too far in the direction of common code. Of course the original set of changes was too much cut-n-paste for my taste. There has to be a happy medium - that's what we need to find. I usually do that by figuring out what I'll need, creating generic structs/code and slowly moving things. Even if the generic structs start in the specific code - they can be moved. I would think at this point you know what you eventually need in the fspool driver - so that's where to start.
I dig through storage_conf.h file once with all ideas you have and tried to use them. It would be easier for me if we agree about virpool structs. The other changes depends on it. Sure to a degree. Some of this ends up being trial and error... or prototyping some changes to see what will and won't work. Trying to do this conceptually in email is difficult too, especially with other things going on. Again, create smaller patches that have the end goal.
Some moments are left unclear to me, so I have written down virpool.h with comments and questions. If you agree, please write Ok or smth else. After sending I kept thinking about things "in the background". I took a pass at trying to extract/abstract just the pool concept and suffice to say it's a bit overwhelming. It's possible - it just has to be done carefully.
Essentially though if you take the concept of a PoolObj to a different level of abstraction - it's a very common thing - there are domain, network, secret, storage, etc. that all use the objects code to build up a list or hash table of objects that point at 'def' data.
In any case at this time I don't think that level of abstraction would be necessary for what you're trying to accomplish. And if I do come up with something - I would hope it'll be easy to merge in what you have.
/* Pool element description */ Lets use PoolUnit instead PoolElement: Not a fan of Unit... This could just be _virPoolDef while the consumer of this would be _virStorageBlockPoolDef and _virStorageFSPoolDef.
No - this is not a pool definition, but the definition of the pool's part.
typedef struct _virPoolUnitDef virPoolUnitDef; typedef virPoolUnitDef *virPoolUnitDefPtr; struct _virPoolUnitDef { char *name; char *key; bool building; unsigned int in_use;
void* UnitTypeDef /* the same as privateData for virConnectPtr. Stores internal information about pool unit */ };
Why *name in both PoolUnitDef and PoolDef?
I think uuid should be here.
In here it is char *key; field.
There should be a 'voltype' field here... Changing the name will dig out code that's using it.
Why voltype there is no volume. I do not see how we can set voltype without knowledge what kind of object we store in pool.
As I found with the 'virStorageSource' "type" field there were a couple of source.target.type field users where source.target.type is not filled in. I have some patches to address that in a branch, but I'm waiting on other reviews to be completed before posting.
Not sure I like UnitTypeDef - the common usage is privateData. Oh and you'd need a "void (*privateDataFreeFunc)(void *);".
Might also need a few more things, but seems to be a good start.
Eg, 3 fields from virStorageVolDef: int type; virStorageVolSource source; virStorageSource target;
typedef struct _virPoolUnitDefList virPoolUnitDefList; typedef virPoolUnitDefList *virPoolUnitDefListPtr; struct _virPoolUnitDefList { size_t count; virPoolUnitDefPtr *obj };
I don't think *List is the way to go, but since that's the model today - we can stick with it until I can work up something better. Lists work well when there's 1-10 elements on the List, but as more elements are added the search times exponentially increase.
Ok. Let's implement lists and and all changes that is necessary for storage pools to work with the new pool object. But I will think about it and may be later we change it . But it easier to start with it. So in virpool.h we will have some bricks to describe common parts, and Storage/FS structs will look like: struct virStorageBlockPoolDef { virPoolDefPtr poolDef; some structs to describe storage } The same is for virStorageFSPool. In this case we do not need to describe precisely pool element. Moreover, we will have API to manage common pool parts, and I think the changes won't be that huge. I think I will send rfc of virpool.h/c separately rather keeping discussion over here, but will leave links to this conversation.
I think HashTable's are the better option (Domains, Secrets, Networks, and DomainSnapshot use them). See the virDomainObjList for a model.
In any case, why are there voldefs in a list? Is this some sort of backing store listing for the same volume object? Or was this meant to be the volume object list?
/* General information about pool source */
Why do we need this information in general part for pool of any kind? This structure manages how a domain views the storage. It is quite confusing and you have to pay close attention to the usage.
As I understand this structure is used when storage is remote or I am missing smth? Yes, this is essentially for remote/network storage typedef struct _virPoolSourceHost virPoolSourceHost; typedef virPoolSourceHost *virPoolSourceHostPtr; struct _virPoolSourceHost { char *name; int port;
}; For purposes of what you're trying to accomplish - it can be block storage specific unless you feel fspools would/could use NFS or would have their own need for a network structure.
I think it should be somewhere in private part, because you have mentioned some other type of pool - vGPU, are you sure that authorization will be the same? A vGPU would be something local and shouldn't need auth. A vGPU is something new dealing with graphics where there will be a need to have a pool of vGPU's to choose from much the same way there is storage.
Otherwise, what is virPoolAuth for general pool description?
typedef struct _virPoolAuthDef virPoolAuthDef; typedef virPoolAuthDef *virPoolAuthDefPtr; struct _virPoolAuthDef { char *username; char *secrettype; /* <secret type='%s' for disk source */ int authType; /* virStorageAuthType */ virSecretLookupTypeDef seclookupdef; }; secrets are usually associated with remote storage; however, they're also something for local only as evidenced by the LUKS encryption secret.
We could start as a private thing, but it could be moved as well. Again, depends on the implementation. Of course I've got the vzstorage pool concepts floating in and out of consciousness - tough to focus on one over the other!
typedef enum {
VIR_POOL_SOURCE_DIR, VIR_POOL_SOURCE_DEVICE,
VIR_POOL_SOURCE_NAME,
VIR_POOL_LAST, }
typedef struct _virPoolSourcePath virPoolSourcePath; typedef virPoolSourcePath *virPoolSourcePathPtr; struct _virPoolSourcePath { virPoolSourcePathType sourcetype; char *path; };
typedef struct _virPoolSource virPoolSource; typedef virPoolSource *virPoolSourcePtr; struct _virPoolSource{ /* One or more host definitions */ size_t nhost; virPoolSourceHostPtr hosts;
/* Authentication information */ virPoolAuthDefPtr auth; /*Not sure about it. We need authorization */ /* when we have to authorize in storage, but in Pool? */ /* One or more devices */ size_t nsrcpath; virPoolSourcePathPtr srcpaths;
/* Name of the source */ May be we can use it for device name like in virPoolSourcePath char *name;
/* Vendor of the source */ char *vendor;
/* Product name of the source */ char *product; };
I have come to realize that mucking in virStorageSource I think is going to require a the structure to become private with a bunch of accessors to fields. Too much code today knows the structure and makes use of it. I started working through doing something like that as a result of other changes I've been posting related to storage source data. The biggest offender in peeking at the StorageSource is the path to the storage.
typedef struct _virPoolPathPerms virPoolPathPerms; typedef virPoolPathPerms *virPoolPathPermsPtr; struct _virPoolPathPerms { mode_t mode; uid_t uid; gid_t gid; char *label; }
typedef struct _virPoolTarget virPoolTarget; typedef virPoolTarget *virPoolTargetPtr; struct _virPoolTarget{ What will be general description for path field? char *path; /* Optional path to target */ virPoolPathPerms perms; /* Default permissions for path */ }; http://libvirt.org/formatstorage.html
Target elements, path.
There are virStorageSource fields that aren't used for 'target' storage... But there's virStorageSourcePtr used for backingStore... You have to follow code paths to understand usage.
typedef struct _virPoolDef virPoolDef; typedef virPoolDef *virPoolDefPtr; struct _virPoolDef { char *name; unsigned char uuid[VIR_UUID_BUFLEN];
virPoolSource source; virPoolTarget target; };
typedef struct _virPoolObj virPoolObj; typedef virPoolObj *virPoolObjPtr; struct _virPoolObj { virMutex lock; ^^ Should use the virObjectLockable object... Yes requires some 'other' adjustments...
char *configFile; char *autostartLink; bool active; int autostart; unsigned int asyncjobs;
virPoolDefPtr def; virPoolDefPtr newDef;
virPoolUnitDefList elements;
you'd have to call this 'units' instead of 'elements', which is why I said "Elements" at first.
};
typedef struct _virPoolObjList virPoolObjList; typedef virPoolObjList *virPoolObjListPtr; struct _virPoolObjList { size_t count; virPoolObjPtr *objs; }; Again, a hash table will be better...
I think there's perhaps :
_virPoolDef -> Common pool definition with private data pointers _virStorageBlockPoolDef -> Consumer of _virPoolDef as private data _virStorageFSPoolDef -> Consumer of _virPoolDef as private data
_virPoolObj -> Common pool object with private data pointer _virStorageBlockPoolObj -> Consumer of _virPoolObj private data _virStorageFSPoolObj -> Consumer of _virPoolObj
_virPoolObjList-> Common pool object list manipulation and search API
I see no need (yet) for a StorageBlock or StoragePool object list. The ObjList is a table of objects with common reference/lookup functions. The tricky part there is the filtering API's currently used for various lookup APIs in order to pull out specific "types" of objects.
The PoolObj some common stuff (def, newdef, some flags, locking) as well as a privateData for specific stuff. It would also have a 'def' that could describe the common lookup of uuid/name.
The PoolDef is mostly private just to allow for easier lookups - that would copy the 'def' uuid/name fields
And some of functions prototype: void virPoolSourceClear(virPoolSourcePtr source); void virPoolSourceFree(virPoolSourcePtr source); void virPoolDefFree(virPoolDefPtr def); void virPoolObjFree(virPoolObjPtr pool); void virPoolObjListFree(virPoolObjListPtr pools); void virPoolObjRemove(virPoolObjListPtr pools, virPoolObjPtr pool); void virPoolObjLock(virPoolObjPtr obj); void virPoolObjUnlock(virPoolObjPtr obj); FWIW: At the higher abstraction level the driver (StoragePool) is responsible to managing some sort of list or table of objects. Using cscope's egrep search capabilities - "^struct vir.*ObjList" returns 8 such instances. Of those 4 use a counted list (Interface, NodeDevice, NWFilter, StoragePool) and 4 use a hash table (Network, DomainSnapshot, Domain, Secret).
Each ObjList would manage the _vir*Obj element corresponding to it (cscope egrep "^struct vir.*Obj {". Each of those Objects has commonality (parent/lock, def, newDef, state bits, privateData, privateDataFreeFunc).
For example, search on consumers of "*ObjListNew()" type calls or anything that could be found by a cscope egrep of "^struct vir.*ObjList". There's quite a bit of cut-n-paste there.
In any case, the previous 3 paragraphs are something on my radar, but I figured I'd share...
On 12/02/2016 10:38 AM, Olga Krishtal wrote:
This is the first patch in fspool patchest. FSPool and storage pools has a lot in common, however we want to have separate drivers for its managment.
We want to use almost all storage pool descriptional structures for filesystem pool. All common structs is moved to virpoolcommon.h
More simply stated - for what's going to be I think a bit more complex than originally thought... The changes would be extracting out common pool mgmt code into their own API's so that they can be used by future patches (eg. the File System Storage Driver).
Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- include/libvirt/libvirt-storage.h | 5 +- src/Makefile.am | 5 +- src/conf/storage_conf.h | 126 +++-------------------------- src/datatypes.h | 4 +- src/util/virpoolcommon.h | 166 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 184 insertions(+), 122 deletions(-) create mode 100644 src/util/virpoolcommon.h
Patch fails "make syntax-check"
preprocessor_indentation cppi: src/util/virpoolcommon.h: line 166: not properly indented maint.mk: incorrect preprocessor indentation cfg.mk:684: recipe for target 'sc_preprocessor_indentation' failed make: *** [sc_preprocessor_indentation] Error 1
Which is the last "# endif" in the file. Now I see, it is cppi that fails. I guess I did not have this test installed. That is the problem that I always have! May be all others failures with syntax-check is because of it. Yeah - there's stuff I've found along the way like this too... Usually when something like this is discovered we try to make sure there's some sort of requirement added into the build system so that everyone would see the issue and not just those that have already tripped across it. I
On 08/12/16 02:43, John Ferlan wrote: think that's where those Requires/BuildRequires come from - been a while since I thought about it though.
...
First and most important, thanks for taking this on - it's going to be bumpy, but I think if we take it piece by piece that will be better in the long run. Also on the horizon is a need for a common pool structure for vGPU's - I think Laine will find having a common pool structure quite helpful for that work.
While I understand why you're providing all the patches, I'm going to only focus on the first three for now. I'd prefer to agree on the infrastructure first, then add the fspool code. Hopefully that makes the mean time between patch series shorter, too.
I see the first few patches as a means to create a common pool infrastructure. I think this is the right path, although I think you swung too far in that direction with what you've done.
The new nomenclature doesn't need the "common" in the name/structures either. It's just "virpool.h" and "virpool.c" and it manages structures commonly used for pools. Currently it's just the block storage driver that needs it, but you're adding fspool which will be a file system storage driver.
Just the first couple of patches have spawned off a few more ideas and a few "pre" patches... I really think it would be better to create the new structures and API's in one patch. Just keep track of wh
This patch definitely can be further split... I think if you copy/paste code from one place to another and rename functions, fix comments, etc. and essentially set up the common pool code, then subsequent patches would just remove code. You can always note in the commit message where code was sourced from...
Also remember, you're trying to hit a moving target. The storage pool/volume code is constantly changing - if you try to do everything at once there's bound to be conflicts. I already of some with what's here and in the subsequent patches. I also have other commitments so larger series will languish ;-) - reviews can take considerable time.
diff --git a/include/libvirt/libvirt-storage.h b/include/libvirt/libvirt-storage.h index 0974f6e..8572685 100644 --- a/include/libvirt/libvirt-storage.h +++ b/include/libvirt/libvirt-storage.h You need to be very careful with changes here. The problem being existing code that may rely on _virStoragePool or _virStorageVol. We can always add, but it's the change that causes issues. That's why stuff got moved into datatypes.h because that's not the external API.
In any case, there is an example - search on virBlkioParameter
@@ -34,7 +34,7 @@ * * a virStoragePool is a private structure representing a storage pool */ -typedef struct _virStoragePool virStoragePool; +typedef struct _virPoolCommon virStoragePool; I think it would be just _virPool, but, what you have won't work. I believe you'd need something like:
/* As of 3.x.x the _virPool was introduced to generalize a block * storage pool. This allows for backwards compatibility. */ # define _virStoragePool _virPool typedef struct _virPool virStoragePool
That way anything that has _virStoragePool will/should do the right thing... I see. I was not quite sure that everyone will agree to accept such change. So I decided to use virStoragePool as a base and to have a union in case fspools will need smth specific. But if it is OK. That I am totally in.
The point I was making is changing from _virStoragePool to _virPoolCommon won't necessary fly without the ability to have some sort of definition. The usage of "_virPool" instead of "_virCommonPool" is my nomenclature. The example I referenced is how BlkioParameter did the changeover.
I think it will work fine, but the details are something that are only known once someone jumps into the pool and starts swimming or sinking (a metaphor for the heap of trouble you get yourself into once you start actually coding things).
John
/** * virStoragePoolPtr: @@ -44,7 +44,6 @@ typedef struct _virStoragePool virStoragePool; */ typedef virStoragePool *virStoragePoolPtr;
-
Unnecessary whitespace adjustment.
typedef enum { VIR_STORAGE_POOL_INACTIVE = 0, /* Not running */ VIR_STORAGE_POOL_BUILDING = 1, /* Initializing pool, not available */ @@ -104,7 +103,7 @@ typedef virStoragePoolInfo *virStoragePoolInfoPtr; * * a virStorageVol is a private structure representing a storage volume */ -typedef struct _virStorageVol virStorageVol; +typedef struct _virItemCommon virStorageVol; Similar issue here - that virItemCommon should be changed to something like "virPoolElement"
/** * virStorageVolPtr: diff --git a/src/Makefile.am b/src/Makefile.am index 8ee5567..f8d4a5b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -170,7 +170,7 @@ UTIL_SOURCES = \ util/virstats.c util/virstats.h \ util/virstorageencryption.c util/virstorageencryption.h \ util/virstoragefile.c util/virstoragefile.h \ - util/virstring.h util/virstring.c \ + util/virstring.h util/virstring.c \ ?? Loss of whitespace?
util/virsysinfo.c util/virsysinfo.h \ util/virsystemd.c util/virsystemd.h \ util/virthread.c util/virthread.h \ @@ -185,7 +185,8 @@ UTIL_SOURCES = \ util/viruuid.c util/viruuid.h \ util/virxdrdefs.h \ util/virxml.c util/virxml.h \ - $(NULL) + util/virpoolcommon.h \
I think this should be util/virpool.h
+ $(NULL) The $(NULL) should line up properly
caveat emptor: I'm not a Makefile expert - not even close, but I would also think there would need to be rules to ensure proper rebuilds when/if virpool.h changes as well. Whatever depends upon it, such as STORAGE_CONF_SOURCES.
EXTRA_DIST += $(srcdir)/util/keymaps.csv $(srcdir)/util/virkeycode-mapgen.py
diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h index 185ae5e..8a9a789 100644 --- a/src/conf/storage_conf.h +++ b/src/conf/storage_conf.h
NB: Changes in here would be done after we settle on the common pool structures...
@@ -27,6 +27,7 @@ # include "internal.h" # include "virstorageencryption.h" # include "virstoragefile.h" +# include "virpoolcommon.h" # include "virbitmap.h" # include "virthread.h" # include "device_conf.h" @@ -58,7 +59,6 @@ struct _virStorageVolSource { * backend for partition type creation */ };
- Loss of whitespace
typedef struct _virStorageVolDef virStorageVolDef; typedef virStorageVolDef *virStorageVolDefPtr; struct _virStorageVolDef { @@ -73,6 +73,7 @@ struct _virStorageVolDef { virStorageSource target; };
+ Add of whitespace - it's just a consistency thing - it has nothing to do with the changes and IMO should not be done.
typedef struct _virStorageVolDefList virStorageVolDefList; typedef virStorageVolDefList *virStorageVolDefListPtr; struct _virStorageVolDefList { @@ -112,12 +113,8 @@ typedef enum { /* * For remote pools, info on how to reach the host */ -typedef struct _virStoragePoolSourceHost virStoragePoolSourceHost; +typedef virPoolSourceHost virStoragePoolSourceHost; typedef virStoragePoolSourceHost *virStoragePoolSourceHostPtr; -struct _virStoragePoolSourceHost { - char *name; - int port; -};
This would be common
/* @@ -142,127 +139,27 @@ struct _virStoragePoolSourceDeviceExtent { int type; /* virStorageFreeType */ };
-typedef struct _virStoragePoolSourceInitiatorAttr virStoragePoolSourceInitiatorAttr; -struct _virStoragePoolSourceInitiatorAttr { - char *iqn; /* Initiator IQN */ -}; -
I don't see this as common... It's SCSI pool specific
/* * Pools can be backed by one or more devices, and some * allow us to track free space on underlying devices. */ -typedef struct _virStoragePoolSourceDevice virStoragePoolSourceDevice; +typedef virPoolSourceDevice virStoragePoolSourceDevice; typedef virStoragePoolSourceDevice *virStoragePoolSourceDevicePtr; -struct _virStoragePoolSourceDevice { Not sure totally removing works - some of this data is storage specific, while other parts would be more common. See my thoughts at the bottom.
- int nfreeExtent; - virStoragePoolSourceDeviceExtentPtr freeExtents; - char *path; - int format; /* Pool specific source format */ - int part_separator; /* enum virTristateSwitch */ - - /* When the source device is a physical disk, - * the geometry data is needed - */ - struct _geometry { - int cylinders; - int heads; - int sectors; - } geometry; -}; BTW: I think you should make a storage_conf.h specific geometry structure as a separate patch prior to *any* other changes and send that patch.
eg. typedef struct _virStoragePoolGeometry virStoragePoolGeometry; typedef struct virStoragePoolGeometry *virStoragePoolGeometryPtr; struct _virStoragePoolGeometry { int cylinders; int heads; int sectors; };
... Then instead of _geometry inline:
virStoragePoolGeometry geometry;
-typedef enum { - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_DEFAULT = 0, - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST, - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST, - - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_LAST, -} virStoragePoolSourceAdapterType; -VIR_ENUM_DECL(virStoragePoolSourceAdapter) -
This is SCSI storage pool specific -typedef struct _virStoragePoolSourceAdapter virStoragePoolSourceAdapter; +typedef virPoolSourceAdapter virStoragePoolSourceAdapter; typedef virStoragePoolSourceAdapter *virStoragePoolSourceAdapterPtr; -struct _virStoragePoolSourceAdapter { - int type; /* virStoragePoolSourceAdapterType */ - - union { - struct { - char *name; - virPCIDeviceAddress parentaddr; /* host address */ - int unique_id; - bool has_parent; - } scsi_host; - struct { - char *parent; - char *wwnn; - char *wwpn; - int managed; /* enum virTristateSwitch */ - } fchost; - } data; -}; This is SCSI storage pool specific. scsi_host and fchost are _scsi backend specific constructs.
-typedef struct _virStoragePoolSource virStoragePoolSource; +typedef virPoolSource virStoragePoolSource; typedef virStoragePoolSource *virStoragePoolSourcePtr; -struct _virStoragePoolSource {
So some of this is storage specific and some could be considered common I suppose.
- /* An optional (maybe multiple) host(s) */ - size_t nhost; - virStoragePoolSourceHostPtr hosts; Common - a generic pool could have host elements
- - /* And either one or more devices ... */ - size_t ndevice; - virStoragePoolSourceDevicePtr devices; Common - a generic pool could have some sort of device elements
- - /* Or a directory */ - char *dir; Common
- - /* Or an adapter */ - virStoragePoolSourceAdapter adapter; Specific
- /* Or a name */ - char *name;
Common
- - /* Initiator IQN */ - virStoragePoolSourceInitiatorAttr initiator; Specific
- - /* Authentication information */ - virStorageAuthDefPtr auth; Common, but the name needs to change to something like "virPoolAuthDefPtr" (that could be a separate pre patch).
- - /* Vendor of the source */ - char *vendor; Common
- - /* Product name of the source*/ - char *product; Common
- - /* Pool type specific format such as filesystem type, - * or lvm version, etc. - */ - int format; This is actually specific to 4 pool types fs, netfs, disk, and logical For the fs/netfs it's the file system format type while for disk and logical it's the partition format type... I have more ideas at the end.
-}; And of course while reviewing this I saw something wrong in the formatstorage.html page... A storage pool doesn't have timestamps nor does it have encryption (<sigh> ... sent a patch to resolve).
- -typedef struct _virStoragePoolTarget virStoragePoolTarget; +typedef virPoolTarget virStoragePoolTarget; typedef virStoragePoolTarget *virStoragePoolTargetPtr; -struct _virStoragePoolTarget { - char *path; /* Optional local filesystem mapping */ - virStoragePerms perms; /* Default permissions for volumes */ -}; Looks like it could be common, although virStoragePerms could change to something like virPoolPathPerms. Also instead of moving it to virstoragefile.c - add it to the virpool common code with the adjusted name. I could see a "need" for a pool element to have some sort of permissions/label'ing required. Anything with a path...
-typedef struct _virStoragePoolDef virStoragePoolDef; +typedef virPoolDef virStoragePoolDef; typedef virStoragePoolDef *virStoragePoolDefPtr; -struct _virStoragePoolDef {
I think some of this is common while other parts are specific
- char *name; - unsigned char uuid[VIR_UUID_BUFLEN]; Definitely common
- int type; /* virStoragePoolType */ Is specific and common...
- - unsigned long long allocation; /* bytes */ - unsigned long long capacity; /* bytes */ - unsigned long long available; /* bytes */ Storage specific - could make some sort of structure to hold all 3 in order to share the data...
- - virStoragePoolSource source; - virStoragePoolTarget target; 'source' uses the adjusted struct above, while target should be able to be just common
-};
typedef struct _virStoragePoolObj virStoragePoolObj; typedef virStoragePoolObj *virStoragePoolObjPtr; - struct _virStoragePoolObj { virMutex lock;
@@ -272,9 +169,8 @@ struct _virStoragePoolObj { int autostart; unsigned int asyncjobs;
- virStoragePoolDefPtr def; - virStoragePoolDefPtr newDef; - + virPoolDefPtr def; + virPoolDefPtr newDef; After a few hours of reviewing and writing some comments, I came back to this change.... I think this is the magic place where things will get interesting...
If you "consider" _virStoragePoolObj to be common, you get "_virPoolObj" which would need to be defined in virpool.h. It would look a bit like:
struct _virPoolObj { virObjectLockable parent; virMutex lock;
virPoolDefPtr def; virPoolDefPtr newDef;
void *privateData; void (*privateDataFreeFunc)(void *); };
where the "privateData" in this case would be the "rest" of this virStoragePoolObj:
struct _virStoragePoolPrivateObj { char *configFile; char *autostartLink; bool active; int autostart; unsigned int asyncjobs; virStorageVolDefList volumes; };
at least for the block storage pool. It could be different for the FS storage... and even more different for anything else.
The key being - the virpool.c is managing the memory and calls to free come in the form of callbacks. It gets really confusing; however, the good news is I've recently done object creation in this manner in "virsecretobj", so I think that might be a good example for you to use. Although the secretobjs don't have the need (yet) for private data like you would for pools. You can look at the virDomainObj to see how it manages the privateData.
If this is just overload, let me know - I can help here. You'd just be gated on me creating the infrastructure. I think you can look at the rest of this, but with my new information - I'd have to rethink how much applies <sigh>.
virStorageVolDefList volumes; };
@@ -307,7 +203,7 @@ typedef virStoragePoolSourceList *virStoragePoolSourceListPtr; struct _virStoragePoolSourceList { int type; unsigned int nsources; - virStoragePoolSourcePtr sources; + virPoolSourcePtr sources; };
typedef bool (*virStoragePoolObjListFilter)(virConnectPtr conn, diff --git a/src/datatypes.h b/src/datatypes.h index 2b6adb4..1eaf4c6 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -561,7 +561,7 @@ struct _virInterface { * * Internal structure associated to a storage pool
s/storage//
IOW: This is an internal structure to describe a pool.
*/ -struct _virStoragePool { +struct _virPoolCommon { s/Common//
IOW: Just "_virPool {"
virObject object; virConnectPtr conn; /* pointer back to the connection */ char *name; /* the storage pool external name */ @@ -580,7 +580,7 @@ struct _virStoragePool { * * Internal structure associated to a storage volume
s/storage volume/pool element/
*/ -struct _virStorageVol { +struct _virItemCommon { Similar comments/issues, although I really don't like the "_virItem" as a name. How about "_virPoolElement"?
virObject object; virConnectPtr conn; /* pointer back to the connection */ char *pool; /* Pool name of owner */
Be careful to check comments of the structures - remove {S|s}torage and {V|v}vol[ume]
diff --git a/src/util/virpoolcommon.h b/src/util/virpoolcommon.h new file mode 100644 index 0000000..d54de36 --- /dev/null +++ b/src/util/virpoolcommon.h @@ -0,0 +1,166 @@ +/* + * virpoolcommon.h: utility to operate common parts in storage pools and + * filesystem pools Even better how about just a purely "common" pool format. Would initially be for storage pools, but eventually for the fspool. I also see a use for something else on the horizon - a graphics (vgpu) pool.
I also think this should just be virpool.h - the common would be a given.
+ * + * 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_POOL_COMMON_H__ +# define __VIR_POOL_COMMON_H__ Changing name to just virpool.h adjust the above macros too.
+ +# include "virstoragefile.h" But you wouldn't be including virstoragefile - that would be done elsewhere by code including this virpool.h that would also need virstoragefile.h
+# include "virthread.h" Why was this needed?
+# include "virpci.h" I think virpci.h won't be necessary either...
+ +/* + * For remote pools, info on how to reach the host + */ +typedef struct _virPoolSourceHost virPoolSourceHost; +typedef virPoolSourceHost *virPoolSourceHostPtr; +struct _virPoolSourceHost { + char *name; + int port; +}; + +/* + * Available extents on the underlying storage + */ +typedef struct _virPoolSourceDeviceExtent virPoolSourceDeviceExtent; +typedef virPoolSourceDeviceExtent *virPoolSourceDeviceExtentPtr; +struct _virPoolSourceDeviceExtent { + unsigned long long start; + unsigned long long end; + int type; /* virStorageFreeType */ +}; NB: The above hunk is block storage specific for the disk backend and thus wouldn't have/need a common structure.
+ +/* + * Pools can be backed by one or more devices, and some + * allow us to track free space on underlying devices. + */ +typedef struct _virPoolSourceDevice virPoolSourceDevice; +typedef virPoolSourceDevice *virPoolSourceDevicePtr; +struct _virPoolSourceDevice { So part of this *isn't* common, it's specific - you could create a common structure and then a block storage specific that includes the common parts
+ int nfreeExtent; + virPoolSourceDeviceExtentPtr freeExtents; The above two are Storage specific
+ char *path; + int format; /* Pool specific source format */ These would be common
+ int part_separator; /* enum virTristateSwitch */ + Very specific to a disk pool for *a* specific case as a result of multipath devices being able to use "user friendly names" or not.
+ /* When the source device is a physical disk, + * the geometry data is needed + */ + struct _geometry { + int cylinders; + int heads; + int sectors; + } geometry; +}; Specific to the disk pool.
+ +typedef enum { + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_DEFAULT = 0, + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST, + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST, + + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_LAST, +} virStoragePoolSourceAdapterType; +VIR_ENUM_DECL(virStoragePoolSourceAdapter) This would be SCSI storage pool specific and not for common file.
+ +typedef struct _virPoolSourceAdapter virPoolSourceAdapter; +typedef virPoolSourceAdapter *virPoolSourceAdapterPtr; +struct _virPoolSourceAdapter { + int type; /* virStoragePoolSourceAdapterType */ + + union { + struct { + char *name; + virPCIDeviceAddress parentaddr; /* host address */ + int unique_id; + bool has_parent; + } scsi_host; + struct { + char *parent; + char *wwnn; + char *wwpn; + int managed; /* enum virTristateSwitch */ + } fchost; + } data; +}; The above is SCSI storage specific.
+ +typedef struct _virPoolSourceInitiatorAttr virPoolSourceInitiatorAttr; +struct _virPoolSourceInitiatorAttr { + char *iqn; /* Initiator IQN */ +}; Same here, SCSI storage
+ +typedef struct _virPoolSource virPoolSource; +typedef virPoolSource *virPoolSourcePtr; +struct _virPoolSource { See my comment earlier regarding which is common and specific - this becomes the common stuff, but it's easier for me to just point out below all the structs, so see the end...
+ /* An optional (maybe multiple) host(s) */ + size_t nhost; + virPoolSourceHostPtr hosts; + + /* And either one or more devices ... */ + size_t ndevice; + virPoolSourceDevicePtr devices; + + /* Or a directory */ + char *dir; + + /* Or an adapter */ + virPoolSourceAdapter adapter; + + /* Or a name */ + char *name; + + /* Initiator IQN */ + virPoolSourceInitiatorAttr initiator; + + /* Authentication information */ + virStorageAuthDefPtr auth; + + /* Vendor of the source */ + char *vendor; + + /* Product name of the source*/ + char *product; + + /* Pool type specific format such as filesystem type, + * or lvm version, etc. + */ + int format; +}; + +typedef struct _virPoolTarget virPoolTarget; +typedef virPoolTarget *virPoolTargetPtr; +struct _virPoolTarget { + char *path; /* Optional local filesystem mapping */ + virStoragePerms perms; /* Default permissions for volumes/items */ +}; This seems generic, although the comments need some tweaking to be more generic. A 'path' to the pool target... The virStoragePerms could become virPoolPathPerms with the virStoragePerms struct being your guide.
+ +typedef struct _virPoolDef virPoolDef; +typedef virPoolDef *virPoolDefPtr; +struct _virPoolDef { + char *name; + unsigned char uuid[VIR_UUID_BUFLEN]; + int type; /* virStoragePoolType */ s/Storage//
I'm conflicted over how to use type... and of course there would need to be a virPoolType list which would initially just be "BLOCK_STORAGE", but would eventually have "FILESYSTEM_STORAGE" (and down the road VGPU_DEVICES).
+ + unsigned long long allocation; /* bytes */ + unsigned long long capacity; /* bytes */ + unsigned long long available; /* bytes */ + These would be "storage" related, but less so common type data. They're all "sizing" elements and could also be their own storage specific structure.
+ virPoolSource source; + virPoolTarget target; +}; +# endif /* __VIR_POOL_COMMON_H__ */
What follows is my thoughts for various structures. I would think you have it fresh in your mind where the exact overlap is.
These would be "virpool.h" type structures (left out some details):
typedef enum { VIR_POOL_BLOCK_STORAGE,
VIR_POOL_LAST, } virPoolType;
struct _virPoolDef { int type; /* virPoolType */ char *name; unsigned char uuid[VIR_UUID_BUFLEN]; virPoolSource source; virPoolTarget target; };
BTW: I'm conflicted over the virPoolType since I'm not sure how it would be used other than to save it. We cannot use the virStoragePoolType enum's because those would be specific to the block storage pool... I'd suspect that FS
struct _virPoolSource { /* One or more host definitions */ size_t nhost; virPoolSourceHostPtr hosts;
/* Authentication information */ virStorageAuthDefPtr auth;
/* One or more devices */ size_t nsrcpath; virPoolSourcePathPtr srcpaths;
/* Name of the source */ char *name;
/* Vendor of the source */ char *vendor;
/* Product name of the source */ char *product; };
typedef enum { VIR_POOL_SOURCE_DIR, VIR_POOL_SOURCE_DEVICE, VIR_POOL_SOURCE_NAME,
VIR_POOL_LAST, } virPoolSourcePathType;
struct _virPoolSourcePath { virPoolSourcePathType sourcetype; char *path; };
NB: Turns out 'logical' can have both 'device' and 'name', but "name" ends up being something we can add to a logical specific structure. Also 'gluster' can have both 'dir' and 'name', but it seems name is primary when both are used (see tests/*xmlin/*pool*gluster*.xml).
Still the key is they are all paths of some sort:
<dir path='$PATH'> <device path='$PATH'>
where <device> it could be a path to a BLOCK device (/dev/) or it could be an iSCSI initiator string (and thus SOURCE_NAME being used...). Search on "<dir" or "<device" in tests/*xmlin/*pool*.xml
struct _virPoolSourceHost { char *name; int port; };
struct _virPoolAuthDef { char *username; char *secrettype; /* <secret type='%s' for disk source */ int authType; /* virStorageAuthType */ virSecretLookupTypeDef seclookupdef; };
struct _virPoolTarget { char *path; /* Optional path to target */ virPoolPathPerms perms; /* Default permissions for path */ };
struct _virPoolPathPerms { mode_t mode; uid_t uid; gid_t gid; char *label; }
Below here would be storage_conf.h type adjustments:
struct _virStoragePoolDef { virPoolDef pool; virStoragePoolType storagetype;
virStoragePoolSizes size;
/* Based on storagetype, a subdata could be allocated to have/save * storagetype specific data */ void *subdata; /* vir*StoragePoolDefPtr */
/* In order to make life easy - format will be defined here * although it's only used by the some pools (fs, netfs, * disk, and logical via virStoragePoolFormat* enums */ int format; /* virStoragePoolFormat* */ };
struct _virStoragePoolSizes { unsigned long long allocation; /* bytes */ unsigned long long capacity; /* bytes */ unsigned long long available; /* bytes */ };
struct _virSCSIStoragePoolDef { virStoragePoolSourceAdapter adapter; virStoragePoolSourceInitiatorAttr initiator; };
struct _virDiskStoragePoolDef { int nfreeExtent; virDiskStoragePoolDeviceExtentPtr freeExtents; virStoragePoolGeometry geometry; int part_separator; /* enum virTristateSwitch */ };
struct _virDiskStoragePoolDeviceExtent { unsigned long long start; unsigned long long end; int type; /* virStorageFreeType */ };
NB: Gluster wouldn't need a pool specific data - it would just use the "name" and "dir" separately. Also, I think there's other patches that will want to have multiple gluster paths, so this (more or less) allows for that.
I probably left out some structures, but I hope this makes sense... Yes, it's going to be painful to make the switchover. That's why I suggest taking it slowly and not trying to pile on all the FSPool changes along.
John
-- Best regards, Olga
-- Best regards, Olga

On 12/21/2016 12:08 PM, Olga Krishtal wrote:
On 20/12/16 20:18, John Ferlan wrote:
On 12/15/2016 12:16 PM, Olga Krishtal wrote:
Hi, John. I needed some time to think over everything that you have written. Thanks a lot. Yeah - I got too wordy, but this type of change caused me to think about other possible consumers too.
With all this new information we have more freedom for changes and refactoring. Like I thought I mentioned - this set of changes seem to have gone too far in the direction of common code. Of course the original set of changes was too much cut-n-paste for my taste. There has to be a happy medium - that's what we need to find. I usually do that by figuring out what I'll need, creating generic structs/code and slowly moving things. Even if the generic structs start in the specific code - they can be moved. I would think at this point you know what you eventually need in the fspool driver - so that's where to start.
I dig through storage_conf.h file once with all ideas you have and tried to use them. It would be easier for me if we agree about virpool structs. The other changes depends on it. Sure to a degree. Some of this ends up being trial and error... or prototyping some changes to see what will and won't work. Trying to do this conceptually in email is difficult too, especially with other things going on. Again, create smaller patches that have the end goal.
Some moments are left unclear to me, so I have written down virpool.h with comments and questions. If you agree, please write Ok or smth else. After sending I kept thinking about things "in the background". I took a pass at trying to extract/abstract just the pool concept and suffice to say it's a bit overwhelming. It's possible - it just has to be done carefully.
Essentially though if you take the concept of a PoolObj to a different level of abstraction - it's a very common thing - there are domain, network, secret, storage, etc. that all use the objects code to build up a list or hash table of objects that point at 'def' data.
In any case at this time I don't think that level of abstraction would be necessary for what you're trying to accomplish. And if I do come up with something - I would hope it'll be easy to merge in what you have.
/* Pool element description */ Lets use PoolUnit instead PoolElement: Not a fan of Unit... This could just be _virPoolDef while the consumer of this would be _virStorageBlockPoolDef and _virStorageFSPoolDef.
No - this is not a pool definition, but the definition of the pool's part.
I've probably reached the point where conceptualizing things just isn't working. Between this and the other work I'm involved - there's not a lot of space left in the short term memory.
typedef struct _virPoolUnitDef virPoolUnitDef; typedef virPoolUnitDef *virPoolUnitDefPtr; struct _virPoolUnitDef { char *name; char *key; bool building; unsigned int in_use;
void* UnitTypeDef /* the same as privateData for virConnectPtr. Stores internal information about pool unit */ };
Why *name in both PoolUnitDef and PoolDef?
I think uuid should be here.
In here it is char *key; field.
I prefer uuid - it is what it is.
There should be a 'voltype' field here... Changing the name will dig out code that's using it.
Why voltype there is no volume. I do not see how we can set voltype without knowledge what kind of object we store in pool.
Oh right - mixing my metaphors... Although a 'pooltype' field could be useful as a way to describe any void * data...
As I found with the 'virStorageSource' "type" field there were a couple of source.target.type field users where source.target.type is not filled in. I have some patches to address that in a branch, but I'm waiting on other reviews to be completed before posting.
Not sure I like UnitTypeDef - the common usage is privateData. Oh and you'd need a "void (*privateDataFreeFunc)(void *);".
Might also need a few more things, but seems to be a good start.
Eg, 3 fields from virStorageVolDef: int type; virStorageVolSource source; virStorageSource target;
typedef struct _virPoolUnitDefList virPoolUnitDefList; typedef virPoolUnitDefList *virPoolUnitDefListPtr; struct _virPoolUnitDefList { size_t count; virPoolUnitDefPtr *obj };
I don't think *List is the way to go, but since that's the model today - we can stick with it until I can work up something better. Lists work well when there's 1-10 elements on the List, but as more elements are added the search times exponentially increase.
Ok. Let's implement lists and and all changes that is necessary for storage pools to work with the new pool object. But I will think about it and may be later we change it . But it easier to start with it.
That's fine - I have it on my list to "get around to" converting all lists to tables... Well actually it's to make common poolobj code which is just another abstraction level.
So in virpool.h we will have some bricks to describe common parts, and Storage/FS structs will look like:
struct virStorageBlockPoolDef { virPoolDefPtr poolDef; some structs to describe storage }
The same is for virStorageFSPool.
In this case we do not need to describe precisely pool element. Moreover, we will have API to manage common pool parts, and I think the changes won't be that huge. I think I will send rfc of virpool.h/c separately rather keeping discussion over here, but will leave links to this conversation.
That's fine - be aware the Red Hat folks (including me) are all going to disappear until 2017... There may be a few brave souls that want to work during their "vacation" (ok company shutdown). John [...]

After reusage of all possible storage pool structures we will able to use some storage pool functions. Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- src/Makefile.am | 2 +- src/conf/storage_conf.c | 162 ---------------------------------------------- src/conf/storage_conf.h | 13 +--- src/libvirt_private.syms | 11 ++-- src/util/virpoolcommon.c | 125 +++++++++++++++++++++++++++++++++++ src/util/virpoolcommon.h | 16 +++++ src/util/virstoragefile.c | 73 +++++++++++++++++++++ src/util/virstoragefile.h | 3 + 8 files changed, 225 insertions(+), 180 deletions(-) create mode 100644 src/util/virpoolcommon.c diff --git a/src/Makefile.am b/src/Makefile.am index f8d4a5b..13a4976 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -185,7 +185,7 @@ UTIL_SOURCES = \ util/viruuid.c util/viruuid.h \ util/virxdrdefs.h \ util/virxml.c util/virxml.h \ - util/virpoolcommon.h \ + util/virpoolcommon.h util/virpoolcommon.c \ $(NULL) EXTRA_DIST += $(srcdir)/util/keymaps.csv $(srcdir)/util/virkeycode-mapgen.py diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index 7e7bb72..f452fba 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -96,10 +96,6 @@ VIR_ENUM_IMPL(virStoragePartedFs, "ext2", "ext2", "extended") -VIR_ENUM_IMPL(virStoragePoolSourceAdapter, - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_LAST, - "default", "scsi_host", "fc_host") - typedef const char *(*virStorageVolFormatToString)(int format); typedef int (*virStorageVolFormatFromString)(const char *format); @@ -328,73 +324,6 @@ virStorageVolDefFree(virStorageVolDefPtr def) VIR_FREE(def); } -static void -virStoragePoolSourceAdapterClear(virStoragePoolSourceAdapterPtr adapter) -{ - if (adapter->type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) { - VIR_FREE(adapter->data.fchost.wwnn); - VIR_FREE(adapter->data.fchost.wwpn); - VIR_FREE(adapter->data.fchost.parent); - } else if (adapter->type == - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) { - VIR_FREE(adapter->data.scsi_host.name); - } -} - -void -virStoragePoolSourceDeviceClear(virStoragePoolSourceDevicePtr dev) -{ - VIR_FREE(dev->freeExtents); - VIR_FREE(dev->path); -} - -void -virStoragePoolSourceClear(virStoragePoolSourcePtr source) -{ - size_t i; - - if (!source) - return; - - for (i = 0; i < source->nhost; i++) - VIR_FREE(source->hosts[i].name); - VIR_FREE(source->hosts); - - for (i = 0; i < source->ndevice; i++) - virStoragePoolSourceDeviceClear(&source->devices[i]); - VIR_FREE(source->devices); - VIR_FREE(source->dir); - VIR_FREE(source->name); - virStoragePoolSourceAdapterClear(&source->adapter); - VIR_FREE(source->initiator.iqn); - virStorageAuthDefFree(source->auth); - VIR_FREE(source->vendor); - VIR_FREE(source->product); -} - -void -virStoragePoolSourceFree(virStoragePoolSourcePtr source) -{ - virStoragePoolSourceClear(source); - VIR_FREE(source); -} - -void -virStoragePoolDefFree(virStoragePoolDefPtr def) -{ - if (!def) - return; - - VIR_FREE(def->name); - - virStoragePoolSourceClear(&def->source); - - VIR_FREE(def->target.path); - VIR_FREE(def->target.perms.label); - VIR_FREE(def); -} - - void virStoragePoolObjFree(virStoragePoolObjPtr obj) { @@ -730,83 +659,6 @@ virStoragePoolDefParseSourceString(const char *srcSpec, return ret; } -static int -virStorageDefParsePerms(xmlXPathContextPtr ctxt, - virStoragePermsPtr perms, - const char *permxpath) -{ - char *mode; - long long val; - int ret = -1; - xmlNodePtr relnode; - xmlNodePtr node; - - node = virXPathNode(permxpath, ctxt); - if (node == NULL) { - /* Set default values if there is not <permissions> element */ - perms->mode = (mode_t) -1; - perms->uid = (uid_t) -1; - perms->gid = (gid_t) -1; - perms->label = NULL; - return 0; - } - - relnode = ctxt->node; - ctxt->node = node; - - if ((mode = virXPathString("string(./mode)", ctxt))) { - int tmp; - - if (virStrToLong_i(mode, NULL, 8, &tmp) < 0 || (tmp & ~0777)) { - VIR_FREE(mode); - virReportError(VIR_ERR_XML_ERROR, "%s", - _("malformed octal mode")); - goto error; - } - perms->mode = tmp; - VIR_FREE(mode); - } else { - perms->mode = (mode_t) -1; - } - - if (virXPathNode("./owner", ctxt) == NULL) { - perms->uid = (uid_t) -1; - } else { - /* We previously could output -1, so continue to parse it */ - if (virXPathLongLong("number(./owner)", ctxt, &val) < 0 || - ((uid_t)val != val && - val != -1)) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("malformed owner element")); - goto error; - } - - perms->uid = val; - } - - if (virXPathNode("./group", ctxt) == NULL) { - perms->gid = (gid_t) -1; - } else { - /* We previously could output -1, so continue to parse it */ - if (virXPathLongLong("number(./group)", ctxt, &val) < 0 || - ((gid_t) val != val && - val != -1)) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("malformed group element")); - goto error; - } - perms->gid = val; - } - - /* NB, we're ignoring missing labels here - they'll simply inherit */ - perms->label = virXPathString("string(./label)", ctxt); - - ret = 0; - error: - ctxt->node = relnode; - return ret; -} - static virStoragePoolDefPtr virStoragePoolDefParseXML(xmlXPathContextPtr ctxt) { @@ -2125,20 +1977,6 @@ virStoragePoolObjDeleteDef(virStoragePoolObjPtr pool) return 0; } -virStoragePoolSourcePtr -virStoragePoolSourceListNewSource(virStoragePoolSourceListPtr list) -{ - virStoragePoolSourcePtr source; - - if (VIR_REALLOC_N(list->sources, list->nsources + 1) < 0) - return NULL; - - source = &list->sources[list->nsources++]; - memset(source, 0, sizeof(*source)); - - return source; -} - char * virStoragePoolSourceListFormat(virStoragePoolSourceListPtr def) { diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h index 8a9a789..ad7de86 100644 --- a/src/conf/storage_conf.h +++ b/src/conf/storage_conf.h @@ -198,13 +198,8 @@ struct _virStorageDriverState { virObjectEventStatePtr storageEventState; }; -typedef struct _virStoragePoolSourceList virStoragePoolSourceList; +typedef virPoolSourceList virStoragePoolSourceList; typedef virStoragePoolSourceList *virStoragePoolSourceListPtr; -struct _virStoragePoolSourceList { - int type; - unsigned int nsources; - virPoolSourcePtr sources; -}; typedef bool (*virStoragePoolObjListFilter)(virConnectPtr conn, virStoragePoolDefPtr def); @@ -290,10 +285,6 @@ int virStoragePoolObjSaveDef(virStorageDriverStatePtr driver, int virStoragePoolObjDeleteDef(virStoragePoolObjPtr pool); void virStorageVolDefFree(virStorageVolDefPtr def); -void virStoragePoolSourceClear(virStoragePoolSourcePtr source); -void virStoragePoolSourceDeviceClear(virStoragePoolSourceDevicePtr dev); -void virStoragePoolSourceFree(virStoragePoolSourcePtr source); -void virStoragePoolDefFree(virStoragePoolDefPtr def); void virStoragePoolObjFree(virStoragePoolObjPtr pool); void virStoragePoolObjListFree(virStoragePoolObjListPtr pools); void virStoragePoolObjRemove(virStoragePoolObjListPtr pools, @@ -302,8 +293,6 @@ void virStoragePoolObjRemove(virStoragePoolObjListPtr pools, virStoragePoolSourcePtr virStoragePoolDefParseSourceString(const char *srcSpec, int pool_type); -virStoragePoolSourcePtr -virStoragePoolSourceListNewSource(virStoragePoolSourceListPtr list); char *virStoragePoolSourceListFormat(virStoragePoolSourceListPtr def); int virStoragePoolObjIsDuplicate(virStoragePoolObjListPtr pools, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 74dd527..a061799 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -867,7 +867,6 @@ virDomainSnapshotUpdateRelations; # conf/storage_conf.h virStoragePartedFsTypeToString; virStoragePoolDefFormat; -virStoragePoolDefFree; virStoragePoolDefParseFile; virStoragePoolDefParseNode; virStoragePoolDefParseSourceString; @@ -895,13 +894,9 @@ virStoragePoolSaveConfig; virStoragePoolSaveState; virStoragePoolSourceAdapterTypeFromString; virStoragePoolSourceAdapterTypeToString; -virStoragePoolSourceClear; -virStoragePoolSourceDeviceClear; virStoragePoolSourceFindDuplicate; virStoragePoolSourceFindDuplicateDevices; -virStoragePoolSourceFree; virStoragePoolSourceListFormat; -virStoragePoolSourceListNewSource; virStoragePoolTypeFromString; virStoragePoolTypeToString; virStorageVolDefFindByKey; @@ -2708,6 +2703,12 @@ virXPathULong; virXPathULongHex; virXPathULongLong; +# util/virpoolcommon.h +virStoragePoolDefFree; +virStoragePoolSourceFree; +virStoragePoolSourceDeviceClear; +virStoragePoolSourceClear; +virStoragePoolSourceListNewSource; # Let emacs know we want case-insensitive sorting # Local Variables: diff --git a/src/util/virpoolcommon.c b/src/util/virpoolcommon.c new file mode 100644 index 0000000..3ee6251 --- /dev/null +++ b/src/util/virpoolcommon.c @@ -0,0 +1,125 @@ +/* + * virpoolcommon.c: utility to operate common parts in storage pools and + * filesystem pools + * + * 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/>. + * + */ + +#include <config.h> +#include "virpoolcommon.h" + +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdlib.h> +#include "viralloc.h" +#include "virxml.h" +#include "viruuid.h" +#include "virerror.h" +#include "virlog.h" +#include "virfile.h" +#include "virendian.h" +#include "virstring.h" +#include "virutil.h" +#include "dirname.h" +#include "virbuffer.h" + +#define VIR_FROM_THIS VIR_FROM_STORAGE + +VIR_ENUM_IMPL(virStoragePoolSourceAdapter, + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_LAST, + "default", "scsi_host", "fc_host") + +static void +virStoragePoolSourceAdapterClear(virPoolSourceAdapterPtr adapter) +{ + if (adapter->type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) { + VIR_FREE(adapter->data.fchost.wwnn); + VIR_FREE(adapter->data.fchost.wwpn); + VIR_FREE(adapter->data.fchost.parent); + } else if (adapter->type == + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) { + VIR_FREE(adapter->data.scsi_host.name); + } +} + +void +virStoragePoolSourceDeviceClear(virPoolSourceDevicePtr dev) +{ + VIR_FREE(dev->freeExtents); + VIR_FREE(dev->path); +} + +void +virStoragePoolSourceClear(virPoolSourcePtr source) +{ + size_t i; + + if (!source) + return; + + for (i = 0; i < source->nhost; i++) + VIR_FREE(source->hosts[i].name); + VIR_FREE(source->hosts); + + for (i = 0; i < source->ndevice; i++) + virStoragePoolSourceDeviceClear(&source->devices[i]); + VIR_FREE(source->devices); + VIR_FREE(source->dir); + VIR_FREE(source->name); + virStoragePoolSourceAdapterClear(&source->adapter); + VIR_FREE(source->initiator.iqn); + virStorageAuthDefFree(source->auth); + VIR_FREE(source->vendor); + VIR_FREE(source->product); +} + +void +virStoragePoolSourceFree(virPoolSourcePtr source) +{ + virStoragePoolSourceClear(source); + VIR_FREE(source); +} + +void +virStoragePoolDefFree(virPoolDefPtr def) +{ + if (!def) + return; + + VIR_FREE(def->name); + + virStoragePoolSourceClear(&def->source); + + VIR_FREE(def->target.path); + VIR_FREE(def->target.perms.label); + VIR_FREE(def); +} + + +virPoolSourcePtr +virStoragePoolSourceListNewSource(virPoolSourceListPtr list) +{ + virPoolSourcePtr source; + + if (VIR_REALLOC_N(list->sources, list->nsources + 1) < 0) + return NULL; + + source = &list->sources[list->nsources++]; + memset(source, 0, sizeof(*source)); + + return source; +} diff --git a/src/util/virpoolcommon.h b/src/util/virpoolcommon.h index d54de36..c1c607f 100644 --- a/src/util/virpoolcommon.h +++ b/src/util/virpoolcommon.h @@ -142,6 +142,15 @@ struct _virPoolSource { int format; }; +typedef struct _virPoolSourceList virPoolSourceList; +typedef virPoolSourceList *virPoolSourceListPtr; +struct _virPoolSourceList { + int type; + unsigned int nsources; + virPoolSourcePtr sources; +}; + + typedef struct _virPoolTarget virPoolTarget; typedef virPoolTarget *virPoolTargetPtr; struct _virPoolTarget { @@ -163,4 +172,11 @@ struct _virPoolDef { virPoolSource source; virPoolTarget target; }; + +void virStoragePoolSourceClear(virPoolSourcePtr source); +void virStoragePoolSourceDeviceClear(virPoolSourceDevicePtr dev); +void virStoragePoolSourceFree(virPoolSourcePtr source); +void virStoragePoolDefFree(virPoolDefPtr def); +virPoolSourcePtr +virStoragePoolSourceListNewSource(virPoolSourceListPtr list); # endif /* __VIR_POOL_COMMON_H__ */ diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index 272db67..318b33d 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -3537,3 +3537,76 @@ virStorageFileCheckCompat(const char *compat) virStringFreeList(version); return ret; } + +int +virStorageDefParsePerms(xmlXPathContextPtr ctxt, + virStoragePermsPtr perms, + const char *permxpath) +{ + char *mode; + long long val; + int ret = -1; + xmlNodePtr relnode; + xmlNodePtr node; + + node = virXPathNode(permxpath, ctxt); + if (node == NULL) { + perms->mode = (mode_t) -1; + perms->uid = (uid_t) -1; + perms->gid = (gid_t) -1; + perms->label = NULL; + return 0; + } + + relnode = ctxt->node; + ctxt->node = node; + + if ((mode = virXPathString("string(./mode)", ctxt))) { + int tmp; + + if (virStrToLong_i(mode, NULL, 8, &tmp) < 0 || (tmp & ~0777)) { + VIR_FREE(mode); + virReportError(VIR_ERR_XML_ERROR, "%s", + _("malformed octal mode")); + goto error; + } + perms->mode = tmp; + VIR_FREE(mode); + } else { + perms->mode = (mode_t) -1; + } + + if (virXPathNode("./owner", ctxt) == NULL) { + perms->uid = (uid_t) -1; + } else { + if (virXPathLongLong("number(./owner)", ctxt, &val) < 0 || + ((uid_t)val != val && + val != -1)) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("malformed owner element")); + goto error; + } + + perms->uid = val; + } + + if (virXPathNode("./group", ctxt) == NULL) { + perms->gid = (gid_t) -1; + } else { + if (virXPathLongLong("number(./group)", ctxt, &val) < 0 || + ((gid_t) val != val && + val != -1)) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("malformed group element")); + goto error; + } + perms->gid = val; + } + + perms->label = virXPathString("string(./label)", ctxt); + + ret = 0; + error: + ctxt->node = relnode; + return ret; +} diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h index 3d09468..8021d42 100644 --- a/src/util/virstoragefile.h +++ b/src/util/virstoragefile.h @@ -383,4 +383,7 @@ int virStorageFileCheckCompat(const char *compat); virStorageSourcePtr virStorageSourceNewFromBackingAbsolute(const char *path); +int virStorageDefParsePerms(xmlXPathContextPtr ctxt, + virStoragePermsPtr perms, + const char *permxpath); #endif /* __VIR_STORAGE_FILE_H__ */ -- 1.8.3.1

On 12/02/2016 10:38 AM, Olga Krishtal wrote:
After reusage of all possible storage pool structures we will able to use some storage pool functions.
Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- src/Makefile.am | 2 +- src/conf/storage_conf.c | 162 ---------------------------------------------- src/conf/storage_conf.h | 13 +--- src/libvirt_private.syms | 11 ++-- src/util/virpoolcommon.c | 125 +++++++++++++++++++++++++++++++++++ src/util/virpoolcommon.h | 16 +++++ src/util/virstoragefile.c | 73 +++++++++++++++++++++ src/util/virstoragefile.h | 3 + 8 files changed, 225 insertions(+), 180 deletions(-) create mode 100644 src/util/virpoolcommon.c
I couldn't get this one to apply via "git am -3" - the src/Makefile.am failed... Even removing that specific change, the volpoolcommon.h changed - so there's something amiss with the patch.... I'll just make some comments along the way... I also suggest adding the virpool.c to the previous patch, then using subsequent patches to remove code from storage_conf. The end result is the same it's just "easier" to review...
diff --git a/src/Makefile.am b/src/Makefile.am index f8d4a5b..13a4976 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -185,7 +185,7 @@ UTIL_SOURCES = \ util/viruuid.c util/viruuid.h \ util/virxdrdefs.h \ util/virxml.c util/virxml.h \ - util/virpoolcommon.h \ + util/virpoolcommon.h util/virpoolcommon.c \
I think the file should be util/virpool.c
$(NULL)
EXTRA_DIST += $(srcdir)/util/keymaps.csv $(srcdir)/util/virkeycode-mapgen.py diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index 7e7bb72..f452fba 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -96,10 +96,6 @@ VIR_ENUM_IMPL(virStoragePartedFs, "ext2", "ext2", "extended")
-VIR_ENUM_IMPL(virStoragePoolSourceAdapter, - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_LAST, - "default", "scsi_host", "fc_host") -
The above stays here - I doubt it'll be used by fspool! It's very specific.
typedef const char *(*virStorageVolFormatToString)(int format); typedef int (*virStorageVolFormatFromString)(const char *format);
@@ -328,73 +324,6 @@ virStorageVolDefFree(virStorageVolDefPtr def) VIR_FREE(def); }
-static void -virStoragePoolSourceAdapterClear(virStoragePoolSourceAdapterPtr adapter) -{ - if (adapter->type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) { - VIR_FREE(adapter->data.fchost.wwnn); - VIR_FREE(adapter->data.fchost.wwpn); - VIR_FREE(adapter->data.fchost.parent); - } else if (adapter->type == - VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) { - VIR_FREE(adapter->data.scsi_host.name); - } -} -
The above stays
-void -virStoragePoolSourceDeviceClear(virStoragePoolSourceDevicePtr dev) -{ - VIR_FREE(dev->freeExtents); - VIR_FREE(dev->path); -} -
Same
-void -virStoragePoolSourceClear(virStoragePoolSourcePtr source) -{ - size_t i; - - if (!source) - return; - - for (i = 0; i < source->nhost; i++) - VIR_FREE(source->hosts[i].name); - VIR_FREE(source->hosts); - - for (i = 0; i < source->ndevice; i++) - virStoragePoolSourceDeviceClear(&source->devices[i]); - VIR_FREE(source->devices); - VIR_FREE(source->dir); - VIR_FREE(source->name); - virStoragePoolSourceAdapterClear(&source->adapter); - VIR_FREE(source->initiator.iqn); - virStorageAuthDefFree(source->auth); - VIR_FREE(source->vendor); - VIR_FREE(source->product); -} - -void -virStoragePoolSourceFree(virStoragePoolSourcePtr source) -{ - virStoragePoolSourceClear(source); - VIR_FREE(source); -} - -void -virStoragePoolDefFree(virStoragePoolDefPtr def) -{ - if (!def) - return; - - VIR_FREE(def->name); - - virStoragePoolSourceClear(&def->source); - - VIR_FREE(def->target.path); - VIR_FREE(def->target.perms.label); - VIR_FREE(def); -} - -
The above has some common and some specific stuff - it'll need to be more closely looked at. The whole question of need for a virPoolObj I raised in 1/15 comes into play...
void virStoragePoolObjFree(virStoragePoolObjPtr obj) { @@ -730,83 +659,6 @@ virStoragePoolDefParseSourceString(const char *srcSpec, return ret; }
-static int -virStorageDefParsePerms(xmlXPathContextPtr ctxt, - virStoragePermsPtr perms, - const char *permxpath)
I think this moves to virpool.c and is renamed to be more generic - that is anything that says "Storage" needs to change...
-{ - char *mode; - long long val; - int ret = -1; - xmlNodePtr relnode; - xmlNodePtr node; - - node = virXPathNode(permxpath, ctxt); - if (node == NULL) { - /* Set default values if there is not <permissions> element */ - perms->mode = (mode_t) -1; - perms->uid = (uid_t) -1; - perms->gid = (gid_t) -1; - perms->label = NULL; - return 0; - } - - relnode = ctxt->node; - ctxt->node = node; - - if ((mode = virXPathString("string(./mode)", ctxt))) { - int tmp; - - if (virStrToLong_i(mode, NULL, 8, &tmp) < 0 || (tmp & ~0777)) { - VIR_FREE(mode); - virReportError(VIR_ERR_XML_ERROR, "%s", - _("malformed octal mode")); - goto error; - } - perms->mode = tmp; - VIR_FREE(mode); - } else { - perms->mode = (mode_t) -1; - } - - if (virXPathNode("./owner", ctxt) == NULL) { - perms->uid = (uid_t) -1; - } else { - /* We previously could output -1, so continue to parse it */ - if (virXPathLongLong("number(./owner)", ctxt, &val) < 0 || - ((uid_t)val != val && - val != -1)) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("malformed owner element")); - goto error; - } - - perms->uid = val; - } - - if (virXPathNode("./group", ctxt) == NULL) { - perms->gid = (gid_t) -1; - } else { - /* We previously could output -1, so continue to parse it */ - if (virXPathLongLong("number(./group)", ctxt, &val) < 0 || - ((gid_t) val != val && - val != -1)) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("malformed group element")); - goto error; - } - perms->gid = val; - } - - /* NB, we're ignoring missing labels here - they'll simply inherit */ - perms->label = virXPathString("string(./label)", ctxt); - - ret = 0; - error: - ctxt->node = relnode; - return ret; -} - static virStoragePoolDefPtr virStoragePoolDefParseXML(xmlXPathContextPtr ctxt) { @@ -2125,20 +1977,6 @@ virStoragePoolObjDeleteDef(virStoragePoolObjPtr pool) return 0; }
-virStoragePoolSourcePtr -virStoragePoolSourceListNewSource(virStoragePoolSourceListPtr list) -{ - virStoragePoolSourcePtr source; - - if (VIR_REALLOC_N(list->sources, list->nsources + 1) < 0) - return NULL; - - source = &list->sources[list->nsources++]; - memset(source, 0, sizeof(*source)); - - return source; -} -
I see this moving to virpool
char * virStoragePoolSourceListFormat(virStoragePoolSourceListPtr def) { diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h index 8a9a789..ad7de86 100644 --- a/src/conf/storage_conf.h +++ b/src/conf/storage_conf.h @@ -198,13 +198,8 @@ struct _virStorageDriverState { virObjectEventStatePtr storageEventState; };
-typedef struct _virStoragePoolSourceList virStoragePoolSourceList; +typedef virPoolSourceList virStoragePoolSourceList; typedef virStoragePoolSourceList *virStoragePoolSourceListPtr; -struct _virStoragePoolSourceList { - int type; - unsigned int nsources; - virPoolSourcePtr sources; -};
typedef bool (*virStoragePoolObjListFilter)(virConnectPtr conn, virStoragePoolDefPtr def); @@ -290,10 +285,6 @@ int virStoragePoolObjSaveDef(virStorageDriverStatePtr driver, int virStoragePoolObjDeleteDef(virStoragePoolObjPtr pool);
void virStorageVolDefFree(virStorageVolDefPtr def); -void virStoragePoolSourceClear(virStoragePoolSourcePtr source); -void virStoragePoolSourceDeviceClear(virStoragePoolSourceDevicePtr dev); -void virStoragePoolSourceFree(virStoragePoolSourcePtr source); -void virStoragePoolDefFree(virStoragePoolDefPtr def);
These are TBD.
void virStoragePoolObjFree(virStoragePoolObjPtr pool); void virStoragePoolObjListFree(virStoragePoolObjListPtr pools); void virStoragePoolObjRemove(virStoragePoolObjListPtr pools, @@ -302,8 +293,6 @@ void virStoragePoolObjRemove(virStoragePoolObjListPtr pools, virStoragePoolSourcePtr virStoragePoolDefParseSourceString(const char *srcSpec, int pool_type); -virStoragePoolSourcePtr -virStoragePoolSourceListNewSource(virStoragePoolSourceListPtr list); char *virStoragePoolSourceListFormat(virStoragePoolSourceListPtr def);
int virStoragePoolObjIsDuplicate(virStoragePoolObjListPtr pools, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 74dd527..a061799 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -867,7 +867,6 @@ virDomainSnapshotUpdateRelations; # conf/storage_conf.h virStoragePartedFsTypeToString; virStoragePoolDefFormat; -virStoragePoolDefFree; virStoragePoolDefParseFile; virStoragePoolDefParseNode; virStoragePoolDefParseSourceString; @@ -895,13 +894,9 @@ virStoragePoolSaveConfig; virStoragePoolSaveState; virStoragePoolSourceAdapterTypeFromString; virStoragePoolSourceAdapterTypeToString; -virStoragePoolSourceClear; -virStoragePoolSourceDeviceClear; virStoragePoolSourceFindDuplicate; virStoragePoolSourceFindDuplicateDevices; -virStoragePoolSourceFree; virStoragePoolSourceListFormat; -virStoragePoolSourceListNewSource; virStoragePoolTypeFromString; virStoragePoolTypeToString; virStorageVolDefFindByKey; @@ -2708,6 +2703,12 @@ virXPathULong; virXPathULongHex; virXPathULongLong;
+# util/virpoolcommon.h
virpool.h
+virStoragePoolDefFree; +virStoragePoolSourceFree; +virStoragePoolSourceDeviceClear; +virStoragePoolSourceClear; +virStoragePoolSourceListNewSource;
Your new names should not be "virStoragePool" - rather just "virPool" obvious affect in code as well...
# Let emacs know we want case-insensitive sorting # Local Variables: diff --git a/src/util/virpoolcommon.c b/src/util/virpoolcommon.c new file mode 100644 index 0000000..3ee6251 --- /dev/null +++ b/src/util/virpoolcommon.c
virpool.c
@@ -0,0 +1,125 @@ +/* + * virpoolcommon.c: utility to operate common parts in storage pools and + * filesystem pools
Similar virpool.c - common pool ... Based on earlier review - some of these API's don't move here.
+ * + * 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/>. + * + */ + +#include <config.h> +#include "virpoolcommon.h" + +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdlib.h> +#include "viralloc.h" +#include "virxml.h" +#include "viruuid.h" +#include "virerror.h" +#include "virlog.h" +#include "virfile.h" +#include "virendian.h" +#include "virstring.h" +#include "virutil.h" +#include "dirname.h" +#include "virbuffer.h" + +#define VIR_FROM_THIS VIR_FROM_STORAGE + +VIR_ENUM_IMPL(virStoragePoolSourceAdapter,
I wouldn't expect a "common" function to have "Storage" in the name...
+ VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_LAST, + "default", "scsi_host", "fc_host") + +static void +virStoragePoolSourceAdapterClear(virPoolSourceAdapterPtr adapter) +{ + if (adapter->type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) { + VIR_FREE(adapter->data.fchost.wwnn); + VIR_FREE(adapter->data.fchost.wwpn); + VIR_FREE(adapter->data.fchost.parent); + } else if (adapter->type == + VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) { + VIR_FREE(adapter->data.scsi_host.name); + } +}
Above is specific to SCSI pool...
+ +void +virStoragePoolSourceDeviceClear(virPoolSourceDevicePtr dev) +{ + VIR_FREE(dev->freeExtents); + VIR_FREE(dev->path); +} +
Above is specific to DISK pool
+void +virStoragePoolSourceClear(virPoolSourcePtr source) +{ + size_t i; + + if (!source) + return; + + for (i = 0; i < source->nhost; i++) + VIR_FREE(source->hosts[i].name); + VIR_FREE(source->hosts); + + for (i = 0; i < source->ndevice; i++) + virStoragePoolSourceDeviceClear(&source->devices[i]); + VIR_FREE(source->devices); + VIR_FREE(source->dir); + VIR_FREE(source->name); + virStoragePoolSourceAdapterClear(&source->adapter); + VIR_FREE(source->initiator.iqn); + virStorageAuthDefFree(source->auth); + VIR_FREE(source->vendor); + VIR_FREE(source->product); +}
Above would just Clear "virPoolSource" things... leaving the virStoragePoolSource things for the storage pool code.
+ +void +virStoragePoolSourceFree(virPoolSourcePtr source) +{ + virStoragePoolSourceClear(source); + VIR_FREE(source); +}
I think this stays in storage pool
+ +void +virStoragePoolDefFree(virPoolDefPtr def) +{
I don't think we even allocate a virPoolDef - it's just a convenience structure within a virStoragePool type. Or inconvenience of typing a few extra characters for structure dereference.
+ if (!def) + return; + + VIR_FREE(def->name); + + virStoragePoolSourceClear(&def->source); + + VIR_FREE(def->target.path); + VIR_FREE(def->target.perms.label); + VIR_FREE(def); +} + + +virPoolSourcePtr +virStoragePoolSourceListNewSource(virPoolSourceListPtr list) +{ + virPoolSourcePtr source; + + if (VIR_REALLOC_N(list->sources, list->nsources + 1) < 0) + return NULL; + + source = &list->sources[list->nsources++]; + memset(source, 0, sizeof(*source)); + + return source; +}
Beyond the "virStoragePool" -> "virPool" name change - I suspect the above changes a bit based on my comments from the first patch.
diff --git a/src/util/virpoolcommon.h b/src/util/virpoolcommon.h index d54de36..c1c607f 100644 --- a/src/util/virpoolcommon.h +++ b/src/util/virpoolcommon.h @@ -142,6 +142,15 @@ struct _virPoolSource { int format; };
+typedef struct _virPoolSourceList virPoolSourceList; +typedef virPoolSourceList *virPoolSourceListPtr; +struct _virPoolSourceList { + int type; + unsigned int nsources; + virPoolSourcePtr sources; +}; + +
The above should have been a part of the original creation of virpool.h
typedef struct _virPoolTarget virPoolTarget; typedef virPoolTarget *virPoolTargetPtr; struct _virPoolTarget { @@ -163,4 +172,11 @@ struct _virPoolDef { virPoolSource source; virPoolTarget target; }; + +void virStoragePoolSourceClear(virPoolSourcePtr source); +void virStoragePoolSourceDeviceClear(virPoolSourceDevicePtr dev); +void virStoragePoolSourceFree(virPoolSourcePtr source); +void virStoragePoolDefFree(virPoolDefPtr def); +virPoolSourcePtr +virStoragePoolSourceListNewSource(virPoolSourceListPtr list); # endif /* __VIR_POOL_COMMON_H__ */ diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index 272db67..318b33d 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -3537,3 +3537,76 @@ virStorageFileCheckCompat(const char *compat) virStringFreeList(version); return ret; } + +int +virStorageDefParsePerms(xmlXPathContextPtr ctxt, + virStoragePermsPtr perms, + const char *permxpath)
I think this should have moved to virpool
+{ + char *mode; + long long val; + int ret = -1; + xmlNodePtr relnode; + xmlNodePtr node; + + node = virXPathNode(permxpath, ctxt); + if (node == NULL) { + perms->mode = (mode_t) -1; + perms->uid = (uid_t) -1; + perms->gid = (gid_t) -1; + perms->label = NULL; + return 0; + } + + relnode = ctxt->node; + ctxt->node = node; + + if ((mode = virXPathString("string(./mode)", ctxt))) { + int tmp; + + if (virStrToLong_i(mode, NULL, 8, &tmp) < 0 || (tmp & ~0777)) { + VIR_FREE(mode); + virReportError(VIR_ERR_XML_ERROR, "%s", + _("malformed octal mode")); + goto error; + } + perms->mode = tmp; + VIR_FREE(mode); + } else { + perms->mode = (mode_t) -1; + } + + if (virXPathNode("./owner", ctxt) == NULL) { + perms->uid = (uid_t) -1; + } else { + if (virXPathLongLong("number(./owner)", ctxt, &val) < 0 || + ((uid_t)val != val && + val != -1)) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("malformed owner element")); + goto error; + } + + perms->uid = val; + } + + if (virXPathNode("./group", ctxt) == NULL) { + perms->gid = (gid_t) -1; + } else { + if (virXPathLongLong("number(./group)", ctxt, &val) < 0 || + ((gid_t) val != val && + val != -1)) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("malformed group element")); + goto error; + } + perms->gid = val; + } + + perms->label = virXPathString("string(./label)", ctxt); + + ret = 0; + error: + ctxt->node = relnode; + return ret; +} diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h index 3d09468..8021d42 100644 --- a/src/util/virstoragefile.h +++ b/src/util/virstoragefile.h @@ -383,4 +383,7 @@ int virStorageFileCheckCompat(const char *compat);
virStorageSourcePtr virStorageSourceNewFromBackingAbsolute(const char *path);
+int virStorageDefParsePerms(xmlXPathContextPtr ctxt, + virStoragePermsPtr perms, + const char *permxpath);
Obviously affecting this. John
#endif /* __VIR_STORAGE_FILE_H__ */

The fs backend for storage pools works a lot with directories and etc. The same is true for filesystem pools with directory backend. In order to avoid rewriting the same code once again patch moves this code to virpoolcommon.c. Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- po/POTFILES.in | 1 + src/libvirt_private.syms | 3 ++ src/storage/storage_backend.h | 1 - src/storage/storage_backend_fs.c | 74 +++------------------------------- src/util/virpoolcommon.c | 87 ++++++++++++++++++++++++++++++++++++++++ src/util/virpoolcommon.h | 7 ++++ 6 files changed, 104 insertions(+), 69 deletions(-) diff --git a/po/POTFILES.in b/po/POTFILES.in index 1469240..29bc45c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -229,6 +229,7 @@ src/util/virpci.c src/util/virperf.c src/util/virpidfile.c src/util/virpolkit.c +src/util/virpoolcommon.c src/util/virportallocator.c src/util/virprocess.c src/util/virqemu.c diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index a061799..67ebe2a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2709,6 +2709,9 @@ virStoragePoolSourceFree; virStoragePoolSourceDeviceClear; virStoragePoolSourceClear; virStoragePoolSourceListNewSource; +virDirPoolDelete; +virDirItemCreate; +virDirPoolBuild; # Let emacs know we want case-insensitive sorting # Local Variables: diff --git a/src/storage/storage_backend.h b/src/storage/storage_backend.h index 28e1a65..a08a725 100644 --- a/src/storage/storage_backend.h +++ b/src/storage/storage_backend.h @@ -214,7 +214,6 @@ int virStorageBackendVolOpen(const char *path, struct stat *sb, ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); -# define VIR_STORAGE_DEFAULT_POOL_PERM_MODE 0755 # define VIR_STORAGE_DEFAULT_VOL_PERM_MODE 0600 int virStorageBackendUpdateVolInfo(virStorageVolDefPtr vol, diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index 6c8bae2..c21fbc8 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -45,6 +45,7 @@ #include "storage_backend_fs.h" #include "storage_conf.h" #include "virstoragefile.h" +#include "virpoolcommon.h" #include "vircommand.h" #include "viralloc.h" #include "virxml.h" @@ -809,11 +810,7 @@ virStorageBackendFileSystemBuild(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned int flags) { int ret = -1; - char *parent = NULL; - char *p = NULL; - mode_t mode; bool needs_create_as_uid; - unsigned int dir_create_flags; virCheckFlags(VIR_STORAGE_POOL_BUILD_OVERWRITE | VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, ret); @@ -822,45 +819,9 @@ virStorageBackendFileSystemBuild(virConnectPtr conn ATTRIBUTE_UNUSED, 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; needs_create_as_uid = (pool->def->type == VIR_STORAGE_POOL_NETFS); - mode = pool->def->target.perms.mode; - - if (mode == (mode_t) -1 && - (needs_create_as_uid || !virFileExists(pool->def->target.path))) - mode = VIR_STORAGE_DEFAULT_POOL_PERM_MODE; - if (needs_create_as_uid) - dir_create_flags |= VIR_DIR_CREATE_AS_UID; - - /* 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; + if (virDirPoolBuild(pool->def, needs_create_as_uid) < 0) + return ret; if (flags != 0) { ret = virStorageBackendMakeFileSystem(pool, flags); @@ -869,7 +830,6 @@ virStorageBackendFileSystemBuild(virConnectPtr conn ATTRIBUTE_UNUSED, } error: - VIR_FREE(parent); return ret; } @@ -1054,14 +1014,8 @@ virStorageBackendFileSystemDelete(virConnectPtr conn ATTRIBUTE_UNUSED, /* XXX delete all vols first ? */ - if (rmdir(pool->def->target.path) < 0) { - virReportSystemError(errno, - _("failed to remove pool '%s'"), - pool->def->target.path); - return -1; - } + return virDirPoolDelete(pool->def->target.path); - return 0; } @@ -1084,27 +1038,11 @@ virStorageBackendFileSystemVolCreate(virConnectPtr conn ATTRIBUTE_UNUSED, 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) + if (virDirItemCreate(vol->name, &vol->target.path, + pool->def->target.path) < 0) 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); } diff --git a/src/util/virpoolcommon.c b/src/util/virpoolcommon.c index 3ee6251..f002939 100644 --- a/src/util/virpoolcommon.c +++ b/src/util/virpoolcommon.c @@ -123,3 +123,90 @@ virStoragePoolSourceListNewSource(virPoolSourceListPtr list) return source; } + +int virDirPoolBuild(virPoolDefPtr pooldef, bool needs_create_as_uid) +{ + int ret = -1; + char *parent = NULL; + char *p = NULL; + mode_t mode; + unsigned int dir_create_flags; + + if (VIR_STRDUP(parent, pooldef->target.path) < 0) + goto error; + if (!(p = strrchr(parent, '/'))) { + virReportError(VIR_ERR_INVALID_ARG, + _("path '%s' is not absolute"), + pooldef->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 = pooldef->target.perms.mode; + + if (mode == (mode_t) -1 && + (needs_create_as_uid || !virFileExists(pooldef->target.path))) + mode = VIR_STORAGE_DEFAULT_POOL_PERM_MODE; + if (needs_create_as_uid) + dir_create_flags |= VIR_DIR_CREATE_AS_UID; + + /* 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(pooldef->target.path, + mode, + pooldef->target.perms.uid, + pooldef->target.perms.gid, + dir_create_flags) < 0) + goto error; + ret = 0; + error: + VIR_FREE(parent); + return ret; +} + +int virDirPoolDelete(char *path) +{ + if (rmdir(path) < 0) { + virReportSystemError(errno, + _("failed to remove pool '%s'"), + path); + return -1; + } + + return 0; +} + +int virDirItemCreate(char *name, char **itempath, char *poolpath) +{ + + if (strchr(name, '/')) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("name '%s' cannot contain '/'"), name); + return -1; + } + + if (virAsprintf(itempath, "%s/%s", + poolpath, name) == -1) + return -1; + + if (virFileExists(*itempath)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("target path '%s' already exists"), + *itempath); + return -1; + } + + return 0; +} diff --git a/src/util/virpoolcommon.h b/src/util/virpoolcommon.h index c1c607f..37d642c 100644 --- a/src/util/virpoolcommon.h +++ b/src/util/virpoolcommon.h @@ -25,6 +25,9 @@ # include "virthread.h" # include "virpci.h" + +# define VIR_STORAGE_DEFAULT_POOL_PERM_MODE 0755 + /* * For remote pools, info on how to reach the host */ @@ -179,4 +182,8 @@ void virStoragePoolSourceFree(virPoolSourcePtr source); void virStoragePoolDefFree(virPoolDefPtr def); virPoolSourcePtr virStoragePoolSourceListNewSource(virPoolSourceListPtr list); +/*Common functions fot directory backend*/ +int virDirPoolBuild(virPoolDefPtr pooldef, bool is_ntfs); +int virDirPoolDelete(char *path); +int virDirItemCreate(char *name, char **itempath, char *poolname); # endif /* __VIR_POOL_COMMON_H__ */ -- 1.8.3.1

On 12/02/2016 10:38 AM, Olga Krishtal wrote:
The fs backend for storage pools works a lot with directories and etc. The same is true for filesystem pools with directory backend. In order to avoid rewriting the same code once again patch moves this code to virpoolcommon.c.
I would just say moving this code to virpool.c in order to be shared by future patches which will be adding a new file system storage driver that will share the code.
Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- po/POTFILES.in | 1 + src/libvirt_private.syms | 3 ++ src/storage/storage_backend.h | 1 - src/storage/storage_backend_fs.c | 74 +++------------------------------- src/util/virpoolcommon.c | 87 ++++++++++++++++++++++++++++++++++++++++ src/util/virpoolcommon.h | 7 ++++ 6 files changed, 104 insertions(+), 69 deletions(-)
diff --git a/po/POTFILES.in b/po/POTFILES.in index 1469240..29bc45c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -229,6 +229,7 @@ src/util/virpci.c src/util/virperf.c src/util/virpidfile.c src/util/virpolkit.c +src/util/virpoolcommon.c
Should this have changed in the previous patch?
src/util/virportallocator.c src/util/virprocess.c src/util/virqemu.c diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index a061799..67ebe2a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2709,6 +2709,9 @@ virStoragePoolSourceFree; virStoragePoolSourceDeviceClear; virStoragePoolSourceClear; virStoragePoolSourceListNewSource; +virDirPoolDelete; +virDirItemCreate; +virDirPoolBuild;
Names would all need to start with virPool (see below for my suggestions).
# Let emacs know we want case-insensitive sorting # Local Variables: diff --git a/src/storage/storage_backend.h b/src/storage/storage_backend.h index 28e1a65..a08a725 100644 --- a/src/storage/storage_backend.h +++ b/src/storage/storage_backend.h @@ -214,7 +214,6 @@ int virStorageBackendVolOpen(const char *path, struct stat *sb, ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
-# define VIR_STORAGE_DEFAULT_POOL_PERM_MODE 0755
Keep the above
# define VIR_STORAGE_DEFAULT_VOL_PERM_MODE 0600
int virStorageBackendUpdateVolInfo(virStorageVolDefPtr vol, diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index 6c8bae2..c21fbc8 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -45,6 +45,7 @@ #include "storage_backend_fs.h" #include "storage_conf.h" #include "virstoragefile.h" +#include "virpoolcommon.h" #include "vircommand.h" #include "viralloc.h" #include "virxml.h" @@ -809,11 +810,7 @@ virStorageBackendFileSystemBuild(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned int flags) { int ret = -1; - char *parent = NULL; - char *p = NULL; - mode_t mode; bool needs_create_as_uid; - unsigned int dir_create_flags;
virCheckFlags(VIR_STORAGE_POOL_BUILD_OVERWRITE | VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, ret); @@ -822,45 +819,9 @@ virStorageBackendFileSystemBuild(virConnectPtr conn ATTRIBUTE_UNUSED, 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; needs_create_as_uid = (pool->def->type == VIR_STORAGE_POOL_NETFS); - mode = pool->def->target.perms.mode; - - if (mode == (mode_t) -1 && - (needs_create_as_uid || !virFileExists(pool->def->target.path))) - mode = VIR_STORAGE_DEFAULT_POOL_PERM_MODE; - if (needs_create_as_uid) - dir_create_flags |= VIR_DIR_CREATE_AS_UID; - - /* 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; + if (virDirPoolBuild(pool->def, needs_create_as_uid) < 0)
alter the first parameter to be "&pool->def->target", then pass the default perms VIR_STORAGE_DEFAULT_POOL_PERM_MODE as a 2nd param
+ return ret;
if (flags != 0) { ret = virStorageBackendMakeFileSystem(pool, flags); @@ -869,7 +830,6 @@ virStorageBackendFileSystemBuild(virConnectPtr conn ATTRIBUTE_UNUSED, }
error: - VIR_FREE(parent); return ret; }
@@ -1054,14 +1014,8 @@ virStorageBackendFileSystemDelete(virConnectPtr conn ATTRIBUTE_UNUSED,
/* XXX delete all vols first ? */
- if (rmdir(pool->def->target.path) < 0) { - virReportSystemError(errno, - _("failed to remove pool '%s'"), - pool->def->target.path); - return -1; - } + return virDirPoolDelete(pool->def->target.path);
Perhaps pass the "pool->def->target" since it contains both "path" and "permissions"...
- return 0; }
@@ -1084,27 +1038,11 @@ virStorageBackendFileSystemVolCreate(virConnectPtr conn ATTRIBUTE_UNUSED, 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) + if (virDirItemCreate(vol->name, &vol->target.path, + pool->def->target.path) < 0)
if (!(vol->target.path = virPoolTargetPathCreate(pool->def->target.path, vol->name))) [it'll make sense later]
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); } diff --git a/src/util/virpoolcommon.c b/src/util/virpoolcommon.c index 3ee6251..f002939 100644 --- a/src/util/virpoolcommon.c +++ b/src/util/virpoolcommon.c @@ -123,3 +123,90 @@ virStoragePoolSourceListNewSource(virPoolSourceListPtr list)
return source; } + +int virDirPoolBuild(virPoolDefPtr pooldef, bool needs_create_as_uid)
int virPoolBuildDir(const virPoolTarget *target, mode_t default_mode, bool needs_create_as_uuid) target then be referenced as "target->$FIELD"
+{ + int ret = -1; + char *parent = NULL; + char *p = NULL; + mode_t mode; + unsigned int dir_create_flags; + + if (VIR_STRDUP(parent, pooldef->target.path) < 0) + goto error; + if (!(p = strrchr(parent, '/'))) { + virReportError(VIR_ERR_INVALID_ARG, + _("path '%s' is not absolute"), + pooldef->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 = pooldef->target.perms.mode; + + if (mode == (mode_t) -1 && + (needs_create_as_uid || !virFileExists(pooldef->target.path))) + mode = VIR_STORAGE_DEFAULT_POOL_PERM_MODE;
The default should be passed.
+ if (needs_create_as_uid) + dir_create_flags |= VIR_DIR_CREATE_AS_UID; + + /* 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(pooldef->target.path, + mode, + pooldef->target.perms.uid, + pooldef->target.perms.gid, + dir_create_flags) < 0) + goto error; + ret = 0; + error: + VIR_FREE(parent); + return ret; +} + +int virDirPoolDelete(char *path)
virPoolDeleteDir taking pool as a parameter...
+{ + if (rmdir(path) < 0) {
Hmm... me wonders if this should be virFileRemove instead... In any case, it could take a 'const virPoolTarget *target' and do the magic from there.
+ virReportSystemError(errno, + _("failed to remove pool '%s'"), + path); + return -1; + } + + return 0; +} + +int virDirItemCreate(char *name, char **itempath, char *poolpath)
char * virPoolTargetPathCreate(char *poolpath, char *name)
+{
char *itempath;
+ + if (strchr(name, '/')) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("name '%s' cannot contain '/'"), name); + return -1;
return NULL;
+ } + + if (virAsprintf(itempath, "%s/%s", + poolpath, name) == -1)
if (!(itempath = virFileBuildPath(poolpath, name, NULL))) return NULL;
+ return -1; + + if (virFileExists(*itempath)) {
s/*//
+ virReportError(VIR_ERR_OPERATION_INVALID, + _("target path '%s' already exists"), + *itempath);
s/*//
+ return -1;
VIR_FREE(itempath); (which will set itempath = NULL and...) return itempath; will either be valid or NULL
+ } + + return 0; +} diff --git a/src/util/virpoolcommon.h b/src/util/virpoolcommon.h index c1c607f..37d642c 100644 --- a/src/util/virpoolcommon.h +++ b/src/util/virpoolcommon.h @@ -25,6 +25,9 @@ # include "virthread.h" # include "virpci.h"
+ +# define VIR_STORAGE_DEFAULT_POOL_PERM_MODE 0755 +
This should be passed and not set here as it's block storage driver specific. John
/* * For remote pools, info on how to reach the host */ @@ -179,4 +182,8 @@ void virStoragePoolSourceFree(virPoolSourcePtr source); void virStoragePoolDefFree(virPoolDefPtr def); virPoolSourcePtr virStoragePoolSourceListNewSource(virPoolSourceListPtr list); +/*Common functions fot directory backend*/ +int virDirPoolBuild(virPoolDefPtr pooldef, bool is_ntfs); +int virDirPoolDelete(char *path); +int virDirItemCreate(char *name, char **itempath, char *poolname); # endif /* __VIR_POOL_COMMON_H__ */

Provides public API for fspools and item management. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> Signed-off-by: Maxim Nestratov <mnestratov@virtuozzo.com> --- docs/schemas/fsitem.rng | 66 +++++++++++ docs/schemas/fspool.rng | 82 ++++++++++++++ include/libvirt/libvirt-fs.h | 254 +++++++++++++++++++++++++++++++++++++++++++ include/libvirt/libvirt.h | 1 + src/libvirt_public.syms | 46 ++++++++ 5 files changed, 449 insertions(+) create mode 100644 docs/schemas/fsitem.rng create mode 100644 docs/schemas/fspool.rng create mode 100644 include/libvirt/libvirt-fs.h diff --git a/docs/schemas/fsitem.rng b/docs/schemas/fsitem.rng new file mode 100644 index 0000000..d828978 --- /dev/null +++ b/docs/schemas/fsitem.rng @@ -0,0 +1,66 @@ +<?xml version="1.0"?> +<!-- A Relax NG schema for the libvirt fspool item XML format --> +<grammar xmlns="http://relaxng.org/ns/structure/1.0" + datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> + <include href='basictypes.rng'/> + <start> + <ref name='item'/> + </start> + + <define name='item'> + <element name='fsitem'> + <optional> + <attribute name='type'> + <value>dir</value> + </attribute> + </optional> + <interleave> + <element name='name'> + <ref name='itemName'/> + </element> + <optional> + <element name='key'> + <text/> + </element> + </optional> + <ref name='sizing'/> + <ref name='target'/> + </interleave> + </element> + </define> + + <define name='sizing'> + <interleave> + <optional> + <element name='capacity'> + <ref name='scaledInteger'/> + </element> + </optional> + <optional> + <element name='allocation'> + <ref name='scaledInteger'/> + </element> + </optional> + </interleave> + </define> + + <define name='target'> + <element name='target'> + <interleave> + <optional> + <element name='path'> + <choice> + <data type='anyURI'/> + <ref name='absFilePath'/> + </choice> + </element> + </optional> + <ref name='permissions'/> + <optional> + <ref name='fileFormatFeatures'/> + </optional> + </interleave> + </element> + </define> + +</grammar> diff --git a/docs/schemas/fspool.rng b/docs/schemas/fspool.rng new file mode 100644 index 0000000..33ea0a2 --- /dev/null +++ b/docs/schemas/fspool.rng @@ -0,0 +1,82 @@ +<?xml version="1.0"?> +<!-- A Relax NG schema for the libvirt fspool XML format --> +<grammar xmlns="http://relaxng.org/ns/structure/1.0" + datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> + <include href='basictypes.rng'/> + <start> + <ref name='fspool'/> + </start> + + + <define name='fspool'> + <element name='fspool'> + <choice> + <ref name='fspooldir'/> + </choice> + </element> + </define> + + <define name='fspooldir'> + <attribute name='type'> + <value>dir</value> + </attribute> + <interleave> + <ref name='commonmetadata'/> + <ref name='sizing'/> + <ref name='sourcedir'/> + <ref name='target'/> + </interleave> + </define> + + <define name='commonmetadata'> + <interleave> + <element name='name'> + <ref name='genericName'/> + </element> + <optional> + <element name='uuid'> + <ref name='UUID'/> + </element> + </optional> + </interleave> + </define> + + <define name='sizing'> + <interleave> + <optional> + <element name='capacity'> + <ref name='scaledInteger'/> + </element> + </optional> + <optional> + <element name='allocation'> + <ref name='scaledInteger'/> + </element> + </optional> + <optional> + <element name='available'> + <ref name='scaledInteger'/> + </element> + </optional> + </interleave> + </define> + + <define name='target'> + <element name='target'> + <interleave> + <element name='path'> + <ref name='absFilePath'/> + </element> + <ref name='permissions'/> + </interleave> + </element> + </define> + + <define name='sourcedir'> + <optional> + <element name='source'> + </element> + </optional> + </define> + +</grammar> diff --git a/include/libvirt/libvirt-fs.h b/include/libvirt/libvirt-fs.h new file mode 100644 index 0000000..1668000 --- /dev/null +++ b/include/libvirt/libvirt-fs.h @@ -0,0 +1,254 @@ +/* libvirt-fs.h + * Summary: APIs for management of filesystem pools and items + * Description: Provides APIs for the management of filesystem pools and items + * Author: Olga Krishtal <okrishtal@virtuozzo.com> + * + * Copyright (C) 2016 Parallels IP Holdings GmbH + * + * 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_LIBVIRT_FS_H__ +# define __VIR_LIBVIRT_FS_H__ + +# ifndef __VIR_LIBVIRT_H_INCLUDES__ +# error "Don't include this file directly, only use libvirt/libvirt.h" +# endif + +typedef enum { + VIR_FSPOOL_CREATE_NORMAL = 0, + + /* Create the fspool and perform fspool build using the + * exclusive to VIR_FSPOOL_CREATE_WITH_BUILD_NO_OVERWRITE */ + VIR_FSPOOL_CREATE_WITH_BUILD_OVERWRITE = 1 << 0, + + /* Create the pool and perform pool build using the + * VIR_FSPOOL_BUILD_NO_OVERWRITE flag. This is mutually + * exclusive to VIR_FSPOOL_CREATE_WITH_BUILD_OVERWRITE */ + VIR_FSPOOL_CREATE_WITH_BUILD_NO_OVERWRITE = 1 << 1, +} virFSPoolCreateFlags; + +typedef enum { + VIR_FSPOOL_BUILD_NO_OVERWRITE = (1 << 2), /* Do not overwrite existing pool */ + VIR_FSPOOL_BUILD_OVERWRITE = (1 << 3), /* Overwrite data */ +} virFSPoolBuildFlags; + +/** + * virFSPool: + * + * a virFSPool is a private structure representing a fspool + */ +typedef struct _virPoolCommon virFSPool; + +/** + * virFSPoolPtr: + * + * a virFSPoolPtr is pointer to a virFSPool private structure, this is the + * type used to reference a fspool in the API. + */ +typedef virFSPool *virFSPoolPtr; + +typedef enum { + VIR_FSPOOL_INACTIVE = 0, + VIR_FSPOOL_BUILDING = 1, + VIR_FSPOOL_RUNNING = 2, + +# ifdef VIR_ENUM_SENTINELS + VIR_FSPOOL_STATE_LAST +# endif +} virFSPoolState; + +typedef struct _virFSPoolInfo virFSPoolInfo; + +struct _virFSPoolInfo { + int state; /* virFSPoolState flags */ + unsigned long long capacity; /* Logical size bytes */ + unsigned long long allocation; /* Current allocation bytes */ + unsigned long long available; /* Remaining free space bytes */ +}; + +typedef virFSPoolInfo *virFSPoolInfoPtr; + +/** + * virFSItem: + * + * a virFSItem is a private structure representing a fspool item + */ +typedef struct _virItemCommon virFSItem; + +/** + * virFSItemPtr: + * + * a virFSItemPtr is pointer to a virFSItem private structure, this is the + * type used to reference a fspool item in the API. + */ +typedef virFSItem *virFSItemPtr; + +typedef struct _virFSItemInfo virFSItemInfo; + +typedef enum { + VIR_FSITEM_DIR = 0, + VIR_FSITEM_LAST +} virFSItemType; + +struct _virFSItemInfo { + int type; /* virFSItemType flags */ + unsigned long long capacity; /* Logical size bytes */ + unsigned long long allocation; /* Current allocation bytes */ +}; + +typedef virFSItemInfo *virFSItemInfoPtr; +/* + * Get connection from fspool. + */ +virConnectPtr virFSPoolGetConnect(virFSPoolPtr fspool); + + +/* + * virConnectListAllFSPoolsFlags: + * + * Flags used to tune fspools returned by virConnectListAllFSPools(). + * Note that these flags come in groups; if all bits from a group are 0, + * then that group is not used to filter results. + */ +typedef enum { + VIR_CONNECT_LIST_FSPOOLS_INACTIVE = 1 << 0, + VIR_CONNECT_LIST_FSPOOLS_ACTIVE = 1 << 1, + + VIR_CONNECT_LIST_FSPOOLS_PERSISTENT = 1 << 2, + VIR_CONNECT_LIST_FSPOOLS_TRANSIENT = 1 << 3, + + VIR_CONNECT_LIST_FSPOOLS_AUTOSTART = 1 << 4, + VIR_CONNECT_LIST_FSPOOLS_NO_AUTOSTART = 1 << 5, + + /* List fspools by type */ + VIR_CONNECT_LIST_FSPOOLS_DIR = 1 << 6, +} virConnectListAllFSPoolsFlags; + +typedef enum { + VIR_FS_XML_INACTIVE = (1 << 0), /* dump inactive fspool/item information */ +} virFsXMLFlags; + + +int virConnectListAllFSPools(virConnectPtr conn, + virFSPoolPtr **fspools, + unsigned int flags); + +/* + * Lookup fspool by name or uuid + */ + +virFSPoolPtr virFSPoolLookupByName(virConnectPtr conn, + const char *name); +virFSPoolPtr virFSPoolLookupByUUID(virConnectPtr conn, + const unsigned char *uuid); +virFSPoolPtr virFSPoolLookupByUUIDString(virConnectPtr conn, + const char *uuid); +virFSPoolPtr virFSPoolLookupByItem(virFSItemPtr item); + + +/* + * Creating/destroying fspools + */ +virFSPoolPtr virFSPoolCreateXML(virConnectPtr conn, + const char *xmlDesc, + unsigned int flags); +virFSPoolPtr virFSPoolDefineXML(virConnectPtr conn, + const char *xmlDesc, + unsigned int flags); +int virFSPoolBuild(virFSPoolPtr fspool, + unsigned int flags); +int virFSPoolRefresh(virFSPoolPtr fspool, + unsigned int flags); +int virFSPoolUndefine(virFSPoolPtr fspool); +int virFSPoolCreate(virFSPoolPtr fspool, + unsigned int flags); +int virFSPoolDestroy(virFSPoolPtr fspool); +int virFSPoolDelete(virFSPoolPtr fspool, + unsigned int flags); +int virFSPoolRefresh(virFSPoolPtr fspool, + unsigned int flags); +int virFSPoolRef(virFSPoolPtr fspool); +int virFSPoolFree(virFSPoolPtr fspool); + +/* + * FSPool information + */ +const char * virFSPoolGetName(virFSPoolPtr fspool); +int virFSPoolGetUUID(virFSPoolPtr fspool, + unsigned char *uuid); +int virFSPoolGetUUIDString(virFSPoolPtr fspool, + char *buf); + +int virFSPoolGetInfo(virFSPoolPtr pool, + virFSPoolInfoPtr info); + +char * virFSPoolGetXMLDesc(virFSPoolPtr fspool, + unsigned int flags); +int virFSPoolGetAutostart(virFSPoolPtr fspool, + int *autostart); +int virFSPoolSetAutostart(virFSPoolPtr fspool, + int autostart); + + +/* + * List/lookup fs items within a fspool + */ +int virFSPoolNumOfItems(virFSPoolPtr fspool); +int virFSPoolListItems(virFSPoolPtr fspool, + char **const names, + int maxnames); +int virFSPoolListAllItems(virFSPoolPtr fspool, + virFSItemPtr **items, + unsigned int flags); + +virConnectPtr virFSItemGetConnect(virFSItemPtr item); + +/* + * Lookup items based on various attributes + */ +virFSItemPtr virFSItemLookupByName(virFSPoolPtr fspool, + const char *name); +virFSItemPtr virFSItemLookupByKey(virConnectPtr conn, + const char *key); +virFSItemPtr virFSItemLookupByPath(virConnectPtr conn, + const char *path); + + +const char * virFSItemGetName(virFSItemPtr item); +const char * virFSItemGetKey(virFSItemPtr item); + +virFSItemPtr virFSItemCreateXML(virFSPoolPtr fspool, + const char *xmldesc, + unsigned int flags); +virFSItemPtr virFSItemCreateXMLFrom(virFSPoolPtr fspool, + const char *xmldesc, + virFSItemPtr cloneitem, + unsigned int flags); + +int virFSItemDelete(virFSItemPtr item, + unsigned int flags); +int virFSItemRef(virFSItemPtr item); +int virFSItemFree(virFSItemPtr item); + +int virFSItemGetInfo(virFSItemPtr item, + virFSItemInfoPtr info); +char * virFSItemGetXMLDesc(virFSItemPtr item, + unsigned int flags); + +char * virFSItemGetPath(virFSItemPtr item); + +int virFSPoolIsActive(virFSPoolPtr fspool); +int virFSPoolIsPersistent(virFSPoolPtr fspool); + +#endif /* __VIR_LIBVIRT_FS_H__ */ diff --git a/include/libvirt/libvirt.h b/include/libvirt/libvirt.h index 36f6d60..665414b 100644 --- a/include/libvirt/libvirt.h +++ b/include/libvirt/libvirt.h @@ -45,6 +45,7 @@ extern "C" { # include <libvirt/libvirt-secret.h> # include <libvirt/libvirt-storage.h> # include <libvirt/libvirt-stream.h> +# include <libvirt/libvirt-fs.h> # undef __VIR_LIBVIRT_H_INCLUDES__ # ifdef __cplusplus diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index e01604c..f938883 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -746,4 +746,50 @@ LIBVIRT_2.2.0 { virConnectNodeDeviceEventDeregisterAny; } LIBVIRT_2.0.0; +LIBVIRT_2.5.0 { + global: + virFSPoolGetConnect; + virConnectListAllFSPools; + virFSPoolListAllItems; + virFSPoolLookupByName; + virFSPoolLookupByUUID; + virFSPoolLookupByUUIDString; + virFSPoolLookupByItem; + virFSPoolCreateXML; + virFSPoolDefineXML; + virFSPoolUndefine; + virFSPoolCreate; + virFSPoolBuild; + virFSPoolDestroy; + virFSPoolDelete; + virFSPoolRefresh; + virFSPoolFree; + virFSPoolGetName; + virFSPoolGetUUID; + virFSPoolGetUUIDString; + virFSPoolGetInfo; + virFSPoolGetXMLDesc; + virFSPoolSetAutostart; + virFSPoolGetAutostart; + virFSPoolNumOfItems; + virFSPoolListItems; + virFSPoolRef; + virFSItemRef; + virFSItemCreateXMLFrom; + virFSItemGetConnect; + virFSItemLookupByName; + virFSItemLookupByKey; + virFSItemLookupByPath; + virFSItemCreateXML; + virFSItemDelete; + virFSItemFree; + virFSItemGetName; + virFSItemGetKey; + virFSItemGetInfo; + virFSItemGetXMLDesc; + virFSItemGetPath; + virFSPoolIsActive; + virFSPoolIsPersistent; +} LIBVIRT_2.2.0; + # .... define new API here using predicted next version number .... -- 1.8.3.1

This patch introduces new filesystem pool driver. Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- src/driver-fs.h | 193 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/driver.h | 1 + 2 files changed, 194 insertions(+) create mode 100644 src/driver-fs.h diff --git a/src/driver-fs.h b/src/driver-fs.h new file mode 100644 index 0000000..ba35ec2 --- /dev/null +++ b/src/driver-fs.h @@ -0,0 +1,193 @@ +/* +* driver-fs.h: entry points for fs drivers +* Author: Olga Krishtal <okrishtal@virtuozzo.com> +* +* Copyright (C) 2016 Parallels IP Holdings GmbH +* +* 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_DRIVER_FS_H__ +# define __VIR_DRIVER_FS_H__ + +# ifndef __VIR_DRIVER_H_INCLUDES___ +# error "Don't include this file directly, only use driver.h" +# endif + +typedef int +(*virDrvConnectListAllFSPools)(virConnectPtr conn, + virFSPoolPtr **pools, + unsigned int flags); + +typedef virFSPoolPtr +(*virDrvFSPoolLookupByName)(virConnectPtr conn, + const char *name); + +typedef virFSPoolPtr +(*virDrvFSPoolLookupByUUID)(virConnectPtr conn, + const unsigned char *uuid); + +typedef virFSPoolPtr +(*virDrvFSPoolLookupByItem)(virFSItemPtr item); + +typedef virFSPoolPtr +(*virDrvFSPoolCreateXML)(virConnectPtr conn, + const char *xmlDesc, + unsigned int flags); + +typedef virFSPoolPtr +(*virDrvFSPoolDefineXML)(virConnectPtr conn, + const char *xmlDesc, + unsigned int flags); + +typedef int +(*virDrvFSPoolUndefine)(virFSPoolPtr fspool); + +typedef int +(*virDrvFSPoolBuild)(virFSPoolPtr fspool, + unsigned int flags); + +typedef int +(*virDrvFSPoolCreate)(virFSPoolPtr fspool, + unsigned int flags); +typedef int +(*virDrvFSPoolDestroy)(virFSPoolPtr fspool); +typedef int +(*virDrvFSPoolRefresh)(virFSPoolPtr fspool, + unsigned int flags); + +typedef int +(*virDrvFSPoolDelete)(virFSPoolPtr fspool, + unsigned int flags); + +typedef int +(*virDrvFSPoolGetInfo)(virFSPoolPtr fspool, + virFSPoolInfoPtr info); + +typedef char * +(*virDrvFSPoolGetXMLDesc)(virFSPoolPtr fspool, + unsigned int flags); +typedef int +(*virDrvFSPoolGetAutostart)(virFSPoolPtr fspool, + int *autostart); +typedef int +(*virDrvFSPoolSetAutostart)(virFSPoolPtr fspool, + int autostart); + +typedef int +(*virDrvFSPoolNumOfItems)(virFSPoolPtr fspool); + +typedef int +(*virDrvFSPoolListItems)(virFSPoolPtr fspool, + char **const names, + int maxnames); + +typedef int +(*virDrvFSPoolListAllItems)(virFSPoolPtr fspool, + virFSItemPtr **items, + unsigned int flags); + +typedef virFSItemPtr +(*virDrvFSItemLookupByName)(virFSPoolPtr fspool, + const char *name); + +typedef virFSItemPtr +(*virDrvFSItemLookupByKey)(virConnectPtr fspool, + const char *key); + +typedef virFSItemPtr +(*virDrvFSItemLookupByPath)(virConnectPtr fspool, + const char *path); + +typedef virFSItemPtr +(*virDrvFSItemCreateXML)(virFSPoolPtr fspool, + const char *xmldesc, + unsigned int flags); + +typedef int +(*virDrvFSItemDelete)(virFSItemPtr item, + unsigned int flags); + + +typedef int +(*virDrvFSItemGetInfo)(virFSItemPtr item, + virFSItemInfoPtr info); + +typedef char * +(*virDrvFSItemGetXMLDesc)(virFSItemPtr fspool, + unsigned int flags); + +typedef char * +(*virDrvFSItemGetPath)(virFSItemPtr item); + +typedef virFSItemPtr +(*virDrvFSItemCreateXMLFrom)(virFSPoolPtr fspool, + const char *xmldesc, + virFSItemPtr cloneitem, + unsigned int flags); + +typedef struct _virFSDriver virFSDriver; +typedef virFSDriver *virFSDriverPtr; + +typedef int +(*virDrvFSPoolIsActive)(virFSPoolPtr fspool); + +typedef int +(*virDrvFSPoolIsPersistent)(virFSPoolPtr fspool); + + + +/** + * _virFSDriver: + * + * Structure associated to a storage driver, defining the various + * entry points for it. + */ +struct _virFSDriver { + const char *name; /* the name of the driver */ + virDrvConnectListAllFSPools connectListAllFSPools; + virDrvFSPoolLookupByName fsPoolLookupByName; + virDrvFSPoolLookupByUUID fsPoolLookupByUUID; + virDrvFSPoolLookupByItem fsPoolLookupByItem; + virDrvFSPoolCreateXML fsPoolCreateXML; + virDrvFSPoolDefineXML fsPoolDefineXML; + virDrvFSPoolBuild fsPoolBuild; + virDrvFSPoolUndefine fsPoolUndefine; + virDrvFSPoolCreate fsPoolCreate; + virDrvFSPoolDestroy fsPoolDestroy; + virDrvFSPoolDelete fsPoolDelete; + virDrvFSPoolRefresh fsPoolRefresh; + virDrvFSPoolGetInfo fsPoolGetInfo; + virDrvFSPoolGetXMLDesc fsPoolGetXMLDesc; + virDrvFSPoolGetAutostart fsPoolGetAutostart; + virDrvFSPoolSetAutostart fsPoolSetAutostart; + virDrvFSPoolNumOfItems fsPoolNumOfItems; + virDrvFSPoolListItems fsPoolListItems; + virDrvFSPoolListAllItems fsPoolListAllItems; + virDrvFSItemLookupByName fsItemLookupByName; + virDrvFSItemLookupByKey fsItemLookupByKey; + virDrvFSItemLookupByPath fsItemLookupByPath; + virDrvFSItemCreateXML fsItemCreateXML; + virDrvFSItemCreateXMLFrom fsItemCreateXMLFrom; + virDrvFSItemDelete fsItemDelete; + virDrvFSItemGetInfo fsItemGetInfo; + virDrvFSItemGetXMLDesc fsItemGetXMLDesc; + virDrvFSItemGetPath fsItemGetPath; + virDrvFSPoolIsActive fsPoolIsActive; + virDrvFSPoolIsPersistent fsPoolIsPersistent; +}; + + +#endif /* __VIR_DRIVER_FS_H__ */ diff --git a/src/driver.h b/src/driver.h index e4e382b..fb93083 100644 --- a/src/driver.h +++ b/src/driver.h @@ -72,6 +72,7 @@ typedef enum { # include "driver-state.h" # include "driver-stream.h" # include "driver-storage.h" +# include "driver-fs.h" # undef __VIR_DRIVER_H_INCLUDES___ -- 1.8.3.1

Implementation of driver API and basic structs defenition Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- include/libvirt/virterror.h | 7 + po/POTFILES.in | 1 + src/conf/fs_conf.h | 159 +++++ src/datatypes.c | 150 +++++ src/datatypes.h | 56 ++ src/driver.h | 2 + src/libvirt-fs.c | 1555 +++++++++++++++++++++++++++++++++++++++++++ src/libvirt.c | 30 +- src/libvirt_private.syms | 4 +- src/util/virerror.c | 37 + 10 files changed, 1999 insertions(+), 2 deletions(-) create mode 100644 src/conf/fs_conf.h create mode 100644 src/libvirt-fs.c diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index efe83aa..677812e 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -132,6 +132,7 @@ typedef enum { VIR_FROM_PERF = 65, /* Error from perf */ + VIR_FROM_FSPOOL = 66, /* Error from FS pool */ # ifdef VIR_ENUM_SENTINELS VIR_ERR_DOMAIN_LAST # endif @@ -317,6 +318,12 @@ typedef enum { VIR_ERR_NO_CLIENT = 96, /* Client was not found */ VIR_ERR_AGENT_UNSYNCED = 97, /* guest agent replies with wrong id to guest-sync command */ + VIR_ERR_INVALID_FSPOOL = 98, /* invalid fspool object */ + VIR_ERR_INVALID_FSITEM = 99, /* invalid fspool object */ + VIR_WAR_NO_FSPOOL = 100, /* failed to start fspool */ + VIR_ERR_NO_FSPOOL = 101, /* fspool not found */ + VIR_ERR_NO_FSITEM = 102, /* fstem not found */ + VIR_ERR_FSITEM_EXIST = 103, /* fspool item already exists */ } virErrorNumber; /** diff --git a/po/POTFILES.in b/po/POTFILES.in index 29bc45c..0c9b3e4 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -68,6 +68,7 @@ src/internal.h src/libvirt-admin.c src/libvirt-domain-snapshot.c src/libvirt-domain.c +src/libvirt-fs.c src/libvirt-host.c src/libvirt-lxc.c src/libvirt-network.c diff --git a/src/conf/fs_conf.h b/src/conf/fs_conf.h new file mode 100644 index 0000000..4f05659 --- /dev/null +++ b/src/conf/fs_conf.h @@ -0,0 +1,159 @@ +/* + * fs_conf.h: config handling for fs driver + * Author: Olga Krishtal <okrishtal@virtuozzo.com> + * + * Copyright (C) 2016 Parallels IP Holdings GmbH + * + * 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_FS_CONF_H__ +# define __VIR_FS_CONF_H__ + +# include "internal.h" +# include "virbitmap.h" +# include "virthread.h" +# include "virutil.h" +# include "virpoolcommon.h" +# include "virstoragefile.h" +# include <libxml/tree.h> + +# define VIR_CONNECT_LIST_FSPOOLS_FILTERS_POOL_TYPE \ + VIR_CONNECT_LIST_FSPOOLS_DIR + +# define VIR_CONNECT_LIST_FSPOOLS_FILTERS_ACTIVE \ + (VIR_CONNECT_LIST_FSPOOLS_ACTIVE | \ + VIR_CONNECT_LIST_FSPOOLS_INACTIVE) + +# define VIR_CONNECT_LIST_FSPOOLS_FILTERS_PERSISTENT \ + (VIR_CONNECT_LIST_FSPOOLS_PERSISTENT | \ + VIR_CONNECT_LIST_FSPOOLS_TRANSIENT) + +# define VIR_CONNECT_LIST_FSPOOLS_FILTERS_AUTOSTART \ + (VIR_CONNECT_LIST_FSPOOLS_AUTOSTART | \ + VIR_CONNECT_LIST_FSPOOLS_NO_AUTOSTART) + +# define VIR_CONNECT_LIST_FSPOOLS_FILTERS_ALL \ + (VIR_CONNECT_LIST_FSPOOLS_FILTERS_ACTIVE | \ + VIR_CONNECT_LIST_FSPOOLS_FILTERS_PERSISTENT | \ + VIR_CONNECT_LIST_FSPOOLS_FILTERS_AUTOSTART | \ + VIR_CONNECT_LIST_FSPOOLS_FILTERS_POOL_TYPE) + +VIR_ENUM_DECL(virFSItem) +VIR_ENUM_DECL(virFS) + +typedef struct _virFSSourcePoolDef virFSSourcePoolDef; +typedef virFSSourcePoolDef *virFSSourcePoolDefPtr; +struct _virFSSourcePoolDef { + char *pool; /* pool name */ + char *item; /* item name */ + int itemtype; /* virFSItemType, internal only */ + int pooltype; /* virFSPoolType internal only */ +}; + +typedef struct _virStorageSource virFSSource; +typedef virFSSource *virFSSourcePtr; + +typedef enum { + VIR_FSPOOL_DIR, /* Local directory */ + VIR_FSPOOL_LAST, +} virFSPoolType; + +VIR_ENUM_DECL(virFSPool) + +typedef struct _virFSItemDef virFSItemDef; +typedef virFSItemDef *virFSItemDefPtr; +struct _virFSItemDef { + char *name; + char *key; + int type;/* * virStorageVolType */ + + bool building; + unsigned int in_use; + virStorageSource target; +}; + +typedef struct _virFSItemDefList virFSItemDefList; +typedef virFSItemDefList *virFSItemDefListPtr; +struct _virFSItemDefList { + size_t count; + virFSItemDefPtr *objs; +}; + +typedef virPoolSource virFSPoolSource; +typedef virFSPoolSource *virFSPoolSourcePtr; + +typedef virPoolTarget virFSPoolTarget; +typedef virFSPoolTarget *virFSPoolTargetPtr; + +typedef virPoolDef virFSPoolDef; +typedef virFSPoolDef *virFSPoolDefPtr; + +typedef struct _virFSPoolObj virFSPoolObj; +typedef virFSPoolObj *virFSPoolObjPtr; +struct _virFSPoolObj { + virMutex lock; + + char *configFile; + char *autostartLink; + bool active; + int autostart; + unsigned int asyncjobs; + + virPoolDefPtr def; + virPoolDefPtr newDef; + virFSItemDefList items; +}; + +typedef struct _virFSPoolObjList virFSPoolObjList; +typedef virFSPoolObjList *virFSPoolObjListPtr; +struct _virFSPoolObjList { + size_t count; + virFSPoolObjPtr *objs; +}; + +typedef struct _virFSDriverState virFSDriverState; +typedef virFSDriverState *virFSDriverStatePtr; + +struct _virFSDriverState { + virMutex lock; + + virFSPoolObjList fspools; + + char *configDir; + char *autostartDir; + char *stateDir; + bool privileged; +}; + +typedef struct _virFSPoolSourceList virFSPoolSourceList; +typedef virFSPoolSourceList *virFSPoolSourceListPtr; +struct _virFSPoolSourceList { + int type; + unsigned int nsources; + virPoolSourcePtr sources; +}; + +typedef bool (*virFSPoolObjListFilter)(virConnectPtr conn, + virFSPoolDefPtr def); + +static inline int +virFSPoolObjIsActive(virFSPoolObjPtr fspool) +{ + return fspool->active; +} + + +#endif /* __VIR_FS_CONF_H__ */ diff --git a/src/datatypes.c b/src/datatypes.c index ff0c46f..33844d7 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -45,6 +45,8 @@ virClassPtr virSecretClass; virClassPtr virStreamClass; virClassPtr virStorageVolClass; virClassPtr virStoragePoolClass; +virClassPtr virFSPoolClass; +virClassPtr virFSItemClass; static void virConnectDispose(void *obj); static void virConnectCloseCallbackDataDispose(void *obj); @@ -58,6 +60,8 @@ static void virSecretDispose(void *obj); static void virStreamDispose(void *obj); static void virStorageVolDispose(void *obj); static void virStoragePoolDispose(void *obj); +static void virFSItemDispose(void *obj); +static void virFSPoolDispose(void *obj); virClassPtr virAdmConnectClass; virClassPtr virAdmConnectCloseCallbackDataClass; @@ -102,6 +106,8 @@ virDataTypesOnceInit(void) DECLARE_CLASS(virAdmServer); DECLARE_CLASS(virAdmClient); + DECLARE_CLASS(virFSPool); + DECLARE_CLASS(virFSItem); #undef DECLARE_CLASS_COMMON #undef DECLARE_CLASS_LOCKABLE #undef DECLARE_CLASS @@ -597,6 +603,150 @@ virStorageVolDispose(void *obj) virObjectUnref(vol->conn); } +/** + * virGetFSPool: + * @conn: the hypervisor connection + * @name: pointer to the FSpool name + * @uuid: pointer to the uuid + * @privateData: pointer to driver specific private data + * @freeFunc: private data cleanup function pointer specific to driver + * + * Allocates a new FS pool object. When the object is no longer needed, + * virObjectUnref() must be called in order to not leak data. + * + * Returns a pointer to the storage pool object, or NULL on error. + */ +virFSPoolPtr +virGetFSPool(virConnectPtr conn, const char *name, + const unsigned char *uuid, + void *privateData, virFreeCallback freeFunc) +{ + virFSPoolPtr ret = NULL; + + if (virDataTypesInitialize() < 0) + return NULL; + + virCheckConnectGoto(conn, error); + virCheckNonNullArgGoto(name, error); + virCheckNonNullArgGoto(uuid, error); + + if (!(ret = virObjectNew(virFSPoolClass))) + goto error; + + if (VIR_STRDUP(ret->name, name) < 0) + goto error; + + ret->conn = virObjectRef(conn); + memcpy(&(ret->uuid[0]), uuid, VIR_UUID_BUFLEN); + + /* set the driver specific data */ + ret->privateData = privateData; + ret->privateDataFreeFunc = freeFunc; + + return ret; + + error: + virObjectUnref(ret); + return NULL; +} + +/** + * virGetFSItem: + * @conn: the hypervisor connection + * @fspool: fspool owning the item + * @name: pointer to the fsitem name + * @key: pointer to unique key of the fsitem + * @privateData: pointer to driver specific private data + * @freeFunc: private data cleanup function pointer specific to driver + * + * Allocates a new fsitem object. When the object is no longer needed, + * virObjectUnref() must be called in order to not leak data. + * + * Returns a pointer to the fsitem object, or NULL on error. + */ +virFSItemPtr +virGetFSItem(virConnectPtr conn, const char *fspool, const char *name, + const char *key, void *privateData, virFreeCallback freeFunc) +{ + virFSItemPtr ret = NULL; + + if (virDataTypesInitialize() < 0) + return NULL; + + virCheckConnectGoto(conn, error); + virCheckNonNullArgGoto(fspool, error); + virCheckNonNullArgGoto(name, error); + virCheckNonNullArgGoto(key, error); + + if (!(ret = virObjectNew(virFSItemClass))) + goto error; + + if (VIR_STRDUP(ret->pool, fspool) < 0 || + VIR_STRDUP(ret->name, name) < 0 || + VIR_STRDUP(ret->key, key) < 0) + goto error; + + ret->conn = virObjectRef(conn); + + /* set driver specific data */ + ret->privateData = privateData; + ret->privateDataFreeFunc = freeFunc; + + return ret; + + error: + virObjectUnref(ret); + return NULL; +} + +/** + * virFSPoolDispose: + * @obj: the filesystem pool to release + * + * It will also unreference the associated connection object, + * which may also be released if its ref count hits zero. + */ +static void +virFSPoolDispose(void *obj) +{ + virFSPoolPtr fspool = obj; + char uuidstr[VIR_UUID_STRING_BUFLEN]; + + virUUIDFormat(fspool->uuid, uuidstr); + VIR_DEBUG("release filesystem pool %p %s %s", + fspool, fspool->name, uuidstr); + + if (fspool->privateDataFreeFunc) + fspool->privateDataFreeFunc(fspool->privateData); + + VIR_FREE(fspool->name); + virObjectUnref(fspool->conn); +} + +/** + * virFSItemDispose: + * @obj: the filesystem pool item to release + * + * Unconditionally release all memory associated with an item. + * The object must not be used once this method returns. + * + * It will also unreference the associated connection object, + * which may also be released if its ref count hits zero. + */ +static void +virFSItemDispose(void *obj) +{ + virFSItemPtr item = obj; + VIR_DEBUG("release item %p %s", item, item->name); + + if (item->privateDataFreeFunc) + item->privateDataFreeFunc(item->privateData); + + VIR_FREE(item->key); + VIR_FREE(item->name); + VIR_FREE(item->pool); + virObjectUnref(item->conn); +} /** * virGetNodeDevice: diff --git a/src/datatypes.h b/src/datatypes.h index 1eaf4c6..dfedbd1 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -40,6 +40,8 @@ extern virClassPtr virSecretClass; extern virClassPtr virStreamClass; extern virClassPtr virStorageVolClass; extern virClassPtr virStoragePoolClass; +extern virClassPtr virFSItemClass; +extern virClassPtr virFSPoolClass; extern virClassPtr virAdmConnectClass; extern virClassPtr virAdmServerClass; @@ -278,6 +280,47 @@ extern virClassPtr virAdmClientClass; } \ } while (0) +# define virCheckFSPoolReturn(obj, retval) \ + do { \ + virFSPoolPtr _pool = (obj); \ + if (!virObjectIsClass(_pool, virFSPoolClass) || \ + !virObjectIsClass(_pool->conn, virConnectClass)) { \ + virReportErrorHelper(VIR_FROM_FSPOOL, \ + VIR_ERR_INVALID_FSPOOL, \ + __FILE__, __FUNCTION__, __LINE__, \ + __FUNCTION__); \ + virDispatchError(NULL); \ + return retval; \ + } \ + } while (0) + +# define virCheckFSItemReturn(obj, retval) \ + do { \ + virFSItemPtr _item = (obj); \ + if (!virObjectIsClass(_item, virFSItemClass) || \ + !virObjectIsClass(_item->conn, virConnectClass)) { \ + virReportErrorHelper(VIR_FROM_FSPOOL, \ + VIR_ERR_INVALID_FSITEM, \ + __FILE__, __FUNCTION__, __LINE__, \ + __FUNCTION__); \ + virDispatchError(NULL); \ + return retval; \ + } \ + } while (0) + +# define virCheckFSItemGoto(obj, label) \ + do { \ + virFSItemPtr _item = (obj); \ + if (!virObjectIsClass(_item, virFSItemClass) || \ + !virObjectIsClass(_item->conn, virConnectClass)) { \ + virReportErrorHelper(VIR_FROM_FSPOOL, \ + VIR_ERR_INVALID_FSITEM, \ + __FILE__, __FUNCTION__, __LINE__, \ + __FUNCTION__); \ + goto label; \ + } \ + } while (0) + /* Helper macros to implement VIR_DOMAIN_DEBUG using just C99. This * assumes you pass fewer than 15 arguments to VIR_DOMAIN_DEBUG, but @@ -457,6 +500,7 @@ struct _virConnect { virNodeDeviceDriverPtr nodeDeviceDriver; virSecretDriverPtr secretDriver; virNWFilterDriverPtr nwfilterDriver; + virFSDriverPtr fsDriver; /* Private data pointer which can be used by driver and * network driver as they wish. @@ -710,6 +754,18 @@ virAdmClientPtr virAdmGetClient(virAdmServerPtr srv, unsigned long long timestamp, unsigned int transport); +virFSPoolPtr virGetFSPool(virConnectPtr conn, + const char *name, + const unsigned char *uuid, + void *privateData, + virFreeCallback freeFunc); +virFSItemPtr virGetFSItem(virConnectPtr conn, + const char *pool, + const char *name, + const char *key, + void *privateData, + virFreeCallback freeFunc); + virConnectCloseCallbackDataPtr virNewConnectCloseCallbackData(void); void virConnectCloseCallbackDataRegister(virConnectCloseCallbackDataPtr close, virConnectPtr conn, diff --git a/src/driver.h b/src/driver.h index fb93083..07cb3fb 100644 --- a/src/driver.h +++ b/src/driver.h @@ -87,6 +87,7 @@ struct _virConnectDriver { virNWFilterDriverPtr nwfilterDriver; virSecretDriverPtr secretDriver; virStorageDriverPtr storageDriver; + virFSDriverPtr fsDriver; }; int virRegisterConnectDriver(virConnectDriverPtr driver, @@ -99,6 +100,7 @@ int virSetSharedNodeDeviceDriver(virNodeDeviceDriverPtr driver) ATTRIBUTE_RETURN int virSetSharedNWFilterDriver(virNWFilterDriverPtr driver) ATTRIBUTE_RETURN_CHECK; int virSetSharedSecretDriver(virSecretDriverPtr driver) ATTRIBUTE_RETURN_CHECK; int virSetSharedStorageDriver(virStorageDriverPtr driver) ATTRIBUTE_RETURN_CHECK; +int virSetSharedFSDriver(virFSDriverPtr driver) ATTRIBUTE_RETURN_CHECK; void *virDriverLoadModule(const char *name); diff --git a/src/libvirt-fs.c b/src/libvirt-fs.c new file mode 100644 index 0000000..4b7092b --- /dev/null +++ b/src/libvirt-fs.c @@ -0,0 +1,1555 @@ +/* + * libvirt-fs.c: entry points for virFS{Pool, Item}Ptr APIs + * Author: Olga Krishtal <okrishtal@virtuozzo.com> + * + * Copyright (C) 2016 Parallels IP Holdings GmbH + * + * 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/>. + */ + +#include <config.h> + +#include "datatypes.h" +#include "virlog.h" + +VIR_LOG_INIT("libvirt.fs"); + +#define VIR_FROM_THIS VIR_FROM_FSPOOL + + +/** + * virFSPoolGetConnect: + * @fspool: pointer to a fspool + * + * Provides the connection pointer associated with fspool. The + * reference counter on the connection is not increased by this + * call. + * Returns the virConnectPtr or NULL in case of failure. + */ +virConnectPtr +virFSPoolGetConnect(virFSPoolPtr fspool) +{ + VIR_DEBUG("fspool=%p", fspool); + + virResetLastError(); + + virCheckFSPoolReturn(fspool, NULL); + + return fspool->conn; +} + + +/** + * virConnectListAllFSPools: + * @conn: Pointer to the hypervisor connection. + * @fspools: Pointer to a variable to store the array containing fspool + * objects or NULL if the list is not required (just returns number + * of fspools). + * @flags: bitwise-OR of virConnectListAllFSPoolsFlags. + * + * Collect the list of fspools, and allocate an array to store those + * objects. This API solves the race inherent between + * virConnectListFSPools and virConnectListDefinedFSPools. + * + * Normally, all fspools are returned; however, @flags can be used to + * filter the results for a smaller list of targeted fspools. The valid + * flags are divided into groups, where each group contains bits that + * describe mutually exclusive attributes of a fspool, and where all bits + * within a group describe all possible fspools. + * + * The only group (at the moment) of @flags is provided to filter the + * fspools by the types, + * the flags include: + * VIR_CONNECT_LIST_FSPOOLS_DIR + * + * Returns the number of fs fspools found or -1 and sets @fspools to + * NULL in case of error. On success, the array stored into @fspools is + * guaranteed to have an extra allocated element set to NULL but not included + * in the return count, to make iteration easier. The caller is responsible + * for calling virFSPoolFree() on each array element, then calling + * free() on @fspools. + */ +int +virConnectListAllFSPools(virConnectPtr conn, + virFSPoolPtr **fspools, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, fspools=%p, flags=%x", conn, fspools, flags); + + virResetLastError(); + + if (fspools) + *fspools = NULL; + + virCheckConnectReturn(conn, -1); + + if (conn->fsDriver && + conn->fsDriver->connectListAllFSPools) { + int ret; + ret = conn->fsDriver->connectListAllFSPools(conn, fspools, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(conn); + return -1; +} + +/** + * virFSPoolLookupByName: + * @conn: pointer to hypervisor connection + * @name: name of fspool to fetch + * + * Fetch fspool based on its unique name + * + * virFSPoolFree should be used to free the resources after the + * fs fspool object is no longer needed. + * + * Returns a virFSPoolPtr object, or NULL if no matching fspool is found + */ +virFSPoolPtr +virFSPoolLookupByName(virConnectPtr conn, + const char *name) +{ + VIR_DEBUG("conn=%p, name=%s", conn, NULLSTR(name)); + + virResetLastError(); + + virCheckConnectReturn(conn, NULL); + virCheckNonNullArgGoto(name, error); + + if (conn->fsDriver && conn->fsDriver->fsPoolLookupByName) { + virFSPoolPtr ret; + ret = conn->fsDriver->fsPoolLookupByName(conn, name); + if (!ret) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(conn); + return NULL; +} + + +/** + * virFSPoolLookupByUUID: + * @conn: pointer to hypervisor connection + * @uuid: globally unique id of fspool to fetch + * + * Fetch a fspool based on its globally unique id + * + * virFSPoolFree should be used to free the resources after the + * fs fspool object is no longer needed. + * + * Returns a virFSPoolPtr object, or NULL if no matching fspool is found + */ +virFSPoolPtr +virFSPoolLookupByUUID(virConnectPtr conn, + const unsigned char *uuid) +{ + VIR_UUID_DEBUG(conn, uuid); + + virResetLastError(); + + virCheckConnectReturn(conn, NULL); + virCheckNonNullArgGoto(uuid, error); + + if (conn->fsDriver && conn->fsDriver->fsPoolLookupByUUID) { + virFSPoolPtr ret; + ret = conn->fsDriver->fsPoolLookupByUUID(conn, uuid); + if (!ret) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(conn); + return NULL; +} + + +/** + * virFSPoolLookupByUUIDString: + * @conn: pointer to hypervisor connection + * @uuidstr: globally unique id of fspool to fetch + * + * Fetch a fs fspool based on its globally unique id + * + * virFSPoolFree should be used to free the resources after the + * fs fspool object is no longer needed. + * + * Returns a virFSPoolPtr object, or NULL if no matching fspool is found + */ +virFSPoolPtr +virFSPoolLookupByUUIDString(virConnectPtr conn, + const char *uuidstr) +{ + unsigned char uuid[VIR_UUID_BUFLEN]; + VIR_DEBUG("conn=%p, uuidstr=%s", conn, NULLSTR(uuidstr)); + + virResetLastError(); + + virCheckConnectReturn(conn, NULL); + virCheckNonNullArgGoto(uuidstr, error); + + if (virUUIDParse(uuidstr, uuid) < 0) { + virReportInvalidArg(uuidstr, + _("uuidstr in %s must be a valid UUID"), + __FUNCTION__); + goto error; + } + + return virFSPoolLookupByUUID(conn, uuid); + + error: + virDispatchError(conn); + return NULL; +} + + +/** + virFSPoolLookupByItem: + * @item: pointer to fspool item + * + * Fetch a fspool which contains a particular item + * + * virFSPoolFree should be used to free the resources after the + * fspool object is no longer needed. + * + * Returns a virFSPoolPtr object, or NULL if no matching fspool is found + */ +virFSPoolPtr +virFSPoolLookupByItem(virFSItemPtr item) +{ + VIR_DEBUG("item=%p", item); + + virResetLastError(); + + virCheckFSItemReturn(item, NULL); + + if (item->conn->fsDriver && item->conn->fsDriver->fsPoolLookupByItem) { + virFSPoolPtr ret; + ret = item->conn->fsDriver->fsPoolLookupByItem(item); + if (!ret) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(item->conn); + return NULL; +} + + +/** + * virFSPoolCreateXML: + * @conn: pointer to hypervisor connection + * @xmlDesc: XML description for new fspool + * @flags: bitwise-OR of virFSPoolCreateFlags + * + * Create a new fspool based on its XML description. The + * fspool is not persistent, so its definition will disappear + * when it is destroyed, or if the host is restarted + * + * virFSPoolFree should be used to free the resources after the + *fspool object is no longer needed. + * + * Returns a virFSPoolPtr object, or NULL if creation failed + */ +virFSPoolPtr +virFSPoolCreateXML(virConnectPtr conn, + const char *xmlDesc, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, xmlDesc=%s, flags=%x", conn, NULLSTR(xmlDesc), flags); + + virResetLastError(); + + virCheckConnectReturn(conn, NULL); + virCheckNonNullArgGoto(xmlDesc, error); + virCheckReadOnlyGoto(conn->flags, error); + + if (conn->fsDriver && conn->fsDriver->fsPoolCreateXML) { + virFSPoolPtr ret; + ret = conn->fsDriver->fsPoolCreateXML(conn, xmlDesc, flags); + if (!ret) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(conn); + return NULL; +} + + +/** + * virFSPoolDefineXML: + * @conn: pointer to hypervisor connection + * @xml: XML description for new fspool + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Define an inactive persistent fspool or modify an existing persistent + * one from the XML description. + * + * virFSPoolFree should be used to free the resources after the + * fspool object is no longer needed. + * + * Returns a virFSPoolPtr object, or NULL if creation failed + */ +virFSPoolPtr +virFSPoolDefineXML(virConnectPtr conn, + const char *xml, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, xml=%s, flags=%x", conn, NULLSTR(xml), flags); + + virResetLastError(); + + virCheckConnectReturn(conn, NULL); + virCheckReadOnlyGoto(conn->flags, error); + virCheckNonNullArgGoto(xml, error); + + if (conn->fsDriver && conn->fsDriver->fsPoolDefineXML) { + virFSPoolPtr ret; + ret = conn->fsDriver->fsPoolDefineXML(conn, xml, flags); + if (!ret) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(conn); + return NULL; +} + + +/** + * virFSPoolBuild: + * @fspool: pointer to fspool + * @flags: bitwise-OR of virFSPoolBuildFlags + * + * Build the underlying fspool + * + * Returns 0 on success, or -1 upon failure + */ +int +virFSPoolBuild(virFSPoolPtr fspool, + unsigned int flags) +{ + virConnectPtr conn; + VIR_DEBUG("fspool=%p, flags=%x", fspool, flags); + + virResetLastError(); + + virCheckFSPoolReturn(fspool, -1); + conn = fspool->conn; + + virCheckReadOnlyGoto(conn->flags, error); + + if (conn->fsDriver && conn->fsDriver->fsPoolBuild) { + int ret; + ret = conn->fsDriver->fsPoolBuild(fspool, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(fspool->conn); + return -1; +} + +/** + * virFSPoolRefresh: + * @fspool: pointer to fspool + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Request that the fspool refresh its list of itemms. This may + * involve communicating with a remote server, and/or initializing + * new devices at the OS layer + * + * Returns 0 if the items list was refreshed, -1 on failure + */ +int +virFSPoolRefresh(virFSPoolPtr fspool, + unsigned int flags) +{ + virConnectPtr conn; + VIR_DEBUG("fspool=%p, flags=%x", fspool, flags); + + virResetLastError(); + + virCheckFSPoolReturn(fspool, -1); + conn = fspool->conn; + + virCheckReadOnlyGoto(conn->flags, error); + + if (conn->fsDriver && conn->fsDriver->fsPoolRefresh) { + int ret; + ret = conn->fsDriver->fsPoolRefresh(fspool, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(fspool->conn); + return -1; +} +/** + * virFSPoolUndefine: + * @fspool: pointer to fspool + * + * Undefine an inactive fspool + * + * Returns 0 on success, -1 on failure + */ +int +virFSPoolUndefine(virFSPoolPtr fspool) +{ + virConnectPtr conn; + VIR_DEBUG("fspool=%p", fspool); + + virResetLastError(); + + virCheckFSPoolReturn(fspool, -1); + conn = fspool->conn; + + virCheckReadOnlyGoto(conn->flags, error); + + if (conn->fsDriver && conn->fsDriver->fsPoolUndefine) { + int ret; + ret = conn->fsDriver->fsPoolUndefine(fspool); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(fspool->conn); + return -1; +} + +/** + * virFSPoolCreate: + * @fspool: pointer to fspool + * @flags: bitwise-OR of virFSPoolCreateFlags + * + * Starts an inactive fspool + * + * Returns 0 on success, or -1 if it could not be started + */ +int +virFSPoolCreate(virFSPoolPtr fspool, + unsigned int flags) +{ + virConnectPtr conn; + VIR_DEBUG("fspool=%p, flags=%x", fspool, flags); + + virResetLastError(); + + virCheckFSPoolReturn(fspool, -1); + conn = fspool->conn; + + virCheckReadOnlyGoto(conn->flags, error); + + if (conn->fsDriver && conn->fsDriver->fsPoolCreate) { + int ret; + ret = conn->fsDriver->fsPoolCreate(fspool, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(fspool->conn); + return -1; +} + +/** + * virFSPoolDestroy: + * @fspool: pointer to fspool + * + * Destroy an active fspool. This will deactivate the + * fspool on the host, but keep any persistent config associated + * with it. If it has a persistent config it can later be + * restarted with virFSPoolCreate(). This does not free + * the associated virFSPoolPtr object. + * + * Returns 0 on success, or -1 if it could not be destroyed + */ +int +virFSPoolDestroy(virFSPoolPtr fspool) +{ + virConnectPtr conn; + VIR_DEBUG("fspool=%p", fspool); + + virResetLastError(); + + virCheckFSPoolReturn(fspool, -1); + conn = fspool->conn; + + virCheckReadOnlyGoto(conn->flags, error); + + if (conn->fsDriver && conn->fsDriver->fsPoolDestroy) { + int ret; + ret = conn->fsDriver->fsPoolDestroy(fspool); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(fspool->conn); + return -1; +} + +/** + * virFSPoolDelete: + * @fspool: pointer to fspool + * @flags: bitwise-OR of virFSPoolDeleteFlags + * + * Delete the underlying fspool resources. This is + * a non-recoverable operation. The virFSPoolPtr object + * itself is not free'd. + * + * Returns 0 on success, or -1 if it could not be obliterate + */ +int +virFSPoolDelete(virFSPoolPtr fspool, + unsigned int flags) +{ + virConnectPtr conn; + VIR_DEBUG("fspool=%p, flags=%x", fspool, flags); + + virResetLastError(); + + virCheckFSPoolReturn(fspool, -1); + conn = fspool->conn; + + virCheckReadOnlyGoto(conn->flags, error); + + if (conn->fsDriver && conn->fsDriver->fsPoolDelete) { + int ret; + ret = conn->fsDriver->fsPoolDelete(fspool, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(fspool->conn); + return -1; +} + + +/** + * virFSPoolFree: + * @fspool: pointer to fspool + * + * Free a fs fspool object, releasing all memory associated with + * it. Does not change the state of the fspool on the host. + * + * Returns 0 on success, or -1 if it could not be free'd. + */ +int +virFSPoolFree(virFSPoolPtr fspool) +{ + VIR_DEBUG("fspool=%p", fspool); + + virResetLastError(); + + virCheckFSPoolReturn(fspool, -1); + + virObjectUnref(fspool); + return 0; + +} + + +/** + * virFSPoolRef: + * @fspool: the fspool to hold a reference on + * + * Increment the reference count on the fspool. For each + * additional call to this method, there shall be a corresponding + * call to virFSPoolFree to release the reference count, once + * the caller no longer needs the reference to this object. + * + * This method is typically useful for applications where multiple + * threads are using a connection, and it is required that the + * connection remain open until all threads have finished using + * it. ie, each new thread using a fspool would increment + * the reference count. + * + * Returns 0 in case of success, -1 in case of failure. + */ +int +virFSPoolRef(virFSPoolPtr fspool) +{ + VIR_DEBUG("fspool=%p refs=%d", fspool, fspool ? fspool->object.u.s.refs : 0); + + virResetLastError(); + + virCheckFSPoolReturn(fspool, -1); + + virObjectRef(fspool); + return 0; +} + +/** + * virFSPoolGetName: + * @fspool: pointer to fs fspool + * + * Fetch the locally unique name of the fs fspool + * + * Returns the name of the fspool, or NULL on error + */ +const char* +virFSPoolGetName(virFSPoolPtr fspool) +{ + VIR_DEBUG("fspool=%p", fspool); + + virResetLastError(); + + virCheckFSPoolReturn(fspool, NULL); + + return fspool->name; +} + + +/** + * virFSPoolGetUUID: + * @fspool: pointer to fspool + * @uuid: buffer of VIR_UUID_BUFLEN bytes in size + * + * Fetch the globally unique ID of the fspool + * + * Returns 0 on success, or -1 on error; + */ +int +virFSPoolGetUUID(virFSPoolPtr fspool, + unsigned char *uuid) +{ + VIR_DEBUG("fspool=%p, uuid=%p", fspool, uuid); + + virResetLastError(); + + virCheckFSPoolReturn(fspool, -1); + virCheckNonNullArgGoto(uuid, error); + + memcpy(uuid, &fspool->uuid[0], VIR_UUID_BUFLEN); + + return 0; + + error: + virDispatchError(fspool->conn); + return -1; +} + + +/** + * virFSPoolGetUUIDString: + * @fspool: pointer to fspool + * @buf: buffer of VIR_UUID_STRING_BUFLEN bytes in size + * + * Fetch the globally unique ID of the fspool as a string + * + * Returns 0 on success, or -1 on error; + */ +int +virFSPoolGetUUIDString(virFSPoolPtr fspool, + char *buf) +{ + VIR_DEBUG("fspool=%p, buf=%p", fspool, buf); + + virResetLastError(); + + virCheckFSPoolReturn(fspool, -1); + virCheckNonNullArgGoto(buf, error); + + virUUIDFormat(fspool->uuid, buf); + return 0; + + error: + virDispatchError(fspool->conn); + return -1; +} + + +/** + * virFSPoolGetInfo: + * @fspool: pointer to fs fspool + * @info: pointer at which to store info + * + * Get information about the fspool + * such as free space / usage summary + * + * Returns 0 on success, or -1 on failure. + */ +int +virFSPoolGetInfo(virFSPoolPtr fspool, + virFSPoolInfoPtr info) +{ + virConnectPtr conn; + VIR_DEBUG("fspool=%p, info=%p", fspool, info); + + virResetLastError(); + + if (info) + memset(info, 0, sizeof(*info)); + + virCheckFSPoolReturn(fspool, -1); + virCheckNonNullArgGoto(info, error); + + conn = fspool->conn; + + if (conn->fsDriver->fsPoolGetInfo) { + int ret; + ret = conn->fsDriver->fsPoolGetInfo(fspool, info); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(fspool->conn); + return -1; +} + +/** + * virFSPoolGetAutostart: + * @fspool: pointer to fspool + * @autostart: location in which to store autostart flag + * + * Fetches the value of the autostart flag, which determines + * whether the fspool is automatically started at boot time + * + * Returns 0 on success, -1 on failure + */ +int +virFSPoolGetAutostart(virFSPoolPtr fspool, + int *autostart) +{ + virConnectPtr conn; + VIR_DEBUG("fspool=%p, autostart=%p", fspool, autostart); + + virResetLastError(); + + virCheckFSPoolReturn(fspool, -1); + virCheckNonNullArgGoto(autostart, error); + + conn = fspool->conn; + + if (conn->fsDriver && conn->fsDriver->fsPoolGetAutostart) { + int ret; + ret = conn->fsDriver->fsPoolGetAutostart(fspool, autostart); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(fspool->conn); + return -1; +} + + +/** + * virFSPoolSetAutostart: + * @fspool: pointer to fspool + * @autostart: new flag setting + * + * Sets the autostart flag + * + * Returns 0 on success, -1 on failure + */ +int +virFSPoolSetAutostart(virFSPoolPtr fspool, + int autostart) +{ + virConnectPtr conn; + VIR_DEBUG("fspool=%p, autostart=%d", fspool, autostart); + + virResetLastError(); + + virCheckFSPoolReturn(fspool, -1); + conn = fspool->conn; + + virCheckReadOnlyGoto(conn->flags, error); + + if (conn->fsDriver && conn->fsDriver->fsPoolSetAutostart) { + int ret; + ret = conn->fsDriver->fsPoolSetAutostart(fspool, autostart); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(fspool->conn); + return -1; +} + +/** + * virFSPoolGetXMLDesc: + * @fspool: pointer to fspool + * @flags: bitwise-OR of virFsXMLFlags + * + * Fetch an XML document describing all aspects of the + * fs fspool. This is suitable for later feeding back + * into the virFSPoolCreateXML method. + * + * Returns a XML document (caller frees), or NULL on error + */ +char * +virFSPoolGetXMLDesc(virFSPoolPtr fspool, + unsigned int flags) +{ + virConnectPtr conn; + VIR_DEBUG("fspool=%p, flags=%x", fspool, flags); + + virResetLastError(); + + virCheckFSPoolReturn(fspool, NULL); + conn = fspool->conn; + + if (conn->fsDriver && conn->fsDriver->fsPoolGetXMLDesc) { + char *ret; + ret = conn->fsDriver->fsPoolGetXMLDesc(fspool, flags); + if (!ret) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(fspool->conn); + return NULL; +} + + +/** + * virFSPoolListAllItems: + * @fspool: Pointer to fspool + * @items: Pointer to a variable to store the array containing fs item + * objects or NULL if the list is not required (just returns number + * of items). + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Collect the list of fsitems, and allocate an array to store those + * objects. + * + * Returns the number of fs items found or -1 and sets @items to + * NULL in case of error. On success, the array stored into @items is + * guaranteed to have an extra allocated element set to NULL but not included + * in the return count, to make iteration easier. The caller is responsible + * for calling virFSItemFree() on each array element, then calling + * free() on @items. + */ +int +virFSPoolListAllItems(virFSPoolPtr fspool, + virFSItemPtr **items, + unsigned int flags) +{ + VIR_DEBUG("fspool=%p, items=%p, flags=%x", fspool, items, flags); + + virResetLastError(); + + virCheckFSPoolReturn(fspool, -1); + + if (fspool->conn->fsDriver && + fspool->conn->fsDriver->fsPoolListAllItems) { + int ret; + ret = fspool->conn->fsDriver->fsPoolListAllItems(fspool, items, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(fspool->conn); + return -1; +} + + +/** + * virFSPoolNumOfItems: + * @fspool: pointer to fspool + * + * Fetch the number of items within a fspool + * + * Returns the number of fspools, or -1 on failure + */ +int +virFSPoolNumOfItems(virFSPoolPtr fspool) +{ + VIR_DEBUG("fspool=%p", fspool); + + virResetLastError(); + + virCheckFSPoolReturn(fspool, -1); + + if (fspool->conn->fsDriver && fspool->conn->fsDriver->fsPoolNumOfItems) { + int ret; + ret = fspool->conn->fsDriver->fsPoolNumOfItems(fspool); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(fspool->conn); + return -1; +} + + +/** + * virFSPoolListItems: + * @fspool: pointer to fspool + * @names: array in which to fsitem names + * @maxnames: size of names array + * + * Fetch list of fs item names, limiting to + * at most maxnames. + * + * To list the item objects directly, see virFSPoolListAllItems(). + * + * Returns the number of names fetched, or -1 on error + */ +int +virFSPoolListItems(virFSPoolPtr fspool, + char **const names, + int maxnames) +{ + VIR_DEBUG("fspool=%p, names=%p, maxnames=%d", fspool, names, maxnames); + + virResetLastError(); + + virCheckFSPoolReturn(fspool, -1); + virCheckNonNullArgGoto(names, error); + virCheckNonNegativeArgGoto(maxnames, error); + + if (fspool->conn->fsDriver && fspool->conn->fsDriver->fsPoolListItems) { + int ret; + ret = fspool->conn->fsDriver->fsPoolListItems(fspool, names, maxnames); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(fspool->conn); + return -1; +} + + +/** + * virFSItemGetConnect: + * @item: pointer to a fspool + * + * Provides the connection pointer associated with a fs item. The + * reference counter on the connection is not increased by this + * call. + * + * WARNING: When writing libvirt bindings in other languages, do + * not use this function. Instead, store the connection and + * the item object together. + * + * Returns the virConnectPtr or NULL in case of failure. + */ +virConnectPtr +virFSItemGetConnect(virFSItemPtr item) +{ + VIR_DEBUG("item=%p", item); + + virResetLastError(); + + virCheckFSItemReturn(item, NULL); + + return item->conn; +} + + +/** + * virFSItemLookupByName: + * @fspool: pointer to fspool + * @name: name of fsitem + * + * Fetch a pointer to a fs item based on its name + * within a fspool. + * + * virFSItemFree should be used to free the resources after the + * fs item object is no longer needed. + * + * Returns a fsitem, or NULL if not found / error + */ +virFSItemPtr +virFSItemLookupByName(virFSPoolPtr fspool, + const char *name) +{ + VIR_DEBUG("fspool=%p, name=%s", fspool, NULLSTR(name)); + + virResetLastError(); + + virCheckFSPoolReturn(fspool, NULL); + virCheckNonNullArgGoto(name, error); + + if (fspool->conn->fsDriver && fspool->conn->fsDriver->fsItemLookupByName) { + virFSItemPtr ret; + ret = fspool->conn->fsDriver->fsItemLookupByName(fspool, name); + if (!ret) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(fspool->conn); + return NULL; +} + + +/** + * virFSItemLookupByKey: + * @conn: pointer to hypervisor connection + * @key: globally unique key + * + * Fetch a pointer to a fspool item based on its + * globally unique key + * + * virFSItemFree should be used to free the resources after the + * fs item object is no longer needed. + * + * Returns a fs item, or NULL if not found / error + */ +virFSItemPtr +virFSItemLookupByKey(virConnectPtr conn, + const char *key) +{ + VIR_DEBUG("conn=%p, key=%s", conn, NULLSTR(key)); + + virResetLastError(); + + virCheckConnectReturn(conn, NULL); + virCheckNonNullArgGoto(key, error); + + if (conn->fsDriver && conn->fsDriver->fsItemLookupByKey) { + virFSItemPtr ret; + ret = conn->fsDriver->fsItemLookupByKey(conn, key); + if (!ret) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(conn); + return NULL; +} + + +/** + * virFSItemLookupByPath: + * @conn: pointer to hypervisor connection + * @path: locally unique path + * + * Fetch a pointer to a fs item based on its + * locally (host) unique path + * + * virFSItemFree should be used to free the resources after the + * fs item object is no longer needed. + * + * Returns a fs item, or NULL if not found / error + */ +virFSItemPtr +virFSItemLookupByPath(virConnectPtr conn, + const char *path) +{ + VIR_DEBUG("conn=%p, path=%s", conn, NULLSTR(path)); + + virResetLastError(); + + virCheckConnectReturn(conn, NULL); + virCheckNonNullArgGoto(path, error); + + if (conn->fsDriver && conn->fsDriver->fsItemLookupByPath) { + virFSItemPtr ret; + ret = conn->fsDriver->fsItemLookupByPath(conn, path); + if (!ret) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(conn); + return NULL; +} + + +/** + * virFSItemGetName: + * @item: pointer to fsitem + * + * Fetch the fsitem name. This is unique + * within the scope of a fspool + * + * Returns the item name, or NULL on error + */ +const char* +virFSItemGetName(virFSItemPtr item) +{ + VIR_DEBUG("item=%p", item); + + virResetLastError(); + + virCheckFSItemReturn(item, NULL); + + return item->name; +} + + +/** + * virFSItemGetKey: + * @item: pointer to fspool item + * + * Fetch the fsitem key. This is globally + * unique, so the same item will have the same + * key no matter what host it is accessed from + * + * Returns the item key, or NULL on error + */ +const char* +virFSItemGetKey(virFSItemPtr item) +{ + VIR_DEBUG("item=%p", item); + + virResetLastError(); + + virCheckFSItemReturn(item, NULL); + + return item->key; +} + + +/** + * virFSItemCreateXML: + * @fspool: pointer to fspool + * @xmlDesc: description of item to create + * @flags: bitwise-OR of virFSItemCreateFlags + * + * Create a fs item within a fspool based + * on an XML description. + * + * virFSItemFree should be used to free the resources after the + * fs item object is no longer needed. + * + * Returns the fs item, or NULL on error + */ +virFSItemPtr +virFSItemCreateXML(virFSPoolPtr fspool, + const char *xmlDesc, + unsigned int flags) +{ + VIR_DEBUG("fspool=%p, xmlDesc=%s, flags=%x", fspool, NULLSTR(xmlDesc), flags); + + virResetLastError(); + + virCheckFSPoolReturn(fspool, NULL); + virCheckNonNullArgGoto(xmlDesc, error); + virCheckReadOnlyGoto(fspool->conn->flags, error); + + if (fspool->conn->fsDriver && fspool->conn->fsDriver->fsItemCreateXML) { + virFSItemPtr ret; + ret = fspool->conn->fsDriver->fsItemCreateXML(fspool, xmlDesc, flags); + if (!ret) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(fspool->conn); + return NULL; +} + + +/** + * virFSItemCreateXMLFrom: + * @fspool: pointer to parent fspool for the new item + * @xmlDesc: description of item to create + * @cloneitem: fspool item to use as input + * @flags: bitwise-OR of virFSItemCreateFlags + * + * Create a fs item in the parent fspool, using the + * 'cloneitem' item as input. Information for the new + * item (name, perms) are passed via a typical item + * XML description. + * + * virFSItemFree should be used to free the resources after the + * fs item object is no longer needed. + * + * Returns the fs item, or NULL on error + */ +virFSItemPtr +virFSItemCreateXMLFrom(virFSPoolPtr fspool, + const char *xmlDesc, + virFSItemPtr cloneitem, + unsigned int flags) +{ + VIR_DEBUG("fspool=%p, xmlDesc=%s, cloneitem=%p, flags=%x", + fspool, NULLSTR(xmlDesc), cloneitem, flags); + + virResetLastError(); + + virCheckFSPoolReturn(fspool, NULL); + virCheckFSItemGoto(cloneitem, error); + virCheckNonNullArgGoto(xmlDesc, error); + virCheckReadOnlyGoto(fspool->conn->flags | cloneitem->conn->flags, error); + + if (fspool->conn->fsDriver && + fspool->conn->fsDriver->fsItemCreateXMLFrom) { + virFSItemPtr ret; + ret = fspool->conn->fsDriver->fsItemCreateXMLFrom(fspool, xmlDesc, + cloneitem, flags); + if (!ret) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(fspool->conn); + return NULL; +} + +/** + * virFSItemDelete: + * @item: pointer to fspool item + * @flags: bitwise-OR of virFSItemDeleteFlags + * + * Delete the fs item from the fspool + * + * Returns 0 on success, or -1 on error + */ +int +virFSItemDelete(virFSItemPtr item, + unsigned int flags) +{ + virConnectPtr conn; + VIR_DEBUG("item=%p, flags=%x", item, flags); + + virResetLastError(); + + virCheckFSItemReturn(item, -1); + conn = item->conn; + + virCheckReadOnlyGoto(conn->flags, error); + + if (conn->fsDriver && conn->fsDriver->fsItemDelete) { + int ret; + ret = conn->fsDriver->fsItemDelete(item, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(item->conn); + return -1; +} + +/** + * virFSItemFree: + * @item: pointer to fspool item + * + * Release the fs item handle. The underlying + * fs item continues to exist. + * + * Returns 0 on success, or -1 on error + */ +int +virFSItemFree(virFSItemPtr item) +{ + VIR_DEBUG("item=%p", item); + + virResetLastError(); + + virCheckFSItemReturn(item, -1); + + virObjectUnref(item); + return 0; +} + + +/** + * virFSItemRef: + * @item: the item to hold a reference on + * + * Increment the reference count on the item. For each + * additional call to this method, there shall be a corresponding + * call to virFSItemFree to release the reference count, once + * the caller no longer needs the reference to this object. + * + * This method is typically useful for applications where multiple + * threads are using a connection, and it is required that the + * connection remain open until all threads have finished using + * it. ie, each new thread using a item would increment + * the reference count. + * + * Returns 0 in case of success, -1 in case of failure. + */ +int +virFSItemRef(virFSItemPtr item) +{ + VIR_DEBUG("item=%p refs=%d", item, item ? item->object.u.s.refs : 0); + + virResetLastError(); + + virCheckFSItemReturn(item, -1); + + virObjectRef(item); + return 0; +} + + +/** + * virFSItemGetInfo: + * @item: pointer to fspool item + * @info: pointer at which to store info + * + * Fetches itematile information about the fspool + * item such as its current allocation + * + * Returns 0 on success, or -1 on failure + */ +int +virFSItemGetInfo(virFSItemPtr item, + virFSItemInfoPtr info) +{ + virConnectPtr conn; + VIR_DEBUG("item=%p, info=%p", item, info); + + virResetLastError(); + + if (info) + memset(info, 0, sizeof(*info)); + + virCheckFSItemReturn(item, -1); + virCheckNonNullArgGoto(info, error); + + conn = item->conn; + + if (conn->fsDriver->fsItemGetInfo) { + int ret; + ret = conn->fsDriver->fsItemGetInfo(item, info); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(item->conn); + return -1; +} + + +/** + * virFSItemGetXMLDesc: + * @item: pointer to fsitem + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Fetch an XML document describing all aspects of + * the fsitem + * + * Returns the XML document, or NULL on error + */ +char * +virFSItemGetXMLDesc(virFSItemPtr item, + unsigned int flags) +{ + virConnectPtr conn; + VIR_DEBUG("item=%p, flags=%x", item, flags); + + virResetLastError(); + + virCheckFSItemReturn(item, NULL); + conn = item->conn; + + if (conn->fsDriver && conn->fsDriver->fsItemGetXMLDesc) { + char *ret; + ret = conn->fsDriver->fsItemGetXMLDesc(item, flags); + if (!ret) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(item->conn); + return NULL; +} + + +/** + * virFSItemGetPath: + * @item: pointer to fspool item + * + * Fetch the fsitem path. Depending on the fspool + * configuration this is either persistent across hosts, + * or dynamically assigned at fspool startup. Consult + * fspool documentation for information on getting the + * persistent naming + * + * Returns the fs item path, or NULL on error. The + * caller must free() the returned path after use. + */ +char * +virFSItemGetPath(virFSItemPtr item) +{ + virConnectPtr conn; + VIR_DEBUG("item=%p", item); + + virResetLastError(); + + virCheckFSItemReturn(item, NULL); + conn = item->conn; + + if (conn->fsDriver && conn->fsDriver->fsItemGetPath) { + char *ret; + ret = conn->fsDriver->fsItemGetPath(item); + if (!ret) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(item->conn); + return NULL; +} + + +/** + * virFSPoolIsActive: + */ +int +virFSPoolIsActive(virFSPoolPtr fspool) +{ + VIR_DEBUG("fspool=%p", fspool); + + virResetLastError(); + + virCheckFSPoolReturn(fspool, -1); + + if (fspool->conn->fsDriver->fsPoolIsActive) { + int ret; + ret = fspool->conn->fsDriver->fsPoolIsActive(fspool); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + error: + virDispatchError(fspool->conn); + return -1; +} + + +/** + * virFSPoolIsPersistent: + * @fspool: pointer to the fspool object + * + * Determine if the fspool has a persistent configuration + * which means it will still exist after shutting down + * + * Returns 1 if persistent, 0 if transient, -1 on error + */ +int +virFSPoolIsPersistent(virFSPoolPtr fspool) +{ + VIR_DEBUG("fspool=%p", fspool); + + virResetLastError(); + + virCheckFSPoolReturn(fspool, -1); + + if (fspool->conn->fsDriver->fsPoolIsPersistent) { + int ret; + ret = fspool->conn->fsDriver->fsPoolIsPersistent(fspool); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + error: + virDispatchError(fspool->conn); + return -1; +} diff --git a/src/libvirt.c b/src/libvirt.c index 52462e3..908a260 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -119,7 +119,7 @@ static virStorageDriverPtr virSharedStorageDriver; static virNodeDeviceDriverPtr virSharedNodeDeviceDriver; static virSecretDriverPtr virSharedSecretDriver; static virNWFilterDriverPtr virSharedNWFilterDriver; - +static virFSDriverPtr virSharedFSDriver; #if defined(POLKIT_AUTH) static int @@ -665,6 +665,30 @@ virSetSharedNWFilterDriver(virNWFilterDriverPtr driver) return 0; } +/** + * virSetSharedFSDriver: + * @driver: pointer to a fs driver block + * + * Register a fs virtualization driver + * + * Returns the driver priority or -1 in case of error. + */ +int +virSetSharedFSDriver(virFSDriverPtr driver) +{ + virCheckNonNullArgReturn(driver, -1); + + if (virSharedFSDriver) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("A fs driver is already registered")); + return -1; + } + + VIR_DEBUG("registering %s as fs driver", driver->name); + + virSharedFSDriver = driver; + return 0; +} /** * virRegisterConnectDriver: @@ -707,6 +731,8 @@ virRegisterConnectDriver(virConnectDriverPtr driver, driver->secretDriver = virSharedSecretDriver; if (driver->storageDriver == NULL) driver->storageDriver = virSharedStorageDriver; + if (driver->fsDriver == NULL) + driver->fsDriver = virSharedFSDriver; } virConnectDriverTab[virConnectDriverTabCount] = driver; @@ -1089,6 +1115,7 @@ virConnectOpenInternal(const char *name, ret->nwfilterDriver = virConnectDriverTab[i]->nwfilterDriver; ret->secretDriver = virConnectDriverTab[i]->secretDriver; ret->storageDriver = virConnectDriverTab[i]->storageDriver; + ret->fsDriver = virConnectDriverTab[i]->fsDriver; res = virConnectDriverTab[i]->hypervisorDriver->connectOpen(ret, auth, conf, flags); VIR_DEBUG("driver %zu %s returned %s", @@ -1107,6 +1134,7 @@ virConnectOpenInternal(const char *name, ret->nwfilterDriver = NULL; ret->secretDriver = NULL; ret->storageDriver = NULL; + ret->storageDriver = NULL; if (res == VIR_DRV_OPEN_ERROR) goto failed; diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 67ebe2a..8589394 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1021,7 +1021,8 @@ virSecretClass; virStoragePoolClass; virStorageVolClass; virStreamClass; - +virGetFSPool; +virGetFSItem; # fdstream.h virFDStreamConnectUNIX; @@ -1061,6 +1062,7 @@ virSetSharedNodeDeviceDriver; virSetSharedNWFilterDriver; virSetSharedSecretDriver; virSetSharedStorageDriver; +virSetSharedFSDriver; virStateCleanup; virStateInitialize; virStateReload; diff --git a/src/util/virerror.c b/src/util/virerror.c index 2958308..57e448d 100644 --- a/src/util/virerror.c +++ b/src/util/virerror.c @@ -138,6 +138,7 @@ VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST, "Xen XL Config", "Perf", + "FSPool" ) @@ -1400,6 +1401,42 @@ virErrorMsg(virErrorNumber error, const char *info) else errmsg = _("guest agent replied with wrong id to guest-sync command: %s"); break; + case VIR_ERR_INVALID_FSPOOL: + if (info == NULL) + errmsg = _("invalid fspool poiter in"); + else + errmsg = _("invalid fspool pointer in %s"); + break; + case VIR_ERR_INVALID_FSITEM: + if (info == NULL) + errmsg = _("invalid fsitem pointer in"); + else + errmsg = _("invalid fsitem pointer in %s"); + break; + case VIR_WAR_NO_FSPOOL: + if (info == NULL) + errmsg = _("Failed to find a FS driver"); + else + errmsg = _("Failed to find a FS driver: %s"); + break; + case VIR_ERR_NO_FSPOOL: + if (info == NULL) + errmsg = _("fspool not found"); + else + errmsg = _("fspool not found: %s"); + break; + case VIR_ERR_NO_FSITEM: + if (info == NULL) + errmsg = _("fspool item not found"); + else + errmsg = _("fspool item not found: %s"); + break; + case VIR_ERR_FSITEM_EXIST: + if (info == NULL) + errmsg = _("fspool item exists"); + else + errmsg = _("fspool item exists: %s"); + break; } return errmsg; } -- 1.8.3.1

Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- src/access/viraccessdriver.h | 15 +++++ src/access/viraccessdrivernop.c | 21 +++++++ src/access/viraccessdriverpolkit.c | 47 ++++++++++++++ src/access/viraccessdriverstack.c | 50 +++++++++++++++ src/access/viraccessmanager.c | 32 ++++++++++ src/access/viraccessmanager.h | 11 +++- src/access/viraccessperm.c | 15 ++++- src/access/viraccessperm.h | 126 +++++++++++++++++++++++++++++++++++++ src/libvirt_private.syms | 5 +- 9 files changed, 318 insertions(+), 4 deletions(-) diff --git a/src/access/viraccessdriver.h b/src/access/viraccessdriver.h index e3050b6..194aa2f 100644 --- a/src/access/viraccessdriver.h +++ b/src/access/viraccessdriver.h @@ -61,6 +61,19 @@ typedef int (*virAccessDriverCheckStorageVolDrv)(virAccessManagerPtr manager, virStorageVolDefPtr vol, virAccessPermStorageVol av); +typedef int (*virAccessDriverCheckFSPoolDrv)(virAccessManagerPtr manager, + const char *driverName, + virFSPoolDefPtr fspool, + virAccessPermFSPool av); +typedef int (*virAccessDriverCheckFSItemDrv)(virAccessManagerPtr manager, + const char *driverName, + virFSPoolDefPtr fspool, + virFSItemDefPtr item, + virAccessPermFSItem av); + +typedef int (*virAccessDriverSetupDrv)(virAccessManagerPtr manager); +typedef void (*virAccessDriverCleanupDrv)(virAccessManagerPtr manager); + typedef int (*virAccessDriverSetupDrv)(virAccessManagerPtr manager); typedef void (*virAccessDriverCleanupDrv)(virAccessManagerPtr manager); @@ -83,6 +96,8 @@ struct _virAccessDriver { virAccessDriverCheckSecretDrv checkSecret; virAccessDriverCheckStoragePoolDrv checkStoragePool; virAccessDriverCheckStorageVolDrv checkStorageVol; + virAccessDriverCheckFSPoolDrv checkFSPool; + virAccessDriverCheckFSItemDrv checkFSItem; }; diff --git a/src/access/viraccessdrivernop.c b/src/access/viraccessdrivernop.c index 86ceef3..a936711 100644 --- a/src/access/viraccessdrivernop.c +++ b/src/access/viraccessdrivernop.c @@ -104,6 +104,25 @@ virAccessDriverNopCheckStorageVol(virAccessManagerPtr manager ATTRIBUTE_UNUSED, } +static int +virAccessDriverNopCheckFSPool(virAccessManagerPtr manager ATTRIBUTE_UNUSED, + const char *driverName ATTRIBUTE_UNUSED, + virFSPoolDefPtr fspool ATTRIBUTE_UNUSED, + virAccessPermFSPool perm ATTRIBUTE_UNUSED) +{ + return 1; /* Allow */ +} + +static int +virAccessDriverNopCheckFSItem(virAccessManagerPtr manager ATTRIBUTE_UNUSED, + const char *driverName ATTRIBUTE_UNUSED, + virFSPoolDefPtr fspool ATTRIBUTE_UNUSED, + virFSItemDefPtr item ATTRIBUTE_UNUSED, + virAccessPermFSItem perm ATTRIBUTE_UNUSED) +{ + return 1; /* Allow */ +} + virAccessDriver accessDriverNop = { .name = "none", .checkConnect = virAccessDriverNopCheckConnect, @@ -115,4 +134,6 @@ virAccessDriver accessDriverNop = { .checkSecret = virAccessDriverNopCheckSecret, .checkStoragePool = virAccessDriverNopCheckStoragePool, .checkStorageVol = virAccessDriverNopCheckStorageVol, + .checkFSPool = virAccessDriverNopCheckFSPool, + .checkFSItem = virAccessDriverNopCheckFSItem, }; diff --git a/src/access/viraccessdriverpolkit.c b/src/access/viraccessdriverpolkit.c index 0d9e0a1..2beaf74 100644 --- a/src/access/viraccessdriverpolkit.c +++ b/src/access/viraccessdriverpolkit.c @@ -399,6 +399,51 @@ virAccessDriverPolkitCheckStorageVol(virAccessManagerPtr manager, attrs); } +static int +virAccessDriverPolkitCheckFSPool(virAccessManagerPtr manager, + const char *driverName, + virFSPoolDefPtr fspool, + virAccessPermFSPool perm) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN]; + const char *attrs[] = { + "connect_driver", driverName, + "fspool_name", fspool->name, + "fspool_uuid", uuidstr, + NULL, + }; + virUUIDFormat(fspool->uuid, uuidstr); + + return virAccessDriverPolkitCheck(manager, + "fs-pool", + virAccessPermFSPoolTypeToString(perm), + attrs); +} + +static int +virAccessDriverPolkitCheckFSItem(virAccessManagerPtr manager, + const char *driverName, + virFSPoolDefPtr fspool, + virFSItemDefPtr item, + virAccessPermFSItem perm) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN]; + const char *attrs[] = { + "connect_driver", driverName, + "fspool_name", fspool->name, + "fspool_uuid", uuidstr, + "item_name", item->name, + "item_key", item->key, + NULL, + }; + virUUIDFormat(fspool->uuid, uuidstr); + + return virAccessDriverPolkitCheck(manager, + "fs-item", + virAccessPermFSItemTypeToString(perm), + attrs); +} + virAccessDriver accessDriverPolkit = { .privateDataLen = sizeof(virAccessDriverPolkitPrivate), .name = "polkit", @@ -412,4 +457,6 @@ virAccessDriver accessDriverPolkit = { .checkSecret = virAccessDriverPolkitCheckSecret, .checkStoragePool = virAccessDriverPolkitCheckStoragePool, .checkStorageVol = virAccessDriverPolkitCheckStorageVol, + .checkFSPool = virAccessDriverPolkitCheckFSPool, + .checkFSItem = virAccessDriverPolkitCheckFSItem, }; diff --git a/src/access/viraccessdriverstack.c b/src/access/viraccessdriverstack.c index b43a743..7fe1658 100644 --- a/src/access/viraccessdriverstack.c +++ b/src/access/viraccessdriverstack.c @@ -267,6 +267,54 @@ virAccessDriverStackCheckStorageVol(virAccessManagerPtr manager, return ret; } +static int +virAccessDriverStackCheckFSPool(virAccessManagerPtr manager, + const char *driverName, + virFSPoolDefPtr fspool, + virAccessPermFSPool perm) +{ + virAccessDriverStackPrivatePtr priv = virAccessManagerGetPrivateData(manager); + int ret = 1; + size_t i; + + for (i = 0; i < priv->managersLen; i++) { + int rv; + /* We do not short-circuit on first denial - always check all drivers */ + rv = virAccessManagerCheckFSPool(priv->managers[i], driverName, fspool, perm); + if (rv == 0 && ret != -1) + ret = 0; + else if (rv < 0) + ret = -1; + } + + return ret; +} + +static int +virAccessDriverStackCheckFSItem(virAccessManagerPtr manager, + const char *driverName, + virFSPoolDefPtr fspool, + virFSItemDefPtr item, + virAccessPermFSItem perm) +{ + virAccessDriverStackPrivatePtr priv = virAccessManagerGetPrivateData(manager); + int ret = 1; + size_t i; + + for (i = 0; i < priv->managersLen; i++) { + int rv; + /* We do not short-circuit on first denial - always check all drivers */ + rv = virAccessManagerCheckFSItem(priv->managers[i], driverName, fspool, item, perm); + if (rv == 0 && ret != -1) + ret = 0; + else if (rv < 0) + ret = -1; + } + + return ret; +} + + virAccessDriver accessDriverStack = { .privateDataLen = sizeof(virAccessDriverStackPrivate), .name = "stack", @@ -280,4 +328,6 @@ virAccessDriver accessDriverStack = { .checkSecret = virAccessDriverStackCheckSecret, .checkStoragePool = virAccessDriverStackCheckStoragePool, .checkStorageVol = virAccessDriverStackCheckStorageVol, + .checkFSPool = virAccessDriverStackCheckFSPool, + .checkFSItem = virAccessDriverStackCheckFSItem, }; diff --git a/src/access/viraccessmanager.c b/src/access/viraccessmanager.c index bcf552b..20a1260 100644 --- a/src/access/viraccessmanager.c +++ b/src/access/viraccessmanager.c @@ -344,3 +344,35 @@ int virAccessManagerCheckStorageVol(virAccessManagerPtr manager, return virAccessManagerSanitizeError(ret); } + + +int virAccessManagerCheckFSPool(virAccessManagerPtr manager, + const char *driverName, + virFSPoolDefPtr fspool, + virAccessPermFSPool perm) +{ + int ret = 0; + VIR_DEBUG("manager=%p(name=%s) driver=%s pool=%p perm=%d", + manager, manager->drv->name, driverName, fspool, perm); + + if (manager->drv->checkFSPool) + ret = manager->drv->checkFSPool(manager, driverName, fspool, perm); + + return virAccessManagerSanitizeError(ret); +} + +int virAccessManagerCheckFSItem(virAccessManagerPtr manager, + const char *driverName, + virFSPoolDefPtr fspool, + virFSItemDefPtr item, + virAccessPermFSItem perm) +{ + int ret = 0; + VIR_DEBUG("manager=%p(name=%s) driver=%s pool=%p vol=%p perm=%d", + manager, manager->drv->name, driverName, fspool, item, perm); + + if (manager->drv->checkFSItem) + ret = manager->drv->checkFSItem(manager, driverName, fspool, item, perm); + + return virAccessManagerSanitizeError(ret); +} diff --git a/src/access/viraccessmanager.h b/src/access/viraccessmanager.h index e7eb15d..5c74572 100644 --- a/src/access/viraccessmanager.h +++ b/src/access/viraccessmanager.h @@ -29,6 +29,7 @@ # include "conf/storage_conf.h" # include "conf/secret_conf.h" # include "conf/interface_conf.h" +# include "conf/fs_conf.h" # include "access/viraccessperm.h" typedef struct _virAccessManager virAccessManager; @@ -86,6 +87,14 @@ int virAccessManagerCheckStorageVol(virAccessManagerPtr manager, virStoragePoolDefPtr pool, virStorageVolDefPtr vol, virAccessPermStorageVol perm); - +int virAccessManagerCheckFSPool(virAccessManagerPtr manager, + const char *driverName, + virFSPoolDefPtr fspool, + virAccessPermFSPool perm); +int virAccessManagerCheckFSItem(virAccessManagerPtr manager, + const char *driverName, + virFSPoolDefPtr fspool, + virFSItemDefPtr item, + virAccessPermFSItem perm); #endif /* __VIR_ACCESS_MANAGER_H__ */ diff --git a/src/access/viraccessperm.c b/src/access/viraccessperm.c index 0f58290..8fe5bbf 100644 --- a/src/access/viraccessperm.c +++ b/src/access/viraccessperm.c @@ -31,7 +31,7 @@ VIR_ENUM_IMPL(virAccessPermConnect, "search_interfaces", "search_secrets", "search_nwfilters", "detect_storage_pools", "pm_control", - "interface_transaction"); + "interface_transaction", "search_fspools"); VIR_ENUM_IMPL(virAccessPermDomain, VIR_ACCESS_PERM_DOMAIN_LAST, @@ -83,3 +83,16 @@ VIR_ENUM_IMPL(virAccessPermStorageVol, "getattr", "read", "create", "delete", "format", "resize", "data_read", "data_write"); + +VIR_ENUM_IMPL(virAccessPermFSPool, + VIR_ACCESS_PERM_FSPOOL_LAST, + "getattr", "read", "write", + "save", "delete", "start", "stop", + "refresh", "search_items", + "format"); + +VIR_ENUM_IMPL(virAccessPermFSItem, + VIR_ACCESS_PERM_FSITEM_LAST, + "getattr", "read", "create", "delete", + "format", "data_read", + "data_write"); diff --git a/src/access/viraccessperm.h b/src/access/viraccessperm.h index 1817da7..b8e2531 100644 --- a/src/access/viraccessperm.h +++ b/src/access/viraccessperm.h @@ -113,6 +113,13 @@ typedef enum { */ VIR_ACCESS_PERM_CONNECT_INTERFACE_TRANSACTION, + /** + * * @desc: List fs pools + * * @message: Listing fs pools requires authorization + * * @anonymous: 1 + * */ + VIR_ACCESS_PERM_CONNECT_SEARCH_FSPOOLS, + VIR_ACCESS_PERM_CONNECT_LAST, } virAccessPermConnect; @@ -651,6 +658,123 @@ typedef enum { VIR_ACCESS_PERM_STORAGE_VOL_LAST } virAccessPermStorageVol; +typedef enum { + + /** + * @desc: Access fs pool + * @message: Accessing fs pool requires authorization + * @anonymous: 1 + */ + VIR_ACCESS_PERM_FSPOOL_GETATTR, + + /** + * @desc: Read fs pool + * @message: Reading fs pool configuration requires authorization + * @anonymous: 1 + */ + VIR_ACCESS_PERM_FSPOOL_READ, + + /** + * @desc: Write fs pool + * @message: Writing fs pool configuration requires authorization + */ + VIR_ACCESS_PERM_FSPOOL_WRITE, + + /** + * @desc: Save fs pool + * @message: Saving fs pool configuration requires authorization + */ + VIR_ACCESS_PERM_FSPOOL_SAVE, + + /** + * @desc: Delete fs pool + * @message: Deleting fs pool configuration requires authorization + */ + VIR_ACCESS_PERM_FSPOOL_DELETE, + + /** + * @desc: Start fs pool + * @message: Starting fs pool configuration requires authorization + */ + VIR_ACCESS_PERM_FSPOOL_START, + + /** + * @desc: Stop fs pool + * @message: Stopping fs pool configuration requires authorization + */ + VIR_ACCESS_PERM_FSPOOL_STOP, + + /** + * @desc: Refresh fs pool + * @message: Refreshing fs pool items requires authorization + */ + VIR_ACCESS_PERM_FSPOOL_REFRESH, + + /** + * @desc: List fs pool items + * @message: Listing fs pool items requires authorization + */ + VIR_ACCESS_PERM_FSPOOL_SEARCH_ITEMS, + + /** + * @desc: Format fs pool + * @message: Formatting fs pool data requires authorization + */ + VIR_ACCESS_PERM_FSPOOL_FORMAT, + + VIR_ACCESS_PERM_FSPOOL_LAST +} virAccessPermFSPool; + +typedef enum { + + /** + * @desc: Access fs item + * @message: Acceessing fs item requires authorization + * @anonymous: 1 + */ + VIR_ACCESS_PERM_FSITEM_GETATTR, + + /** + * @desc: Read fs item + * @message: Reading fs item configuration requires authorization + * @anonymous: 1 + */ + VIR_ACCESS_PERM_FSITEM_READ, + + /** + * @desc: Create fs item + * @message: Creating fs item requires authorization + */ + VIR_ACCESS_PERM_FSITEM_CREATE, + + /** + * @desc: Delete fs item + * @message: Deleting fs item requires authorization + */ + VIR_ACCESS_PERM_FSITEM_DELETE, + + /** + * @desc: Format fs item + * @message: Formatting fs item data requires authorization + */ + VIR_ACCESS_PERM_FSITEM_FORMAT, + + /** + * @desc: Read fs item data + * @message: Reading fs item data requires authorization + */ + VIR_ACCESS_PERM_FSITEM_DATA_READ, + + /** + * @desc: Write fs item data + * @message: Writing fs item data requires authorization + */ + VIR_ACCESS_PERM_FSITEM_DATA_WRITE, + + VIR_ACCESS_PERM_FSITEM_LAST +} virAccessPermFSItem; + + VIR_ENUM_DECL(virAccessPermConnect); VIR_ENUM_DECL(virAccessPermDomain); VIR_ENUM_DECL(virAccessPermInterface); @@ -660,5 +784,7 @@ VIR_ENUM_DECL(virAccessPermNWFilter); VIR_ENUM_DECL(virAccessPermSecret); VIR_ENUM_DECL(virAccessPermStoragePool); VIR_ENUM_DECL(virAccessPermStorageVol); +VIR_ENUM_DECL(virAccessPermFSPool); +VIR_ENUM_DECL(virAccessPermFSItem); #endif /* __VIR_ACCESS_PERM_H__ */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 8589394..a14dfc8 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -19,7 +19,8 @@ virAccessManagerGetDefault; virAccessManagerNew; virAccessManagerNewStack; virAccessManagerSetDefault; - +virAccessManagerCheckFSItem; +virAccessManagerCheckFSPool; # access/viraccessperm.h virAccessPermConnectTypeFromString; @@ -40,7 +41,7 @@ virAccessPermStoragePoolTypeFromString; virAccessPermStoragePoolTypeToString; virAccessPermStorageVolTypeFromString; virAccessPermStorageVolTypeToString; - +virAccessPermFSPoolTypeToString; # conf/capabilities.h virCapabilitiesAddGuest; -- 1.8.3.1

In order to use fspool use --with-fs configuration option. It is is turned off by default. Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- configure.ac | 6 ++++++ m4/virt-driver-fspool.m4 | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 m4/virt-driver-fspool.m4 diff --git a/configure.ac b/configure.ac index 9e26b8c..2f9b78d 100644 --- a/configure.ac +++ b/configure.ac @@ -1074,6 +1074,11 @@ dnl LIBVIRT_DRIVER_CHECK_BHYVE +dnl +dnl Checks for FSPOOL driver +dnl + +LIBVIRT_DRIVER_CHECK_FSPOOL dnl dnl check for kernel headers required by src/bridge.c @@ -2636,6 +2641,7 @@ AC_MSG_NOTICE([ ESX: $with_esx]) AC_MSG_NOTICE([ Hyper-V: $with_hyperv]) LIBVIRT_DRIVER_RESULT_VZ LIBVIRT_DRIVER_RESULT_BHYVE +LIBVIRT_DRIVER_RESULT_FSPOOL AC_MSG_NOTICE([ Test: $with_test]) AC_MSG_NOTICE([ Remote: $with_remote]) AC_MSG_NOTICE([ Network: $with_network]) diff --git a/m4/virt-driver-fspool.m4 b/m4/virt-driver-fspool.m4 new file mode 100644 index 0000000..634cb7f --- /dev/null +++ b/m4/virt-driver-fspool.m4 @@ -0,0 +1,33 @@ +dnl The FSPool driver checks +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_DRIVER_CHECK_FSPOOL],[ + AC_ARG_WITH([fs], + [AS_HELP_STRING([--with-fs], + [add FS driver @<:@default=check@:>@])]) + m4_divert_text([DEFAULTS], [with_fs=check]) + + if test "$with_fs" = "yes"; then + AC_DEFINE_UNQUOTED([WITH_FS], 1, + [whether fs driver is enabled]) + fi + AM_CONDITIONAL([WITH_FS], [test "$with_fs" = "yes"]) +]) + +AC_DEFUN([LIBVIRT_DRIVER_RESULT_FSPOOL],[ + AC_MSG_NOTICE([ FSPool: $with_fs]) +]) -- 1.8.3.1

Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- daemon/remote.c | 35 ++++ src/Makefile.am | 6 +- src/check-driverimpls.pl | 2 + src/remote/remote_driver.c | 66 ++++++ src/remote/remote_protocol.x | 466 ++++++++++++++++++++++++++++++++++++++++++- src/remote_protocol-structs | 165 +++++++++++++++ src/rpc/gendispatch.pl | 23 ++- 7 files changed, 753 insertions(+), 10 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index e414f92..33e5e77 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -88,6 +88,8 @@ static virNetworkPtr get_nonnull_network(virConnectPtr conn, remote_nonnull_netw static virInterfacePtr get_nonnull_interface(virConnectPtr conn, remote_nonnull_interface iface); static virStoragePoolPtr get_nonnull_storage_pool(virConnectPtr conn, remote_nonnull_storage_pool pool); static virStorageVolPtr get_nonnull_storage_vol(virConnectPtr conn, remote_nonnull_storage_vol vol); +static virFSPoolPtr get_nonnull_fspool(virConnectPtr conn, remote_nonnull_fspool fspool); +static virFSItemPtr get_nonnull_fsitem(virConnectPtr conn, remote_nonnull_fsitem item); static virSecretPtr get_nonnull_secret(virConnectPtr conn, remote_nonnull_secret secret); static virNWFilterPtr get_nonnull_nwfilter(virConnectPtr conn, remote_nonnull_nwfilter nwfilter); static virDomainSnapshotPtr get_nonnull_domain_snapshot(virDomainPtr dom, remote_nonnull_domain_snapshot snapshot); @@ -97,6 +99,8 @@ static void make_nonnull_network(remote_nonnull_network *net_dst, virNetworkPtr static void make_nonnull_interface(remote_nonnull_interface *interface_dst, virInterfacePtr interface_src); static void make_nonnull_storage_pool(remote_nonnull_storage_pool *pool_dst, virStoragePoolPtr pool_src); static void make_nonnull_storage_vol(remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_src); +static void make_nonnull_fspool(remote_nonnull_fspool *fspool_dst, virFSPoolPtr fspool_src); +static void make_nonnull_fsitem(remote_nonnull_fsitem *item_dst, virFSItemPtr item_src); static void make_nonnull_node_device(remote_nonnull_node_device *dev_dst, virNodeDevicePtr dev_src); static void make_nonnull_secret(remote_nonnull_secret *secret_dst, virSecretPtr secret_src); static void make_nonnull_nwfilter(remote_nonnull_nwfilter *net_dst, virNWFilterPtr nwfilter_src); @@ -6660,6 +6664,22 @@ get_nonnull_domain_snapshot(virDomainPtr dom, remote_nonnull_domain_snapshot sna return virGetDomainSnapshot(dom, snapshot.name); } +static virFSPoolPtr +get_nonnull_fspool(virConnectPtr conn, remote_nonnull_fspool fspool) +{ + return virGetFSPool(conn, fspool.name, BAD_CAST fspool.uuid, + NULL, NULL); +} + +static virFSItemPtr +get_nonnull_fsitem(virConnectPtr conn, remote_nonnull_fsitem item) +{ + virFSItemPtr ret; + ret = virGetFSItem(conn, item.fspool, item.name, item.key, + NULL, NULL); + return ret; +} + static virNodeDevicePtr get_nonnull_node_device(virConnectPtr conn, remote_nonnull_node_device dev) { @@ -6706,6 +6726,21 @@ make_nonnull_storage_vol(remote_nonnull_storage_vol *vol_dst, virStorageVolPtr v } static void +make_nonnull_fspool(remote_nonnull_fspool *fspool_dst, virFSPoolPtr fspool_src) +{ + ignore_value(VIR_STRDUP_QUIET(fspool_dst->name, fspool_src->name)); + memcpy(fspool_dst->uuid, fspool_src->uuid, VIR_UUID_BUFLEN); +} + +static void +make_nonnull_fsitem(remote_nonnull_fsitem *item_dst, virFSItemPtr item_src) +{ + ignore_value(VIR_STRDUP_QUIET(item_dst->fspool, item_src->pool)); + ignore_value(VIR_STRDUP_QUIET(item_dst->name, item_src->name)); + ignore_value(VIR_STRDUP_QUIET(item_dst->key, item_src->key)); +} + +static void make_nonnull_node_device(remote_nonnull_node_device *dev_dst, virNodeDevicePtr dev_src) { ignore_value(VIR_STRDUP_QUIET(dev_dst->name, dev_src->name)); diff --git a/src/Makefile.am b/src/Makefile.am index 13a4976..2c9d675 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -233,7 +233,8 @@ DRIVER_SOURCES = \ locking/lock_driver_nop.h locking/lock_driver_nop.c \ locking/domain_lock.h locking/domain_lock.c \ logging/log_manager.c logging/log_manager.h \ - $(NULL) + libvirt-fs.c \ + $(NULL) LOCK_DRIVER_SANLOCK_SOURCES = \ locking/lock_driver_sanlock.c @@ -2400,7 +2401,8 @@ libvirt_setuid_rpc_client_la_SOURCES = \ libvirt-storage.c \ libvirt-stream.c \ libvirt-lxc.c \ - $(NULL) + libvirt-fs.c \ + $(NULL) libvirt_setuid_rpc_client_la_LDFLAGS = \ $(AM_LDFLAGS) \ diff --git a/src/check-driverimpls.pl b/src/check-driverimpls.pl index e320558..bd86886 100755 --- a/src/check-driverimpls.pl +++ b/src/check-driverimpls.pl @@ -54,6 +54,8 @@ while (<>) { if ($api !~ /^$mainprefix/) { $suffix =~ s/^[a-z]+(?:Unified)?//; $suffix =~ s/^([A-Z]+)/lc $1/e; + $suffix =~ s/fsitem/fsItem/; + $suffix =~ s/fspool/fsPool/; } if ($api ne $suffix) { diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index a3cd7cd..b08d598 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -144,6 +144,8 @@ static virNWFilterPtr get_nonnull_nwfilter(virConnectPtr conn, remote_nonnull_nw static virInterfacePtr get_nonnull_interface(virConnectPtr conn, remote_nonnull_interface iface); static virStoragePoolPtr get_nonnull_storage_pool(virConnectPtr conn, remote_nonnull_storage_pool pool); static virStorageVolPtr get_nonnull_storage_vol(virConnectPtr conn, remote_nonnull_storage_vol vol); +static virFSPoolPtr get_nonnull_fspool(virConnectPtr conn, remote_nonnull_fspool fspool); +static virFSItemPtr get_nonnull_fsitem(virConnectPtr conn, remote_nonnull_fsitem item); static virNodeDevicePtr get_nonnull_node_device(virConnectPtr conn, remote_nonnull_node_device dev); static virSecretPtr get_nonnull_secret(virConnectPtr conn, remote_nonnull_secret secret); static virDomainSnapshotPtr get_nonnull_domain_snapshot(virDomainPtr domain, remote_nonnull_domain_snapshot snapshot); @@ -152,6 +154,8 @@ static void make_nonnull_network(remote_nonnull_network *net_dst, virNetworkPtr static void make_nonnull_interface(remote_nonnull_interface *interface_dst, virInterfacePtr interface_src); static void make_nonnull_storage_pool(remote_nonnull_storage_pool *pool_dst, virStoragePoolPtr vol_src); static void make_nonnull_storage_vol(remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_src); +static void make_nonnull_fspool(remote_nonnull_fspool *fspool_dst, virFSPoolPtr fspool_src); +static void make_nonnull_fsitem(remote_nonnull_fsitem *item_dst, virFSItemPtr item_src); static void make_nonnull_node_device(remote_nonnull_node_device *dev_dst, virNodeDevicePtr dev_src); static void make_nonnull_secret(remote_nonnull_secret *secret_dst, virSecretPtr secret_src); @@ -7841,6 +7845,19 @@ get_nonnull_storage_vol(virConnectPtr conn, remote_nonnull_storage_vol vol) NULL, NULL); } +static virFSPoolPtr +get_nonnull_fspool(virConnectPtr conn, remote_nonnull_fspool fspool) +{ + return virGetFSPool(conn, fspool.name, BAD_CAST fspool.uuid, + NULL, NULL); +} + +static virFSItemPtr +get_nonnull_fsitem(virConnectPtr conn, remote_nonnull_fsitem item) +{ + return virGetFSItem(conn, item.fspool, item.name, item.key, + NULL, NULL); +} static virNodeDevicePtr get_nonnull_node_device(virConnectPtr conn, remote_nonnull_node_device dev) { @@ -7906,6 +7923,21 @@ make_nonnull_storage_vol(remote_nonnull_storage_vol *vol_dst, virStorageVolPtr v } static void +make_nonnull_fspool(remote_nonnull_fspool *fspool_dst, virFSPoolPtr fspool_src) +{ + fspool_dst->name = fspool_src->name; + memcpy(fspool_dst->uuid, fspool_src->uuid, VIR_UUID_BUFLEN); +} + +static void +make_nonnull_fsitem(remote_nonnull_fsitem *item_dst, virFSItemPtr item_src) +{ + item_dst->fspool = item_src->pool; + item_dst->name = item_src->name; + item_dst->key = item_src->key; +} + +static void make_nonnull_secret(remote_nonnull_secret *secret_dst, virSecretPtr secret_src) { memcpy(secret_dst->uuid, secret_src->uuid, VIR_UUID_BUFLEN); @@ -8296,6 +8328,39 @@ static virNWFilterDriver nwfilter_driver = { .connectListAllNWFilters = remoteConnectListAllNWFilters, /* 0.10.2 */ }; +static virFSDriver fspool_driver = { + .fsPoolLookupByName = remoteFSPoolLookupByName, + .fsPoolLookupByUUID = remoteFSPoolLookupByUUID, + .fsPoolLookupByItem = remoteFSPoolLookupByItem, + .fsPoolCreateXML = remoteFSPoolCreateXML, + .fsPoolDefineXML = remoteFSPoolDefineXML, + .fsPoolBuild = remoteFSPoolBuild, + .fsPoolUndefine = remoteFSPoolUndefine, + .fsPoolCreate = remoteFSPoolCreate, + .fsPoolDestroy = remoteFSPoolDestroy, + .fsPoolDelete = remoteFSPoolDelete, + .fsPoolRefresh = remoteFSPoolRefresh, + .fsPoolGetInfo = remoteFSPoolGetInfo, + .fsPoolGetXMLDesc = remoteFSPoolGetXMLDesc, + .fsPoolGetAutostart = remoteFSPoolGetAutostart, + .fsPoolSetAutostart = remoteFSPoolSetAutostart, + .fsPoolNumOfItems = remoteFSPoolNumOfItems, + .fsPoolListItems = remoteFSPoolListItems, + .fsPoolListAllItems = remoteFSPoolListAllItems, + .fsItemLookupByName = remoteFSItemLookupByName, + .fsItemLookupByKey = remoteFSItemLookupByKey, + .fsItemLookupByPath = remoteFSItemLookupByPath, + .fsItemCreateXML = remoteFSItemCreateXML, + .fsItemCreateXMLFrom = remoteFSItemCreateXMLFrom, + .fsItemDelete = remoteFSItemDelete, + .fsItemGetInfo = remoteFSItemGetInfo, + .fsItemGetXMLDesc = remoteFSItemGetXMLDesc, + .fsItemGetPath = remoteFSItemGetPath, + .fsPoolIsActive = remoteFSPoolIsActive, + .fsPoolIsPersistent = remoteFSPoolIsPersistent, + .connectListAllFSPools = remoteConnectListAllFSPools, +}; + static virConnectDriver connect_driver = { .hypervisorDriver = &hypervisor_driver, .interfaceDriver = &interface_driver, @@ -8304,6 +8369,7 @@ static virConnectDriver connect_driver = { .nwfilterDriver = &nwfilter_driver, .secretDriver = &secret_driver, .storageDriver = &storage_driver, + .fsDriver = &fspool_driver, }; static virStateDriver state_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index e8382dc..d1493fc 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -85,6 +85,12 @@ const REMOTE_STORAGE_POOL_LIST_MAX = 4096; /* Upper limit on lists of storage vols. */ const REMOTE_STORAGE_VOL_LIST_MAX = 16384; +/* Upper limit on lists of fspools. */ +const REMOTE_FSPOOL_LIST_MAX = 4096; + +/* Upper limit on lists of fsitems. */ +const REMOTE_FSITEM_LIST_MAX = 16384; + /* Upper limit on lists of node devices. */ const REMOTE_NODE_DEVICE_LIST_MAX = 16384; @@ -294,6 +300,19 @@ struct remote_nonnull_storage_vol { remote_nonnull_string key; }; +/* A fspool which may not be NULL. */ +struct remote_nonnull_fspool { + remote_nonnull_string name; + remote_uuid uuid; +}; + +/* A fsitem which may not be NULL. */ +struct remote_nonnull_fsitem { + remote_nonnull_string fspool; + remote_nonnull_string name; + remote_nonnull_string key; +}; + /* A node device which may not be NULL. */ struct remote_nonnull_node_device { remote_nonnull_string name; @@ -318,6 +337,8 @@ typedef remote_nonnull_network *remote_network; typedef remote_nonnull_nwfilter *remote_nwfilter; typedef remote_nonnull_storage_pool *remote_storage_pool; typedef remote_nonnull_storage_vol *remote_storage_vol; +typedef remote_nonnull_fspool *remote_fspool; +typedef remote_nonnull_fsitem *remote_fsitem; typedef remote_nonnull_node_device *remote_node_device; /* Error message. See <virterror.h> for explanation of fields. */ @@ -1955,6 +1976,206 @@ struct remote_storage_vol_resize_args { unsigned int flags; }; +/* FS pool calls: */ + +struct remote_fspool_lookup_by_uuid_args { + remote_uuid uuid; +}; + +struct remote_fspool_lookup_by_uuid_ret { + remote_nonnull_fspool pool; +}; + +struct remote_fspool_lookup_by_name_args { + remote_nonnull_string name; +}; + +struct remote_fspool_lookup_by_name_ret { + remote_nonnull_fspool fspool; +}; + +struct remote_fspool_lookup_by_item_args { + remote_nonnull_fsitem item; +}; + +struct remote_fspool_lookup_by_item_ret { + remote_nonnull_fspool fspool; +}; + +struct remote_fspool_create_xml_args { + remote_nonnull_string xml; + unsigned int flags; +}; + +struct remote_fspool_create_xml_ret { + remote_nonnull_fspool fspool; +}; + +struct remote_fspool_define_xml_args { + remote_nonnull_string xml; + unsigned int flags; +}; + +struct remote_fspool_define_xml_ret { + remote_nonnull_fspool fspool; +}; + +struct remote_fspool_build_args { + remote_nonnull_fspool fspool; + unsigned int flags; +}; + +struct remote_fspool_undefine_args { + remote_nonnull_fspool fspool; +}; + +struct remote_fspool_create_args { + remote_nonnull_fspool fspool; + unsigned int flags; +}; + +struct remote_fspool_destroy_args { + remote_nonnull_fspool fspool; +}; +struct remote_fspool_delete_args { + remote_nonnull_fspool fspool; + unsigned int flags; +}; + +struct remote_fspool_get_xml_desc_args { + remote_nonnull_fspool fspool; + unsigned int flags; +}; + +struct remote_fs_pool_get_xml_desc_ret { + remote_nonnull_string xml; +}; + +struct remote_fspool_get_info_args { + remote_nonnull_fspool fspool; +}; + +struct remote_fspool_get_info_ret { /* insert@1 */ + unsigned char state; + unsigned hyper capacity; + unsigned hyper allocation; + unsigned hyper available; +}; + +struct remote_fspool_get_autostart_args { + remote_nonnull_fspool fspool; +}; + +struct remote_fspool_get_autostart_ret { + int autostart; +}; + +struct remote_fspool_set_autostart_args { + remote_nonnull_fspool fspool; + int autostart; +}; + +struct remote_fspool_num_of_items_args { + remote_nonnull_fspool fspool; +}; + +struct remote_fspool_num_of_items_ret { + int num; +}; + +struct remote_fspool_list_items_args { + remote_nonnull_fspool fspool; + int maxnames; +}; + +struct remote_fspool_list_items_ret { + remote_nonnull_string names<REMOTE_FSITEM_LIST_MAX>; /* insert@1 */ +}; +struct remote_fspool_refresh_args { + remote_nonnull_fspool fspool; + unsigned int flags; +}; + +/* FS item calls: */ + +struct remote_fsitem_lookup_by_name_args { + remote_nonnull_fspool fspool; + remote_nonnull_string name; +}; + +struct remote_fsitem_lookup_by_name_ret { + remote_nonnull_fsitem item; +}; + +struct remote_fsitem_lookup_by_key_args { + remote_nonnull_string key; +}; + +struct remote_fsitem_lookup_by_key_ret { + remote_nonnull_fsitem item; +}; + +struct remote_fsitem_lookup_by_path_args { + remote_nonnull_string path; +}; + +struct remote_fsitem_lookup_by_path_ret { + remote_nonnull_fsitem item; +}; + +struct remote_fsitem_create_xml_args { + remote_nonnull_fspool fspool; + remote_nonnull_string xml; + unsigned int flags; +}; + +struct remote_fsitem_create_xml_ret { + remote_nonnull_fsitem item; +}; + +struct remote_fsitem_create_xml_from_args { + remote_nonnull_fspool fspool; + remote_nonnull_string xml; + remote_nonnull_fsitem cloneitem; + unsigned int flags; +}; + +struct remote_fsitem_create_xml_from_ret { + remote_nonnull_fsitem item; +}; + +struct remote_fsitem_delete_args { + remote_nonnull_fsitem item; + unsigned int flags; +}; + +struct remote_fsitem_get_xml_desc_args { + remote_nonnull_fsitem item; + unsigned int flags; +}; + +struct remote_fsitem_get_xml_desc_ret { + remote_nonnull_string xml; +}; + +struct remote_fsitem_get_info_args { + remote_nonnull_fsitem item; +}; + +struct remote_fsitem_get_info_ret { /* insert@1 */ + char type; + unsigned hyper capacity; + unsigned hyper allocation; +}; + +struct remote_fsitem_get_path_args { + remote_nonnull_fsitem item; +}; + +struct remote_fsitem_get_path_ret { + remote_nonnull_string name; +}; + /* Node driver calls: */ struct remote_node_num_of_devices_args { @@ -2244,7 +2465,21 @@ struct remote_storage_pool_is_persistent_ret { int persistent; }; +struct remote_fspool_is_active_args { + remote_nonnull_fspool fspool; +}; +struct remote_fspool_is_active_ret { + int active; +}; + +struct remote_fspool_is_persistent_args { + remote_nonnull_fspool fspool; +}; + +struct remote_fspool_is_persistent_ret { + int persistent; +}; struct remote_interface_is_active_args { remote_nonnull_interface iface; }; @@ -2874,6 +3109,27 @@ struct remote_storage_pool_list_all_volumes_ret { /* insert@1 */ unsigned int ret; }; +struct remote_connect_list_all_fspools_args { + int need_results; + unsigned int flags; +}; + +struct remote_connect_list_all_fspools_ret { /* insert@1 */ + remote_nonnull_fspool fspools<REMOTE_FSPOOL_LIST_MAX>; + unsigned int ret; +}; + +struct remote_fspool_list_all_items_args { + remote_nonnull_fspool fspool; + int need_results; + unsigned int flags; +}; + +struct remote_fspool_list_all_items_ret { /* insert@1 */ + remote_nonnull_fsitem items<REMOTE_FSITEM_LIST_MAX>; + unsigned int ret; +}; + struct remote_connect_list_all_networks_args { int need_results; unsigned int flags; @@ -5934,5 +6190,213 @@ enum remote_procedure { * @generate: both * @acl: none */ - REMOTE_PROC_NODE_DEVICE_EVENT_UPDATE = 377 + REMOTE_PROC_NODE_DEVICE_EVENT_UPDATE = 377, + + /** + * @generate: both + * @acl: fspool:start + * @acl: fspool:write + */ + REMOTE_PROC_FSPOOL_CREATE_XML = 382, + + /** + * @generate: both + * @priority: high + * @acl: fspool:write + * @acl: fspool:save + */ + REMOTE_PROC_FSPOOL_DEFINE_XML = 383, + + /** + * @generate: both + * @acl: fspool:format + */ + REMOTE_PROC_FSPOOL_BUILD = 384, + + /** + * @generate: both + * @acl: fspool:format + */ + REMOTE_PROC_FSPOOL_DELETE = 385, + + /** + * @generate: both + * @priority: high + * @acl: fspool:delete + */ + REMOTE_PROC_FSPOOL_UNDEFINE = 386, + + /** + * @generate: both + * @priority: high + * @acl: fspool:getattr + */ + REMOTE_PROC_FSPOOL_LOOKUP_BY_NAME = 387, + + /** + * @generate: both + * @priority: high + * @acl: fspool:getattr + */ + REMOTE_PROC_FSPOOL_LOOKUP_BY_UUID = 388, + + /** + * @generate: both + * @priority: high + * @acl: fspool:getattr + */ + REMOTE_PROC_FSPOOL_LOOKUP_BY_ITEM = 389, + + /** + * @generate: both + * @priority: high + * @acl: fspool:read + */ + REMOTE_PROC_FSPOOL_GET_INFO = 390, + + /** + * @generate: both + * @priority: high + * @acl: fspool:read + */ + REMOTE_PROC_FSPOOL_GET_XML_DESC = 391, + + /** + * @generate: both + * @priority: high + * @acl: fspool:search_items + * @aclfilter: fsitem:getattr + */ + REMOTE_PROC_FSPOOL_NUM_OF_ITEMS = 392, + + /** + * @generate: both + * @priority: high + * @acl: fspool:search_items + * @aclfilter: fsitem:getattr + */ + REMOTE_PROC_FSPOOL_LIST_ITEMS = 393, + + /** + * @generate: both + * @acl: fsitem:create + */ + REMOTE_PROC_FSITEM_CREATE_XML = 394, + + /** + * @generate: both + * @acl: fsitem:delete + */ + REMOTE_PROC_FSITEM_DELETE = 395, + + /** + * @generate: both + * @priority: high + * @acl: fsitem:getattr + */ + REMOTE_PROC_FSITEM_LOOKUP_BY_NAME = 396, + + /** + * @generate: both + * @priority: high + * @acl: fsitem:getattr + */ + REMOTE_PROC_FSITEM_LOOKUP_BY_KEY = 397, + + /** + * @generate: both + * @priority: high + * @acl: fsitem:getattr + */ + REMOTE_PROC_FSITEM_LOOKUP_BY_PATH = 398, + + /** + * @generate: both + * @priority: high + * @acl: fsitem:read + */ + REMOTE_PROC_FSITEM_GET_INFO = 399, + + /** + * @generate: both + * @priority: high + * @acl: fsitem:read + */ + REMOTE_PROC_FSITEM_GET_XML_DESC = 400, + + /** + * @generate: both + * @priority: high + * @acl: fsitem:read + */ + REMOTE_PROC_FSITEM_GET_PATH = 401, + + /** + * @generate: both + * @acl: fsitem:create + */ + REMOTE_PROC_FSITEM_CREATE_XML_FROM = 402, + + /** + * @generate: both + * @priority: high + * @acl: connect:search_fspools + * @aclfilter: fspool:getattr + */ + REMOTE_PROC_CONNECT_LIST_ALL_FSPOOLS = 403, + + /** + * @generate: both + * @priority: high + * @acl: fspool:search_items + * @aclfilter: fsitem:getattr + */ + REMOTE_PROC_FSPOOL_LIST_ALL_ITEMS = 404, + + /** + * @generate: both + * @acl: fspool:refresh + */ + REMOTE_PROC_FSPOOL_REFRESH = 405, + + /** + * @generate: both + * @priority: high + * @acl: fspool:read + */ + REMOTE_PROC_FSPOOL_IS_ACTIVE = 406, + + /** + * @generate: both + * @priority: high + * @acl: fspool:read + */ + REMOTE_PROC_FSPOOL_IS_PERSISTENT = 407, + + /** + * @generate: both + * @priority: high + * @acl: fspool:read + */ + REMOTE_PROC_FSPOOL_GET_AUTOSTART = 408, + + /** + * @generate: both + * @priority: high + * @acl: fspool:write + */ + REMOTE_PROC_FSPOOL_SET_AUTOSTART = 409, + + /** + * @generate: both + * @acl: fspool:start + */ + REMOTE_PROC_FSPOOL_CREATE = 410, + + /** + * @generate: both + * @priority: high + * @acl: fspool:stop + */ + REMOTE_PROC_FSPOOL_DESTROY = 411 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index b71accc..bac0efb 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -34,6 +34,15 @@ struct remote_nonnull_storage_vol { remote_nonnull_string name; remote_nonnull_string key; }; +struct remote_nonnull_fspool { + remote_nonnull_string name; + remote_uuid uuid; +}; +struct remote_nonnull_fsitem { + remote_nonnull_string fspool; + remote_nonnull_string name; + remote_nonnull_string key; +}; struct remote_nonnull_node_device { remote_nonnull_string name; }; @@ -1483,6 +1492,162 @@ struct remote_storage_vol_resize_args { uint64_t capacity; u_int flags; }; +struct remote_fspool_lookup_by_uuid_args { + remote_uuid uuid; +}; +struct remote_fspool_lookup_by_uuid_ret { + remote_nonnull_fspool pool; +}; +struct remote_fspool_lookup_by_name_args { + remote_nonnull_string name; +}; +struct remote_fspool_lookup_by_name_ret { + remote_nonnull_fspool fspool; +}; +struct remote_fspool_lookup_by_item_args { + remote_nonnull_fsitem item; +}; +struct remote_fspool_lookup_by_item_ret { + remote_nonnull_fspool fspool; +}; +struct remote_fspool_create_xml_args { + remote_nonnull_string xml; + unsigned int flags; +}; +struct remote_fspool_create_xml_ret { + remote_nonnull_fspool fspool; +}; +struct remote_fspool_define_xml_args { + remote_nonnull_string xml; + unsigned int flags; +}; +struct remote_fspool_define_xml_ret { + remote_nonnull_fspool fspool; +}; +struct remote_fspool_build_args { + remote_nonnull_fspool fspool; + unsigned int flags; +}; +struct remote_fspool_undefine_args { + remote_nonnull_fspool fspool; +}; +struct remote_fspool_create_args { + remote_nonnull_fspool fspool; + unsigned int flags; +}; + +struct remote_fspool_destroy_args { + remote_nonnull_fspool fspool; +}; +struct remote_fspool_delete_args { + remote_nonnull_fspool fspool; + unsigned int flags; +}; +struct remote_fspool_get_xml_desc_args { + remote_nonnull_fspool fspool; + unsigned int flags; +}; +struct remote_fs_pool_get_xml_desc_ret { + remote_nonnull_string xml; +}; +struct remote_fspool_get_info_args { + remote_nonnull_fspool fspool; +}; +struct remote_fspool_get_info_ret { + unsigned char state; + unsigned hyper capacity; + unsigned hyper allocation; + unsigned hyper available; +}; +struct remote_fspool_get_autostart_args { + remote_nonnull_fspool fspool; +}; +struct remote_fspool_get_autostart_ret { + int autostart; +}; +struct remote_fspool_set_autostart_args { + remote_nonnull_fspool fspool; + int autostart; +}; +struct remote_fspool_num_of_items_args { + remote_nonnull_fspool fspool; +}; +struct remote_fspool_num_of_items_ret { + int num; +}; +struct remote_fspool_list_items_args { + remote_nonnull_fspool fspool; + int maxnames; +}; + +struct remote_fspool_list_items_ret { + remote_nonnull_string names<REMOTE_FSITEM_LIST_MAX>; +}; +struct remote_fspool_refresh_args { + remote_nonnull_fspool fspool; + unsigned int flags; +}; +struct remote_fsitem_lookup_by_name_args { + remote_nonnull_fspool fspool; + remote_nonnull_string name; +}; +struct remote_fsitem_lookup_by_name_ret { + remote_nonnull_fsitem item; +}; +struct remote_fsitem_lookup_by_key_args { + remote_nonnull_string key; +}; +struct remote_fsitem_lookup_by_key_ret { + remote_nonnull_fsitem item; +}; +struct remote_fsitem_lookup_by_path_args { + remote_nonnull_string path; +}; +struct remote_fsitem_lookup_by_path_ret { + remote_nonnull_fsitem item; +}; +struct remote_fsitem_create_xml_args { + remote_nonnull_fspool fspool; + remote_nonnull_string xml; + unsigned int flags; +}; +struct remote_fsitem_create_xml_ret { + remote_nonnull_fsitem item; +}; +struct remote_fsitem_create_xml_from_args { + remote_nonnull_fspool fspool; + remote_nonnull_string xml; + remote_nonnull_fsitem cloneitem; + unsigned int flags; +}; +struct remote_fsitem_create_xml_from_ret { + remote_nonnull_fsitem item; +}; +struct remote_fsitem_delete_args { + remote_nonnull_fsitem item; + unsigned int flags; +}; +struct remote_fsitem_get_xml_desc_args { + remote_nonnull_fsitem item; + unsigned int flags; +}; +struct remote_fsitem_get_xml_desc_ret { + remote_nonnull_string xml; +}; +struct remote_fsitem_get_info_args { + remote_nonnull_fsitem item; +}; +struct remote_fsitem_get_info_ret { + char type; + unsigned hyper capacity; + unsigned hyper allocation; +}; +struct remote_fsitem_get_path_args { + remote_nonnull_fsitem item; +}; +struct remote_fsitem_get_path_ret { + remote_nonnull_string name; +}; struct remote_node_num_of_devices_args { remote_string cap; u_int flags; diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl index 173189c..7fd0bbd 100755 --- a/src/rpc/gendispatch.pl +++ b/src/rpc/gendispatch.pl @@ -56,6 +56,8 @@ sub fixup_name { my $name = shift; $name =~ s/Nwfilter/NWFilter/; + $name =~ s/Fspool/FSPool/; + $name =~ s/Fsitem/FSItem/; $name =~ s/Xml$/XML/; $name =~ s/Uri$/URI/; $name =~ s/Uuid$/UUID/; @@ -500,7 +502,7 @@ elsif ($mode eq "server") { if ($args_member =~ m/^remote_nonnull_string name;/ and $has_node_device) { # ignore the name arg for node devices next - } elsif ($args_member =~ m/^remote_nonnull_(domain|network|storage_pool|storage_vol|interface|secret|nwfilter) (\S+);/) { + } elsif ($args_member =~ m/^remote_nonnull_(domain|network|storage_pool|storage_vol|interface|secret|nwfilter|fspool|fsitem) (\S+);/) { my $type_name = name_to_TypeName($1); push(@vars_list, "vir${type_name}Ptr $2 = NULL"); @@ -665,7 +667,7 @@ elsif ($mode eq "server") { if (!$modern_ret_as_list) { push(@ret_list, "ret->$3 = tmp.$3;"); } - } elsif ($ret_member =~ m/(?:admin|remote)_nonnull_(secret|nwfilter|node_device|interface|network|storage_vol|storage_pool|domain_snapshot|domain|server|client) (\S+)<(\S+)>;/) { + } elsif ($ret_member =~ m/(?:admin|remote)_nonnull_(secret|nwfilter|node_device|interface|network|storage_vol|storage_pool|domain_snapshot|domain|server|client|fspool|fsitem) (\S+)<(\S+)>;/) { $modern_ret_struct_name = $1; $single_ret_list_error_msg_type = $1; $single_ret_list_name = $2; @@ -723,7 +725,7 @@ elsif ($mode eq "server") { $single_ret_var = $1; $single_ret_by_ref = 0; $single_ret_check = " == NULL"; - } elsif ($ret_member =~ m/^remote_nonnull_(domain|network|storage_pool|storage_vol|interface|node_device|secret|nwfilter|domain_snapshot) (\S+);/) { + } elsif ($ret_member =~ m/^remote_nonnull_(domain|network|storage_pool|storage_vol|interface|node_device|secret|nwfilter|domain_snapshot|fspool|fsitem) (\S+);/) { my $type_name = name_to_TypeName($1); if ($call->{ProcName} eq "DomainCreateWithFlags") { @@ -1268,7 +1270,7 @@ elsif ($mode eq "client") { $priv_src = "dev->conn"; push(@args_list, "virNodeDevicePtr dev"); push(@setters_list, "args.name = dev->name;"); - } elsif ($args_member =~ m/^remote_nonnull_(domain|network|storage_pool|storage_vol|interface|secret|nwfilter|domain_snapshot) (\S+);/) { + } elsif ($args_member =~ m/^remote_nonnull_(domain|network|storage_pool|storage_vol|interface|secret|nwfilter|domain_snapshot|fspool|fsitem) (\S+);/) { my $name = $1; my $arg_name = $2; my $type_name = name_to_TypeName($name); @@ -1461,7 +1463,7 @@ elsif ($mode eq "client") { } push(@ret_list, "memcpy(result->$3, ret.$3, sizeof(result->$3));"); - } elsif ($ret_member =~ m/(?:admin|remote)_nonnull_(secret|nwfilter|node_device|interface|network|storage_vol|storage_pool|domain_snapshot|domain|server|client) (\S+)<(\S+)>;/) { + } elsif ($ret_member =~ m/(?:admin|remote)_nonnull_(secret|nwfilter|node_device|interface|network|storage_vol|storage_pool|domain_snapshot|domain|server|client|fspool|fsitem) (\S+)<(\S+)>;/) { my $proc_name = name_to_TypeName($1); if ($structprefix eq "admin") { @@ -1513,7 +1515,7 @@ elsif ($mode eq "client") { push(@ret_list, "VIR_FREE(ret.$1);"); $single_ret_var = "char *rv = NULL"; $single_ret_type = "char *"; - } elsif ($ret_member =~ m/^remote_nonnull_(domain|network|storage_pool|storage_vol|node_device|interface|secret|nwfilter|domain_snapshot) (\S+);/) { + } elsif ($ret_member =~ m/^remote_nonnull_(domain|network|storage_pool|storage_vol|node_device|interface|secret|nwfilter|domain_snapshot|fspool|fsitem) (\S+);/) { my $name = $1; my $arg_name = $2; my $type_name = name_to_TypeName($name); @@ -1968,7 +1970,8 @@ elsif ($mode eq "client") { "storage_conf.h", "nwfilter_conf.h", "node_device_conf.h", - "interface_conf.h" + "interface_conf.h", + "fs_conf.h" ); foreach my $hdr (@headers) { print "#include \"$hdr\"\n"; @@ -2053,6 +2056,8 @@ elsif ($mode eq "client") { $object =~ s/^(\w)/uc $1/e; $object =~ s/_(\w)/uc $1/e; $object =~ s/Nwfilter/NWFilter/; + $object =~ s/Fspool/FSPool/; + $object =~ s/Fsitem/FSItem/; my $objecttype = $prefix . $object . "DefPtr"; $apiname .= $action . "ACL"; @@ -2065,6 +2070,8 @@ elsif ($mode eq "client") { if ($object ne "Connect") { if ($object eq "StorageVol") { push @argdecls, "virStoragePoolDefPtr pool"; + } elsif ($object eq "FSItem") { + push @argdecls, "virFSPoolDefPtr fspool"; } push @argdecls, "$objecttype $arg"; } @@ -2094,6 +2101,8 @@ elsif ($mode eq "client") { if ($object ne "Connect") { if ($object eq "StorageVol") { push @argvars, "pool"; + } elsif ($object eq "FSItem") { + push @argvars, "fspool"; } push @argvars, $arg; } -- 1.8.3.1

Due to reusage of structs and some of functions from storage pools we operate in storage terms. Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- po/POTFILES.in | 1 + src/Makefile.am | 7 +- src/conf/fs_conf.c | 1479 ++++++++++++++++++++++++++++++++++++++++++++++ src/conf/fs_conf.h | 103 ++++ src/libvirt_private.syms | 35 ++ 5 files changed, 1624 insertions(+), 1 deletion(-) create mode 100644 src/conf/fs_conf.c diff --git a/po/POTFILES.in b/po/POTFILES.in index 0c9b3e4..7ad9174 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -25,6 +25,7 @@ src/conf/domain_addr.c src/conf/domain_capabilities.c src/conf/domain_conf.c src/conf/domain_event.c +src/conf/fs_conf.c src/conf/interface_conf.c src/conf/netdev_bandwidth_conf.c src/conf/netdev_vlan_conf.c diff --git a/src/Makefile.am b/src/Makefile.am index 2c9d675..07e55ec 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -399,6 +399,10 @@ CHRDEV_CONF_SOURCES = \ DEVICE_CONF_SOURCES = \ conf/device_conf.c conf/device_conf.h +# FSPool driver sources +FS_CONF_SOURCES = \ + conf/fs_conf.c conf/fs_conf.h + CONF_SOURCES = \ $(NETDEV_CONF_SOURCES) \ $(DOMAIN_CONF_SOURCES) \ @@ -415,7 +419,8 @@ CONF_SOURCES = \ $(SECRET_CONF_SOURCES) \ $(CPU_CONF_SOURCES) \ $(CHRDEV_CONF_SOURCES) \ - $(DEVICE_CONF_SOURCES) + $(DEVICE_CONF_SOURCES) \ + $(FS_CONF_SOURCES) # The remote RPC driver, covering domains, storage, networks, etc REMOTE_DRIVER_GENERATED = \ diff --git a/src/conf/fs_conf.c b/src/conf/fs_conf.c new file mode 100644 index 0000000..4114ac3 --- /dev/null +++ b/src/conf/fs_conf.c @@ -0,0 +1,1479 @@ +/* + * fs_conf.c: config handling for fs driver + * Author: Olga Krishtal <okrishtal@virtuozzo.com> + * + * Copyright (C) 2016 Parallels IP Holdings GmbH + * + * 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/>. + */ + +#include <config.h> + +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <fcntl.h> +#include <string.h> + +#include "virerror.h" +#include "datatypes.h" +#include "fs_conf.h" + +#include "virxml.h" +#include "viruuid.h" +#include "virbuffer.h" +#include "viralloc.h" +#include "virfile.h" +#include "virstring.h" +#include "virlog.h" + +#define VIR_FROM_THIS VIR_FROM_FSPOOL + +VIR_LOG_INIT("conf.fs_conf"); + +VIR_ENUM_IMPL(virFSPool, + VIR_FSPOOL_LAST, + "dir") + +VIR_ENUM_IMPL(virFSItem, + VIR_FSITEM_LAST, + "dir") + +/* Flags to indicate mandatory components in the fspool source */ +enum { + VIR_FSPOOL_SOURCE_DIR = (1 << 2), + VIR_FSPOOL_SOURCE_NAME = (1 << 4), + VIR_FSPOOL_SOURCE_NETWORK = (1 << 6), +}; + +typedef const char *(*virFSItemFormatToString)(int format); +typedef int (*virFSItemFormatFromString)(const char *format); + +typedef const char *(*virFSPoolFormatToString)(int format); +typedef int (*virFSPoolFormatFromString)(const char *format); + +typedef struct _virFSItemOptions virFSItemOptions; +typedef virFSItemOptions *virFSItemOptionsPtr; +struct _virFSItemOptions { + int defaultFormat; + virFSItemFormatToString formatToString; + virFSItemFormatFromString formatFromString; +}; + +typedef struct _virFSPoolOptions virFSPoolOptions; +typedef virFSPoolOptions *virFSPoolOptionsPtr; +struct _virFSPoolOptions { + unsigned int flags; + int defaultFormat; + virFSPoolFormatToString formatToString; + virFSPoolFormatFromString formatFromString; +}; + +typedef struct _virFSPoolTypeInfo virFSPoolTypeInfo; +typedef virFSPoolTypeInfo *virFSPoolTypeInfoPtr; +struct _virFSPoolTypeInfo { + int fspoolType; + virFSPoolOptions fspoolOptions; + virFSItemOptions itemOptions; +}; + +static virFSPoolTypeInfo fspoolTypeInfo[] = { + {.fspoolType = VIR_FSPOOL_DIR} +}; + + +static virFSPoolTypeInfoPtr +virFSPoolTypeInfoLookup(int type) +{ + size_t i; + for (i = 0; i < ARRAY_CARDINALITY(fspoolTypeInfo); i++) + if (fspoolTypeInfo[i].fspoolType == type) + return &fspoolTypeInfo[i]; + + virReportError(VIR_ERR_INTERNAL_ERROR, + _("missing backend for fspool type %d"), type); + return NULL; +} + +static virFSPoolOptionsPtr +virFSPoolOptionsForPoolType(int type) +{ + virFSPoolTypeInfoPtr backend = virFSPoolTypeInfoLookup(type); + if (backend == NULL) + return NULL; + return &backend->fspoolOptions; +} + +static virFSItemOptionsPtr +virFSItemOptionsForPoolType(int type) +{ + virFSPoolTypeInfoPtr backend = virFSPoolTypeInfoLookup(type); + if (backend == NULL) + return NULL; + return &backend->itemOptions; +} + +void +virFSItemDefFree(virFSItemDefPtr def) +{ + if (!def) + return; + + VIR_FREE(def->name); + VIR_FREE(def->key); + + virStorageSourceClear(&def->target); + VIR_FREE(def); +} + +void +virFSPoolObjFree(virFSPoolObjPtr obj) +{ + if (!obj) + return; + + virFSPoolObjClearItems(obj); + + virStoragePoolDefFree(obj->def); + virStoragePoolDefFree(obj->newDef); + + VIR_FREE(obj->configFile); + VIR_FREE(obj->autostartLink); + + virMutexDestroy(&obj->lock); + + VIR_FREE(obj); +} + +void +virFSPoolObjListFree(virFSPoolObjListPtr fspools) +{ + size_t i; + for (i = 0; i < fspools->count; i++) + virFSPoolObjFree(fspools->objs[i]); + VIR_FREE(fspools->objs); + fspools->count = 0; +} + +void +virFSPoolObjRemove(virFSPoolObjListPtr fspools, + virFSPoolObjPtr fspool) +{ + size_t i; + + virFSPoolObjUnlock(fspool); + + for (i = 0; i < fspools->count; i++) { + virFSPoolObjLock(fspools->objs[i]); + if (fspools->objs[i] == fspool) { + virFSPoolObjUnlock(fspools->objs[i]); + virFSPoolObjFree(fspools->objs[i]); + + VIR_DELETE_ELEMENT(fspools->objs, i, fspools->count); + break; + } + virFSPoolObjUnlock(fspools->objs[i]); + } +} + +static int +virFSPoolDefParseSource(xmlXPathContextPtr ctxt, + virFSPoolSourcePtr source, + int fspool_type, + xmlNodePtr node) +{ + int ret = -1; + xmlNodePtr relnode /*, authnode, *nodeset = NULL*/; + virFSPoolOptionsPtr options; + + relnode = ctxt->node; + ctxt->node = node; + + if ((options = virFSPoolOptionsForPoolType(fspool_type)) == NULL) + goto cleanup; + + source->name = virXPathString("string(./name)", ctxt); + + if (options->formatFromString) { + char *format = virXPathString("string(./format/@type)", ctxt); + if (format == NULL) + source->format = options->defaultFormat; + else + source->format = options->formatFromString(format); + + if (source->format < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("unknown fspool format type %s"), format); + VIR_FREE(format); + goto cleanup; + } + VIR_FREE(format); + } + + source->dir = virXPathString("string(./dir/@path)", ctxt); + + source->product = virXPathString("string(./product/@name)", ctxt); + + ret = 0; + cleanup: + ctxt->node = relnode; + + return ret; +} + +virFSPoolSourcePtr +virFSPoolDefParseSourceString(const char *srcSpec, + int fspool_type) +{ + xmlDocPtr doc = NULL; + xmlNodePtr node = NULL; + xmlXPathContextPtr xpath_ctxt = NULL; + virFSPoolSourcePtr def = NULL, ret = NULL; + + if (!(doc = virXMLParseStringCtxt(srcSpec, + _("(storage_source_specification)"), + &xpath_ctxt))) + goto cleanup; + + if (VIR_ALLOC(def) < 0) + goto cleanup; + + if (!(node = virXPathNode("/source", xpath_ctxt))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("root element was not source")); + goto cleanup; + } + + if (virFSPoolDefParseSource(xpath_ctxt, def, fspool_type, + node) < 0) + goto cleanup; + + ret = def; + def = NULL; + cleanup: + virStoragePoolSourceFree(def); + xmlFreeDoc(doc); + xmlXPathFreeContext(xpath_ctxt); + + return ret; +} + +static virFSPoolDefPtr +virFSPoolDefParseXML(xmlXPathContextPtr ctxt) +{ + virFSPoolOptionsPtr options; + virFSPoolDefPtr ret; + xmlNodePtr source_node; + char *type = NULL; + char *uuid = NULL; + char *target_path = NULL; + + if (VIR_ALLOC(ret) < 0) + return NULL; + + type = virXPathString("string(./@type)", ctxt); + if (type == NULL) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("fspool missing type attribute")); + goto error; + } + + if ((ret->type = virFSPoolTypeFromString(type)) < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("unknown fspool type %s"), type); + goto error; + } + + if ((options = virFSPoolOptionsForPoolType(ret->type)) == NULL) + goto error; + + source_node = virXPathNode("./source", ctxt); + if (source_node) { + if (virFSPoolDefParseSource(ctxt, &ret->source, ret->type, + source_node) < 0) + goto error; + } + + ret->name = virXPathString("string(./name)", ctxt); + if (ret->name == NULL && + options->flags & VIR_FSPOOL_SOURCE_NAME) + ret->name = ret->source.name; + if (ret->name == NULL) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing pool source name element")); + goto error; + } + + if (strchr(ret->name, '/')) { + virReportError(VIR_ERR_XML_ERROR, + _("name %s cannot contain '/'"), ret->name); + goto error; + } + + uuid = virXPathString("string(./uuid)", ctxt); + if (uuid == NULL) { + if (virUUIDGenerate(ret->uuid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("unable to generate uuid")); + goto error; + } + } else { + if (virUUIDParse(uuid, ret->uuid) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("malformed uuid element")); + goto error; + } + } + + + if (options->flags & VIR_FSPOOL_SOURCE_DIR) { + if (!ret->source.dir) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing storage pool source path")); + goto error; + } + } + if (options->flags & VIR_FSPOOL_SOURCE_NAME) { + if (ret->source.name == NULL) { + /* source name defaults to pool name */ + if (VIR_STRDUP(ret->source.name, ret->name) < 0) + goto error; + } + } + target_path = virXPathString("string(./target/path)", ctxt); + if (!target_path) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing storage pool target path")); + goto error; + } + ret->target.path = virFileSanitizePath(target_path); + if (!ret->target.path) + goto error; + + if (virStorageDefParsePerms(ctxt, &ret->target.perms, + "./target/permissions") < 0) + goto error; + + cleanup: + VIR_FREE(uuid); + VIR_FREE(type); + VIR_FREE(target_path); + return ret; + + error: + virStoragePoolDefFree(ret); + ret = NULL; + goto cleanup; +} + +virFSPoolDefPtr +virFSPoolDefParseNode(xmlDocPtr xml, + xmlNodePtr root) +{ + xmlXPathContextPtr ctxt = NULL; + virFSPoolDefPtr def = NULL; + + if (!xmlStrEqual(root->name, BAD_CAST "fspool")) { + virReportError(VIR_ERR_XML_ERROR, + _("unexpected root element <%s>, " + "expecting <fspool>"), + root->name); + goto cleanup; + } + + ctxt = xmlXPathNewContext(xml); + if (ctxt == NULL) { + virReportOOMError(); + goto cleanup; + } + + ctxt->node = root; + def = virFSPoolDefParseXML(ctxt); + cleanup: + xmlXPathFreeContext(ctxt); + return def; +} + +static virFSPoolDefPtr +virFSPoolDefParse(const char *xmlStr, + const char *filename) +{ + virFSPoolDefPtr ret = NULL; + xmlDocPtr xml; + + if ((xml = virXMLParse(filename, xmlStr, _("(fs_pool_definition)")))) { + ret = virFSPoolDefParseNode(xml, xmlDocGetRootElement(xml)); + xmlFreeDoc(xml); + } + + return ret; +} + +virFSPoolDefPtr +virFSPoolDefParseString(const char *xmlStr) +{ + return virFSPoolDefParse(xmlStr, NULL); +} + +virFSPoolDefPtr +virFSPoolDefParseFile(const char *filename) +{ + return virFSPoolDefParse(NULL, filename); +} + +static int +virFSPoolSourceFormat(virBufferPtr buf, + virFSPoolOptionsPtr options, + virFSPoolSourcePtr src) +{ + + virBufferAddLit(buf, "<source>\n"); + virBufferAdjustIndent(buf, 2); + + if (options->flags & VIR_FSPOOL_SOURCE_DIR) + virBufferEscapeString(buf, "<dir path='%s'/>\n", src->dir); + + if (options->flags & VIR_FSPOOL_SOURCE_NAME) + virBufferEscapeString(buf, "<name>%s</name>\n", src->name); + + if (options->formatToString) { + const char *format = (options->formatToString)(src->format); + if (!format) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown pool format number %d"), + src->format); + return -1; + } + virBufferAsprintf(buf, "<format type='%s'/>\n", format); + } + + + virBufferEscapeString(buf, "<product name='%s'/>\n", src->product); + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</source>\n"); + return 0; +} + + +static int +virFSPoolDefFormatBuf(virBufferPtr buf, + virFSPoolDefPtr def) +{ + virFSPoolOptionsPtr options; + char uuid[VIR_UUID_STRING_BUFLEN]; + const char *type; + + options = virFSPoolOptionsForPoolType(def->type); + if (options == NULL) + return -1; + + type = virFSPoolTypeToString(def->type); + if (!type) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("unexpected fspool type")); + return -1; + } + virBufferAsprintf(buf, "<fspool type='%s'>\n", type); + virBufferAdjustIndent(buf, 2); + virBufferEscapeString(buf, "<name>%s</name>\n", def->name); + + virUUIDFormat(def->uuid, uuid); + virBufferAsprintf(buf, "<uuid>%s</uuid>\n", uuid); + + virBufferAsprintf(buf, "<capacity unit='bytes'>%llu</capacity>\n", + def->capacity); + virBufferAsprintf(buf, "<allocation unit='bytes'>%llu</allocation>\n", + def->allocation); + virBufferAsprintf(buf, "<available unit='bytes'>%llu</available>\n", + def->available); + + if (virFSPoolSourceFormat(buf, options, &def->source) < 0) + return -1; + + virBufferAddLit(buf, "<target>\n"); + virBufferAdjustIndent(buf, 2); + + virBufferEscapeString(buf, "<path>%s</path>\n", def->target.path); + + if (def->target.perms.mode != (mode_t) -1 || + def->target.perms.uid != (uid_t) -1 || + def->target.perms.gid != (gid_t) -1 || + def->target.perms.label) { + virBufferAddLit(buf, "<permissions>\n"); + virBufferAdjustIndent(buf, 2); + if (def->target.perms.mode != (mode_t) -1) + virBufferAsprintf(buf, "<mode>0%o</mode>\n", + def->target.perms.mode); + if (def->target.perms.uid != (uid_t) -1) + virBufferAsprintf(buf, "<owner>%d</owner>\n", + (int) def->target.perms.uid); + if (def->target.perms.gid != (gid_t) -1) + virBufferAsprintf(buf, "<group>%d</group>\n", + (int) def->target.perms.gid); + virBufferEscapeString(buf, "<label>%s</label>\n", + def->target.perms.label); + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</permissions>\n"); + } + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</target>\n"); + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</fspool>\n"); + + return 0; +} + +char * +virFSPoolDefFormat(virFSPoolDefPtr def) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (virFSPoolDefFormatBuf(&buf, def) < 0) + goto error; + + if (virBufferCheckError(&buf) < 0) + goto error; + + return virBufferContentAndReset(&buf); + + error: + virBufferFreeAndReset(&buf); + return NULL; +} + + +static int +virFSSize(const char *unit, + const char *val, + unsigned long long *ret) +{ + if (virStrToLong_ull(val, NULL, 10, ret) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("malformed capacity element")); + return -1; + } + /* off_t is signed, so you cannot create a file larger than 2**63 + * bytes in the first place. */ + if (virScaleInteger(ret, unit, 1, LLONG_MAX) < 0) + return -1; + + return 0; +} + +static virFSItemDefPtr +virFSItemDefParseXML(virFSPoolDefPtr fspool, + xmlXPathContextPtr ctxt, + unsigned int flags) +{ + virFSItemDefPtr ret; + virFSItemOptionsPtr options; + char *type = NULL; + char *allocation = NULL; + char *capacity = NULL; + char *unit = NULL; + xmlNodePtr *nodes = NULL; + + virCheckFlags(VIR_ITEM_XML_PARSE_NO_CAPACITY | + VIR_ITEM_XML_PARSE_OPT_CAPACITY, NULL); + + options = virFSItemOptionsForPoolType(fspool->type); + if (options == NULL) + return NULL; + + if (VIR_ALLOC(ret) < 0) + return NULL; + + ret->name = virXPathString("string(./name)", ctxt); + if (ret->name == NULL) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing item name element")); + goto error; + } + + /* Normally generated by pool refresh, but useful for unit tests */ + ret->key = virXPathString("string(./key)", ctxt); + + /* Technically overridden by pool refresh, but useful for unit tests */ + type = virXPathString("string(./@type)", ctxt); + if (type) { + if ((ret->type = virFSItemTypeFromString(type)) < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("unknown item type '%s'"), type); + goto error; + } + } + + capacity = virXPathString("string(./capacity)", ctxt); + unit = virXPathString("string(./capacity/@unit)", ctxt); + if (capacity) { + if (virFSSize(unit, capacity, &ret->target.capacity) < 0) + goto error; + } else if (!(flags & VIR_ITEM_XML_PARSE_NO_CAPACITY) && + !((flags & VIR_ITEM_XML_PARSE_OPT_CAPACITY))) { + virReportError(VIR_ERR_XML_ERROR, "%s", _("missing capacity element")); + goto error; + } + VIR_FREE(unit); + + allocation = virXPathString("string(./allocation)", ctxt); + if (allocation) { + unit = virXPathString("string(./allocation/@unit)", ctxt); + if (virFSSize(unit, allocation, &ret->target.allocation) < 0) + goto error; + } else { + ret->target.allocation = ret->target.capacity; + } + + ret->target.path = virXPathString("string(./target/path)", ctxt); + + if (VIR_ALLOC(ret->target.perms) < 0) + goto error; + if (virStorageDefParsePerms(ctxt, ret->target.perms, + "./target/permissions") < 0) + goto error; + + cleanup: + VIR_FREE(nodes); + VIR_FREE(allocation); + VIR_FREE(capacity); + VIR_FREE(unit); + VIR_FREE(type); + return ret; + + error: + virFSItemDefFree(ret); + ret = NULL; + goto cleanup; +} + +virFSItemDefPtr +virFSItemDefParseNode(virFSPoolDefPtr fspool, + xmlDocPtr xml, + xmlNodePtr root, + unsigned int flags) +{ + xmlXPathContextPtr ctxt = NULL; + virFSItemDefPtr def = NULL; + + if (!xmlStrEqual(root->name, BAD_CAST "item")) { + virReportError(VIR_ERR_XML_ERROR, + _("unexpected root element <%s>, " + "expecting <item>"), + root->name); + goto cleanup; + } + + ctxt = xmlXPathNewContext(xml); + if (ctxt == NULL) { + virReportOOMError(); + goto cleanup; + } + + ctxt->node = root; + def = virFSItemDefParseXML(fspool, ctxt, flags); + cleanup: + xmlXPathFreeContext(ctxt); + return def; +} + +static virFSItemDefPtr +virFSItemDefParse(virFSPoolDefPtr fspool, + const char *xmlStr, + const char *filename, + unsigned int flags) +{ + virFSItemDefPtr ret = NULL; + xmlDocPtr xml; + + if ((xml = virXMLParse(filename, xmlStr, _("(fspool_item_definition)")))) { + ret = virFSItemDefParseNode(fspool, xml, xmlDocGetRootElement(xml), flags); + xmlFreeDoc(xml); + } + + return ret; +} + +virFSItemDefPtr +virFSItemDefParseString(virFSPoolDefPtr fspool, + const char *xmlStr, + unsigned int flags) +{ + return virFSItemDefParse(fspool, xmlStr, NULL, flags); +} + +virFSItemDefPtr +virFSItemDefParseFile(virFSPoolDefPtr fspool, + const char *filename, + unsigned int flags) +{ + return virFSItemDefParse(fspool, NULL, filename, flags); +} + +static int +virFSItemTargetDefFormat(virFSItemOptionsPtr options ATTRIBUTE_UNUSED, + virBufferPtr buf, + virFSSourcePtr def, + const char *type) +{ + virBufferAsprintf(buf, "<%s>\n", type); + virBufferAdjustIndent(buf, 2); + + if (def->perms && + (def->perms->mode != (mode_t) -1 || + def->perms->uid != (uid_t) -1 || + def->perms->gid != (gid_t) -1 || + def->perms->label)) { + virBufferAddLit(buf, "<permissions>\n"); + virBufferAdjustIndent(buf, 2); + + if (def->perms->mode != (mode_t) -1) + virBufferAsprintf(buf, "<mode>0%o</mode>\n", + def->perms->mode); + if (def->perms->uid != (uid_t) -1) + virBufferAsprintf(buf, "<owner>%d</owner>\n", + (int) def->perms->uid); + if (def->perms->gid != (gid_t) -1) + virBufferAsprintf(buf, "<group>%d</group>\n", + (int) def->perms->gid); + + virBufferEscapeString(buf, "<label>%s</label>\n", + def->perms->label); + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</permissions>\n"); + } + + virBufferAdjustIndent(buf, -2); + virBufferAsprintf(buf, "</%s>\n", type); + return 0; +} + +char * +virFSItemDefFormat(virFSPoolDefPtr fspool, + virFSItemDefPtr def) +{ + virFSItemOptionsPtr options; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + options = virFSItemOptionsForPoolType(fspool->type); + if (options == NULL) + return NULL; + + virBufferAddLit(&buf, "<item>\n"); + virBufferAdjustIndent(&buf, 2); + + virBufferEscapeString(&buf, "<name>%s</name>\n", def->name); + virBufferEscapeString(&buf, "<key>%s</key>\n", def->key); + + virBufferAsprintf(&buf, "<capacity unit='bytes'>%llu</capacity>\n", + def->target.capacity); + virBufferAsprintf(&buf, "<allocation unit='bytes'>%llu</allocation>\n", + def->target.allocation); + + if (virFSItemTargetDefFormat(options, &buf, + &def->target, "target") < 0) + goto cleanup; + + virBufferAdjustIndent(&buf, -2); + virBufferAddLit(&buf, "</item>\n"); + + if (virBufferCheckError(&buf) < 0) + goto cleanup; + + return virBufferContentAndReset(&buf); + + cleanup: + virBufferFreeAndReset(&buf); + return NULL; +} + + +virFSPoolObjPtr +virFSPoolObjFindByUUID(virFSPoolObjListPtr fspools, + const unsigned char *uuid) +{ + size_t i; + + for (i = 0; i < fspools->count; i++) { + virFSPoolObjLock(fspools->objs[i]); + if (!memcmp(fspools->objs[i]->def->uuid, uuid, VIR_UUID_BUFLEN)) + return fspools->objs[i]; + virFSPoolObjUnlock(fspools->objs[i]); + } + + return NULL; +} + +virFSPoolObjPtr +virFSPoolObjFindByName(virFSPoolObjListPtr fspools, + const char *name) +{ + size_t i; + + for (i = 0; i < fspools->count; i++) { + virFSPoolObjLock(fspools->objs[i]); + if (STREQ(fspools->objs[i]->def->name, name)) + return fspools->objs[i]; + virFSPoolObjUnlock(fspools->objs[i]); + } + + return NULL; +} + + +void +virFSPoolObjClearItems(virFSPoolObjPtr fspool) +{ + size_t i; + for (i = 0; i < fspool->items.count; i++) + virFSItemDefFree(fspool->items.objs[i]); + + VIR_FREE(fspool->items.objs); + fspool->items.count = 0; +} + +virFSItemDefPtr +virFSItemDefFindByKey(virFSPoolObjPtr fspool, + const char *key) +{ + size_t i; + + for (i = 0; i < fspool->items.count; i++) + if (STREQ(fspool->items.objs[i]->key, key)) + return fspool->items.objs[i]; + + return NULL; +} + +virFSItemDefPtr +virFSItemDefFindByPath(virFSPoolObjPtr fspool, + const char *path) +{ + size_t i; + + for (i = 0; i < fspool->items.count; i++) + if (STREQ(fspool->items.objs[i]->target.path, path)) + return fspool->items.objs[i]; + + return NULL; +} + +virFSItemDefPtr +virFSItemDefFindByName(virFSPoolObjPtr fspool, + const char *name) +{ + size_t i; + + for (i = 0; i < fspool->items.count; i++) + if (STREQ(fspool->items.objs[i]->name, name)) + return fspool->items.objs[i]; + + return NULL; +} + +virFSPoolObjPtr +virFSPoolObjAssignDef(virFSPoolObjListPtr fspools, + virFSPoolDefPtr def) +{ + virFSPoolObjPtr fspool; + + if ((fspool = virFSPoolObjFindByName(fspools, def->name))) { + if (!virFSPoolObjIsActive(fspool)) { + virStoragePoolDefFree(fspool->def); + fspool->def = def; + } else { + virStoragePoolDefFree(fspool->newDef); + fspool->newDef = def; + } + return fspool; + } + + if (VIR_ALLOC(fspool) < 0) + return NULL; + + if (virMutexInit(&fspool->lock) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot initialize mutex")); + VIR_FREE(fspool); + return NULL; + } + virFSPoolObjLock(fspool); + fspool->active = 0; + + if (VIR_APPEND_ELEMENT_COPY(fspools->objs, fspools->count, fspool) < 0) { + virFSPoolObjUnlock(fspool); + virFSPoolObjFree(fspool); + return NULL; + } + fspool->def = def; + + return fspool; +} + +static virFSPoolObjPtr +virFSPoolObjLoad(virFSPoolObjListPtr fspools, + const char *file, + const char *path, + const char *autostartLink) +{ + virFSPoolDefPtr def; + virFSPoolObjPtr fspool; + + if (!(def = virFSPoolDefParseFile(path))) + return NULL; + + if (!virFileMatchesNameSuffix(file, def->name, ".xml")) { + virReportError(VIR_ERR_XML_ERROR, + _("Storage fspool config filename '%s' does " + "not match fspool name '%s'"), + path, def->name); + virStoragePoolDefFree(def); + return NULL; + } + + if (!(fspool = virFSPoolObjAssignDef(fspools, def))) { + virStoragePoolDefFree(def); + return NULL; + } + + VIR_FREE(fspool->configFile); /* for driver reload */ + if (VIR_STRDUP(fspool->configFile, path) < 0) { + virFSPoolObjRemove(fspools, fspool); + return NULL; + } + VIR_FREE(fspool->autostartLink); /* for driver reload */ + if (VIR_STRDUP(fspool->autostartLink, autostartLink) < 0) { + virFSPoolObjRemove(fspools, fspool); + return NULL; + } + + fspool->autostart = virFileLinkPointsTo(fspool->autostartLink, + fspool->configFile); + + return fspool; +} + + +virFSPoolObjPtr +virFSPoolLoadState(virFSPoolObjListPtr fspools, + const char *stateDir, + const char *name) +{ + char *stateFile = NULL; + virFSPoolDefPtr def = NULL; + virFSPoolObjPtr fspool = NULL; + xmlDocPtr xml = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlNodePtr node = NULL; + + if (!(stateFile = virFileBuildPath(stateDir, name, ".xml"))) + goto error; + + if (!(xml = virXMLParseCtxt(stateFile, NULL, _("(fspool state)"), &ctxt))) + goto error; + + if (!(node = virXPathNode("//fspool", ctxt))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not find any 'fspool' element in state file")); + goto error; + } + + ctxt->node = node; + if (!(def = virFSPoolDefParseXML(ctxt))) + goto error; + + if (STRNEQ(name, def->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Storage fspool state file '%s' does not match " + "fspool name '%s'"), + stateFile, def->name); + goto error; + } + + /* create the object */ + if (!(fspool = virFSPoolObjAssignDef(fspools, def))) + goto error; + + /* XXX: future handling of some additional useful status data, + * for now, if a status file for a fspool exists, the fspool will be marked + * as active + */ + + fspool->active = 1; + + cleanup: + VIR_FREE(stateFile); + xmlFreeDoc(xml); + xmlXPathFreeContext(ctxt); + return fspool; + + error: + virStoragePoolDefFree(def); + goto cleanup; +} + + +int +virFSPoolLoadAllState(virFSPoolObjListPtr fspools, + const char *stateDir) +{ + DIR *dir; + struct dirent *entry; + int ret = -1; + int rc; + + if ((rc = virDirOpenIfExists(&dir, stateDir)) <= 0) + return rc; + + while ((ret = virDirRead(dir, &entry, stateDir)) > 0) { + virFSPoolObjPtr fspool; + + if (!virFileStripSuffix(entry->d_name, ".xml")) + continue; + + if (!(fspool = virFSPoolLoadState(fspools, stateDir, entry->d_name))) + continue; + virFSPoolObjUnlock(fspool); + } + + VIR_DIR_CLOSE(dir); + return ret; +} + + +int +virFSPoolLoadAllConfigs(virFSPoolObjListPtr fspools, + const char *configDir, + const char *autostartDir) +{ + DIR *dir; + struct dirent *entry; + int ret; + int rc; + + if ((rc = virDirOpenIfExists(&dir, configDir)) <= 0) + return rc; + + while ((ret = virDirRead(dir, &entry, configDir)) > 0) { + char *path; + char *autostartLink; + virFSPoolObjPtr fspool; + + if (!virFileHasSuffix(entry->d_name, ".xml")) + continue; + + if (!(path = virFileBuildPath(configDir, entry->d_name, NULL))) + continue; + + if (!(autostartLink = virFileBuildPath(autostartDir, entry->d_name, + NULL))) { + VIR_FREE(path); + continue; + } + + fspool = virFSPoolObjLoad(fspools, entry->d_name, path, + autostartLink); + if (fspool) + virFSPoolObjUnlock(fspool); + + VIR_FREE(path); + VIR_FREE(autostartLink); + } + + VIR_DIR_CLOSE(dir); + return ret; +} + + +static int virFSPoolSaveXML(const char *path, + virFSPoolDefPtr def, + const char *xml) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN]; + int ret = -1; + + virUUIDFormat(def->uuid, uuidstr); + ret = virXMLSaveFile(path, + virXMLPickShellSafeComment(def->name, uuidstr), + "fspool-edit", xml); + + return ret; +} + + +int +virFSPoolSaveState(const char *stateFile, + virFSPoolDefPtr def) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + int ret = -1; + char *xml; + + virBufferAddLit(&buf, "<fspoolstate>\n"); + virBufferAdjustIndent(&buf, 2); + + if (virFSPoolDefFormatBuf(&buf, def) < 0) + goto error; + + virBufferAdjustIndent(&buf, -2); + virBufferAddLit(&buf, "</fspoolstate>\n"); + + if (virBufferCheckError(&buf) < 0) + goto error; + + if (!(xml = virBufferContentAndReset(&buf))) + goto error; + + if (virFSPoolSaveXML(stateFile, def, xml)) + goto error; + + ret = 0; + + error: + VIR_FREE(xml); + return ret; +} + + +int +virFSPoolSaveConfig(const char *configFile, + virFSPoolDefPtr def) +{ + char *xml; + int ret = -1; + + if (!(xml = virFSPoolDefFormat(def))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to generate XML")); + return -1; + } + + if (virFSPoolSaveXML(configFile, def, xml)) + goto cleanup; + + ret = 0; + cleanup: + VIR_FREE(xml); + return ret; +} + +int +virFSPoolObjSaveDef(virFSDriverStatePtr driver, + virFSPoolObjPtr fspool, + virFSPoolDefPtr def) +{ + if (!fspool->configFile) { + if (virFileMakePath(driver->configDir) < 0) { + virReportSystemError(errno, + _("cannot create config directory %s"), + driver->configDir); + return -1; + } + + if (!(fspool->configFile = virFileBuildPath(driver->configDir, + def->name, ".xml"))) { + return -1; + } + + if (!(fspool->autostartLink = virFileBuildPath(driver->autostartDir, + def->name, ".xml"))) { + VIR_FREE(fspool->configFile); + return -1; + } + } + + return virFSPoolSaveConfig(fspool->configFile, def); +} + +int +virFSPoolObjDeleteDef(virFSPoolObjPtr fspool) +{ + if (!fspool->configFile) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("no config file for %s"), fspool->def->name); + return -1; + } + + if (unlink(fspool->configFile) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot remove config for %s"), + fspool->def->name); + return -1; + } + + return 0; +} + +char * +virFSPoolSourceListFormat(virFSPoolSourceListPtr def) +{ + virFSPoolOptionsPtr options; + virBuffer buf = VIR_BUFFER_INITIALIZER; + const char *type; + size_t i; + + options = virFSPoolOptionsForPoolType(def->type); + if (options == NULL) + return NULL; + + type = virFSPoolTypeToString(def->type); + if (!type) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("unexpected fspool type")); + goto cleanup; + } + + virBufferAddLit(&buf, "<sources>\n"); + virBufferAdjustIndent(&buf, 2); + + for (i = 0; i < def->nsources; i++) + virFSPoolSourceFormat(&buf, options, &def->sources[i]); + + virBufferAdjustIndent(&buf, -2); + virBufferAddLit(&buf, "</sources>\n"); + + if (virBufferCheckError(&buf) < 0) + goto cleanup; + + return virBufferContentAndReset(&buf); + + cleanup: + virBufferFreeAndReset(&buf); + return NULL; +} + + +/* + * virFSPoolObjIsDuplicate: + * @doms : virFSPoolObjListPtr to search + * @def : virFSPoolDefPtr definition of fspool to lookup + * @check_active: If true, ensure that fspool is not active + * + * Returns: -1 on error + * 0 if fspool is new + * 1 if fspool is a duplicate + */ +int +virFSPoolObjIsDuplicate(virFSPoolObjListPtr fspools, + virFSPoolDefPtr def, + unsigned int check_active) +{ + int ret = -1; + virFSPoolObjPtr fspool = NULL; + + /* See if a Pool with matching UUID already exists */ + fspool = virFSPoolObjFindByUUID(fspools, def->uuid); + if (fspool) { + /* UUID matches, but if names don't match, refuse it */ + if (STRNEQ(fspool->def->name, def->name)) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(fspool->def->uuid, uuidstr); + virReportError(VIR_ERR_OPERATION_FAILED, + _("fspool '%s' is already defined with uuid %s"), + fspool->def->name, uuidstr); + goto cleanup; + } + + if (check_active) { + /* UUID & name match, but if Pool is already active, refuse it */ + if (virFSPoolObjIsActive(fspool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("fspool is already active as '%s'"), + fspool->def->name); + goto cleanup; + } + } + + ret = 1; + } else { + /* UUID does not match, but if a name matches, refuse it */ + fspool = virFSPoolObjFindByName(fspools, def->name); + if (fspool) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(fspool->def->uuid, uuidstr); + virReportError(VIR_ERR_OPERATION_FAILED, + _("fspool '%s' already exists with uuid %s"), + def->name, uuidstr); + goto cleanup; + } + ret = 0; + } + + cleanup: + if (fspool) + virFSPoolObjUnlock(fspool); + return ret; +} + +int +virFSPoolSourceFindDuplicate(virConnectPtr conn ATTRIBUTE_UNUSED, + virFSPoolObjListPtr fspools, + virFSPoolDefPtr def) +{ + size_t i; + int ret = 1; + virFSPoolObjPtr fspool = NULL; + virFSPoolObjPtr matchfspool = NULL; + + /* Check the fspool list for duplicate underlying storage */ + for (i = 0; i < fspools->count; i++) { + fspool = fspools->objs[i]; + if (def->type != fspool->def->type) + continue; + + /* Don't mach against ourself if re-defining existing fspool ! */ + if (STREQ(fspool->def->name, def->name)) + continue; + + virFSPoolObjLock(fspool); + + switch ((virFSPoolType)fspool->def->type) { + case VIR_FSPOOL_DIR: + if (STREQ(fspool->def->target.path, def->target.path)) + matchfspool = fspool; + break; + + case VIR_FSPOOL_LAST: + break; + } + virFSPoolObjUnlock(fspool); + + if (matchfspool) + break; + } + + if (matchfspool) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("FS source conflict with fspool: '%s'"), + matchfspool->def->name); + ret = -1; + } + return ret; +} + +void +virFSPoolObjLock(virFSPoolObjPtr obj) +{ + virMutexLock(&obj->lock); +} + +void +virFSPoolObjUnlock(virFSPoolObjPtr obj) +{ + virMutexUnlock(&obj->lock); +} + +#define MATCH(FLAG) (flags & (FLAG)) +static bool +virFSPoolMatch(virFSPoolObjPtr fspoolobj, + unsigned int flags) +{ + /* filter by active state */ + if (MATCH(VIR_CONNECT_LIST_FSPOOLS_FILTERS_ACTIVE) && + !((MATCH(VIR_CONNECT_LIST_FSPOOLS_ACTIVE) && + virFSPoolObjIsActive(fspoolobj)) || + (MATCH(VIR_CONNECT_LIST_FSPOOLS_INACTIVE) && + !virFSPoolObjIsActive(fspoolobj)))) + return false; + + /* filter by persistence */ + if (MATCH(VIR_CONNECT_LIST_FSPOOLS_FILTERS_PERSISTENT) && + !((MATCH(VIR_CONNECT_LIST_FSPOOLS_PERSISTENT) && + fspoolobj->configFile) || + (MATCH(VIR_CONNECT_LIST_FSPOOLS_TRANSIENT) && + !fspoolobj->configFile))) + return false; + + /* filter by autostart option */ + if (MATCH(VIR_CONNECT_LIST_FSPOOLS_FILTERS_AUTOSTART) && + !((MATCH(VIR_CONNECT_LIST_FSPOOLS_AUTOSTART) && + fspoolobj->autostart) || + (MATCH(VIR_CONNECT_LIST_FSPOOLS_NO_AUTOSTART) && + !fspoolobj->autostart))) + return false; + + /* filter by fspool type */ + if (MATCH(VIR_CONNECT_LIST_FSPOOLS_FILTERS_POOL_TYPE)) { + if (!(MATCH(VIR_CONNECT_LIST_FSPOOLS_DIR) && + (fspoolobj->def->type == VIR_FSPOOL_DIR))) + return false; + } + + return true; +} +#undef MATCH + +int +virFSPoolObjListExport(virConnectPtr conn, + virFSPoolObjList fspoolobjs, + virFSPoolPtr **fspools, + virFSPoolObjListFilter filter, + unsigned int flags) +{ + virFSPoolPtr *tmp_fspools = NULL; + virFSPoolPtr fspool = NULL; + int nfspools = 0; + int ret = -1; + size_t i; + + if (fspools && VIR_ALLOC_N(tmp_fspools, fspoolobjs.count + 1) < 0) + goto cleanup; + + for (i = 0; i < fspoolobjs.count; i++) { + virFSPoolObjPtr fspoolobj = fspoolobjs.objs[i]; + virFSPoolObjLock(fspoolobj); + if ((!filter || filter(conn, fspoolobj->def)) && + virFSPoolMatch(fspoolobj, flags)) { + if (fspools) { + if (!(fspool = virGetFSPool(conn, + fspoolobj->def->name, + fspoolobj->def->uuid, + NULL, NULL))) { + virFSPoolObjUnlock(fspoolobj); + goto cleanup; + } + tmp_fspools[nfspools] = fspool; + } + nfspools++; + } + virFSPoolObjUnlock(fspoolobj); + } + + if (tmp_fspools) { + /* trim the array to the final size */ + ignore_value(VIR_REALLOC_N(tmp_fspools, nfspools + 1)); + *fspools = tmp_fspools; + tmp_fspools = NULL; + } + + ret = nfspools; + + cleanup: + if (tmp_fspools) { + for (i = 0; i < nfspools; i++) + virObjectUnref(tmp_fspools[i]); + } + + VIR_FREE(tmp_fspools); + return ret; +} diff --git a/src/conf/fs_conf.h b/src/conf/fs_conf.h index 4f05659..063cfbe 100644 --- a/src/conf/fs_conf.h +++ b/src/conf/fs_conf.h @@ -155,5 +155,108 @@ virFSPoolObjIsActive(virFSPoolObjPtr fspool) return fspool->active; } +int virFSPoolLoadAllConfigs(virFSPoolObjListPtr fspools, + const char *configDir, + const char *autostartDir); + +int virFSPoolLoadAllState(virFSPoolObjListPtr fspools, + const char *stateDir); + +virFSPoolObjPtr +virFSPoolLoadState(virFSPoolObjListPtr fspools, + const char *stateDir, + const char *name); +virFSPoolObjPtr +virFSPoolObjFindByUUID(virFSPoolObjListPtr fspools, + const unsigned char *uuid); +virFSPoolObjPtr +virFSPoolObjFindByName(virFSPoolObjListPtr fspools, + const char *name); + +virFSItemDefPtr +virFSItemDefFindByKey(virFSPoolObjPtr fspool, + const char *key); +virFSItemDefPtr +virFSItemDefFindByPath(virFSPoolObjPtr fspool, + const char *path); +virFSItemDefPtr +virFSItemDefFindByName(virFSPoolObjPtr fspool, + const char *name); + +void virFSPoolObjClearItems(virFSPoolObjPtr fspool); + +virFSPoolDefPtr virFSPoolDefParseString(const char *xml); +virFSPoolDefPtr virFSPoolDefParseFile(const char *filename); +virFSPoolDefPtr virFSPoolDefParseNode(xmlDocPtr xml, + xmlNodePtr root); +char *virFSPoolDefFormat(virFSPoolDefPtr def); + +typedef enum { + /* do not require volume capacity at all */ + VIR_ITEM_XML_PARSE_NO_CAPACITY = 1 << 0, + /* do not require volume capacity if the volume has a backing store */ + VIR_ITEM_XML_PARSE_OPT_CAPACITY = 1 << 1, +} virFSItemDefParseFlags; + +virFSItemDefPtr +virFSItemDefParseString(virFSPoolDefPtr fspool, + const char *xml, + unsigned int flags); +virFSItemDefPtr +virFSItemDefParseFile(virFSPoolDefPtr fspool, + const char *filename, + unsigned int flags); +virFSItemDefPtr +virFSItemDefParseNode(virFSPoolDefPtr fspool, + xmlDocPtr xml, + xmlNodePtr root, + unsigned int flags); +char *virFSItemDefFormat(virFSPoolDefPtr fspool, + virFSItemDefPtr def); + +virFSPoolObjPtr +virFSPoolObjAssignDef(virFSPoolObjListPtr fspools, + virFSPoolDefPtr def); + +int virFSPoolSaveState(const char *stateFile, + virFSPoolDefPtr def); +int virFSPoolSaveConfig(const char *configFile, + virFSPoolDefPtr def); +int virFSPoolObjSaveDef(virFSDriverStatePtr driver, + virFSPoolObjPtr fspool, + virFSPoolDefPtr def); +int virFSPoolObjDeleteDef(virFSPoolObjPtr fspool); + +void virFSItemDefFree(virFSItemDefPtr def); +void virFSPoolObjFree(virFSPoolObjPtr fspool); +void virFSPoolObjListFree(virFSPoolObjListPtr fspools); +void virFSPoolObjRemove(virFSPoolObjListPtr fspools, + virFSPoolObjPtr fspool); + +virFSPoolSourcePtr +virFSPoolDefParseSourceString(const char *srcSpec, + int fspool_type); +char *virFSPoolSourceListFormat(virFSPoolSourceListPtr def); + +int virFSPoolObjIsDuplicate(virFSPoolObjListPtr fspools, + virFSPoolDefPtr def, + unsigned int check_active); + +char *virFSPoolGetVhbaSCSIHostParent(virConnectPtr conn, + const char *name) + ATTRIBUTE_NONNULL(1); + +int virFSPoolSourceFindDuplicate(virConnectPtr conn, + virFSPoolObjListPtr fspools, + virFSPoolDefPtr def); + +void virFSPoolObjLock(virFSPoolObjPtr obj); +void virFSPoolObjUnlock(virFSPoolObjPtr obj); + +int virFSPoolObjListExport(virConnectPtr conn, + virFSPoolObjList fspoolobjs, + virFSPoolPtr **fspools, + virFSPoolObjListFilter filter, + unsigned int flags); #endif /* __VIR_FS_CONF_H__ */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index a14dfc8..93caf47 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -606,6 +606,41 @@ virInterfaceObjLock; virInterfaceObjUnlock; virInterfaceRemove; +#conf/fs_conf.h +virFSPoolTypeFromString; +virFSItemDefFree; +virFSItemDefFindByKey; +virFSItemDefFindByName; +virFSItemDefFindByPath; +virFSItemDefFormat; +virFSItemDefParseFile; +virFSItemDefParseNode; +virFSItemDefParseString; +virFSItemTypeFromString; +virFSItemTypeToString; +virFSPoolDefFormat; +virFSPoolTypeToString; +virFSPoolObjAssignDef; +virFSPoolObjClearItems; +virFSPoolObjDeleteDef; +virFSPoolObjFindByName; +virFSPoolObjFindByUUID; +virFSPoolObjIsDuplicate; +virFSPoolObjListExport; +virFSPoolObjListFree; +virFSPoolObjLock; +virFSPoolObjRemove; +virFSPoolObjSaveDef; +virFSPoolObjUnlock; +virFSPoolDefParseFile; +virFSPoolDefParseNode; +virFSPoolDefParseSourceString; +virFSPoolDefParseString; +virFSPoolLoadAllConfigs; +virFSPoolLoadAllState; +virFSPoolSaveConfig; +virFSPoolSaveState; +virFSPoolSourceFindDuplicate; # conf/netdev_bandwidth_conf.h virDomainClearNetBandwidth; -- 1.8.3.1

Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> Signed-off-by: Maxim Nestratov <mnestratov@virtuozzo.com> --- po/POTFILES.in | 2 + tools/Makefile.am | 2 + tools/virsh-fsitem.c | 1293 +++++++++++++++++++++++++++++++++++++++++ tools/virsh-fsitem.h | 39 ++ tools/virsh-fspool.c | 1574 ++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh-fspool.h | 38 ++ tools/virsh.c | 4 + tools/virsh.h | 9 + tools/virsh.pod | 252 +++++++- 9 files changed, 3212 insertions(+), 1 deletion(-) create mode 100644 tools/virsh-fsitem.c create mode 100644 tools/virsh-fsitem.h create mode 100644 tools/virsh-fspool.c create mode 100644 tools/virsh-fspool.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 7ad9174..2d4c191 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -289,8 +289,10 @@ tools/virsh-console.c tools/virsh-domain-monitor.c tools/virsh-domain.c tools/virsh-edit.c +tools/virsh-fspool.c tools/virsh-host.c tools/virsh-interface.c +tools/virsh-fsitem.c tools/virsh-network.c tools/virsh-nodedev.c tools/virsh-nwfilter.c diff --git a/tools/Makefile.am b/tools/Makefile.am index 319abb2..ff68bd2 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -198,9 +198,11 @@ virsh_SOURCES = \ virsh-nodedev.c virsh-nodedev.h \ virsh-nwfilter.c virsh-nwfilter.h \ virsh-pool.c virsh-pool.h \ + virsh-fspool.c virsh-fspool.h \ virsh-secret.c virsh-secret.h \ virsh-snapshot.c virsh-snapshot.h \ virsh-volume.c virsh-volume.h \ + virsh-fsitem.c virsh-fsitem.h \ $(NULL) virsh_LDFLAGS = \ diff --git a/tools/virsh-fsitem.c b/tools/virsh-fsitem.c new file mode 100644 index 0000000..87fb327 --- /dev/null +++ b/tools/virsh-fsitem.c @@ -0,0 +1,1293 @@ +/* + * virsh-fsitem.c: Commands to manage storage item + * + * Copyright (C) 2016 Parallels IP Holdings GmbH + * + * 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/>. + * + * Olga Krishtal <okrishtal@virtuozzo.com> + * + */ +#include <config.h> +#include "virsh-fsitem.h" + +#include <fcntl.h> + +#include <libxml/parser.h> +#include <libxml/tree.h> +#include <libxml/xpath.h> +#include <libxml/xmlsave.h> + +#include "internal.h" +#include "virbuffer.h" +#include "viralloc.h" +#include "virutil.h" +#include "virfile.h" +#include "virsh-fspool.h" +#include "virxml.h" +#include "virstring.h" + +#define VIRSH_COMMON_OPT_FSPOOL_FULL \ + VIRSH_COMMON_OPT_FSPOOL(N_("fspool name or uuid")) \ + +#define VIRSH_COMMON_OPT_FSPOOL_NAME \ + VIRSH_COMMON_OPT_FSPOOL(N_("fspool name")) \ + +#define VIRSH_COMMON_OPT_FSPOOL_OPTIONAL \ + {.name = "fspool", \ + .type = VSH_OT_STRING, \ + .help = N_("fspool name or uuid") \ + } \ + +#define VIRSH_COMMON_OPT_ITEM \ + {.name = "item", \ + .type = VSH_OT_DATA, \ + .flags = VSH_OFLAG_REQ, \ + .help = N_("item name, key or path") \ + } \ + +virFSItemPtr +virshCommandOptItemBy(vshControl *ctl, const vshCmd *cmd, + const char *optname, + const char *fspooloptname, + const char **name, unsigned int flags) +{ + virFSItemPtr item = NULL; + virFSPoolPtr fspool = NULL; + const char *n = NULL, *p = NULL; + virshControlPtr priv = ctl->privData; + + virCheckFlags(VIRSH_BYUUID | VIRSH_BYNAME, NULL); + + if (vshCommandOptStringReq(ctl, cmd, optname, &n) < 0) + return NULL; + + if (fspooloptname != NULL && + vshCommandOptStringReq(ctl, cmd, fspooloptname, &p) < 0) + return NULL; + + if (p) { + if (!(fspool = virshCommandOptFSPoolBy(ctl, cmd, fspooloptname, name, flags))) + return NULL; + + if (virFSPoolIsActive(fspool) != 1) { + vshError(ctl, _("fspool '%s' is not active"), p); + virFSPoolFree(fspool); + return NULL; + } + } + + vshDebug(ctl, VSH_ERR_DEBUG, "%s: found option <%s>: %s\n", + cmd->def->name, optname, n); + + if (name) + *name = n; + + /* try it by name */ + if (fspool && (flags & VIRSH_BYNAME)) { + vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as item name\n", + cmd->def->name, optname); + item = virFSItemLookupByName(fspool, n); + } + /* try it by key */ + if (!item && (flags & VIRSH_BYUUID)) { + vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as item key\n", + cmd->def->name, optname); + item = virFSItemLookupByKey(priv->conn, n); + } + /* try it by path */ + if (!item && (flags & VIRSH_BYUUID)) { + vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as item path\n", + cmd->def->name, optname); + item = virFSItemLookupByPath(priv->conn, n); + } + + if (!item) { + if (fspool || !fspooloptname) + vshError(ctl, _("failed to get item '%s'"), n); + else + vshError(ctl, _("failed to get item '%s', specifying --%s " + "might help"), n, fspooloptname); + } + + /* If the fspool was specified, then make sure that the returned + * item is from the given fspool */ + if (fspool && item) { + virFSPoolPtr itemfspool = NULL; + + if ((itemfspool = virFSPoolLookupByItem(item))) { + if (STRNEQ(virFSPoolGetName(itemfspool), + virFSPoolGetName(fspool))) { + vshResetLibvirtError(); + vshError(ctl, + _("Requested item '%s' is not in fspool '%s'"), + n, virFSPoolGetName(fspool)); + virFSItemFree(item); + item = NULL; + } + virFSPoolFree(itemfspool); + } + } + + if (fspool) + virFSPoolFree(fspool); + + return item; +} + +/* + * "item-create-as" command + */ +static const vshCmdInfo info_item_create_as[] = { + {.name = "help", + .data = N_("create a item from a set of args") + }, + {.name = "desc", + .data = N_("Create a item.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_item_create_as[] = { + VIRSH_COMMON_OPT_FSPOOL_NAME, + {.name = "name", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_REQ, + .help = N_("name of the item") + }, + {.name = "capacity", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_REQ, + .help = N_("size of the item, as scaled integer (default bytes)") + }, + {.name = "allocation", + .type = VSH_OT_STRING, + .help = N_("initial allocation size, as scaled integer (default bytes)") + }, + {.name = "format", + .type = VSH_OT_STRING, + .help = N_("file format type raw,bochs,qcow,qcow2,qed,vmdk") + }, + {.name = "print-xml", + .type = VSH_OT_BOOL, + .help = N_("print XML document, but don't define/create") + }, + {.name = NULL} +}; + +static int +virshItemSize(const char *data, unsigned long long *val) +{ + char *end; + if (virStrToLong_ull(data, &end, 10, val) < 0) + return -1; + return virScaleInteger(val, end, 1, ULLONG_MAX); +} + +static bool +cmdItemCreateAs(vshControl *ctl, const vshCmd *cmd) +{ + virFSPoolPtr fspool; + virFSItemPtr item = NULL; + char *xml = NULL; + bool printXML = vshCommandOptBool(cmd, "print-xml"); + const char *name, *capacityStr = NULL, *allocationStr = NULL, *format = NULL; + unsigned long long capacity, allocation = 0; + virBuffer buf = VIR_BUFFER_INITIALIZER; + unsigned long flags = 0; + bool ret = false; + + if (!(fspool = virshCommandOptFSPool(ctl, cmd, "fspool", NULL))) + return false; + + if (vshCommandOptStringReq(ctl, cmd, "name", &name) < 0) + goto cleanup; + + if (vshCommandOptStringReq(ctl, cmd, "capacity", &capacityStr) < 0) + goto cleanup; + + if (virshItemSize(capacityStr, &capacity) < 0) { + vshError(ctl, _("Malformed size %s"), capacityStr); + goto cleanup; + } + + if (vshCommandOptStringQuiet(ctl, cmd, "allocation", &allocationStr) > 0 && + virshItemSize(allocationStr, &allocation) < 0) { + vshError(ctl, _("Malformed size %s"), allocationStr); + goto cleanup; + } + + if (vshCommandOptStringReq(ctl, cmd, "format", &format)) + goto cleanup; + + virBufferAddLit(&buf, "<item>\n"); + virBufferAdjustIndent(&buf, 2); + virBufferAsprintf(&buf, "<name>%s</name>\n", name); + virBufferAsprintf(&buf, "<capacity>%llu</capacity>\n", capacity); + if (allocationStr) + virBufferAsprintf(&buf, "<allocation>%llu</allocation>\n", allocation); + + if (format) { + virBufferAddLit(&buf, "<target>\n"); + virBufferAdjustIndent(&buf, 2); + virBufferAsprintf(&buf, "<format type='%s'/>\n", format); + virBufferAdjustIndent(&buf, -2); + virBufferAddLit(&buf, "</target>\n"); + } + + virBufferAdjustIndent(&buf, -2); + virBufferAddLit(&buf, "</item>\n"); + + if (virBufferError(&buf)) { + vshPrint(ctl, "%s", _("Failed to allocate XML buffer")); + goto cleanup; + } + xml = virBufferContentAndReset(&buf); + + if (printXML) { + vshPrint(ctl, "%s", xml); + } else { + if (!(item = virFSItemCreateXML(fspool, xml, flags))) { + vshError(ctl, _("Failed to create item %s"), name); + goto cleanup; + } + vshPrint(ctl, _("Item %s created\n"), name); + } + + ret = true; + + cleanup: + virBufferFreeAndReset(&buf); + if (item) + virFSItemFree(item); + virFSPoolFree(fspool); + VIR_FREE(xml); + return ret; +} + +/* + * "item-create" command + */ +static const vshCmdInfo info_item_create[] = { + {.name = "help", + .data = N_("create a item from an XML file") + }, + {.name = "desc", + .data = N_("Create a item.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_item_create[] = { + VIRSH_COMMON_OPT_FSPOOL_NAME, + VIRSH_COMMON_OPT_FILE(N_("file containing an XML item description")), + {.name = NULL} +}; + +static bool +cmdItemCreate(vshControl *ctl, const vshCmd *cmd) +{ + virFSPoolPtr fspool; + virFSItemPtr item; + const char *from = NULL; + bool ret = false; + unsigned int flags = 0; + char *buffer = NULL; + + if (!(fspool = virshCommandOptFSPool(ctl, cmd, "fspool", NULL))) + return false; + + if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0) + goto cleanup; + + if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0) { + vshSaveLibvirtError(); + goto cleanup; + } + + if ((item = virFSItemCreateXML(fspool, buffer, flags))) { + vshPrint(ctl, _("Item %s created from %s\n"), + virFSItemGetName(item), from); + virFSItemFree(item); + ret = true; + } else { + vshError(ctl, _("Failed to create item from %s"), from); + } + + cleanup: + VIR_FREE(buffer); + virFSPoolFree(fspool); + return ret; +} + +/* + * "item-create-from" command + */ +static const vshCmdInfo info_item_create_from[] = { + {.name = "help", + .data = N_("create a item, using another item as input") + }, + {.name = "desc", + .data = N_("Create a item from an existing item.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_item_create_from[] = { + VIRSH_COMMON_OPT_FSPOOL_FULL, + VIRSH_COMMON_OPT_FILE(N_("file containing an XML item description")), + VIRSH_COMMON_OPT_ITEM, + {.name = "inputfspool", + .type = VSH_OT_STRING, + .help = N_("fspool name or uuid of the input item's fspool") + }, + {.name = NULL} +}; + +static bool +cmdItemCreateFrom(vshControl *ctl, const vshCmd *cmd) +{ + virFSPoolPtr fspool = NULL; + virFSItemPtr newitem = NULL, inputitem = NULL; + const char *from = NULL; + bool ret = false; + char *buffer = NULL; + unsigned int flags = 0; + + if (!(fspool = virshCommandOptFSPool(ctl, cmd, "fspool", NULL))) + goto cleanup; + + if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0) + goto cleanup; + + if (!(inputitem = virshCommandOptItem(ctl, cmd, "item", "inputfspool", NULL))) + goto cleanup; + + if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0) { + vshReportError(ctl); + goto cleanup; + } + + newitem = virFSItemCreateXMLFrom(fspool, buffer, inputitem, flags); + + if (newitem != NULL) { + vshPrint(ctl, _("Item %s created from input item %s\n"), + virFSItemGetName(newitem), virFSItemGetName(inputitem)); + } else { + vshError(ctl, _("Failed to create item from %s"), from); + goto cleanup; + } + + ret = true; + cleanup: + VIR_FREE(buffer); + if (fspool) + virFSPoolFree(fspool); + if (inputitem) + virFSItemFree(inputitem); + if (newitem) + virFSItemFree(newitem); + return ret; +} + +static xmlChar * +virshMakeCloneXML(const char *origxml, const char *newname) +{ + + xmlDocPtr doc = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlXPathObjectPtr obj = NULL; + xmlChar *newxml = NULL; + int size; + + doc = virXMLParseStringCtxt(origxml, _("(item_definition)"), &ctxt); + if (!doc) + goto cleanup; + + obj = xmlXPathEval(BAD_CAST "/item/name", ctxt); + if (obj == NULL || obj->nodesetval == NULL || + obj->nodesetval->nodeTab == NULL) + goto cleanup; + + xmlNodeSetContent(obj->nodesetval->nodeTab[0], (const xmlChar *)newname); + xmlDocDumpMemory(doc, &newxml, &size); + + cleanup: + xmlXPathFreeObject(obj); + xmlXPathFreeContext(ctxt); + xmlFreeDoc(doc); + return newxml; +} + +/* + * "item-clone" command + */ +static const vshCmdInfo info_item_clone[] = { + {.name = "help", + .data = N_("clone a item.") + }, + {.name = "desc", + .data = N_("Clone an existing item within the parent fspool.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_item_clone[] = { + VIRSH_COMMON_OPT_ITEM, + {.name = "newname", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_REQ, + .help = N_("clone name") + }, + VIRSH_COMMON_OPT_FSPOOL_OPTIONAL, + {.name = NULL} +}; + +static bool +cmdItemClone(vshControl *ctl, const vshCmd *cmd) +{ + virFSPoolPtr origfspool = NULL; + virFSItemPtr origitem = NULL, newitem = NULL; + const char *name = NULL; + char *origxml = NULL; + xmlChar *newxml = NULL; + bool ret = false; + unsigned int flags = 0; + + if (!(origitem = virshCommandOptItem(ctl, cmd, "item", "fspool", NULL))) + goto cleanup; + + origfspool = virFSPoolLookupByItem(origitem); + if (!origfspool) { + vshError(ctl, "%s", _("failed to get parent fspool")); + goto cleanup; + } + + if (vshCommandOptStringReq(ctl, cmd, "newname", &name) < 0) + goto cleanup; + + origxml = virFSItemGetXMLDesc(origitem, 0); + if (!origxml) + goto cleanup; + + newxml = virshMakeCloneXML(origxml, name); + if (!newxml) { + vshPrint(ctl, "%s", _("Failed to allocate XML buffer")); + goto cleanup; + } + + newitem = virFSItemCreateXMLFrom(origfspool, (char *) newxml, origitem, flags); + + if (newitem != NULL) { + vshPrint(ctl, _("Item %s cloned from %s\n"), + virFSItemGetName(newitem), virFSItemGetName(origitem)); + } else { + vshError(ctl, _("Failed to clone item from %s"), + virFSItemGetName(origitem)); + goto cleanup; + } + + ret = true; + + cleanup: + VIR_FREE(origxml); + xmlFree(newxml); + if (origitem) + virFSItemFree(origitem); + if (newitem) + virFSItemFree(newitem); + if (origfspool) + virFSPoolFree(origfspool); + return ret; +} + +/* + * "item-delete" command + */ +static const vshCmdInfo info_item_delete[] = { + {.name = "help", + .data = N_("delete a item") + }, + {.name = "desc", + .data = N_("Delete a given item.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_item_delete[] = { + VIRSH_COMMON_OPT_ITEM, + VIRSH_COMMON_OPT_FSPOOL_OPTIONAL, + {.name = NULL} +}; + +static bool +cmdItemDelete(vshControl *ctl, const vshCmd *cmd) +{ + virFSItemPtr item; + bool ret = true; + const char *name; + unsigned int flags = 0; + + if (!(item = virshCommandOptItem(ctl, cmd, "item", "fspool", &name))) + return false; + + if (virFSItemDelete(item, flags) == 0) { + vshPrint(ctl, _("Item %s deleted\n"), name); + } else { + vshError(ctl, _("Failed to delete item %s"), name); + ret = false; + } + + virFSItemFree(item); + return ret; +} + +VIR_ENUM_DECL(virshFSItem) +VIR_ENUM_IMPL(virshFSItem, + VIR_FSITEM_LAST, + N_("dir")) + +static const char * +virshItemTypeToString(int type) +{ + const char *str = virshFSItemTypeToString(type); + return str ? _(str) : _("unknown"); +} + + +/* + * "item-info" command + */ +static const vshCmdInfo info_item_info[] = { + {.name = "help", + .data = N_("storage item information") + }, + {.name = "desc", + .data = N_("Returns basic information about the storage item.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_item_info[] = { + VIRSH_COMMON_OPT_ITEM, + VIRSH_COMMON_OPT_FSPOOL_OPTIONAL, + {.name = "bytes", + .type = VSH_OT_BOOL, + .help = N_("sizes are represented in bytes rather than pretty units") + }, + {.name = NULL} +}; + +static bool +cmdItemInfo(vshControl *ctl, const vshCmd *cmd) +{ + virFSItemInfo info; + virFSItemPtr item; + bool bytes = vshCommandOptBool(cmd, "bytes"); + bool ret = true; + + if (!(item = virshCommandOptItem(ctl, cmd, "item", "fspool", NULL))) + return false; + + vshPrint(ctl, "%-15s %s\n", _("Name:"), virFSItemGetName(item)); + + if (virFSItemGetInfo(item, &info) == 0) { + double val; + const char *unit; + + vshPrint(ctl, "%-15s %s\n", _("Type:"), + virshItemTypeToString(info.type)); + + if (bytes) { + vshPrint(ctl, "%-15s %llu %s\n", _("Capacity:"), + info.capacity, _("bytes")); + } else { + val = vshPrettyCapacity(info.capacity, &unit); + vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit); + } + + if (bytes) { + vshPrint(ctl, "%-15s %llu %s\n", _("Allocation:"), + info.allocation, _("bytes")); + } else { + val = vshPrettyCapacity(info.allocation, &unit); + vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit); + } + } else { + ret = false; + } + + virFSItemFree(item); + return ret; +} + +/* + * "item-dumpxml" command + */ +static const vshCmdInfo info_item_dumpxml[] = { + {.name = "help", + .data = N_("item information in XML") + }, + {.name = "desc", + .data = N_("Output the item information as an XML dump to stdout.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_item_dumpxml[] = { + VIRSH_COMMON_OPT_ITEM, + VIRSH_COMMON_OPT_FSPOOL_OPTIONAL, + {.name = NULL} +}; + +static bool +cmdItemDumpXML(vshControl *ctl, const vshCmd *cmd) +{ + virFSItemPtr item; + bool ret = true; + char *dump; + + if (!(item = virshCommandOptItem(ctl, cmd, "item", "fspool", NULL))) + return false; + + dump = virFSItemGetXMLDesc(item, 0); + if (dump != NULL) { + vshPrint(ctl, "%s", dump); + VIR_FREE(dump); + } else { + ret = false; + } + + virFSItemFree(item); + return ret; +} + +static int +virshFSItemSorter(const void *a, const void *b) +{ + virFSItemPtr *va = (virFSItemPtr *) a; + virFSItemPtr *vb = (virFSItemPtr *) b; + + if (*va && !*vb) + return -1; + + if (!*va) + return *vb != NULL; + + return vshStrcasecmp(virFSItemGetName(*va), + virFSItemGetName(*vb)); +} + +struct virshFSItemList { + virFSItemPtr *items; + size_t nitems; +}; +typedef struct virshFSItemList *virshFSItemListPtr; + +static void +virshFSItemListFree(virshFSItemListPtr list) +{ + size_t i; + + if (list && list->items) { + for (i = 0; i < list->nitems; i++) { + if (list->items[i]) + virFSItemFree(list->items[i]); + } + VIR_FREE(list->items); + } + VIR_FREE(list); +} + +static virshFSItemListPtr +virshFSItemListCollect(vshControl *ctl, + virFSPoolPtr fspool, + unsigned int flags) +{ + virshFSItemListPtr list = vshMalloc(ctl, sizeof(*list)); + size_t i; + char **names = NULL; + virFSItemPtr item = NULL; + bool success = false; + size_t deleted = 0; + int nitems = 0; + int ret = -1; + + /* try the list with flags support (0.10.2 and later) */ + if ((ret = virFSPoolListAllItems(fspool, + &list->items, + flags)) >= 0) { + list->nitems = ret; + goto finished; + } + + /* check if the command is actually supported */ + if (last_error && last_error->code == VIR_ERR_NO_SUPPORT) + goto fallback; + + /* there was an error during the call */ + vshError(ctl, "%s", _("Failed to list items")); + goto cleanup; + + fallback: + /* fall back to old method (0.10.1 and older) */ + vshResetLibvirtError(); + + /* Determine the number of items in the fspool */ + if ((nitems = virFSPoolNumOfItems(fspool)) < 0) { + vshError(ctl, "%s", _("Failed to list storage items")); + goto cleanup; + } + + if (nitems == 0) { + success = true; + return list; + } + + /* Retrieve the list of item names in the fspool */ + names = vshCalloc(ctl, nitems, sizeof(*names)); + if ((nitems = virFSPoolListItems(fspool, names, nitems)) < 0) { + vshError(ctl, "%s", _("Failed to list storage items")); + goto cleanup; + } + + list->items = vshMalloc(ctl, sizeof(virFSItemPtr) * (nitems)); + list->nitems = 0; + + /* get the items */ + for (i = 0; i < nitems; i++) { + if (!(item = virFSItemLookupByName(fspool, names[i]))) + continue; + list->items[list->nitems++] = item; + } + + /* truncate the list for not found items */ + deleted = nitems - list->nitems; + + finished: + /* sort the list */ + if (list->items && list->nitems) + qsort(list->items, list->nitems, sizeof(*list->items), virshFSItemSorter); + + if (deleted) + VIR_SHRINK_N(list->items, list->nitems, deleted); + + success = true; + + cleanup: + if (nitems > 0) + for (i = 0; i < nitems; i++) + VIR_FREE(names[i]); + VIR_FREE(names); + + if (!success) { + virshFSItemListFree(list); + list = NULL; + } + + return list; +} + +/* + * "item-list" command + */ +static const vshCmdInfo info_item_list[] = { + {.name = "help", + .data = N_("list items") + }, + {.name = "desc", + .data = N_("Returns list of items by fspool.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_item_list[] = { + VIRSH_COMMON_OPT_FSPOOL_FULL, + {.name = "details", + .type = VSH_OT_BOOL, + .help = N_("display extended details for items") + }, + {.name = NULL} +}; + +static bool +cmdItemList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + virFSItemInfo itemInfo; + virFSPoolPtr fspool; + char *outputStr = NULL; + const char *unit; + double val; + bool details = vshCommandOptBool(cmd, "details"); + size_t i; + bool ret = false; + int stringLength = 0; + size_t allocStrLength = 0, capStrLength = 0; + size_t nameStrLength = 0, pathStrLength = 0; + size_t typeStrLength = 0; + struct itemInfoText { + char *allocation; + char *capacity; + char *path; + char *type; + }; + struct itemInfoText *itemInfoTexts = NULL; + virshFSItemListPtr list = NULL; + + /* Look up the fspool information given to us by the user */ + if (!(fspool = virshCommandOptFSPool(ctl, cmd, "fspool", NULL))) + return false; + + if (!(list = virshFSItemListCollect(ctl, fspool, 0))) + goto cleanup; + + if (list->nitems > 0) + itemInfoTexts = vshCalloc(ctl, list->nitems, sizeof(*itemInfoTexts)); + + /* Collect the rest of the item information for display */ + for (i = 0; i < list->nitems; i++) { + /* Retrieve item info */ + virFSItemPtr item = list->items[i]; + + /* Retrieve the item path */ + if ((itemInfoTexts[i].path = virFSItemGetPath(item)) == NULL) { + /* Something went wrong retrieving a item path, cope with it */ + itemInfoTexts[i].path = vshStrdup(ctl, _("unknown")); + } + + /* If requested, retrieve item type and sizing information */ + if (details) { + if (virFSItemGetInfo(item, &itemInfo) != 0) { + /* Something went wrong retrieving item info, cope with it */ + itemInfoTexts[i].allocation = vshStrdup(ctl, _("unknown")); + itemInfoTexts[i].capacity = vshStrdup(ctl, _("unknown")); + itemInfoTexts[i].type = vshStrdup(ctl, _("unknown")); + } else { + /* Convert the returned item info into output strings */ + + /* Item type */ + itemInfoTexts[i].type = vshStrdup(ctl, + virshItemTypeToString(itemInfo.type)); + + val = vshPrettyCapacity(itemInfo.capacity, &unit); + if (virAsprintf(&itemInfoTexts[i].capacity, + "%.2lf %s", val, unit) < 0) + goto cleanup; + + val = vshPrettyCapacity(itemInfo.allocation, &unit); + if (virAsprintf(&itemInfoTexts[i].allocation, + "%.2lf %s", val, unit) < 0) + goto cleanup; + } + + /* Remember the largest length for each output string. + * This lets us displaying header and item information rows + * using a single, properly sized, printf style output string. + */ + + /* Keep the length of name string if longest so far */ + stringLength = strlen(virFSItemGetName(list->items[i])); + if (stringLength > nameStrLength) + nameStrLength = stringLength; + + /* Keep the length of path string if longest so far */ + stringLength = strlen(itemInfoTexts[i].path); + if (stringLength > pathStrLength) + pathStrLength = stringLength; + + /* Keep the length of type string if longest so far */ + stringLength = strlen(itemInfoTexts[i].type); + if (stringLength > typeStrLength) + typeStrLength = stringLength; + + /* Keep the length of capacity string if longest so far */ + stringLength = strlen(itemInfoTexts[i].capacity); + if (stringLength > capStrLength) + capStrLength = stringLength; + + /* Keep the length of allocation string if longest so far */ + stringLength = strlen(itemInfoTexts[i].allocation); + if (stringLength > allocStrLength) + allocStrLength = stringLength; + } + } + + /* If the --details option wasn't selected, we output the item + * info using the fixed string format from previous versions to + * maintain backward compatibility. + */ + + /* Output basic info then return if --details option not selected */ + if (!details) { + /* The old output format */ + vshPrintExtra(ctl, " %-20s %-40s\n", _("Name"), _("Path")); + vshPrintExtra(ctl, "---------------------------------------" + "---------------------------------------\n"); + for (i = 0; i < list->nitems; i++) { + vshPrint(ctl, " %-20s %-40s\n", virFSItemGetName(list->items[i]), + itemInfoTexts[i].path); + } + + /* Cleanup and return */ + ret = true; + goto cleanup; + } + + /* We only get here if the --details option was selected. */ + + /* Use the length of name header string if it's longest */ + stringLength = strlen(_("Name")); + if (stringLength > nameStrLength) + nameStrLength = stringLength; + + /* Use the length of path header string if it's longest */ + stringLength = strlen(_("Path")); + if (stringLength > pathStrLength) + pathStrLength = stringLength; + + /* Use the length of type header string if it's longest */ + stringLength = strlen(_("Type")); + if (stringLength > typeStrLength) + typeStrLength = stringLength; + + /* Use the length of capacity header string if it's longest */ + stringLength = strlen(_("Capacity")); + if (stringLength > capStrLength) + capStrLength = stringLength; + + /* Use the length of allocation header string if it's longest */ + stringLength = strlen(_("Allocation")); + if (stringLength > allocStrLength) + allocStrLength = stringLength; + + /* Display the string lengths for debugging */ + vshDebug(ctl, VSH_ERR_DEBUG, + "Longest name string = %zu chars\n", nameStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, + "Longest path string = %zu chars\n", pathStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, + "Longest type string = %zu chars\n", typeStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, + "Longest capacity string = %zu chars\n", capStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, + "Longest allocation string = %zu chars\n", allocStrLength); + + if (virAsprintf(&outputStr, + " %%-%lus %%-%lus %%-%lus %%%lus %%%lus\n", + (unsigned long) nameStrLength, + (unsigned long) pathStrLength, + (unsigned long) typeStrLength, + (unsigned long) capStrLength, + (unsigned long) allocStrLength) < 0) + goto cleanup; + + /* Display the header */ + vshPrint(ctl, outputStr, _("Name"), _("Path"), _("Type"), + ("Capacity"), _("Allocation")); + for (i = nameStrLength + pathStrLength + typeStrLength + + capStrLength + allocStrLength + + 10; i > 0; i--) + vshPrintExtra(ctl, "-"); + vshPrintExtra(ctl, "\n"); + + /* Display the item info rows */ + for (i = 0; i < list->nitems; i++) { + vshPrint(ctl, outputStr, + virFSItemGetName(list->items[i]), + itemInfoTexts[i].path, + itemInfoTexts[i].type, + itemInfoTexts[i].capacity, + itemInfoTexts[i].allocation); + } + + /* Cleanup and return */ + ret = true; + + cleanup: + + /* Safely free the memory allocated in this function */ + if (list && list->nitems) { + for (i = 0; i < list->nitems; i++) { + /* Cleanup the memory for one item info structure per loop */ + VIR_FREE(itemInfoTexts[i].path); + VIR_FREE(itemInfoTexts[i].type); + VIR_FREE(itemInfoTexts[i].capacity); + VIR_FREE(itemInfoTexts[i].allocation); + } + } + + /* Cleanup remaining memory */ + VIR_FREE(outputStr); + VIR_FREE(itemInfoTexts); + virFSPoolFree(fspool); + virshFSItemListFree(list); + + /* Return the desired value */ + return ret; +} + +/* + * "item-name" command + */ +static const vshCmdInfo info_item_name[] = { + {.name = "help", + .data = N_("returns the item name for a given item key or path") + }, + {.name = "desc", + .data = "" + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_item_name[] = { + {.name = "item", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_REQ, + .help = N_("item key or path") + }, + {.name = NULL} +}; + +static bool +cmdItemName(vshControl *ctl, const vshCmd *cmd) +{ + virFSItemPtr item; + + if (!(item = virshCommandOptItemBy(ctl, cmd, "item", NULL, NULL, + VIRSH_BYUUID))) + return false; + + vshPrint(ctl, "%s\n", virFSItemGetName(item)); + virFSItemFree(item); + return true; +} + +/* + * "item-fspool" command + */ +static const vshCmdInfo info_item_fspool[] = { + {.name = "help", + .data = N_("returns the storage fspool for a given item key or path") + }, + {.name = "desc", + .data = "" + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_item_fspool[] = { + {.name = "item", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_REQ, + .help = N_("item key or path") + }, + {.name = "uuid", + .type = VSH_OT_BOOL, + .help = N_("return the fspool uuid rather than fspool name") + }, + {.name = NULL} +}; + +static bool +cmdItemPool(vshControl *ctl, const vshCmd *cmd) +{ + virFSPoolPtr fspool; + virFSItemPtr item; + char uuid[VIR_UUID_STRING_BUFLEN]; + + /* Use the supplied string to locate the item */ + if (!(item = virshCommandOptItemBy(ctl, cmd, "item", NULL, NULL, + VIRSH_BYUUID))) { + return false; + } + + /* Look up the parent storage fspool for the item */ + fspool = virFSPoolLookupByItem(item); + if (fspool == NULL) { + vshError(ctl, "%s", _("failed to get parent fspool")); + virFSItemFree(item); + return false; + } + + /* Return the requested details of the parent storage fspool */ + if (vshCommandOptBool(cmd, "uuid")) { + /* Retrieve and return fspool UUID string */ + if (virFSPoolGetUUIDString(fspool, &uuid[0]) == 0) + vshPrint(ctl, "%s\n", uuid); + } else { + /* Return the storage fspool name */ + vshPrint(ctl, "%s\n", virFSPoolGetName(fspool)); + } + + /* Cleanup */ + virFSItemFree(item); + virFSPoolFree(fspool); + return true; +} + +/* + * "item-key" command + */ +static const vshCmdInfo info_item_key[] = { + {.name = "help", + .data = N_("returns the item key for a given item name or path") + }, + {.name = "desc", + .data = "" + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_item_key[] = { + {.name = "item", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_REQ, + .help = N_("item name or path") + }, + VIRSH_COMMON_OPT_FSPOOL_OPTIONAL, + {.name = NULL} +}; + +static bool +cmdItemKey(vshControl *ctl, const vshCmd *cmd) +{ + virFSItemPtr item; + + if (!(item = virshCommandOptItem(ctl, cmd, "item", "fspool", NULL))) + return false; + + vshPrint(ctl, "%s\n", virFSItemGetKey(item)); + virFSItemFree(item); + return true; +} + +/* + * "item-path" command + */ +static const vshCmdInfo info_item_path[] = { + {.name = "help", + .data = N_("returns the item path for a given item name or key") + }, + {.name = "desc", + .data = "" + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_item_path[] = { + {.name = "item", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_REQ, + .help = N_("item name or key") + }, + VIRSH_COMMON_OPT_FSPOOL_OPTIONAL, + {.name = NULL} +}; + +static bool +cmdItemPath(vshControl *ctl, const vshCmd *cmd) +{ + virFSItemPtr item; + char * FSItemPath; + + if (!(item = virshCommandOptItem(ctl, cmd, "item", "fspool", NULL))) + return false; + + if ((FSItemPath = virFSItemGetPath(item)) == NULL) { + virFSItemFree(item); + return false; + } + + vshPrint(ctl, "%s\n", FSItemPath); + VIR_FREE(FSItemPath); + virFSItemFree(item); + return true; +} + +const vshCmdDef fsItemCmds[] = { + {.name = "item-clone", + .handler = cmdItemClone, + .opts = opts_item_clone, + .info = info_item_clone, + .flags = 0 + }, + {.name = "item-create-as", + .handler = cmdItemCreateAs, + .opts = opts_item_create_as, + .info = info_item_create_as, + .flags = 0 + }, + {.name = "item-create", + .handler = cmdItemCreate, + .opts = opts_item_create, + .info = info_item_create, + .flags = 0 + }, + {.name = "item-create-from", + .handler = cmdItemCreateFrom, + .opts = opts_item_create_from, + .info = info_item_create_from, + .flags = 0 + }, + {.name = "item-delete", + .handler = cmdItemDelete, + .opts = opts_item_delete, + .info = info_item_delete, + .flags = 0 + }, + {.name = "item-dumpxml", + .handler = cmdItemDumpXML, + .opts = opts_item_dumpxml, + .info = info_item_dumpxml, + .flags = 0 + }, + {.name = "item-info", + .handler = cmdItemInfo, + .opts = opts_item_info, + .info = info_item_info, + .flags = 0 + }, + {.name = "item-key", + .handler = cmdItemKey, + .opts = opts_item_key, + .info = info_item_key, + .flags = 0 + }, + {.name = "item-list", + .handler = cmdItemList, + .opts = opts_item_list, + .info = info_item_list, + .flags = 0 + }, + {.name = "item-name", + .handler = cmdItemName, + .opts = opts_item_name, + .info = info_item_name, + .flags = 0 + }, + {.name = "item-path", + .handler = cmdItemPath, + .opts = opts_item_path, + .info = info_item_path, + .flags = 0 + }, + {.name = "item-fspool", + .handler = cmdItemPool, + .opts = opts_item_fspool, + .info = info_item_fspool, + .flags = 0 + }, + {.name = NULL} +}; diff --git a/tools/virsh-fsitem.h b/tools/virsh-fsitem.h new file mode 100644 index 0000000..0607ac5 --- /dev/null +++ b/tools/virsh-fsitem.h @@ -0,0 +1,39 @@ +/* + * virsh-fsitem.h: Commands to manage fsitems + * + * Copyright (C) 2016 Parallels IP Holdings GmbH + * + * 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 VIRSH_FSITEM_H +# define VIRSH_FSITEM_H + +# include "virsh.h" + +virFSItemPtr virshCommandOptItemBy(vshControl *ctl, const vshCmd *cmd, + const char *optname, + const char *fspooloptname, + const char **name, unsigned int flags); + +/* default is lookup by Name and UUID */ +# define virshCommandOptItem(_ctl, _cmd, _optname, _fspooloptname, _name) \ + virshCommandOptItemBy(_ctl, _cmd, _optname, _fspooloptname, _name, \ + VIRSH_BYUUID | VIRSH_BYNAME) + +extern const vshCmdDef fsItemCmds[]; + +#endif /* VIRSH_FSITEM_H */ diff --git a/tools/virsh-fspool.c b/tools/virsh-fspool.c new file mode 100644 index 0000000..5034fce --- /dev/null +++ b/tools/virsh-fspool.c @@ -0,0 +1,1574 @@ +/* + * virsh-fspool.c: Commands to manage fspool + * + * Copyright (C) 2016 Parallels IP Holdings GmbH + * + * + * 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/>. + * + * Olga Krishtal <okrishtal@virtuozzo.com> + * + */ + +#include <config.h> +#include "virsh-fspool.h" + +#include "internal.h" +#include "virbuffer.h" +#include "viralloc.h" +#include "virfile.h" +#include "conf/fs_conf.h" +#include "virstring.h" + +#define VIRSH_COMMON_OPT_FSPOOL_FULL \ + VIRSH_COMMON_OPT_FSPOOL(N_("fspool name or uuid")) \ + +#define VIRSH_COMMON_OPT_FSPOOL_BUILD \ + {.name = "build", \ + .type = VSH_OT_BOOL, \ + .flags = 0, \ + .help = N_("build the fspool as normal") \ + } \ + +#define VIRSH_COMMON_OPT_FSPOOL_NO_OVERWRITE \ + {.name = "no-overwrite", \ + .type = VSH_OT_BOOL, \ + .flags = 0, \ + .help = N_("do not overwrite an existing fspool of this type") \ + } \ + +#define VIRSH_COMMON_OPT_FSPOOL_OVERWRITE \ + {.name = "overwrite", \ + .type = VSH_OT_BOOL, \ + .flags = 0, \ + .help = N_("overwrite any existing data") \ + } \ + +#define VIRSH_COMMON_OPT_FSPOOL_X_AS \ + {.name = "name", \ + .type = VSH_OT_DATA, \ + .flags = VSH_OFLAG_REQ, \ + .help = N_("name of the fspool") \ + }, \ + {.name = "type", \ + .type = VSH_OT_DATA, \ + .flags = VSH_OFLAG_REQ, \ + .help = N_("type of the fspool") \ + }, \ + {.name = "print-xml", \ + .type = VSH_OT_BOOL, \ + .help = N_("print XML document, but don't define/create") \ + }, \ + {.name = "source-host", \ + .type = VSH_OT_STRING, \ + .help = N_("source-host for underlying storage") \ + }, \ + {.name = "source-path", \ + .type = VSH_OT_STRING, \ + .help = N_("source path for underlying storage") \ + }, \ + {.name = "source-name", \ + .type = VSH_OT_STRING, \ + .help = N_("source name for underlying storage") \ + }, \ + {.name = "target", \ + .type = VSH_OT_STRING, \ + .help = N_("target for underlying storage") \ + }, \ + {.name = "source-format", \ + .type = VSH_OT_STRING, \ + .help = N_("format for underlying storage") \ + } \ + +virFSPoolPtr +virshCommandOptFSPoolBy(vshControl *ctl, const vshCmd *cmd, const char *optname, + const char **name, unsigned int flags) +{ + virFSPoolPtr fspool = NULL; + const char *n = NULL; + virshControlPtr priv = ctl->privData; + + virCheckFlags(VIRSH_BYUUID | VIRSH_BYNAME, NULL); + + if (vshCommandOptStringReq(ctl, cmd, optname, &n) < 0) + return NULL; + + vshDebug(ctl, VSH_ERR_INFO, "%s: found option <%s>: %s\n", + cmd->def->name, optname, n); + + if (name) + *name = n; + + /* try it by UUID */ + if ((flags & VIRSH_BYUUID) && strlen(n) == VIR_UUID_STRING_BUFLEN-1) { + vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as fspool UUID\n", + cmd->def->name, optname); + fspool = virFSPoolLookupByUUIDString(priv->conn, n); + } + /* try it by NAME */ + if (!fspool && (flags & VIRSH_BYNAME)) { + vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as fspool NAME\n", + cmd->def->name, optname); + fspool = virFSPoolLookupByName(priv->conn, n); + } + + if (!fspool) + vshError(ctl, _("failed to get fspool '%s'"), n); + + return fspool; +} + +/* + * "fspool-create" command + */ +static const vshCmdInfo info_fspool_create[] = { + {.name = "help", + .data = N_("create a fspool from an XML file") + }, + {.name = "desc", + .data = N_("Create a fspool.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_fspool_create[] = { + VIRSH_COMMON_OPT_FILE(N_("file containing an XML fspool description")), + VIRSH_COMMON_OPT_FSPOOL_BUILD, + VIRSH_COMMON_OPT_FSPOOL_NO_OVERWRITE, + VIRSH_COMMON_OPT_FSPOOL_OVERWRITE, + + {.name = NULL} +}; + +static bool +cmdFSPoolCreate(vshControl *ctl, const vshCmd *cmd) +{ + virFSPoolPtr fspool; + const char *from = NULL; + bool ret = true; + char *buffer; + bool overwrite; + bool no_overwrite; + unsigned int flags = 0; + virshControlPtr priv = ctl->privData; + + if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0) + return false; + + overwrite = vshCommandOptBool(cmd, "overwrite"); + no_overwrite = vshCommandOptBool(cmd, "no-overwrite"); + + VSH_EXCLUSIVE_OPTIONS_EXPR("overwrite", overwrite, + "no-overwrite", no_overwrite); + + if (overwrite) + flags |= VIR_FSPOOL_CREATE_WITH_BUILD_OVERWRITE; + if (no_overwrite) + flags |= VIR_FSPOOL_CREATE_WITH_BUILD_NO_OVERWRITE; + + if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0) + return false; + + fspool = virFSPoolCreateXML(priv->conn, buffer, flags); + VIR_FREE(buffer); + + if (fspool != NULL) { + vshPrint(ctl, _("FSpool %s created from %s\n"), + virFSPoolGetName(fspool), from); + virFSPoolFree(fspool); + } else { + vshError(ctl, _("Failed to create fspool from %s"), from); + ret = false; + } + return ret; +} + +static const vshCmdOptDef opts_fspool_define_as[] = { + VIRSH_COMMON_OPT_FSPOOL_X_AS, + + {.name = NULL} +}; + +static int +virshBuildFSPoolXML(vshControl *ctl, + const vshCmd *cmd, + const char **retname, + char **xml) +{ + const char *name = NULL, *type = NULL, *srcHost = NULL, *srcPath = NULL, + *srcName = NULL, *srcFormat = NULL, *target = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (vshCommandOptStringReq(ctl, cmd, "name", &name) < 0) + goto cleanup; + if (vshCommandOptStringReq(ctl, cmd, "type", &type) < 0) + goto cleanup; + + if (vshCommandOptStringReq(ctl, cmd, "source-host", &srcHost) < 0 || + vshCommandOptStringReq(ctl, cmd, "source-path", &srcPath) < 0 || + vshCommandOptStringReq(ctl, cmd, "source-name", &srcName) < 0 || + vshCommandOptStringReq(ctl, cmd, "source-format", &srcFormat) < 0 || + vshCommandOptStringReq(ctl, cmd, "target", &target) < 0) + goto cleanup; + + virBufferAsprintf(&buf, "<fspool type='%s'>\n", type); + virBufferAdjustIndent(&buf, 2); + virBufferAsprintf(&buf, "<name>%s</name>\n", name); + if (srcHost || srcPath || srcFormat || srcName) { + virBufferAddLit(&buf, "<source>\n"); + virBufferAdjustIndent(&buf, 2); + + if (srcHost) + virBufferAsprintf(&buf, "<host name='%s'/>\n", srcHost); + if (srcPath) + virBufferAsprintf(&buf, "<dir path='%s'/>\n", srcPath); + if (srcFormat) + virBufferAsprintf(&buf, "<format type='%s'/>\n", srcFormat); + if (srcName) + virBufferAsprintf(&buf, "<name>%s</name>\n", srcName); + + virBufferAdjustIndent(&buf, -2); + virBufferAddLit(&buf, "</source>\n"); + } + if (target) { + virBufferAddLit(&buf, "<target>\n"); + virBufferAdjustIndent(&buf, 2); + virBufferAsprintf(&buf, "<path>%s</path>\n", target); + virBufferAdjustIndent(&buf, -2); + virBufferAddLit(&buf, "</target>\n"); + } + virBufferAdjustIndent(&buf, -2); + virBufferAddLit(&buf, "</fspool>\n"); + + if (virBufferError(&buf)) { + vshPrint(ctl, "%s", _("Failed to allocate XML buffer")); + return false; + } + + *xml = virBufferContentAndReset(&buf); + *retname = name; + return true; + + cleanup: + virBufferFreeAndReset(&buf); + return false; +} + +/* + * "fspool-autostart" command + */ +static const vshCmdInfo info_fspool_autostart[] = { + {.name = "help", + .data = N_("autostart a fspool") + }, + {.name = "desc", + .data = N_("Configure a fspool to be automatically started at boot.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_fspool_autostart[] = { + VIRSH_COMMON_OPT_FSPOOL_FULL, + + {.name = "disable", + .type = VSH_OT_BOOL, + .help = N_("disable autostarting") + }, + {.name = NULL} +}; + +static bool +cmdFSPoolAutostart(vshControl *ctl, const vshCmd *cmd) +{ + virFSPoolPtr fspool; + const char *name; + int autostart; + + if (!(fspool = virshCommandOptFSPool(ctl, cmd, "fspool", &name))) + return false; + + autostart = !vshCommandOptBool(cmd, "disable"); + + if (virFSPoolSetAutostart(fspool, autostart) < 0) { + if (autostart) + vshError(ctl, _("failed to mark fspool %s as autostarted"), name); + else + vshError(ctl, _("failed to unmark fspool %s as autostarted"), name); + virFSPoolFree(fspool); + return false; + } + + if (autostart) + vshPrint(ctl, _("Fspool %s marked as autostarted\n"), name); + else + vshPrint(ctl, _("Fspool %s unmarked as autostarted\n"), name); + + virFSPoolFree(fspool); + return true; +} + +/* + * "fspool-create-as" command + */ +static const vshCmdInfo info_fspool_create_as[] = { + {.name = "help", + .data = N_("create a fspool from a set of args") + }, + {.name = "desc", + .data = N_("Create a fspool.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_fspool_create_as[] = { + VIRSH_COMMON_OPT_FSPOOL_X_AS, + VIRSH_COMMON_OPT_FSPOOL_BUILD, + VIRSH_COMMON_OPT_FSPOOL_NO_OVERWRITE, + VIRSH_COMMON_OPT_FSPOOL_OVERWRITE, + + {.name = NULL} +}; + +static bool +cmdFSPoolCreateAs(vshControl *ctl, const vshCmd *cmd) +{ + virFSPoolPtr fspool; + const char *name; + char *xml; + bool printXML = vshCommandOptBool(cmd, "print-xml"); + bool overwrite; + bool no_overwrite; + unsigned int flags = 0; + virshControlPtr priv = ctl->privData; + + overwrite = vshCommandOptBool(cmd, "overwrite"); + no_overwrite = vshCommandOptBool(cmd, "no-overwrite"); + + VSH_EXCLUSIVE_OPTIONS_EXPR("overwrite", overwrite, + "no-overwrite", no_overwrite); + + if (overwrite) + flags |= VIR_FSPOOL_CREATE_WITH_BUILD_OVERWRITE; + if (no_overwrite) + flags |= VIR_FSPOOL_CREATE_WITH_BUILD_NO_OVERWRITE; + + if (!virshBuildFSPoolXML(ctl, cmd, &name, &xml)) + return false; + + if (printXML) { + vshPrint(ctl, "%s", xml); + VIR_FREE(xml); + } else { + fspool = virFSPoolCreateXML(priv->conn, xml, flags); + VIR_FREE(xml); + + if (fspool != NULL) { + vshPrint(ctl, _("FSool %s created\n"), name); + virFSPoolFree(fspool); + } else { + vshError(ctl, _("Failed to create fspool %s"), name); + return false; + } + } + return true; +} + +/* + * "fspool-define" command + */ +static const vshCmdInfo info_fspool_define[] = { + {.name = "help", + .data = N_("define an inactive persistent fspool or modify " + "an existing persistent one from an XML file") + }, + {.name = "desc", + .data = N_("Define or modify a persistent fspool.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_fspool_define[] = { + VIRSH_COMMON_OPT_FILE(N_("file containing an XML fspool description")), + + {.name = NULL} +}; + +static bool +cmdFSPoolDefine(vshControl *ctl, const vshCmd *cmd) +{ + virFSPoolPtr fspool; + const char *from = NULL; + bool ret = true; + char *buffer; + virshControlPtr priv = ctl->privData; + + if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0) + return false; + + if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0) + return false; + + fspool = virFSPoolDefineXML(priv->conn, buffer, 0); + VIR_FREE(buffer); + + if (fspool != NULL) { + vshPrint(ctl, _("FSool %s defined from %s\n"), + virFSPoolGetName(fspool), from); + virFSPoolFree(fspool); + } else { + vshError(ctl, _("Failed to define fspool from %s"), from); + ret = false; + } + return ret; +} + +/* + * "fspool-define-as" command + */ +static const vshCmdInfo info_fspool_define_as[] = { + {.name = "help", + .data = N_("define a fspool from a set of args") + }, + {.name = "desc", + .data = N_("Define a fspool.") + }, + {.name = NULL} +}; + +static bool +cmdFSPoolDefineAs(vshControl *ctl, const vshCmd *cmd) +{ + virFSPoolPtr fspool; + const char *name; + char *xml; + bool printXML = vshCommandOptBool(cmd, "print-xml"); + virshControlPtr priv = ctl->privData; + + if (!virshBuildFSPoolXML(ctl, cmd, &name, &xml)) + return false; + + if (printXML) { + vshPrint(ctl, "%s", xml); + VIR_FREE(xml); + } else { + fspool = virFSPoolDefineXML(priv->conn, xml, 0); + VIR_FREE(xml); + + if (fspool != NULL) { + vshPrint(ctl, _("FSpool %s defined\n"), name); + virFSPoolFree(fspool); + } else { + vshError(ctl, _("Failed to define fspool %s"), name); + return false; + } + } + return true; +} + +/* + * "fspool-build" command + */ +static const vshCmdInfo info_fspool_build[] = { + {.name = "help", + .data = N_("build a fspool") + }, + {.name = "desc", + .data = N_("Build a given fspool.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_fspool_build[] = { + VIRSH_COMMON_OPT_FSPOOL_FULL, + VIRSH_COMMON_OPT_FSPOOL_NO_OVERWRITE, + VIRSH_COMMON_OPT_FSPOOL_OVERWRITE, + + {.name = NULL} +}; + +static bool +cmdFSPoolBuild(vshControl *ctl, const vshCmd *cmd) +{ + virFSPoolPtr fspool; + bool ret = true; + const char *name; + unsigned int flags = 0; + + if (!(fspool = virshCommandOptFSPool(ctl, cmd, "fspool", &name))) + return false; + + if (vshCommandOptBool(cmd, "no-overwrite")) + flags |= VIR_FSPOOL_BUILD_NO_OVERWRITE; + + if (vshCommandOptBool(cmd, "overwrite")) + flags |= VIR_FSPOOL_BUILD_OVERWRITE; + + if (virFSPoolBuild(fspool, flags) == 0) { + vshPrint(ctl, _("FSpool %s built\n"), name); + } else { + vshError(ctl, _("Failed to build fspool %s"), name); + ret = false; + } + + virFSPoolFree(fspool); + + return ret; +} + +/* + * "fspool-destroy" command + */ +static const vshCmdInfo info_fspool_destroy[] = { + {.name = "help", + .data = N_("stop a fspool") + }, + {.name = "desc", + .data = N_("Forcefully stop a given fspool.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_fspool_destroy[] = { + VIRSH_COMMON_OPT_FSPOOL_FULL, + + {.name = NULL} +}; + +static bool +cmdFSPoolDestroy(vshControl *ctl, const vshCmd *cmd) +{ + virFSPoolPtr fspool; + bool ret = true; + const char *name; + + if (!(fspool = virshCommandOptFSPool(ctl, cmd, "fspool", &name))) + return false; + + if (virFSPoolDestroy(fspool) == 0) { + vshPrint(ctl, _("FSpool %s destroyed\n"), name); + } else { + vshError(ctl, _("Failed to destroy fspool %s"), name); + ret = false; + } + + virFSPoolFree(fspool); + return ret; +} + +/* + * "fspool-delete" command + */ +static const vshCmdInfo info_fspool_delete[] = { + {.name = "help", + .data = N_("delete a fspool") + }, + {.name = "desc", + .data = N_("Delete a given fspool.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_fspool_delete[] = { + VIRSH_COMMON_OPT_FSPOOL_FULL, + + {.name = NULL} +}; + +static bool +cmdFSPoolDelete(vshControl *ctl, const vshCmd *cmd) +{ + virFSPoolPtr fspool; + bool ret = true; + const char *name; + + if (!(fspool = virshCommandOptFSPool(ctl, cmd, "fspool", &name))) + return false; + + if (virFSPoolDelete(fspool, 0) == 0) { + vshPrint(ctl, _("Pool %s deleted\n"), name); + } else { + vshError(ctl, _("Failed to delete fspool %s"), name); + ret = false; + } + + virFSPoolFree(fspool); + return ret; +} + +/* + * "fspool-refresh" command + */ +static const vshCmdInfo info_fspool_refresh[] = { + {.name = "help", + .data = N_("refresh a fspool") + }, + {.name = "desc", + .data = N_("Refresh a given fspool.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_fspool_refresh[] = { + VIRSH_COMMON_OPT_FSPOOL_FULL, + + {.name = NULL} +}; + +static bool +cmdFSPoolRefresh(vshControl *ctl, const vshCmd *cmd) +{ + virFSPoolPtr fspool; + bool ret = true; + const char *name; + + if (!(fspool = virshCommandOptFSPool(ctl, cmd, "fspool", &name))) + return false; + + if (virFSPoolRefresh(fspool, 0) == 0) { + vshPrint(ctl, _("Pool %s refreshed\n"), name); + } else { + vshError(ctl, _("Failed to refresh fspool %s"), name); + ret = false; + } + virFSPoolFree(fspool); + + return ret; +} + +/* + * "fspool-dumpxml" command + */ +static const vshCmdInfo info_fspool_dumpxml[] = { + {.name = "help", + .data = N_("fspool information in XML") + }, + {.name = "desc", + .data = N_("Output the fspool information as an XML dump to stdout.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_fspool_dumpxml[] = { + VIRSH_COMMON_OPT_FSPOOL_FULL, + + {.name = "inactive", + .type = VSH_OT_BOOL, + .help = N_("show inactive defined XML") + }, + {.name = NULL} +}; + +static bool +cmdFSPoolDumpXML(vshControl *ctl, const vshCmd *cmd) +{ + virFSPoolPtr fspool; + bool ret = true; + bool inactive = vshCommandOptBool(cmd, "inactive"); + unsigned int flags = 0; + char *dump; + + if (inactive) + flags |= VIR_FS_XML_INACTIVE; + + if (!(fspool = virshCommandOptFSPool(ctl, cmd, "fspool", NULL))) + return false; + + dump = virFSPoolGetXMLDesc(fspool, flags); + if (dump != NULL) { + vshPrint(ctl, "%s", dump); + VIR_FREE(dump); + } else { + ret = false; + } + + virFSPoolFree(fspool); + return ret; +} + +static int +virshFSPoolSorter(const void *a, const void *b) +{ + virFSPoolPtr *pa = (virFSPoolPtr *) a; + virFSPoolPtr *pb = (virFSPoolPtr *) b; + + if (*pa && !*pb) + return -1; + + if (!*pa) + return *pb != NULL; + + return vshStrcasecmp(virFSPoolGetName(*pa), + virFSPoolGetName(*pb)); +} + +struct virshFSPoolList { + virFSPoolPtr *fspools; + size_t nfspools; +}; +typedef struct virshFSPoolList *virshFSPoolListPtr; + +static void +virshFSPoolListFree(virshFSPoolListPtr list) +{ + size_t i; + + if (list && list->fspools) { + for (i = 0; i < list->nfspools; i++) { + if (list->fspools[i]) + virFSPoolFree(list->fspools[i]); + } + VIR_FREE(list->fspools); + } + VIR_FREE(list); +} + +static virshFSPoolListPtr +virshFSPoolListCollect(vshControl *ctl, + unsigned int flags) +{ + virshFSPoolListPtr list = vshMalloc(ctl, sizeof(*list)); + int ret; + virshControlPtr priv = ctl->privData; + + /* try the list with flags support (0.10.2 and later) */ + if ((ret = virConnectListAllFSPools(priv->conn, + &list->fspools, + flags)) < 0) { + vshError(ctl, "%s", _("Failed to list fspools")); + return NULL; + } + + list->nfspools = ret; + + /* sort the list */ + if (list->fspools && list->nfspools) + qsort(list->fspools, list->nfspools, + sizeof(*list->fspools), virshFSPoolSorter); + + return list; +} + + +VIR_ENUM_DECL(virshFSPoolState) +VIR_ENUM_IMPL(virshFSPoolState, + VIR_FSPOOL_STATE_LAST, + N_("inactive"), + N_("building"), + N_("running")) + +static const char * +virshFSPoolStateToString(int state) +{ + const char *str = virshFSPoolStateTypeToString(state); + return str ? _(str) : _("unknown"); +} + + +/* + * "fspool-list" command + */ +static const vshCmdInfo info_fspool_list[] = { + {.name = "help", + .data = N_("list fspools") + }, + {.name = "desc", + .data = N_("Returns list of fspools.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_fspool_list[] = { + {.name = "inactive", + .type = VSH_OT_BOOL, + .help = N_("list inactive fspools") + }, + {.name = "all", + .type = VSH_OT_BOOL, + .help = N_("list inactive & active fspools") + }, + {.name = "transient", + .type = VSH_OT_BOOL, + .help = N_("list transient fspools") + }, + {.name = "persistent", + .type = VSH_OT_BOOL, + .help = N_("list persistent fspools") + }, + {.name = "autostart", + .type = VSH_OT_BOOL, + .help = N_("list fspools with autostart enabled") + }, + {.name = "no-autostart", + .type = VSH_OT_BOOL, + .help = N_("list fspools with autostart disabled") + }, + {.name = "type", + .type = VSH_OT_STRING, + .help = N_("only list fspool of specified type(s) (if supported)") + }, + {.name = "details", + .type = VSH_OT_BOOL, + .help = N_("display extended details for fspools") + }, + {.name = NULL} +}; + +static bool +cmdFSPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + virFSPoolInfo info; + size_t i; + bool ret = false; + size_t stringLength = 0, nameStrLength = 0; + size_t autostartStrLength = 0, persistStrLength = 0; + size_t stateStrLength = 0, capStrLength = 0; + size_t allocStrLength = 0, availStrLength = 0; + struct fspoolInfoText { + char *state; + char *autostart; + char *persistent; + char *capacity; + char *allocation; + char *available; + }; + struct fspoolInfoText *fspoolInfoTexts = NULL; + unsigned int flags = VIR_CONNECT_LIST_FSPOOLS_ACTIVE; + virshFSPoolListPtr list = NULL; + const char *type = NULL; + bool details = vshCommandOptBool(cmd, "details"); + bool inactive, all; + char *outputStr = NULL; + + inactive = vshCommandOptBool(cmd, "inactive"); + all = vshCommandOptBool(cmd, "all"); + + if (inactive) + flags = VIR_CONNECT_LIST_FSPOOLS_INACTIVE; + + if (all) + flags = VIR_CONNECT_LIST_FSPOOLS_ACTIVE | + VIR_CONNECT_LIST_FSPOOLS_INACTIVE; + + if (vshCommandOptBool(cmd, "autostart")) + flags |= VIR_CONNECT_LIST_FSPOOLS_AUTOSTART; + + if (vshCommandOptBool(cmd, "no-autostart")) + flags |= VIR_CONNECT_LIST_FSPOOLS_NO_AUTOSTART; + + if (vshCommandOptBool(cmd, "persistent")) + flags |= VIR_CONNECT_LIST_FSPOOLS_PERSISTENT; + + if (vshCommandOptBool(cmd, "transient")) + flags |= VIR_CONNECT_LIST_FSPOOLS_TRANSIENT; + + if (vshCommandOptStringReq(ctl, cmd, "type", &type) < 0) + return false; + + if (type) { + int fspoolType = -1; + char **fspoolTypes = NULL; + int nfspoolTypes = 0; + + if ((nfspoolTypes = vshStringToArray(type, &fspoolTypes)) < 0) + return false; + + for (i = 0; i < nfspoolTypes; i++) { + if ((fspoolType = virFSPoolTypeFromString(fspoolTypes[i])) < 0) { + vshError(ctl, _("Invalid fspool type '%s'"), fspoolTypes[i]); + virStringFreeList(fspoolTypes); + return false; + } + + switch ((virFSPoolType) fspoolType) { + case VIR_FSPOOL_DIR: + flags |= VIR_CONNECT_LIST_FSPOOLS_DIR; + break; + case VIR_FSPOOL_LAST: + break; + } + } + virStringFreeList(fspoolTypes); + } + + if (!(list = virshFSPoolListCollect(ctl, flags))) + goto cleanup; + + fspoolInfoTexts = vshCalloc(ctl, list->nfspools, sizeof(*fspoolInfoTexts)); + + /* Collect the storage fspool information for display */ + for (i = 0; i < list->nfspools; i++) { + int autostart = 0, persistent = 0; + + /* Retrieve the autostart status of the fspool */ + if (virFSPoolGetAutostart(list->fspools[i], &autostart) < 0) + fspoolInfoTexts[i].autostart = vshStrdup(ctl, _("no autostart")); + else + fspoolInfoTexts[i].autostart = vshStrdup(ctl, autostart ? + _("yes") : _("no")); + + /* Retrieve the persistence status of the fspool */ + if (details) { + persistent = virFSPoolIsPersistent(list->fspools[i]); + vshDebug(ctl, VSH_ERR_DEBUG, "Persistent flag value: %d\n", + persistent); + if (persistent < 0) + fspoolInfoTexts[i].persistent = vshStrdup(ctl, _("unknown")); + else + fspoolInfoTexts[i].persistent = vshStrdup(ctl, persistent ? + _("yes") : _("no")); + + /* Keep the length of persistent string if longest so far */ + stringLength = strlen(fspoolInfoTexts[i].persistent); + if (stringLength > persistStrLength) + persistStrLength = stringLength; + } + + /* Collect further extended information about the fspool */ + if (virFSPoolGetInfo(list->fspools[i], &info) != 0) { + /* Something went wrong retrieving fspool info, cope with it */ + vshError(ctl, "%s", _("Could not retrieve fspool information")); + fspoolInfoTexts[i].state = vshStrdup(ctl, _("unknown")); + if (details) { + fspoolInfoTexts[i].capacity = vshStrdup(ctl, _("unknown")); + fspoolInfoTexts[i].allocation = vshStrdup(ctl, _("unknown")); + fspoolInfoTexts[i].available = vshStrdup(ctl, _("unknown")); + } + } else { + /* Decide which state string to display */ + if (details) { + const char *state = virshFSPoolStateToString(info.state); + + fspoolInfoTexts[i].state = vshStrdup(ctl, state); + + /* Create the fspool size related strings */ + if (info.state == VIR_FSPOOL_RUNNING) { + double val; + const char *unit; + + val = vshPrettyCapacity(info.capacity, &unit); + if (virAsprintf(&fspoolInfoTexts[i].capacity, + "%.2lf %s", val, unit) < 0) + goto cleanup; + + val = vshPrettyCapacity(info.allocation, &unit); + if (virAsprintf(&fspoolInfoTexts[i].allocation, + "%.2lf %s", val, unit) < 0) + goto cleanup; + + val = vshPrettyCapacity(info.available, &unit); + if (virAsprintf(&fspoolInfoTexts[i].available, + "%.2lf %s", val, unit) < 0) + goto cleanup; + } else { + /* Capacity related information isn't available */ + fspoolInfoTexts[i].capacity = vshStrdup(ctl, _("-")); + fspoolInfoTexts[i].allocation = vshStrdup(ctl, _("-")); + fspoolInfoTexts[i].available = vshStrdup(ctl, _("-")); + } + + /* Keep the length of capacity string if longest so far */ + stringLength = strlen(fspoolInfoTexts[i].capacity); + if (stringLength > capStrLength) + capStrLength = stringLength; + + /* Keep the length of allocation string if longest so far */ + stringLength = strlen(fspoolInfoTexts[i].allocation); + if (stringLength > allocStrLength) + allocStrLength = stringLength; + + /* Keep the length of available string if longest so far */ + stringLength = strlen(fspoolInfoTexts[i].available); + if (stringLength > availStrLength) + availStrLength = stringLength; + } else { + /* --details option was not specified, only active/inactive + * state strings are used */ + if (virFSPoolIsActive(list->fspools[i])) + fspoolInfoTexts[i].state = vshStrdup(ctl, _("active")); + else + fspoolInfoTexts[i].state = vshStrdup(ctl, _("inactive")); + } + } + + /* Keep the length of name string if longest so far */ + stringLength = strlen(virFSPoolGetName(list->fspools[i])); + if (stringLength > nameStrLength) + nameStrLength = stringLength; + + /* Keep the length of state string if longest so far */ + stringLength = strlen(fspoolInfoTexts[i].state); + if (stringLength > stateStrLength) + stateStrLength = stringLength; + + /* Keep the length of autostart string if longest so far */ + stringLength = strlen(fspoolInfoTexts[i].autostart); + if (stringLength > autostartStrLength) + autostartStrLength = stringLength; + } + + /* If the --details option wasn't selected, we output the fspool + * info using the fixed string format from previous versions to + * maintain backward compatibility. + */ + + /* Output basic info then return if --details option not selected */ + if (!details) { + /* Output old style header */ + vshPrintExtra(ctl, " %-20s %-10s %-10s\n", _("Name"), _("State"), + _("Autostart")); + vshPrintExtra(ctl, "-------------------------------------------\n"); + + /* Output old style fspool info */ + for (i = 0; i < list->nfspools; i++) { + const char *name = virFSPoolGetName(list->fspools[i]); + vshPrint(ctl, " %-20s %-10s %-10s\n", + name, + fspoolInfoTexts[i].state, + fspoolInfoTexts[i].autostart); + } + + /* Cleanup and return */ + ret = true; + goto cleanup; + } + + /* We only get here if the --details option was selected. */ + + /* Use the length of name header string if it's longest */ + stringLength = strlen(_("Name")); + if (stringLength > nameStrLength) + nameStrLength = stringLength; + + /* Use the length of state header string if it's longest */ + stringLength = strlen(_("State")); + if (stringLength > stateStrLength) + stateStrLength = stringLength; + + /* Use the length of autostart header string if it's longest */ + stringLength = strlen(_("Autostart")); + if (stringLength > autostartStrLength) + autostartStrLength = stringLength; + + /* Use the length of persistent header string if it's longest */ + stringLength = strlen(_("Persistent")); + if (stringLength > persistStrLength) + persistStrLength = stringLength; + + /* Use the length of capacity header string if it's longest */ + stringLength = strlen(_("Capacity")); + if (stringLength > capStrLength) + capStrLength = stringLength; + + /* Use the length of allocation header string if it's longest */ + stringLength = strlen(_("Allocation")); + if (stringLength > allocStrLength) + allocStrLength = stringLength; + + /* Use the length of available header string if it's longest */ + stringLength = strlen(_("Available")); + if (stringLength > availStrLength) + availStrLength = stringLength; + + /* Display the string lengths for debugging. */ + vshDebug(ctl, VSH_ERR_DEBUG, "Longest name string = %lu chars\n", + (unsigned long) nameStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, "Longest state string = %lu chars\n", + (unsigned long) stateStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, "Longest autostart string = %lu chars\n", + (unsigned long) autostartStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, "Longest persistent string = %lu chars\n", + (unsigned long) persistStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, "Longest capacity string = %lu chars\n", + (unsigned long) capStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, "Longest allocation string = %lu chars\n", + (unsigned long) allocStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, "Longest available string = %lu chars\n", + (unsigned long) availStrLength); + + /* Create the output template. Each column is sized according to + * the longest string. + */ + if (virAsprintf(&outputStr, + " %%-%lus %%-%lus %%-%lus %%-%lus %%%lus %%%lus %%%lus\n", + (unsigned long) nameStrLength, + (unsigned long) stateStrLength, + (unsigned long) autostartStrLength, + (unsigned long) persistStrLength, + (unsigned long) capStrLength, + (unsigned long) allocStrLength, + (unsigned long) availStrLength) < 0) + goto cleanup; + + /* Display the header */ + vshPrint(ctl, outputStr, _("Name"), _("State"), _("Autostart"), + _("Persistent"), _("Capacity"), _("Allocation"), _("Available")); + for (i = nameStrLength + stateStrLength + autostartStrLength + + persistStrLength + capStrLength + + allocStrLength + availStrLength + + 14; i > 0; i--) + vshPrintExtra(ctl, "-"); + vshPrintExtra(ctl, "\n"); + + /* Display the fspool info rows */ + for (i = 0; i < list->nfspools; i++) { + vshPrint(ctl, outputStr, + virFSPoolGetName(list->fspools[i]), + fspoolInfoTexts[i].state, + fspoolInfoTexts[i].autostart, + fspoolInfoTexts[i].persistent, + fspoolInfoTexts[i].capacity, + fspoolInfoTexts[i].allocation, + fspoolInfoTexts[i].available); + } + + /* Cleanup and return */ + ret = true; + + cleanup: + VIR_FREE(outputStr); + if (list && list->nfspools) { + for (i = 0; i < list->nfspools; i++) { + VIR_FREE(fspoolInfoTexts[i].state); + VIR_FREE(fspoolInfoTexts[i].autostart); + VIR_FREE(fspoolInfoTexts[i].persistent); + VIR_FREE(fspoolInfoTexts[i].capacity); + VIR_FREE(fspoolInfoTexts[i].allocation); + VIR_FREE(fspoolInfoTexts[i].available); + } + } + VIR_FREE(fspoolInfoTexts); + + virshFSPoolListFree(list); + return ret; +} + +/* + * "fspool-info" command + */ +static const vshCmdInfo info_fspool_info[] = { + {.name = "help", + .data = N_("storage fspool information") + }, + {.name = "desc", + .data = N_("Returns basic information about the storage fspool.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_fspool_info[] = { + VIRSH_COMMON_OPT_FSPOOL_FULL, + + {.name = NULL} +}; + +static bool +cmdFSPoolInfo(vshControl *ctl, const vshCmd *cmd) +{ + virFSPoolInfo info; + virFSPoolPtr fspool; + int autostart = 0; + int persistent = 0; + bool ret = true; + char uuid[VIR_UUID_STRING_BUFLEN]; + + if (!(fspool = virshCommandOptFSPool(ctl, cmd, "fspool", NULL))) + return false; + + vshPrint(ctl, "%-15s %s\n", _("Name:"), virFSPoolGetName(fspool)); + + if (virFSPoolGetUUIDString(fspool, &uuid[0]) == 0) + vshPrint(ctl, "%-15s %s\n", _("UUID:"), uuid); + + if (virFSPoolGetInfo(fspool, &info) == 0) { + double val; + const char *unit; + vshPrint(ctl, "%-15s %s\n", _("State:"), + virshFSPoolStateToString(info.state)); + + /* Check and display whether the fspool is persistent or not */ + persistent = virFSPoolIsPersistent(fspool); + vshDebug(ctl, VSH_ERR_DEBUG, "Pool persistent flag value: %d\n", + persistent); + if (persistent < 0) + vshPrint(ctl, "%-15s %s\n", _("Persistent:"), _("unknown")); + else + vshPrint(ctl, "%-15s %s\n", _("Persistent:"), persistent ? _("yes") : _("no")); + + /* Check and display whether the fspool is autostarted or not */ + if (virFSPoolGetAutostart(fspool, &autostart) < 0) + vshPrint(ctl, "%-15s %s\n", _("Autostart:"), _("no autostart")); + else + vshPrint(ctl, "%-15s %s\n", _("Autostart:"), autostart ? _("yes") : _("no")); + + if (info.state == VIR_FSPOOL_RUNNING) { + val = vshPrettyCapacity(info.capacity, &unit); + vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit); + + val = vshPrettyCapacity(info.allocation, &unit); + vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit); + + val = vshPrettyCapacity(info.available, &unit); + vshPrint(ctl, "%-15s %2.2lf %s\n", _("Available:"), val, unit); + } + } else { + ret = false; + } + + virFSPoolFree(fspool); + return ret; +} + +/* + * "fspool-name" command + */ +static const vshCmdInfo info_fspool_name[] = { + {.name = "help", + .data = N_("convert a fspool UUID to fspool name") + }, + {.name = "desc", + .data = "" + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_fspool_name[] = { + VIRSH_COMMON_OPT_FSPOOL_FULL, + + {.name = NULL} +}; + +static bool +cmdFSPoolName(vshControl *ctl, const vshCmd *cmd) +{ + virFSPoolPtr fspool; + + if (!(fspool = virshCommandOptFSPoolBy(ctl, cmd, "fspool", NULL, VIRSH_BYUUID))) + return false; + + vshPrint(ctl, "%s\n", virFSPoolGetName(fspool)); + virFSPoolFree(fspool); + return true; +} + +/* + * "fspool-start" command + */ +static const vshCmdInfo info_fspool_start[] = { + {.name = "help", + .data = N_("start a (previously defined) inactive fspool") + }, + {.name = "desc", + .data = N_("Start a fspool.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_fspool_start[] = { + VIRSH_COMMON_OPT_FSPOOL_FULL, + VIRSH_COMMON_OPT_FSPOOL_BUILD, + VIRSH_COMMON_OPT_FSPOOL_NO_OVERWRITE, + VIRSH_COMMON_OPT_FSPOOL_OVERWRITE, + + {.name = NULL} +}; + +static bool +cmdFSPoolStart(vshControl *ctl, const vshCmd *cmd) +{ + virFSPoolPtr fspool; + bool ret = true; + const char *name = NULL; + bool overwrite; + bool no_overwrite; + unsigned int flags = 0; + + if (!(fspool = virshCommandOptFSPool(ctl, cmd, "fspool", &name))) + return false; + + overwrite = vshCommandOptBool(cmd, "overwrite"); + no_overwrite = vshCommandOptBool(cmd, "no-overwrite"); + + VSH_EXCLUSIVE_OPTIONS_EXPR("overwrite", overwrite, + "no-overwrite", no_overwrite); + + if (overwrite) + flags |= VIR_FSPOOL_CREATE_WITH_BUILD_OVERWRITE; + if (no_overwrite) + flags |= VIR_FSPOOL_CREATE_WITH_BUILD_NO_OVERWRITE; + + if (virFSPoolCreate(fspool, flags) == 0) { + vshPrint(ctl, _("FSpool %s started\n"), name); + } else { + vshError(ctl, _("Failed to start fspool %s"), name); + ret = false; + } + + virFSPoolFree(fspool); + return ret; +} + +/* + * "fspool-undefine" command + */ +static const vshCmdInfo info_fspool_undefine[] = { + {.name = "help", + .data = N_("undefine an inactive fspool") + }, + {.name = "desc", + .data = N_("Undefine the configuration for an inactive fspool.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_fspool_undefine[] = { + VIRSH_COMMON_OPT_FSPOOL_FULL, + + {.name = NULL} +}; + +static bool +cmdFSPoolUndefine(vshControl *ctl, const vshCmd *cmd) +{ + virFSPoolPtr fspool; + bool ret = true; + const char *name; + + if (!(fspool = virshCommandOptFSPool(ctl, cmd, "fspool", &name))) + return false; + + if (virFSPoolUndefine(fspool) == 0) { + vshPrint(ctl, _("Pool %s has been undefined\n"), name); + } else { + vshError(ctl, _("Failed to undefine fspool %s"), name); + ret = false; + } + + virFSPoolFree(fspool); + return ret; +} + +/* + * "fspool-uuid" command + */ +static const vshCmdInfo info_fspool_uuid[] = { + {.name = "help", + .data = N_("convert a fspool name to fspool UUID") + }, + {.name = "desc", + .data = "" + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_fspool_uuid[] = { + VIRSH_COMMON_OPT_FSPOOL_FULL, + + {.name = NULL} +}; + +static bool +cmdFSPoolUuid(vshControl *ctl, const vshCmd *cmd) +{ + virFSPoolPtr fspool; + char uuid[VIR_UUID_STRING_BUFLEN]; + + if (!(fspool = virshCommandOptFSPoolBy(ctl, cmd, "fspool", NULL, VIRSH_BYNAME))) + return false; + + if (virFSPoolGetUUIDString(fspool, uuid) != -1) + vshPrint(ctl, "%s\n", uuid); + else + vshError(ctl, "%s", _("failed to get fspool UUID")); + + virFSPoolFree(fspool); + return true; +} + +/* + * "fspool-edit" command + */ +static const vshCmdInfo info_fspool_edit[] = { + {.name = "help", + .data = N_("edit XML configuration for a fspool") + }, + {.name = "desc", + .data = N_("Edit the XML configuration for a fspool.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_fspool_edit[] = { + VIRSH_COMMON_OPT_FSPOOL_FULL, + + {.name = NULL} +}; + +static bool +cmdFSPoolEdit(vshControl *ctl, const vshCmd *cmd) +{ + bool ret = false; + virFSPoolPtr fspool = NULL; + virFSPoolPtr fspool_edited = NULL; + unsigned int flags = VIR_FS_XML_INACTIVE; + char *tmp_desc = NULL; + virshControlPtr priv = ctl->privData; + + fspool = virshCommandOptFSPool(ctl, cmd, "fspool", NULL); + if (fspool == NULL) + goto cleanup; + + /* Some old daemons don't support _INACTIVE flag */ + if (!(tmp_desc = virFSPoolGetXMLDesc(fspool, flags))) { + if (last_error->code == VIR_ERR_INVALID_ARG) { + flags &= ~VIR_FS_XML_INACTIVE; + vshResetLibvirtError(); + } else { + goto cleanup; + } + } else { + VIR_FREE(tmp_desc); + } + +#define EDIT_GET_XML virFSPoolGetXMLDesc(fspool, flags) +#define EDIT_NOT_CHANGED \ + do { \ + vshPrint(ctl, _("Pool %s XML configuration not changed.\n"), \ + virFSPoolGetName(fspool)); \ + ret = true; \ + goto edit_cleanup; \ + } while (0) +#define EDIT_DEFINE \ + (fspool_edited = virFSPoolDefineXML(priv->conn, doc_edited, 0)) +#include "virsh-edit.c" + + vshPrint(ctl, _("Pool %s XML configuration edited.\n"), + virFSPoolGetName(fspool_edited)); + + ret = true; + + cleanup: + if (fspool) + virFSPoolFree(fspool); + if (fspool_edited) + virFSPoolFree(fspool_edited); + + return ret; +} + +const vshCmdDef fsPoolCmds[] = { + {.name = "fspool-autostart", + .handler = cmdFSPoolAutostart, + .opts = opts_fspool_autostart, + .info = info_fspool_autostart, + .flags = 0 + }, + {.name = "fspool-build", + .handler = cmdFSPoolBuild, + .opts = opts_fspool_build, + .info = info_fspool_build, + .flags = 0 + }, + {.name = "fspool-create-as", + .handler = cmdFSPoolCreateAs, + .opts = opts_fspool_create_as, + .info = info_fspool_create_as, + .flags = 0 + }, + {.name = "fspool-create", + .handler = cmdFSPoolCreate, + .opts = opts_fspool_create, + .info = info_fspool_create, + .flags = 0 + }, + {.name = "fspool-define-as", + .handler = cmdFSPoolDefineAs, + .opts = opts_fspool_define_as, + .info = info_fspool_define_as, + .flags = 0 + }, + {.name = "fspool-define", + .handler = cmdFSPoolDefine, + .opts = opts_fspool_define, + .info = info_fspool_define, + .flags = 0 + }, + {.name = "fspool-delete", + .handler = cmdFSPoolDelete, + .opts = opts_fspool_delete, + .info = info_fspool_delete, + .flags = 0 + }, + {.name = "fspool-destroy", + .handler = cmdFSPoolDestroy, + .opts = opts_fspool_destroy, + .info = info_fspool_destroy, + .flags = 0 + }, + {.name = "fspool-dumpxml", + .handler = cmdFSPoolDumpXML, + .opts = opts_fspool_dumpxml, + .info = info_fspool_dumpxml, + .flags = 0 + }, + {.name = "fspool-edit", + .handler = cmdFSPoolEdit, + .opts = opts_fspool_edit, + .info = info_fspool_edit, + .flags = 0 + }, + {.name = "fspool-info", + .handler = cmdFSPoolInfo, + .opts = opts_fspool_info, + .info = info_fspool_info, + .flags = 0 + }, + {.name = "fspool-list", + .handler = cmdFSPoolList, + .opts = opts_fspool_list, + .info = info_fspool_list, + .flags = 0 + }, + {.name = "fspool-name", + .handler = cmdFSPoolName, + .opts = opts_fspool_name, + .info = info_fspool_name, + .flags = 0 + }, + {.name = "fspool-refresh", + .handler = cmdFSPoolRefresh, + .opts = opts_fspool_refresh, + .info = info_fspool_refresh, + .flags = 0 + }, + {.name = "fspool-undefine", + .handler = cmdFSPoolUndefine, + .opts = opts_fspool_undefine, + .info = info_fspool_undefine, + .flags = 0 + }, + {.name = "fspool-uuid", + .handler = cmdFSPoolUuid, + .opts = opts_fspool_uuid, + .info = info_fspool_uuid, + .flags = 0 + }, + {.name = "fspool-start", + .handler = cmdFSPoolStart, + .opts = opts_fspool_start, + .info = info_fspool_start, + .flags = 0 + }, + {.name = NULL} +}; diff --git a/tools/virsh-fspool.h b/tools/virsh-fspool.h new file mode 100644 index 0000000..9eb60f1 --- /dev/null +++ b/tools/virsh-fspool.h @@ -0,0 +1,38 @@ +/* + * virsh-fspool.h: Commands to manage fspool + * + * Copyright (C) 2016 Parallels IP Holdings GmbH + * + * 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 VIRSH_FSPOOL_H +# define VIRSH_FSPOOL_H + +# include "virsh.h" + +virFSPoolPtr +virshCommandOptFSPoolBy(vshControl *ctl, const vshCmd *cmd, const char *optname, + const char **name, unsigned int flags); + +/* default is lookup by Name and UUID */ +# define virshCommandOptFSPool(_ctl, _cmd, _optname, _name) \ + virshCommandOptFSPoolBy(_ctl, _cmd, _optname, _name, \ + VIRSH_BYUUID | VIRSH_BYNAME) + +extern const vshCmdDef fsPoolCmds[]; + +#endif /* VIRSH_FSPOOL_H */ diff --git a/tools/virsh.c b/tools/virsh.c index 1068447..7d7e619 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -68,9 +68,11 @@ #include "virsh-nodedev.h" #include "virsh-nwfilter.h" #include "virsh-pool.h" +#include "virsh-fspool.h" #include "virsh-secret.h" #include "virsh-snapshot.h" #include "virsh-volume.h" +#include "virsh-fsitem.h" /* Gnulib doesn't guarantee SA_SIGINFO support. */ #ifndef SA_SIGINFO @@ -878,6 +880,8 @@ static const vshCmdGrp cmdGroups[] = { {VIRSH_CMD_GRP_SNAPSHOT, "snapshot", snapshotCmds}, {VIRSH_CMD_GRP_STORAGE_POOL, "pool", storagePoolCmds}, {VIRSH_CMD_GRP_STORAGE_VOL, "volume", storageVolCmds}, + {VIRSH_CMD_GRP_FSPOOL, "fspool", fsPoolCmds}, + {VIRSH_CMD_GRP_FSITEM, "item", fsItemCmds}, {VIRSH_CMD_GRP_VIRSH, "virsh", virshCmds}, {NULL, NULL, NULL} }; diff --git a/tools/virsh.h b/tools/virsh.h index fd552bb..5b7a636 100644 --- a/tools/virsh.h +++ b/tools/virsh.h @@ -51,6 +51,8 @@ # define VIRSH_CMD_GRP_DOM_MONITORING "Domain Monitoring" # define VIRSH_CMD_GRP_STORAGE_POOL "Storage Pool" # define VIRSH_CMD_GRP_STORAGE_VOL "Storage Volume" +# define VIRSH_CMD_GRP_FSPOOL "Fspool" +# define VIRSH_CMD_GRP_FSITEM "Item" # define VIRSH_CMD_GRP_NETWORK "Networking" # define VIRSH_CMD_GRP_NODEDEV "Node Device" # define VIRSH_CMD_GRP_IFACE "Interface" @@ -70,6 +72,13 @@ .help = _helpstr \ } \ +# define VIRSH_COMMON_OPT_FSPOOL(_helpstr) \ + {.name = "fspool", \ + .type = VSH_OT_DATA, \ + .flags = VSH_OFLAG_REQ, \ + .help = _helpstr \ + } + # define VIRSH_COMMON_OPT_DOMAIN(_helpstr) \ {.name = "domain", \ .type = VSH_OT_DATA, \ diff --git a/tools/virsh.pod b/tools/virsh.pod index f278fec..1181391 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -699,7 +699,7 @@ Immediately terminate the domain I<domain>. This doesn't give the domain OS any chance to react, and it's the equivalent of ripping the power cord out on a physical machine. In most cases you will want to use the B<shutdown> command instead. However, this does not delete any -storage volumes used by the guest, and if the domain is persistent, it +storage volumes or fspool items used by the guest, and if the domain is persistent, it can be restarted later. If I<domain> is transient, then the metadata of any snapshots will @@ -3904,6 +3904,256 @@ B<blockresize> for live resizing. =back +=head1 FSPOOL COMMANDS + +The following commands manipulate filesystem pools. Many of the commands +for filesystem pools are similar to the ones used for storage pools. + +=over 4 + +=item B<fspool-autostart> I<pool-or-uuid> [I<--disable>] + +Configure whether I<fspool> should automatically start at boot. + +=item B<fspool-build> I<pool-or-uuid> [I<--overwrite>] [I<--no-overwrite>] + +Build a given fspool. + +=item B<pool-create> I<file> +[I<--build>] [[I<--overwrite>] | [I<--no-overwrite>]] + +Create and start a fspool object from the XML I<file>. + +[I<--build>] perform a B<fspool-build> after creation in order +to remove the need for a follow-up command to build the fspool. + +=item B<pool-create-as> I<name> I<type> [I<--print-xml>] +[I<--source-host hostname>] [I<--source-path path>] +[I<--source-name name>] [I<--target path>] [I<--source-format format>] +[I<--build>] [[I<--overwrite>] | [I<--no-overwrite>]] + +Create and start a fspool object I<name> from the raw parameters. If +I<--print-xml> is specified, then print the XML of the fspool object +without creating the fspool. Otherwise, the fspool has the specified +I<type>. +[I<--source-host hostname>] provides the source hostname for fspools backed +by fspool from a remote server (fspool netfs, etc). + +[I<--source-path path>] provides the source directory path for fspools backed +by directories (fspool type dir). + +[I<--source-name name>] provides the source name for fspools backed by storage +from a named element. + +[I<--target path>] is the path for the mapping of the fspool into +the host file system. + +[I<--source-format format>] provides information about the format of the +fspool filesystem type. + +[I<--build>] [[I<--overwrite>] | [I<--no-overwrite>]] perform a +B<fspool-build> after creation in order to remove the need for a +follow-up command to build the fspool. The I<--overwrite> and +I<--no-overwrite> flags follow the same rules as B<fspool-build>. If +just I<--build> is provided, then B<fspool-build> is called with no flags. + +=item B<fspool-define> I<file> + +Define an inactive persistent fspool or modify an existing persistent one +from the XML I<file>. + +=item B<pool-define-as> I<name> I<type> [I<--print-xml>] +[I<--source-host hostname>] [I<--source-path path>] +[I<--source-name name>] [I<--target path>] [I<--source-format format>] + +Create, but do not start, a fspool object I<name> from the raw parameters. +If I<--print-xml> is specified, then print the XML of the pool object +without defining the pool. Otherwise, the pool has the specified +I<type>. + +Use the same arguments as B<fspool-create-as>, except for the I<--build>, +I<--overwrite>, and I<--no-overwrite> options. + +=item B<fspool-destroy> I<fspool-or-uuid> + +Destroy (stop) a given I<fspool> object. Libvirt will no longer manage the fspool +object, but the raw data contained in +the fspool is not changed, and can be later recovered with +B<fspool-create>. + +=item B<fspool-delete> I<fspool-or-uuid> + +Destroy the resources used by a given I<fspool> object. This operation +is non-recoverable. The I<fspool> object will still exist after this +command, ready for the creation of new fspool item. + +=item B<fspool-dumpxml> [I<--inactive>] I<fspool-or-uuid> + +Returns the XML information about the I<fspool> object. +I<--inactive> tells virsh to dump fspool configuration that will be used +on next start of the fspool as opposed to the current fspool configuration. + +=item B<fspool-edit> I<fspool-or-uuid> + +Edit the XML configuration file for a fspool. + +This is equivalent to: + + virsh fspool-dumpxml fspool > fspool.xml + vi fspool.xml (or make changes with your other text editor) + virsh pool-define pool.xml + +except that it does some error checking. + +The editor used can be supplied by the C<$VISUAL> or C<$EDITOR> environment +variables, and defaults to C<vi>. + +=item B<fspool-info> I<fspool-or-uuid> + +Returns basic information about the I<fspool> object. + +=item B<pool-fslist> [I<--inactive>] [I<--all>] + [I<--persistent>] [I<--transient>] + [I<--autostart>] [I<--no-autostart>] + [[I<--details>] [<type>] + +List fspool objects known to libvirt. By default, only active pools +are listed; I<--inactive> lists just the inactive pools, and I<--all> +lists all pools. + +In addition, there are several sets of filtering flags. I<--persistent> is to +list the persistent fspools, I<--transient> is to list the transient fspools. +I<--autostart> lists the autostarting fspools, I<--no-autostart> lists the fspools +with autostarting disabled. + +You may also want to list fspools with specified types using I<type>, the +pool types must be separated by comma, e.g. --type dir. + +The I<--details> option instructs virsh to additionally +display fspool persistence and capacity related information where available. + +=item B<fspool-name> I<uuid> + +Convert the I<uuid> to a fspool name. + +=item B<fspool-refresh> I<fspool-or-uuid> + +Refresh the list of items contained in I<fspool>. + +=item B<fspool-start> I<fspool-or-uuid> +[I<--build>] [[I<--overwrite>] | [I<--no-overwrite>]] + +Start the I<fspool>, which is previously defined but inactive. + +=item B<fspool-undefine> I<fspool-or-uuid> + +Undefine the configuration for an inactive I<fspool>. + +=item B<fspool-uuid> I<fspool> + +Returns the UUID of the named I<fspool>. + +=back + +=head1 FS ITEMS COMMANDS + +=over 4 + +=item B<item-create> I<fspool-or-uuid> I<FILE> + +Create a item from an XML <file>. +I<fspool-or-uuid> is the name or UUID of the fspool to create the item in. +I<FILE> is the XML <file> with the item definition. An easy way to create the +XML <file> is to use the B<item-dumpxml> command to obtain the definition of a +pre-existing item. + +=item B<vol-create-from> I<pool-or-uuid> I<FILE> [I<--inputpool> +I<pool-or-uuid>] I<vol-name-or-key-or-path> [I<--prealloc-metadata>] +[I<--reflink>] + +Create a volume, using another item as input. +I<fspool-or-uuid> is the name or UUID of the fspool to create the item in. +I<FILE> is the XML <file> with the volume definition. +I<--inputfspool> I<fspool-or-uuid> is the name or uuid of the fspool the +source item is in. +I<item-name-or-key-or-path> is the name or key or path of the source item. + +=item B<item-create-as> I<fspool-or-uuid> I<name> I<capacity> +[I<--allocation> I<size>] [I<--format> I<string>][I<--print-xml>] + +Create a item from a set of arguments unless I<--print-xml> is specified, in +which case just the XML of the item object is printed out without any actual +object creation. +I<fspool-or-uuid> is the name or UUID of the fspool to create the item +in. +I<name> is the name of the new item. +I<capacity> is the size of the item to be created, as a scaled integer +(see B<NOTES> above), defaulting to bytes if there is no suffix. +I<--allocation> I<size> is the initial size to be allocated in the item, +also as a scaled integer defaulting to bytes. + +=item B<item-clone> [I<--fspool> I<fspool-or-uuid>] I<item-name-or-key-or-path> +I<name> + +Clone an existing item within the parent fspool. Less powerful, +but easier to type, version of B<item-create-from>. +I<--fspool> I<fspool-or-uuid> is the name or UUID of the fspool +that contains the source item, and will contain the new item. +I<item-name-or-key-or-path> is the name or key or path of the source item. +I<name> is the name of the new item. + +=item B<item-delete> [I<--fspool> I<fspool-or-uuid>] I<item-name-or-key-or-path> + +Delete a given item. +I<--pool> I<fspool-or-uuid> is the name or UUID of the fspool the item +is in. +I<item-name-or-key-or-path> is the name or key or path of the item to delete. + +=item B<item-dumpxml> [I<--fspool> I<fspool-or-uuid>] I<item-name-or-key-or-path> + +Output the item information as an XML dump to stdout. +I<--fspool> I<fspool-or-uuid> is the name or UUID of the fspool the item +is in. I<item-name-or-key-or-path> is the name or key or path of the item +to output the XML of. + +=item B<item-info> [I<--fspool> I<fspool-or-uuid>] I<item-name-or-key-or-path> +[I<--bytes>] + +Returns basic information about the given item. +I<--fspool> I<fspool-or-uuid> is the name or UUID of the fspool the item +is in. I<item-name-or-key-or-path> is the name or key or path of the item +to return information for. If I<--bytes> is specified the sizes are not +converted to human friendly units. + +=item B<item-list> [I<--pool> I<pool-or-uuid>] [I<--details>] + +Return the list of volumes in the given fspool. +I<--fspool> I<fspool-or-uuid> is the name or UUID of the fspool. +The I<--details> option instructs virsh to additionally display item +type and capacity related information where available. + + +=item B<item-path> [I<--fspool> I<fspool-or-uuid>] I<item-name-or-key> + +Return the path for a given item. +I<--fspool> I<fspool-or-uuid> is the name or UUID of the fspool the item +is in. +I<item-name-or-key> is the name or key of the item to return the path for. + +=item B<item-name> I<item-key-or-path> + +Return the name for a given item. +I<item-key-or-path> is the key or path of the item to return the name for. + +=item B<item-key> [I<--fspool> I<fspool-or-uuid>] I<item-name-or-path> + +Return the item key for a given volume. +I<--fspool> I<fspool-or-uuid> is the name or UUID of the fspool the item +is in. I<item-name-or-path> is the name or path of the item to return the +item key for. + +=back + =head1 SECRET COMMANDS The following commands manipulate "secrets" (e.g. passwords, passphrases and -- 1.8.3.1

Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- daemon/Makefile.am | 4 + daemon/libvirtd.c | 9 + po/POTFILES.in | 1 + src/Makefile.am | 33 ++- src/fs/fs_backend.h | 94 +++++++ src/fs/fs_driver.c | 729 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/fs/fs_driver.h | 10 + 7 files changed, 879 insertions(+), 1 deletion(-) create mode 100644 src/fs/fs_backend.h create mode 100644 src/fs/fs_driver.c create mode 100644 src/fs/fs_driver.h diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 927d16f..5e95106 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -260,6 +260,10 @@ endif WITH_SECRETS if WITH_NWFILTER libvirtd_LDADD += ../src/libvirt_driver_nwfilter.la endif WITH_NWFILTER + +if WITH_FS + libvirtd_LDADD += ../src/libvirt_driver_fs.la +endif WITH_FS endif ! WITH_DRIVER_MODULES libvirtd_LDADD += ../src/libvirt.la diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index cd25b50..e978075 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -92,6 +92,9 @@ # ifdef WITH_STORAGE # include "storage/storage_driver.h" # endif +# ifdef WITH_FS +# include "fs/fs_driver.h" +# endif # ifdef WITH_NODE_DEVICES # include "node_device/node_device_driver.h" # endif @@ -374,6 +377,9 @@ static void daemonInitialize(void) # ifdef WITH_NWFILTER virDriverLoadModule("nwfilter"); # endif +# ifdef WITH_FS + virDriverLoadModule("fs"); +# endif # ifdef WITH_XEN virDriverLoadModule("xen"); # endif @@ -408,6 +414,9 @@ static void daemonInitialize(void) # ifdef WITH_STORAGE storageRegister(); # endif +# ifdef WITH_FS + fsRegister(); +# endif # ifdef WITH_NODE_DEVICES nodedevRegister(); # endif diff --git a/po/POTFILES.in b/po/POTFILES.in index 2d4c191..942e099 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -60,6 +60,7 @@ src/esx/esx_vi.c src/esx/esx_vi_methods.c src/esx/esx_vi_types.c src/fdstream.c +src/fs/fs_driver.c src/hyperv/hyperv_driver.c src/hyperv/hyperv_util.c src/hyperv/hyperv_wmi.c diff --git a/src/Makefile.am b/src/Makefile.am index 07e55ec..d18d3f4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -651,7 +651,8 @@ DRIVER_SOURCE_FILES = \ $(VMWARE_DRIVER_SOURCES) \ $(XEN_DRIVER_SOURCES) \ $(XENAPI_DRIVER_SOURCES) \ - $(NULL) + $(FS_DRIVER_SOURCES)\ + $(NULL) STATEFUL_DRIVER_SOURCE_FILES = \ $(BHYVE_DRIVER_SOURCES) \ @@ -667,6 +668,7 @@ STATEFUL_DRIVER_SOURCE_FILES = \ $(UML_DRIVER_SOURCES) \ $(XEN_DRIVER_SOURCES) \ $(VZ_DRIVER_SOURCES) \ + $(FS_DRIVER_SOURCES)\ $(NULL) @@ -1113,6 +1115,10 @@ XENCONFIG_SOURCES += \ xenconfig/xen_xl.c xenconfig/xen_xl.h endif WITH_LIBXL +FS_DRIVER_SOURCES = \ + fs/fs_driver.h fs/fs_driver.c \ + fs/fs_backend.h + pkgdata_DATA = cpu/cpu_map.xml EXTRA_DIST += $(pkgdata_DATA) @@ -1637,6 +1643,30 @@ endif WITH_DRIVER_MODULES libvirt_driver_secret_la_SOURCES = $(SECRET_DRIVER_SOURCES) endif WITH_SECRETS +libvirt_driver_fs_impl_la_SOURCES = +libvirt_driver_fs_impl_la_CFLAGS = \ + -I$(srcdir)/access \ + -I$(srcdir)/conf \ + $(AM_CFLAGS) +libvirt_driver_fs_impl_la_LDFLAGS = $(AM_LDFLAGS) +libvirt_driver_fs_impl_la_LIBADD = +libvirt_driver_fs_impl_la_LIBADD += $(SECDRIVER_LIBS) $(LIBXML_LIBS) +if WITH_FS +noinst_LTLIBRARIES += libvirt_driver_fs_impl.la +libvirt_driver_fs_la_SOURCES = +libvirt_driver_fs_la_LIBADD = libvirt_driver_fs_impl.la +if WITH_DRIVER_MODULES +mod_LTLIBRARIES += libvirt_driver_fs.la +libvirt_driver_fs_la_LIBADD += ../gnulib/lib/libgnu.la +libvirt_driver_fs_la_LDFLAGS = -module -avoid-version $(AM_LDFLAGS) +else ! WITH_DRIVER_MODULES +noinst_LTLIBRARIES += libvirt_driver_fs.la +# Stateful, so linked to daemon instead +#libvirt_la_BUILT_LIBADD += libvirt_driver_fs.la +endif ! WITH_DRIVER_MODULES +libvirt_driver_fs_impl_la_SOURCES += $(FS_DRIVER_SOURCES) +endif WITH_FS + # Needed to keep automake quiet about conditionals libvirt_driver_storage_impl_la_SOURCES = libvirt_driver_storage_impl_la_CFLAGS = \ @@ -1908,6 +1938,7 @@ EXTRA_DIST += \ $(BHYVE_DRIVER_SOURCES) \ $(NETWORK_DRIVER_SOURCES) \ $(INTERFACE_DRIVER_SOURCES) \ + $(FS_DRIVER_SOURCES) \ $(STORAGE_DRIVER_SOURCES) \ $(STORAGE_DRIVER_FS_SOURCES) \ $(STORAGE_DRIVER_LVM_SOURCES) \ diff --git a/src/fs/fs_backend.h b/src/fs/fs_backend.h new file mode 100644 index 0000000..67ea30c --- /dev/null +++ b/src/fs/fs_backend.h @@ -0,0 +1,94 @@ +/* + * fs_backend.h: file system backend implementation + * Author: Olga Krishtal <okrishtal@virtuozzo.com> + * + * Copyright (C) 2016 Parallels IP Holdings GmbH + * + * 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_FS_BACKEND_H__ +# define __VIR_FS_BACKEND_H__ + +# include <sys/stat.h> + +# include "internal.h" +# include "fs_conf.h" +# include "fs_driver.h" + +typedef char * (*virFSBackendFindFSpoolSources)(virConnectPtr conn, + const char *srcSpec, + unsigned int flags); +typedef int (*virFSBackendCheckFSpool)(virFSPoolObjPtr fspool, + bool *active); +typedef int (*virFSBackendStartFSpool)(virConnectPtr conn, + virFSPoolObjPtr fspool); +typedef int (*virFSBackendBuildFSpool)(virConnectPtr conn, + virFSPoolObjPtr fspool, + unsigned int flags); +typedef int (*virFSBackendRefreshFSpool)(virConnectPtr conn, + virFSPoolObjPtr fspool); +typedef int (*virFSBackendStopFSpool)(virConnectPtr conn, + virFSPoolObjPtr fspool); +typedef int (*virFSBackendDeleteFSpool)(virConnectPtr conn, + virFSPoolObjPtr fspool, + unsigned int flags); +typedef int (*virFSBackendBuildItem)(virConnectPtr conn, + virFSPoolObjPtr fspool, + virFSItemDefPtr item, + unsigned int flags); +typedef int (*virFSBackendCreateItem)(virConnectPtr conn, + virFSPoolObjPtr fspool, + virFSItemDefPtr item); +typedef int (*virFSBackendRefreshItem)(virConnectPtr conn, + virFSPoolObjPtr fspool, + virFSItemDefPtr item); +typedef int (*virFSBackendDeleteItem)(virConnectPtr conn, + virFSPoolObjPtr fspool, + virFSItemDefPtr item, + unsigned int flags); +typedef int (*virFSBackendBuildItemFrom)(virConnectPtr conn, + virFSPoolObjPtr fspool, + virFSItemDefPtr origitem, + virFSItemDefPtr newitem, + unsigned int flags); + +typedef struct _virFSBackend virFSBackend; +typedef virFSBackend *virFSBackendPtr; + +/* Callbacks are optional unless documented otherwise; but adding more + * callbacks provides better fspool support. */ +struct _virFSBackend { + int type; + + virFSBackendBuildFSpool buildFSpool; + virFSBackendCheckFSpool checkFSpool; + virFSBackendStartFSpool startFSpool; + virFSBackendRefreshFSpool refreshFSpool; /* Must be non-NULL */ + virFSBackendStopFSpool stopFSpool; + virFSBackendDeleteFSpool deleteFSpool; + + virFSBackendBuildItem buildItem; + virFSBackendBuildItemFrom buildItemFrom; + virFSBackendCreateItem createItem; + virFSBackendRefreshItem refreshItem; + virFSBackendDeleteItem deleteItem; +}; + +# define VIR_FS_DEFAULT_POOL_PERM_MODE 0755 +# define VIR_FS_DEFAULT_ITEM_PERM_MODE 0600 + +#endif /* __VIR_FS_BACKEND_H__ */ diff --git a/src/fs/fs_driver.c b/src/fs/fs_driver.c new file mode 100644 index 0000000..98d91fa --- /dev/null +++ b/src/fs/fs_driver.c @@ -0,0 +1,729 @@ +/* + * fs_driver.c: file system driver implementation + * Author: Olga Krishtal <okrishtal@virtuozzo.com> + * + * Copyright (C) 2016 Parallels IP Holdings GmbH + * + * 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/>. + */ + +#include <config.h> + +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <fcntl.h> + +#include <errno.h> +#include <string.h> + +#include "virerror.h" +#include "datatypes.h" +#include "driver.h" +#include "fs_driver.h" +#include "fs_conf.h" +#include "fs_backend.h" +#include "viralloc.h" +#include "virlog.h" +#include "virfile.h" +#include "virstoragefile.h" +#include "virpoolcommon.h" +#include "fdstream.h" +#include "configmake.h" +#include "virstring.h" +#include "viraccessapicheck.h" +#include "dirname.h" + +#define VIR_FROM_THIS VIR_FROM_FSPOOL +VIR_LOG_INIT("fs.fs_driver"); + +static virFSDriverStatePtr driver; + +static int fsStateCleanup(void); + +static void fsDriverLock(void) +{ + virMutexLock(&driver->lock); +} + +static void fsDriverUnlock(void) +{ + virMutexUnlock(&driver->lock); +} + +static virFSBackendPtr backends[] = {}; + +static virFSBackendPtr +virFSBackendForType(int type) +{ + size_t i; + for (i = 0; backends[i]; i++) + if (backends[i]->type == type) + return backends[i]; + + virReportError(VIR_ERR_INTERNAL_ERROR, + _("missing backend for fspool type %d (%s)"), + type, NULLSTR(virFSPoolTypeToString(type))); + return NULL; +} + +/* General fspool/item implementation */ +static int +fsConnectListAllFSPools(virConnectPtr conn ATTRIBUTE_UNUSED, + virFSPoolPtr **fspools ATTRIBUTE_UNUSED, + unsigned int flags) +{ + virCheckFlags(0, -1); + + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return -1; +} + +static virFSPoolPtr +fsPoolLookupByName(virConnectPtr conn ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return NULL; +} + +static virFSPoolPtr +fsPoolLookupByUUID(virConnectPtr conn ATTRIBUTE_UNUSED, + const unsigned char *uuid ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return NULL; +} + +static virFSPoolPtr +fsPoolLookupByItem(virFSItemPtr item ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return NULL; +} + +static virFSPoolPtr +fsPoolCreateXML(virConnectPtr conn ATTRIBUTE_UNUSED, + const char *xml ATTRIBUTE_UNUSED, + unsigned int flags) +{ + virCheckFlags(0, NULL); + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return NULL; +} + +static virFSPoolPtr +fsPoolDefineXML(virConnectPtr conn ATTRIBUTE_UNUSED, + const char *xml ATTRIBUTE_UNUSED, + unsigned int flags) +{ + virCheckFlags(0, NULL); + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return NULL; +} + +static int +fsPoolCreate(virFSPoolPtr obj ATTRIBUTE_UNUSED, + unsigned int flags) +{ + virCheckFlags(0, -1); + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return -1; +} + +static int +fsPoolBuild(virFSPoolPtr obj ATTRIBUTE_UNUSED, + unsigned int flags) +{ + virCheckFlags(0, -1); + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return -1; +} + +static int +fsPoolUndefine(virFSPoolPtr obj ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return -1; +} + +static int +fsPoolDestroy(virFSPoolPtr obj ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return -1; +} + +static int +fsPoolDelete(virFSPoolPtr obj ATTRIBUTE_UNUSED, + unsigned int flags) +{ + virCheckFlags(0, -1); + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return -1; +} + +static int +fsPoolRefresh(virFSPoolPtr obj ATTRIBUTE_UNUSED, + unsigned int flags) +{ + virCheckFlags(0, -1); + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return -1; +} + +static int +fsPoolGetInfo(virFSPoolPtr obj ATTRIBUTE_UNUSED, + virFSPoolInfoPtr info ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return -1; +} + +static char * +fsPoolGetXMLDesc(virFSPoolPtr obj ATTRIBUTE_UNUSED, + unsigned int flags) +{ + virCheckFlags(0, NULL); + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return NULL; +} + +static int +fsPoolGetAutostart(virFSPoolPtr obj ATTRIBUTE_UNUSED, int *autostart ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return -1; +} + +static int +fsPoolSetAutostart(virFSPoolPtr obj ATTRIBUTE_UNUSED, int autostart ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return -1; +} + +static int +fsPoolNumOfItems(virFSPoolPtr obj ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return -1; +} + +static int +fsPoolListItems(virFSPoolPtr obj ATTRIBUTE_UNUSED, + char **const names ATTRIBUTE_UNUSED, + int maxnames ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return -1; +} + +static int +fsPoolListAllItems(virFSPoolPtr fspool ATTRIBUTE_UNUSED, + virFSItemPtr **items ATTRIBUTE_UNUSED, + unsigned int flags) +{ + virCheckFlags(0, -1); + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return -1; +} + +static virFSItemPtr +fsItemLookupByName(virFSPoolPtr obj ATTRIBUTE_UNUSED, const char *name ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return NULL; +} + +static virFSItemPtr +fsItemLookupByKey(virConnectPtr conn ATTRIBUTE_UNUSED, const char *key ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return NULL; +} + +static virFSItemPtr +fsItemLookupByPath(virConnectPtr conn ATTRIBUTE_UNUSED, + const char *path ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return NULL; +} + +static virFSItemPtr +fsItemCreateXML(virFSPoolPtr obj ATTRIBUTE_UNUSED, + const char *xmldesc ATTRIBUTE_UNUSED, + unsigned int flags) +{ + virCheckFlags(0, NULL); + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return NULL; +} + +static virFSItemPtr +fsItemCreateXMLFrom(virFSPoolPtr obj ATTRIBUTE_UNUSED, + const char *xmldesc ATTRIBUTE_UNUSED, + virFSItemPtr vobj ATTRIBUTE_UNUSED, + unsigned int flags) +{ + virCheckFlags(0, NULL); + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return NULL; +} + +static int +fsItemGetInfo(virFSItemPtr obj ATTRIBUTE_UNUSED, + virFSItemInfoPtr info ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return -1; +} + +static char * +fsItemGetXMLDesc(virFSItemPtr obj ATTRIBUTE_UNUSED, unsigned int flags) +{ + virCheckFlags(0, NULL); + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return NULL; +} + +static char * +fsItemGetPath(virFSItemPtr obj ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return NULL; +} + +static int +fsPoolIsActive(virFSPoolPtr fspool ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return -1; +} + +static int +fsPoolIsPersistent(virFSPoolPtr fspool ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return -1; +} + +static int +fsItemDelete(virFSItemPtr obj ATTRIBUTE_UNUSED, + unsigned int flags) +{ + virCheckFlags(0, -1); + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("the operation is not yet supported")); + + return -1; +} + +static virFSDriver fsDriver = { + .name = "fs", + .connectListAllFSPools = fsConnectListAllFSPools, /* 2.3.0 */ + .fsPoolLookupByName = fsPoolLookupByName, /* 2.3.0 */ + .fsPoolLookupByUUID = fsPoolLookupByUUID, /* 2.3.0 */ + .fsPoolLookupByItem = fsPoolLookupByItem, /* 2.3.0 */ + .fsPoolCreateXML = fsPoolCreateXML, /* 2.3.0 */ + .fsPoolDefineXML = fsPoolDefineXML, /* 2.3.0 */ + .fsPoolBuild = fsPoolBuild, /* 2.3.0 */ + .fsPoolCreate = fsPoolCreate, /* 2.3.0 */ + .fsPoolUndefine = fsPoolUndefine, /* 2.3.0 */ + .fsPoolDestroy = fsPoolDestroy, /* 2.3.0 */ + .fsPoolDelete = fsPoolDelete, /* 2.3.0 */ + .fsPoolRefresh = fsPoolRefresh, /* 2.3.0 */ + .fsPoolGetInfo = fsPoolGetInfo, /* 2.3.0 */ + .fsPoolGetXMLDesc = fsPoolGetXMLDesc, /* 2.3.0 */ + .fsPoolGetAutostart = fsPoolGetAutostart, /* 2.3.0 */ + .fsPoolSetAutostart = fsPoolSetAutostart, /* 2.3.0 */ + .fsPoolNumOfItems = fsPoolNumOfItems, /* 2.3.0 */ + .fsPoolListItems = fsPoolListItems, /* 2.3.0 */ + .fsPoolListAllItems = fsPoolListAllItems, /* 2.3.0 */ + .fsItemLookupByName = fsItemLookupByName, /* 2.3.0 */ + .fsItemLookupByKey = fsItemLookupByKey, /* 2.3.0 */ + .fsItemLookupByPath = fsItemLookupByPath, /* 2.3.0 */ + .fsItemCreateXML = fsItemCreateXML, /* 2.3.0 */ + .fsItemCreateXMLFrom = fsItemCreateXMLFrom, /* 2.3.0 */ + .fsItemDelete = fsItemDelete, /* 2.3.0 */ + .fsItemGetInfo = fsItemGetInfo, /* 2.3.0 */ + .fsItemGetXMLDesc = fsItemGetXMLDesc, /* 2.3.0 */ + .fsItemGetPath = fsItemGetPath, /* 2.3.0 */ + .fsPoolIsActive = fsPoolIsActive, /* 2.3.0 */ + .fsPoolIsPersistent = fsPoolIsPersistent, /* 2.3.0 */ +}; + + +static void +fsPoolUpdateState(virFSPoolObjPtr fspool) +{ + bool active; + virFSBackendPtr backend; + int ret = -1; + char *stateFile; + + if (!(stateFile = virFileBuildPath(driver->stateDir, + fspool->def->name, ".xml"))) + goto error; + + if ((backend = virFSBackendForType(fspool->def->type)) == NULL) { + VIR_ERROR(_("Missing backend %d"), fspool->def->type); + goto error; + } + + /* Backends which do not support 'checkFSpool' are considered + * inactive by default. + */ + active = false; + if (backend->checkFSpool && + backend->checkFSpool(fspool, &active) < 0) { + virErrorPtr err = virGetLastError(); + VIR_ERROR(_("Failed to initialize fspool '%s': %s"), + fspool->def->name, err ? err->message : + _("no error message found")); + goto error; + } + + /* We can pass NULL as connection, most backends do not use + * it anyway, but if they do and fail, we want to log error and + * continue with other fspools. + */ + if (active) { + virFSPoolObjClearItems(fspool); + if (backend->refreshFSpool(NULL, fspool) < 0) { + virErrorPtr err = virGetLastError(); + if (backend->stopFSpool) + backend->stopFSpool(NULL, fspool); + VIR_ERROR(_("Failed to restart fspool '%s': %s"), + fspool->def->name, err ? err->message : + _("no error message found")); + goto error; + } + } + + fspool->active = active; + ret = 0; + error: + if (ret < 0) { + if (stateFile) + unlink(stateFile); + } + VIR_FREE(stateFile); + + return; +} + +static void +fsPoolUpdateAllState(void) +{ + size_t i; + + for (i = 0; i < driver->fspools.count; i++) { + virFSPoolObjPtr fspool = driver->fspools.objs[i]; + + virFSPoolObjLock(fspool); + fsPoolUpdateState(fspool); + virFSPoolObjUnlock(fspool); + } +} + +static void +fsDriverAutostart(void) +{ + size_t i; + virConnectPtr conn = NULL; + + /* XXX Remove hardcoding of QEMU URI */ + if (driver->privileged) + conn = virConnectOpen("qemu:///system"); + else + conn = virConnectOpen("qemu:///session"); + /* Ignoring NULL conn - let backends decide */ + + for (i = 0; i < driver->fspools.count; i++) { + virFSPoolObjPtr fspool = driver->fspools.objs[i]; + virFSBackendPtr backend; + bool started = false; + + virFSPoolObjLock(fspool); + if ((backend = virFSBackendForType(fspool->def->type)) == NULL) { + virFSPoolObjUnlock(fspool); + continue; + } + + if (fspool->autostart && + !virFSPoolObjIsActive(fspool)) { + if (backend->startFSpool && + backend->startFSpool(conn, fspool) < 0) { + virErrorPtr err = virGetLastError(); + VIR_ERROR(_("Failed to autostart fspool '%s': %s"), + fspool->def->name, err ? err->message : + _("no error message found")); + virFSPoolObjUnlock(fspool); + continue; + } + started = true; + } + + if (started) { + char *stateFile; + + virFSPoolObjClearItems(fspool); + stateFile = virFileBuildPath(driver->stateDir, + fspool->def->name, ".xml"); + if (!stateFile || + virFSPoolSaveState(stateFile, fspool->def) < 0 || + backend->refreshFSpool(conn, fspool) < 0) { + virErrorPtr err = virGetLastError(); + if (stateFile) + unlink(stateFile); + if (backend->stopFSpool) + backend->stopFSpool(conn, fspool); + VIR_ERROR(_("Failed to autostart fspool '%s': %s"), + fspool->def->name, err ? err->message : + _("no error message found")); + } else { + fspool->active = true; + } + VIR_FREE(stateFile); + } + virFSPoolObjUnlock(fspool); + } + + virObjectUnref(conn); +} + +/** + * virFSStartup: + * + * Initialization function for the FS Driver + */ +static int +fsStateInitialize(bool privileged, + virStateInhibitCallback callback ATTRIBUTE_UNUSED, + void *opaque ATTRIBUTE_UNUSED) +{ + int ret = -1; + char *configdir = NULL; + char *rundir = NULL; + + if (VIR_ALLOC(driver) < 0) + return ret; + + if (virMutexInit(&driver->lock) < 0) { + VIR_FREE(driver); + return ret; + } + fsDriverLock(); + + if (privileged) { + if (VIR_STRDUP(driver->configDir, + SYSCONFDIR "/libvirt/fs") < 0 || + VIR_STRDUP(driver->autostartDir, + SYSCONFDIR "/libvirt/fs/autostart") < 0 || + VIR_STRDUP(driver->stateDir, + LOCALSTATEDIR "/run/libvirt/fs") < 0) + goto error; + } else { + configdir = virGetUserConfigDirectory(); + rundir = virGetUserRuntimeDirectory(); + if (!(configdir && rundir)) + goto error; + + if ((virAsprintf(&driver->configDir, + "%s/fs", configdir) < 0) || + (virAsprintf(&driver->autostartDir, + "%s/fs/autostart", configdir) < 0) || + (virAsprintf(&driver->stateDir, + "%s/fs/run", rundir) < 0)) + goto error; + } + driver->privileged = privileged; + + if (virFileMakePath(driver->stateDir) < 0) { + virReportError(errno, + _("cannot create directory %s"), + driver->stateDir); + goto error; + } + + if (virFSPoolLoadAllState(&driver->fspools, + driver->stateDir) < 0) + goto error; + + if (virFSPoolLoadAllConfigs(&driver->fspools, + driver->configDir, + driver->autostartDir) < 0) + goto error; + + fsPoolUpdateAllState(); + fsDriverUnlock(); + + ret = 0; + cleanup: + VIR_FREE(configdir); + VIR_FREE(rundir); + return ret; + + error: + fsDriverUnlock(); + fsStateCleanup(); + goto cleanup; +} + +/** + * fsStateAutoStart: + * + * Function to auto start the fs_driver + * At the moment it doing nothing + */ +static void +fsStateAutoStart(void) +{ + if (!driver) + return; + + fsDriverLock(); + fsDriverAutostart(); + fsDriverUnlock(); +} + +/** + * fsStateReload: + * + * Function to restart the fs_driver, it will recheck the configuration + * files and update its state + */ +static int +fsStateReload(void) +{ + if (!driver) + return -1; + + fsDriverLock(); + virFSPoolLoadAllState(&driver->fspools, + driver->stateDir); + virFSPoolLoadAllConfigs(&driver->fspools, + driver->configDir, + driver->autostartDir); + fsDriverAutostart(); + fsDriverUnlock(); + + return 0; +} + +/** + * fsStateCleanup + * + * Shutdown the fs driver, it will stop all active fspools + */ +static int +fsStateCleanup(void) +{ + if (!driver) + return -1; + + fsDriverLock(); + + /* free inactive fspools */ + virFSPoolObjListFree(&driver->fspools); + + VIR_FREE(driver->configDir); + VIR_FREE(driver->autostartDir); + VIR_FREE(driver->stateDir); + fsDriverUnlock(); + virMutexDestroy(&driver->lock); + VIR_FREE(driver); + + return 0; +} + +static virStateDriver stateDriver = { + .name = "fs", + .stateInitialize = fsStateInitialize, + .stateAutoStart = fsStateAutoStart, + .stateCleanup = fsStateCleanup, + .stateReload = fsStateReload, +}; + +int fsRegister(void) +{ + if (virSetSharedFSDriver(&fsDriver) < 0) + return -1; + if (virRegisterStateDriver(&stateDriver) < 0) + return -1; + return 0; +} diff --git a/src/fs/fs_driver.h b/src/fs/fs_driver.h new file mode 100644 index 0000000..aaf0258 --- /dev/null +++ b/src/fs/fs_driver.h @@ -0,0 +1,10 @@ +#ifndef __VIR_FS_DRIVER_H__ +# define __VIR_FS_DRIVER_H__ + +# include <sys/stat.h> + +# include "domain_conf.h" +# include "fs_conf.h" + +int fsRegister(void); +#endif /* __VIR_FS_DRIVER_H__ */ -- 1.8.3.1

Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- src/fs/fs_driver.c | 1723 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 1515 insertions(+), 208 deletions(-) diff --git a/src/fs/fs_driver.c b/src/fs/fs_driver.c index 98d91fa..f913ce5 100644 --- a/src/fs/fs_driver.c +++ b/src/fs/fs_driver.c @@ -82,314 +82,1621 @@ virFSBackendForType(int type) } /* General fspool/item implementation */ + static int -fsConnectListAllFSPools(virConnectPtr conn ATTRIBUTE_UNUSED, - virFSPoolPtr **fspools ATTRIBUTE_UNUSED, +fsConnectListAllFSPools(virConnectPtr conn, + virFSPoolPtr **fspools, unsigned int flags) { - virCheckFlags(0, -1); + int ret = -1; - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + virCheckFlags(VIR_CONNECT_LIST_FSPOOLS_FILTERS_ALL, -1); + + if (virConnectListAllFSPoolsEnsureACL(conn) < 0) + goto cleanup; + + fsDriverLock(); + ret = virFSPoolObjListExport(conn, driver->fspools, fspools, + virConnectListAllFSPoolsCheckACL, + flags); + fsDriverUnlock(); + + cleanup: + return ret; - return -1; } static virFSPoolPtr -fsPoolLookupByName(virConnectPtr conn ATTRIBUTE_UNUSED, - const char *name ATTRIBUTE_UNUSED) +fsPoolLookupByName(virConnectPtr conn, + const char *name) { - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + virFSPoolObjPtr fspool; + virFSPoolPtr ret = NULL; - return NULL; + fsDriverLock(); + fspool = virFSPoolObjFindByName(&driver->fspools, name); + fsDriverUnlock(); + + if (!fspool) { + virReportError(VIR_ERR_NO_FSPOOL, + _("no fspool with matching name '%s'"), name); + return NULL; + } + + if (virFSPoolLookupByNameEnsureACL(conn, fspool->def) < 0) + goto cleanup; + + ret = virGetFSPool(conn, fspool->def->name, fspool->def->uuid, + NULL, NULL); + + cleanup: + virFSPoolObjUnlock(fspool); + return ret; } static virFSPoolPtr -fsPoolLookupByUUID(virConnectPtr conn ATTRIBUTE_UNUSED, - const unsigned char *uuid ATTRIBUTE_UNUSED) +fsPoolLookupByUUID(virConnectPtr conn, + const unsigned char *uuid) { - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + virFSPoolObjPtr fspool; + virFSPoolPtr ret = NULL; - return NULL; + fsDriverLock(); + fspool = virFSPoolObjFindByUUID(&driver->fspools, uuid); + fsDriverUnlock(); + + if (!fspool) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(uuid, uuidstr); + virReportError(VIR_ERR_NO_FSPOOL, + _("no fspool with matching uuid '%s'"), uuidstr); + return NULL; + } + + if (virFSPoolLookupByUUIDEnsureACL(conn, fspool->def) < 0) + goto cleanup; + + ret = virGetFSPool(conn, fspool->def->name, fspool->def->uuid, + NULL, NULL); + + cleanup: + virFSPoolObjUnlock(fspool); + return ret; } static virFSPoolPtr -fsPoolLookupByItem(virFSItemPtr item ATTRIBUTE_UNUSED) +fsPoolLookupByItem(virFSItemPtr item) { - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + virFSPoolObjPtr fspool; + virFSPoolPtr ret = NULL; - return NULL; + fsDriverLock(); + fspool = virFSPoolObjFindByName(&driver->fspools, item->pool); + fsDriverUnlock(); + + if (!fspool) { + virReportError(VIR_ERR_NO_FSPOOL, + _("no fspool with matching name '%s'"), + item->pool); + return NULL; + } + + if (virFSPoolLookupByItemEnsureACL(item->conn, fspool->def) < 0) + goto cleanup; + + ret = virGetFSPool(item->conn, fspool->def->name, fspool->def->uuid, + NULL, NULL); + + cleanup: + virFSPoolObjUnlock(fspool); + return ret; } static virFSPoolPtr -fsPoolCreateXML(virConnectPtr conn ATTRIBUTE_UNUSED, - const char *xml ATTRIBUTE_UNUSED, +fsPoolCreateXML(virConnectPtr conn, + const char *xml, unsigned int flags) { - virCheckFlags(0, NULL); - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + virFSPoolDefPtr def; + virFSPoolObjPtr fspool = NULL; + virFSPoolPtr ret = NULL; + virFSBackendPtr backend; + char *stateFile = NULL; + unsigned int build_flags = 0; - return NULL; + virCheckFlags(VIR_FSPOOL_CREATE_WITH_BUILD_OVERWRITE | + VIR_FSPOOL_CREATE_WITH_BUILD_NO_OVERWRITE, NULL); + + VIR_EXCLUSIVE_FLAGS_RET(VIR_FSPOOL_BUILD_OVERWRITE, + VIR_FSPOOL_BUILD_NO_OVERWRITE, NULL); + + fsDriverLock(); + if (!(def = virFSPoolDefParseString(xml))) + goto cleanup; + + if (virFSPoolCreateXMLEnsureACL(conn, def) < 0) + goto cleanup; + + if (virFSPoolObjIsDuplicate(&driver->fspools, def, 1) < 0) + goto cleanup; + + if (virFSPoolSourceFindDuplicate(conn, &driver->fspools, def) < 0) + goto cleanup; + + if ((backend = virFSBackendForType(def->type)) == NULL) + goto cleanup; + + if (!(fspool = virFSPoolObjAssignDef(&driver->fspools, def))) + goto cleanup; + def = NULL; + + if (backend->buildFSpool) { + if (flags & VIR_FSPOOL_CREATE_WITH_BUILD_OVERWRITE) + build_flags |= VIR_FSPOOL_BUILD_OVERWRITE; + else if (flags & VIR_FSPOOL_CREATE_WITH_BUILD_NO_OVERWRITE) + build_flags |= VIR_FSPOOL_BUILD_NO_OVERWRITE; + + if (backend->buildFSpool(conn, fspool, build_flags) < 0) { + virFSPoolObjRemove(&driver->fspools, fspool); + fspool = NULL; + goto cleanup; + } + } + + if (backend->startFSpool && + backend->startFSpool(conn, fspool) < 0) { + virFSPoolObjRemove(&driver->fspools, fspool); + fspool = NULL; + goto cleanup; + } + + stateFile = virFileBuildPath(driver->stateDir, + fspool->def->name, ".xml"); + + if (!stateFile || virFSPoolSaveState(stateFile, fspool->def) < 0 || + backend->refreshFSpool(conn, fspool) < 0) { + if (stateFile) + unlink(stateFile); + if (backend->stopFSpool) + backend->stopFSpool(conn, fspool); + virFSPoolObjRemove(&driver->fspools, fspool); + fspool = NULL; + goto cleanup; + } + VIR_INFO("Creating fspool '%s'", fspool->def->name); + fspool->active = true; + + ret = virGetFSPool(conn, fspool->def->name, fspool->def->uuid, + NULL, NULL); + + cleanup: + VIR_FREE(stateFile); + virStoragePoolDefFree(def); + if (fspool) + virFSPoolObjUnlock(fspool); + fsDriverUnlock(); + return ret; } static virFSPoolPtr -fsPoolDefineXML(virConnectPtr conn ATTRIBUTE_UNUSED, - const char *xml ATTRIBUTE_UNUSED, +fsPoolDefineXML(virConnectPtr conn, + const char *xml, unsigned int flags) { + virFSPoolDefPtr def; + virFSPoolObjPtr fspool = NULL; + virFSPoolPtr ret = NULL; + virCheckFlags(0, NULL); - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); - return NULL; -} + fsDriverLock(); + if (!(def = virFSPoolDefParseString(xml))) + goto cleanup; -static int -fsPoolCreate(virFSPoolPtr obj ATTRIBUTE_UNUSED, - unsigned int flags) -{ - virCheckFlags(0, -1); - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + if (virFSPoolDefineXMLEnsureACL(conn, def) < 0) + goto cleanup; - return -1; -} + if (virFSPoolObjIsDuplicate(&driver->fspools, def, 0) < 0) + goto cleanup; -static int -fsPoolBuild(virFSPoolPtr obj ATTRIBUTE_UNUSED, - unsigned int flags) -{ - virCheckFlags(0, -1); - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + if (virFSPoolSourceFindDuplicate(conn, &driver->fspools, def) < 0) + goto cleanup; - return -1; -} + if (virFSBackendForType(def->type) == NULL) + goto cleanup; -static int -fsPoolUndefine(virFSPoolPtr obj ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + if (!(fspool = virFSPoolObjAssignDef(&driver->fspools, def))) + goto cleanup; - return -1; -} + if (virFSPoolObjSaveDef(driver, fspool, def) < 0) { + virFSPoolObjRemove(&driver->fspools, fspool); + def = NULL; + fspool = NULL; + goto cleanup; + } + def = NULL; -static int -fsPoolDestroy(virFSPoolPtr obj ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + VIR_INFO("Defining fspool '%s'", fspool->def->name); + ret = virGetFSPool(conn, fspool->def->name, fspool->def->uuid, + NULL, NULL); - return -1; + cleanup: + + virStoragePoolDefFree(def); + if (fspool) + virFSPoolObjUnlock(fspool); + fsDriverUnlock(); + return ret; } -static int -fsPoolDelete(virFSPoolPtr obj ATTRIBUTE_UNUSED, - unsigned int flags) +static virFSPoolObjPtr +virFSPoolObjFromFSPool(virFSPoolPtr fspool) { - virCheckFlags(0, -1); - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virFSPoolObjPtr ret; - return -1; + fsDriverLock(); + if (!(ret = virFSPoolObjFindByUUID(&driver->fspools, fspool->uuid))) { + virUUIDFormat(fspool->uuid, uuidstr); + virReportError(VIR_ERR_NO_FSPOOL, + _("no fspool with matching uuid '%s' (%s)"), + uuidstr, fspool->name); + } + fsDriverUnlock(); + + return ret; } static int -fsPoolRefresh(virFSPoolPtr obj ATTRIBUTE_UNUSED, - unsigned int flags) +fsPoolCreate(virFSPoolPtr obj, + unsigned int flags) { - virCheckFlags(0, -1); - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + virFSPoolObjPtr fspool; + virFSBackendPtr backend; + int ret = -1; + char *stateFile = NULL; + unsigned int build_flags = 0; - return -1; -} + virCheckFlags(VIR_FSPOOL_CREATE_WITH_BUILD_OVERWRITE | + VIR_FSPOOL_CREATE_WITH_BUILD_NO_OVERWRITE, -1); -static int -fsPoolGetInfo(virFSPoolPtr obj ATTRIBUTE_UNUSED, - virFSPoolInfoPtr info ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + VIR_EXCLUSIVE_FLAGS_RET(VIR_FSPOOL_BUILD_OVERWRITE, + VIR_FSPOOL_BUILD_NO_OVERWRITE, -1); - return -1; -} + if (!(fspool = virFSPoolObjFromFSPool(obj))) + return -1; -static char * -fsPoolGetXMLDesc(virFSPoolPtr obj ATTRIBUTE_UNUSED, - unsigned int flags) -{ - virCheckFlags(0, NULL); - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + if (virFSPoolCreateEnsureACL(obj->conn, fspool->def) < 0) + goto cleanup; - return NULL; -} + if ((backend = virFSBackendForType(fspool->def->type)) == NULL) + goto cleanup; -static int -fsPoolGetAutostart(virFSPoolPtr obj ATTRIBUTE_UNUSED, int *autostart ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + if (virFSPoolObjIsActive(fspool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("fspool '%s' is already active"), + fspool->def->name); + goto cleanup; + } - return -1; -} + if (backend->buildFSpool) { + if (flags & VIR_FSPOOL_CREATE_WITH_BUILD_OVERWRITE) + build_flags |= VIR_FSPOOL_BUILD_OVERWRITE; + else if (flags & VIR_FSPOOL_CREATE_WITH_BUILD_NO_OVERWRITE) + build_flags |= VIR_FSPOOL_BUILD_NO_OVERWRITE; -static int -fsPoolSetAutostart(virFSPoolPtr obj ATTRIBUTE_UNUSED, int autostart ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + if (backend->buildFSpool(obj->conn, fspool, build_flags) < 0) { + virFSPoolObjRemove(&driver->fspools, fspool); + fspool = NULL; + goto cleanup; + } + } - return -1; -} + VIR_INFO("Starting up fspool '%s'", fspool->def->name); + if (backend->startFSpool && + backend->startFSpool(obj->conn, fspool) < 0) + goto cleanup; -static int -fsPoolNumOfItems(virFSPoolPtr obj ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + stateFile = virFileBuildPath(driver->stateDir, + fspool->def->name, ".xml"); - return -1; -} + virFSPoolObjClearItems(fspool); + if (!stateFile || virFSPoolSaveState(stateFile, fspool->def) < 0 || + backend->refreshFSpool(obj->conn, fspool) < 0) { + if (stateFile) + unlink(stateFile); + goto cleanup; + } -static int -fsPoolListItems(virFSPoolPtr obj ATTRIBUTE_UNUSED, - char **const names ATTRIBUTE_UNUSED, - int maxnames ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + fspool->active = true; + ret = 0; + + cleanup: + VIR_FREE(stateFile); + if (fspool) + virFSPoolObjUnlock(fspool); + return ret; - return -1; } static int -fsPoolListAllItems(virFSPoolPtr fspool ATTRIBUTE_UNUSED, - virFSItemPtr **items ATTRIBUTE_UNUSED, - unsigned int flags) +fsPoolBuild(virFSPoolPtr obj, + unsigned int flags) { + virFSPoolObjPtr fspool; + virFSBackendPtr backend; + int ret = -1; + virCheckFlags(0, -1); - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); - return -1; -} + if (!(fspool = virFSPoolObjFromFSPool(obj))) + return -1; -static virFSItemPtr -fsItemLookupByName(virFSPoolPtr obj ATTRIBUTE_UNUSED, const char *name ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + if (virFSPoolBuildEnsureACL(obj->conn, fspool->def) < 0) + goto cleanup; - return NULL; -} + if ((backend = virFSBackendForType(fspool->def->type)) == NULL) + goto cleanup; -static virFSItemPtr -fsItemLookupByKey(virConnectPtr conn ATTRIBUTE_UNUSED, const char *key ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + if (virFSPoolObjIsActive(fspool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("fspool '%s' is already active"), + fspool->def->name); + goto cleanup; + } - return NULL; -} + if (backend->buildFSpool && + backend->buildFSpool(obj->conn, fspool, flags) < 0) + goto cleanup; -static virFSItemPtr -fsItemLookupByPath(virConnectPtr conn ATTRIBUTE_UNUSED, - const char *path ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + ret = 0; + + cleanup: + virFSPoolObjUnlock(fspool); + return ret; - return NULL; } -static virFSItemPtr -fsItemCreateXML(virFSPoolPtr obj ATTRIBUTE_UNUSED, - const char *xmldesc ATTRIBUTE_UNUSED, - unsigned int flags) +static int +fsPoolUndefine(virFSPoolPtr obj) { - virCheckFlags(0, NULL); - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + virFSPoolObjPtr fspool; + int ret = -1; - return NULL; -} + fsDriverLock(); + if (!(fspool = virFSPoolObjFindByUUID(&driver->fspools, obj->uuid))) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(obj->uuid, uuidstr); + virReportError(VIR_ERR_NO_FSPOOL, + _("no fspool with matching uuid '%s' (%s)"), + uuidstr, obj->name); + goto cleanup; + } -static virFSItemPtr -fsItemCreateXMLFrom(virFSPoolPtr obj ATTRIBUTE_UNUSED, - const char *xmldesc ATTRIBUTE_UNUSED, - virFSItemPtr vobj ATTRIBUTE_UNUSED, - unsigned int flags) -{ - virCheckFlags(0, NULL); - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + if (virFSPoolUndefineEnsureACL(obj->conn, fspool->def) < 0) + goto cleanup; - return NULL; -} + if (virFSPoolObjIsActive(fspool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("fspool '%s' is still active"), + fspool->def->name); + goto cleanup; + } -static int -fsItemGetInfo(virFSItemPtr obj ATTRIBUTE_UNUSED, - virFSItemInfoPtr info ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + if (fspool->asyncjobs > 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("fspool '%s' has asynchronous jobs running."), + fspool->def->name); + goto cleanup; + } - return -1; -} + if (virFSPoolObjDeleteDef(fspool) < 0) + goto cleanup; -static char * -fsItemGetXMLDesc(virFSItemPtr obj ATTRIBUTE_UNUSED, unsigned int flags) -{ - virCheckFlags(0, NULL); - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + if (unlink(fspool->autostartLink) < 0 && + errno != ENOENT && + errno != ENOTDIR) { + char ebuf[1024]; + VIR_ERROR(_("Failed to delete autostart link '%s': %s"), + fspool->autostartLink, virStrerror(errno, ebuf, sizeof(ebuf))); + } - return NULL; -} + VIR_FREE(fspool->configFile); + VIR_FREE(fspool->autostartLink); -static char * -fsItemGetPath(virFSItemPtr obj ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + VIR_INFO("Undefining fspool '%s'", fspool->def->name); + virFSPoolObjRemove(&driver->fspools, fspool); + fspool = NULL; + ret = 0; + + cleanup: + if (fspool) + virFSPoolObjUnlock(fspool); + fsDriverUnlock(); + return ret; - return NULL; } static int -fsPoolIsActive(virFSPoolPtr fspool ATTRIBUTE_UNUSED) +fsPoolDestroy(virFSPoolPtr obj) { - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + virFSPoolObjPtr fspool; + virFSBackendPtr backend; + char *stateFile = NULL; + int ret = -1; - return -1; -} + fsDriverLock(); + if (!(fspool = virFSPoolObjFindByUUID(&driver->fspools, obj->uuid))) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(obj->uuid, uuidstr); + virReportError(VIR_ERR_NO_FSPOOL, + _("no fspool with matching uuid '%s' (%s)"), + uuidstr, obj->name); + goto cleanup; + } -static int -fsPoolIsPersistent(virFSPoolPtr fspool ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); + if (virFSPoolDestroyEnsureACL(obj->conn, fspool->def) < 0) + goto cleanup; - return -1; + if ((backend = virFSBackendForType(fspool->def->type)) == NULL) + goto cleanup; + + VIR_INFO("Destroying fspool '%s'", fspool->def->name); + + if (!virFSPoolObjIsActive(fspool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("fspool '%s' is not active"), fspool->def->name); + goto cleanup; + } + + if (fspool->asyncjobs > 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("fspool '%s' has asynchronous jobs running."), + fspool->def->name); + goto cleanup; + } + + if (!(stateFile = virFileBuildPath(driver->stateDir, + fspool->def->name, + ".xml"))) + goto cleanup; + + unlink(stateFile); + VIR_FREE(stateFile); + + if (backend->stopFSpool && + backend->stopFSpool(obj->conn, fspool) < 0) + goto cleanup; + + virFSPoolObjClearItems(fspool); + + fspool->active = false; + + if (fspool->configFile == NULL) { + virFSPoolObjRemove(&driver->fspools, fspool); + fspool = NULL; + } else if (fspool->newDef) { + virStoragePoolDefFree(fspool->def); + fspool->def = fspool->newDef; + fspool->newDef = NULL; + } + + ret = 0; + + cleanup: + if (fspool) + virFSPoolObjUnlock(fspool); + fsDriverUnlock(); + return ret; } static int -fsItemDelete(virFSItemPtr obj ATTRIBUTE_UNUSED, +fsPoolDelete(virFSPoolPtr obj, unsigned int flags) { + virFSPoolObjPtr fspool; + virFSBackendPtr backend; + char *stateFile = NULL; + int ret = -1; + virCheckFlags(0, -1); - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("the operation is not yet supported")); - return -1; + if (!(fspool = virFSPoolObjFromFSPool(obj))) + return -1; + + if (virFSPoolDeleteEnsureACL(obj->conn, fspool->def) < 0) + goto cleanup; + + if ((backend = virFSBackendForType(fspool->def->type)) == NULL) + goto cleanup; + + VIR_INFO("Deleting fspool '%s'", fspool->def->name); + + if (virFSPoolObjIsActive(fspool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("fspool '%s' is still active"), + fspool->def->name); + goto cleanup; + } + + if (fspool->asyncjobs > 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("fspool '%s' has asynchronous jobs running."), + fspool->def->name); + goto cleanup; + } + + if (!(stateFile = virFileBuildPath(driver->stateDir, + fspool->def->name, + ".xml"))) + goto cleanup; + + unlink(stateFile); + VIR_FREE(stateFile); + + if (!backend->deleteFSpool) { + virReportError(VIR_ERR_NO_SUPPORT, + "%s", _("fspool does not support fspool deletion")); + goto cleanup; + } + if (backend->deleteFSpool(obj->conn, fspool, flags) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virFSPoolObjUnlock(fspool); + return ret; +} + +static int +fsPoolRefresh(virFSPoolPtr obj, + unsigned int flags) +{ + virFSPoolObjPtr fspool; + virFSBackendPtr backend; + int ret = -1; + + virCheckFlags(0, -1); + + fsDriverLock(); + if (!(fspool = virFSPoolObjFindByUUID(&driver->fspools, obj->uuid))) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(obj->uuid, uuidstr); + virReportError(VIR_ERR_NO_FSPOOL, + _("no fspool with matching uuid '%s' (%s)"), + uuidstr, obj->name); + goto cleanup; + } + + if (virFSPoolRefreshEnsureACL(obj->conn, fspool->def) < 0) + goto cleanup; + + if ((backend = virFSBackendForType(fspool->def->type)) == NULL) + goto cleanup; + + if (!virFSPoolObjIsActive(fspool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("fspool '%s' is not active"), fspool->def->name); + goto cleanup; + } + + if (fspool->asyncjobs > 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("fspool '%s' has asynchronous jobs running."), + fspool->def->name); + goto cleanup; + } + + virFSPoolObjClearItems(fspool); + if (backend->refreshFSpool(obj->conn, fspool) < 0) { + if (backend->stopFSpool) + backend->stopFSpool(obj->conn, fspool); + + fspool->active = false; + + if (fspool->configFile == NULL) { + virFSPoolObjRemove(&driver->fspools, fspool); + fspool = NULL; + } + goto cleanup; + } + ret = 0; + + cleanup: + if (fspool) + virFSPoolObjUnlock(fspool); + fsDriverUnlock(); + return ret; + +} + +static int +fsPoolGetInfo(virFSPoolPtr obj, + virFSPoolInfoPtr info) +{ + virFSPoolObjPtr fspool; + int ret = -1; + + if (!(fspool = virFSPoolObjFromFSPool(obj))) + return -1; + + if (virFSPoolGetInfoEnsureACL(obj->conn, fspool->def) < 0) + goto cleanup; + + if (virFSBackendForType(fspool->def->type) == NULL) + goto cleanup; + + memset(info, 0, sizeof(virFSPoolInfo)); + if (fspool->active) + info->state = VIR_FSPOOL_RUNNING; + else + info->state = VIR_FSPOOL_INACTIVE; + info->capacity = fspool->def->capacity; + info->allocation = fspool->def->allocation; + info->available = fspool->def->available; + ret = 0; + + cleanup: + virFSPoolObjUnlock(fspool); + return ret; +} + +static char * +fsPoolGetXMLDesc(virFSPoolPtr obj, + unsigned int flags) +{ + virFSPoolObjPtr fspool; + virFSPoolDefPtr def; + char *ret = NULL; + + virCheckFlags(VIR_FS_XML_INACTIVE, NULL); + + if (!(fspool = virFSPoolObjFromFSPool(obj))) + return NULL; + + if (virFSPoolGetXMLDescEnsureACL(obj->conn, fspool->def) < 0) + goto cleanup; + + if ((flags & VIR_FS_XML_INACTIVE) && fspool->newDef) + def = fspool->newDef; + else + def = fspool->def; + + ret = virFSPoolDefFormat(def); + + cleanup: + virFSPoolObjUnlock(fspool); + return ret; +} + +static int +fsPoolGetAutostart(virFSPoolPtr obj, int *autostart) +{ + virFSPoolObjPtr fspool; + int ret = -1; + + if (!(fspool = virFSPoolObjFromFSPool(obj))) + return -1; + + if (virFSPoolGetAutostartEnsureACL(obj->conn, fspool->def) < 0) + goto cleanup; + + if (!fspool->configFile) { + *autostart = 0; + } else { + *autostart = fspool->autostart; + } + ret = 0; + + cleanup: + virFSPoolObjUnlock(fspool); + return ret; +} + +static int +fsPoolSetAutostart(virFSPoolPtr obj, int autostart) +{ + virFSPoolObjPtr fspool; + int ret = -1; + + fsDriverLock(); + fspool = virFSPoolObjFindByUUID(&driver->fspools, obj->uuid); + + if (!fspool) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(obj->uuid, uuidstr); + virReportError(VIR_ERR_NO_FSPOOL, + _("no fspool with matching uuid '%s' (%s)"), + uuidstr, obj->name); + goto cleanup; + } + + if (virFSPoolSetAutostartEnsureACL(obj->conn, fspool->def) < 0) + goto cleanup; + + if (!fspool->configFile) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("fspool has no config file")); + goto cleanup; + } + + autostart = (autostart != 0); + + if (fspool->autostart != autostart) { + if (autostart) { + if (virFileMakePath(driver->autostartDir) < 0) { + virReportSystemError(errno, + _("cannot create autostart directory %s"), + driver->autostartDir); + goto cleanup; + } + + if (symlink(fspool->configFile, fspool->autostartLink) < 0) { + virReportSystemError(errno, + _("Failed to create symlink '%s' to '%s'"), + fspool->autostartLink, fspool->configFile); + goto cleanup; + } + } else { + if (unlink(fspool->autostartLink) < 0 && + errno != ENOENT && errno != ENOTDIR) { + virReportSystemError(errno, + _("Failed to delete symlink '%s'"), + fspool->autostartLink); + goto cleanup; + } + } + fspool->autostart = autostart; + } + ret = 0; + + cleanup: + if (fspool) + virFSPoolObjUnlock(fspool); + fsDriverUnlock(); + return ret; +} + +static int +fsPoolNumOfItems(virFSPoolPtr obj) +{ + virFSPoolObjPtr fspool; + int ret = -1; + size_t i; + + if (!(fspool = virFSPoolObjFromFSPool(obj))) + return -1; + + if (virFSPoolNumOfItemsEnsureACL(obj->conn, fspool->def) < 0) + goto cleanup; + + if (!virFSPoolObjIsActive(fspool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("fspool '%s' is not active"), fspool->def->name); + goto cleanup; + } + ret = 0; + for (i = 0; i < fspool->items.count; i++) { + if (virFSPoolNumOfItemsCheckACL(obj->conn, fspool->def, + fspool->items.objs[i])) + ret++; + } + + cleanup: + virFSPoolObjUnlock(fspool); + return ret; +} + +static int +fsPoolListItems(virFSPoolPtr obj, + char **const names, + int maxnames) +{ + virFSPoolObjPtr fspool; + size_t i; + int n = 0; + + memset(names, 0, maxnames * sizeof(*names)); + + if (!(fspool = virFSPoolObjFromFSPool(obj))) + return -1; + + if (virFSPoolListItemsEnsureACL(obj->conn, fspool->def) < 0) + goto cleanup; + + if (!virFSPoolObjIsActive(fspool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("fspool '%s' is not active"), fspool->def->name); + goto cleanup; + } + + for (i = 0; i < fspool->items.count && n < maxnames; i++) { + if (!virFSPoolListItemsCheckACL(obj->conn, fspool->def, + fspool->items.objs[i])) + continue; + if (VIR_STRDUP(names[n++], fspool->items.objs[i]->name) < 0) + goto cleanup; + } + + virFSPoolObjUnlock(fspool); + return n; + + cleanup: + virFSPoolObjUnlock(fspool); + for (n = 0; n < maxnames; n++) + VIR_FREE(names[n]); + + memset(names, 0, maxnames * sizeof(*names)); + return -1; +} + +static int +fsPoolListAllItems(virFSPoolPtr fspool, + virFSItemPtr **items, + unsigned int flags) +{ + virFSPoolObjPtr obj; + size_t i; + virFSItemPtr *tmp_items = NULL; + virFSItemPtr item = NULL; + int nitems = 0; + int ret = -1; + + virCheckFlags(0, -1); + + if (!(obj = virFSPoolObjFromFSPool(fspool))) + return -1; + + if (virFSPoolListAllItemsEnsureACL(fspool->conn, obj->def) < 0) + goto cleanup; + + if (!virFSPoolObjIsActive(obj)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("fspool '%s' is not active"), obj->def->name); + goto cleanup; + } + + /* Just returns the items count */ + if (!items) { + ret = obj->items.count; + goto cleanup; + } + + if (VIR_ALLOC_N(tmp_items, obj->items.count + 1) < 0) + goto cleanup; + + for (i = 0; i < obj->items.count; i++) { + if (!virFSPoolListAllItemsCheckACL(fspool->conn, obj->def, + obj->items.objs[i])) + continue; + if (!(item = virGetFSItem(fspool->conn, obj->def->name, + obj->items.objs[i]->name, + obj->items.objs[i]->key, + NULL, NULL))) + goto cleanup; + tmp_items[nitems++] = item; + } + + *items = tmp_items; + tmp_items = NULL; + ret = nitems; + + cleanup: + if (tmp_items) { + for (i = 0; i < nitems; i++) + virObjectUnref(tmp_items[i]); + VIR_FREE(tmp_items); + } + + virFSPoolObjUnlock(obj); + + return ret; +} + +static virFSItemPtr +fsItemLookupByName(virFSPoolPtr obj, const char *name) +{ + virFSPoolObjPtr fspool; + virFSItemDefPtr item; + virFSItemPtr ret = NULL; + + if (!(fspool = virFSPoolObjFromFSPool(obj))) + return NULL; + + if (!virFSPoolObjIsActive(fspool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("fspool '%s' is not active"), fspool->def->name); + goto cleanup; + } + + item = virFSItemDefFindByName(fspool, name); + + if (!item) { + virReportError(VIR_ERR_NO_FSITEM, + _("no fspool item with matching name '%s'"), + name); + goto cleanup; + } + + if (virFSItemLookupByNameEnsureACL(obj->conn, fspool->def, item) < 0) + goto cleanup; + + ret = virGetFSItem(obj->conn, fspool->def->name, item->name, item->key, + NULL, NULL); + + cleanup: + virFSPoolObjUnlock(fspool); + return ret; +} + +static virFSItemPtr +fsItemLookupByKey(virConnectPtr conn, const char *key) +{ + size_t i; + virFSItemPtr ret = NULL; + + fsDriverLock(); + for (i = 0; i < driver->fspools.count && !ret; i++) { + virFSPoolObjLock(driver->fspools.objs[i]); + if (virFSPoolObjIsActive(driver->fspools.objs[i])) { + virFSItemDefPtr item = + virFSItemDefFindByKey(driver->fspools.objs[i], key); + + if (item) { + virFSPoolDefPtr def = driver->fspools.objs[i]->def; + if (virFSItemLookupByKeyEnsureACL(conn, def, item) < 0) { + virFSPoolObjUnlock(driver->fspools.objs[i]); + goto cleanup; + } + + ret = virGetFSItem(conn, + def->name, + item->name, + item->key, + NULL, NULL); + } + } + virFSPoolObjUnlock(driver->fspools.objs[i]); + } + + if (!ret) + virReportError(VIR_ERR_NO_FSITEM, + _("no fspool item with matching key %s"), key); + + cleanup: + fsDriverUnlock(); + return ret; +} + +static virFSItemPtr +fsItemLookupByPath(virConnectPtr conn, + const char *path) +{ + size_t i; + virFSItemPtr ret = NULL; + char *cleanpath; + + cleanpath = virFileSanitizePath(path); + if (!cleanpath) + return NULL; + + fsDriverLock(); + for (i = 0; i < driver->fspools.count && !ret; i++) { + virFSPoolObjPtr fspool = driver->fspools.objs[i]; + virFSItemDefPtr item; + + virFSPoolObjLock(fspool); + + if (!virFSPoolObjIsActive(fspool)) { + virFSPoolObjUnlock(fspool); + continue; + } + + item = virFSItemDefFindByPath(fspool, cleanpath); + + if (item) { + if (virFSItemLookupByPathEnsureACL(conn, fspool->def, item) < 0) { + virFSPoolObjUnlock(fspool); + goto cleanup; + } + + ret = virGetFSItem(conn, fspool->def->name, + item->name, item->key, + NULL, NULL); + } + + virFSPoolObjUnlock(fspool); + } + + if (!ret) { + if (STREQ(path, cleanpath)) { + virReportError(VIR_ERR_NO_FSITEM, + _("no fspool item with matching path '%s'"), path); + } else { + virReportError(VIR_ERR_NO_FSITEM, + _("no fspool item with matching path '%s' (%s)"), + path, cleanpath); + } + } + + cleanup: + VIR_FREE(cleanpath); + fsDriverUnlock(); + return ret; +} + +static void +fsItemRemoveFromFSPool(virFSPoolObjPtr fspool, + virFSItemDefPtr item) +{ + size_t i; + + for (i = 0; i < fspool->items.count; i++) { + if (fspool->items.objs[i] == item) { + VIR_INFO("Deleting item '%s' from fspool '%s'", + item->name, fspool->def->name); + virFSItemDefFree(item); + + VIR_DELETE_ELEMENT(fspool->items.objs, i, fspool->items.count); + break; + } + } +} + +static int +fsItemDeleteInternal(virFSItemPtr obj, + virFSBackendPtr backend, + virFSPoolObjPtr fspool, + virFSItemDefPtr item, + unsigned int flags) +{ + int ret = -1; + + virCheckFlags(0, -1); + + if (!backend->deleteItem) { + virReportError(VIR_ERR_NO_SUPPORT, + "%s", _("fspool does not support item deletion")); + goto cleanup; + } + if (backend->deleteItem(obj->conn, fspool, item, flags) < 0) + goto cleanup; + + fsItemRemoveFromFSPool(fspool, item); + + ret = 0; + + cleanup: + return ret; +} + +static virFSItemPtr +fsItemCreateXML(virFSPoolPtr obj, + const char *xmldesc, + unsigned int flags) +{ + + virFSPoolObjPtr fspool; + virFSBackendPtr backend; + virFSItemDefPtr itemdef = NULL; + virFSItemPtr ret = NULL, itemobj = NULL; + + virCheckFlags(0, NULL); + + if (!(fspool = virFSPoolObjFromFSPool(obj))) + return NULL; + + if (!virFSPoolObjIsActive(fspool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("fspool '%s' is not active"), fspool->def->name); + goto cleanup; + } + + if ((backend = virFSBackendForType(fspool->def->type)) == NULL) + goto cleanup; + + itemdef = virFSItemDefParseString(fspool->def, xmldesc, + VIR_ITEM_XML_PARSE_OPT_CAPACITY); + if (itemdef == NULL) + goto cleanup; + + if (!itemdef->target.capacity && !backend->buildItem) { + virReportError(VIR_ERR_NO_SUPPORT, + "%s", _("item capacity required for this " + "fspool")); + goto cleanup; + } + + if (virFSItemCreateXMLEnsureACL(obj->conn, fspool->def, itemdef) < 0) + goto cleanup; + + if (virFSItemDefFindByName(fspool, itemdef->name)) { + virReportError(VIR_ERR_FSITEM_EXIST, + _("'%s'"), itemdef->name); + goto cleanup; + } + + if (!backend->createItem) { + virReportError(VIR_ERR_NO_SUPPORT, + "%s", _("fspool does not support item " + "creation")); + goto cleanup; + } + + if (VIR_REALLOC_N(fspool->items.objs, + fspool->items.count+1) < 0) + goto cleanup; + + /* Wipe any key the user may have suggested, as item creation + * will generate the canonical key. */ + VIR_FREE(itemdef->key); + if (backend->createItem(obj->conn, fspool, itemdef) < 0) + goto cleanup; + + fspool->items.objs[fspool->items.count++] = itemdef; + itemobj = virGetFSItem(obj->conn, fspool->def->name, itemdef->name, + itemdef->key, NULL, NULL); + if (!itemobj) { + fspool->items.count--; + goto cleanup; + } + + + if (backend->buildItem) { + int buildret; + virFSItemDefPtr builditemdef = NULL; + + if (VIR_ALLOC(builditemdef) < 0) { + itemdef = NULL; + goto cleanup; + } + + /* Make a shallow copy of the 'defined' item definition, since the + * original allocation value will change as the user polls 'info', + * but we only need the initial requested values + */ + memcpy(builditemdef, itemdef, sizeof(*itemdef)); + + /* Drop the fspool lock during item allocation */ + fspool->asyncjobs++; + itemdef->building = true; + virFSPoolObjUnlock(fspool); + + buildret = backend->buildItem(obj->conn, fspool, builditemdef, flags); + + VIR_FREE(builditemdef); + + fsDriverLock(); + virFSPoolObjLock(fspool); + fsDriverUnlock(); + + itemdef->building = false; + fspool->asyncjobs--; + + if (buildret < 0) { + /* buildItem handles deleting item on failure */ + fsItemRemoveFromFSPool(fspool, itemdef); + itemdef = NULL; + goto cleanup; + } + + } + + if (backend->refreshItem && + backend->refreshItem(obj->conn, fspool, itemdef) < 0) { + fsItemDeleteInternal(itemobj, backend, fspool, itemdef, 0); + itemdef = NULL; + goto cleanup; + } + + /* Update fspool metadata ignoring the disk backend since + * it updates the fspool values. + */ + + VIR_INFO("Creating item '%s' in fspool '%s'", + itemobj->name, fspool->def->name); + ret = itemobj; + itemobj = NULL; + itemdef = NULL; + + cleanup: + virObjectUnref(itemobj); + virFSItemDefFree(itemdef); + if (fspool) + virFSPoolObjUnlock(fspool); + return ret; +} + +static virFSItemPtr +fsItemCreateXMLFrom(virFSPoolPtr obj, + const char *xmldesc, + virFSItemPtr vobj, + unsigned int flags) +{ + virFSPoolObjPtr fspool, origpool = NULL; + virFSBackendPtr backend; + virFSItemDefPtr origitem = NULL, newitem = NULL, shadowitem = NULL; + virFSItemPtr ret = NULL, itemobj = NULL; + int buildret; + + virCheckFlags(0, NULL); + + fsDriverLock(); + fspool = virFSPoolObjFindByUUID(&driver->fspools, obj->uuid); + if (fspool && STRNEQ(obj->name, vobj->pool)) { + virFSPoolObjUnlock(fspool); + origpool = virFSPoolObjFindByName(&driver->fspools, vobj->pool); + virFSPoolObjLock(fspool); + } + fsDriverUnlock(); + if (!fspool) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(obj->uuid, uuidstr); + virReportError(VIR_ERR_NO_FSPOOL, + _("no fspool with matching uuid '%s' (%s)"), + uuidstr, obj->name); + goto cleanup; + } + + if (STRNEQ(obj->name, vobj->pool) && !origpool) { + virReportError(VIR_ERR_NO_FSPOOL, + _("no fspool with matching name '%s'"), + vobj->pool); + goto cleanup; + } + + if (!virFSPoolObjIsActive(fspool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("fspool '%s' is not active"), fspool->def->name); + goto cleanup; + } + + if (origpool && !virFSPoolObjIsActive(origpool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("fspool '%s' is not active"), + origpool->def->name); + goto cleanup; + } + + if ((backend = virFSBackendForType(fspool->def->type)) == NULL) + goto cleanup; + + origitem = virFSItemDefFindByName(origpool ? + origpool : fspool, vobj->name); + if (!origitem) { + virReportError(VIR_ERR_NO_FSITEM, + _("no fsitem with matching name '%s'"), + vobj->name); + goto cleanup; + } + + newitem = virFSItemDefParseString(fspool->def, xmldesc, + VIR_VOL_XML_PARSE_NO_CAPACITY); + if (newitem == NULL) + goto cleanup; + + if (virFSItemCreateXMLFromEnsureACL(obj->conn, fspool->def, newitem) < 0) + goto cleanup; + + if (virFSItemDefFindByName(fspool, newitem->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("fsitem name '%s' already in use."), + newitem->name); + goto cleanup; + } + + /* Use the original item's capacity in case the new capacity + * is less than that, or it was omitted */ + if (newitem->target.capacity < origitem->target.capacity) + newitem->target.capacity = origitem->target.capacity; + + if (!backend->buildItemFrom) { + virReportError(VIR_ERR_NO_SUPPORT, + "%s", _("fspool does not support" + " item creation from an existing item")); + goto cleanup; + } + + if (origitem->building) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("fsitem '%s' is still being allocated."), + origitem->name); + goto cleanup; + } + + if (backend->refreshItem && + backend->refreshItem(obj->conn, fspool, origitem) < 0) + goto cleanup; + + if (VIR_REALLOC_N(fspool->items.objs, + fspool->items.count+1) < 0) + goto cleanup; + + /* 'Define' the new item so we get async progress reporting. + * Wipe any key the user may have suggested, as item creation + * will generate the canonical key. */ + VIR_FREE(newitem->key); + if (backend->createItem(obj->conn, fspool, newitem) < 0) + goto cleanup; + + /* Make a shallow copy of the 'defined' item definition, since the + * original allocation value will change as the user polls 'info', + * but we only need the initial requested values + */ + if (VIR_ALLOC(shadowitem) < 0) + goto cleanup; + + memcpy(shadowitem, newitem, sizeof(*newitem)); + + fspool->items.objs[fspool->items.count++] = newitem; + itemobj = virGetFSItem(obj->conn, fspool->def->name, newitem->name, + newitem->key, NULL, NULL); + if (!itemobj) { + fspool->items.count--; + goto cleanup; + } + + /* Drop the fspool lock during item allocation */ + fspool->asyncjobs++; + newitem->building = true; + origitem->in_use++; + virFSPoolObjUnlock(fspool); + + if (origpool) { + origpool->asyncjobs++; + virFSPoolObjUnlock(origpool); + } + + buildret = backend->buildItemFrom(obj->conn, fspool, shadowitem, origitem, flags); + + fsDriverLock(); + virFSPoolObjLock(fspool); + if (origpool) + virFSPoolObjLock(origpool); + fsDriverUnlock(); + + origitem->in_use--; + newitem->building = false; + fspool->asyncjobs--; + + if (origpool) { + origpool->asyncjobs--; + virFSPoolObjUnlock(origpool); + origpool = NULL; + } + + if (buildret < 0 || + (backend->refreshItem && + backend->refreshItem(obj->conn, fspool, newitem) < 0)) { + fsItemDeleteInternal(itemobj, backend, fspool, newitem, 0); + newitem = NULL; + goto cleanup; + } + + fspool->def->allocation += newitem->target.allocation; + fspool->def->available -= newitem->target.allocation; + + VIR_INFO("Creating item '%s' in fspool '%s'", + itemobj->name, fspool->def->name); + ret = itemobj; + itemobj = NULL; + newitem = NULL; + + cleanup: + virObjectUnref(itemobj); + virFSItemDefFree(newitem); + VIR_FREE(shadowitem); + if (fspool) + virFSPoolObjUnlock(fspool); + if (origpool) + virFSPoolObjUnlock(origpool); + return ret; +} + +static virFSItemDefPtr +virFSItemDefFromItem(virFSItemPtr obj, + virFSPoolObjPtr *fspool, + virFSBackendPtr *backend) +{ + virFSItemDefPtr item = NULL; + + *fspool = NULL; + + fsDriverLock(); + *fspool = virFSPoolObjFindByName(&driver->fspools, obj->pool); + fsDriverUnlock(); + + if (!*fspool) { + virReportError(VIR_ERR_NO_FSPOOL, + _("no fspool with matching name '%s'"), + obj->pool); + return NULL; + } + + if (!virFSPoolObjIsActive(*fspool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("fspool '%s' is not active"), + (*fspool)->def->name); + goto error; + } + + if (!(item = virFSItemDefFindByName(*fspool, obj->name))) { + virReportError(VIR_ERR_NO_FSITEM, + _("no fsitem with matching name '%s'"), + obj->name); + goto error; + } + + if (backend) { + if (!(*backend = virFSBackendForType((*fspool)->def->type))) + goto error; + } + + return item; + + error: + virFSPoolObjUnlock(*fspool); + *fspool = NULL; + + return NULL; +} + +static int +fsItemGetInfo(virFSItemPtr obj, + virFSItemInfoPtr info) +{ + virFSPoolObjPtr fspool; + virFSBackendPtr backend; + virFSItemDefPtr item; + int ret = -1; + + if (!(item = virFSItemDefFromItem(obj, &fspool, &backend))) + return -1; + + if (virFSItemGetInfoEnsureACL(obj->conn, fspool->def, item) < 0) + goto cleanup; + + if (backend->refreshItem && + backend->refreshItem(obj->conn, fspool, item) < 0) + goto cleanup; + + memset(info, 0, sizeof(*info)); + info->type = item->type; + info->capacity = item->target.capacity; + info->allocation = item->target.allocation; + ret = 0; + + cleanup: + virFSPoolObjUnlock(fspool); + return ret; +} + +static char * +fsItemGetXMLDesc(virFSItemPtr obj, unsigned int flags) +{ + virFSPoolObjPtr fspool; + virFSBackendPtr backend; + virFSItemDefPtr item; + char *ret = NULL; + + virCheckFlags(0, NULL); + + if (!(item = virFSItemDefFromItem(obj, &fspool, &backend))) + return NULL; + + if (virFSItemGetXMLDescEnsureACL(obj->conn, fspool->def, item) < 0) + goto cleanup; + + if (backend->refreshItem && + backend->refreshItem(obj->conn, fspool, item) < 0) + goto cleanup; + + ret = virFSItemDefFormat(fspool->def, item); + + cleanup: + virFSPoolObjUnlock(fspool); + + return ret; +} + +static char * +fsItemGetPath(virFSItemPtr obj) +{ + virFSPoolObjPtr fspool; + virFSItemDefPtr item; + char *ret = NULL; + + if (!(item = virFSItemDefFromItem(obj, &fspool, NULL))) + return NULL; + + if (virFSItemGetPathEnsureACL(obj->conn, fspool->def, item) < 0) + goto cleanup; + + ignore_value(VIR_STRDUP(ret, item->target.path)); + + cleanup: + virFSPoolObjUnlock(fspool); + return ret; +} + +static int +fsPoolIsActive(virFSPoolPtr fspool) +{ + virFSPoolObjPtr obj; + int ret = -1; + + if (!(obj = virFSPoolObjFromFSPool(fspool))) + return -1; + + if (virFSPoolIsActiveEnsureACL(fspool->conn, obj->def) < 0) + goto cleanup; + + ret = virFSPoolObjIsActive(obj); + + cleanup: + virFSPoolObjUnlock(obj); + return ret; +} + +static int +fsPoolIsPersistent(virFSPoolPtr fspool) +{ + virFSPoolObjPtr obj; + int ret = -1; + + if (!(obj = virFSPoolObjFromFSPool(fspool))) + return -1; + + if (virFSPoolIsPersistentEnsureACL(fspool->conn, obj->def) < 0) + goto cleanup; + + ret = obj->configFile ? 1 : 0; + + cleanup: + virFSPoolObjUnlock(obj); + return ret; +} + +static int +fsItemDelete(virFSItemPtr obj, + unsigned int flags) +{ + virFSPoolObjPtr fspool; + virFSBackendPtr backend; + virFSItemDefPtr item = NULL; + int ret = -1; + + virCheckFlags(0, -1); + + if (!(item = virFSItemDefFromItem(obj, &fspool, &backend))) + return -1; + + if (virFSItemDeleteEnsureACL(obj->conn, fspool->def, item) < 0) + goto cleanup; + + if (item->in_use) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("item '%s' is still in use."), + item->name); + goto cleanup; + } + + if (item->building) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("item '%s' is still being allocated."), + item->name); + goto cleanup; + } + + if (fsItemDeleteInternal(obj, backend, fspool, item, flags) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virFSPoolObjUnlock(fspool); + return ret; } static virFSDriver fsDriver = { -- 1.8.3.1

Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- m4/virt-driver-fspool.m4 | 14 ++- po/POTFILES.in | 1 + src/Makefile.am | 10 +- src/fs/fs_backend_dir.c | 290 +++++++++++++++++++++++++++++++++++++++++++++++ src/fs/fs_backend_dir.h | 8 ++ src/fs/fs_driver.c | 10 +- 6 files changed, 328 insertions(+), 5 deletions(-) create mode 100644 src/fs/fs_backend_dir.c create mode 100644 src/fs/fs_backend_dir.h diff --git a/m4/virt-driver-fspool.m4 b/m4/virt-driver-fspool.m4 index 634cb7f..2507879 100644 --- a/m4/virt-driver-fspool.m4 +++ b/m4/virt-driver-fspool.m4 @@ -17,17 +17,27 @@ dnl AC_DEFUN([LIBVIRT_DRIVER_CHECK_FSPOOL],[ AC_ARG_WITH([fs], - [AS_HELP_STRING([--with-fs], + [AS_HELP_STRING([--with-fs-dir], [add FS driver @<:@default=check@:>@])]) - m4_divert_text([DEFAULTS], [with_fs=check]) + m4_divert_text([DEFAULTS], [with_fs_dir=check]) if test "$with_fs" = "yes"; then AC_DEFINE_UNQUOTED([WITH_FS], 1, [whether fs driver is enabled]) fi + + if test "$with_fs_dir" = "yes"; then + AC_DEFINE_UNQUOTED([WITH_FS], 1, + [whether fs driver is enabled]) + AC_DEFINE_UNQUOTED([WITH_FS_DIR], 1, + [whether fs directory backend is enabled]) + fi + AM_CONDITIONAL([WITH_FS], [test "$with_fs" = "yes"]) + AM_CONDITIONAL([WITH_FS_DIR], [test "$with_fs_dir" = "yes"]) ]) AC_DEFUN([LIBVIRT_DRIVER_RESULT_FSPOOL],[ AC_MSG_NOTICE([ FSPool: $with_fs]) + AC_MSG_NOTICE([FSPool dir: $with_fs_dir]) ]) diff --git a/po/POTFILES.in b/po/POTFILES.in index 942e099..cdb6296 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -60,6 +60,7 @@ src/esx/esx_vi.c src/esx/esx_vi_methods.c src/esx/esx_vi_types.c src/fdstream.c +src/fs/fs_backend_dir.c src/fs/fs_driver.c src/hyperv/hyperv_driver.c src/hyperv/hyperv_util.c diff --git a/src/Makefile.am b/src/Makefile.am index d18d3f4..10e1161 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1119,6 +1119,10 @@ FS_DRIVER_SOURCES = \ fs/fs_driver.h fs/fs_driver.c \ fs/fs_backend.h +FS_DRIVER_DIR_SOURCES = \ + fs/fs_backend_dir.h fs/fs_backend_dir.c + + pkgdata_DATA = cpu/cpu_map.xml EXTRA_DIST += $(pkgdata_DATA) @@ -1665,6 +1669,7 @@ noinst_LTLIBRARIES += libvirt_driver_fs.la #libvirt_la_BUILT_LIBADD += libvirt_driver_fs.la endif ! WITH_DRIVER_MODULES libvirt_driver_fs_impl_la_SOURCES += $(FS_DRIVER_SOURCES) +libvirt_driver_fs_impl_la_SOURCES += $(FS_DRIVER_DIR_SOURCES) endif WITH_FS # Needed to keep automake quiet about conditionals @@ -1938,8 +1943,9 @@ EXTRA_DIST += \ $(BHYVE_DRIVER_SOURCES) \ $(NETWORK_DRIVER_SOURCES) \ $(INTERFACE_DRIVER_SOURCES) \ - $(FS_DRIVER_SOURCES) \ - $(STORAGE_DRIVER_SOURCES) \ + $(FS_DRIVER_SOURCES) \ + $(FS_DRIVER_DIR_SOURCES) \ + $(STORAGE_DRIVER_SOURCES) \ $(STORAGE_DRIVER_FS_SOURCES) \ $(STORAGE_DRIVER_LVM_SOURCES) \ $(STORAGE_DRIVER_ISCSI_SOURCES) \ diff --git a/src/fs/fs_backend_dir.c b/src/fs/fs_backend_dir.c new file mode 100644 index 0000000..814c2cb --- /dev/null +++ b/src/fs/fs_backend_dir.c @@ -0,0 +1,290 @@ +/* + * fs_backend_dir.c: file system backend implementation + * Author: Olga Krishtal <okrishtal@virtuozzo.com> + * + * Copyright (C) 2016 Parallels IP Holdings GmbH + * + * 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/>. + */ + +#include <config.h> + +#include <sys/statvfs.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> + +#include <libxml/parser.h> +#include <libxml/tree.h> +#include <libxml/xpath.h> + +#include "virerror.h" +#include "fs_backend_dir.h" +#include "fs_conf.h" +#include "vircommand.h" +#include "viralloc.h" +#include "virxml.h" +#include "virfile.h" +#include "virpoolcommon.h" +#include "virlog.h" +#include "virstring.h" +#include "fdstream.h" +#include "stat-time.h" + +#define VIR_FROM_THIS VIR_FROM_FSPOOL + +VIR_LOG_INIT("fs.fs_backend_dir"); + +static int +virFSDirBuild(virConnectPtr conn ATTRIBUTE_UNUSED, + virFSPoolObjPtr fspool, + unsigned int flags) +{ + + virCheckFlags(VIR_STORAGE_POOL_BUILD_OVERWRITE | + VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, -1); + return virDirPoolBuild(fspool->def, false); + +} + +static int +virFSDirRefresh(virConnectPtr conn ATTRIBUTE_UNUSED, + virFSPoolObjPtr fspool) +{ + DIR *dir; + struct dirent *entry; + virFSItemDefPtr item = NULL; + struct statvfs sb; + struct stat statbuf; + int fd = 0; + int ret = -1; + + if (virDirOpen(&dir, fspool->def->target.path) < 0) + goto cleanup; + + while (virDirRead(dir, &entry, fspool->def->target.path) > 0) { + if (virStringHasControlChars(entry->d_name)) { + VIR_WARN("Ignoring control characters under '%s'", + fspool->def->target.path); + continue; + } + + if (VIR_ALLOC(item) < 0) + goto cleanup; + + if (VIR_STRDUP(item->name, entry->d_name) < 0) + goto cleanup; + item->type = VIR_FSITEM_DIR; + if (virAsprintf(&item->target.path, "%s/%s", + fspool->def->target.path, + item->name) == -1) + goto cleanup; + + if (VIR_STRDUP(item->key, item->target.path) < 0) + goto cleanup; + + + if (VIR_APPEND_ELEMENT(fspool->items.objs, fspool->items.count, item) < 0) + goto cleanup; + } + + + if ((fd = open(fspool->def->target.path, O_RDONLY)) < 0) { + virReportSystemError(errno, + _("cannot open path '%s'"), + fspool->def->target.path); + goto cleanup; + } + + if (fstat(fd, &statbuf) < 0) { + virReportSystemError(errno, + _("cannot stat path '%s'"), + fspool->def->target.path); + goto cleanup; + } + + fspool->def->target.perms.mode = statbuf.st_mode & S_IRWXUGO; + fspool->def->target.perms.uid = statbuf.st_uid; + fspool->def->target.perms.gid = statbuf.st_gid; + + if (statvfs(fspool->def->target.path, &sb) < 0) { + virReportSystemError(errno, + _("cannot statvfs path '%s'"), + fspool->def->target.path); + goto cleanup; + } + + fspool->def->capacity = ((unsigned long long)sb.f_blocks * + (unsigned long long)sb.f_frsize); + fspool->def->available = ((unsigned long long)sb.f_bfree * + (unsigned long long)sb.f_frsize); + fspool->def->allocation = fspool->def->capacity - fspool->def->available; + + ret = 0; + + cleanup: + VIR_DIR_CLOSE(dir); + VIR_FORCE_CLOSE(fd); + virFSItemDefFree(item); + if (ret < 0) + virFSPoolObjClearItems(fspool); + return ret; +} + +static int +virFSDirDelete(virConnectPtr conn ATTRIBUTE_UNUSED, + virFSPoolObjPtr fspool, + unsigned int flags) +{ + virCheckFlags(0, -1); + return virDirPoolDelete(fspool->def->target.path); + +} + +static int +virFSDirItemBuild(virConnectPtr conn ATTRIBUTE_UNUSED, + virFSPoolObjPtr fspool ATTRIBUTE_UNUSED, + virFSItemDefPtr item, + unsigned int flags) +{ + virCheckFlags(0, -1); + + if (item->type == VIR_FSITEM_DIR) { + if ((virDirCreate(item->target.path, + (item->target.perms->mode == (mode_t) -1 ? + VIR_FS_DEFAULT_ITEM_PERM_MODE: + item->target.perms->mode), + item->target.perms->uid, + item->target.perms->gid, + 0)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("error creating item")); + return -1; + } + } + + return 0; +} + +static int +virFSDirItemBuildFrom(virConnectPtr conn ATTRIBUTE_UNUSED, + virFSPoolObjPtr fspool ATTRIBUTE_UNUSED, + virFSItemDefPtr item, + virFSItemDefPtr inputitem, + unsigned int flags) +{ + virCommandPtr cmd = NULL; + int ret = -1; + + virCheckFlags(0, -1); + + item->target.capacity = inputitem->target.capacity; + cmd = virCommandNewArgList("cp", "-r", inputitem->target.path, + item->target.path, NULL); + ret = virCommandRun(cmd, NULL); + + virCommandFree(cmd); + return ret; +} + +static int +virFSDirItemCreate(virConnectPtr conn ATTRIBUTE_UNUSED, + virFSPoolObjPtr fspool, + virFSItemDefPtr item) +{ + VIR_FREE(item->target.path); + if (virDirItemCreate(item->name, &item->target.path, + fspool->def->target.path) < 0) + return -1; + + VIR_FREE(item->key); + return VIR_STRDUP(item->key, item->target.path); +} + + +static int +virFSDirItemRefresh(virConnectPtr conn ATTRIBUTE_UNUSED, + virFSPoolObjPtr fspool ATTRIBUTE_UNUSED, + virFSItemDefPtr item) +{ + int fd; + int ret = -1; + struct stat statbuf; + virCommandPtr cmd = NULL; + char *output = NULL, *end; + + if ((fd = open(item->target.path, O_RDONLY)) < 0) { + virReportSystemError(errno, _("cannot open directory '%s'"), + item->target.path); + return -1; + } + if (fstat(fd, &statbuf) < 0) { + virReportSystemError(errno, _("cannot stat path '%s'"), + item->target.path); + goto cleanup; + } + + cmd = virCommandNewArgList("du", "-sB1", item->target.path, NULL); + virCommandSetOutputBuffer(cmd, &output); + if ((ret = virCommandRun(cmd, NULL)) < 0) + goto cleanup; + + if (virStrToLong_ull(output, &end, 10, &item->target.allocation) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Malformed du output: %s"), output); + goto cleanup; + } + + if (&(item->target.perms) && VIR_ALLOC(*(&item->target.perms)) < 0) + goto cleanup; + item->target.perms->mode = statbuf.st_mode & S_IRWXUGO; + item->target.perms->uid = statbuf.st_uid; + item->target.perms->gid = statbuf.st_gid; + + ret = 0; + cleanup: + VIR_FORCE_CLOSE(fd); + VIR_FREE(output); + virCommandFree(cmd); + return ret; +} + +static int +virFSDirItemDelete(virConnectPtr conn ATTRIBUTE_UNUSED, + virFSPoolObjPtr fspool ATTRIBUTE_UNUSED, + virFSItemDefPtr item, + unsigned int flags) +{ + virCheckFlags(0, -1); + return virFileDeleteTree(item->target.path); +} + +virFSBackend virFSBackendDir = { + .type = VIR_FSPOOL_DIR, + + .buildFSpool = virFSDirBuild, + .refreshFSpool = virFSDirRefresh, + .deleteFSpool = virFSDirDelete, + .buildItem = virFSDirItemBuild, + .buildItemFrom = virFSDirItemBuildFrom, + .createItem = virFSDirItemCreate, + .deleteItem = virFSDirItemDelete, + .refreshItem = virFSDirItemRefresh, +}; diff --git a/src/fs/fs_backend_dir.h b/src/fs/fs_backend_dir.h new file mode 100644 index 0000000..335e008 --- /dev/null +++ b/src/fs/fs_backend_dir.h @@ -0,0 +1,8 @@ +#ifndef __VIR_FS_BACKEND_DIR_H__ +# define __VIR_FS_BACKEND_DIR_H__ + +# include "fs_backend.h" + +extern virFSBackend virFSBackendDir; + +#endif /* __VIR_FS_BACKEND_DIR_H__ */ diff --git a/src/fs/fs_driver.c b/src/fs/fs_driver.c index f913ce5..b566893 100644 --- a/src/fs/fs_driver.c +++ b/src/fs/fs_driver.c @@ -48,6 +48,10 @@ #include "viraccessapicheck.h" #include "dirname.h" +#if WITH_FS_DIR +# include "fs_backend_dir.h" +#endif + #define VIR_FROM_THIS VIR_FROM_FSPOOL VIR_LOG_INIT("fs.fs_driver"); @@ -65,7 +69,11 @@ static void fsDriverUnlock(void) virMutexUnlock(&driver->lock); } -static virFSBackendPtr backends[] = {}; +static virFSBackendPtr backends[] = { +#if WITH_FS_DIR + &virFSBackendDir, +#endif +}; static virFSBackendPtr virFSBackendForType(int type) -- 1.8.3.1

Patch adds general documentation for fspool and tests for directory backend. Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com> --- docs/formatfs.html.in | 206 +++++++++++++++++++++ docs/fspool.html.in | 41 ++++ docs/sitemap.html.in | 4 + tests/Makefile.am | 12 ++ tests/fsitemxml2xmlin/item.xml | 13 ++ tests/fsitemxml2xmlout/item.xml | 13 ++ tests/fsitemxml2xmltest.c | 105 +++++++++++ .../dir-missing-target-path-invalid.xml | 12 ++ tests/fspoolxml2xmlin/fspool-dir.xml | 16 ++ tests/fspoolxml2xmlout/fspool-dir.xml | 16 ++ tests/fspoolxml2xmltest.c | 81 ++++++++ 11 files changed, 519 insertions(+) create mode 100644 docs/formatfs.html.in create mode 100644 docs/fspool.html.in create mode 100644 tests/fsitemxml2xmlin/item.xml create mode 100644 tests/fsitemxml2xmlout/item.xml create mode 100644 tests/fsitemxml2xmltest.c create mode 100644 tests/fspoolschemadata/dir-missing-target-path-invalid.xml create mode 100644 tests/fspoolxml2xmlin/fspool-dir.xml create mode 100644 tests/fspoolxml2xmlout/fspool-dir.xml create mode 100644 tests/fspoolxml2xmltest.c diff --git a/docs/formatfs.html.in b/docs/formatfs.html.in new file mode 100644 index 0000000..b50034c --- /dev/null +++ b/docs/formatfs.html.in @@ -0,0 +1,206 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <body> + <h1>Filesystem pool and item XML format</h1> + + <ul id="toc"></ul> + + <h2><a name="FSPool">Filesystem pool XML</a></h2> + + <p> + Filesystem pools is a facility to manage filesystems. They has a lot in common with + storage pools (nearly the same api and way of managment). However the managment units + are completely different. To avoid the misunderstanding in fspool usage use this XML + description. See <a href="fspool.html">fspool driver page</a> + </p> + + <p> + The root element is named <code>fspool</code>. It has attribute <code>type</code>, + at the moment fspool has only one type <code>dir</code>. It represents fspool that + holds filesystems in subdirectories on a host filesystem. + </p> + + <h3><a name="FSPoolFirst">General metadata</a></h3> + + <pre> + <fspool type="dir"> + <name>virfs</name> + <uuid>4584ee21-db40-4e98-980e-44802c47b62f</uuid> + <allocation>10000000</allocation> + <capacity>50000000</capacity> + <available>40000000</available> + ...</pre> + + <dl> + <dt><code>name</code></dt> + <dd>Providing a name for the fspool which is unique to the host. + This is mandatory when defining a filesystem pool.</dd> + <dt><code>uuid</code></dt> + <dd>Providing an identifier for the fspool which is globally unique. + This is optional when defining a fspool, a UUID will be generated if + omitted.</dd> + <dt><code>allocation</code></dt> + <dd>Providing the total storage allocation for the pool. This value is in bytes. + This is not applicable when creating a fspool.</dd> + <dt><code>capacity</code></dt> + <dd>Providing the total capacity for the fspool. This value is in bytes. This + is not applicable when creating a fspool.</dd> + <dt><code>available</code></dt> + <dd>Providing the free space available for allocating new items + in the fspool. This value is in bytes. This is not applicable when creating a + fspool.</dd> + </dl> + + <h3><a name="FSPoolSource">Source elements</a></h3> + + <p> + A single <code>source</code> element is contained within the top level + <code>fspool</code> element. This tag is used to describe the source of + the fspool. At the moment it is left empty. + </p> + + <h3><a name="FSPoolTarget">Target elements</a></h3> + + <p> + A single <code>target</code> element is contained within the top level + <code>fspool</code> element for all types of fspools (fspool types <code>dir</code>). + This tag is used to describe the mapping of fspool into the host filesystem. + It can contain the following child elements: + </p> + + <pre> + ... + <target> + <path>/path/in/host/fs</path> + <permissions> + <owner>107</owner> + <group>107</group> + <mode>0744</mode> + </permissions> + </target> + </fspool></pre> + + <dl> + <dt><code>path</code></dt> + <dd>Provides the location at which the fspool will be mapped into + the local filesystem namespace, as an absolute path. For a fspool with directory + backend it will be a fully qualified name of the directory in which items + will be created. + </dd> + <dt><code>permissions</code></dt> + <dd> It provides information about the permissions to use for the + final directory when the fspool is built. There are 4 child elements. + The <code>mode</code> element contains the octal permission set. + The <code>mode</code> defaults to 0755 when not provided. + The <code>owner</code> element contains the numeric user ID. + The <code>group</code> element contains the numeric group ID. + If <code>owner</code> or <code>group</code> aren't specified when + creating a directory, the values are inherited from the parent + directory. + </dd> + </dl> + + <h2><a name="FSItem">Item XML</a></h2> + <p> + An item is a directory that holds single filesystem. The filesystem item + XML format is available. + </p> + + <h3><a name="FSItemFirst">General metadata</a></h3> + + <pre> + <item> + <name>item1</name> + <key>/path/to/fspool/</key> + <allocation>0</allocation> + <capacity unit="T">1</capacity> + ...</pre> + + <dl> + <dt><code>name</code></dt> + <dd>Providing a name for the item which is unique to the fspool. + This is mandatory when defining an item.</dd> + <dt><code>key</code></dt> + <dd>Providing an identifier for the item which identifies a + single item. It is impossible to have two distinct keys + identifying a single item. This field cannot be set when creating + an item: it is always generated.</dd> + <dt><code>allocation</code></dt> + <dd>Providing the total storage allocation for the item.</dd> + <dt><code>capacity</code></dt> + <dd>Providing the logical capacity for the item.</dd> + </dl> + + <h3><a name="FsItemTarget">Target elements</a></h3> + + <p> + A single <code>target</code> element is contained within the top level + <code>item</code> element. This tag is used to describe the mapping of + the fspool item into the host filesystem. It can contain the following + child elements: + </p> + + <pre> + ... + <target> + <path>/var/lib/virt/images/sparse.img</path> + <format type='qcow2'/> + <permissions> + <owner>107</owner> + <group>107</group> + <mode>0744</mode> + </permissions> + </target></pre> + + <dl> + <dt><code>permissions</code></dt> + <dd>Provides information about the permissions to use + when creating items. There are 4 child elements. + The <code>mode</code> element contains the octal permission set. + The <code>mode</code> defaults to 0600 when not provided. + The <code>owner</code> element contains the numeric user ID. + The <code>group</code> element contains the numeric group ID. + If <code>owner</code> or <code>group</code> aren't specified when + creating fspool item, the values are inherited from the parent + directory. + </dd> + </dl> + + + <h2><a name="examples">Example configuration</a></h2> + + <p> + Here is an example of fspool and item. + </p> + + <h3><a name="exampleDir">Directory based fspool</a></h3> + + <pre> + <fspool type="dir"> + <name>my_fspool</name> + <source> + </source> + <target> + <path>/my_fspool_dir</path> + </target> + </fspool></pre> + + <h3><a name="exampleItem">Fspool Item</a></h3> + + <pre> + <item> + <name>item1</name> + <allocation>0</allocation> + <capacity unit="T">1</capacity> + <target> + <permissions> + <owner>107</owner> + <group>107</group> + <mode>0744</mode> + </permissions> + </target> + </item></pre> + + </body> +</html> diff --git a/docs/fspool.html.in b/docs/fspool.html.in new file mode 100644 index 0000000..a501ad3 --- /dev/null +++ b/docs/fspool.html.in @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <body> + <h1 >Filesystem Pool Management</h1> + <p> + Libvirt provides filesystems managment on the physical host through + fspools and items. + </p> + <p> + Fspool is the entity that holds filesystems. It has a lot in + common with storage pools and volumes. However, fspool deals with + filesystems and has the only one unit managment type - filesystem. + Single filesystem in fspool is called an item. + </p> + <p> + Libvirt supports the following fspool types: + </p> + <ul> + <li> + <a href="#FSPoolBackendDir">Directory backend</a> + </li> + </ul> + + <h2><a name="FSPoolBackendDir">Fspool with directory backend</a></h2> + <p> + A fspool with a type of <code>dir</code> provides the means to manage + filesystems within a directory on a single host. + </p> + + <h3>Example pool input definition</h3> + <pre> + <fspool type="dir"> + <name>virtfs</name> + <target> + <path>/var/lib/virt/fs</path> + </target> + </fspool></pre> + + </body> +</html> diff --git a/docs/sitemap.html.in b/docs/sitemap.html.in index 757d5aa..31606d1 100644 --- a/docs/sitemap.html.in +++ b/docs/sitemap.html.in @@ -177,6 +177,10 @@ <span>Network filter XML format</span> </li> <li> + <a href="formatfs.html">Filesystem pool</a> + <span>The filesystem pool and filesystem item XML format</span> + </li> + <li> <a href="formatstorage.html">Storage</a> <span>The storage pool and volume XML format</span> </li> diff --git a/tests/Makefile.am b/tests/Makefile.am index 924029a..cf4eb1c 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -351,6 +351,8 @@ test_programs += secretxml2xmltest test_programs += genericxml2xmltest +test_programs += fsitemxml2xmltest fspoolxml2xmltest + if WITH_LINUX test_programs += virusbtest \ virnetdevbandwidthtest \ @@ -873,6 +875,16 @@ interfacexml2xmltest_SOURCES = \ testutils.c testutils.h interfacexml2xmltest_LDADD = $(LDADDS) +fsitemxml2xmltest_SOURCES = \ + fsitemxml2xmltest.c \ + testutils.c testutils.h +fsitemxml2xmltest_LDADD = $(LDADDS) + +fspoolxml2xmltest_SOURCES = \ + fspoolxml2xmltest.c \ + testutils.c testutils.h +fspoolxml2xmltest_LDADD = $(LDADDS) + cputest_SOURCES = \ cputest.c \ testutils.c testutils.h diff --git a/tests/fsitemxml2xmlin/item.xml b/tests/fsitemxml2xmlin/item.xml new file mode 100644 index 0000000..ae1be59 --- /dev/null +++ b/tests/fsitemxml2xmlin/item.xml @@ -0,0 +1,13 @@ +<item> + <name>item1</name> + <key>/var/lib/libvirt/images/fs/item1</key> + <capacity unit='bytes'>0</capacity> + <allocation unit='bytes'>4096</allocation> + <target> + <permissions> + <mode>0600</mode> + <owner>0</owner> + <group>0</group> + </permissions> + </target> +</item> diff --git a/tests/fsitemxml2xmlout/item.xml b/tests/fsitemxml2xmlout/item.xml new file mode 100644 index 0000000..ae1be59 --- /dev/null +++ b/tests/fsitemxml2xmlout/item.xml @@ -0,0 +1,13 @@ +<item> + <name>item1</name> + <key>/var/lib/libvirt/images/fs/item1</key> + <capacity unit='bytes'>0</capacity> + <allocation unit='bytes'>4096</allocation> + <target> + <permissions> + <mode>0600</mode> + <owner>0</owner> + <group>0</group> + </permissions> + </target> +</item> diff --git a/tests/fsitemxml2xmltest.c b/tests/fsitemxml2xmltest.c new file mode 100644 index 0000000..a6fec33 --- /dev/null +++ b/tests/fsitemxml2xmltest.c @@ -0,0 +1,105 @@ +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <sys/types.h> +#include <fcntl.h> + +#include "internal.h" +#include "testutils.h" +#include "fs_conf.h" +#include "testutilsqemu.h" +#include "virstring.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +static int +testCompareXMLToXMLFiles(const char *fspoolxml, const char *inxml, + const char *outxml, unsigned int flags) +{ + char *actual = NULL; + int ret = -1; + virFSPoolDefPtr fspool = NULL; + virFSItemDefPtr dev = NULL; + + if (!(fspool = virFSPoolDefParseFile(fspoolxml))) + goto fail; + + if (!(dev = virFSItemDefParseFile(fspool, inxml, flags))) + goto fail; + + if (!(actual = virFSItemDefFormat(fspool, dev))) + goto fail; + + if (virTestCompareToFile(actual, outxml) < 0) + goto fail; + + ret = 0; + + fail: + VIR_FREE(actual); + virStoragePoolDefFree(fspool); + virFSItemDefFree(dev); + return ret; +} + +struct testInfo { + const char *fspool; + const char *name; + unsigned int flags; +}; + +static int +testCompareXMLToXMLHelper(const void *data) +{ + int result = -1; + const struct testInfo *info = data; + char *fspoolxml = NULL; + char *inxml = NULL; + char *outxml = NULL; + + if (virAsprintf(&fspoolxml, "%s/fspoolxml2xmlin/%s.xml", + abs_srcdir, info->fspool) < 0 || + virAsprintf(&inxml, "%s/fsitemxml2xmlin/%s.xml", + abs_srcdir, info->name) < 0 || + virAsprintf(&outxml, "%s/fsitemxml2xmlout/%s.xml", + abs_srcdir, info->name) < 0) { + goto cleanup; + } + + result = testCompareXMLToXMLFiles(fspoolxml, inxml, outxml, info->flags); + + cleanup: + VIR_FREE(fspoolxml); + VIR_FREE(inxml); + VIR_FREE(outxml); + + return result; +} + + +static int +mymain(void) +{ + int ret = 0; + +#define DO_TEST_FULL(fspool, name, flags) \ + do { \ + struct testInfo info = { fspool, name, flags }; \ + if (virTestRun("FS Item XML-2-XML " name, \ + testCompareXMLToXMLHelper, &info) < 0) \ + ret = -1; \ + } \ + while (0); + +#define DO_TEST(fspool, name) DO_TEST_FULL(fspool, name, 0) + + DO_TEST("fspool-dir", "item"); + + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} + +VIRT_TEST_MAIN(mymain) diff --git a/tests/fspoolschemadata/dir-missing-target-path-invalid.xml b/tests/fspoolschemadata/dir-missing-target-path-invalid.xml new file mode 100644 index 0000000..a52bf49 --- /dev/null +++ b/tests/fspoolschemadata/dir-missing-target-path-invalid.xml @@ -0,0 +1,12 @@ +<fspool type='dir'> + <name>test</name> + <source> + </source> + <target> + <permissions> + <mode>0700</mode> + <owner>-1</owner> + <group>-1</group> + </permissions> + </target> +</fspool> diff --git a/tests/fspoolxml2xmlin/fspool-dir.xml b/tests/fspoolxml2xmlin/fspool-dir.xml new file mode 100644 index 0000000..d1a3f28 --- /dev/null +++ b/tests/fspoolxml2xmlin/fspool-dir.xml @@ -0,0 +1,16 @@ +<fspool type='dir'> + <name>virtfs</name> + <uuid>5584ee21-db40-4e98-980e-44802c47b62f</uuid> + <capacity unit='bytes'>0</capacity> + <allocation unit='bytes'>0</allocation> + <available unit='bytes'>0</available> + <source> + </source> + <target> + <path>///var/////lib/libvirt/fs//</path> + <permissions> + <mode>0700</mode> + <label>some_lable_t</label> + </permissions> + </target> +</fspool> diff --git a/tests/fspoolxml2xmlout/fspool-dir.xml b/tests/fspoolxml2xmlout/fspool-dir.xml new file mode 100644 index 0000000..dbca470 --- /dev/null +++ b/tests/fspoolxml2xmlout/fspool-dir.xml @@ -0,0 +1,16 @@ +<fspool type='dir'> + <name>virtfs</name> + <uuid>5584ee21-db40-4e98-980e-44802c47b62f</uuid> + <capacity unit='bytes'>0</capacity> + <allocation unit='bytes'>0</allocation> + <available unit='bytes'>0</available> + <source> + </source> + <target> + <path>/var/lib/libvirt/fs</path> + <permissions> + <mode>0700</mode> + <label>some_lable_t</label> + </permissions> + </target> +</fspool> diff --git a/tests/fspoolxml2xmltest.c b/tests/fspoolxml2xmltest.c new file mode 100644 index 0000000..7883d65 --- /dev/null +++ b/tests/fspoolxml2xmltest.c @@ -0,0 +1,81 @@ +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <sys/types.h> +#include <fcntl.h> + +#include "internal.h" +#include "testutils.h" +#include "fs_conf.h" +#include "testutilsqemu.h" +#include "virstring.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +static int +testCompareXMLToXMLFiles(const char *inxml, const char *outxml) +{ + char *actual = NULL; + int ret = -1; + virFSPoolDefPtr dev = NULL; + + if (!(dev = virFSPoolDefParseFile(inxml))) + goto fail; + + if (!(actual = virFSPoolDefFormat(dev))) + goto fail; + + if (virTestCompareToFile(actual, outxml) < 0) + goto fail; + + ret = 0; + + fail: + VIR_FREE(actual); + virStoragePoolDefFree(dev); + return ret; +} + +static int +testCompareXMLToXMLHelper(const void *data) +{ + int result = -1; + char *inxml = NULL; + char *outxml = NULL; + + if (virAsprintf(&inxml, "%s/fspoolxml2xmlin/%s.xml", + abs_srcdir, (const char*)data) < 0 || + virAsprintf(&outxml, "%s/fspoolxml2xmlout/%s.xml", + abs_srcdir, (const char*)data) < 0) { + goto cleanup; + } + + result = testCompareXMLToXMLFiles(inxml, outxml); + + cleanup: + VIR_FREE(inxml); + VIR_FREE(outxml); + + return result; +} + +static int +mymain(void) +{ + int ret = 0; + +#define DO_TEST(name) \ + if (virTestRun("FS Pool XML-2-XML " name, \ + testCompareXMLToXMLHelper, (name)) < 0) \ + ret = -1 + + DO_TEST("fspool-dir"); + + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} + +VIRT_TEST_MAIN(mymain) -- 1.8.3.1
participants (2)
-
John Ferlan
-
Olga Krishtal