[libvirt] [PATCH 0/7] fspool: backend directory

Hi everyone, we would like to propose the first implementation of fspool with directory backend. Filesystem pools is a facility to manage filesystems resources similar to how storage pools manages volume resources. Furthermore new API follows storage API closely where it makes sense. 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. The patchset provides 'dir' backend which simply expose directories in some directory in host filesystem. The virsh commands are provided too. So it is ready to play with, just replace 'pool' in xml descriptions and virsh commands to 'fspool' and 'volume' to 'item'. Examle and usage: Define: virsh -c qemu:///system fspool-define-as fs_pool_name dir --target /path/on/host Build virsh -c qemu:///system fspool-build fs_pool_name Start virsh -c qemu:///system fspool-start fs_pool_name Look inside virsh -c qemu:///system fspool-list (--all) fspool_name Fspool called POOL, on the host fs uses /fs_driver to hold items. virsh -c qemu:///system fspool-dumpxml POOL <fspool type='dir'> <name>POOL</name> <uuid>c57c9d7c-b1d5-4c45-ba9c-67f03d4da160</uuid> <capacity unit='bytes'>733722615808</capacity> <allocation unit='bytes'>1331486720</allocation> <available unit='bytes'>534810800128</available> <source> </source> <target> <path>/fs_driver</path> <permissions> <mode>0755</mode> <owner>0</owner> <group>0</group> </permissions> </target> </fspool> virsh -c qemu:///system fspool-info POOL Name: POOL UUID: c57c9d7c-b1d5-4c45-ba9c-67f03d4da160 State: running Persistent: yes Autostart: no autostart Capacity: 683.33 GiB Allocation: 1.24 GiB Available: 498.08 GiB virsh -c qemu+unix:///system item-list POOL Name Path ------------------------------------------------------------------------------ item1 /fs_driver/item1 item10 /fs_driver/item10 item11 /fs_driver/item11 item12 /fs_driver/item12 item15 /fs_driver/item15 Fspool of directory type is some directory on host fs that holds items (subdirs). Example of usage for items: virsh -c vz+unix:///system item-create-as POOL item1 1g - create item virsh -c qemu+unix:///system item-dumpxml item1 POOL <fsitem> <name>item1</name> <key>/fs_driver/item1</key> <source> fspoo ='POOL' </source> <capacity unit='bytes'>0</capacity> <allocation unit='bytes'>0</allocation> <target> <format type='dir'/> </target> </fsitem> virsh -c qemu+unix:///system item-info item1 POOL Name: item1 Type: dir Capacity: 683.33 GiB Allocation: 634.87 MiB Autostart: no autostart Capacity: 683.33 GiB Allocation: 1.24 GiB Available: 498.08 GiB virsh -c qemu+unix:///system item-list POOL Name Path ------------------------------------------------------------------------------ item1 /fs_driver/item1 item10 /fs_driver/item10 item11 /fs_driver/item11 item12 /fs_driver/item12 item15 /fs_driver/item15 Olga Krishtal (7): fspool: introduce filesystem pools API fspool: usual driver based implementation of filesystem pools API fspools: configuration and internal representation fspools: acl support for filesystem pools remote: filesystem pools driver implementation fspool: default implementation of filesystem pools virsh: filesystem pools commands configure.ac | 33 + daemon/Makefile.am | 4 + daemon/libvirtd.c | 10 + daemon/remote.c | 35 + include/libvirt/libvirt-fs.h | 273 +++++ include/libvirt/libvirt.h | 1 + include/libvirt/virterror.h | 8 + po/POTFILES.in | 6 + src/Makefile.am | 46 + src/access/viraccessdriver.h | 12 + src/access/viraccessdrivernop.c | 19 + src/access/viraccessdriverpolkit.c | 47 + src/access/viraccessdriverstack.c | 49 + src/access/viraccessmanager.c | 31 + src/access/viraccessmanager.h | 11 + src/access/viraccessperm.c | 15 +- src/access/viraccessperm.h | 124 +++ src/conf/fs_conf.c | 1624 +++++++++++++++++++++++++++ src/conf/fs_conf.h | 310 ++++++ src/datatypes.c | 154 +++ src/datatypes.h | 94 ++ src/driver-fs.h | 210 ++++ src/driver.h | 3 + src/fs/fs_backend.h | 85 ++ src/fs/fs_backend_dir.c | 334 ++++++ src/fs/fs_backend_dir.h | 8 + src/fs/fs_driver.c | 2164 ++++++++++++++++++++++++++++++++++++ src/fs/fs_driver.h | 10 + src/libvirt-fs.c | 1715 ++++++++++++++++++++++++++++ src/libvirt.c | 28 + src/libvirt_private.syms | 53 + src/libvirt_public.syms | 46 + src/remote/remote_driver.c | 72 +- src/remote/remote_protocol.x | 522 ++++++++- src/rpc/gendispatch.pl | 19 +- src/util/virerror.c | 37 + tools/Makefile.am | 4 + tools/virsh-fspool.c | 1728 ++++++++++++++++++++++++++++ tools/virsh-fspool.h | 36 + tools/virsh-item.c | 1274 +++++++++++++++++++++ tools/virsh-item.h | 37 + tools/virsh.c | 4 + tools/virsh.h | 9 + 43 files changed, 11294 insertions(+), 10 deletions(-) create mode 100644 include/libvirt/libvirt-fs.h 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 tools/virsh-fspool.c create mode 100644 tools/virsh-fspool.h create mode 100644 tools/virsh-item.c create mode 100644 tools/virsh-item.h -- 1.8.3.1

API follows the API of storage pools closely in parts which do not differ for filesystems. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- include/libvirt/libvirt-fs.h | 273 +++++++++++++++++++++++++++++++++++++++++++ include/libvirt/libvirt.h | 1 + 2 files changed, 274 insertions(+) create mode 100644 include/libvirt/libvirt-fs.h diff --git a/include/libvirt/libvirt-fs.h b/include/libvirt/libvirt-fs.h new file mode 100644 index 0000000..4385220 --- /dev/null +++ b/include/libvirt/libvirt-fs.h @@ -0,0 +1,273 @@ +/* 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> + * + * 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_FS_POOL_CREATE_NORMAL = 0, + + /* Create the fspool and perform fspool build without any flags */ + VIR_FS_POOL_CREATE_WITH_BUILD = 1 << 0, + + /* Create the fspool and perform fspool build using the + * exclusive to VIR_FS_POOL_CREATE_WITH_BUILD_NO_OVERWRITE */ + VIR_FS_POOL_CREATE_WITH_BUILD_OVERWRITE = 1 << 1, + + /* Create the pool and perform pool build using the + * VIR_FS_POOL_BUILD_NO_OVERWRITE flag. This is mutually + * exclusive to VIR_FS_POOL_CREATE_WITH_BUILD_OVERWRITE */ + VIR_FS_POOL_CREATE_WITH_BUILD_NO_OVERWRITE = 1 << 2, +} virFsPoolCreateFlags; + +typedef enum { + VIR_FS_POOL_BUILD_NEW = 0, /* Regular build from scratch */ + VIR_FS_POOL_BUILD_NO_OVERWRITE = (1 << 2), /* Do not overwrite existing pool */ + VIR_FS_POOL_BUILD_OVERWRITE = (1 << 3), /* Overwrite data */ +} virFsPoolBuildFlags; + +/** + * virFsPool: + * + * a virFsPool is a private structure representing a fspool + */ +typedef struct _virFsPool 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_FS_POOL_INACTIVE = 0, + VIR_FS_POOL_BUILDING = 1, + VIR_FS_POOL_RUNNING = 2, + +# ifdef VIR_ENUM_SENTINELS + VIR_FS_POOL_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 _virFsItem 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_FS_ITEM_DIR = 0, + VIR_FS_ITEM_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 fsool); + +/* + * List active fspools + */ +int virConnectNumOfFsPools (virConnectPtr conn); +int virConnectListFsPools (virConnectPtr conn, + char **const names, + int maxnames); + +/* + * List inactive fspools + */ +int virConnectNumOfDefinedFsPools(virConnectPtr conn); +int virConnectListDefinedFsPools(virConnectPtr conn, + char **const names, + int maxnames); + + +/* + * 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_FS_POOLS_INACTIVE = 1 << 0, + VIR_CONNECT_LIST_FS_POOLS_ACTIVE = 1 << 1, + + VIR_CONNECT_LIST_FS_POOLS_PERSISTENT = 1 << 2, + VIR_CONNECT_LIST_FS_POOLS_TRANSIENT = 1 << 3, + + VIR_CONNECT_LIST_FS_POOLS_AUTOSTART = 1 << 4, + VIR_CONNECT_LIST_FS_POOLS_NO_AUTOSTART = 1 << 5, + + /* List fspools by type */ + VIR_CONNECT_LIST_FS_POOLS_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 fsool, + unsigned int flags); +int virFsPoolRefresh (virFsPoolPtr fsool, + unsigned int flags); +int virFsPoolUndefine (virFsPoolPtr fsool); +int virFsPoolCreate (virFsPoolPtr pool, + unsigned int flags); +int virFsPoolDestroy (virFsPoolPtr fsool); +int virFsPoolDelete (virFsPoolPtr fsool, + unsigned int flags); +int virFsPoolRefresh (virFsPoolPtr fsool, + unsigned int flags); +int virFsPoolRef (virFsPoolPtr fspool); +int virFsPoolFree (virFsPoolPtr fspool); + +/* + * FsPool information + */ +const char* virFsPoolGetName (virFsPoolPtr fsool); +int virFsPoolGetUUID (virFsPoolPtr fsool, + unsigned char *uuid); +int virFsPoolGetUUIDString (virFsPoolPtr fsool, + char *buf); + +int virFsPoolGetInfo (virFsPoolPtr item, + virFsPoolInfoPtr info); + +char * virFsPoolGetXMLDesc (virFsPoolPtr fsool, + unsigned int flags); +int virFsPoolGetAutostart (virFsPoolPtr pool, + int *autostart); +int virFsPoolSetAutostart (virFsPoolPtr pool, + int autostart); + + +/* + * List/lookup fs items within a fsool + */ +int virFsPoolNumOfItems (virFsPoolPtr fsool); +int virFsPoolListItems (virFsPoolPtr fsool, + char **const names, + int maxnames); +int virFsPoolListAllItems (virFsPoolPtr fsool, + virFsItemPtr **items, + unsigned int flags); + +virConnectPtr virFsItemGetConnect (virFsItemPtr item); + +/* + * Lookup itemumes based on various attributes + */ +virFsItemPtr virFsItemLookupByName (virFsPoolPtr fsool, + 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 fsool, + const char *xmldesc, + unsigned int flags); +virFsItemPtr virFsItemCreateXMLFrom (virFsPoolPtr fsool, + 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 -- 1.8.3.1

On Fri, Aug 19, 2016 at 06:03:29PM +0300, Olga Krishtal wrote:
API follows the API of storage pools closely in parts which do not differ for filesystems.
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- include/libvirt/libvirt-fs.h | 273 +++++++++++++++++++++++++++++++++++++++++++ include/libvirt/libvirt.h | 1 + 2 files changed, 274 insertions(+) create mode 100644 include/libvirt/libvirt-fs.h
diff --git a/include/libvirt/libvirt-fs.h b/include/libvirt/libvirt-fs.h new file mode 100644 index 0000000..4385220 --- /dev/null +++ b/include/libvirt/libvirt-fs.h
+typedef enum { + VIR_FS_POOL_CREATE_NORMAL = 0, + + /* Create the fspool and perform fspool build without any flags */ + VIR_FS_POOL_CREATE_WITH_BUILD = 1 << 0, + + /* Create the fspool and perform fspool build using the + * exclusive to VIR_FS_POOL_CREATE_WITH_BUILD_NO_OVERWRITE */ + VIR_FS_POOL_CREATE_WITH_BUILD_OVERWRITE = 1 << 1, + + /* Create the pool and perform pool build using the + * VIR_FS_POOL_BUILD_NO_OVERWRITE flag. This is mutually + * exclusive to VIR_FS_POOL_CREATE_WITH_BUILD_OVERWRITE */ + VIR_FS_POOL_CREATE_WITH_BUILD_NO_OVERWRITE = 1 << 2, +} virFsPoolCreateFlags;
nitpick, I suggest we use virFSPool, not virFsPool, since 'fs' is an abbreviation and thus normal to capitalize both parts.
+ +typedef enum { + VIR_FS_POOL_BUILD_NEW = 0, /* Regular build from scratch */ + VIR_FS_POOL_BUILD_NO_OVERWRITE = (1 << 2), /* Do not overwrite existing pool */ + VIR_FS_POOL_BUILD_OVERWRITE = (1 << 3), /* Overwrite data */ +} virFsPoolBuildFlags; + +/** + * virFsPool: + * + * a virFsPool is a private structure representing a fspool + */ +typedef struct _virFsPool 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_FS_POOL_INACTIVE = 0, + VIR_FS_POOL_BUILDING = 1, + VIR_FS_POOL_RUNNING = 2, + +# ifdef VIR_ENUM_SENTINELS + VIR_FS_POOL_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 _virFsItem 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_FS_ITEM_DIR = 0, + VIR_FS_ITEM_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 fsool);
No need to copy the crazy whitespace we have in other headers - a single ' ' between return value and function name, is fine and no space at all between function name and '('
+ +/* + * List active fspools + */ +int virConnectNumOfFsPools (virConnectPtr conn); +int virConnectListFsPools (virConnectPtr conn, + char **const names, + int maxnames); + +/* + * List inactive fspools + */ +int virConnectNumOfDefinedFsPools(virConnectPtr conn); +int virConnectListDefinedFsPools(virConnectPtr conn, + char **const names, + int maxnames);
The 4 apis follow our old model for listing objects which we discourage apps from using since they require O(N) API calls and have a designed in race condition. So, I suggest just skip these 4 APis and exclusively rely on the virConnectListAllFsPools API, as we have no need for back compat with old apps for this new stuff.
+ +/* + * 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_FS_POOLS_INACTIVE = 1 << 0, + VIR_CONNECT_LIST_FS_POOLS_ACTIVE = 1 << 1, + + VIR_CONNECT_LIST_FS_POOLS_PERSISTENT = 1 << 2, + VIR_CONNECT_LIST_FS_POOLS_TRANSIENT = 1 << 3, + + VIR_CONNECT_LIST_FS_POOLS_AUTOSTART = 1 << 4, + VIR_CONNECT_LIST_FS_POOLS_NO_AUTOSTART = 1 << 5, + + /* List fspools by type */ + VIR_CONNECT_LIST_FS_POOLS_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 fsool, + unsigned int flags); +int virFsPoolRefresh (virFsPoolPtr fsool, + unsigned int flags); +int virFsPoolUndefine (virFsPoolPtr fsool); +int virFsPoolCreate (virFsPoolPtr pool, + unsigned int flags); +int virFsPoolDestroy (virFsPoolPtr fsool); +int virFsPoolDelete (virFsPoolPtr fsool, + unsigned int flags); +int virFsPoolRefresh (virFsPoolPtr fsool, + unsigned int flags); +int virFsPoolRef (virFsPoolPtr fspool); +int virFsPoolFree (virFsPoolPtr fspool); + +/* + * FsPool information + */ +const char* virFsPoolGetName (virFsPoolPtr fsool); +int virFsPoolGetUUID (virFsPoolPtr fsool, + unsigned char *uuid); +int virFsPoolGetUUIDString (virFsPoolPtr fsool, + char *buf); + +int virFsPoolGetInfo (virFsPoolPtr item, + virFsPoolInfoPtr info); + +char * virFsPoolGetXMLDesc (virFsPoolPtr fsool, + unsigned int flags); +int virFsPoolGetAutostart (virFsPoolPtr pool, + int *autostart); +int virFsPoolSetAutostart (virFsPoolPtr pool, + int autostart); + + +/* + * List/lookup fs items within a fsool + */ +int virFsPoolNumOfItems (virFsPoolPtr fsool); +int virFsPoolListItems (virFsPoolPtr fsool, + char **const names, + int maxnames); +int virFsPoolListAllItems (virFsPoolPtr fsool, + virFsItemPtr **items, + unsigned int flags); + +virConnectPtr virFsItemGetConnect (virFsItemPtr item); + +/* + * Lookup itemumes based on various attributes + */ +virFsItemPtr virFsItemLookupByName (virFsPoolPtr fsool, + 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 fsool, + const char *xmldesc, + unsigned int flags); +virFsItemPtr virFsItemCreateXMLFrom (virFsPoolPtr fsool, + 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);
All this looks fine to me. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 25/08/16 04:00, Daniel P. Berrange wrote:
On Fri, Aug 19, 2016 at 06:03:29PM +0300, Olga Krishtal wrote:
API follows the API of storage pools closely in parts which do not differ for filesystems.
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- include/libvirt/libvirt-fs.h | 273 +++++++++++++++++++++++++++++++++++++++++++ include/libvirt/libvirt.h | 1 + 2 files changed, 274 insertions(+) create mode 100644 include/libvirt/libvirt-fs.h
diff --git a/include/libvirt/libvirt-fs.h b/include/libvirt/libvirt-fs.h new file mode 100644 index 0000000..4385220 --- /dev/null +++ b/include/libvirt/libvirt-fs.h
+typedef enum { + VIR_FS_POOL_CREATE_NORMAL = 0, + + /* Create the fspool and perform fspool build without any flags */ + VIR_FS_POOL_CREATE_WITH_BUILD = 1 << 0, + + /* Create the fspool and perform fspool build using the + * exclusive to VIR_FS_POOL_CREATE_WITH_BUILD_NO_OVERWRITE */ + VIR_FS_POOL_CREATE_WITH_BUILD_OVERWRITE = 1 << 1, + + /* Create the pool and perform pool build using the + * VIR_FS_POOL_BUILD_NO_OVERWRITE flag. This is mutually + * exclusive to VIR_FS_POOL_CREATE_WITH_BUILD_OVERWRITE */ + VIR_FS_POOL_CREATE_WITH_BUILD_NO_OVERWRITE = 1 << 2, +} virFsPoolCreateFlags;
nitpick, I suggest we use virFSPool, not virFsPool, since 'fs' is an abbreviation and thus normal to capitalize both parts.
+ +typedef enum { + VIR_FS_POOL_BUILD_NEW = 0, /* Regular build from scratch */ + VIR_FS_POOL_BUILD_NO_OVERWRITE = (1 << 2), /* Do not overwrite existing pool */ + VIR_FS_POOL_BUILD_OVERWRITE = (1 << 3), /* Overwrite data */ +} virFsPoolBuildFlags; + +/** + * virFsPool: + * + * a virFsPool is a private structure representing a fspool + */ +typedef struct _virFsPool 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_FS_POOL_INACTIVE = 0, + VIR_FS_POOL_BUILDING = 1, + VIR_FS_POOL_RUNNING = 2, + +# ifdef VIR_ENUM_SENTINELS + VIR_FS_POOL_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 _virFsItem 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_FS_ITEM_DIR = 0, + VIR_FS_ITEM_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 fsool); No need to copy the crazy whitespace we have in other headers - a single ' ' between return value and function name, is fine and no space at all between function name and '('
+ +/* + * List active fspools + */ +int virConnectNumOfFsPools (virConnectPtr conn); +int virConnectListFsPools (virConnectPtr conn, + char **const names, + int maxnames); + +/* + * List inactive fspools + */ +int virConnectNumOfDefinedFsPools(virConnectPtr conn); +int virConnectListDefinedFsPools(virConnectPtr conn, + char **const names, + int maxnames); The 4 apis follow our old model for listing objects which we discourage apps from using since they require O(N) API calls and have a designed in race condition.
So, I suggest just skip these 4 APis and exclusively rely on the virConnectListAllFsPools API, as we have no need for back compat with old apps for this new stuff.
+ +/* + * 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_FS_POOLS_INACTIVE = 1 << 0, + VIR_CONNECT_LIST_FS_POOLS_ACTIVE = 1 << 1, + + VIR_CONNECT_LIST_FS_POOLS_PERSISTENT = 1 << 2, + VIR_CONNECT_LIST_FS_POOLS_TRANSIENT = 1 << 3, + + VIR_CONNECT_LIST_FS_POOLS_AUTOSTART = 1 << 4, + VIR_CONNECT_LIST_FS_POOLS_NO_AUTOSTART = 1 << 5, + + /* List fspools by type */ + VIR_CONNECT_LIST_FS_POOLS_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 fsool, + unsigned int flags); +int virFsPoolRefresh (virFsPoolPtr fsool, + unsigned int flags); +int virFsPoolUndefine (virFsPoolPtr fsool); +int virFsPoolCreate (virFsPoolPtr pool, + unsigned int flags); +int virFsPoolDestroy (virFsPoolPtr fsool); +int virFsPoolDelete (virFsPoolPtr fsool, + unsigned int flags); +int virFsPoolRefresh (virFsPoolPtr fsool, + unsigned int flags); +int virFsPoolRef (virFsPoolPtr fspool); +int virFsPoolFree (virFsPoolPtr fspool); + +/* + * FsPool information + */ +const char* virFsPoolGetName (virFsPoolPtr fsool); +int virFsPoolGetUUID (virFsPoolPtr fsool, + unsigned char *uuid); +int virFsPoolGetUUIDString (virFsPoolPtr fsool, + char *buf); + +int virFsPoolGetInfo (virFsPoolPtr item, + virFsPoolInfoPtr info); + +char * virFsPoolGetXMLDesc (virFsPoolPtr fsool, + unsigned int flags); +int virFsPoolGetAutostart (virFsPoolPtr pool, + int *autostart); +int virFsPoolSetAutostart (virFsPoolPtr pool, + int autostart); + + +/* + * List/lookup fs items within a fsool + */ +int virFsPoolNumOfItems (virFsPoolPtr fsool); +int virFsPoolListItems (virFsPoolPtr fsool, + char **const names, + int maxnames); +int virFsPoolListAllItems (virFsPoolPtr fsool, + virFsItemPtr **items, + unsigned int flags); + +virConnectPtr virFsItemGetConnect (virFsItemPtr item); + +/* + * Lookup itemumes based on various attributes + */ +virFsItemPtr virFsItemLookupByName (virFsPoolPtr fsool, + 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 fsool, + const char *xmldesc, + unsigned int flags); +virFsItemPtr virFsItemCreateXMLFrom (virFsPoolPtr fsool, + 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);
All this looks fine to me.
Regards, Daniel
OK

Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- include/libvirt/virterror.h | 8 + po/POTFILES.in | 1 + src/Makefile.am | 3 + src/datatypes.c | 154 ++++ src/datatypes.h | 94 +++ src/driver-fs.h | 210 ++++++ src/driver.h | 1 + src/libvirt-fs.c | 1715 +++++++++++++++++++++++++++++++++++++++++++ src/libvirt_private.syms | 4 + src/libvirt_public.syms | 46 ++ src/util/virerror.c | 37 + 11 files changed, 2273 insertions(+) create mode 100644 src/driver-fs.h create mode 100644 src/libvirt-fs.c diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index 2ec560e..39cddca 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -132,6 +132,8 @@ 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 @@ -315,6 +317,12 @@ typedef enum { VIR_ERR_AUTH_UNAVAILABLE = 94, /* authentication unavailable */ VIR_ERR_NO_SERVER = 95, /* Server was not found */ VIR_ERR_NO_CLIENT = 96, /* Client was not found */ + VIR_ERR_INVALID_FS_POOL = 97, /* invalid fspool object */ + VIR_ERR_INVALID_FS_ITEM = 98, /* invalid fspool object */ + VIR_WAR_NO_FS_POOL = 99, /* failed to start fspool */ + VIR_ERR_NO_FS_POOL = 100, /* fspool not found */ + VIR_ERR_NO_FS_ITEM = 101, /* fstem not found */ + VIR_ERR_FS_ITEM_EXIST = 102, /* fspool item already exists */ } virErrorNumber; /** diff --git a/po/POTFILES.in b/po/POTFILES.in index 25dbc84..af00155 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -67,6 +67,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/Makefile.am b/src/Makefile.am index e2a2128..8fc6582 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -209,6 +209,7 @@ DRIVER_SOURCES = \ driver-secret.h \ driver-state.h \ driver-storage.h \ + driver-fs.h \ driver-stream.h \ internal.h \ $(DATATYPES_SOURCES) \ @@ -225,6 +226,7 @@ DRIVER_SOURCES = \ libvirt-secret.c \ libvirt-storage.c \ libvirt-stream.c \ + libvirt-fs.c \ locking/lock_manager.c locking/lock_manager.h \ locking/lock_driver.h \ locking/lock_driver_nop.h locking/lock_driver_nop.c \ @@ -2401,6 +2403,7 @@ libvirt_setuid_rpc_client_la_SOURCES = \ libvirt-storage.c \ libvirt-stream.c \ libvirt-lxc.c \ + libvirt-fs.c \ $(NULL) libvirt_setuid_rpc_client_la_LDFLAGS = \ diff --git a/src/datatypes.c b/src/datatypes.c index ff0c46f..465a8bf 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; @@ -96,6 +100,8 @@ virDataTypesOnceInit(void) DECLARE_CLASS(virStream); DECLARE_CLASS(virStorageVol); DECLARE_CLASS(virStoragePool); + DECLARE_CLASS(virFsItem); + DECLARE_CLASS(virFsPool); DECLARE_CLASS_LOCKABLE(virAdmConnect); DECLARE_CLASS_LOCKABLE(virAdmConnectCloseCallbackData); @@ -597,7 +603,155 @@ virStorageVolDispose(void *obj) virObjectUnref(vol->conn); } +/** + * virGetFsPool: + * @conn: the hypervisor connection + * @name: pointer to the fs pool 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 storage 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; +} + + +/** + * virFsPoolDispose: + * @obj: the fs pool to release + * + * Unconditionally release all memory associated with fs pool. + * The pool 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 +virFsPoolDispose(void *obj) +{ + virFsPoolPtr fspool = obj; + char uuidstr[VIR_UUID_STRING_BUFLEN]; + + virUUIDFormat(fspool->uuid, uuidstr); + VIR_DEBUG("release fs pool %p %s %s", fspool, fspool->name, uuidstr); + + if (fspool->privateDataFreeFunc) + fspool->privateDataFreeFunc(fspool->privateData); + VIR_FREE(fspool->name); + virObjectUnref(fspool->conn); +} + + +/** + * virGetFsItem: + * @conn: the hypervisor connection + * @pool: 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->fspool, 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; +} + + +/** + * virFsItemDispose: + * @obj: the fsitem to release + * + * Unconditionally release all memory associated with a fsitem. + * The fsitem 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 fsitem = obj; + VIR_DEBUG("release vol %p %s", fsitem, fsitem->name); + + if (fsitem->privateDataFreeFunc) + fsitem->privateDataFreeFunc(fsitem->privateData); + + VIR_FREE(fsitem->key); + VIR_FREE(fsitem->name); + VIR_FREE(fsitem->fspool); + virObjectUnref(fsitem->conn); +} /** * virGetNodeDevice: * @conn: the hypervisor connection diff --git a/src/datatypes.h b/src/datatypes.h index 2b6adb4..6f1f11b 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; @@ -182,6 +184,46 @@ 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_FS_POOL, \ + __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_FS_ITEM, \ + __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_FS_ITEM, \ + __FILE__, __FUNCTION__, __LINE__, \ + __FUNCTION__); \ + goto label; \ + } \ + } while (0) + # define virCheckNodeDeviceReturn(obj, retval) \ do { \ virNodeDevicePtr _node = (obj); \ @@ -457,6 +499,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. @@ -596,6 +639,45 @@ struct _virStorageVol { }; /** +* _virFsPool: +* +* Internal structure associated to a fs pool +*/ +struct _virFsPool { + virObject object; + virConnectPtr conn; /* pointer back to the connection */ + char *name; /* the storage pool external name */ + unsigned char uuid[VIR_UUID_BUFLEN]; /* the storage pool unique identifier */ + + /* Private data pointer which can be used by driver as they wish. + * Cleanup function pointer can be hooked to provide custom cleanup + * operation. + */ + void *privateData; + virFreeCallback privateDataFreeFunc; +}; + +/** +* _virFsItem: +* +* Internal structure associated to a fs pool item +*/ +struct _virFsItem { + virObject object; + virConnectPtr conn; /* pointer back to the connection */ + char *fspool; /* Pool name of owner */ + char *name; /* the storage vol external name */ + char *key; /* unique key for storage vol */ + + /* Private data pointer which can be used by driver as they wish. + * Cleanup function pointer can be hooked to provide custom cleanup + * operation. + */ + void *privateData; + virFreeCallback privateDataFreeFunc; +}; + +/** * _virNodeDevice: * * Internal structure associated with a node device @@ -687,6 +769,18 @@ virStorageVolPtr virGetStorageVol(virConnectPtr conn, const char *key, void *privateData, virFreeCallback freeFunc); +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); + virNodeDevicePtr virGetNodeDevice(virConnectPtr conn, const char *name); virSecretPtr virGetSecret(virConnectPtr conn, diff --git a/src/driver-fs.h b/src/driver-fs.h new file mode 100644 index 0000000..1aecb3c --- /dev/null +++ b/src/driver-fs.h @@ -0,0 +1,210 @@ +/* + * driver-fs.h: entry points for fs drivers + * + * + * 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 +(*virDrvConnectNumOfFsPools)(virConnectPtr conn); + +typedef int +(*virDrvConnectListFsPools)(virConnectPtr conn, + char **const names, + int maxnames); + +typedef int +(*virDrvConnectNumOfDefinedFsPools)(virConnectPtr conn); + +typedef int +(*virDrvConnectListDefinedFsPools)(virConnectPtr conn, + char **const names, + int maxnames); + +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 item, + 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 */ + virDrvConnectNumOfFsPools connectNumOfFsPools; + virDrvConnectListFsPools connectListFsPools; + virDrvConnectNumOfDefinedFsPools connectNumOfDefinedFsPools; + virDrvConnectListDefinedFsPools connectListDefinedFsPools; + 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_STORAGE_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___ diff --git a/src/libvirt-fs.c b/src/libvirt-fs.c new file mode 100644 index 0000000..4432cfd --- /dev/null +++ b/src/libvirt-fs.c @@ -0,0 +1,1715 @@ +/* + * libvirt-fs.c: entry points for virFs{Pool, Item}Ptr APIs + * + * Copyright (C) 2006-2015 Red Hat, Inc. + * + * 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_FS_POOLS_DIR + * VIR_CONNECT_LIST_FS_POOLS_VOLUME + * VIR_CONNECT_LIST_FS_POOLS_NETFS + * + * 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; +} + + +/** + * virConnectNumOfFsPools: + * @conn: pointer to hypervisor connection + * + * Provides the number of active fspools + * + * Returns the number of fspools found, or -1 on error + */ +int +virConnectNumOfFsPools(virConnectPtr conn) +{ + VIR_DEBUG("conn=%p", conn); + + virResetLastError(); + + virCheckConnectReturn(conn, -1); + + if (conn->fsDriver && conn->fsDriver->connectNumOfFsPools) { + int ret; + ret = conn->fsDriver->connectNumOfFsPools(conn); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(conn); + return -1; +} + + +/** + * virConnectListFsPools: + * @conn: pointer to hypervisor connection + * @names: array of char * to fill with fspool names (allocated by caller) + * @maxnames: size of the names array + * + * Provides the list of names of active fspools up to maxnames. + * If there are more than maxnames, the remaining names will be silently + * ignored. + * + * For more control over the results, see virConnectListAllFsPools(). + * + * Returns the number of fspools found or -1 in case of error. Note that + * this command is inherently racy; a fspool can be started between a call to + * virConnectNumOfFsPools() and this call; you are only guaranteed + * that all currently active fspools were listed if the return is less than + * @maxnames. The client must call free() on each returned name. + */ +int +virConnectListFsPools(virConnectPtr conn, + char **const names, + int maxnames) +{ + VIR_DEBUG("conn=%p, names=%p, maxnames=%d", conn, names, maxnames); + + virResetLastError(); + + virCheckConnectReturn(conn, -1); + virCheckNonNullArgGoto(names, error); + virCheckNonNegativeArgGoto(maxnames, error); + + if (conn->fsDriver && conn->fsDriver->connectListFsPools) { + int ret; + ret = conn->fsDriver->connectListFsPools(conn, names, maxnames); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(conn); + return -1; +} + + +/** + * virConnectNumOfDefinedFsPools: + * @conn: pointer to hypervisor connection + * + * Provides the number of inactive fs fspools + * + * Returns the number of fspools found, or -1 on error + */ +int +virConnectNumOfDefinedFsPools(virConnectPtr conn) +{ + VIR_DEBUG("conn=%p", conn); + + virResetLastError(); + + virCheckConnectReturn(conn, -1); + + if (conn->fsDriver && conn->fsDriver->connectNumOfDefinedFsPools) { + int ret; + ret = conn->fsDriver->connectNumOfDefinedFsPools(conn); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(conn); + return -1; +} + + +/** + * virConnectListDefinedFsPools: + * @conn: pointer to hypervisor connection + * @names: array of char * to fill with fspool names (allocated by caller) + * @maxnames: size of the names array + * + * Provides the list of names of inactive fspools up to maxnames. + * If there are more than maxnames, the remaining names will be silently + * ignored. + * + * For more control over the results, see virConnectListAllFsPools(). + * + * Returns the number of names provided in the array or -1 in case of error. + * Note that this command is inherently racy; a fspool can be defined between + * a call to virConnectNumOfDefinedFsPools() and this call; you are only + * guaranteed that all currently defined fspools were listed if the return + * is less than @maxnames. The client must call free() on each returned name. + */ +int +virConnectListDefinedFsPools(virConnectPtr conn, + char **const names, + int maxnames) +{ + VIR_DEBUG("conn=%p, names=%p, maxnames=%d", conn, names, maxnames); + + virResetLastError(); + + virCheckConnectReturn(conn, -1); + virCheckNonNullArgGoto(names, error); + virCheckNonNegativeArgGoto(maxnames, error); + + if (conn->fsDriver && conn->fsDriver->connectListDefinedFsPools) { + int ret; + ret = conn->fsDriver->connectListDefinedFsPools(conn, names, maxnames); + 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_private.syms b/src/libvirt_private.syms index 419c33d..2efaab1 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -979,9 +979,13 @@ virConnectCloseCallbackDataRegister; virConnectCloseCallbackDataUnregister; virDomainClass; virDomainSnapshotClass; +virFsItemClass; +virFsPoolClass; virGetConnect; virGetDomain; virGetDomainSnapshot; +virGetFsItem; +virGetFsPool; virGetInterface; virGetNetwork; virGetNodeDevice; diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index e01604c..7420e40 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -738,6 +738,52 @@ LIBVIRT_2.0.0 { virConnectStoragePoolEventDeregisterAny; virDomainGetGuestVcpus; virDomainSetGuestVcpus; + virFsPoolGetConnect; + virConnectNumOfFsPools; + virConnectNumOfDefinedFsPools; + virConnectListFsPools; + virConnectListDefinedFsPools; + 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_1.3.3; LIBVIRT_2.2.0 { diff --git a/src/util/virerror.c b/src/util/virerror.c index 1177570..b2d1329 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", + "Fs Driver" ) @@ -1394,6 +1395,42 @@ virErrorMsg(virErrorNumber error, const char *info) else errmsg = _("Client not found: %s"); break; + case VIR_ERR_INVALID_FS_POOL: + if (info == NULL) + errmsg = _("invalid fspool poiter in"); + else + errmsg = _("invalid fspool pointer in %s"); + break; + case VIR_ERR_INVALID_FS_ITEM: + if (info == NULL) + errmsg = _("invalid fsitem pointer in"); + else + errmsg = _("invalid fsitem pointer in %s"); + break; + case VIR_WAR_NO_FS_POOL: + if (info == NULL) + errmsg = _("Failed to find a fs driver"); + else + errmsg = _("Failed to find a fs driver: %s"); + break; + case VIR_ERR_NO_FS_POOL: + if (info == NULL) + errmsg = _("Fspool not found"); + else + errmsg = _("Fspool not found: %s"); + break; + case VIR_ERR_NO_FS_ITEM: + if (info == NULL) + errmsg = _("Fspool item not found"); + else + errmsg = _("Fspool item not found: %s"); + break; + case VIR_ERR_FS_ITEM_EXIST: + if (info == NULL) + errmsg = _("Fspool item exists"); + else + errmsg = _("Fspool item exists: %s"); + break; } return errmsg; } -- 1.8.3.1

Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- po/POTFILES.in | 1 + src/Makefile.am | 5 + src/conf/fs_conf.c | 1624 ++++++++++++++++++++++++++++++++++++++++++++++ src/conf/fs_conf.h | 310 +++++++++ src/libvirt_private.syms | 42 ++ 5 files changed, 1982 insertions(+) create mode 100644 src/conf/fs_conf.c create mode 100644 src/conf/fs_conf.h diff --git a/po/POTFILES.in b/po/POTFILES.in index af00155..f4d2f25 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 8fc6582..db69fbb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -397,6 +397,10 @@ CHRDEV_CONF_SOURCES = \ DEVICE_CONF_SOURCES = \ conf/device_conf.c conf/device_conf.h +# FS driver generic impl APIs +FS_CONF_SOURCES = \ + conf/fs_conf.h conf/fs_conf.c + CONF_SOURCES = \ $(NETDEV_CONF_SOURCES) \ $(DOMAIN_CONF_SOURCES) \ @@ -409,6 +413,7 @@ CONF_SOURCES = \ $(NWFILTER_CONF_SOURCES) \ $(NODE_DEVICE_CONF_SOURCES) \ $(STORAGE_CONF_SOURCES) \ + $(FS_CONF_SOURCES) \ $(INTERFACE_CONF_SOURCES) \ $(SECRET_CONF_SOURCES) \ $(CPU_CONF_SOURCES) \ diff --git a/src/conf/fs_conf.c b/src/conf/fs_conf.c new file mode 100644 index 0000000..4906c86 --- /dev/null +++ b/src/conf/fs_conf.c @@ -0,0 +1,1624 @@ +/* + * fs_conf.c: config handling for fs driver + * + */ + +#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_FS_POOL_LAST, + "dir") + +VIR_ENUM_IMPL(virFsItem, + VIR_FS_ITEM_LAST, + "dir") + +/* Flags to indicate mandatory components in the fspool source */ +enum { + VIR_FS_POOL_SOURCE_DIR = (1 << 2), + VIR_FS_POOL_SOURCE_NAME = (1 << 4), + VIR_FS_POOL_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_FS_POOL_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; +} + +static void +virFsSourcePoolDefFree(virFsSourcePoolDefPtr def) +{ + if (!def) + return; + + VIR_FREE(def->pool); + VIR_FREE(def->item); + + VIR_FREE(def); +} + +static void +virFsPermsFree(virFsPermsPtr def) +{ + if (!def) + return; + + VIR_FREE(def->label); + VIR_FREE(def); +} + +static void +virFsSourceClear(virFsSourcePtr def) +{ + if (!def) + return; + + VIR_FREE(def->path); + virFsSourcePoolDefFree(def->srcpool); + VIR_FREE(def->driverName); + virFsPermsFree(def->perms); +} + +void +virFsItemDefFree(virFsItemDefPtr def) +{ + if (!def) + return; + + VIR_FREE(def->name); + VIR_FREE(def->key); + + virFsSourceClear(&def->target); + VIR_FREE(def); +} + +void +virFsPoolSourceClear(virFsPoolSourcePtr source) +{ + if (!source) + return; + + VIR_FREE(source->dir); + VIR_FREE(source->name); + VIR_FREE(source->vendor); + VIR_FREE(source->product); +} + +void +virFsPoolSourceFree(virFsPoolSourcePtr source) +{ + virFsPoolSourceClear(source); + VIR_FREE(source); +} + +void +virFsPoolDefFree(virFsPoolDefPtr def) +{ + if (!def) + return; + + VIR_FREE(def->name); + + virFsPoolSourceClear(&def->source); + + VIR_FREE(def->target.path); + VIR_FREE(def->target.perms.label); + VIR_FREE(def); +} + +void +virFsPoolObjFree(virFsPoolObjPtr obj) +{ + if (!obj) + return; + + virFsPoolObjClearItems(obj); + + virFsPoolDefFree(obj->def); + virFsPoolDefFree(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->vendor = virXPathString("string(./vendor/@name)", 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: + virFsPoolSourceFree(def); + xmlFreeDoc(doc); + xmlXPathFreeContext(xpath_ctxt); + + return ret; +} + +static int +virFsDefParsePerms(xmlXPathContextPtr ctxt, + virFsPermsPtr 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 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_FS_POOL_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_FS_POOL_SOURCE_DIR) { + if (!ret->source.dir) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing storage pool source path")); + goto error; + } + } + if (options->flags & VIR_FS_POOL_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 (virFsDefParsePerms(ctxt, &ret->target.perms, + "./target/permissions") < 0) + goto error; + + cleanup: + VIR_FREE(uuid); + VIR_FREE(type); + VIR_FREE(target_path); + return ret; + + error: + virFsPoolDefFree(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_FS_POOL_SOURCE_DIR) + virBufferEscapeString(buf, "<dir path='%s'/>\n", src->dir); + + if (options->flags & VIR_FS_POOL_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, "<vendor name='%s'/>\n", src->vendor); + 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 (virFsDefParsePerms(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)) { + virFsPoolDefFree(fspool->def); + fspool->def = def; + } else { + virFsPoolDefFree(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); + virFsPoolDefFree(def); + return NULL; + } + + if (!(fspool = virFsPoolObjAssignDef(fspools, def))) { + virFsPoolDefFree(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: + virFsPoolDefFree(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; +} + +virFsPoolSourcePtr +virFsPoolSourceListNewSource(virFsPoolSourceListPtr list) +{ + virFsPoolSourcePtr 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 * +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_FS_POOL_DIR: + if (STREQ(fspool->def->target.path, def->target.path)) + matchfspool = fspool; + break; + + case VIR_FS_POOL_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_FS_POOLS_FILTERS_ACTIVE) && + !((MATCH(VIR_CONNECT_LIST_FS_POOLS_ACTIVE) && + virFsPoolObjIsActive(fspoolobj)) || + (MATCH(VIR_CONNECT_LIST_FS_POOLS_INACTIVE) && + !virFsPoolObjIsActive(fspoolobj)))) + return false; + + /* filter by persistence */ + if (MATCH(VIR_CONNECT_LIST_FS_POOLS_FILTERS_PERSISTENT) && + !((MATCH(VIR_CONNECT_LIST_FS_POOLS_PERSISTENT) && + fspoolobj->configFile) || + (MATCH(VIR_CONNECT_LIST_FS_POOLS_TRANSIENT) && + !fspoolobj->configFile))) + return false; + + /* filter by autostart option */ + if (MATCH(VIR_CONNECT_LIST_FS_POOLS_FILTERS_AUTOSTART) && + !((MATCH(VIR_CONNECT_LIST_FS_POOLS_AUTOSTART) && + fspoolobj->autostart) || + (MATCH(VIR_CONNECT_LIST_FS_POOLS_NO_AUTOSTART) && + !fspoolobj->autostart))) + return false; + + /* filter by fspool type */ + if (MATCH(VIR_CONNECT_LIST_FS_POOLS_FILTERS_POOL_TYPE)) { + if (!(MATCH(VIR_CONNECT_LIST_FS_POOLS_DIR) && + (fspoolobj->def->type == VIR_FS_POOL_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 new file mode 100644 index 0000000..fa8888a --- /dev/null +++ b/src/conf/fs_conf.h @@ -0,0 +1,310 @@ +/* + * fs_conf.h: config handling for fs driver + * + */ + +#ifndef __VIR_FS_CONF_H__ +# define __VIR_FS_CONF_H__ + +# include "internal.h" +# include "virbitmap.h" +# include "virthread.h" +# include "virutil.h" + +# include <libxml/tree.h> + +# define VIR_CONNECT_LIST_FS_POOLS_FILTERS_POOL_TYPE \ + VIR_CONNECT_LIST_FS_POOLS_DIR + +# define VIR_CONNECT_LIST_FS_POOLS_FILTERS_ACTIVE \ + (VIR_CONNECT_LIST_FS_POOLS_ACTIVE | \ + VIR_CONNECT_LIST_FS_POOLS_INACTIVE) + +# define VIR_CONNECT_LIST_FS_POOLS_FILTERS_PERSISTENT \ + (VIR_CONNECT_LIST_FS_POOLS_PERSISTENT | \ + VIR_CONNECT_LIST_FS_POOLS_TRANSIENT) + +# define VIR_CONNECT_LIST_FS_POOLS_FILTERS_AUTOSTART \ + (VIR_CONNECT_LIST_FS_POOLS_AUTOSTART | \ + VIR_CONNECT_LIST_FS_POOLS_NO_AUTOSTART) + +# define VIR_CONNECT_LIST_FS_POOLS_FILTERS_ALL \ + (VIR_CONNECT_LIST_FS_POOLS_FILTERS_ACTIVE | \ + VIR_CONNECT_LIST_FS_POOLS_FILTERS_PERSISTENT | \ + VIR_CONNECT_LIST_FS_POOLS_FILTERS_AUTOSTART | \ + VIR_CONNECT_LIST_FS_POOLS_FILTERS_POOL_TYPE) + +VIR_ENUM_DECL(virFsItem) +VIR_ENUM_DECL(virFs) + +typedef struct _virFsPerms virFsPerms; +typedef virFsPerms *virFsPermsPtr; +struct _virFsPerms { + mode_t mode; + uid_t uid; + gid_t gid; + char *label; +}; + +typedef struct _virFsSourcePoolDef virFsSourcePoolDef; +struct _virFsSourcePoolDef { + char *pool; /* pool name */ + char *item; /* item name */ + int itemtype; /* virFsItemType, internal only */ + int pooltype; /* virFsPoolType internal only */ +}; +typedef virFsSourcePoolDef *virFsSourcePoolDefPtr; + +typedef struct _virFsSource virFsSource; +typedef virFsSource *virFsSourcePtr; + +struct _virFsSource { + int type; /* virFsType */ + char *path; + virFsSourcePoolDefPtr srcpool; + char *driverName; + virFsPermsPtr perms; + unsigned long long capacity; /* in bytes, 0 if unknown */ + unsigned long long allocation; /* in bytes, 0 if unknown */ +}; + +typedef enum { + VIR_FS_POOL_DIR, /* Local directory */ + VIR_FS_POOL_LAST, +} virFsPoolType; + +VIR_ENUM_DECL(virFsPool) + +typedef struct _virFsItemDef virFsItemDef; +typedef virFsItemDef *virFsItemDefPtr; +struct _virFsItemDef { + char *name; + char *key; + int type; /* virFsItemType */ + + bool building; + unsigned int in_use; + + virFsSource target; +}; + +typedef struct _virFsItemDefList virFsItemDefList; +typedef virFsItemDefList *virFsItemDefListPtr; +struct _virFsItemDefList { + size_t count; + virFsItemDefPtr *objs; +}; + +typedef struct _virFsPoolSource virFsPoolSource; +typedef virFsPoolSource *virFsPoolSourcePtr; +struct _virFsPoolSource { + /* An optional (maybe multiple) host(s) */ + + /* Or a directory */ + char *dir; + + /* Or a name */ + char *name; + + /* 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 _virFsPoolTarget virFsPoolTarget; +typedef virFsPoolTarget *virFsPoolTargetPtr; +struct _virFsPoolTarget { + char *path; /* Optional local filesystem mapping */ + virFsPerms perms; /* Default permissions for volumes */ +}; + +typedef struct _virFsPoolDef virFsPoolDef; +typedef virFsPoolDef *virFsPoolDefPtr; +struct _virFsPoolDef { + char *name; + unsigned char uuid[VIR_UUID_BUFLEN]; + int type; /* virFsPoolType */ + + unsigned long long allocation; /* bytes */ + unsigned long long capacity; /* bytes */ + unsigned long long available; /* bytes */ + + virFsPoolSource source; + virFsPoolTarget target; +}; + +typedef struct _virFsPoolObj virFsPoolObj; +typedef virFsPoolObj *virFsPoolObjPtr; + +struct _virFsPoolObj { + virMutex lock; + + char *configFile; + char *autostartLink; + bool active; + int autostart; + unsigned int asyncjobs; + + virFsPoolDefPtr def; + virFsPoolDefPtr 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; + virFsPoolSourcePtr sources; +}; + +typedef bool (*virFsPoolObjListFilter)(virConnectPtr conn, + virFsPoolDefPtr def); + +static inline int +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 virFsPoolSourceClear(virFsPoolSourcePtr source); +void virFsPoolSourceFree(virFsPoolSourcePtr source); +void virFsPoolDefFree(virFsPoolDefPtr def); +void virFsPoolObjFree(virFsPoolObjPtr fspool); +void virFsPoolObjListFree(virFsPoolObjListPtr fspools); +void virFsPoolObjRemove(virFsPoolObjListPtr fspools, + virFsPoolObjPtr fspool); + +virFsPoolSourcePtr +virFsPoolDefParseSourceString(const char *srcSpec, + int fspool_type); +virFsPoolSourcePtr +virFsPoolSourceListNewSource(virFsPoolSourceListPtr list); +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 2efaab1..026543c 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -565,6 +565,48 @@ virDomainConfNWFilterTeardown; virDomainConfVMNWFilterTeardown; +# conf/fs_conf.h +virFsItemDefFindByKey; +virFsItemDefFindByName; +virFsItemDefFindByPath; +virFsItemDefFormat; +virFsItemDefFree; +virFsItemDefParseFile; +virFsItemDefParseNode; +virFsItemDefParseString; +virFsItemTypeFromString; +virFsItemTypeToString; +virFsPoolDefFormat; +virFsPoolDefFree; +virFsPoolDefParseFile; +virFsPoolDefParseNode; +virFsPoolDefParseSourceString; +virFsPoolDefParseString; +virFsPoolLoadAllConfigs; +virFsPoolLoadAllState; +virFsPoolObjAssignDef; +virFsPoolObjClearItems; +virFsPoolObjDeleteDef; +virFsPoolObjFindByName; +virFsPoolObjFindByUUID; +virFsPoolObjIsDuplicate; +virFsPoolObjListExport; +virFsPoolObjListFree; +virFsPoolObjLock; +virFsPoolObjRemove; +virFsPoolObjSaveDef; +virFsPoolObjUnlock; +virFsPoolSaveConfig; +virFsPoolSaveState; +virFsPoolSourceClear; +virFsPoolSourceFindDuplicate; +virFsPoolSourceFree; +virFsPoolSourceListFormat; +virFsPoolSourceListNewSource; +virFsPoolTypeFromString; +virFsPoolTypeToString; + + # conf/interface_conf.h virInterfaceAssignDef; virInterfaceDefFormat; -- 1.8.3.1

On Fri, Aug 19, 2016 at 06:03:31PM +0300, Olga Krishtal wrote:
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- po/POTFILES.in | 1 + src/Makefile.am | 5 + src/conf/fs_conf.c | 1624 ++++++++++++++++++++++++++++++++++++++++++++++ src/conf/fs_conf.h | 310 +++++++++
To go along with this could you create docs/schemas/{fspool,fsitem}.rng schema files, and corresponding docs/formatfs.html.in docs. Finally, we should have tests/fs{pool,item}xml2xmltest.c files which checks that we correctly round-trip the XML docs, with at least one example XML file for each schema.
diff --git a/src/conf/fs_conf.c b/src/conf/fs_conf.c new file mode 100644 index 0000000..4906c86 --- /dev/null +++ b/src/conf/fs_conf.c @@ -0,0 +1,1624 @@ +/* + * fs_conf.c: config handling for fs driver + * + */
Can you add the full LGPLv2+ boilerplate we normally have for files. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 25/08/16 04:07, Daniel P. Berrange wrote:
On Fri, Aug 19, 2016 at 06:03:31PM +0300, Olga Krishtal wrote:
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- po/POTFILES.in | 1 + src/Makefile.am | 5 + src/conf/fs_conf.c | 1624 ++++++++++++++++++++++++++++++++++++++++++++++ src/conf/fs_conf.h | 310 +++++++++ To go along with this could you create docs/schemas/{fspool,fsitem}.rng schema files, and corresponding docs/formatfs.html.in docs.
Finally, we should have tests/fs{pool,item}xml2xmltest.c files which checks that we correctly round-trip the XML docs, with at least one example XML file for each schema. OK
diff --git a/src/conf/fs_conf.c b/src/conf/fs_conf.c new file mode 100644 index 0000000..4906c86 --- /dev/null +++ b/src/conf/fs_conf.c @@ -0,0 +1,1624 @@ +/* + * fs_conf.c: config handling for fs driver + * + */ Can you add the full LGPLv2+ boilerplate we normally have for files.
Regards, Daniel OK

Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/access/viraccessdriver.h | 12 ++++ src/access/viraccessdrivernop.c | 19 ++++++ src/access/viraccessdriverpolkit.c | 47 ++++++++++++++ src/access/viraccessdriverstack.c | 49 +++++++++++++++ src/access/viraccessmanager.c | 31 ++++++++++ src/access/viraccessmanager.h | 11 ++++ src/access/viraccessperm.c | 15 ++++- src/access/viraccessperm.h | 124 +++++++++++++++++++++++++++++++++++++ src/libvirt_private.syms | 6 ++ 9 files changed, 313 insertions(+), 1 deletion(-) diff --git a/src/access/viraccessdriver.h b/src/access/viraccessdriver.h index e3050b6..e0d505e 100644 --- a/src/access/viraccessdriver.h +++ b/src/access/viraccessdriver.h @@ -61,6 +61,16 @@ 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); @@ -83,6 +93,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..1ed8b35 100644 --- a/src/access/viraccessdrivernop.c +++ b/src/access/viraccessdrivernop.c @@ -103,7 +103,24 @@ virAccessDriverNopCheckStorageVol(virAccessManagerPtr manager ATTRIBUTE_UNUSED, return 1; /* Allow */ } +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 +132,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 89bc890..fae3f26 100644 --- a/src/access/viraccessdriverpolkit.c +++ b/src/access/viraccessdriverpolkit.c @@ -385,6 +385,50 @@ virAccessDriverPolkitCheckStorageVol(virAccessManagerPtr manager, virAccessPermStorageVolTypeToString(perm), 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", + virAccessPermStorageVolTypeToString(perm), + attrs); +} virAccessDriver accessDriverPolkit = { .privateDataLen = sizeof(virAccessDriverPolkitPrivate), @@ -399,4 +443,7 @@ 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..c78c321 100644 --- a/src/access/viraccessdriverstack.c +++ b/src/access/viraccessdriverstack.c @@ -267,6 +267,53 @@ 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 +327,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..6882c03 100644 --- a/src/access/viraccessmanager.c +++ b/src/access/viraccessmanager.c @@ -344,3 +344,34 @@ 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..69cddb5 100644 --- a/src/access/viraccessmanager.h +++ b/src/access/viraccessmanager.h @@ -27,6 +27,7 @@ # include "conf/nwfilter_conf.h" # include "conf/node_device_conf.h" # include "conf/storage_conf.h" +# include "conf/fs_conf.h" # include "conf/secret_conf.h" # include "conf/interface_conf.h" # include "access/viraccessperm.h" @@ -86,6 +87,16 @@ 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..5ac7162 100644 --- a/src/access/viraccessperm.c +++ b/src/access/viraccessperm.c @@ -29,7 +29,7 @@ VIR_ENUM_IMPL(virAccessPermConnect, "search_domains", "search_networks", "search_storage_pools", "search_node_devices", "search_interfaces", "search_secrets", - "search_nwfilters", + "search_nwfilters", "search_fs_pools", "detect_storage_pools", "pm_control", "interface_transaction"); @@ -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_FS_POOL_LAST, + "getattr", "read", "write", + "save", "delete", "start", "stop", + "refresh", "search_items", + "format"); + +VIR_ENUM_IMPL(virAccessPermFsItem, + VIR_ACCESS_PERM_FS_ITEM_LAST, + "getattr", "read", "create", "delete", + "format", "data_read", + "data_write"); diff --git a/src/access/viraccessperm.h b/src/access/viraccessperm.h index 1817da7..7a29de5 100644 --- a/src/access/viraccessperm.h +++ b/src/access/viraccessperm.h @@ -67,6 +67,12 @@ typedef enum { VIR_ACCESS_PERM_CONNECT_SEARCH_STORAGE_POOLS, /** + * @desc: List fs pools + * @message: Listing fs pools requires authorization + * @anonymous: 1 + */ + VIR_ACCESS_PERM_CONNECT_SEARCH_FS_POOLS, + /** * @desc: List node devices * @message: Listing node devices requires authorization * @anonymous: 1 @@ -651,6 +657,122 @@ 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_FS_POOL_GETATTR, + + /** + * @desc: Read fs pool + * @message: Reading fs pool configuration requires authorization + * @anonymous: 1 + */ + VIR_ACCESS_PERM_FS_POOL_READ, + + /** + * @desc: Write fs pool + * @message: Writing fs pool configuration requires authorization + */ + VIR_ACCESS_PERM_FS_POOL_WRITE, + + /** + * @desc: Save fs pool + * @message: Saving fs pool configuration requires authorization + */ + VIR_ACCESS_PERM_FS_POOL_SAVE, + + /** + * @desc: Delete fs pool + * @message: Deleting fs pool configuration requires authorization + */ + VIR_ACCESS_PERM_FS_POOL_DELETE, + + /** + * @desc: Start fs pool + * @message: Starting fs pool configuration requires authorization + */ + VIR_ACCESS_PERM_FS_POOL_START, + + /** + * @desc: Stop fs pool + * @message: Stopping fs pool configuration requires authorization + */ + VIR_ACCESS_PERM_FS_POOL_STOP, + + /** + * @desc: Refresh fs pool + * @message: Refreshing fs pool items requires authorization + */ + VIR_ACCESS_PERM_FS_POOL_REFRESH, + + /** + * @desc: List fs pool items + * @message: Listing fs pool items requires authorization + */ + VIR_ACCESS_PERM_FS_POOL_SEARCH_ITEMS, + + /** + * @desc: Format fs pool + * @message: Formatting fs pool data requires authorization + */ + VIR_ACCESS_PERM_FS_POOL_FORMAT, + + VIR_ACCESS_PERM_FS_POOL_LAST +} virAccessPermFsPool; + +typedef enum { + + /** + * @desc: Access fs item + * @message: Acceessing fs item requires authorization + * @anonymous: 1 + */ + VIR_ACCESS_PERM_FS_ITEM_GETATTR, + + /** + * @desc: Read fs item + * @message: Reading fs item configuration requires authorization + * @anonymous: 1 + */ + VIR_ACCESS_PERM_FS_ITEM_READ, + + /** + * @desc: Create fs item + * @message: Creating fs item requires authorization + */ + VIR_ACCESS_PERM_FS_ITEM_CREATE, + + /** + * @desc: Delete fs item + * @message: Deleting fs item requires authorization + */ + VIR_ACCESS_PERM_FS_ITEM_DELETE, + + /** + * @desc: Format fs item + * @message: Formatting fs item data requires authorization + */ + VIR_ACCESS_PERM_FS_ITEM_FORMAT, + + /** + * @desc: Read fs item data + * @message: Reading fs item data requires authorization + */ + VIR_ACCESS_PERM_FS_ITEM_DATA_READ, + + /** + * @desc: Write fs item data + * @message: Writing fs item data requires authorization + */ + VIR_ACCESS_PERM_FS_ITEM_DATA_WRITE, + + VIR_ACCESS_PERM_FS_ITEM_LAST +} virAccessPermFsItem; + VIR_ENUM_DECL(virAccessPermConnect); VIR_ENUM_DECL(virAccessPermDomain); VIR_ENUM_DECL(virAccessPermInterface); @@ -660,5 +782,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 026543c..68150d6 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -8,6 +8,8 @@ # access/viraccessmanager.h virAccessManagerCheckConnect; virAccessManagerCheckDomain; +virAccessManagerCheckFsItem; +virAccessManagerCheckFsPool; virAccessManagerCheckInterface; virAccessManagerCheckNetwork; virAccessManagerCheckNodeDevice; @@ -26,6 +28,10 @@ virAccessPermConnectTypeFromString; virAccessPermConnectTypeToString; virAccessPermDomainTypeFromString; virAccessPermDomainTypeToString; +virAccessPermFsItemTypeFromString; +virAccessPermFsItemTypeToString; +virAccessPermFsPoolTypeFromString; +virAccessPermFsPoolTypeToString; virAccessPermInterfaceTypeFromString; virAccessPermInterfaceTypeToString; virAccessPermNetworkTypeFromString; -- 1.8.3.1

On Fri, Aug 19, 2016 at 06:03:32PM +0300, Olga Krishtal wrote:
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/access/viraccessdriver.h | 12 ++++ src/access/viraccessdrivernop.c | 19 ++++++ src/access/viraccessdriverpolkit.c | 47 ++++++++++++++ src/access/viraccessdriverstack.c | 49 +++++++++++++++ src/access/viraccessmanager.c | 31 ++++++++++ src/access/viraccessmanager.h | 11 ++++ src/access/viraccessperm.c | 15 ++++- src/access/viraccessperm.h | 124 +++++++++++++++++++++++++++++++++++++ src/libvirt_private.syms | 6 ++ 9 files changed, 313 insertions(+), 1 deletion(-)
ACK Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- daemon/libvirtd.c | 10 + daemon/remote.c | 35 +++ src/driver.h | 1 + src/remote/remote_driver.c | 72 +++++- src/remote/remote_protocol.x | 522 ++++++++++++++++++++++++++++++++++++++++++- src/rpc/gendispatch.pl | 19 +- 6 files changed, 650 insertions(+), 9 deletions(-) diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index 95c1b1c..b6d4d80 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 @@ -398,6 +404,7 @@ static void daemonInitialize(void) # ifdef WITH_VZ virDriverLoadModule("vz"); # endif + #else # ifdef WITH_NETWORK networkRegister(); @@ -408,6 +415,9 @@ static void daemonInitialize(void) # ifdef WITH_STORAGE storageRegister(); # endif +# ifdef WITH_FS + fsRegister(); +# endif # ifdef WITH_NODE_DEVICES nodedevRegister(); # endif diff --git a/daemon/remote.c b/daemon/remote.c index 9e75472..bf60246 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_fs_pool(virConnectPtr conn, remote_nonnull_fs_pool fspool); +static virFsItemPtr get_nonnull_fs_item(virConnectPtr conn, remote_nonnull_fs_item 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_fs_pool(remote_nonnull_fs_pool *fspool_dst, virFsPoolPtr fspool_src); +static void make_nonnull_fs_item(remote_nonnull_fs_item *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); @@ -6631,6 +6635,22 @@ get_nonnull_domain_snapshot(virDomainPtr dom, remote_nonnull_domain_snapshot sna return virGetDomainSnapshot(dom, snapshot.name); } +static virFsPoolPtr +get_nonnull_fs_pool(virConnectPtr conn, remote_nonnull_fs_pool fspool) +{ + return virGetFsPool(conn, fspool.name, BAD_CAST fspool.uuid, + NULL, NULL); +} + +static virFsItemPtr +get_nonnull_fs_item(virConnectPtr conn, remote_nonnull_fs_item 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) { @@ -6677,6 +6697,21 @@ make_nonnull_storage_vol(remote_nonnull_storage_vol *vol_dst, virStorageVolPtr v } static void +make_nonnull_fs_pool(remote_nonnull_fs_pool *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_fs_item(remote_nonnull_fs_item *item_dst, virFsItemPtr item_src) +{ + ignore_value(VIR_STRDUP_QUIET(item_dst->fspool, item_src->fspool)); + 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/driver.h b/src/driver.h index fb93083..57ad1f7 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, diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 6637a1d..2aa765c 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_fs_pool(virConnectPtr conn, remote_nonnull_fs_pool fspool); +static virFsItemPtr get_nonnull_fs_item(virConnectPtr conn, remote_nonnull_fs_item 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_fs_pool(remote_nonnull_fs_pool *fspool_dst, virFsPoolPtr fspool_src); +static void make_nonnull_fs_item(remote_nonnull_fs_item *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); @@ -7501,7 +7505,7 @@ remoteDomainGetFSInfo(virDomainPtr dom, if (ret.info.info_len > REMOTE_DOMAIN_FSINFO_MAX) { virReportError(VIR_ERR_INTERNAL_ERROR, - _("Too many mountpoints in fsinfo: %d for limit %d"), + _("Too many mountpoints in = remoteFsinfo: %d for limit %d"), ret.info.info_len, REMOTE_DOMAIN_FSINFO_MAX); goto cleanup; } @@ -7811,6 +7815,19 @@ get_nonnull_storage_vol(virConnectPtr conn, remote_nonnull_storage_vol vol) NULL, NULL); } +static virFsPoolPtr +get_nonnull_fs_pool(virConnectPtr conn, remote_nonnull_fs_pool fspool) +{ + return virGetFsPool(conn, fspool.name, BAD_CAST fspool.uuid, + NULL, NULL); +} + +static virFsItemPtr +get_nonnull_fs_item(virConnectPtr conn, remote_nonnull_fs_item 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) { @@ -7876,6 +7893,21 @@ make_nonnull_storage_vol(remote_nonnull_storage_vol *vol_dst, virStorageVolPtr v } static void +make_nonnull_fs_pool(remote_nonnull_fs_pool *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_fs_item(remote_nonnull_fs_item *item_dst, virFsItemPtr item_src) +{ + item_dst->fspool = item_src->fspool; + 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); @@ -8266,6 +8298,43 @@ static virNWFilterDriver nwfilter_driver = { .connectListAllNWFilters = remoteConnectListAllNWFilters, /* 0.10.2 */ }; +static virFsDriver fs_driver = { + .connectNumOfFsPools = remoteConnectNumOfFsPools, + .connectListFsPools = remoteConnectListFsPools, + .connectNumOfDefinedFsPools = remoteConnectNumOfDefinedFsPools, + .connectListDefinedFsPools = remoteConnectListDefinedFsPools, + .connectListAllFsPools = remoteConnectListAllFsPools, + .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, +}; + static virConnectDriver connect_driver = { .hypervisorDriver = &hypervisor_driver, .interfaceDriver = &interface_driver, @@ -8274,6 +8343,7 @@ static virConnectDriver connect_driver = { .nwfilterDriver = &nwfilter_driver, .secretDriver = &secret_driver, .storageDriver = &storage_driver, + .fsDriver = &fs_driver, }; static virStateDriver state_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index b4fd057..ec4a94e 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_FS_POOL_LIST_MAX = 4096; + +/* Upper limit on lists of fsitems. */ +const REMOTE_FS_ITEM_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_fs_pool { + remote_nonnull_string name; + remote_uuid uuid; +}; + +/* A fsitem which may not be NULL. */ +struct remote_nonnull_fs_item { + 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_fs_pool *remote_fs_pool; +typedef remote_nonnull_fs_item *remote_fs_item; typedef remote_nonnull_node_device *remote_node_device; /* Error message. See <virterror.h> for explanation of fields. */ @@ -1955,6 +1976,230 @@ struct remote_storage_vol_resize_args { unsigned int flags; }; +/* Fs pool calls: */ + +struct remote_connect_num_of_fs_pools_ret { + int num; +}; + +struct remote_connect_list_fs_pools_args { + int maxnames; +}; + +struct remote_connect_list_fs_pools_ret { + remote_nonnull_string names<REMOTE_FS_POOL_LIST_MAX>; /* insert@1 */ +}; + +struct remote_connect_num_of_defined_fs_pools_ret { + int num; +}; + +struct remote_connect_list_defined_fs_pools_args { + int maxnames; +}; + +struct remote_connect_list_defined_fs_pools_ret { + remote_nonnull_string names<REMOTE_FS_POOL_LIST_MAX>; /* insert@1 */ +}; + +struct remote_fs_pool_lookup_by_uuid_args { + remote_uuid uuid; +}; + +struct remote_fs_pool_lookup_by_uuid_ret { + remote_nonnull_fs_pool pool; +}; + +struct remote_fs_pool_lookup_by_name_args { + remote_nonnull_string name; +}; + +struct remote_fs_pool_lookup_by_name_ret { + remote_nonnull_fs_pool fspool; +}; + +struct remote_fs_pool_lookup_by_item_args { + remote_nonnull_fs_item item; +}; + +struct remote_fs_pool_lookup_by_item_ret { + remote_nonnull_fs_pool fspool; +}; + +struct remote_fs_pool_create_xml_args { + remote_nonnull_string xml; + unsigned int flags; +}; + +struct remote_fs_pool_create_xml_ret { + remote_nonnull_fs_pool fspool; +}; + +struct remote_fs_pool_define_xml_args { + remote_nonnull_string xml; + unsigned int flags; +}; + +struct remote_fs_pool_define_xml_ret { + remote_nonnull_fs_pool fspool; +}; + +struct remote_fs_pool_build_args { + remote_nonnull_fs_pool fspool; + unsigned int flags; +}; + +struct remote_fs_pool_undefine_args { + remote_nonnull_fs_pool fspool; +}; + +struct remote_fs_pool_create_args { + remote_nonnull_fs_pool fspool; + unsigned int flags; +}; + +struct remote_fs_pool_destroy_args { + remote_nonnull_fs_pool fspool; +}; +struct remote_fs_pool_delete_args { + remote_nonnull_fs_pool fspool; + unsigned int flags; +}; + +struct remote_fs_pool_get_xml_desc_args { + remote_nonnull_fs_pool fspool; + unsigned int flags; +}; + +struct remote_fs_pool_get_xml_desc_ret { + remote_nonnull_string xml; +}; + +struct remote_fs_pool_get_info_args { + remote_nonnull_fs_pool fspool; +}; + +struct remote_fs_pool_get_info_ret { /* insert@1 */ + unsigned char state; + unsigned hyper capacity; + unsigned hyper allocation; + unsigned hyper available; +}; + +struct remote_fs_pool_get_autostart_args { + remote_nonnull_fs_pool fspool; +}; + +struct remote_fs_pool_get_autostart_ret { + int autostart; +}; + +struct remote_fs_pool_set_autostart_args { + remote_nonnull_fs_pool fspool; + int autostart; +}; + +struct remote_fs_pool_num_of_items_args { + remote_nonnull_fs_pool fspool; +}; + +struct remote_fs_pool_num_of_items_ret { + int num; +}; + +struct remote_fs_pool_list_items_args { + remote_nonnull_fs_pool fspool; + int maxnames; +}; + +struct remote_fs_pool_list_items_ret { + remote_nonnull_string names<REMOTE_FS_ITEM_LIST_MAX>; /* insert@1 */ +}; +struct remote_fs_pool_refresh_args { + remote_nonnull_fs_pool fspool; + unsigned int flags; +}; + +/* Fs item calls: */ + +struct remote_fs_item_lookup_by_name_args { + remote_nonnull_fs_pool fspool; + remote_nonnull_string name; +}; + +struct remote_fs_item_lookup_by_name_ret { + remote_nonnull_fs_item item; +}; + +struct remote_fs_item_lookup_by_key_args { + remote_nonnull_string key; +}; + +struct remote_fs_item_lookup_by_key_ret { + remote_nonnull_fs_item item; +}; + +struct remote_fs_item_lookup_by_path_args { + remote_nonnull_string path; +}; + +struct remote_fs_item_lookup_by_path_ret { + remote_nonnull_fs_item item; +}; + +struct remote_fs_item_create_xml_args { + remote_nonnull_fs_pool fspool; + remote_nonnull_string xml; + unsigned int flags; +}; + +struct remote_fs_item_create_xml_ret { + remote_nonnull_fs_item item; +}; + +struct remote_fs_item_create_xml_from_args { + remote_nonnull_fs_pool fspool; + remote_nonnull_string xml; + remote_nonnull_fs_item cloneitem; + unsigned int flags; +}; + +struct remote_fs_item_create_xml_from_ret { + remote_nonnull_fs_item item; +}; + +struct remote_fs_item_delete_args { + remote_nonnull_fs_item item; + unsigned int flags; +}; + +struct remote_fs_item_get_xml_desc_args { + remote_nonnull_fs_item item; + unsigned int flags; +}; + +struct remote_fs_item_get_xml_desc_ret { + remote_nonnull_string xml; +}; + +struct remote_fs_item_get_info_args { + remote_nonnull_fs_item item; +}; + +struct remote_fs_item_get_info_ret { /* insert@1 */ + char type; + unsigned hyper capacity; + unsigned hyper allocation; +}; + +struct remote_fs_item_get_path_args { + remote_nonnull_fs_item item; +}; + +struct remote_fs_item_get_path_ret { + remote_nonnull_string name; +}; + /* Node driver calls: */ struct remote_node_num_of_devices_args { @@ -2244,7 +2489,21 @@ struct remote_storage_pool_is_persistent_ret { int persistent; }; +struct remote_fs_pool_is_active_args { + remote_nonnull_fs_pool fspool; +}; + +struct remote_fs_pool_is_active_ret { + int active; +}; + +struct remote_fs_pool_is_persistent_args { + remote_nonnull_fs_pool fspool; +}; +struct remote_fs_pool_is_persistent_ret { + int persistent; +}; struct remote_interface_is_active_args { remote_nonnull_interface iface; }; @@ -2874,6 +3133,27 @@ struct remote_storage_pool_list_all_volumes_ret { /* insert@1 */ unsigned int ret; }; +struct remote_connect_list_all_fs_pools_args { + int need_results; + unsigned int flags; +}; + +struct remote_connect_list_all_fs_pools_ret { /* insert@1 */ + remote_nonnull_fs_pool fspools<REMOTE_FS_POOL_LIST_MAX>; + unsigned int ret; +}; + +struct remote_fs_pool_list_all_items_args { + remote_nonnull_fs_pool fspool; + int need_results; + unsigned int flags; +}; + +struct remote_fs_pool_list_all_items_ret { /* insert@1 */ + remote_nonnull_fs_item items<REMOTE_FS_ITEM_LIST_MAX>; + unsigned int ret; +}; + struct remote_connect_list_all_networks_args { int need_results; unsigned int flags; @@ -5923,5 +6203,245 @@ enum remote_procedure { * @generate: both * @acl: none */ - REMOTE_PROC_NODE_DEVICE_EVENT_LIFECYCLE = 376 + REMOTE_PROC_STORAGE_POOL_EVENT_REFRESH = 376, + + /** + * @generate: both + * @priority: high + * @acl: connect:search_fs_pools + * @aclfilter: fs_pool:getattr + */ + REMOTE_PROC_CONNECT_NUM_OF_FS_POOLS = 377, + + /** + * @generate: both + * @priority: high + * @acl: connect:search_fs_pools + * @aclfilter: fs_pool:getattr + */ + REMOTE_PROC_CONNECT_LIST_FS_POOLS = 378, + + /** + * @generate: both + * @priority: high + * @acl: connect:search_fs_pools + * @aclfilter: fs_pool:getattr + */ + REMOTE_PROC_CONNECT_NUM_OF_DEFINED_FS_POOLS = 379, + + /** + * @generate: both + * @priority: high + * @acl: connect:search_fs_pools + * @aclfilter: fs_pool:getattr + */ + REMOTE_PROC_CONNECT_LIST_DEFINED_FS_POOLS = 380, + + /** + * @generate: both + * @acl: fs_pool:start + * @acl: fs_pool:write + */ + REMOTE_PROC_FS_POOL_CREATE_XML = 381, + + /** + * @generate: both + * @priority: high + * @acl: fs_pool:write + * @acl: fs_pool:save + */ + REMOTE_PROC_FS_POOL_DEFINE_XML = 382, + + /** + * @generate: both + * @acl: fs_pool:format + */ + REMOTE_PROC_FS_POOL_BUILD = 383, + + /** + * @generate: both + * @acl: fs_pool:format + */ + REMOTE_PROC_FS_POOL_DELETE = 384, + + /** + * @generate: both + * @priority: high + * @acl: fs_pool:delete + */ + REMOTE_PROC_FS_POOL_UNDEFINE = 385, + + /** + * @generate: both + * @priority: high + * @acl: fs_pool:getattr + */ + REMOTE_PROC_FS_POOL_LOOKUP_BY_NAME = 386, + + /** + * @generate: both + * @priority: high + * @acl: fs_pool:getattr + */ + REMOTE_PROC_FS_POOL_LOOKUP_BY_UUID = 387, + + /** + * @generate: both + * @priority: high + * @acl: fs_pool:getattr + */ + REMOTE_PROC_FS_POOL_LOOKUP_BY_ITEM = 388, + + /** + * @generate: both + * @priority: high + * @acl: fs_pool:read + */ + REMOTE_PROC_FS_POOL_GET_INFO = 389, + + /** + * @generate: both + * @priority: high + * @acl: fs_pool:read + */ + REMOTE_PROC_FS_POOL_GET_XML_DESC = 390, + + /** + * @generate: both + * @priority: high + * @acl: fs_pool:search_items + * @aclfilter: fs_item:getattr + */ + REMOTE_PROC_FS_POOL_NUM_OF_ITEMS = 391, + + /** + * @generate: both + * @priority: high + * @acl: fs_pool:search_items + * @aclfilter: fs_item:getattr + */ + REMOTE_PROC_FS_POOL_LIST_ITEMS = 392, + + /** + * @generate: both + * @acl: fs_item:create + */ + REMOTE_PROC_FS_ITEM_CREATE_XML = 393, + + /** + * @generate: both + * @acl: fs_item:delete + */ + REMOTE_PROC_FS_ITEM_DELETE = 394, + + /** + * @generate: both + * @priority: high + * @acl: fs_item:getattr + */ + REMOTE_PROC_FS_ITEM_LOOKUP_BY_NAME = 395, + + /** + * @generate: both + * @priority: high + * @acl: fs_item:getattr + */ + REMOTE_PROC_FS_ITEM_LOOKUP_BY_KEY = 396, + + /** + * @generate: both + * @priority: high + * @acl: fs_item:getattr + */ + REMOTE_PROC_FS_ITEM_LOOKUP_BY_PATH = 397, + + /** + * @generate: both + * @priority: high + * @acl: fs_item:read + */ + REMOTE_PROC_FS_ITEM_GET_INFO = 398, + + /** + * @generate: both + * @priority: high + * @acl: fs_item:read + */ + REMOTE_PROC_FS_ITEM_GET_XML_DESC = 399, + + /** + * @generate: both + * @priority: high + * @acl: fs_item:read + */ + REMOTE_PROC_FS_ITEM_GET_PATH = 400, + + /** + * @generate: both + * @acl: fs_item:create + */ + REMOTE_PROC_FS_ITEM_CREATE_XML_FROM = 401, + + /** + * @generate: both + * @priority: high + * @acl: connect:search_fs_pools + * @aclfilter: fs_pool:getattr + */ + REMOTE_PROC_CONNECT_LIST_ALL_FS_POOLS = 402, + + /** + * @generate: both + * @priority: high + * @acl: fs_pool:search_items + * @aclfilter: fs_item:getattr + */ + REMOTE_PROC_FS_POOL_LIST_ALL_ITEMS = 403, + + /** + * @generate: both + * @acl: fs_pool:refresh + */ + REMOTE_PROC_FS_POOL_REFRESH = 404, + + /** + * @generate: both + * @priority: high + * @acl: fs_pool:read + */ + REMOTE_PROC_FS_POOL_IS_ACTIVE = 405, + + /** + * @generate: both + * @priority: high + * @acl: fs_pool:read + */ + REMOTE_PROC_FS_POOL_IS_PERSISTENT = 406, + + /** + * @generate: both + * @priority: high + * @acl: fs_pool:read + */ + REMOTE_PROC_FS_POOL_GET_AUTOSTART = 407, + + /** + * @generate: both + * @priority: high + * @acl: fs_pool:write + */ + REMOTE_PROC_FS_POOL_SET_AUTOSTART = 408, + + /** + * @generate: both + * @acl: fs_pool:start + */ + REMOTE_PROC_FS_POOL_CREATE = 409, + + /** + * @generate: both + * @priority: high + * @acl: fs_pool:stop + */ + REMOTE_PROC_FS_POOL_DESTROY = 410 }; diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl index 173189c..171684b 100755 --- a/src/rpc/gendispatch.pl +++ b/src/rpc/gendispatch.pl @@ -500,7 +500,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|fs_pool|fs_item) (\S+);/) { my $type_name = name_to_TypeName($1); push(@vars_list, "vir${type_name}Ptr $2 = NULL"); @@ -665,7 +665,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|fs_pool|fs_item) (\S+)<(\S+)>;/) { $modern_ret_struct_name = $1; $single_ret_list_error_msg_type = $1; $single_ret_list_name = $2; @@ -723,7 +723,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|fs_pool|fs_item) (\S+);/) { my $type_name = name_to_TypeName($1); if ($call->{ProcName} eq "DomainCreateWithFlags") { @@ -1268,7 +1268,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|fs_pool|fs_item) (\S+);/) { my $name = $1; my $arg_name = $2; my $type_name = name_to_TypeName($name); @@ -1461,7 +1461,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|fs_pool|fs_item) (\S+)<(\S+)>;/) { my $proc_name = name_to_TypeName($1); if ($structprefix eq "admin") { @@ -1513,7 +1513,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|fs_pool|fs_item) (\S+);/) { my $name = $1; my $arg_name = $2; my $type_name = name_to_TypeName($name); @@ -1968,7 +1968,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"; @@ -2065,6 +2066,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 +2097,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

On Fri, Aug 19, 2016 at 06:03:33PM +0300, Olga Krishtal wrote:
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- daemon/libvirtd.c | 10 + daemon/remote.c | 35 +++ src/driver.h | 1 + src/remote/remote_driver.c | 72 +++++- src/remote/remote_protocol.x | 522 ++++++++++++++++++++++++++++++++++++++++++- src/rpc/gendispatch.pl | 19 +- 6 files changed, 650 insertions(+), 9 deletions(-)
ACK Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Implementation is backend base as in case of storage pools. This patch adds directory backend which is nothing more than managing directories inside another one as starting point. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- configure.ac | 33 + daemon/Makefile.am | 4 + po/POTFILES.in | 2 + src/Makefile.am | 38 + src/driver.h | 1 + src/fs/fs_backend.h | 85 ++ src/fs/fs_backend_dir.c | 334 +++++++ src/fs/fs_backend_dir.h | 8 + src/fs/fs_driver.c | 2164 ++++++++++++++++++++++++++++++++++++++++++++++ src/fs/fs_driver.h | 10 + src/libvirt.c | 28 + src/libvirt_private.syms | 1 + 12 files changed, 2708 insertions(+) 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 diff --git a/configure.ac b/configure.ac index 8d7d63e..435b1ec 100644 --- a/configure.ac +++ b/configure.ac @@ -1647,6 +1647,35 @@ fi AM_CONDITIONAL([WITH_SECRETS], [test "$with_secrets" = "yes"]) +AC_ARG_WITH([fs-dir], + [AS_HELP_STRING([--with-fs-dir], + [with fs backend for fs driver @<:@default=yes@:>])], + [],[with_fs_dir=yes]) + +if test "$with_libvirtd" = "no"; then + with_fs_dir=no +fi + +if test "$with_fs_dir" = "yes" ; then + AC_DEFINE_UNQUOTED([WITH_FS_DIR], 1, [whether directory backend for fs driver is enabled]) +fi +AM_CONDITIONAL([WITH_FS_DIR], [test "$with_fs_dir" = "yes"]) + +with_fs=no +for backend in dir; do + if eval test \$with_fs_$backend = yes; then + with_fs=yes + break + fi +done +if test $with_fs = yes; then + AC_DEFINE([WITH_FS], [1], + [Define to 1 if at least one fs backend is in use]) +fi +AM_CONDITIONAL([WITH_FS], [test "$with_fs" = "yes"]) + + + AC_ARG_WITH([storage-dir], [AS_HELP_STRING([--with-storage-dir], [with directory backend for the storage driver @<:@default=yes@:>@])], @@ -2760,6 +2789,10 @@ AC_MSG_NOTICE([Sheepdog: $with_storage_sheepdog]) AC_MSG_NOTICE([ Gluster: $with_storage_gluster]) AC_MSG_NOTICE([ ZFS: $with_storage_zfs]) AC_MSG_NOTICE([]) +AC_MSG_NOTICE([Fs Drivers]) +AC_MSG_NOTICE([]) +AC_MSG_NOTICE([ Dir: $with_fs_dir]) +AC_MSG_NOTICE([]) AC_MSG_NOTICE([Security Drivers]) AC_MSG_NOTICE([]) AC_MSG_NOTICE([ SELinux: $with_secdriver_selinux ($SELINUX_MOUNT)]) diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 927d16f..63444cf 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -241,6 +241,10 @@ if WITH_STORAGE libvirtd_LDADD += ../src/libvirt_driver_storage.la endif WITH_STORAGE +if WITH_FS + libvirtd_LDADD += ../src/libvirt_driver_fs.la +endif WITH_FS + if WITH_NETWORK libvirtd_LDADD += ../src/libvirt_driver_network.la endif WITH_NETWORK diff --git a/po/POTFILES.in b/po/POTFILES.in index f4d2f25..0fc3b79 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -59,6 +59,8 @@ 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 src/hyperv/hyperv_wmi.c diff --git a/src/Makefile.am b/src/Makefile.am index db69fbb..6275f9e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -642,6 +642,7 @@ DRIVER_SOURCE_FILES = \ $(REMOTE_DRIVER_SOURCES) \ $(SECRET_DRIVER_SOURCES) \ $(STORAGE_DRIVER_SOURCES) \ + $(FS_DRIVER_SOURCES) \ $(TEST_DRIVER_SOURCES) \ $(UML_DRIVER_SOURCES) \ $(VBOX_DRIVER_SOURCES) \ @@ -662,6 +663,7 @@ STATEFUL_DRIVER_SOURCE_FILES = \ $(QEMU_DRIVER_SOURCES) \ $(SECRET_DRIVER_SOURCES) \ $(STORAGE_DRIVER_SOURCES) \ + $(FS_DRIVER_SOURCES) \ $(UML_DRIVER_SOURCES) \ $(XEN_DRIVER_SOURCES) \ $(NULL) @@ -968,6 +970,14 @@ SECRET_UTIL_SOURCES = \ SECRET_DRIVER_SOURCES = \ secret/secret_driver.h secret/secret_driver.c +# FS pool backend specific impls +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 + # Storage backend specific impls STORAGE_DRIVER_SOURCES = \ storage/storage_driver.h storage/storage_driver.c \ @@ -1631,6 +1641,32 @@ 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) +libvirt_driver_fs_impl_la_SOURCES += $(FS_DRIVER_DIR_SOURCES) +endif WITH_FS + + # Needed to keep automake quiet about conditionals libvirt_driver_storage_impl_la_SOURCES = libvirt_driver_storage_impl_la_CFLAGS = \ @@ -1902,6 +1938,8 @@ EXTRA_DIST += \ $(BHYVE_DRIVER_SOURCES) \ $(NETWORK_DRIVER_SOURCES) \ $(INTERFACE_DRIVER_SOURCES) \ + $(FS_DRIVER_SOURCES) \ + $(FS_DRIVER_DIR_SOURCES) \ $(STORAGE_DRIVER_SOURCES) \ $(STORAGE_DRIVER_FS_SOURCES) \ $(STORAGE_DRIVER_LVM_SOURCES) \ diff --git a/src/driver.h b/src/driver.h index 57ad1f7..6d475f9 100644 --- a/src/driver.h +++ b/src/driver.h @@ -100,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/fs/fs_backend.h b/src/fs/fs_backend.h new file mode 100644 index 0000000..f714b29 --- /dev/null +++ b/src/fs/fs_backend.h @@ -0,0 +1,85 @@ +#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); + +/* FIXME */ + +/* A 'buildItem' backend must remove any volume created on error since + * the storage driver does not distinguish whether the failure is due + * to failure to create the volume, to reserve any space necessary for + * the volume, to get data about the volume, to change it's accessibility, + * etc. This avoids issues arising from a creation failure due to some + * external action which created a volume of the same name that libvirt + * was not aware of between checking the fspool and the create attempt. It + * also avoids extra round trips to just delete a file. + */ +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; + + virFsBackendFindFspoolSources findFspoolSources; + virFsBackendCheckFspool checkFspool; + virFsBackendStartFspool startFspool; + virFsBackendBuildFspool buildFspool; + 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_backend_dir.c b/src/fs/fs_backend_dir.c new file mode 100644 index 0000000..fc08b85 --- /dev/null +++ b/src/fs/fs_backend_dir.c @@ -0,0 +1,334 @@ +#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 "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) +{ + int ret = -1; + char *parent = NULL; + char *p = NULL; + mode_t mode; + unsigned int dir_create_flags; + + virCheckFlags(0, -1); + + if (VIR_STRDUP(parent, fspool->def->target.path) < 0) + goto error; + if (!(p = strrchr(parent, '/'))) { + virReportError(VIR_ERR_INVALID_ARG, + _("path '%s' is not absolute"), + fspool->def->target.path); + goto error; + } + + if (p != parent) { + /* assure all directories in the path prior to the final dir + * exist, with default uid/gid/mode. */ + *p = '\0'; + if (virFileMakePath(parent) < 0) { + virReportSystemError(errno, _("cannot create path '%s'"), + parent); + goto error; + } + } + + dir_create_flags = VIR_DIR_CREATE_ALLOW_EXIST; + mode = fspool->def->target.perms.mode; + + if (mode == (mode_t) -1 && + (!virFileExists(fspool->def->target.path))) + mode = VIR_FS_DEFAULT_POOL_PERM_MODE; + + /* Now create the final dir in the path with the uid/gid/mode + * requested in the config. If the dir already exists, just set + * the perms. */ + if (virDirCreate(fspool->def->target.path, + mode, + fspool->def->target.perms.uid, + fspool->def->target.perms.gid, + dir_create_flags) < 0) + goto error; + + ret = 0; + + error: + VIR_FREE(parent); + return ret; +} + +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_FS_ITEM_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); + + if (rmdir(fspool->def->target.path) < 0) { + virReportSystemError(errno, _("failed to remove fspool '%s'"), + fspool->def->target.path); + return -1; + } + + return 0; + +} +static int +virFsDirItemBuild(virConnectPtr conn ATTRIBUTE_UNUSED, + virFsPoolObjPtr fspool ATTRIBUTE_UNUSED, + virFsItemDefPtr item, + unsigned int flags) +{ + virCheckFlags(0, -1); + + if (item->type == VIR_FS_ITEM_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) +{ + if (strchr(item->name, '/')) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("volume name '%s' cannot contain '/'"), item->name); + return -1; + } + + VIR_FREE(item->target.path); + if (virAsprintf(&item->target.path, "%s/%s", + fspool->def->target.path, + item->name) == -1) + return -1; + + if (virFileExists(item->target.path)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("item target path '%s' already exists"), + item->target.path); + 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_FS_POOL_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..d8ff68f --- /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 new file mode 100644 index 0000000..76aba7a --- /dev/null +++ b/src/fs/fs_driver.c @@ -0,0 +1,2164 @@ +#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 "fdstream.h" +#include "configmake.h" +#include "virstring.h" +#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"); + +static virFsDriverStatePtr driver; + +typedef struct _virFsItemStreamInfo virFsItemStreamInfo; +typedef virFsItemStreamInfo *virFsItemStreamInfoPtr; +struct _virFsItemStreamInfo { + char *fspool_name; + char *item_path; +}; + +static int fsStateCleanup(void); + +static void fsDriverLock(void) +{ + virMutexLock(&driver->lock); +} + +static void fsDriverUnlock(void) +{ + virMutexUnlock(&driver->lock); +} + +static virFsBackendPtr backends[] = { +#if WITH_FS_DIR + &virFsBackendDir, +#endif +}; + +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; +} + +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 virFsItemDefPtr +virFsItemDefFromItem(virFsItemPtr obj, + virFsPoolObjPtr *fspool, + virFsBackendPtr *backend) +{ + virFsItemDefPtr item = NULL; + + *fspool = NULL; + + fsDriverLock(); + *fspool = virFsPoolObjFindByName(&driver->fspools, obj->fspool); + fsDriverUnlock(); + + if (!*fspool) { + virReportError(VIR_ERR_NO_FS_POOL, + _("no fspool with matching name '%s'"), + obj->fspool); + 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_FS_ITEM, + _("no fs item 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 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 + */ +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 virFsPoolObjPtr +virFsPoolObjFromFsPool(virFsPoolPtr fspool) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virFsPoolObjPtr ret; + + fsDriverLock(); + if (!(ret = virFsPoolObjFindByUUID(&driver->fspools, fspool->uuid))) { + virUUIDFormat(fspool->uuid, uuidstr); + virReportError(VIR_ERR_NO_FS_POOL, + _("no fspool with matching uuid '%s' (%s)"), + uuidstr, fspool->name); + } + fsDriverUnlock(); + + return ret; +} + +static int +fsConnectNumOfFsPools(virConnectPtr conn) +{ + size_t i; + int nactive = 0; + + if (virConnectNumOfFsPoolsEnsureACL(conn) < 0) + return -1; + + fsDriverLock(); + for (i = 0; i < driver->fspools.count; i++) { + virFsPoolObjPtr obj = driver->fspools.objs[i]; + virFsPoolObjLock(obj); + if (virConnectNumOfFsPoolsCheckACL(conn, obj->def) && + virFsPoolObjIsActive(obj)) + nactive++; + virFsPoolObjUnlock(obj); + } + fsDriverUnlock(); + + return nactive; +} + +static int +fsConnectListAllFsPools(virConnectPtr conn, + virFsPoolPtr **fspools, + unsigned int flags) +{ + int ret = -1; + + virCheckFlags(VIR_CONNECT_LIST_FS_POOLS_FILTERS_ALL, -1); + + if (virConnectListAllFsPoolsEnsureACL(conn) < 0) + goto cleanup; + + fsDriverLock(); + ret = virFsPoolObjListExport(conn, driver->fspools, fspools, + virConnectListAllFsPoolsCheckACL, + flags); + fsDriverUnlock(); + + cleanup: + return ret; +} + +static int +fsConnectListFsPools(virConnectPtr conn, + char **const names, + int nnames) +{ + int got = 0; + size_t i; + + if (virConnectListFsPoolsEnsureACL(conn) < 0) + return -1; + + fsDriverLock(); + for (i = 0; i < driver->fspools.count && got < nnames; i++) { + virFsPoolObjPtr obj = driver->fspools.objs[i]; + virFsPoolObjLock(obj); + if (virConnectListFsPoolsCheckACL(conn, obj->def) && + virFsPoolObjIsActive(obj)) { + if (VIR_STRDUP(names[got], obj->def->name) < 0) { + virFsPoolObjUnlock(obj); + goto cleanup; + } + got++; + } + virFsPoolObjUnlock(obj); + } + fsDriverUnlock(); + return got; + + cleanup: + fsDriverUnlock(); + for (i = 0; i < got; i++) + VIR_FREE(names[i]); + memset(names, 0, nnames * sizeof(*names)); + return -1; +} + +static int +fsConnectNumOfDefinedFsPools(virConnectPtr conn) +{ + size_t i; + int nactive = 0; + + if (virConnectNumOfDefinedFsPoolsEnsureACL(conn) < 0) + return -1; + + fsDriverLock(); + for (i = 0; i < driver->fspools.count; i++) { + virFsPoolObjPtr obj = driver->fspools.objs[i]; + virFsPoolObjLock(obj); + if (virConnectNumOfDefinedFsPoolsCheckACL(conn, obj->def) && + !virFsPoolObjIsActive(obj)) + nactive++; + virFsPoolObjUnlock(obj); + } + fsDriverUnlock(); + + return nactive; +} + +static int +fsConnectListDefinedFsPools(virConnectPtr conn, + char **const names, + int nnames) +{ + int got = 0; + size_t i; + + if (virConnectListDefinedFsPoolsEnsureACL(conn) < 0) + return -1; + + fsDriverLock(); + for (i = 0; i < driver->fspools.count && got < nnames; i++) { + virFsPoolObjPtr obj = driver->fspools.objs[i]; + virFsPoolObjLock(obj); + if (virConnectListDefinedFsPoolsCheckACL(conn, obj->def) && + !virFsPoolObjIsActive(obj)) { + if (VIR_STRDUP(names[got], obj->def->name) < 0) { + virFsPoolObjUnlock(obj); + goto cleanup; + } + got++; + } + virFsPoolObjUnlock(obj); + } + fsDriverUnlock(); + return got; + + cleanup: + fsDriverUnlock(); + for (i = 0; i < got; i++) + VIR_FREE(names[i]); + memset(names, 0, nnames * sizeof(*names)); + return -1; +} + +static virFsPoolPtr +fsPoolLookupByUUID(virConnectPtr conn, + const unsigned char *uuid) +{ + virFsPoolObjPtr fspool; + virFsPoolPtr ret = NULL; + + fsDriverLock(); + fspool = virFsPoolObjFindByUUID(&driver->fspools, uuid); + fsDriverUnlock(); + + if (!fspool) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(uuid, uuidstr); + virReportError(VIR_ERR_NO_FS_POOL, + _("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 +fsPoolLookupByName(virConnectPtr conn, + const char *name) +{ + virFsPoolObjPtr fspool; + virFsPoolPtr ret = NULL; + + fsDriverLock(); + fspool = virFsPoolObjFindByName(&driver->fspools, name); + fsDriverUnlock(); + + if (!fspool) { + virReportError(VIR_ERR_NO_FS_POOL, + _("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 +fsPoolLookupByItem(virFsItemPtr item) +{ + virFsPoolObjPtr fspool; + virFsPoolPtr ret = NULL; + + fsDriverLock(); + fspool = virFsPoolObjFindByName(&driver->fspools, item->fspool); + fsDriverUnlock(); + + if (!fspool) { + virReportError(VIR_ERR_NO_FS_POOL, + _("no fspool with matching name '%s'"), + item->fspool); + 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, + const char *xml, + unsigned int flags) +{ + virFsPoolDefPtr def; + virFsPoolObjPtr fspool = NULL; + virFsPoolPtr ret = NULL; + virFsBackendPtr backend; + char *stateFile = NULL; + unsigned int build_flags = 0; + + virCheckFlags(VIR_FS_POOL_CREATE_WITH_BUILD | + VIR_FS_POOL_CREATE_WITH_BUILD_OVERWRITE | + VIR_FS_POOL_CREATE_WITH_BUILD_NO_OVERWRITE, NULL); + + VIR_EXCLUSIVE_FLAGS_RET(VIR_FS_POOL_BUILD_OVERWRITE, + VIR_FS_POOL_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_FS_POOL_CREATE_WITH_BUILD_OVERWRITE) + build_flags |= VIR_FS_POOL_BUILD_OVERWRITE; + else if (flags & VIR_FS_POOL_CREATE_WITH_BUILD_NO_OVERWRITE) + build_flags |= VIR_FS_POOL_BUILD_NO_OVERWRITE; + + if (build_flags || + (flags & VIR_FS_POOL_CREATE_WITH_BUILD)) { + 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); + virFsPoolDefFree(def); + if (fspool) + virFsPoolObjUnlock(fspool); + fsDriverUnlock(); + return ret; +} + +static virFsPoolPtr +fsPoolDefineXML(virConnectPtr conn, + const char *xml, + unsigned int flags) +{ + virFsPoolDefPtr def; + virFsPoolObjPtr fspool = NULL; + virFsPoolPtr ret = NULL; + + virCheckFlags(0, NULL); + + fsDriverLock(); + if (!(def = virFsPoolDefParseString(xml))) + goto cleanup; + + if (virFsPoolDefineXMLEnsureACL(conn, def) < 0) + goto cleanup; + + if (virFsPoolObjIsDuplicate(&driver->fspools, def, 0) < 0) + goto cleanup; + + if (virFsPoolSourceFindDuplicate(conn, &driver->fspools, def) < 0) + goto cleanup; + + if (virFsBackendForType(def->type) == NULL) + goto cleanup; + + if (!(fspool = virFsPoolObjAssignDef(&driver->fspools, def))) + goto cleanup; + + if (virFsPoolObjSaveDef(driver, fspool, def) < 0) { + virFsPoolObjRemove(&driver->fspools, fspool); + def = NULL; + fspool = NULL; + goto cleanup; + } + def = NULL; + + VIR_INFO("Defining fspool '%s'", fspool->def->name); + ret = virGetFsPool(conn, fspool->def->name, fspool->def->uuid, + NULL, NULL); + + cleanup: + virFsPoolDefFree(def); + if (fspool) + virFsPoolObjUnlock(fspool); + fsDriverUnlock(); + return ret; +} + +static int +fsPoolCreate(virFsPoolPtr obj, + unsigned int flags) +{ + virFsPoolObjPtr fspool; + virFsBackendPtr backend; + int ret = -1; + char *stateFile = NULL; + unsigned int build_flags = 0; + + virCheckFlags(VIR_FS_POOL_CREATE_WITH_BUILD | + VIR_FS_POOL_CREATE_WITH_BUILD_OVERWRITE | + VIR_FS_POOL_CREATE_WITH_BUILD_NO_OVERWRITE, -1); + + VIR_EXCLUSIVE_FLAGS_RET(VIR_FS_POOL_BUILD_OVERWRITE, + VIR_FS_POOL_BUILD_NO_OVERWRITE, -1); + + if (!(fspool = virFsPoolObjFromFsPool(obj))) + return -1; + + if (virFsPoolCreateEnsureACL(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 already active"), + fspool->def->name); + goto cleanup; + } + + if (backend->buildFspool) { + if (flags & VIR_FS_POOL_CREATE_WITH_BUILD_OVERWRITE) + build_flags |= VIR_FS_POOL_BUILD_OVERWRITE; + else if (flags & VIR_FS_POOL_CREATE_WITH_BUILD_NO_OVERWRITE) + build_flags |= VIR_FS_POOL_BUILD_NO_OVERWRITE; + + if (build_flags || + (flags & VIR_FS_POOL_CREATE_WITH_BUILD)) { + if (backend->buildFspool(obj->conn, fspool, build_flags) < 0) { + virFsPoolObjRemove(&driver->fspools, fspool); + fspool = NULL; + goto cleanup; + } + } + } + + VIR_INFO("Starting up fspool '%s'", fspool->def->name); + if (backend->startFspool && + backend->startFspool(obj->conn, fspool) < 0) + goto cleanup; + + stateFile = virFileBuildPath(driver->stateDir, + fspool->def->name, ".xml"); + + virFsPoolObjClearItems(fspool); + if (!stateFile || virFsPoolSaveState(stateFile, fspool->def) < 0 || + backend->refreshFspool(obj->conn, fspool) < 0) { + if (stateFile) + unlink(stateFile); + goto cleanup; + } + + fspool->active = true; + ret = 0; + + cleanup: + VIR_FREE(stateFile); + if (fspool) + virFsPoolObjUnlock(fspool); + return ret; +} + +static int +fsPoolBuild(virFsPoolPtr obj, + unsigned int flags) +{ + virFsPoolObjPtr fspool; + virFsBackendPtr backend; + int ret = -1; + + virCheckFlags(0, -1); + + if (!(fspool = virFsPoolObjFromFsPool(obj))) + return -1; + + if (virFsPoolBuildEnsureACL(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 already active"), + fspool->def->name); + goto cleanup; + } + + if (backend->buildFspool && + backend->buildFspool(obj->conn, fspool, flags) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virFsPoolObjUnlock(fspool); + return ret; +} + +static int +fsPoolUndefine(virFsPoolPtr obj) +{ + virFsPoolObjPtr fspool; + int ret = -1; + + fsDriverLock(); + if (!(fspool = virFsPoolObjFindByUUID(&driver->fspools, obj->uuid))) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(obj->uuid, uuidstr); + virReportError(VIR_ERR_NO_FS_POOL, + _("no fspool with matching uuid '%s' (%s)"), + uuidstr, obj->name); + goto cleanup; + } + + if (virFsPoolUndefineEnsureACL(obj->conn, fspool->def) < 0) + goto cleanup; + + 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 (virFsPoolObjDeleteDef(fspool) < 0) + goto cleanup; + + 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))); + } + + VIR_FREE(fspool->configFile); + VIR_FREE(fspool->autostartLink); + + VIR_INFO("Undefining fspool '%s'", fspool->def->name); + virFsPoolObjRemove(&driver->fspools, fspool); + fspool = NULL; + ret = 0; + + cleanup: + if (fspool) + virFsPoolObjUnlock(fspool); + fsDriverUnlock(); + return ret; +} + +static int +fsPoolDestroy(virFsPoolPtr obj) +{ + virFsPoolObjPtr fspool; + virFsBackendPtr backend; + char *stateFile = NULL; + int ret = -1; + + fsDriverLock(); + if (!(fspool = virFsPoolObjFindByUUID(&driver->fspools, obj->uuid))) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(obj->uuid, uuidstr); + virReportError(VIR_ERR_NO_FS_POOL, + _("no fspool with matching uuid '%s' (%s)"), + uuidstr, obj->name); + goto cleanup; + } + + if (virFsPoolDestroyEnsureACL(obj->conn, fspool->def) < 0) + goto cleanup; + + 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) { + virFsPoolDefFree(fspool->def); + fspool->def = fspool->newDef; + fspool->newDef = NULL; + } + + ret = 0; + + cleanup: + if (fspool) + virFsPoolObjUnlock(fspool); + fsDriverUnlock(); + return ret; +} + +static int +fsPoolDelete(virFsPoolPtr obj, + unsigned int flags) +{ + virFsPoolObjPtr fspool; + virFsBackendPtr backend; + char *stateFile = NULL; + int ret = -1; + + virCheckFlags(0, -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_FS_POOL, + _("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; + + return 0; +} + + +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_FS_POOL_RUNNING; + else + info->state = VIR_FS_POOL_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_FS_POOL, + _("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_FS_ITEM, + _("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_FS_ITEM, + _("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_FS_ITEM, + _("no fspool item with matching path '%s'"), path); + } else { + virReportError(VIR_ERR_NO_FS_ITEM, + _("no fspool item with matching path '%s' (%s)"), + path, cleanpath); + } + } + + cleanup: + VIR_FREE(cleanpath); + fsDriverUnlock(); + 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_FS_ITEM_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 fs 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->fspool)) { + virFsPoolObjUnlock(fspool); + origpool = virFsPoolObjFindByName(&driver->fspools, vobj->fspool); + virFsPoolObjLock(fspool); + } + fsDriverUnlock(); + if (!fspool) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(obj->uuid, uuidstr); + virReportError(VIR_ERR_NO_FS_POOL, + _("no fs fspool with matching uuid '%s' (%s)"), + uuidstr, obj->name); + goto cleanup; + } + + if (STRNEQ(obj->name, vobj->fspool) && !origpool) { + virReportError(VIR_ERR_NO_FS_POOL, + _("no fs fspool with matching name '%s'"), + vobj->fspool); + goto cleanup; + } + + if (!virFsPoolObjIsActive(fspool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("fs fspool '%s' is not active"), fspool->def->name); + goto cleanup; + } + + if (origpool && !virFsPoolObjIsActive(origpool)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("fs 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_FS_ITEM, + _("no fs item 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, + _("fs item 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", _("fs fspool does not support" + " item creation from an existing item")); + goto cleanup; + } + + if (origitem->building) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("item '%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 fs 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 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 = { + .name = "fs", + .connectNumOfFsPools = fsConnectNumOfFsPools, /* 2.1.0 */ + .connectListFsPools = fsConnectListFsPools, /* 2.1.0 */ + .connectNumOfDefinedFsPools = fsConnectNumOfDefinedFsPools, /* 2.1.0 */ + .connectListDefinedFsPools = fsConnectListDefinedFsPools, /* 2.1.0 */ + .connectListAllFsPools = fsConnectListAllFsPools, /* 2.1.0 */ + .fsPoolLookupByName = fsPoolLookupByName, /* 2.1.0 */ + .fsPoolLookupByUUID = fsPoolLookupByUUID, /* 2.1.0 */ + .fsPoolLookupByItem = fsPoolLookupByItem, /* 2.1.0 */ + .fsPoolCreateXML = fsPoolCreateXML, /* 2.1.0 */ + .fsPoolDefineXML = fsPoolDefineXML, /* 2.1.0 */ + .fsPoolBuild = fsPoolBuild, /* 2.1.0 */ + .fsPoolCreate = fsPoolCreate, /* 2.1.0 */ + .fsPoolUndefine = fsPoolUndefine, /* 2.1.0 */ + .fsPoolDestroy = fsPoolDestroy, /* 2.1.0 */ + .fsPoolDelete = fsPoolDelete, /* 2.1.0 */ + .fsPoolRefresh = fsPoolRefresh, /* 2.1.0 */ + .fsPoolGetInfo = fsPoolGetInfo, /* 2.1.0 */ + .fsPoolGetXMLDesc = fsPoolGetXMLDesc, /* 2.1.0 */ + .fsPoolGetAutostart = fsPoolGetAutostart, /* 2.1.0 */ + .fsPoolSetAutostart = fsPoolSetAutostart, /* 2.1.0 */ + .fsPoolNumOfItems = fsPoolNumOfItems, /* 2.1.0 */ + .fsPoolListItems = fsPoolListItems, /* 2.1.0 */ + .fsPoolListAllItems = fsPoolListAllItems, /* 2.1.0 */ + .fsItemLookupByName = fsItemLookupByName, /* 2.1.0 */ + .fsItemLookupByKey = fsItemLookupByKey, /* 2.1.0 */ + .fsItemLookupByPath = fsItemLookupByPath, /* 2.1.0 */ + .fsItemCreateXML = fsItemCreateXML, /* 2.1.0 */ + .fsItemCreateXMLFrom = fsItemCreateXMLFrom, /* 2.1.0 */ + .fsItemDelete = fsItemDelete, /* 2.1.0 */ + .fsItemGetInfo = fsItemGetInfo, /* 2.1.0 */ + .fsItemGetXMLDesc = fsItemGetXMLDesc, /* 2.1.0 */ + .fsItemGetPath = fsItemGetPath, /* 2.1.0 */ + .fsPoolIsActive = fsPoolIsActive, /* 2.1.0 */ + .fsPoolIsPersistent = fsPoolIsPersistent, /* 2.1.0 */ +}; + + +static virStateDriver stateDriver = { + .name = "fs", + .stateInitialize = fsStateInitialize, + .stateAutoStart = fsStateAutoStart, + .stateCleanup = fsStateCleanup, + .stateReload = fsStateReload, +}; + +int fsRegister(void) +{ + VIR_DEBUG("fsDriver = %p", &fsDriver); + + if (virSetSharedFsDriver(&fsDriver) < 0) + return -1; + + if (virRegisterStateDriver(&stateDriver) < 0) + return -1; + + VIR_DEBUG("fsDriver = %p", &fsDriver); + + 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__ */ diff --git a/src/libvirt.c b/src/libvirt.c index 52462e3..cccebdd 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -116,6 +116,7 @@ static int virStateDriverTabCount; static virNetworkDriverPtr virSharedNetworkDriver; static virInterfaceDriverPtr virSharedInterfaceDriver; static virStorageDriverPtr virSharedStorageDriver; +static virFsDriverPtr virSharedFsDriver; static virNodeDeviceDriverPtr virSharedNodeDeviceDriver; static virSecretDriverPtr virSharedSecretDriver; static virNWFilterDriverPtr virSharedNWFilterDriver; @@ -587,7 +588,30 @@ virSetSharedStorageDriver(virStorageDriverPtr 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; +} /** * virSetSharedNodeDeviceDriver: * @driver: pointer to a device monitor block @@ -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->fsDriver = NULL; if (res == VIR_DRV_OPEN_ERROR) goto failed; diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 68150d6..f504143 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1085,6 +1085,7 @@ virDomainMigratePrepareTunnel3; virDomainMigratePrepareTunnel3Params; virRegisterConnectDriver; virRegisterStateDriver; +virSetSharedFsDriver; virSetSharedInterfaceDriver; virSetSharedNetworkDriver; virSetSharedNodeDeviceDriver; -- 1.8.3.1

On Fri, Aug 19, 2016 at 06:03:34PM +0300, Olga Krishtal wrote:
Implementation is backend base as in case of storage pools. This patch adds directory backend which is nothing more than managing directories inside another one as starting point.
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- configure.ac | 33 + daemon/Makefile.am | 4 + po/POTFILES.in | 2 + src/Makefile.am | 38 + src/driver.h | 1 + src/fs/fs_backend.h | 85 ++ src/fs/fs_backend_dir.c | 334 +++++++ src/fs/fs_backend_dir.h | 8 + src/fs/fs_driver.c | 2164 ++++++++++++++++++++++++++++++++++++++++++++++ src/fs/fs_driver.h | 10 + src/libvirt.c | 28 + src/libvirt_private.syms | 1 + 12 files changed, 2708 insertions(+) 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
diff --git a/configure.ac b/configure.ac index 8d7d63e..435b1ec 100644 --- a/configure.ac +++ b/configure.ac @@ -1647,6 +1647,35 @@ fi AM_CONDITIONAL([WITH_SECRETS], [test "$with_secrets" = "yes"])
+AC_ARG_WITH([fs-dir], + [AS_HELP_STRING([--with-fs-dir], + [with fs backend for fs driver @<:@default=yes@:>])], + [],[with_fs_dir=yes]) + +if test "$with_libvirtd" = "no"; then + with_fs_dir=no +fi + +if test "$with_fs_dir" = "yes" ; then + AC_DEFINE_UNQUOTED([WITH_FS_DIR], 1, [whether directory backend for fs driver is enabled]) +fi +AM_CONDITIONAL([WITH_FS_DIR], [test "$with_fs_dir" = "yes"]) + +with_fs=no +for backend in dir; do + if eval test \$with_fs_$backend = yes; then + with_fs=yes + break + fi +done +if test $with_fs = yes; then + AC_DEFINE([WITH_FS], [1], + [Define to 1 if at least one fs backend is in use]) +fi +AM_CONDITIONAL([WITH_FS], [test "$with_fs" = "yes"]) + +
Lets have all this in a separate m4/virt-fspool.m4 file and just call it via a macro LIBVIRT_FS_POOL_CHECK
+ AC_ARG_WITH([storage-dir], [AS_HELP_STRING([--with-storage-dir], [with directory backend for the storage driver @<:@default=yes@:>@])], @@ -2760,6 +2789,10 @@ AC_MSG_NOTICE([Sheepdog: $with_storage_sheepdog]) AC_MSG_NOTICE([ Gluster: $with_storage_gluster]) AC_MSG_NOTICE([ ZFS: $with_storage_zfs]) AC_MSG_NOTICE([]) +AC_MSG_NOTICE([Fs Drivers]) +AC_MSG_NOTICE([]) +AC_MSG_NOTICE([ Dir: $with_fs_dir]) +AC_MSG_NOTICE([])
Likewise move this and call it via LIBVIRT_FS_POOL_RESULT
AC_MSG_NOTICE([Security Drivers]) AC_MSG_NOTICE([]) AC_MSG_NOTICE([ SELinux: $with_secdriver_selinux ($SELINUX_MOUNT)])
Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 25/08/16 04:12, Daniel P. Berrange wrote:
On Fri, Aug 19, 2016 at 06:03:34PM +0300, Olga Krishtal wrote:
Implementation is backend base as in case of storage pools. This patch adds directory backend which is nothing more than managing directories inside another one as starting point.
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- configure.ac | 33 + daemon/Makefile.am | 4 + po/POTFILES.in | 2 + src/Makefile.am | 38 + src/driver.h | 1 + src/fs/fs_backend.h | 85 ++ src/fs/fs_backend_dir.c | 334 +++++++ src/fs/fs_backend_dir.h | 8 + src/fs/fs_driver.c | 2164 ++++++++++++++++++++++++++++++++++++++++++++++ src/fs/fs_driver.h | 10 + src/libvirt.c | 28 + src/libvirt_private.syms | 1 + 12 files changed, 2708 insertions(+) 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
diff --git a/configure.ac b/configure.ac index 8d7d63e..435b1ec 100644 --- a/configure.ac +++ b/configure.ac @@ -1647,6 +1647,35 @@ fi AM_CONDITIONAL([WITH_SECRETS], [test "$with_secrets" = "yes"])
+AC_ARG_WITH([fs-dir], + [AS_HELP_STRING([--with-fs-dir], + [with fs backend for fs driver @<:@default=yes@:>])], + [],[with_fs_dir=yes]) + +if test "$with_libvirtd" = "no"; then + with_fs_dir=no +fi + +if test "$with_fs_dir" = "yes" ; then + AC_DEFINE_UNQUOTED([WITH_FS_DIR], 1, [whether directory backend for fs driver is enabled]) +fi +AM_CONDITIONAL([WITH_FS_DIR], [test "$with_fs_dir" = "yes"]) + +with_fs=no +for backend in dir; do + if eval test \$with_fs_$backend = yes; then + with_fs=yes + break + fi +done +if test $with_fs = yes; then + AC_DEFINE([WITH_FS], [1], + [Define to 1 if at least one fs backend is in use]) +fi +AM_CONDITIONAL([WITH_FS], [test "$with_fs" = "yes"]) + +
Lets have all this in a separate m4/virt-fspool.m4 file and just call it via a macro LIBVIRT_FS_POOL_CHECK
+ AC_ARG_WITH([storage-dir], [AS_HELP_STRING([--with-storage-dir], [with directory backend for the storage driver @<:@default=yes@:>@])], @@ -2760,6 +2789,10 @@ AC_MSG_NOTICE([Sheepdog: $with_storage_sheepdog]) AC_MSG_NOTICE([ Gluster: $with_storage_gluster]) AC_MSG_NOTICE([ ZFS: $with_storage_zfs]) AC_MSG_NOTICE([]) +AC_MSG_NOTICE([Fs Drivers]) +AC_MSG_NOTICE([]) +AC_MSG_NOTICE([ Dir: $with_fs_dir]) +AC_MSG_NOTICE([]) Likewise move this and call it via LIBVIRT_FS_POOL_RESULT
AC_MSG_NOTICE([Security Drivers]) AC_MSG_NOTICE([]) AC_MSG_NOTICE([ SELinux: $with_secdriver_selinux ($SELINUX_MOUNT)])
Regards, Daniel
OK

Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- po/POTFILES.in | 2 + tools/Makefile.am | 4 + tools/virsh-fspool.c | 1728 ++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh-fspool.h | 36 ++ tools/virsh-item.c | 1274 +++++++++++++++++++++++++++++++++++++ tools/virsh-item.h | 37 ++ tools/virsh.c | 4 + tools/virsh.h | 9 + 8 files changed, 3094 insertions(+) create mode 100644 tools/virsh-fspool.c create mode 100644 tools/virsh-fspool.h create mode 100644 tools/virsh-item.c create mode 100644 tools/virsh-item.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 0fc3b79..7f8cdfa 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-item.c tools/virsh-network.c tools/virsh-nodedev.c tools/virsh-nwfilter.c diff --git a/tools/Makefile.am b/tools/Makefile.am index a01c58d..a55550f 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -71,6 +71,8 @@ EXTRA_DIST = \ virsh-nwfilter.c virsh-pool.c \ virsh-secret.c virsh-snapshot.c \ virsh-volume.c \ + virsh-fspool.c \ + virsh-item.c \ $(PODFILES) \ $(MANINFILES) \ $(NULL) @@ -205,9 +207,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-item.c virsh-item.h \ $(NULL) virsh_LDFLAGS = \ diff --git a/tools/virsh-fspool.c b/tools/virsh-fspool.c new file mode 100644 index 0000000..820c1c7 --- /dev/null +++ b/tools/virsh-fspool.c @@ -0,0 +1,1728 @@ +/* + * virsh-fspool.c: Commands to manage fspool + */ + +#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_FS_POOL_FULL \ + VIRSH_COMMON_OPT_FS_POOL(N_("fspool name or uuid")) \ + +#define VIRSH_COMMON_OPT_FS_POOL_BUILD \ + {.name = "build", \ + .type = VSH_OT_BOOL, \ + .flags = 0, \ + .help = N_("build the fspool as normal") \ + } \ + +#define VIRSH_COMMON_OPT_FS_POOL_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_FS_POOL_OVERWRITE \ + {.name = "overwrite", \ + .type = VSH_OT_BOOL, \ + .flags = 0, \ + .help = N_("overwrite any existing data") \ + } \ + +#define VIRSH_COMMON_OPT_FS_POOL_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_FS_POOL_BUILD, + VIRSH_COMMON_OPT_FS_POOL_NO_OVERWRITE, + VIRSH_COMMON_OPT_FS_POOL_OVERWRITE, + + {.name = NULL} +}; + +static bool +cmdFsPoolCreate(vshControl *ctl, const vshCmd *cmd) +{ + virFsPoolPtr fspool; + const char *from = NULL; + bool ret = true; + char *buffer; + bool build; + bool overwrite; + bool no_overwrite; + unsigned int flags = 0; + virshControlPtr priv = ctl->privData; + + if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0) + return false; + + build = vshCommandOptBool(cmd, "build"); + overwrite = vshCommandOptBool(cmd, "overwrite"); + no_overwrite = vshCommandOptBool(cmd, "no-overwrite"); + + VSH_EXCLUSIVE_OPTIONS_EXPR("overwrite", overwrite, + "no-overwrite", no_overwrite); + + if (build) + flags |= VIR_FS_POOL_CREATE_WITH_BUILD; + if (overwrite) + flags |= VIR_FS_POOL_CREATE_WITH_BUILD_OVERWRITE; + if (no_overwrite) + flags |= VIR_FS_POOL_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_FS_POOL_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_FS_POOL_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_FS_POOL_X_AS, + VIRSH_COMMON_OPT_FS_POOL_BUILD, + VIRSH_COMMON_OPT_FS_POOL_NO_OVERWRITE, + VIRSH_COMMON_OPT_FS_POOL_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 build; + bool overwrite; + bool no_overwrite; + unsigned int flags = 0; + virshControlPtr priv = ctl->privData; + + build = vshCommandOptBool(cmd, "build"); + overwrite = vshCommandOptBool(cmd, "overwrite"); + no_overwrite = vshCommandOptBool(cmd, "no-overwrite"); + + VSH_EXCLUSIVE_OPTIONS_EXPR("overwrite", overwrite, + "no-overwrite", no_overwrite); + + if (build) + flags |= VIR_FS_POOL_CREATE_WITH_BUILD; + if (overwrite) + flags |= VIR_FS_POOL_CREATE_WITH_BUILD_OVERWRITE; + if (no_overwrite) + flags |= VIR_FS_POOL_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_FS_POOL_FULL, + VIRSH_COMMON_OPT_FS_POOL_NO_OVERWRITE, + VIRSH_COMMON_OPT_FS_POOL_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_FS_POOL_BUILD_NO_OVERWRITE; + + if (vshCommandOptBool(cmd, "overwrite")) + flags |= VIR_FS_POOL_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_FS_POOL_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_FS_POOL_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_FS_POOL_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_FS_POOL_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)); + size_t i; + int ret; + char **names = NULL; + virFsPoolPtr fspool; + bool success = false; + size_t deleted = 0; + int persistent; + int autostart; + int nActivePools = 0; + int nInactivePools = 0; + int nAllPools = 0; + virshControlPtr priv = ctl->privData; + + /* try the list with flags support (0.10.2 and later) */ + if ((ret = virConnectListAllFsPools(priv->conn, + &list->fspools, + flags)) >= 0) { + list->nfspools = ret; + goto finished; + } + + /* check if the command is actually supported */ + if (last_error && last_error->code == VIR_ERR_NO_SUPPORT) + goto fallback; + + if (last_error && last_error->code == VIR_ERR_INVALID_ARG) { + /* try the new API again but mask non-guaranteed flags */ + unsigned int newflags = flags & (VIR_CONNECT_LIST_FS_POOLS_ACTIVE | + VIR_CONNECT_LIST_FS_POOLS_INACTIVE); + vshResetLibvirtError(); + if ((ret = virConnectListAllFsPools(priv->conn, &list->fspools, + newflags)) >= 0) { + list->nfspools = ret; + goto filter; + } + } + + /* there was an error during the first or second call */ + vshError(ctl, "%s", _("Failed to list fspools")); + goto cleanup; + + + fallback: + /* fall back to old method (0.10.1 and older) */ + vshResetLibvirtError(); + + /* There is no way to get the fspool type */ + if (VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_FILTERS_POOL_TYPE)) { + vshError(ctl, "%s", _("Filtering using --type is not supported " + "by this libvirt")); + goto cleanup; + } + + /* Get the number of active fspools */ + if (!VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_FILTERS_ACTIVE) || + VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_ACTIVE)) { + if ((nActivePools = virConnectNumOfFsPools(priv->conn)) < 0) { + vshError(ctl, "%s", _("Failed to get the number of active fspools ")); + goto cleanup; + } + } + + /* Get the number of inactive fspools */ + if (!VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_FILTERS_ACTIVE) || + VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_INACTIVE)) { + if ((nInactivePools = virConnectNumOfDefinedFsPools(priv->conn)) < 0) { + vshError(ctl, "%s", _("Failed to get the number of inactive fspools")); + goto cleanup; + } + } + + nAllPools = nActivePools + nInactivePools; + + if (nAllPools == 0) + return list; + + names = vshMalloc(ctl, sizeof(char *) * nAllPools); + + /* Retrieve a list of active storage fspool names */ + if (!VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_FILTERS_ACTIVE) || + VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_ACTIVE)) { + if (virConnectListFsPools(priv->conn, + names, nActivePools) < 0) { + vshError(ctl, "%s", _("Failed to list active fspools")); + goto cleanup; + } + } + + /* Add the inactive storage fspools to the end of the name list */ + if (!VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_FILTERS_ACTIVE) || + VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_ACTIVE)) { + if (virConnectListDefinedFsPools(priv->conn, + &names[nActivePools], + nInactivePools) < 0) { + vshError(ctl, "%s", _("Failed to list inactive fspools")); + goto cleanup; + } + } + + list->fspools = vshMalloc(ctl, sizeof(virFsPoolPtr) * (nAllPools)); + list->nfspools = 0; + + /* get active fspools */ + for (i = 0; i < nActivePools; i++) { + if (!(fspool = virFsPoolLookupByName(priv->conn, names[i]))) + continue; + list->fspools[list->nfspools++] = fspool; + } + + /* get inactive fspools */ + for (i = 0; i < nInactivePools; i++) { + if (!(fspool = virFsPoolLookupByName(priv->conn, names[i]))) + continue; + list->fspools[list->nfspools++] = fspool; + } + + /* truncate fspools that weren't found */ + deleted = nAllPools - list->nfspools; + + filter: + /* filter list the list if the list was acquired by fallback means */ + for (i = 0; i < list->nfspools; i++) { + fspool = list->fspools[i]; + + /* persistence filter */ + if (VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_FILTERS_PERSISTENT)) { + if ((persistent = virFsPoolIsPersistent(fspool)) < 0) { + vshError(ctl, "%s", _("Failed to get fspool persistence info")); + goto cleanup; + } + + if (!((VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_PERSISTENT) && persistent) || + (VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_TRANSIENT) && !persistent))) + goto remove_entry; + } + + /* autostart filter */ + if (VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_FILTERS_AUTOSTART)) { + if (virFsPoolGetAutostart(fspool, &autostart) < 0) { + vshError(ctl, "%s", _("Failed to get fspool autostart state")); + goto cleanup; + } + + if (!((VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_AUTOSTART) && autostart) || + (VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_NO_AUTOSTART) && !autostart))) + goto remove_entry; + } + + /* the fspool matched all filters, it may stay */ + continue; + + remove_entry: + /* the fspool has to be removed as it failed one of the filters */ + virFsPoolFree(list->fspools[i]); + list->fspools[i] = NULL; + deleted++; + } + + finished: + /* sort the list */ + if (list->fspools && list->nfspools) + qsort(list->fspools, list->nfspools, + sizeof(*list->fspools), virshFsPoolSorter); + + /* truncate the list if filter simulation deleted entries */ + if (deleted) + VIR_SHRINK_N(list->fspools, list->nfspools, deleted); + + success = true; + + cleanup: + for (i = 0; i < nAllPools; i++) + VIR_FREE(names[i]); + + if (!success) { + virshFsPoolListFree(list); + list = NULL; + } + + VIR_FREE(names); + return list; +} + + +VIR_ENUM_DECL(virshFsPoolState) +VIR_ENUM_IMPL(virshFsPoolState, + VIR_FS_POOL_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_FS_POOLS_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_FS_POOLS_INACTIVE; + + if (all) + flags = VIR_CONNECT_LIST_FS_POOLS_ACTIVE | + VIR_CONNECT_LIST_FS_POOLS_INACTIVE; + + if (vshCommandOptBool(cmd, "autostart")) + flags |= VIR_CONNECT_LIST_FS_POOLS_AUTOSTART; + + if (vshCommandOptBool(cmd, "no-autostart")) + flags |= VIR_CONNECT_LIST_FS_POOLS_NO_AUTOSTART; + + if (vshCommandOptBool(cmd, "persistent")) + flags |= VIR_CONNECT_LIST_FS_POOLS_PERSISTENT; + + if (vshCommandOptBool(cmd, "transient")) + flags |= VIR_CONNECT_LIST_FS_POOLS_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_FS_POOL_DIR: + flags |= VIR_CONNECT_LIST_FS_POOLS_DIR; + break; + case VIR_FS_POOL_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_FS_POOL_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_FS_POOL_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_FS_POOL_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_FS_POOL_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_FS_POOL_FULL, + VIRSH_COMMON_OPT_FS_POOL_BUILD, + VIRSH_COMMON_OPT_FS_POOL_NO_OVERWRITE, + VIRSH_COMMON_OPT_FS_POOL_OVERWRITE, + + {.name = NULL} +}; + +static bool +cmdFsPoolStart(vshControl *ctl, const vshCmd *cmd) +{ + virFsPoolPtr fspool; + bool ret = true; + const char *name = NULL; + bool build; + bool overwrite; + bool no_overwrite; + unsigned int flags = 0; + + if (!(fspool = virshCommandOptFsPool(ctl, cmd, "fspool", &name))) + return false; + + build = vshCommandOptBool(cmd, "build"); + overwrite = vshCommandOptBool(cmd, "overwrite"); + no_overwrite = vshCommandOptBool(cmd, "no-overwrite"); + + VSH_EXCLUSIVE_OPTIONS_EXPR("overwrite", overwrite, + "no-overwrite", no_overwrite); + + if (build) + flags |= VIR_FS_POOL_CREATE_WITH_BUILD; + if (overwrite) + flags |= VIR_FS_POOL_CREATE_WITH_BUILD_OVERWRITE; + if (no_overwrite) + flags |= VIR_FS_POOL_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_FS_POOL_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_FS_POOL_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_FS_POOL_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..d2d4361 --- /dev/null +++ b/tools/virsh-fspool.h @@ -0,0 +1,36 @@ +/* + * virsh-fspool.h: Commands to manage fspool + * + * 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-item.c b/tools/virsh-item.c new file mode 100644 index 0000000..37c5c30 --- /dev/null +++ b/tools/virsh-item.c @@ -0,0 +1,1274 @@ +/* + * virsh-item.c: Commands to manage storage item + */ + +#include <config.h> +#include "virsh-item.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_FS_POOL_FULL \ + VIRSH_COMMON_OPT_FS_POOL(N_("fspool name or uuid")) \ + +#define VIRSH_COMMON_OPT_FS_POOL_NAME \ + VIRSH_COMMON_OPT_FS_POOL(N_("fspool name")) \ + +#define VIRSH_COMMON_OPT_FS_POOL_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_FS_POOL_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_FS_POOL_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_FS_POOL_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") + }, + {.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_FS_POOL_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_FS_ITEM_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_FS_POOL_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_FS_POOL_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_FS_POOL_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_FS_POOL_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_FS_POOL_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-item.h b/tools/virsh-item.h new file mode 100644 index 0000000..841ff43 --- /dev/null +++ b/tools/virsh-item.h @@ -0,0 +1,37 @@ +/* + * virsh-item.h: Commands to manage fsitems + * + * 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_ITEM_H +# define VIRSH_ITEM_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_ITEM_H */ diff --git a/tools/virsh.c b/tools/virsh.c index d3fe06f..35c82c6 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-item.h" /* Gnulib doesn't guarantee SA_SIGINFO support. */ #ifndef SA_SIGINFO @@ -921,6 +923,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_FS_POOL, "fspool", fsPoolCmds}, + {VIRSH_CMD_GRP_FS_ITEM, "item", fsItemCmds}, {VIRSH_CMD_GRP_VIRSH, "virsh", virshCmds}, {NULL, NULL, NULL} }; diff --git a/tools/virsh.h b/tools/virsh.h index fd552bb..b1a1d0d 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_FS_POOL "Fspool" +# define VIRSH_CMD_GRP_FS_ITEM "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_FS_POOL(_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, \ -- 1.8.3.1

On Fri, Aug 19, 2016 at 06:03:35PM +0300, Olga Krishtal wrote:
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- po/POTFILES.in | 2 + tools/Makefile.am | 4 + tools/virsh-fspool.c | 1728 ++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh-fspool.h | 36 ++ tools/virsh-item.c | 1274 +++++++++++++++++++++++++++++++++++++ tools/virsh-item.h | 37 ++ tools/virsh.c | 4 + tools/virsh.h | 9 +
Could you also update tools/virsh.pod with the docs Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 25/08/16 04:13, Daniel P. Berrange wrote:
On Fri, Aug 19, 2016 at 06:03:35PM +0300, Olga Krishtal wrote:
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- po/POTFILES.in | 2 + tools/Makefile.am | 4 + tools/virsh-fspool.c | 1728 ++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh-fspool.h | 36 ++ tools/virsh-item.c | 1274 +++++++++++++++++++++++++++++++++++++ tools/virsh-item.h | 37 ++ tools/virsh.c | 4 + tools/virsh.h | 9 + Could you also update tools/virsh.pod with the docs
Regards, Daniel
Ok

On Fri, Aug 19, 2016 at 06:03:28PM +0300, Olga Krishtal wrote:
Hi everyone, we would like to propose the first implementation of fspool with directory backend.
Filesystem pools is a facility to manage filesystems resources similar to how storage pools manages volume resources. Furthermore new API follows storage API closely where it makes sense. 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.
The patchset provides 'dir' backend which simply expose directories in some directory in host filesystem. The virsh commands are provided too. So it is ready to play with, just replace 'pool' in xml descriptions and virsh commands to 'fspool' and 'volume' to 'item'. Examle and usage: Define: virsh -c qemu:///system fspool-define-as fs_pool_name dir --target /path/on/host Build virsh -c qemu:///system fspool-build fs_pool_name Start virsh -c qemu:///system fspool-start fs_pool_name Look inside virsh -c qemu:///system fspool-list (--all) fspool_name
Fspool called POOL, on the host fs uses /fs_driver to hold items. virsh -c qemu:///system fspool-dumpxml POOL <fspool type='dir'> <name>POOL</name> <uuid>c57c9d7c-b1d5-4c45-ba9c-67f03d4da160</uuid> <capacity unit='bytes'>733722615808</capacity> <allocation unit='bytes'>1331486720</allocation> <available unit='bytes'>534810800128</available> <source> </source> <target> <path>/fs_driver</path> <permissions> <mode>0755</mode> <owner>0</owner> <group>0</group> </permissions> </target> </fspool>
virsh -c qemu:///system fspool-info POOL Name: POOL UUID: c57c9d7c-b1d5-4c45-ba9c-67f03d4da160 State: running Persistent: yes Autostart: no autostart Capacity: 683.33 GiB Allocation: 1.24 GiB Available: 498.08 GiB
virsh -c qemu+unix:///system item-list POOL Name Path ------------------------------------------------------------------------------ item1 /fs_driver/item1 item10 /fs_driver/item10 item11 /fs_driver/item11 item12 /fs_driver/item12 item15 /fs_driver/item15
Fspool of directory type is some directory on host fs that holds items (subdirs). Example of usage for items: virsh -c vz+unix:///system item-create-as POOL item1 1g - create item virsh -c qemu+unix:///system item-dumpxml item1 POOL <fsitem> <name>item1</name> <key>/fs_driver/item1</key> <source> fspoo ='POOL'
Is this a typo, or is it really what you intend the <source> content to look like. It seems rather odd to me
</source> <capacity unit='bytes'>0</capacity> <allocation unit='bytes'>0</allocation> <target> <format type='dir'/> </target> </fsitem> virsh -c qemu+unix:///system item-info item1 POOL Name: item1 Type: dir Capacity: 683.33 GiB Allocation: 634.87 MiB Autostart: no autostart Capacity: 683.33 GiB Allocation: 1.24 GiB Available: 498.08 GiB virsh -c qemu+unix:///system item-list POOL Name Path ------------------------------------------------------------------------------ item1 /fs_driver/item1 item10 /fs_driver/item10 item11 /fs_driver/item11 item12 /fs_driver/item12 item15 /fs_driver/item15
Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 25/08/16 04:14, Daniel P. Berrange wrote:
On Fri, Aug 19, 2016 at 06:03:28PM +0300, Olga Krishtal wrote:
Hi everyone, we would like to propose the first implementation of fspool with directory backend.
Filesystem pools is a facility to manage filesystems resources similar to how storage pools manages volume resources. Furthermore new API follows storage API closely where it makes sense. 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.
The patchset provides 'dir' backend which simply expose directories in some directory in host filesystem. The virsh commands are provided too. So it is ready to play with, just replace 'pool' in xml descriptions and virsh commands to 'fspool' and 'volume' to 'item'. Examle and usage: Define: virsh -c qemu:///system fspool-define-as fs_pool_name dir --target /path/on/host Build virsh -c qemu:///system fspool-build fs_pool_name Start virsh -c qemu:///system fspool-start fs_pool_name Look inside virsh -c qemu:///system fspool-list (--all) fspool_name
Fspool called POOL, on the host fs uses /fs_driver to hold items. virsh -c qemu:///system fspool-dumpxml POOL <fspool type='dir'> <name>POOL</name> <uuid>c57c9d7c-b1d5-4c45-ba9c-67f03d4da160</uuid> <capacity unit='bytes'>733722615808</capacity> <allocation unit='bytes'>1331486720</allocation> <available unit='bytes'>534810800128</available> <source> </source> <target> <path>/fs_driver</path> <permissions> <mode>0755</mode> <owner>0</owner> <group>0</group> </permissions> </target> </fspool>
virsh -c qemu:///system fspool-info POOL Name: POOL UUID: c57c9d7c-b1d5-4c45-ba9c-67f03d4da160 State: running Persistent: yes Autostart: no autostart Capacity: 683.33 GiB Allocation: 1.24 GiB Available: 498.08 GiB
virsh -c qemu+unix:///system item-list POOL Name Path ------------------------------------------------------------------------------ item1 /fs_driver/item1 item10 /fs_driver/item10 item11 /fs_driver/item11 item12 /fs_driver/item12 item15 /fs_driver/item15
Fspool of directory type is some directory on host fs that holds items (subdirs). Example of usage for items: virsh -c vz+unix:///system item-create-as POOL item1 1g - create item virsh -c qemu+unix:///system item-dumpxml item1 POOL <fsitem> <name>item1</name> <key>/fs_driver/item1</key> <source> fspoo ='POOL' Is this a typo, or is it really what you intend the <source> content to look like. It seems rather odd to me It should be <fspool name= 'POOL'/> but afterword xml looks like: <item> <name>item1</name> <key>/home/gray_pig/dirfspool/item1</key> <capacity unit='bytes'>1073741824</capacity> <allocation unit='bytes'>0</allocation> <target> <permissions> <mode>0600</mode> <owner>0</owner> <group>0</group> </permissions> </target> </item>
</source> <capacity unit='bytes'>0</capacity> <allocation unit='bytes'>0</allocation> <target> <format type='dir'/> </target> </fsitem> virsh -c qemu+unix:///system item-info item1 POOL Name: item1 Type: dir Capacity: 683.33 GiB Allocation: 634.87 MiB Autostart: no autostart Capacity: 683.33 GiB Allocation: 1.24 GiB Available: 498.08 GiB virsh -c qemu+unix:///system item-list POOL Name Path ------------------------------------------------------------------------------ item1 /fs_driver/item1 item10 /fs_driver/item10 item11 /fs_driver/item11 item12 /fs_driver/item12 item15 /fs_driver/item15
Regards, Daniel

On Thu, Aug 25, 2016 at 02:03:01PM +0300, Olga Krishtal wrote:
On 25/08/16 04:14, Daniel P. Berrange wrote:
On Fri, Aug 19, 2016 at 06:03:28PM +0300, Olga Krishtal wrote:
Hi everyone, we would like to propose the first implementation of fspool with directory backend.
Filesystem pools is a facility to manage filesystems resources similar to how storage pools manages volume resources. Furthermore new API follows storage API closely where it makes sense. 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.
The patchset provides 'dir' backend which simply expose directories in some directory in host filesystem. The virsh commands are provided too. So it is ready to play with, just replace 'pool' in xml descriptions and virsh commands to 'fspool' and 'volume' to 'item'. Examle and usage: Define: virsh -c qemu:///system fspool-define-as fs_pool_name dir --target /path/on/host Build virsh -c qemu:///system fspool-build fs_pool_name Start virsh -c qemu:///system fspool-start fs_pool_name Look inside virsh -c qemu:///system fspool-list (--all) fspool_name
Fspool called POOL, on the host fs uses /fs_driver to hold items. virsh -c qemu:///system fspool-dumpxml POOL <fspool type='dir'> <name>POOL</name> <uuid>c57c9d7c-b1d5-4c45-ba9c-67f03d4da160</uuid> <capacity unit='bytes'>733722615808</capacity> <allocation unit='bytes'>1331486720</allocation> <available unit='bytes'>534810800128</available> <source> </source> <target> <path>/fs_driver</path> <permissions> <mode>0755</mode> <owner>0</owner> <group>0</group> </permissions> </target> </fspool>
virsh -c qemu:///system fspool-info POOL Name: POOL UUID: c57c9d7c-b1d5-4c45-ba9c-67f03d4da160 State: running Persistent: yes Autostart: no autostart Capacity: 683.33 GiB Allocation: 1.24 GiB Available: 498.08 GiB
virsh -c qemu+unix:///system item-list POOL Name Path ------------------------------------------------------------------------------ item1 /fs_driver/item1 item10 /fs_driver/item10 item11 /fs_driver/item11 item12 /fs_driver/item12 item15 /fs_driver/item15
Fspool of directory type is some directory on host fs that holds items (subdirs). Example of usage for items: virsh -c vz+unix:///system item-create-as POOL item1 1g - create item virsh -c qemu+unix:///system item-dumpxml item1 POOL <fsitem> <name>item1</name> <key>/fs_driver/item1</key> <source> fspoo ='POOL' Is this a typo, or is it really what you intend the <source> content to look like. It seems rather odd to me It should be <fspool name= 'POOL'/> but afterword xml looks like:
I don't think we actually need that info in the fsitem XML - the pool is passed explicitly as a parameter in the API call, so its redundant putting it in the XML too - especially as you don't output it afterwards.
<item> <name>item1</name> <key>/home/gray_pig/dirfspool/item1</key> <capacity unit='bytes'>1073741824</capacity> <allocation unit='bytes'>0</allocation> <target> <permissions> <mode>0600</mode> <owner>0</owner> <group>0</group> </permissions> </target> </item>
Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
participants (2)
-
Daniel P. Berrange
-
Olga Krishtal