[Libvir] PATCH: 0/7 Implementation of storage APIs

Since the previous discussions didn't really end up anywhere conclusive I decided it would be better to have a crack at getting some working code to illustrate my ideas. Thus, the following series of 7 patches provide an implementation of storage APIs which follow the scheme outlined in the previous mail on storage concepts http://www.redhat.com/archives/libvir-list/2007-October/msg00195.html I have only addressed storage pools & volumes. I am not tackling the host device enumeration APIs at this time, since it is not a blocker for the rest of the work. The mails which follow, in particular the last one, will explain the patches in more details. The focus is primarily on providing the public API, and wiring up the remote driver, daemon and protocol, and the generic storage driver. The generic storage driver then calls out to specific backends for different types of storage. implementation provides a fully functional backend for managing local directories containing raw files (aka equivalent of /var/lib/xen/images). There are empty stubs for LVM, iSCSI, Disks/Partitions, etc to be filled in as we decide... Some open questions - Is it worth bothering with a UUID for individual storage volumes. It is possible to construct a globally unique identifier for most volumes, by combing various bits of metadata we have such as device unique ID, inode, iSCSI target & LUN, etc There isn't really any UUID that fits into the classic libvirt 16 byte UUID. I've implemented (randomly generated) UUIDs for the virStorageVolPtr object, but I'm inclined to remove them, since its not much use if they change each time the libvirtd daemon is restarted. The 'name' field provides a unique identifier scoped to the storage pool. I think we could add a 'char *key' field, as an arbitrary opaque string, forming a globally unique identifier for the volume. This would serve same purpose as UUID, but without the 16 bytes constraint which we can't usefully provide. - For the local directory backend, I've got the ability to choose between file formats on a per-volume basis. eg, /var/lib/xen/images can contain a mix of raw, qcow, vmdk, etc files. This is nice & flexible for the user, but a more complex thing to implement, since it means we have to probe each volume and try & figure out its format each time we list volumes. If we constrained the choice between formats to be at the pool level instead of the volume level we could avoid probing & thus simplify the code. This is what XenAPI does. - If creating non-sparse files, it can take a very long time to do the I/O to fill in the image. In virt-intsall/virt-manager we have nice incremental progress display. The API I've got currently though is blocking. This blocks the calling application. It also blocks the entire libvirtd daemon since we are single process. There are a couple of ways we can address this: - Allow the libvirtd daemon to serve each client connection in a separate thread. We'd need to adding some mutex locking to the QEMU driver and the storage driver to handle this. It would have been nice to avoid threads, but I don't think we can much longer. - For long running operations, spawn off a worker thread (or process) to perform the operation. Don't send a reply to the RPC message, instead just put the client on a 'wait queue', and get on with serving other clients. When the worker thread completes, send the RPC reply to the original client. - Having the virStorageVolCreate() method return immediately, giving back the client app some kind of 'job id'. The client app can poll on another API virStorageVolJob() method to determine how far through the task has got. The implementation in the driver would have to spawn a worker thread to do the actual long operation. Possibly we can allow creation to be async or blocking by making use of the 'flags' field to virStorageVolCreate() method, eg VIR_STORAGE_ASYNC. If we make async behaviour optional, we still need some work in the daemon to avoid blocking all clients. This problem will also impact us when we add cloning of existing volumes. It already sort of hits us when saving & restoring VMs if they have large amounts of memory. So perhaps we need togo for the general solution of making the daemon threaded per client connection. The ASYNC flag may still be useful anyway to get the incremental progress feedback in the UI. Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

This patch splits up the libvirt.h file into multiple pieces. The big header file was getting rather long & hard to follow, with API calls for domains and networks all mixed together, and macros & typedefs & methods all mixed up. Adding another 25 APIs for storage won't improve this. So this splits up the header into libvirt/connection.h - connection related API calls & objects libvirt/node.h - host node information APIs & objects libvirt/domain.h - hypervisor/domain API calls & objects libvirt/network.h - virtual networking API calls & objects The original libvirt.h, now simply #include's all four of these files. The header files aren't intended to be included directly - apps carry on just using the main header file. Makefile.am | 2 b/include/libvirt/connection.h | 60 +++ b/include/libvirt/domain.h | 499 +++++++++++++++++++++++++++++++ b/include/libvirt/network.h | 125 +++++++ b/include/libvirt/node.h | 90 +++++ include/libvirt/Makefile.am | 3 include/libvirt/libvirt.h | 644 ----------------------------------------- include/libvirt/libvirt.h.in | 644 ----------------------------------------- src/libvirt.c | 1 9 files changed, 800 insertions(+), 1268 deletions(-) diff -r 0d270ffcf3f0 Makefile.am --- a/Makefile.am Sat Oct 27 00:23:28 2007 +0000 +++ b/Makefile.am Sat Oct 27 13:27:23 2007 -0400 @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in -SUBDIRS = src qemud proxy include docs @PYTHON_SUBDIR@ tests po m4 scripts +SUBDIRS = include src qemud proxy docs @PYTHON_SUBDIR@ tests po m4 scripts ACLOCAL_AMFLAGS = -I m4 diff -r 0d270ffcf3f0 include/libvirt/Makefile.am --- a/include/libvirt/Makefile.am Sat Oct 27 00:23:28 2007 +0000 +++ b/include/libvirt/Makefile.am Sat Oct 27 13:23:36 2007 -0400 @@ -3,6 +3,9 @@ virincdir = $(includedir)/libvirt virincdir = $(includedir)/libvirt virinc_HEADERS = libvirt.h \ + node.h \ + domain.h \ + network.h \ virterror.h install-exec-hook: diff -r 0d270ffcf3f0 include/libvirt/connection.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/libvirt/connection.h Sat Oct 27 13:26:34 2007 -0400 @@ -0,0 +1,60 @@ +/* -*- c -*- + * connection.h: + * Summary: connection interfaces + * Description: Provides the interfaces of the libvirt library to handle + * connections from a process running in the host + * + * Copy: Copyright (C) 2005-2007 Red Hat, Inc. + * + * See COPYING.LIB for the License of this software + * + * Author: Daniel Veillard <veillard@redhat.com> + */ + + + +#ifndef __VIR_VIRLIB_H__ +#error "Do not include connection.h directly. Use libvirt.h instead" +#endif + +#ifndef __VIR_VIRLIB_CONNECTION_H__ +#define __VIR_VIRLIB_CONNECTION_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * virConnect: + * + * a virConnect is a private structure representing a connection to + * the Xen Hypervisor. + */ +typedef struct _virConnect virConnect; + +/** + * virConnectPtr: + * + * a virConnectPtr is pointer to a virConnect private structure, this is the + * type used to reference a connection to the Xen Hypervisor in the API. + */ +typedef virConnect *virConnectPtr; + + +virConnectPtr virConnectOpen (const char *name); +virConnectPtr virConnectOpenReadOnly (const char *name); +int virConnectClose (virConnectPtr conn); +const char * virConnectGetType (virConnectPtr conn); +int virConnectGetVersion (virConnectPtr conn, + unsigned long *hvVer); +char * virConnectGetHostname (virConnectPtr conn); +char * virConnectGetURI (virConnectPtr conn); + + + +#ifdef __cplusplus +} +#endif + +#endif /* __VIR_VIRLIB_CONNECTION_H__ */ diff -r 0d270ffcf3f0 include/libvirt/domain.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/libvirt/domain.h Sat Oct 27 13:34:39 2007 -0400 @@ -0,0 +1,499 @@ +/* -*- c -*- + * domain.h: + * Summary: virtual domain interfaces + * Description: Provides the interfaces of the libvirt library to handle + * virtual domains from a process running in the host + * + * Copy: Copyright (C) 2005-2007 Red Hat, Inc. + * + * See COPYING.LIB for the License of this software + * + * Author: Daniel Veillard <veillard@redhat.com> + */ + + +/* -*- c -*- + * domain.h: + * Summary: virtual domain interfaces + * Description: Provides the interfaces of the libvirt library to handle + * virtual domains from a process running in the host + * + * Copy: Copyright (C) 2005-2007 Red Hat, Inc. + * + * See COPYING.LIB for the License of this software + * + * Author: Daniel Veillard <veillard@redhat.com> + */ + + + +#ifndef __VIR_VIRLIB_H__ +#error "Do not include network.h directly. Use libvirt.h instead" +#endif + +#ifndef __VIR_VIRLIB_DOMAIN_H__ +#define __VIR_VIRLIB_DOMAIN_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * virDomain: + * + * a virDomain is a private structure representing a Xen domain. + */ +typedef struct _virDomain virDomain; + +/** + * virDomainPtr: + * + * a virDomainPtr is pointer to a virDomain private structure, this is the + * type used to reference a Xen domain in the API. + */ +typedef virDomain *virDomainPtr; + +/** + * virDomainState: + * + * A domain may be in different states at a given point in time + */ +typedef enum { + VIR_DOMAIN_NOSTATE = 0, /* no state */ + VIR_DOMAIN_RUNNING = 1, /* the domain is running */ + VIR_DOMAIN_BLOCKED = 2, /* the domain is blocked on resource */ + VIR_DOMAIN_PAUSED = 3, /* the domain is paused by user */ + VIR_DOMAIN_SHUTDOWN= 4, /* the domain is being shut down */ + VIR_DOMAIN_SHUTOFF = 5, /* the domain is shut off */ + VIR_DOMAIN_CRASHED = 6 /* the domain is crashed */ +} virDomainState; + +/** + * virDomainInfoPtr: + * + * a virDomainInfo is a structure filled by virDomainGetInfo() and extracting + * runtime informations for a given active Domain + */ + +typedef struct _virDomainInfo virDomainInfo; + +struct _virDomainInfo { + unsigned char state; /* the running state, one of virDomainFlags */ + unsigned long maxMem; /* the maximum memory in KBytes allowed */ + unsigned long memory; /* the memory in KBytes used by the domain */ + unsigned short nrVirtCpu; /* the number of virtual CPUs for the domain */ + unsigned long long cpuTime; /* the CPU time used in nanoseconds */ +}; + +/** + * virDomainInfoPtr: + * + * a virDomainInfoPtr is a pointer to a virDomainInfo structure. + */ + +typedef virDomainInfo *virDomainInfoPtr; + +/** + * virDomainCreateFlags: + * + * Flags OR'ed together to provide specific behaviour when creating a + * Domain. + */ +typedef enum { + VIR_DOMAIN_NONE = 0 +} virDomainCreateFlags; + + +/** + * virDomainSchedParameterType: + * + * A scheduler parameter field type + */ +typedef enum { + VIR_DOMAIN_SCHED_FIELD_INT = 1, /* integer case */ + VIR_DOMAIN_SCHED_FIELD_UINT = 2, /* unsigned integer case */ + VIR_DOMAIN_SCHED_FIELD_LLONG = 3, /* long long case */ + VIR_DOMAIN_SCHED_FIELD_ULLONG = 4, /* unsigned long long case */ + VIR_DOMAIN_SCHED_FIELD_DOUBLE = 5, /* double case */ + VIR_DOMAIN_SCHED_FIELD_BOOLEAN = 6 /* boolean(character) case */ +} virSchedParameterType; + +/** + * VIR_DOMAIN_SCHED_FIELD_LENGTH: + * + * Macro providing the field length of virSchedParameter + */ + +#define VIR_DOMAIN_SCHED_FIELD_LENGTH 80 + +/** + * virDomainSchedParameter: + * + * a virDomainSchedParameter is the set of scheduler parameters + */ + +typedef struct _virSchedParameter virSchedParameter; + +struct _virSchedParameter { + char field[VIR_DOMAIN_SCHED_FIELD_LENGTH]; /* parameter name */ + int type; /* parameter type */ + union { + int i; /* data for integer case */ + unsigned int ui; /* data for unsigned integer case */ + long long int l; /* data for long long integer case */ + unsigned long long int ul; /* data for unsigned long long integer case */ + double d; /* data for double case */ + char b; /* data for char case */ + } value; /* parameter value */ +}; + +/** + * virSchedParameterPtr: + * + * a virSchedParameterPtr is a pointer to a virSchedParameter structure. + */ + +typedef virSchedParameter *virSchedParameterPtr; + + +/** + * virDomainBlockStats: + * + * Block device stats for virDomainBlockStats. + * + * Hypervisors may return a field set to ((long long)-1) which indicates + * that the hypervisor does not support that statistic. + * + * NB. Here 'long long' means 64 bit integer. + */ +typedef struct _virDomainBlockStats virDomainBlockStatsStruct; + +struct _virDomainBlockStats { + long long rd_req; + long long rd_bytes; + long long wr_req; + long long wr_bytes; + long long errs; /* In Xen this returns the mysterious 'oo_req'. */ +}; + +/** + * virDomainBlockStatsPtr: + * + * A pointer to a virDomainBlockStats structure + */ +typedef virDomainBlockStatsStruct *virDomainBlockStatsPtr; + +/** + * virDomainInterfaceStats: + * + * Network interface stats for virDomainInterfaceStats. + * + * Hypervisors may return a field set to ((long long)-1) which indicates + * that the hypervisor does not support that statistic. + * + * NB. Here 'long long' means 64 bit integer. + */ +typedef struct _virDomainInterfaceStats virDomainInterfaceStatsStruct; + +struct _virDomainInterfaceStats { + long long rx_bytes; + long long rx_packets; + long long rx_errs; + long long rx_drop; + long long tx_bytes; + long long tx_packets; + long long tx_errs; + long long tx_drop; +}; + +/** + * virDomainInterfaceStatsPtr: + * + * A pointe to a virDomainInterfaceStats structure + */ +typedef virDomainInterfaceStatsStruct *virDomainInterfaceStatsPtr; + +/** + * virVcpuInfo: structure for information about a virtual CPU in a domain. + */ + +typedef enum { + VIR_VCPU_OFFLINE = 0, /* the virtual CPU is offline */ + VIR_VCPU_RUNNING = 1, /* the virtual CPU is running */ + VIR_VCPU_BLOCKED = 2, /* the virtual CPU is blocked on resource */ +} virVcpuState; + +typedef struct _virVcpuInfo virVcpuInfo; +struct _virVcpuInfo { + unsigned int number; /* virtual CPU number */ + int state; /* value from virVcpuState */ + unsigned long long cpuTime; /* CPU time used, in nanoseconds */ + int cpu; /* real CPU number, or -1 if offline */ +}; +typedef virVcpuInfo *virVcpuInfoPtr; + +/** + * virDomainXMLFlags: + * + * Flags available for virDomainGetXMLDesc + */ + +typedef enum { + VIR_DOMAIN_XML_SECURE = 1, /* dump security sensitive informations too */ + VIR_DOMAIN_XML_INACTIVE = 2/* dump inactive domain informations */ +} virDomainXMLFlags; + +/* Domain migration flags. */ +typedef enum { + VIR_MIGRATE_LIVE = 1, /* live migration */ +} virDomainMigrateFlags; + +/** + * VIR_USE_CPU: + * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN/OUT) + * @cpu: the physical CPU number + * + * This macro is to be used in conjonction with virDomainPinVcpu() API. + * USE_CPU macro set the bit (CPU usable) of the related cpu in cpumap. + */ + +#define VIR_USE_CPU(cpumap,cpu) (cpumap[(cpu)/8] |= (1<<((cpu)%8))) + +/** + * VIR_UNUSE_CPU: + * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN/OUT) + * @cpu: the physical CPU number + * + * This macro is to be used in conjonction with virDomainPinVcpu() API. + * USE_CPU macro reset the bit (CPU not usable) of the related cpu in cpumap. + */ + +#define VIR_UNUSE_CPU(cpumap,cpu) (cpumap[(cpu)/8] &= ~(1<<((cpu)%8))) + +/** + * VIR_CPU_MAPLEN: + * @cpu: number of physical CPUs + * + * This macro is to be used in conjonction with virDomainPinVcpu() API. + * It returns the length (in bytes) required to store the complete + * CPU map between a single virtual & all physical CPUs of a domain. + */ + +#define VIR_CPU_MAPLEN(cpu) (((cpu)+7)/8) + +/** + * VIR_CPU_USABLE: + * @cpumaps: pointer to an array of cpumap (in 8-bit bytes) (IN) + * @maplen: the length (in bytes) of one cpumap + * @vcpu: the virtual CPU number + * @cpu: the physical CPU number + * + * This macro is to be used in conjonction with virDomainGetVcpus() API. + * VIR_CPU_USABLE macro returns a non zero value (true) if the cpu + * is usable by the vcpu, and 0 otherwise. + */ + +#define VIR_CPU_USABLE(cpumaps,maplen,vcpu,cpu) \ + (cpumaps[((vcpu)*(maplen))+((cpu)/8)] & (1<<((cpu)%8))) + +/** + * VIR_COPY_CPUMAP: + * @cpumaps: pointer to an array of cpumap (in 8-bit bytes) (IN) + * @maplen: the length (in bytes) of one cpumap + * @vcpu: the virtual CPU number + * @cpumap: pointer to a cpumap (in 8-bit bytes) (OUT) + * This cpumap must be previously allocated by the caller + * (ie: malloc(maplen)) + * + * This macro is to be used in conjonction with virDomainGetVcpus() and + * virDomainPinVcpu() APIs. VIR_COPY_CPUMAP macro extract the cpumap of + * the specified vcpu from cpumaps array and copy it into cpumap to be used + * later by virDomainPinVcpu() API. + */ +#define VIR_COPY_CPUMAP(cpumaps,maplen,vcpu,cpumap) \ + memcpy(cpumap, &(cpumaps[(vcpu)*(maplen)]), (maplen)) + + +/** + * VIR_GET_CPUMAP: + * @cpumaps: pointer to an array of cpumap (in 8-bit bytes) (IN) + * @maplen: the length (in bytes) of one cpumap + * @vcpu: the virtual CPU number + * + * This macro is to be used in conjonction with virDomainGetVcpus() and + * virDomainPinVcpu() APIs. VIR_GET_CPUMAP macro returns a pointer to the + * cpumap of the specified vcpu from cpumaps array. + */ +#define VIR_GET_CPUMAP(cpumaps,maplen,vcpu) &(cpumaps[(vcpu)*(maplen)]) + + +int virConnectGetMaxVcpus (virConnectPtr conn, + const char *type); +/* + * Gather list of running domains + */ +int virConnectListDomains (virConnectPtr conn, + int *ids, + int maxids); + +/* + * Number of domains + */ +int virConnectNumOfDomains (virConnectPtr conn); + + +/* + * Get connection from domain. + */ +virConnectPtr virDomainGetConnect (virDomainPtr domain); + +/* + * Domain creation and destruction + */ +virDomainPtr virDomainCreateLinux (virConnectPtr conn, + const char *xmlDesc, + unsigned int flags); +virDomainPtr virDomainLookupByName (virConnectPtr conn, + const char *name); +virDomainPtr virDomainLookupByID (virConnectPtr conn, + int id); +virDomainPtr virDomainLookupByUUID (virConnectPtr conn, + const unsigned char *uuid); +virDomainPtr virDomainLookupByUUIDString (virConnectPtr conn, + const char *uuid); + +int virDomainShutdown (virDomainPtr domain); +int virDomainReboot (virDomainPtr domain, + unsigned int flags); +int virDomainDestroy (virDomainPtr domain); +int virDomainFree (virDomainPtr domain); + +/* + * Domain suspend/resume + */ +int virDomainSuspend (virDomainPtr domain); +int virDomainResume (virDomainPtr domain); + +/* + * Domain save/restore + */ +int virDomainSave (virDomainPtr domain, + const char *to); +int virDomainRestore (virConnectPtr conn, + const char *from); + +/* + * Domain core dump + */ +int virDomainCoreDump (virDomainPtr domain, + const char *to, + int flags); + +/* + * Domain runtime informations + */ +int virDomainGetInfo (virDomainPtr domain, + virDomainInfoPtr info); + +/* + * Return scheduler type in effect 'sedf', 'credit', 'linux' + */ +char * virDomainGetSchedulerType(virDomainPtr domain, + int *nparams); + +/* + * Dynamic control of domains + */ +const char * virDomainGetName (virDomainPtr domain); +unsigned int virDomainGetID (virDomainPtr domain); +int virDomainGetUUID (virDomainPtr domain, + unsigned char *uuid); +int virDomainGetUUIDString (virDomainPtr domain, + char *buf); +char * virDomainGetOSType (virDomainPtr domain); +unsigned long virDomainGetMaxMemory (virDomainPtr domain); +int virDomainSetMaxMemory (virDomainPtr domain, + unsigned long memory); +int virDomainSetMemory (virDomainPtr domain, + unsigned long memory); +int virDomainGetMaxVcpus (virDomainPtr domain); + +/* + * XML domain description + */ + +char * virDomainGetXMLDesc (virDomainPtr domain, + int flags); + +int virDomainBlockStats (virDomainPtr dom, + const char *path, + virDomainBlockStatsPtr stats, + size_t size); +int virDomainInterfaceStats (virDomainPtr dom, + const char *path, + virDomainInterfaceStatsPtr stats, + size_t size); + + +/* + * defined but not running domains + */ +virDomainPtr virDomainDefineXML (virConnectPtr conn, + const char *xml); +int virDomainUndefine (virDomainPtr domain); +int virConnectNumOfDefinedDomains (virConnectPtr conn); +int virConnectListDefinedDomains (virConnectPtr conn, + char **const names, + int maxnames); +int virDomainCreate (virDomainPtr domain); + +int virDomainGetAutostart (virDomainPtr domain, + int *autostart); +int virDomainSetAutostart (virDomainPtr domain, + int autostart); + +/* + * Fetch scheduler parameters, caller allocates 'params' field of size 'nparams' + */ +int virDomainGetSchedulerParameters (virDomainPtr domain, + virSchedParameterPtr params, + int *nparams); + +/* + * Change scheduler parameters + */ +int virDomainSetSchedulerParameters (virDomainPtr domain, + virSchedParameterPtr params, + int nparams); + + +int virDomainSetVcpus (virDomainPtr domain, + unsigned int nvcpus); + +int virDomainPinVcpu (virDomainPtr domain, + unsigned int vcpu, + unsigned char *cpumap, + int maplen); +/* Domain migration. */ +virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn, + unsigned long flags, const char *dname, + const char *uri, unsigned long bandwidth); + + + +int virDomainGetVcpus (virDomainPtr domain, + virVcpuInfoPtr info, + int maxinfo, + unsigned char *cpumaps, + int maplen); + + +int virDomainAttachDevice(virDomainPtr domain, const char *xml); +int virDomainDetachDevice(virDomainPtr domain, const char *xml); + + +#ifdef __cplusplus +} +#endif + +#endif /* __VIR_VIRLIB_DOMAIN_H__ */ diff -r 0d270ffcf3f0 include/libvirt/libvirt.h --- a/include/libvirt/libvirt.h Sat Oct 27 00:23:28 2007 +0000 +++ b/include/libvirt/libvirt.h Sat Oct 27 13:33:58 2007 -0400 @@ -16,263 +16,26 @@ #include <sys/types.h> +#include <libvirt/connection.h> +#include <libvirt/node.h> +#include <libvirt/domain.h> +#include <libvirt/network.h> + #ifdef __cplusplus extern "C" { #endif -/** - * virConnect: - * - * a virConnect is a private structure representing a connection to - * the Xen Hypervisor. - */ -typedef struct _virConnect virConnect; + +/* library versionning */ /** - * virConnectPtr: + * LIBVIR_VERSION_NUMBER: * - * a virConnectPtr is pointer to a virConnect private structure, this is the - * type used to reference a connection to the Xen Hypervisor in the API. - */ -typedef virConnect *virConnectPtr; - -/** - * virDomain: - * - * a virDomain is a private structure representing a Xen domain. - */ -typedef struct _virDomain virDomain; - -/** - * virDomainPtr: - * - * a virDomainPtr is pointer to a virDomain private structure, this is the - * type used to reference a Xen domain in the API. - */ -typedef virDomain *virDomainPtr; - -/** - * virDomainState: - * - * A domain may be in different states at a given point in time - */ -typedef enum { - VIR_DOMAIN_NOSTATE = 0, /* no state */ - VIR_DOMAIN_RUNNING = 1, /* the domain is running */ - VIR_DOMAIN_BLOCKED = 2, /* the domain is blocked on resource */ - VIR_DOMAIN_PAUSED = 3, /* the domain is paused by user */ - VIR_DOMAIN_SHUTDOWN= 4, /* the domain is being shut down */ - VIR_DOMAIN_SHUTOFF = 5, /* the domain is shut off */ - VIR_DOMAIN_CRASHED = 6 /* the domain is crashed */ -} virDomainState; - -/** - * virDomainInfoPtr: - * - * a virDomainInfo is a structure filled by virDomainGetInfo() and extracting - * runtime informations for a given active Domain + * Macro providing the version of the library as + * version * 1,000,000 + minor * 1000 + micro */ -typedef struct _virDomainInfo virDomainInfo; - -struct _virDomainInfo { - unsigned char state; /* the running state, one of virDomainFlags */ - unsigned long maxMem; /* the maximum memory in KBytes allowed */ - unsigned long memory; /* the memory in KBytes used by the domain */ - unsigned short nrVirtCpu; /* the number of virtual CPUs for the domain */ - unsigned long long cpuTime; /* the CPU time used in nanoseconds */ -}; - -/** - * virDomainInfoPtr: - * - * a virDomainInfoPtr is a pointer to a virDomainInfo structure. - */ - -typedef virDomainInfo *virDomainInfoPtr; - -/** - * virDomainCreateFlags: - * - * Flags OR'ed together to provide specific behaviour when creating a - * Domain. - */ -typedef enum { - VIR_DOMAIN_NONE = 0 -} virDomainCreateFlags; - -/** - * virNodeInfoPtr: - * - * a virNodeInfo is a structure filled by virNodeGetInfo() and providing - * the informations for the Node. - */ - -typedef struct _virNodeInfo virNodeInfo; - -struct _virNodeInfo { - char model[32]; /* string indicating the CPU model */ - unsigned long memory;/* memory size in kilobytes */ - unsigned int cpus; /* the number of active CPUs */ - unsigned int mhz; /* expected CPU frequency */ - unsigned int nodes; /* the number of NUMA cell, 1 for uniform mem access */ - unsigned int sockets;/* number of CPU socket per node */ - unsigned int cores; /* number of core per socket */ - unsigned int threads;/* number of threads per core */ -}; - - -/** - * virDomainSchedParameterType: - * - * A scheduler parameter field type - */ -typedef enum { - VIR_DOMAIN_SCHED_FIELD_INT = 1, /* integer case */ - VIR_DOMAIN_SCHED_FIELD_UINT = 2, /* unsigned integer case */ - VIR_DOMAIN_SCHED_FIELD_LLONG = 3, /* long long case */ - VIR_DOMAIN_SCHED_FIELD_ULLONG = 4, /* unsigned long long case */ - VIR_DOMAIN_SCHED_FIELD_DOUBLE = 5, /* double case */ - VIR_DOMAIN_SCHED_FIELD_BOOLEAN = 6 /* boolean(character) case */ -} virSchedParameterType; - -/** - * VIR_DOMAIN_SCHED_FIELD_LENGTH: - * - * Macro providing the field length of virSchedParameter - */ - -#define VIR_DOMAIN_SCHED_FIELD_LENGTH 80 - -/** - * virDomainSchedParameter: - * - * a virDomainSchedParameter is the set of scheduler parameters - */ - -typedef struct _virSchedParameter virSchedParameter; - -struct _virSchedParameter { - char field[VIR_DOMAIN_SCHED_FIELD_LENGTH]; /* parameter name */ - int type; /* parameter type */ - union { - int i; /* data for integer case */ - unsigned int ui; /* data for unsigned integer case */ - long long int l; /* data for long long integer case */ - unsigned long long int ul; /* data for unsigned long long integer case */ - double d; /* data for double case */ - char b; /* data for char case */ - } value; /* parameter value */ -}; - -/** - * virSchedParameterPtr: - * - * a virSchedParameterPtr is a pointer to a virSchedParameter structure. - */ - -typedef virSchedParameter *virSchedParameterPtr; - -/* - * Fetch scheduler parameters, caller allocates 'params' field of size 'nparams' - */ -int virDomainGetSchedulerParameters (virDomainPtr domain, - virSchedParameterPtr params, - int *nparams); - -/* - * Change scheduler parameters - */ -int virDomainSetSchedulerParameters (virDomainPtr domain, - virSchedParameterPtr params, - int nparams); - -/** - * virDomainBlockStats: - * - * Block device stats for virDomainBlockStats. - * - * Hypervisors may return a field set to ((long long)-1) which indicates - * that the hypervisor does not support that statistic. - * - * NB. Here 'long long' means 64 bit integer. - */ -typedef struct _virDomainBlockStats virDomainBlockStatsStruct; - -struct _virDomainBlockStats { - long long rd_req; - long long rd_bytes; - long long wr_req; - long long wr_bytes; - long long errs; /* In Xen this returns the mysterious 'oo_req'. */ -}; - -/** - * virDomainBlockStatsPtr: - * - * A pointer to a virDomainBlockStats structure - */ -typedef virDomainBlockStatsStruct *virDomainBlockStatsPtr; - -/** - * virDomainInterfaceStats: - * - * Network interface stats for virDomainInterfaceStats. - * - * Hypervisors may return a field set to ((long long)-1) which indicates - * that the hypervisor does not support that statistic. - * - * NB. Here 'long long' means 64 bit integer. - */ -typedef struct _virDomainInterfaceStats virDomainInterfaceStatsStruct; - -struct _virDomainInterfaceStats { - long long rx_bytes; - long long rx_packets; - long long rx_errs; - long long rx_drop; - long long tx_bytes; - long long tx_packets; - long long tx_errs; - long long tx_drop; -}; - -/** - * virDomainInterfaceStatsPtr: - * - * A pointe to a virDomainInterfaceStats structure - */ -typedef virDomainInterfaceStatsStruct *virDomainInterfaceStatsPtr; - - -/* Domain migration flags. */ -typedef enum { - VIR_MIGRATE_LIVE = 1, /* live migration */ -} virDomainMigrateFlags; - -/* Domain migration. */ -virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn, - unsigned long flags, const char *dname, - const char *uri, unsigned long bandwidth); - -/** - * VIR_NODEINFO_MAXCPUS: - * @nodeinfo: virNodeInfo instance - * - * This macro is to calculate the total number of CPUs supported - * but not neccessarily active in the host. - */ - - -#define VIR_NODEINFO_MAXCPUS(nodeinfo) ((nodeinfo).nodes*(nodeinfo).sockets*(nodeinfo).cores*(nodeinfo).threads) - -/** - * virNodeInfoPtr: - * - * a virNodeInfoPtr is a pointer to a virNodeInfo structure. - */ - -typedef virNodeInfo *virNodeInfoPtr; +#define LIBVIR_VERSION_NUMBER 3003 /** * VIR_UUID_BUFLEN: @@ -292,17 +55,6 @@ typedef virNodeInfo *virNodeInfoPtr; #define VIR_UUID_STRING_BUFLEN (36+1) -/* library versionning */ - -/** - * LIBVIR_VERSION_NUMBER: - * - * Macro providing the version of the library as - * version * 1,000,000 + minor * 1000 + micro - */ - -#define LIBVIR_VERSION_NUMBER 3003 - int virGetVersion (unsigned long *libVer, const char *type, unsigned long *typeVer); @@ -312,380 +64,6 @@ int virGetVersion (unsigned long *lib */ int virInitialize (void); -virConnectPtr virConnectOpen (const char *name); -virConnectPtr virConnectOpenReadOnly (const char *name); -int virConnectClose (virConnectPtr conn); -const char * virConnectGetType (virConnectPtr conn); -int virConnectGetVersion (virConnectPtr conn, - unsigned long *hvVer); -char * virConnectGetHostname (virConnectPtr conn); -char * virConnectGetURI (virConnectPtr conn); - - -/* - * Capabilities of the connection / driver. - */ - -int virConnectGetMaxVcpus (virConnectPtr conn, - const char *type); -int virNodeGetInfo (virConnectPtr conn, - virNodeInfoPtr info); -char * virConnectGetCapabilities (virConnectPtr conn); - -unsigned long long virNodeGetFreeMemory (virConnectPtr conn); - -/* - * Gather list of running domains - */ -int virConnectListDomains (virConnectPtr conn, - int *ids, - int maxids); - -/* - * Number of domains - */ -int virConnectNumOfDomains (virConnectPtr conn); - - -/* - * Get connection from domain. - */ -virConnectPtr virDomainGetConnect (virDomainPtr domain); - -/* - * Domain creation and destruction - */ -virDomainPtr virDomainCreateLinux (virConnectPtr conn, - const char *xmlDesc, - unsigned int flags); -virDomainPtr virDomainLookupByName (virConnectPtr conn, - const char *name); -virDomainPtr virDomainLookupByID (virConnectPtr conn, - int id); -virDomainPtr virDomainLookupByUUID (virConnectPtr conn, - const unsigned char *uuid); -virDomainPtr virDomainLookupByUUIDString (virConnectPtr conn, - const char *uuid); - -int virDomainShutdown (virDomainPtr domain); -int virDomainReboot (virDomainPtr domain, - unsigned int flags); -int virDomainDestroy (virDomainPtr domain); -int virDomainFree (virDomainPtr domain); - -/* - * Domain suspend/resume - */ -int virDomainSuspend (virDomainPtr domain); -int virDomainResume (virDomainPtr domain); - -/* - * Domain save/restore - */ -int virDomainSave (virDomainPtr domain, - const char *to); -int virDomainRestore (virConnectPtr conn, - const char *from); - -/* - * Domain core dump - */ -int virDomainCoreDump (virDomainPtr domain, - const char *to, - int flags); - -/* - * Domain runtime informations - */ -int virDomainGetInfo (virDomainPtr domain, - virDomainInfoPtr info); - -/* - * Return scheduler type in effect 'sedf', 'credit', 'linux' - */ -char * virDomainGetSchedulerType(virDomainPtr domain, - int *nparams); - -/* - * Dynamic control of domains - */ -const char * virDomainGetName (virDomainPtr domain); -unsigned int virDomainGetID (virDomainPtr domain); -int virDomainGetUUID (virDomainPtr domain, - unsigned char *uuid); -int virDomainGetUUIDString (virDomainPtr domain, - char *buf); -char * virDomainGetOSType (virDomainPtr domain); -unsigned long virDomainGetMaxMemory (virDomainPtr domain); -int virDomainSetMaxMemory (virDomainPtr domain, - unsigned long memory); -int virDomainSetMemory (virDomainPtr domain, - unsigned long memory); -int virDomainGetMaxVcpus (virDomainPtr domain); - -/* - * XML domain description - */ -/** - * virDomainXMLFlags: - * - * Flags available for virDomainGetXMLDesc - */ - -typedef enum { - VIR_DOMAIN_XML_SECURE = 1, /* dump security sensitive informations too */ - VIR_DOMAIN_XML_INACTIVE = 2/* dump inactive domain informations */ -} virDomainXMLFlags; - -char * virDomainGetXMLDesc (virDomainPtr domain, - int flags); - -int virDomainBlockStats (virDomainPtr dom, - const char *path, - virDomainBlockStatsPtr stats, - size_t size); -int virDomainInterfaceStats (virDomainPtr dom, - const char *path, - virDomainInterfaceStatsPtr stats, - size_t size); - - -/* - * defined but not running domains - */ -virDomainPtr virDomainDefineXML (virConnectPtr conn, - const char *xml); -int virDomainUndefine (virDomainPtr domain); -int virConnectNumOfDefinedDomains (virConnectPtr conn); -int virConnectListDefinedDomains (virConnectPtr conn, - char **const names, - int maxnames); -int virDomainCreate (virDomainPtr domain); - -int virDomainGetAutostart (virDomainPtr domain, - int *autostart); -int virDomainSetAutostart (virDomainPtr domain, - int autostart); - -/** - * virVcpuInfo: structure for information about a virtual CPU in a domain. - */ - -typedef enum { - VIR_VCPU_OFFLINE = 0, /* the virtual CPU is offline */ - VIR_VCPU_RUNNING = 1, /* the virtual CPU is running */ - VIR_VCPU_BLOCKED = 2, /* the virtual CPU is blocked on resource */ -} virVcpuState; - -typedef struct _virVcpuInfo virVcpuInfo; -struct _virVcpuInfo { - unsigned int number; /* virtual CPU number */ - int state; /* value from virVcpuState */ - unsigned long long cpuTime; /* CPU time used, in nanoseconds */ - int cpu; /* real CPU number, or -1 if offline */ -}; -typedef virVcpuInfo *virVcpuInfoPtr; - -int virDomainSetVcpus (virDomainPtr domain, - unsigned int nvcpus); - -int virDomainPinVcpu (virDomainPtr domain, - unsigned int vcpu, - unsigned char *cpumap, - int maplen); - -/** - * VIR_USE_CPU: - * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN/OUT) - * @cpu: the physical CPU number - * - * This macro is to be used in conjonction with virDomainPinVcpu() API. - * USE_CPU macro set the bit (CPU usable) of the related cpu in cpumap. - */ - -#define VIR_USE_CPU(cpumap,cpu) (cpumap[(cpu)/8] |= (1<<((cpu)%8))) - -/** - * VIR_UNUSE_CPU: - * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN/OUT) - * @cpu: the physical CPU number - * - * This macro is to be used in conjonction with virDomainPinVcpu() API. - * USE_CPU macro reset the bit (CPU not usable) of the related cpu in cpumap. - */ - -#define VIR_UNUSE_CPU(cpumap,cpu) (cpumap[(cpu)/8] &= ~(1<<((cpu)%8))) - -/** - * VIR_CPU_MAPLEN: - * @cpu: number of physical CPUs - * - * This macro is to be used in conjonction with virDomainPinVcpu() API. - * It returns the length (in bytes) required to store the complete - * CPU map between a single virtual & all physical CPUs of a domain. - */ - -#define VIR_CPU_MAPLEN(cpu) (((cpu)+7)/8) - - -int virDomainGetVcpus (virDomainPtr domain, - virVcpuInfoPtr info, - int maxinfo, - unsigned char *cpumaps, - int maplen); - -/** - * VIR_CPU_USABLE: - * @cpumaps: pointer to an array of cpumap (in 8-bit bytes) (IN) - * @maplen: the length (in bytes) of one cpumap - * @vcpu: the virtual CPU number - * @cpu: the physical CPU number - * - * This macro is to be used in conjonction with virDomainGetVcpus() API. - * VIR_CPU_USABLE macro returns a non zero value (true) if the cpu - * is usable by the vcpu, and 0 otherwise. - */ - -#define VIR_CPU_USABLE(cpumaps,maplen,vcpu,cpu) \ - (cpumaps[((vcpu)*(maplen))+((cpu)/8)] & (1<<((cpu)%8))) - -/** - * VIR_COPY_CPUMAP: - * @cpumaps: pointer to an array of cpumap (in 8-bit bytes) (IN) - * @maplen: the length (in bytes) of one cpumap - * @vcpu: the virtual CPU number - * @cpumap: pointer to a cpumap (in 8-bit bytes) (OUT) - * This cpumap must be previously allocated by the caller - * (ie: malloc(maplen)) - * - * This macro is to be used in conjonction with virDomainGetVcpus() and - * virDomainPinVcpu() APIs. VIR_COPY_CPUMAP macro extract the cpumap of - * the specified vcpu from cpumaps array and copy it into cpumap to be used - * later by virDomainPinVcpu() API. - */ -#define VIR_COPY_CPUMAP(cpumaps,maplen,vcpu,cpumap) \ - memcpy(cpumap, &(cpumaps[(vcpu)*(maplen)]), (maplen)) - - -/** - * VIR_GET_CPUMAP: - * @cpumaps: pointer to an array of cpumap (in 8-bit bytes) (IN) - * @maplen: the length (in bytes) of one cpumap - * @vcpu: the virtual CPU number - * - * This macro is to be used in conjonction with virDomainGetVcpus() and - * virDomainPinVcpu() APIs. VIR_GET_CPUMAP macro returns a pointer to the - * cpumap of the specified vcpu from cpumaps array. - */ -#define VIR_GET_CPUMAP(cpumaps,maplen,vcpu) &(cpumaps[(vcpu)*(maplen)]) - -int virDomainAttachDevice(virDomainPtr domain, const char *xml); -int virDomainDetachDevice(virDomainPtr domain, const char *xml); - -/* - * NUMA support - */ - -int virNodeGetCellsFreeMemory(virConnectPtr conn, - unsigned long long *freeMems, - int startCell, - int maxCells); - -/* - * Virtual Networks API - */ - -/** - * virNetwork: - * - * a virNetwork is a private structure representing a virtual network. - */ -typedef struct _virNetwork virNetwork; - -/** - * virNetworkPtr: - * - * a virNetworkPtr is pointer to a virNetwork private structure, this is the - * type used to reference a virtual network in the API. - */ -typedef virNetwork *virNetworkPtr; - -/* - * Get connection from network. - */ -virConnectPtr virNetworkGetConnect (virNetworkPtr network); - -/* - * List active networks - */ -int virConnectNumOfNetworks (virConnectPtr conn); -int virConnectListNetworks (virConnectPtr conn, - char **const names, - int maxnames); - -/* - * List inactive networks - */ -int virConnectNumOfDefinedNetworks (virConnectPtr conn); -int virConnectListDefinedNetworks (virConnectPtr conn, - char **const names, - int maxnames); - -/* - * Lookup network by name or uuid - */ -virNetworkPtr virNetworkLookupByName (virConnectPtr conn, - const char *name); -virNetworkPtr virNetworkLookupByUUID (virConnectPtr conn, - const unsigned char *uuid); -virNetworkPtr virNetworkLookupByUUIDString (virConnectPtr conn, - const char *uuid); - -/* - * Create active transient network - */ -virNetworkPtr virNetworkCreateXML (virConnectPtr conn, - const char *xmlDesc); - -/* - * Define inactive persistent network - */ -virNetworkPtr virNetworkDefineXML (virConnectPtr conn, - const char *xmlDesc); - -/* - * Delete persistent network - */ -int virNetworkUndefine (virNetworkPtr network); - -/* - * Activate persistent network - */ -int virNetworkCreate (virNetworkPtr network); - -/* - * Network destroy/free - */ -int virNetworkDestroy (virNetworkPtr network); -int virNetworkFree (virNetworkPtr network); - -/* - * Network informations - */ -const char* virNetworkGetName (virNetworkPtr network); -int virNetworkGetUUID (virNetworkPtr network, - unsigned char *uuid); -int virNetworkGetUUIDString (virNetworkPtr network, - char *buf); -char * virNetworkGetXMLDesc (virNetworkPtr network, - int flags); -char * virNetworkGetBridgeName (virNetworkPtr network); - -int virNetworkGetAutostart (virNetworkPtr network, - int *autostart); -int virNetworkSetAutostart (virNetworkPtr network, - int autostart); - #ifdef __cplusplus } #endif diff -r 0d270ffcf3f0 include/libvirt/libvirt.h.in --- a/include/libvirt/libvirt.h.in Sat Oct 27 00:23:28 2007 +0000 +++ b/include/libvirt/libvirt.h.in Sat Oct 27 13:30:05 2007 -0400 @@ -16,263 +16,26 @@ #include <sys/types.h> +#include <libvirt/connection.h> +#include <libvirt/node.h> +#include <libvirt/domain.h> +#include <libvirt/network.h> + #ifdef __cplusplus extern "C" { #endif -/** - * virConnect: - * - * a virConnect is a private structure representing a connection to - * the Xen Hypervisor. - */ -typedef struct _virConnect virConnect; + +/* library versionning */ /** - * virConnectPtr: + * LIBVIR_VERSION_NUMBER: * - * a virConnectPtr is pointer to a virConnect private structure, this is the - * type used to reference a connection to the Xen Hypervisor in the API. - */ -typedef virConnect *virConnectPtr; - -/** - * virDomain: - * - * a virDomain is a private structure representing a Xen domain. - */ -typedef struct _virDomain virDomain; - -/** - * virDomainPtr: - * - * a virDomainPtr is pointer to a virDomain private structure, this is the - * type used to reference a Xen domain in the API. - */ -typedef virDomain *virDomainPtr; - -/** - * virDomainState: - * - * A domain may be in different states at a given point in time - */ -typedef enum { - VIR_DOMAIN_NOSTATE = 0, /* no state */ - VIR_DOMAIN_RUNNING = 1, /* the domain is running */ - VIR_DOMAIN_BLOCKED = 2, /* the domain is blocked on resource */ - VIR_DOMAIN_PAUSED = 3, /* the domain is paused by user */ - VIR_DOMAIN_SHUTDOWN= 4, /* the domain is being shut down */ - VIR_DOMAIN_SHUTOFF = 5, /* the domain is shut off */ - VIR_DOMAIN_CRASHED = 6 /* the domain is crashed */ -} virDomainState; - -/** - * virDomainInfoPtr: - * - * a virDomainInfo is a structure filled by virDomainGetInfo() and extracting - * runtime informations for a given active Domain + * Macro providing the version of the library as + * version * 1,000,000 + minor * 1000 + micro */ -typedef struct _virDomainInfo virDomainInfo; - -struct _virDomainInfo { - unsigned char state; /* the running state, one of virDomainFlags */ - unsigned long maxMem; /* the maximum memory in KBytes allowed */ - unsigned long memory; /* the memory in KBytes used by the domain */ - unsigned short nrVirtCpu; /* the number of virtual CPUs for the domain */ - unsigned long long cpuTime; /* the CPU time used in nanoseconds */ -}; - -/** - * virDomainInfoPtr: - * - * a virDomainInfoPtr is a pointer to a virDomainInfo structure. - */ - -typedef virDomainInfo *virDomainInfoPtr; - -/** - * virDomainCreateFlags: - * - * Flags OR'ed together to provide specific behaviour when creating a - * Domain. - */ -typedef enum { - VIR_DOMAIN_NONE = 0 -} virDomainCreateFlags; - -/** - * virNodeInfoPtr: - * - * a virNodeInfo is a structure filled by virNodeGetInfo() and providing - * the informations for the Node. - */ - -typedef struct _virNodeInfo virNodeInfo; - -struct _virNodeInfo { - char model[32]; /* string indicating the CPU model */ - unsigned long memory;/* memory size in kilobytes */ - unsigned int cpus; /* the number of active CPUs */ - unsigned int mhz; /* expected CPU frequency */ - unsigned int nodes; /* the number of NUMA cell, 1 for uniform mem access */ - unsigned int sockets;/* number of CPU socket per node */ - unsigned int cores; /* number of core per socket */ - unsigned int threads;/* number of threads per core */ -}; - - -/** - * virDomainSchedParameterType: - * - * A scheduler parameter field type - */ -typedef enum { - VIR_DOMAIN_SCHED_FIELD_INT = 1, /* integer case */ - VIR_DOMAIN_SCHED_FIELD_UINT = 2, /* unsigned integer case */ - VIR_DOMAIN_SCHED_FIELD_LLONG = 3, /* long long case */ - VIR_DOMAIN_SCHED_FIELD_ULLONG = 4, /* unsigned long long case */ - VIR_DOMAIN_SCHED_FIELD_DOUBLE = 5, /* double case */ - VIR_DOMAIN_SCHED_FIELD_BOOLEAN = 6 /* boolean(character) case */ -} virSchedParameterType; - -/** - * VIR_DOMAIN_SCHED_FIELD_LENGTH: - * - * Macro providing the field length of virSchedParameter - */ - -#define VIR_DOMAIN_SCHED_FIELD_LENGTH 80 - -/** - * virDomainSchedParameter: - * - * a virDomainSchedParameter is the set of scheduler parameters - */ - -typedef struct _virSchedParameter virSchedParameter; - -struct _virSchedParameter { - char field[VIR_DOMAIN_SCHED_FIELD_LENGTH]; /* parameter name */ - int type; /* parameter type */ - union { - int i; /* data for integer case */ - unsigned int ui; /* data for unsigned integer case */ - long long int l; /* data for long long integer case */ - unsigned long long int ul; /* data for unsigned long long integer case */ - double d; /* data for double case */ - char b; /* data for char case */ - } value; /* parameter value */ -}; - -/** - * virSchedParameterPtr: - * - * a virSchedParameterPtr is a pointer to a virSchedParameter structure. - */ - -typedef virSchedParameter *virSchedParameterPtr; - -/* - * Fetch scheduler parameters, caller allocates 'params' field of size 'nparams' - */ -int virDomainGetSchedulerParameters (virDomainPtr domain, - virSchedParameterPtr params, - int *nparams); - -/* - * Change scheduler parameters - */ -int virDomainSetSchedulerParameters (virDomainPtr domain, - virSchedParameterPtr params, - int nparams); - -/** - * virDomainBlockStats: - * - * Block device stats for virDomainBlockStats. - * - * Hypervisors may return a field set to ((long long)-1) which indicates - * that the hypervisor does not support that statistic. - * - * NB. Here 'long long' means 64 bit integer. - */ -typedef struct _virDomainBlockStats virDomainBlockStatsStruct; - -struct _virDomainBlockStats { - long long rd_req; - long long rd_bytes; - long long wr_req; - long long wr_bytes; - long long errs; /* In Xen this returns the mysterious 'oo_req'. */ -}; - -/** - * virDomainBlockStatsPtr: - * - * A pointer to a virDomainBlockStats structure - */ -typedef virDomainBlockStatsStruct *virDomainBlockStatsPtr; - -/** - * virDomainInterfaceStats: - * - * Network interface stats for virDomainInterfaceStats. - * - * Hypervisors may return a field set to ((long long)-1) which indicates - * that the hypervisor does not support that statistic. - * - * NB. Here 'long long' means 64 bit integer. - */ -typedef struct _virDomainInterfaceStats virDomainInterfaceStatsStruct; - -struct _virDomainInterfaceStats { - long long rx_bytes; - long long rx_packets; - long long rx_errs; - long long rx_drop; - long long tx_bytes; - long long tx_packets; - long long tx_errs; - long long tx_drop; -}; - -/** - * virDomainInterfaceStatsPtr: - * - * A pointe to a virDomainInterfaceStats structure - */ -typedef virDomainInterfaceStatsStruct *virDomainInterfaceStatsPtr; - - -/* Domain migration flags. */ -typedef enum { - VIR_MIGRATE_LIVE = 1, /* live migration */ -} virDomainMigrateFlags; - -/* Domain migration. */ -virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn, - unsigned long flags, const char *dname, - const char *uri, unsigned long bandwidth); - -/** - * VIR_NODEINFO_MAXCPUS: - * @nodeinfo: virNodeInfo instance - * - * This macro is to calculate the total number of CPUs supported - * but not neccessarily active in the host. - */ - - -#define VIR_NODEINFO_MAXCPUS(nodeinfo) ((nodeinfo).nodes*(nodeinfo).sockets*(nodeinfo).cores*(nodeinfo).threads) - -/** - * virNodeInfoPtr: - * - * a virNodeInfoPtr is a pointer to a virNodeInfo structure. - */ - -typedef virNodeInfo *virNodeInfoPtr; +#define LIBVIR_VERSION_NUMBER @LIBVIRT_VERSION_NUMBER@ /** * VIR_UUID_BUFLEN: @@ -292,17 +55,6 @@ typedef virNodeInfo *virNodeInfoPtr; #define VIR_UUID_STRING_BUFLEN (36+1) -/* library versionning */ - -/** - * LIBVIR_VERSION_NUMBER: - * - * Macro providing the version of the library as - * version * 1,000,000 + minor * 1000 + micro - */ - -#define LIBVIR_VERSION_NUMBER @LIBVIRT_VERSION_NUMBER@ - int virGetVersion (unsigned long *libVer, const char *type, unsigned long *typeVer); @@ -312,380 +64,6 @@ int virGetVersion (unsigned long *lib */ int virInitialize (void); -virConnectPtr virConnectOpen (const char *name); -virConnectPtr virConnectOpenReadOnly (const char *name); -int virConnectClose (virConnectPtr conn); -const char * virConnectGetType (virConnectPtr conn); -int virConnectGetVersion (virConnectPtr conn, - unsigned long *hvVer); -char * virConnectGetHostname (virConnectPtr conn); -char * virConnectGetURI (virConnectPtr conn); - - -/* - * Capabilities of the connection / driver. - */ - -int virConnectGetMaxVcpus (virConnectPtr conn, - const char *type); -int virNodeGetInfo (virConnectPtr conn, - virNodeInfoPtr info); -char * virConnectGetCapabilities (virConnectPtr conn); - -unsigned long long virNodeGetFreeMemory (virConnectPtr conn); - -/* - * Gather list of running domains - */ -int virConnectListDomains (virConnectPtr conn, - int *ids, - int maxids); - -/* - * Number of domains - */ -int virConnectNumOfDomains (virConnectPtr conn); - - -/* - * Get connection from domain. - */ -virConnectPtr virDomainGetConnect (virDomainPtr domain); - -/* - * Domain creation and destruction - */ -virDomainPtr virDomainCreateLinux (virConnectPtr conn, - const char *xmlDesc, - unsigned int flags); -virDomainPtr virDomainLookupByName (virConnectPtr conn, - const char *name); -virDomainPtr virDomainLookupByID (virConnectPtr conn, - int id); -virDomainPtr virDomainLookupByUUID (virConnectPtr conn, - const unsigned char *uuid); -virDomainPtr virDomainLookupByUUIDString (virConnectPtr conn, - const char *uuid); - -int virDomainShutdown (virDomainPtr domain); -int virDomainReboot (virDomainPtr domain, - unsigned int flags); -int virDomainDestroy (virDomainPtr domain); -int virDomainFree (virDomainPtr domain); - -/* - * Domain suspend/resume - */ -int virDomainSuspend (virDomainPtr domain); -int virDomainResume (virDomainPtr domain); - -/* - * Domain save/restore - */ -int virDomainSave (virDomainPtr domain, - const char *to); -int virDomainRestore (virConnectPtr conn, - const char *from); - -/* - * Domain core dump - */ -int virDomainCoreDump (virDomainPtr domain, - const char *to, - int flags); - -/* - * Domain runtime informations - */ -int virDomainGetInfo (virDomainPtr domain, - virDomainInfoPtr info); - -/* - * Return scheduler type in effect 'sedf', 'credit', 'linux' - */ -char * virDomainGetSchedulerType(virDomainPtr domain, - int *nparams); - -/* - * Dynamic control of domains - */ -const char * virDomainGetName (virDomainPtr domain); -unsigned int virDomainGetID (virDomainPtr domain); -int virDomainGetUUID (virDomainPtr domain, - unsigned char *uuid); -int virDomainGetUUIDString (virDomainPtr domain, - char *buf); -char * virDomainGetOSType (virDomainPtr domain); -unsigned long virDomainGetMaxMemory (virDomainPtr domain); -int virDomainSetMaxMemory (virDomainPtr domain, - unsigned long memory); -int virDomainSetMemory (virDomainPtr domain, - unsigned long memory); -int virDomainGetMaxVcpus (virDomainPtr domain); - -/* - * XML domain description - */ -/** - * virDomainXMLFlags: - * - * Flags available for virDomainGetXMLDesc - */ - -typedef enum { - VIR_DOMAIN_XML_SECURE = 1, /* dump security sensitive informations too */ - VIR_DOMAIN_XML_INACTIVE = 2/* dump inactive domain informations */ -} virDomainXMLFlags; - -char * virDomainGetXMLDesc (virDomainPtr domain, - int flags); - -int virDomainBlockStats (virDomainPtr dom, - const char *path, - virDomainBlockStatsPtr stats, - size_t size); -int virDomainInterfaceStats (virDomainPtr dom, - const char *path, - virDomainInterfaceStatsPtr stats, - size_t size); - - -/* - * defined but not running domains - */ -virDomainPtr virDomainDefineXML (virConnectPtr conn, - const char *xml); -int virDomainUndefine (virDomainPtr domain); -int virConnectNumOfDefinedDomains (virConnectPtr conn); -int virConnectListDefinedDomains (virConnectPtr conn, - char **const names, - int maxnames); -int virDomainCreate (virDomainPtr domain); - -int virDomainGetAutostart (virDomainPtr domain, - int *autostart); -int virDomainSetAutostart (virDomainPtr domain, - int autostart); - -/** - * virVcpuInfo: structure for information about a virtual CPU in a domain. - */ - -typedef enum { - VIR_VCPU_OFFLINE = 0, /* the virtual CPU is offline */ - VIR_VCPU_RUNNING = 1, /* the virtual CPU is running */ - VIR_VCPU_BLOCKED = 2, /* the virtual CPU is blocked on resource */ -} virVcpuState; - -typedef struct _virVcpuInfo virVcpuInfo; -struct _virVcpuInfo { - unsigned int number; /* virtual CPU number */ - int state; /* value from virVcpuState */ - unsigned long long cpuTime; /* CPU time used, in nanoseconds */ - int cpu; /* real CPU number, or -1 if offline */ -}; -typedef virVcpuInfo *virVcpuInfoPtr; - -int virDomainSetVcpus (virDomainPtr domain, - unsigned int nvcpus); - -int virDomainPinVcpu (virDomainPtr domain, - unsigned int vcpu, - unsigned char *cpumap, - int maplen); - -/** - * VIR_USE_CPU: - * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN/OUT) - * @cpu: the physical CPU number - * - * This macro is to be used in conjonction with virDomainPinVcpu() API. - * USE_CPU macro set the bit (CPU usable) of the related cpu in cpumap. - */ - -#define VIR_USE_CPU(cpumap,cpu) (cpumap[(cpu)/8] |= (1<<((cpu)%8))) - -/** - * VIR_UNUSE_CPU: - * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN/OUT) - * @cpu: the physical CPU number - * - * This macro is to be used in conjonction with virDomainPinVcpu() API. - * USE_CPU macro reset the bit (CPU not usable) of the related cpu in cpumap. - */ - -#define VIR_UNUSE_CPU(cpumap,cpu) (cpumap[(cpu)/8] &= ~(1<<((cpu)%8))) - -/** - * VIR_CPU_MAPLEN: - * @cpu: number of physical CPUs - * - * This macro is to be used in conjonction with virDomainPinVcpu() API. - * It returns the length (in bytes) required to store the complete - * CPU map between a single virtual & all physical CPUs of a domain. - */ - -#define VIR_CPU_MAPLEN(cpu) (((cpu)+7)/8) - - -int virDomainGetVcpus (virDomainPtr domain, - virVcpuInfoPtr info, - int maxinfo, - unsigned char *cpumaps, - int maplen); - -/** - * VIR_CPU_USABLE: - * @cpumaps: pointer to an array of cpumap (in 8-bit bytes) (IN) - * @maplen: the length (in bytes) of one cpumap - * @vcpu: the virtual CPU number - * @cpu: the physical CPU number - * - * This macro is to be used in conjonction with virDomainGetVcpus() API. - * VIR_CPU_USABLE macro returns a non zero value (true) if the cpu - * is usable by the vcpu, and 0 otherwise. - */ - -#define VIR_CPU_USABLE(cpumaps,maplen,vcpu,cpu) \ - (cpumaps[((vcpu)*(maplen))+((cpu)/8)] & (1<<((cpu)%8))) - -/** - * VIR_COPY_CPUMAP: - * @cpumaps: pointer to an array of cpumap (in 8-bit bytes) (IN) - * @maplen: the length (in bytes) of one cpumap - * @vcpu: the virtual CPU number - * @cpumap: pointer to a cpumap (in 8-bit bytes) (OUT) - * This cpumap must be previously allocated by the caller - * (ie: malloc(maplen)) - * - * This macro is to be used in conjonction with virDomainGetVcpus() and - * virDomainPinVcpu() APIs. VIR_COPY_CPUMAP macro extract the cpumap of - * the specified vcpu from cpumaps array and copy it into cpumap to be used - * later by virDomainPinVcpu() API. - */ -#define VIR_COPY_CPUMAP(cpumaps,maplen,vcpu,cpumap) \ - memcpy(cpumap, &(cpumaps[(vcpu)*(maplen)]), (maplen)) - - -/** - * VIR_GET_CPUMAP: - * @cpumaps: pointer to an array of cpumap (in 8-bit bytes) (IN) - * @maplen: the length (in bytes) of one cpumap - * @vcpu: the virtual CPU number - * - * This macro is to be used in conjonction with virDomainGetVcpus() and - * virDomainPinVcpu() APIs. VIR_GET_CPUMAP macro returns a pointer to the - * cpumap of the specified vcpu from cpumaps array. - */ -#define VIR_GET_CPUMAP(cpumaps,maplen,vcpu) &(cpumaps[(vcpu)*(maplen)]) - -int virDomainAttachDevice(virDomainPtr domain, const char *xml); -int virDomainDetachDevice(virDomainPtr domain, const char *xml); - -/* - * NUMA support - */ - -int virNodeGetCellsFreeMemory(virConnectPtr conn, - unsigned long long *freeMems, - int startCell, - int maxCells); - -/* - * Virtual Networks API - */ - -/** - * virNetwork: - * - * a virNetwork is a private structure representing a virtual network. - */ -typedef struct _virNetwork virNetwork; - -/** - * virNetworkPtr: - * - * a virNetworkPtr is pointer to a virNetwork private structure, this is the - * type used to reference a virtual network in the API. - */ -typedef virNetwork *virNetworkPtr; - -/* - * Get connection from network. - */ -virConnectPtr virNetworkGetConnect (virNetworkPtr network); - -/* - * List active networks - */ -int virConnectNumOfNetworks (virConnectPtr conn); -int virConnectListNetworks (virConnectPtr conn, - char **const names, - int maxnames); - -/* - * List inactive networks - */ -int virConnectNumOfDefinedNetworks (virConnectPtr conn); -int virConnectListDefinedNetworks (virConnectPtr conn, - char **const names, - int maxnames); - -/* - * Lookup network by name or uuid - */ -virNetworkPtr virNetworkLookupByName (virConnectPtr conn, - const char *name); -virNetworkPtr virNetworkLookupByUUID (virConnectPtr conn, - const unsigned char *uuid); -virNetworkPtr virNetworkLookupByUUIDString (virConnectPtr conn, - const char *uuid); - -/* - * Create active transient network - */ -virNetworkPtr virNetworkCreateXML (virConnectPtr conn, - const char *xmlDesc); - -/* - * Define inactive persistent network - */ -virNetworkPtr virNetworkDefineXML (virConnectPtr conn, - const char *xmlDesc); - -/* - * Delete persistent network - */ -int virNetworkUndefine (virNetworkPtr network); - -/* - * Activate persistent network - */ -int virNetworkCreate (virNetworkPtr network); - -/* - * Network destroy/free - */ -int virNetworkDestroy (virNetworkPtr network); -int virNetworkFree (virNetworkPtr network); - -/* - * Network informations - */ -const char* virNetworkGetName (virNetworkPtr network); -int virNetworkGetUUID (virNetworkPtr network, - unsigned char *uuid); -int virNetworkGetUUIDString (virNetworkPtr network, - char *buf); -char * virNetworkGetXMLDesc (virNetworkPtr network, - int flags); -char * virNetworkGetBridgeName (virNetworkPtr network); - -int virNetworkGetAutostart (virNetworkPtr network, - int *autostart); -int virNetworkSetAutostart (virNetworkPtr network, - int autostart); - #ifdef __cplusplus } #endif diff -r 0d270ffcf3f0 include/libvirt/network.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/libvirt/network.h Sat Oct 27 13:34:08 2007 -0400 @@ -0,0 +1,125 @@ +/* -*- c -*- + * network.h: + * Summary: virtual network interfaces + * Description: Provides the interfaces of the libvirt library to handle + * virtual networks from a process running in the host + * + * Copy: Copyright (C) 2005-2007 Red Hat, Inc. + * + * See COPYING.LIB for the License of this software + * + * Author: Daniel Veillard <veillard@redhat.com> + */ + + +#ifndef __VIR_VIRLIB_H__ +#error "Do not include network.h directly. Use libvirt.h instead" +#endif + +#ifndef __VIR_VIRLIB_NETWORK_H__ +#define __VIR_VIRLIB_NETWORK_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Virtual Networks API + */ + +/** + * virNetwork: + * + * a virNetwork is a private structure representing a virtual network. + */ +typedef struct _virNetwork virNetwork; + +/** + * virNetworkPtr: + * + * a virNetworkPtr is pointer to a virNetwork private structure, this is the + * type used to reference a virtual network in the API. + */ +typedef virNetwork *virNetworkPtr; + +/* + * Get connection from network. + */ +virConnectPtr virNetworkGetConnect (virNetworkPtr network); + +/* + * List active networks + */ +int virConnectNumOfNetworks (virConnectPtr conn); +int virConnectListNetworks (virConnectPtr conn, + char **const names, + int maxnames); + +/* + * List inactive networks + */ +int virConnectNumOfDefinedNetworks (virConnectPtr conn); +int virConnectListDefinedNetworks (virConnectPtr conn, + char **const names, + int maxnames); + +/* + * Lookup network by name or uuid + */ +virNetworkPtr virNetworkLookupByName (virConnectPtr conn, + const char *name); +virNetworkPtr virNetworkLookupByUUID (virConnectPtr conn, + const unsigned char *uuid); +virNetworkPtr virNetworkLookupByUUIDString (virConnectPtr conn, + const char *uuid); + +/* + * Create active transient network + */ +virNetworkPtr virNetworkCreateXML (virConnectPtr conn, + const char *xmlDesc); + +/* + * Define inactive persistent network + */ +virNetworkPtr virNetworkDefineXML (virConnectPtr conn, + const char *xmlDesc); + +/* + * Delete persistent network + */ +int virNetworkUndefine (virNetworkPtr network); + +/* + * Activate persistent network + */ +int virNetworkCreate (virNetworkPtr network); + +/* + * Network destroy/free + */ +int virNetworkDestroy (virNetworkPtr network); +int virNetworkFree (virNetworkPtr network); + +/* + * Network informations + */ +const char* virNetworkGetName (virNetworkPtr network); +int virNetworkGetUUID (virNetworkPtr network, + unsigned char *uuid); +int virNetworkGetUUIDString (virNetworkPtr network, + char *buf); +char * virNetworkGetXMLDesc (virNetworkPtr network, + int flags); +char * virNetworkGetBridgeName (virNetworkPtr network); + +int virNetworkGetAutostart (virNetworkPtr network, + int *autostart); +int virNetworkSetAutostart (virNetworkPtr network, + int autostart); + +#ifdef __cplusplus +} +#endif + +#endif /* __VIR_VIRLIB_NETWORK_H__ */ diff -r 0d270ffcf3f0 include/libvirt/node.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/libvirt/node.h Sat Oct 27 13:22:06 2007 -0400 @@ -0,0 +1,90 @@ +/* -*- c -*- + * node.h: + * Summary: host node information + * Description: Provides the interfaces of the libvirt library to handle + * information about the host node. + * + * Copy: Copyright (C) 2005-2007 Red Hat, Inc. + * + * See COPYING.LIB for the License of this software + * + * Author: Daniel Veillard <veillard@redhat.com> + */ + + + +#ifndef __VIR_VIRLIB_H__ +#error "Do not include node.h directly. Use libvirt.h instead" +#endif + +#ifndef __VIR_VIRLIB_NODE_H__ +#define __VIR_VIRLIB_NODE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * virNodeInfo: + * + * a virNodeInfo is a structure filled by virNodeGetInfo() and providing + * the informations for the Node. + */ + +typedef struct _virNodeInfo virNodeInfo; + +struct _virNodeInfo { + char model[32]; /* string indicating the CPU model */ + unsigned long memory;/* memory size in kilobytes */ + unsigned int cpus; /* the number of active CPUs */ + unsigned int mhz; /* expected CPU frequency */ + unsigned int nodes; /* the number of NUMA cell, 1 for uniform mem access */ + unsigned int sockets;/* number of CPU socket per node */ + unsigned int cores; /* number of core per socket */ + unsigned int threads;/* number of threads per core */ +}; + +/** + * virNodeInfoPtr: + * + * a virNodeInfoPtr is a pointer to a virNodeInfo structure. + */ + +typedef virNodeInfo *virNodeInfoPtr; + + +/** + * VIR_NODEINFO_MAXCPUS: + * @nodeinfo: virNodeInfo instance + * + * This macro is to calculate the total number of CPUs supported + * but not neccessarily active in the host. + */ + + +#define VIR_NODEINFO_MAXCPUS(nodeinfo) ((nodeinfo).nodes*(nodeinfo).sockets*(nodeinfo).cores*(nodeinfo).threads) + +/* + * Capabilities of the connection / driver. + */ + +int virNodeGetInfo (virConnectPtr conn, + virNodeInfoPtr info); +char * virConnectGetCapabilities (virConnectPtr conn); + +unsigned long long virNodeGetFreeMemory (virConnectPtr conn); + +/* + * NUMA support + */ + +int virNodeGetCellsFreeMemory(virConnectPtr conn, + unsigned long long *freeMems, + int startCell, + int maxCells); + +#ifdef __cplusplus +} +#endif + +#endif /* __VIR_VIRLIB_NODE_H__ */ diff -r 0d270ffcf3f0 src/libvirt.c --- a/src/libvirt.c Sat Oct 27 00:23:28 2007 +0000 +++ b/src/libvirt.c Sat Oct 27 13:33:18 2007 -0400 @@ -10,7 +10,6 @@ */ #include "config.h" -#include "libvirt/libvirt.h" #include <stdio.h> #include <stdlib.h> -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

Daniel P. Berrange wrote:
This patch splits up the libvirt.h file into multiple pieces. The big header file was getting rather long & hard to follow, with API calls for domains and networks all mixed together, and macros & typedefs & methods all mixed up. Adding another 25 APIs for storage won't improve this. So this splits up the header into
libvirt/connection.h - connection related API calls & objects libvirt/node.h - host node information APIs & objects libvirt/domain.h - hypervisor/domain API calls & objects libvirt/network.h - virtual networking API calls & objects
The original libvirt.h, now simply #include's all four of these files. The header files aren't intended to be included directly - apps carry on just using the main header file.
No real preference either way with this one. Rich. -- Emerging Technologies, Red Hat - http://et.redhat.com/~rjones/ Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SL4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 03798903

On Mon, Oct 29, 2007 at 03:56:18AM +0000, Daniel P. Berrange wrote:
This patch splits up the libvirt.h file into multiple pieces. The big header file was getting rather long & hard to follow, with API calls for domains and networks all mixed together, and macros & typedefs & methods all mixed up. Adding another 25 APIs for storage won't improve this. So this splits up the header into
libvirt/connection.h - connection related API calls & objects libvirt/node.h - host node information APIs & objects libvirt/domain.h - hypervisor/domain API calls & objects libvirt/network.h - virtual networking API calls & objects
The original libvirt.h, now simply #include's all four of these files. The header files aren't intended to be included directly - apps carry on just using the main header file.
The main impact is not covered by this patch, it's the documentation generation, which also mean that on the web site the doc page for libvirt would become nearly empty and 4 new pages would be added. I'm not against the change (though it will break all previous reference to documentation functions embedded in list archives) but the documentation impact seems to not have been considered and it's not neglectible, really. Daniel -- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard@redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/

On Wed, Oct 31, 2007 at 09:53:07AM -0400, Daniel Veillard wrote:
On Mon, Oct 29, 2007 at 03:56:18AM +0000, Daniel P. Berrange wrote:
This patch splits up the libvirt.h file into multiple pieces. The big header file was getting rather long & hard to follow, with API calls for domains and networks all mixed together, and macros & typedefs & methods all mixed up. Adding another 25 APIs for storage won't improve this. So this splits up the header into
libvirt/connection.h - connection related API calls & objects libvirt/node.h - host node information APIs & objects libvirt/domain.h - hypervisor/domain API calls & objects libvirt/network.h - virtual networking API calls & objects
The original libvirt.h, now simply #include's all four of these files. The header files aren't intended to be included directly - apps carry on just using the main header file.
The main impact is not covered by this patch, it's the documentation generation, which also mean that on the web site the doc page for libvirt would become nearly empty and 4 new pages would be added. I'm not against the change (though it will break all previous reference to documentation functions embedded in list archives) but the documentation impact seems to not have been considered and it's not neglectible, really.
Hmm, yes I forgot about the docs - it will have an impact there. One could argue though that the impact will be positive, since it'll split the docs into more managable chunks each page dealing with a specific class of APIs. In any case, this patch doesn't really block any of the storage work - its just something I tried out. We can easily stay with existing scheme and reconsider it another time. Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

On Wed, Oct 31, 2007 at 03:20:00PM +0000, Daniel P. Berrange wrote:
On Wed, Oct 31, 2007 at 09:53:07AM -0400, Daniel Veillard wrote:
On Mon, Oct 29, 2007 at 03:56:18AM +0000, Daniel P. Berrange wrote:
This patch splits up the libvirt.h file into multiple pieces. The big header file was getting rather long & hard to follow, with API calls for domains and networks all mixed together, and macros & typedefs & methods all mixed up. Adding another 25 APIs for storage won't improve this. So this splits up the header into
libvirt/connection.h - connection related API calls & objects libvirt/node.h - host node information APIs & objects libvirt/domain.h - hypervisor/domain API calls & objects libvirt/network.h - virtual networking API calls & objects
The original libvirt.h, now simply #include's all four of these files. The header files aren't intended to be included directly - apps carry on just using the main header file.
The main impact is not covered by this patch, it's the documentation generation, which also mean that on the web site the doc page for libvirt would become nearly empty and 4 new pages would be added. I'm not against the change (though it will break all previous reference to documentation functions embedded in list archives) but the documentation impact seems to not have been considered and it's not neglectible, really.
Hmm, yes I forgot about the docs - it will have an impact there. One could argue though that the impact will be positive, since it'll split the docs into more managable chunks each page dealing with a specific class of APIs.
I'm not against, we just need to check all cross references :-\
In any case, this patch doesn't really block any of the storage work - its just something I tried out. We can easily stay with existing scheme and reconsider it another time.
let's just make it a separate kind of change and track it on its own, I may give it some testing ... Daniel -- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard@redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/

This patch adds a public header file defining the application facing contract for the storage APIs. b/include/libvirt/storage.h | 215 +++++++++++++++++++++++++++++++++++++++++++ include/libvirt/libvirt.h | 1 include/libvirt/libvirt.h.in | 1 src/libvirt_sym.version | 39 +++++++ 4 files changed, 256 insertions(+) diff -r a123e74573bb include/libvirt/libvirt.h --- a/include/libvirt/libvirt.h Sat Oct 27 13:36:24 2007 -0400 +++ b/include/libvirt/libvirt.h Sat Oct 27 16:18:43 2007 -0400 @@ -20,6 +20,7 @@ #include <libvirt/node.h> #include <libvirt/domain.h> #include <libvirt/network.h> +#include <libvirt/storage.h> #ifdef __cplusplus extern "C" { diff -r a123e74573bb include/libvirt/libvirt.h.in --- a/include/libvirt/libvirt.h.in Sat Oct 27 13:36:24 2007 -0400 +++ b/include/libvirt/libvirt.h.in Sat Oct 27 16:18:43 2007 -0400 @@ -20,6 +20,7 @@ #include <libvirt/node.h> #include <libvirt/domain.h> #include <libvirt/network.h> +#include <libvirt/storage.h> #ifdef __cplusplus extern "C" { diff -r a123e74573bb include/libvirt/storage.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/libvirt/storage.h Sat Oct 27 16:18:43 2007 -0400 @@ -0,0 +1,215 @@ +/* -*- c -*- + * storage.h: + * Summary: storage management interfaces + * Description: Provides the interfaces of the libvirt library to handle + * storage management from a process running in the host + * + * Copy: Copyright (C) 2005-2007 Red Hat, Inc. + * + * See COPYING.LIB for the License of this software + * + * Author: Daniel Veillard <veillard@redhat.com> + */ + + + +#ifndef __VIR_VIRLIB_H__ +#error "Do not include storage.h directly. Use libvirt.h instead" +#endif + +#ifndef __VIR_VIRLIB_STORAGE_H__ +#define __VIR_VIRLIB_STORAGE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * virStoragePool: + * + * a virStoragePool is a private structure representing a storage pool + */ +typedef struct _virStoragePool virStoragePool; + +/** + * virStoragePoolPtr: + * + * a virStoragePoolPtr is pointer to a virStoragePool private structure, this is the + * type used to reference a storage pool in the API. + */ +typedef virStoragePool *virStoragePoolPtr; + + +typedef enum { + VIR_STORAGE_POOL_INACTIVE = 0, + VIR_STORAGE_POOL_ACTIVE = 1, +} virStoragePoolState; + +typedef struct _virStoragePoolInfo virStoragePoolInfo; + +struct _virStoragePoolInfo { + int state; /* virStoragePoolState flags */ + unsigned long long capacity; /* Logical size bytes */ + unsigned long long allocation; /* Current allocation bytes */ +}; + +typedef virStoragePoolInfo *virStoragePoolInfoPtr; + + +/** + * virStorageVol: + * + * a virStorageVol is a private structure representing a storage volume + */ +typedef struct _virStorageVol virStorageVol; + +/** + * virStorageVolPtr: + * + * a virStorageVolPtr is pointer to a virStorageVol private structure, this is the + * type used to reference a storage volume in the API. + */ +typedef virStorageVol *virStorageVolPtr; + + +typedef enum { + VIR_STORAGE_POOL_FILE = 0, + VIR_STORAGE_POOL_BLOCK = 1, +} virStoragePoolType; + +typedef struct _virStorageVolInfo virStorageVolInfo; + +struct _virStorageVolInfo { + int type; /* virStoragePoolType flags */ + unsigned long long capacity; /* Logical size bytes */ + unsigned long long allocation; /* Current allocation bytes */ +}; + +typedef virStorageVolInfo *virStorageVolInfoPtr; + +/* + * Get connection from pool. + */ +virConnectPtr virStoragePoolGetConnect (virStoragePoolPtr pool); + +/* + * List active storage pools + */ +int virConnectNumOfStoragePools (virConnectPtr conn); +int virConnectListStoragePools (virConnectPtr conn, + char **const names, + int maxnames); + +/* + * List inactive storage pools + */ +int virConnectNumOfDefinedStoragePools(virConnectPtr conn); +int virConnectListDefinedStoragePools(virConnectPtr conn, + char **const names, + int maxnames); + +/* + * Lookup network by name or uuid + */ +virStoragePoolPtr virStoragePoolLookupByName(virConnectPtr conn, + const char *name); +virStoragePoolPtr virStoragePoolLookupByUUID(virConnectPtr conn, + const unsigned char *uuid); +virStoragePoolPtr virStoragePoolLookupByUUIDString(virConnectPtr conn, + const char *uuid); + +/* + * Create active transient storage pool + */ +virStoragePoolPtr virStoragePoolCreateXML(virConnectPtr conn, + const char *xmlDesc); + +/* + * Define inactive persistent storage pool + */ +virStoragePoolPtr virStoragePoolDefineXML(virConnectPtr conn, + const char *xmlDesc); + +/* + * Delete persistent storage pool + */ +int virStoragePoolUndefine(virStoragePoolPtr pool); + +/* + * Activate persistent pool + */ +int virStoragePoolCreate(virStoragePoolPtr pool); + +/* + * StoragePool destroy/free + */ +int virStoragePoolShutdown(virStoragePoolPtr pool); +int virStoragePoolDestroy (virStoragePoolPtr pool); +int virStoragePoolFree (virStoragePoolPtr pool); + +/* + * StoragePool information + */ +const char* virStoragePoolGetName (virStoragePoolPtr pool); +int virStoragePoolGetUUID (virStoragePoolPtr pool, + unsigned char *uuid); +int virStoragePoolGetUUIDString(virStoragePoolPtr pool, + char *buf); + +int virStoragePoolGetInfo(virStoragePoolPtr vol, + virStoragePoolInfoPtr info); + +char * virStoragePoolGetXMLDesc(virStoragePoolPtr pool, + int flags); + +int virStoragePoolGetAutostart(virStoragePoolPtr pool, + int *autostart); +int virStoragePoolSetAutostart(virStoragePoolPtr pool, + int autostart); + + + +/* + * List storage volumes within a pool + */ +int virStoragePoolNumOfVolumes(virStoragePoolPtr pool); +int virStoragePoolListVolumes (virStoragePoolPtr pool, + char **const names, + int maxnames); + +/* + * Lookup network by name or uuid + */ +virStorageVolPtr virStorageVolLookupByName(virStoragePoolPtr pool, + const char *name); +virStorageVolPtr virStorageVolLookupByUUID(virStoragePoolPtr pool, + const unsigned char *uuid); +virStorageVolPtr virStorageVolLookupByUUIDString(virStoragePoolPtr pool, + const char *uuid); + +const char* virStorageVolGetName (virStorageVolPtr vol); +int virStorageVolGetUUID (virStorageVolPtr vol, + unsigned char *uuid); +int virStorageVolGetUUIDString(virStorageVolPtr vol, + char *buf); + + +virStorageVolPtr virStorageVolCreateXML(virStoragePoolPtr pool, + const char *xmldesc, + int flags); + +int virStorageVolDestroy(virStorageVolPtr vol); +int virStorageVolFree(virStorageVolPtr vol); + +int virStorageVolGetInfo(virStorageVolPtr vol, + virStorageVolInfoPtr info); +char * virStorageVolGetXMLDesc(virStorageVolPtr pool, + int flags); + +char * virStorageVolGetPath(virStorageVolPtr vol); + +#ifdef __cplusplus +} +#endif + +#endif /* __VIR_VIRLIB_STORAGE_H__ */ diff -r a123e74573bb src/libvirt_sym.version --- a/src/libvirt_sym.version Sat Oct 27 13:36:24 2007 -0400 +++ b/src/libvirt_sym.version Sat Oct 27 16:56:25 2007 -0400 @@ -97,6 +97,43 @@ virNetworkGetAutostart; virNetworkSetAutostart; + virConnectNumOfStoragePools; + virConnectNumOfDefinedStoragePools; + virConnectListStoragePools; + virConnectListDefinedStoragePools; + virStoragePoolCreateXML; + virStoragePoolDefineXML; + virStoragePoolCreate; + virStoragePoolUndefine; + virStoragePoolShutdown; + virStoragePoolDestroy; + virStoragePoolFree; + virStoragePoolLookupByName; + virStoragePoolLookupByUUID; + virStoragePoolLookupByUUIDString; + virStoragePoolGetName; + virStoragePoolGetUUID; + virStoragePoolGetUUIDString; + virStoragePoolGetInfo; + virStoragePoolGetXMLDesc; + virStoragePoolSetAutostart; + virStoragePoolGetAutostart; + + virConnectNumOfStorageVolumes; + virConnectListStorageVolumes; + virStorageVolCreateXML; + virStorageVolDestroy; + virStorageVolFree; + virStorageVolLookupByName; + virStorageVolLookupByUUID; + virStorageVolLookupByUUIDString; + virStorageVolGetName; + virStorageVolGetUUID; + virStorageVolGetUUIDString; + virStorageVolGetInfo; + virStorageVolGetXMLDesc; + virStorageVolGetPath; + /* Symbols with __ are private only for use by the libvirtd daemon. They are not part of stable ABI @@ -114,6 +151,8 @@ __virGetDomain; __virGetNetwork; + __virGetStoragePool; + __virGetStorageVol; __virEventRegisterImpl; -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

On Mon, Oct 29, 2007 at 03:57:01AM +0000, Daniel P. Berrange wrote:
This patch adds a public header file defining the application facing contract for the storage APIs.
+/* -*- c -*- + * storage.h: + * Summary: storage management interfaces + * Description: Provides the interfaces of the libvirt library to handle + * storage management from a process running in the host + * + * Copy: Copyright (C) 2005-2007 Red Hat, Inc. + * + * See COPYING.LIB for the License of this software + * + * Author: Daniel Veillard <veillard@redhat.com>
Need to fix the author I guess :-)
+ */ + + + +#ifndef __VIR_VIRLIB_H__ +#error "Do not include storage.h directly. Use libvirt.h instead" +#endif
That would be one reason against the split, if you can't reference files individually I don't think we can export them as an API...
+#ifndef __VIR_VIRLIB_STORAGE_H__ +#define __VIR_VIRLIB_STORAGE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * virStoragePool: + * + * a virStoragePool is a private structure representing a storage pool + */ +typedef struct _virStoragePool virStoragePool; + +/** + * virStoragePoolPtr: + * + * a virStoragePoolPtr is pointer to a virStoragePool private structure, this is the + * type used to reference a storage pool in the API. + */ +typedef virStoragePool *virStoragePoolPtr; + + +typedef enum { + VIR_STORAGE_POOL_INACTIVE = 0, + VIR_STORAGE_POOL_ACTIVE = 1, +} virStoragePoolState; + +typedef struct _virStoragePoolInfo virStoragePoolInfo; + +struct _virStoragePoolInfo { + int state; /* virStoragePoolState flags */ + unsigned long long capacity; /* Logical size bytes */ + unsigned long long allocation; /* Current allocation bytes */ +};
There is no name available ? Once you got a pointer to that structure, how do you expose its capability to the user ?
+typedef virStoragePoolInfo *virStoragePoolInfoPtr; + + +/** + * virStorageVol: + * + * a virStorageVol is a private structure representing a storage volume + */ +typedef struct _virStorageVol virStorageVol; + +/** + * virStorageVolPtr: + * + * a virStorageVolPtr is pointer to a virStorageVol private structure, this is the + * type used to reference a storage volume in the API. + */ +typedef virStorageVol *virStorageVolPtr; + + +typedef enum { + VIR_STORAGE_POOL_FILE = 0, + VIR_STORAGE_POOL_BLOCK = 1, +} virStoragePoolType; + +typedef struct _virStorageVolInfo virStorageVolInfo; + +struct _virStorageVolInfo { + int type; /* virStoragePoolType flags */ + unsigned long long capacity; /* Logical size bytes */ + unsigned long long allocation; /* Current allocation bytes */ +};
Same thing, I feel it lacks some external naming in the structure,
+typedef virStorageVolInfo *virStorageVolInfoPtr; + +/* + * Get connection from pool. + */ +virConnectPtr virStoragePoolGetConnect (virStoragePoolPtr pool); + +/* + * List active storage pools + */ +int virConnectNumOfStoragePools (virConnectPtr conn); +int virConnectListStoragePools (virConnectPtr conn, + char **const names, + int maxnames); + +/* + * List inactive storage pools + */ +int virConnectNumOfDefinedStoragePools(virConnectPtr conn); +int virConnectListDefinedStoragePools(virConnectPtr conn, + char **const names, + int maxnames); + +/* + * Lookup network by name or uuid + */ +virStoragePoolPtr virStoragePoolLookupByName(virConnectPtr conn, + const char *name); +virStoragePoolPtr virStoragePoolLookupByUUID(virConnectPtr conn, + const unsigned char *uuid); +virStoragePoolPtr virStoragePoolLookupByUUIDString(virConnectPtr conn, + const char *uuid); + +/* + * Create active transient storage pool + */ +virStoragePoolPtr virStoragePoolCreateXML(virConnectPtr conn, + const char *xmlDesc); + +/* + * Define inactive persistent storage pool + */ +virStoragePoolPtr virStoragePoolDefineXML(virConnectPtr conn, + const char *xmlDesc); + +/* + * Delete persistent storage pool + */ +int virStoragePoolUndefine(virStoragePoolPtr pool); + +/* + * Activate persistent pool + */ +int virStoragePoolCreate(virStoragePoolPtr pool); + +/* + * StoragePool destroy/free + */ +int virStoragePoolShutdown(virStoragePoolPtr pool); +int virStoragePoolDestroy (virStoragePoolPtr pool); +int virStoragePoolFree (virStoragePoolPtr pool);
Hum, I really wonder about the precise semantic for those 3 operations
+/* + * StoragePool information + */ +const char* virStoragePoolGetName (virStoragePoolPtr pool); +int virStoragePoolGetUUID (virStoragePoolPtr pool, + unsigned char *uuid); +int virStoragePoolGetUUIDString(virStoragePoolPtr pool, + char *buf); + +int virStoragePoolGetInfo(virStoragePoolPtr vol, + virStoragePoolInfoPtr info); + +char * virStoragePoolGetXMLDesc(virStoragePoolPtr pool, + int flags); + +int virStoragePoolGetAutostart(virStoragePoolPtr pool, + int *autostart); +int virStoragePoolSetAutostart(virStoragePoolPtr pool, + int autostart); + + + +/* + * List storage volumes within a pool + */ +int virStoragePoolNumOfVolumes(virStoragePoolPtr pool); +int virStoragePoolListVolumes (virStoragePoolPtr pool, + char **const names, + int maxnames); + +/* + * Lookup network by name or uuid
s/network/storage/ :-)
+ */ +virStorageVolPtr virStorageVolLookupByName(virStoragePoolPtr pool, + const char *name); +virStorageVolPtr virStorageVolLookupByUUID(virStoragePoolPtr pool, + const unsigned char *uuid); +virStorageVolPtr virStorageVolLookupByUUIDString(virStoragePoolPtr pool, + const char *uuid); + +const char* virStorageVolGetName (virStorageVolPtr vol);
so there is a public name, keep it in the structure, you can't garantee the storage will have exactly the name the user expect, aliasing is frequent in storage I think.
+int virStorageVolGetUUID (virStorageVolPtr vol, + unsigned char *uuid); +int virStorageVolGetUUIDString(virStorageVolPtr vol, + char *buf); + + +virStorageVolPtr virStorageVolCreateXML(virStoragePoolPtr pool, + const char *xmldesc, + int flags); + +int virStorageVolDestroy(virStorageVolPtr vol); +int virStorageVolFree(virStorageVolPtr vol); + +int virStorageVolGetInfo(virStorageVolPtr vol, + virStorageVolInfoPtr info); +char * virStorageVolGetXMLDesc(virStorageVolPtr pool, + int flags); + +char * virStorageVolGetPath(virStorageVolPtr vol); + +#ifdef __cplusplus +}
The API being derived from existing APIs they of course looks rather sane to me, but the XML formats is also part of the APIs not described here. Daniel -- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard@redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/

On Wed, Oct 31, 2007 at 10:03:01AM -0400, Daniel Veillard wrote:
On Mon, Oct 29, 2007 at 03:57:01AM +0000, Daniel P. Berrange wrote:
for the storage APIs. +typedef struct _virStoragePoolInfo virStoragePoolInfo; + +struct _virStoragePoolInfo { + int state; /* virStoragePoolState flags */ + unsigned long long capacity; /* Logical size bytes */ + unsigned long long allocation; /* Current allocation bytes */ +};
There is no name available ? Once you got a pointer to that structure, how do you expose its capability to the user ?
This is akin to the virDomainInfoPtr object - its just a struct containing some basic status metadata. The main handle to the thing is virStoragePoolPtr which is an opaque handle.
+struct _virStorageVolInfo { + int type; /* virStoragePoolType flags */ + unsigned long long capacity; /* Logical size bytes */ + unsigned long long allocation; /* Current allocation bytes */ +};
Same thing, I feel it lacks some external naming in the structure,
Same here - cf virDomainInfoPtr.
+int virStoragePoolShutdown(virStoragePoolPtr pool); +int virStoragePoolDestroy (virStoragePoolPtr pool); +int virStoragePoolFree (virStoragePoolPtr pool);
Hum, I really wonder about the precise semantic for those 3 operations
To be honest I've not 100% finalized, but current thoughts are: - virStoragePoolShutdown() de-activate the pool - eg logout of iSCSI server, or unmount the disk, etc - virStoragePoolDestroy() the same, but also free's the virStoragePoolPtr object cf virDomainDestroy, vs virDomainShutdown - virStoragePoolFree just free the virStoragePoolPtr. I think we might want a way to remove all trace of a pool, eg - virStoragePoolDelete() trash the data, eg rm -rf the directory, or remove the LVM volume group, or blow away the partition table If it were not for the historical precent of the virDomainXXXX apis, I'd be calling this last one, virStoragePoolDestroy, but I don't want to overload 'Destory' already has defined semantics in thec context of a domain which is that its equivalent to a forced Shutdown + Free. So i figure it best to pick virStoragePoolDelete instead.
+ */ +virStorageVolPtr virStorageVolLookupByName(virStoragePoolPtr pool, + const char *name); +virStorageVolPtr virStorageVolLookupByUUID(virStoragePoolPtr pool, + const unsigned char *uuid); +virStorageVolPtr virStorageVolLookupByUUIDString(virStoragePoolPtr pool, + const char *uuid); + +const char* virStorageVolGetName (virStorageVolPtr vol);
so there is a public name, keep it in the structure, you can't garantee the storage will have exactly the name the user expect, aliasing is frequent in storage I think.
Yep, you can only really on 'name' being consistent for as long as a storage pool is active. It may come up with a different name next time. For long term persistent naming, I think we need some form of unique key which is an opaque char *, comprised of whatever 'unique' metadata we can pull out of the underlying physical storage - cf the mail 0/7 which discussed 'open issues'
The API being derived from existing APIs they of course looks rather sane to me, but the XML formats is also part of the APIs not described here.
The XML is basically following the style I posted in the last of my messages in the 'Storage concepts' thread. I'll be making some changes as suggested by Rich to make things more optional so will post a revised XML description next time. Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

This patch defines the internal driver API for the storage API calls. It also provides the cache implementation for the virStoragePoolPtr and virStorageVolPtr objects. The virStorageVolPtr object is a little different in that it doesn't reference the virConnectPtr object directly. Instead it points to the virStoragePoolPtr object. This makes the reference counting 'interesting', because when we get a virStorageVolPtr object, we have increment the count on both the pool and the connection. This was starting to get complex, so to keep it sane I don't bother with referencing counting on the virStorageVolPtr object itself. include/libvirt/virterror.h | 3 src/driver.h | 119 +++++ src/hash.c | 349 +++++++++++++-- src/internal.h | 93 +++- src/libvirt.c | 975 +++++++++++++++++++++++++++++++++++++++++++- src/libvirt_sym.version | 4 6 files changed, 1464 insertions(+), 79 deletions(-) diff -r b5447763aad6 include/libvirt/virterror.h --- a/include/libvirt/virterror.h Sat Oct 27 16:56:42 2007 -0400 +++ b/include/libvirt/virterror.h Sun Oct 28 22:44:08 2007 -0400 @@ -129,6 +129,9 @@ typedef enum { VIR_ERR_NO_DOMAIN, /* domain not found or unexpectedly disappeared */ VIR_ERR_NO_NETWORK, /* network not found */ VIR_ERR_INVALID_MAC, /* invalid MAC adress */ + VIR_ERR_INVALID_STORAGE_POOL, /* invalid storage pool object */ + VIR_ERR_INVALID_STORAGE_VOL, /* invalid storage vol object */ + VIR_WAR_NO_STORAGE, /* failed to start storage */ } virErrorNumber; /** diff -r b5447763aad6 src/driver.h --- a/src/driver.h Sat Oct 27 16:56:42 2007 -0400 +++ b/src/driver.h Sun Oct 28 14:34:03 2007 -0400 @@ -414,6 +414,124 @@ struct _virNetworkDriver { virDrvNetworkSetAutostart networkSetAutostart; }; + +typedef int + (*virDrvConnectNumOfStoragePools)(virConnectPtr conn); +typedef int + (*virDrvConnectListStoragePools)(virConnectPtr conn, + char **const names, + int maxnames); +typedef int + (*virDrvConnectNumOfDefinedStoragePools)(virConnectPtr conn); +typedef int + (*virDrvConnectListDefinedStoragePools)(virConnectPtr conn, + char **const names, + int maxnames); +typedef virStoragePoolPtr + (*virDrvStoragePoolLookupByName)(virConnectPtr conn, + const char *name); +typedef virStoragePoolPtr + (*virDrvStoragePoolLookupByUUID)(virConnectPtr conn, + const unsigned char *uuid); +typedef virStoragePoolPtr + (*virDrvStoragePoolCreateXML)(virConnectPtr conn, + const char *xmlDesc); +typedef virStoragePoolPtr + (*virDrvStoragePoolDefineXML)(virConnectPtr conn, + const char *xmlDesc); +typedef int + (*virDrvStoragePoolUndefine)(virStoragePoolPtr pool); +typedef int + (*virDrvStoragePoolCreate)(virStoragePoolPtr pool); +typedef int + (*virDrvStoragePoolShutdown)(virStoragePoolPtr pool); +typedef int + (*virDrvStoragePoolDestroy)(virStoragePoolPtr pool); +typedef int + (*virDrvStoragePoolGetInfo)(virStoragePoolPtr vol, + virStoragePoolInfoPtr info); +typedef char * + (*virDrvStoragePoolGetXMLDesc)(virStoragePoolPtr pool, + int flags); +typedef int + (*virDrvStoragePoolGetAutostart)(virStoragePoolPtr pool, + int *autostart); +typedef int + (*virDrvStoragePoolSetAutostart)(virStoragePoolPtr pool, + int autostart); +typedef int + (*virDrvStoragePoolNumOfVolumes)(virStoragePoolPtr pool); +typedef int + (*virDrvStoragePoolListVolumes)(virStoragePoolPtr pool, + char **const names, + int maxnames); +typedef virStorageVolPtr + (*virDrvStorageVolLookupByName)(virStoragePoolPtr pool, + const char *name); +typedef virStorageVolPtr + (*virDrvStorageVolLookupByUUID)(virStoragePoolPtr pool, + const unsigned char *uuid); +typedef virStorageVolPtr + (*virDrvStorageVolCreateXML)(virStoragePoolPtr pool, + const char *xmldesc, + int flags); +typedef int + (*virDrvStorageVolDestroy)(virStorageVolPtr vol); +typedef int + (*virDrvStorageVolGetInfo)(virStorageVolPtr vol, + virStorageVolInfoPtr info); +typedef char * + (*virDrvStorageVolGetXMLDesc)(virStorageVolPtr pool, + int flags); +typedef char * + (*virDrvStorageVolGetPath)(virStorageVolPtr vol); + + + +typedef struct _virStorageDriver virStorageDriver; +typedef virStorageDriver *virStorageDriverPtr; + +/** + * _virStorageDriver: + * + * Structure associated to a network virtualization driver, defining the various + * entry points for it. + * + * All drivers must support the following fields/methods: + * - open + * - close + */ +struct _virStorageDriver { + const char * name; /* the name of the driver */ + virDrvOpen open; + virDrvClose close; + virDrvConnectNumOfStoragePools numOfPools; + virDrvConnectListStoragePools listPools; + virDrvConnectNumOfDefinedStoragePools numOfDefinedPools; + virDrvConnectListDefinedStoragePools listDefinedPools; + virDrvStoragePoolLookupByName poolLookupByName; + virDrvStoragePoolLookupByUUID poolLookupByUUID; + virDrvStoragePoolCreateXML poolCreateXML; + virDrvStoragePoolDefineXML poolDefineXML; + virDrvStoragePoolUndefine poolUndefine; + virDrvStoragePoolCreate poolCreate; + virDrvStoragePoolShutdown poolShutdown; + virDrvStoragePoolDestroy poolDestroy; + virDrvStoragePoolGetInfo poolGetInfo; + virDrvStoragePoolGetXMLDesc poolGetXMLDesc; + virDrvStoragePoolGetAutostart poolGetAutostart; + virDrvStoragePoolSetAutostart poolSetAutostart; + virDrvStoragePoolNumOfVolumes poolNumOfVolumes; + virDrvStoragePoolListVolumes poolListVolumes; + virDrvStorageVolLookupByName volLookupByName; + virDrvStorageVolLookupByUUID volLookupByUUID; + virDrvStorageVolCreateXML volCreateXML; + virDrvStorageVolDestroy volDestroy; + virDrvStorageVolGetInfo volGetInfo; + virDrvStorageVolGetXMLDesc volGetXMLDesc; + virDrvStorageVolGetPath volGetPath; +}; + typedef int (*virDrvStateInitialize) (void); typedef int (*virDrvStateCleanup) (void); typedef int (*virDrvStateReload) (void); @@ -436,6 +554,7 @@ struct _virStateDriver { */ int virRegisterDriver(virDriverPtr); int virRegisterNetworkDriver(virNetworkDriverPtr); +int virRegisterStorageDriver(virStorageDriverPtr); int virRegisterStateDriver(virStateDriverPtr); #ifdef __cplusplus diff -r b5447763aad6 src/hash.c --- a/src/hash.c Sat Oct 27 16:56:42 2007 -0400 +++ b/src/hash.c Sun Oct 28 22:44:58 2007 -0400 @@ -649,6 +649,20 @@ virNetworkFreeName(virNetworkPtr network } /** + * virStoragePoolFreeName: + * @pool: a storage pool object + * + * Destroy the storage pool object, this is just used by the storage pool hash callback. + * + * Returns 0 in case of success and -1 in case of failure. + */ +static int +virStoragePoolFreeName(virStoragePoolPtr pool, const char *name ATTRIBUTE_UNUSED) +{ + return (virStoragePoolFree(pool)); +} + +/** * virGetConnect: * * Allocates a new hypervisor connection structure @@ -675,6 +689,9 @@ virGetConnect(void) { ret->networks = virHashCreate(20); if (ret->networks == NULL) goto failed; + ret->storagePools = virHashCreate(20); + if (ret->storagePools == NULL) + goto failed; ret->hashes_mux = xmlNewMutex(); if (ret->hashes_mux == NULL) goto failed; @@ -688,6 +705,8 @@ failed: virHashFree(ret->domains, (virHashDeallocator) virDomainFreeName); if (ret->networks != NULL) virHashFree(ret->networks, (virHashDeallocator) virNetworkFreeName); + if (ret->storagePools != NULL) + virHashFree(ret->storagePools, (virHashDeallocator) virStoragePoolFreeName); if (ret->hashes_mux != NULL) xmlFreeMutex(ret->hashes_mux); free(ret); @@ -695,39 +714,49 @@ failed: return(NULL); } -/** - * virFreeConnect: - * @conn: the hypervisor connection - * - * Release the connection. if the use count drops to zero, the structure is - * actually freed. - * - * Returns the reference count or -1 in case of failure. - */ -int -virFreeConnect(virConnectPtr conn) { +static int +virFreeConnectLocked(virConnectPtr conn) { int ret; - - if ((!VIR_IS_CONNECT(conn)) || (conn->hashes_mux == NULL)) { - virHashError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); - return(-1); - } - xmlMutexLock(conn->hashes_mux); conn->uses--; ret = conn->uses; - if (ret > 0) { - xmlMutexUnlock(conn->hashes_mux); - return(ret); - } + if (ret > 0) + return(ret); if (conn->domains != NULL) virHashFree(conn->domains, (virHashDeallocator) virDomainFreeName); if (conn->networks != NULL) virHashFree(conn->networks, (virHashDeallocator) virNetworkFreeName); - if (conn->hashes_mux != NULL) - xmlFreeMutex(conn->hashes_mux); + if (conn->storagePools != NULL) + virHashFree(conn->storagePools, (virHashDeallocator) virStoragePoolFreeName); free(conn); return(0); +} + +/** + * virFreeConnect: + * @conn: the hypervisor connection + * + * Release the connection. if the use count drops to zero, the structure is + * actually freed. + * + * Returns the reference count or -1 in case of failure. + */ +int +virFreeConnect(virConnectPtr conn) { + int ret; + xmlMutexPtr mux; + + if ((!VIR_IS_CONNECT(conn)) || (conn->hashes_mux == NULL)) { + virHashError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(-1); + } + mux = conn->hashes_mux; + xmlMutexLock(mux); + ret = virFreeConnectLocked(conn); + xmlMutexUnlock(mux); + if (ret == 0) + xmlFreeMutex(mux); + return ret; } /** @@ -815,13 +844,15 @@ int int virFreeDomain(virConnectPtr conn, virDomainPtr domain) { int ret = 0; + xmlMutexPtr mux; if ((!VIR_IS_CONNECT(conn)) || (!VIR_IS_CONNECTED_DOMAIN(domain)) || (domain->conn != conn) || (conn->hashes_mux == NULL)) { virHashError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); return(-1); } - xmlMutexLock(conn->hashes_mux); + mux = conn->hashes_mux; + xmlMutexLock(mux); /* * decrement the count for the domain @@ -844,22 +875,14 @@ virFreeDomain(virConnectPtr conn, virDom free(domain->name); free(domain); - /* - * decrement the count for the connection - */ - conn->uses--; - if (conn->uses > 0) - goto done; - - if (conn->domains != NULL) - virHashFree(conn->domains, (virHashDeallocator) virDomainFreeName); - if (conn->hashes_mux != NULL) - xmlFreeMutex(conn->hashes_mux); - free(conn); + ret = virFreeConnectLocked(conn); + xmlMutexUnlock(mux); + if (ret == 0) + xmlFreeMutex(mux); return(0); done: - xmlMutexUnlock(conn->hashes_mux); + xmlMutexUnlock(mux); return(ret); } @@ -947,13 +970,15 @@ int int virFreeNetwork(virConnectPtr conn, virNetworkPtr network) { int ret = 0; + xmlMutexPtr mux; if ((!VIR_IS_CONNECT(conn)) || (!VIR_IS_CONNECTED_NETWORK(network)) || (network->conn != conn) || (conn->hashes_mux == NULL)) { virHashError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); return(-1); } - xmlMutexLock(conn->hashes_mux); + mux = conn->hashes_mux; + xmlMutexLock(mux); /* * decrement the count for the network @@ -975,23 +1000,255 @@ virFreeNetwork(virConnectPtr conn, virNe free(network->name); free(network); + ret = virFreeConnectLocked(conn); + xmlMutexUnlock(mux); + if (ret == 0) + xmlFreeMutex(mux); + return(0); + +done: + xmlMutexUnlock(mux); + return(ret); +} + +/** + * virGetStoragePool: + * @conn: the hypervisor connection + * @name: pointer to the pool name + * @uuid: pointer to the uuid + * + * Lookup if the pool is already registered for that connection, + * if yes return a new pointer to it, if no allocate a new structure, + * and register it in the table. In any case a corresponding call to + * virFreeStoragePool() is needed to not leak data. + * + * Returns a pointer to the pool, or NULL in case of failure + */ +virStoragePoolPtr +__virGetStoragePool(virConnectPtr conn, const char *name, const unsigned char *uuid) { + virStoragePoolPtr ret = NULL; + + if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (uuid == NULL) || + (conn->hashes_mux == NULL)) { + virHashError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(NULL); + } + xmlMutexLock(conn->hashes_mux); + + /* TODO search by UUID first as they are better differenciators */ + + ret = (virStoragePoolPtr) virHashLookup(conn->storagePools, name); + if (ret != NULL) { + /* TODO check the UUID */ + goto done; + } + /* - * decrement the count for the connection + * not found, allocate a new one */ - conn->uses--; - if (conn->uses > 0) + ret = (virStoragePoolPtr) calloc(1, sizeof(virStoragePool)); + if (ret == NULL) { + virHashError(conn, VIR_ERR_NO_MEMORY, _("allocating storage pool")); + goto error; + } + ret->name = strdup(name); + if (ret->name == NULL) { + virHashError(conn, VIR_ERR_NO_MEMORY, _("allocating storage pool")); + goto error; + } + ret->magic = VIR_STORAGE_POOL_MAGIC; + ret->conn = conn; + if (uuid != NULL) + memcpy(&(ret->uuid[0]), uuid, VIR_UUID_BUFLEN); + + if (virHashAddEntry(conn->storagePools, name, ret) < 0) { + virHashError(conn, VIR_ERR_INTERNAL_ERROR, + _("failed to add storage pool to connection hash table")); + goto error; + } + conn->uses++; +done: + ret->uses++; + xmlMutexUnlock(conn->hashes_mux); + return(ret); + +error: + xmlMutexUnlock(conn->hashes_mux); + if (ret != NULL) { + if (ret->name != NULL) + free(ret->name); + free(ret); + } + return(NULL); +} + +static int +virFreeStoragePoolLocked(virConnectPtr conn, virStoragePoolPtr pool) { + int ret = 0; + /* + * decrement the count for the pool + */ + pool->uses--; + ret = pool->uses; + if (ret > 0) goto done; - if (conn->networks != NULL) - virHashFree(conn->networks, (virHashDeallocator) virNetworkFreeName); - if (conn->hashes_mux != NULL) - xmlFreeMutex(conn->hashes_mux); - free(conn); + /* TODO search by UUID first as they are better differenciators */ + + if (virHashRemoveEntry(conn->storagePools, pool->name, NULL) < 0) { + virHashError(conn, VIR_ERR_INTERNAL_ERROR, + _("pool missing from connection hash table")); + goto done; + } + pool->magic = -1; + if (pool->name) + free(pool->name); + free(pool); return(0); done: xmlMutexUnlock(conn->hashes_mux); return(ret); +} +/** + * virFreeStoragePool: + * @conn: the hypervisor connection + * @pool: the pool to release + * + * Release the given storage pool, if the reference count drops to zero, then + * the pool is really freed. + * + * Returns the reference count or -1 in case of failure. + */ +int +virFreeStoragePool(virConnectPtr conn, virStoragePoolPtr pool) { + int ret = 0; + xmlMutexPtr mux; + + if ((!VIR_IS_CONNECT(conn)) || (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) || + (pool->conn != conn) || (conn->hashes_mux == NULL)) { + virHashError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(-1); + } + mux = conn->hashes_mux; + xmlMutexLock(mux); + + ret = virFreeStoragePoolLocked(conn, pool); + if (ret > 0) + goto done; + + ret = virFreeConnectLocked(conn); + xmlMutexUnlock(mux); + if (ret == 0) + xmlFreeMutex(mux); + return(0); + +done: + xmlMutexUnlock(mux); + return(ret); +} + +/** + * virGetStorageVol: + * @pool: the storage pool + * @name: pointer to the pool name + * @uuid: pointer to the uuid + * + * Lookup if the storage is already registered for that connection, + * if yes return a new pointer to it, if no allocate a new structure, + * and register it in the table. In any case a corresponding call to + * virFreeStorageVol() is needed to not leak data. + * + * Returns a pointer to the vol, or NULL in case of failure + */ +virStorageVolPtr +__virGetStorageVol(virStoragePoolPtr pool, const char *name, const unsigned char *uuid) { + virStorageVolPtr ret = NULL; + + if ((!VIR_IS_STORAGE_POOL(pool)) || (name == NULL) || (uuid == NULL) || + (pool->conn->hashes_mux == NULL)) { + virHashError(pool->conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(NULL); + } + xmlMutexLock(pool->conn->hashes_mux); + + /* + * not found, allocate a new one + */ + ret = (virStorageVolPtr) calloc(1, sizeof(virStorageVol)); + if (ret == NULL) { + virHashError(pool->conn, VIR_ERR_NO_MEMORY, _("allocating storage vol")); + goto error; + } + ret->name = strdup(name); + if (ret->name == NULL) { + virHashError(pool->conn, VIR_ERR_NO_MEMORY, _("allocating storage vol")); + goto error; + } + ret->magic = VIR_STORAGE_VOL_MAGIC; + ret->pool = pool; + if (uuid != NULL) + memcpy(&(ret->uuid[0]), uuid, VIR_UUID_BUFLEN); + + pool->uses++; + pool->conn->uses++; + xmlMutexUnlock(pool->conn->hashes_mux); + return(ret); + +error: + xmlMutexUnlock(pool->conn->hashes_mux); + if (ret != NULL) { + if (ret->name != NULL) + free(ret->name); + free(ret); + } + return(NULL); +} + +/** + * virFreeStorageVol: + * @conn: the hypervisor connection + * @vol: the vol to release + * + * Release the given storage volume + * + * Returns zero on success, or -1 in case of failure. + */ +int +virFreeStorageVol(virConnectPtr conn, virStorageVolPtr vol) { + int ret = 0; + xmlMutexPtr mux; + virStoragePoolPtr pool; + + if ((!VIR_IS_CONNECT(conn)) || (!VIR_IS_CONNECTED_STORAGE_VOL(vol)) || + (vol->pool->conn != conn)) { + virHashError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(-1); + } + pool = vol->pool; + mux = conn->hashes_mux; + xmlMutexLock(conn->hashes_mux); + + vol->magic = -1; + if (vol->name) + free(vol->name); + free(vol); + + ret = virFreeStoragePoolLocked(conn, pool); + if (ret > 0) + goto done; + + ret = virFreeConnectLocked(conn); + xmlMutexUnlock(mux); + if (ret == 0) + xmlFreeMutex(mux); + return(0); + + return(0); + +done: + xmlMutexUnlock(mux); + return(0); } /* diff -r b5447763aad6 src/internal.h --- a/src/internal.h Sat Oct 27 16:56:42 2007 -0400 +++ b/src/internal.h Sun Oct 28 14:34:03 2007 -0400 @@ -90,7 +90,7 @@ extern "C" { * VIR_DOMAIN_MAGIC: * * magic value used to protect the API when pointers to domain structures - * are passed down by the uers. + * are passed down by the users. */ #define VIR_DOMAIN_MAGIC 0xDEAD4321 #define VIR_IS_DOMAIN(obj) ((obj) && (obj)->magic==VIR_DOMAIN_MAGIC) @@ -100,12 +100,33 @@ extern "C" { * VIR_NETWORK_MAGIC: * * magic value used to protect the API when pointers to network structures - * are passed down by the uers. + * are passed down by the users. */ #define VIR_NETWORK_MAGIC 0xDEAD1234 #define VIR_IS_NETWORK(obj) ((obj) && (obj)->magic==VIR_NETWORK_MAGIC) #define VIR_IS_CONNECTED_NETWORK(obj) (VIR_IS_NETWORK(obj) && VIR_IS_CONNECT((obj)->conn)) +/** + * VIR_STORAGE_POOL_MAGIC: + * + * magic value used to protect the API when pointers to storage pool structures + * are passed down by the users. + */ +#define VIR_STORAGE_POOL_MAGIC 0xDEAD5678 +#define VIR_IS_STORAGE_POOL(obj) ((obj) && (obj)->magic==VIR_STORAGE_POOL_MAGIC) +#define VIR_IS_CONNECTED_STORAGE_POOL(obj) (VIR_IS_STORAGE_POOL(obj) && VIR_IS_CONNECT((obj)->conn)) + +/** + * VIR_STORAGE_VOL_MAGIC: + * + * magic value used to protect the API when pointers to storage vol structures + * are passed down by the users. + */ +#define VIR_STORAGE_VOL_MAGIC 0xDEAD8765 +#define VIR_IS_STORAGE_VOL(obj) ((obj) && (obj)->magic==VIR_STORAGE_VOL_MAGIC) +#define VIR_IS_CONNECTED_STORAGE_VOL(obj) (VIR_IS_STORAGE_VOL(obj) && VIR_IS_CONNECTED_STORAGE_POOL((obj)->pool) \ + && VIR_IS_CONNECT((obj)->pool->conn)) + /* * arbitrary limitations */ @@ -130,6 +151,7 @@ struct _virConnect { /* The underlying hypervisor driver and network driver. */ virDriverPtr driver; virNetworkDriverPtr networkDriver; + virStorageDriverPtr storageDriver; /* Private data pointer which can be used by driver and * network driver as they wish. @@ -137,6 +159,7 @@ struct _virConnect { */ void * privateData; void * networkPrivateData; + void * storagePrivateData; /* Per-connection error. */ virError err; /* the last error */ @@ -146,7 +169,8 @@ struct _virConnect { /* misc */ xmlMutexPtr hashes_mux;/* a mutex to protect the domain and networks hash tables */ virHashTablePtr domains;/* hash table for known domains */ - virHashTablePtr networks;/* hash table for known domains */ + virHashTablePtr networks;/* hash table for known networks */ + virHashTablePtr storagePools;/* hash table for known storage pools */ int flags; /* a set of connection flags */ }; @@ -175,6 +199,33 @@ struct _virNetwork { virConnectPtr conn; /* pointer back to the connection */ char *name; /* the network external name */ unsigned char uuid[VIR_UUID_BUFLEN]; /* the network unique identifier */ +}; + +/** +* _virNetwork: +* +* Internal structure associated to a domain +*/ +struct _virStoragePool { + unsigned int magic; /* specific value to check */ + int uses; /* reference count */ + 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 */ +}; + +/** +* _virNetwork: +* +* Internal structure associated to a domain. +* NB, this is not reference counted. They +* are directly created/freed as needed. +*/ +struct _virStorageVol { + unsigned int magic; /* specific value to check */ + virStoragePoolPtr pool; /* pointer back to the storage pool */ + char *name; /* the storage vol external name */ + unsigned char uuid[VIR_UUID_BUFLEN]; /* the storage vol unique identifier */ }; /* @@ -208,21 +259,33 @@ const char *__virErrorMsg(virErrorNumber * * ************************************************************************/ -virConnectPtr virGetConnect (void); -int virFreeConnect (virConnectPtr conn); -virDomainPtr __virGetDomain (virConnectPtr conn, - const char *name, - const unsigned char *uuid); -int virFreeDomain (virConnectPtr conn, - virDomainPtr domain); -virNetworkPtr __virGetNetwork (virConnectPtr conn, - const char *name, - const unsigned char *uuid); -int virFreeNetwork (virConnectPtr conn, - virNetworkPtr domain); +virConnectPtr virGetConnect (void); +int virFreeConnect (virConnectPtr conn); +virDomainPtr __virGetDomain (virConnectPtr conn, + const char *name, + const unsigned char *uuid); +int virFreeDomain (virConnectPtr conn, + virDomainPtr domain); +virNetworkPtr __virGetNetwork (virConnectPtr conn, + const char *name, + const unsigned char *uuid); +int virFreeNetwork (virConnectPtr conn, + virNetworkPtr domain); +virStoragePoolPtr __virGetStoragePool (virConnectPtr conn, + const char *name, + const unsigned char *uuid); +int virFreeStoragePool (virConnectPtr conn, + virStoragePoolPtr domain); +virStorageVolPtr __virGetStorageVol (virStoragePoolPtr pool, + const char *name, + const unsigned char *uuid); +int virFreeStorageVol (virConnectPtr conn, + virStorageVolPtr domain); #define virGetDomain(c,n,u) __virGetDomain((c),(n),(u)) #define virGetNetwork(c,n,u) __virGetNetwork((c),(n),(u)) +#define virGetStoragePool(c,n,u) __virGetStoragePool((c),(n),(u)) +#define virGetStorageVol(c,n,u) __virGetStorageVol((c),(n),(u)) int __virStateInitialize(void); int __virStateCleanup(void); diff -r b5447763aad6 src/libvirt.c --- a/src/libvirt.c Sat Oct 27 16:56:42 2007 -0400 +++ b/src/libvirt.c Sun Oct 28 22:44:52 2007 -0400 @@ -30,6 +30,7 @@ #include "xen_unified.h" #include "remote_internal.h" #include "qemu_driver.h" +#include "storage_driver.h" #ifdef WITH_OPENVZ #include "openvz_driver.h" #endif @@ -44,6 +45,8 @@ static int virDriverTabCount = 0; static int virDriverTabCount = 0; static virNetworkDriverPtr virNetworkDriverTab[MAX_DRIVERS]; static int virNetworkDriverTabCount = 0; +static virStorageDriverPtr virStorageDriverTab[MAX_DRIVERS]; +static int virStorageDriverTabCount = 0; static virStateDriverPtr virStateDriverTab[MAX_DRIVERS]; static int virStateDriverTabCount = 0; static int initialized = 0; @@ -52,10 +55,11 @@ static int initialized = 0; * are printed to stderr for debugging. */ #ifdef ENABLE_DEBUG +static int debug = 0; #define DEBUG(fs,...) \ - fprintf (stderr, "libvirt: %s (" fs ")\n", __func__, __VA_ARGS__) + do { if (debug) fprintf (stderr, "libvirt: %s (" fs ")\n", __func__, __VA_ARGS__); } while (0) #define DEBUG0 \ - fprintf (stderr, "libvirt: %s ()\n", __func__) + do { if (debug) fprintf (stderr, "libvirt: %s ()\n", __func__); } while (0) #else #define DEBUG0 #define DEBUG(fs,...) @@ -73,10 +77,14 @@ int int virInitialize(void) { - DEBUG0; + char *debugFlag = getenv("LIBVIRT_DEBUG"); + if (debugFlag && *debugFlag) + debug = 1; + if (initialized) return(0); initialized = 1; + DEBUG0; if (!bindtextdomain(GETTEXT_PACKAGE, LOCALEBASEDIR)) return (-1); @@ -97,6 +105,7 @@ virInitialize(void) #ifdef WITH_OPENVZ if (openvzRegister() == -1) return -1; #endif + if (storageRegister() == -1) return -1; #ifdef WITH_REMOTE if (remoteRegister () == -1) return -1; #endif @@ -201,6 +210,58 @@ virLibNetworkError(virNetworkPtr network } /** + * virLibStoragePoolError: + * @conn: the connection if available + * @error: the error noumber + * @info: extra information string + * + * Handle an error at the connection level + */ +static void +virLibStoragePoolError(virStoragePoolPtr pool, virErrorNumber error, + const char *info) +{ + virConnectPtr conn = NULL; + const char *errmsg; + + if (error == VIR_ERR_OK) + return; + + errmsg = __virErrorMsg(error, info); + if (error != VIR_ERR_INVALID_STORAGE_POOL) + conn = pool->conn; + + __virRaiseError(conn, NULL, NULL, VIR_FROM_STORAGE, error, VIR_ERR_ERROR, + errmsg, info, NULL, 0, 0, errmsg, info); +} + +/** + * virLibStorageVolError: + * @conn: the connection if available + * @error: the error noumber + * @info: extra information string + * + * Handle an error at the connection level + */ +static void +virLibStorageVolError(virStorageVolPtr vol, virErrorNumber error, + const char *info) +{ + virConnectPtr conn = NULL; + const char *errmsg; + + if (error == VIR_ERR_OK) + return; + + errmsg = __virErrorMsg(error, info); + if (error != VIR_ERR_INVALID_STORAGE_VOL) + conn = vol->pool->conn; + + __virRaiseError(conn, NULL, NULL, VIR_FROM_STORAGE, error, VIR_ERR_ERROR, + errmsg, info, NULL, 0, 0, errmsg, info); +} + +/** * virRegisterNetworkDriver: * @driver: pointer to a network driver block * @@ -226,6 +287,34 @@ virRegisterNetworkDriver(virNetworkDrive virNetworkDriverTab[virNetworkDriverTabCount] = driver; return virNetworkDriverTabCount++; +} + +/** + * virRegisterStorageDriver: + * @driver: pointer to a storage driver block + * + * Register a storage virtualization driver + * + * Returns the driver priority or -1 in case of error. + */ +int +virRegisterStorageDriver(virStorageDriverPtr driver) +{ + if (virInitialize() < 0) + return -1; + + if (driver == NULL) { + virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(-1); + } + + if (virStorageDriverTabCount >= MAX_DRIVERS) { + virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(-1); + } + + virStorageDriverTab[virStorageDriverTabCount] = driver; + return virStorageDriverTabCount++; } /** @@ -417,21 +506,24 @@ do_open (const char *name, int flags) } #ifdef ENABLE_DEBUG - fprintf (stderr, "libvirt: do_open: proceeding with name=%s\n", name); + DEBUG("proceeding with name=%s", name); #endif + + + /* Primary driver is for domains. At least one must succeed */ for (i = 0; i < virDriverTabCount; i++) { #ifdef ENABLE_DEBUG - fprintf (stderr, "libvirt: do_open: trying driver %d (%s) ...\n", - i, virDriverTab[i]->name); + DEBUG("trying driver %d (%s) ...", + i, virDriverTab[i]->name); #endif res = virDriverTab[i]->open (ret, name, flags); #ifdef ENABLE_DEBUG - fprintf (stderr, "libvirt: do_open: driver %d %s returned %s\n", - i, virDriverTab[i]->name, - res == VIR_DRV_OPEN_SUCCESS ? "SUCCESS" : - (res == VIR_DRV_OPEN_DECLINED ? "DECLINED" : - (res == VIR_DRV_OPEN_ERROR ? "ERROR" : "unknown status"))); + DEBUG("driver %d %s returned %s", + i, virDriverTab[i]->name, + res == VIR_DRV_OPEN_SUCCESS ? "SUCCESS" : + (res == VIR_DRV_OPEN_DECLINED ? "DECLINED" : + (res == VIR_DRV_OPEN_ERROR ? "ERROR" : "unknown status"))); #endif if (res == VIR_DRV_OPEN_ERROR) goto failed; else if (res == VIR_DRV_OPEN_SUCCESS) { @@ -446,14 +538,16 @@ do_open (const char *name, int flags) goto failed; } + + /* Secondary driver for networks. Optional */ for (i = 0; i < virNetworkDriverTabCount; i++) { res = virNetworkDriverTab[i]->open (ret, name, flags); #ifdef ENABLE_DEBUG - fprintf (stderr, "libvirt: do_open: network driver %d %s returned %s\n", - i, virNetworkDriverTab[i]->name, - res == VIR_DRV_OPEN_SUCCESS ? "SUCCESS" : - (res == VIR_DRV_OPEN_DECLINED ? "DECLINED" : - (res == VIR_DRV_OPEN_ERROR ? "ERROR" : "unknown status"))); + DEBUG("network driver %d %s returned %s", + i, virNetworkDriverTab[i]->name, + res == VIR_DRV_OPEN_SUCCESS ? "SUCCESS" : + (res == VIR_DRV_OPEN_DECLINED ? "DECLINED" : + (res == VIR_DRV_OPEN_ERROR ? "ERROR" : "unknown status"))); #endif if (res == VIR_DRV_OPEN_ERROR) { if (STREQ(virNetworkDriverTab[i]->name, "remote")) { @@ -467,6 +561,29 @@ do_open (const char *name, int flags) } } + + /* Secondary driver for storage. Optional */ + for (i = 0; i < virStorageDriverTabCount; i++) { + res = virStorageDriverTab[i]->open (ret, name, flags); +#ifdef ENABLE_DEBUG + DEBUG("storage driver %d %s returned %s", + i, virStorageDriverTab[i]->name, + res == VIR_DRV_OPEN_SUCCESS ? "SUCCESS" : + (res == VIR_DRV_OPEN_DECLINED ? "DECLINED" : + (res == VIR_DRV_OPEN_ERROR ? "ERROR" : "unknown status"))); +#endif + if (res == VIR_DRV_OPEN_ERROR) { + if (STREQ(virStorageDriverTab[i]->name, "remote")) { + virLibConnWarning (NULL, VIR_WAR_NO_STORAGE, + "Is the daemon running ?"); + } + break; + } else if (res == VIR_DRV_OPEN_SUCCESS) { + ret->storageDriver = virStorageDriverTab[i]; + break; + } + } + if (flags & VIR_DRV_OPEN_RO) { ret->flags = VIR_CONNECT_RO; } @@ -537,6 +654,8 @@ virConnectClose(virConnectPtr conn) if (conn->networkDriver) conn->networkDriver->close (conn); + if (conn->storageDriver) + conn->storageDriver->close (conn); conn->driver->close (conn); if (virFreeConnect(conn) < 0) @@ -3360,6 +3479,830 @@ virNetworkSetAutostart(virNetworkPtr net return -1; } + +/** + * virStoragePoolGetConnect: + * @net: pointer to a poool + * + * Provides the connection pointer associated with a storage poolk. 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 pool object together. + * + * Returns the virConnectPtr or NULL in case of failure. + */ +virConnectPtr +virStoragePoolGetConnect (virStoragePoolPtr pool) +{ + DEBUG("pool=%p", pool); + + if (!VIR_IS_STORAGE_POOL (pool)) { + virLibStoragePoolError (NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return NULL; + } + return pool->conn; +} + +/* + * List active storage pools + */ +int +virConnectNumOfStoragePools (virConnectPtr conn) +{ + DEBUG("conn=%p", conn); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (-1); + } + + if (conn->storageDriver && conn->storageDriver->numOfPools) + return conn->storageDriver->numOfPools (conn); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + +int +virConnectListStoragePools (virConnectPtr conn, + char **const names, + int maxnames) +{ + DEBUG("conn=%p, names=%p, maxnames=%d", conn, names, maxnames); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (-1); + } + + if ((names == NULL) || (maxnames < 0)) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + if (conn->storageDriver && conn->storageDriver->listPools) + return conn->storageDriver->listPools (conn, names, maxnames); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; + +} + +int +virConnectNumOfDefinedStoragePools(virConnectPtr conn) +{ + DEBUG("conn=%p", conn); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (-1); + } + + if (conn->storageDriver && conn->storageDriver->numOfDefinedPools) + return conn->storageDriver->numOfDefinedPools (conn); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + + +int +virConnectListDefinedStoragePools(virConnectPtr conn, + char **const names, + int maxnames) +{ + DEBUG("conn=%p, names=%p, maxnames=%d", conn, names, maxnames); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (-1); + } + + if ((names == NULL) || (maxnames < 0)) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + if (conn->storageDriver && conn->storageDriver->listDefinedPools) + return conn->storageDriver->listDefinedPools (conn, names, maxnames); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + + +virStoragePoolPtr +virStoragePoolLookupByName(virConnectPtr conn, + const char *name) +{ + DEBUG("conn=%p, name=%s", conn, name); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (NULL); + } + if (name == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + if (conn->storageDriver && conn->storageDriver->poolLookupByName) + return conn->storageDriver->poolLookupByName (conn, name); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; +} + + +virStoragePoolPtr +virStoragePoolLookupByUUID(virConnectPtr conn, + const unsigned char *uuid) +{ + DEBUG("conn=%p, uuid=%s", conn, uuid); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (NULL); + } + if (uuid == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + if (conn->storageDriver && conn->storageDriver->poolLookupByUUID) + return conn->storageDriver->poolLookupByUUID (conn, uuid); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; + +} + + +virStoragePoolPtr +virStoragePoolLookupByUUIDString(virConnectPtr conn, + const char *uuidstr) +{ + unsigned char uuid[VIR_UUID_BUFLEN]; + DEBUG("conn=%p, uuidstr=%s", conn, uuidstr); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (NULL); + } + if (uuidstr == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + if (virUUIDParse(uuidstr, uuid) < 0) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + return virStoragePoolLookupByUUID(conn, uuid); +} + +virStoragePoolPtr +virStoragePoolCreateXML(virConnectPtr conn, + const char *xmlDesc) +{ + DEBUG("conn=%p, xmlDesc=%s", conn, xmlDesc); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (NULL); + } + if (xmlDesc == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + if (conn->flags & VIR_CONNECT_RO) { + virLibConnError(conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (NULL); + } + + if (conn->storageDriver && conn->storageDriver->poolCreateXML) + return conn->storageDriver->poolCreateXML (conn, xmlDesc); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; +} + +virStoragePoolPtr +virStoragePoolDefineXML(virConnectPtr conn, + const char *xml) +{ + DEBUG("conn=%p, xml=%s", conn, xml); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (NULL); + } + if (conn->flags & VIR_CONNECT_RO) { + virLibConnError(conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (NULL); + } + if (xml == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + if (conn->storageDriver && conn->storageDriver->poolDefineXML) + return conn->storageDriver->poolDefineXML (conn, xml); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; + +} + +int +virStoragePoolUndefine(virStoragePoolPtr pool) +{ + virConnectPtr conn; + DEBUG("pool=%p", pool); + + if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__); + return (-1); + } + conn = pool->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (-1); + } + + if (conn->storageDriver && conn->storageDriver->poolUndefine) + return conn->storageDriver->poolUndefine (pool); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; + +} + +int +virStoragePoolCreate(virStoragePoolPtr pool) +{ + virConnectPtr conn; + DEBUG("pool=%p", pool); + + if (pool == NULL) { + TODO; + return (-1); + } + if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (-1); + } + conn = pool->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (-1); + } + + if (conn->storageDriver && conn->storageDriver->poolCreate) + return conn->storageDriver->poolCreate (pool); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; + +} + +int +virStoragePoolShutdown(virStoragePoolPtr pool) +{ + virConnectPtr conn; + DEBUG("pool=%p", pool); + + if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (-1); + } + + conn = pool->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (-1); + } + + if (conn->storageDriver && conn->storageDriver->poolShutdown) + return conn->storageDriver->poolShutdown (pool); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + + +int +virStoragePoolDestroy (virStoragePoolPtr pool) +{ + virConnectPtr conn; + DEBUG("pool=%p", pool); + + if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (-1); + } + + conn = pool->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (-1); + } + + if (conn->storageDriver && conn->storageDriver->poolDestroy) + return conn->storageDriver->poolDestroy (pool); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + +int +virStoragePoolFree (virStoragePoolPtr pool) +{ + DEBUG("pool=%p", pool); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (-1); + } + if (virFreeStoragePool(pool->conn, pool) < 0) + return (-1); + return(0); + +} + +const char* +virStoragePoolGetName(virStoragePoolPtr pool) +{ + DEBUG("pool=%p", pool); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (NULL); + } + return (pool->name); + +} + + +int +virStoragePoolGetUUID(virStoragePoolPtr pool, + unsigned char *uuid) +{ + DEBUG("pool=%p, uuid=%p", pool, uuid); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (-1); + } + if (uuid == NULL) { + virLibStoragePoolError(pool, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + memcpy(uuid, &pool->uuid[0], VIR_UUID_BUFLEN); + + return (0); + +} + +int +virStoragePoolGetUUIDString(virStoragePoolPtr pool, + char *buf) +{ + unsigned char uuid[VIR_UUID_BUFLEN]; + DEBUG("pool=%p, buf=%p", pool, buf); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (-1); + } + if (buf == NULL) { + virLibStoragePoolError(pool, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + if (virStoragePoolGetUUID(pool, &uuid[0])) + return (-1); + + virUUIDFormat(uuid, buf); + return (0); + +} + +int +virStoragePoolGetInfo(virStoragePoolPtr pool, + virStoragePoolInfoPtr info) +{ + virConnectPtr conn; + DEBUG("pool=%p, info=%p", pool, info); + + if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (-1); + } + if (info == NULL) { + virLibStoragePoolError(pool, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + memset(info, 0, sizeof(virStoragePoolInfo)); + + conn = pool->conn; + + if (conn->storageDriver->poolGetInfo) + return conn->storageDriver->poolGetInfo (pool, info); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; + +} + +char * +virStoragePoolGetXMLDesc(virStoragePoolPtr pool, + int flags) +{ + virConnectPtr conn; + DEBUG("pool=%p, flags=%d", pool, flags); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (NULL); + } + if (flags != 0) { + virLibStoragePoolError(pool, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + conn = pool->conn; + + if (conn->storageDriver && conn->storageDriver->poolGetXMLDesc) + return conn->storageDriver->poolGetXMLDesc (pool, flags); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; + +} + +int +virStoragePoolGetAutostart(virStoragePoolPtr pool, + int *autostart) +{ + virConnectPtr conn; + DEBUG("pool=%p, autostart=%p", pool, autostart); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (-1); + } + if (!autostart) { + virLibStoragePoolError(pool, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + conn = pool->conn; + + if (conn->storageDriver && conn->storageDriver->poolGetAutostart) + return conn->storageDriver->poolGetAutostart (pool, autostart); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + +int +virStoragePoolSetAutostart(virStoragePoolPtr pool, + int autostart) +{ + virConnectPtr conn; + DEBUG("pool=%p, autostart=%d", pool, autostart); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (-1); + } + + conn = pool->conn; + + if (conn->storageDriver && conn->storageDriver->poolSetAutostart) + return conn->storageDriver->poolSetAutostart (pool, autostart); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + +int +virStoragePoolNumOfVolumes(virStoragePoolPtr pool) +{ + DEBUG("pool=%p", pool); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibConnError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (-1); + } + + if (pool->conn->storageDriver && pool->conn->storageDriver->poolNumOfVolumes) + return pool->conn->storageDriver->poolNumOfVolumes (pool); + + virLibConnError (pool->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + + +int +virStoragePoolListVolumes(virStoragePoolPtr pool, + char **const names, + int maxnames) +{ + DEBUG("pool=%p, names=%p, maxnames=%d", pool, names, maxnames); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibConnError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (-1); + } + + if ((names == NULL) || (maxnames < 0)) { + virLibConnError(pool->conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + if (pool->conn->storageDriver && pool->conn->storageDriver->poolListVolumes) + return pool->conn->storageDriver->poolListVolumes (pool, names, maxnames); + + virLibConnError (pool->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + +virStorageVolPtr +virStorageVolLookupByName(virStoragePoolPtr pool, + const char *name) +{ + DEBUG("pool=%p, name=%s", pool, name); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (NULL); + } + if (name == NULL) { + virLibConnError(pool->conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + if (pool->conn->storageDriver && pool->conn->storageDriver->volLookupByName) + return pool->conn->storageDriver->volLookupByName (pool, name); + + virLibConnError (pool->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; +} + +virStorageVolPtr +virStorageVolLookupByUUID(virStoragePoolPtr pool, + const unsigned char *uuid) +{ + DEBUG("pool=%p, uuid=%p", pool, uuid); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (NULL); + } + if (uuid == NULL) { + virLibConnError(pool->conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + if (pool->conn->storageDriver && pool->conn->storageDriver->volLookupByUUID) + return pool->conn->storageDriver->volLookupByUUID (pool, uuid); + + virLibConnError (pool->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; +} + +virStorageVolPtr +virStorageVolLookupByUUIDString(virStoragePoolPtr pool, + const char *uuidstr) +{ + unsigned char uuid[VIR_UUID_BUFLEN]; + DEBUG("pool=%p, uuidstr=%s", pool, uuidstr); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (NULL); + } + if (uuidstr == NULL) { + virLibConnError(pool->conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + if (virUUIDParse(uuidstr, uuid) < 0) { + virLibConnError(pool->conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + return virStorageVolLookupByUUID(pool, uuid); +} + +const char* +virStorageVolGetName(virStorageVolPtr vol) +{ + DEBUG("vol=%p", vol); + + if (!VIR_IS_STORAGE_VOL(vol)) { + virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__); + return (NULL); + } + return (vol->name); +} + +int +virStorageVolGetUUID(virStorageVolPtr vol, + unsigned char *uuid) +{ + DEBUG("vol=%p, uuid=%p", vol, uuid); + + if (!VIR_IS_STORAGE_VOL(vol)) { + virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__); + return (-1); + } + if (uuid == NULL) { + virLibStorageVolError(vol, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + memcpy(uuid, &vol->uuid[0], VIR_UUID_BUFLEN); + + return (0); + +} + + +int +virStorageVolGetUUIDString(virStorageVolPtr vol, + char *buf) +{ + unsigned char uuid[VIR_UUID_BUFLEN]; + DEBUG("vol=%p, buf=%p", vol, buf); + + if (!VIR_IS_STORAGE_VOL(vol)) { + virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__); + return (-1); + } + if (buf == NULL) { + virLibStorageVolError(vol, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + if (virStorageVolGetUUID(vol, &uuid[0])) + return (-1); + + virUUIDFormat(uuid, buf); + return (0); +} + + + +virStorageVolPtr +virStorageVolCreateXML(virStoragePoolPtr pool, + const char *xmldesc, + int flags) +{ + virConnectPtr conn; + DEBUG("pool=%p", pool); + + if (pool == NULL) { + TODO; + return (NULL); + } + if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__); + return (NULL); + } + conn = pool->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (NULL); + } + + if (conn->storageDriver && conn->storageDriver->volCreateXML) + return conn->storageDriver->volCreateXML (pool, xmldesc, flags); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; +} + +int +virStorageVolDestroy(virStorageVolPtr vol) +{ + virConnectPtr conn; + DEBUG("vol=%p", vol); + + if (!VIR_IS_CONNECTED_STORAGE_VOL(vol)) { + virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__); + return (-1); + } + + conn = vol->pool->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibStorageVolError(vol, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (-1); + } + + if (conn->storageDriver && conn->storageDriver->volDestroy) + return conn->storageDriver->volDestroy (vol); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + +int +virStorageVolFree(virStorageVolPtr vol) +{ + DEBUG("vol=%p", vol); + + if (!VIR_IS_STORAGE_VOL(vol)) { + virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__); + return (-1); + } + if (virFreeStorageVol(vol->pool->conn, vol) < 0) + return (-1); + return(0); +} + +int +virStorageVolGetInfo(virStorageVolPtr vol, + virStorageVolInfoPtr info) +{ + virConnectPtr conn; + DEBUG("vol=%p, info=%p", vol, info); + + if (!VIR_IS_CONNECTED_STORAGE_VOL(vol)) { + virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__); + return (-1); + } + if (info == NULL) { + virLibStorageVolError(vol, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + memset(info, 0, sizeof(virStorageVolInfo)); + + conn = vol->pool->conn; + + if (conn->storageDriver->volGetInfo) + return conn->storageDriver->volGetInfo (vol, info); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + +char * +virStorageVolGetXMLDesc(virStorageVolPtr vol, + int flags) +{ + virConnectPtr conn; + DEBUG("vol=%p, flags=%d", vol, flags); + + if (!VIR_IS_STORAGE_VOL(vol)) { + virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__); + return (NULL); + } + if (flags != 0) { + virLibStorageVolError(vol, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + conn = vol->pool->conn; + + if (conn->storageDriver && conn->storageDriver->volGetXMLDesc) + return conn->storageDriver->volGetXMLDesc (vol, flags); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; + +} + +char * +virStorageVolGetPath(virStorageVolPtr vol) +{ + virConnectPtr conn; + DEBUG("vol=%p", vol); + + if (!VIR_IS_STORAGE_VOL(vol)) { + virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__); + return (NULL); + } + + conn = vol->pool->conn; + + if (conn->storageDriver && conn->storageDriver->volGetPath) + return conn->storageDriver->volGetPath (vol); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; +} + + /* * vim: set tabstop=4: * vim: set shiftwidth=4: diff -r b5447763aad6 src/libvirt_sym.version --- a/src/libvirt_sym.version Sat Oct 27 16:56:42 2007 -0400 +++ b/src/libvirt_sym.version Sun Oct 28 14:34:03 2007 -0400 @@ -119,8 +119,8 @@ virStoragePoolSetAutostart; virStoragePoolGetAutostart; - virConnectNumOfStorageVolumes; - virConnectListStorageVolumes; + virStoragePoolNumOfVolumes; + virStoragePoolListVolumes; virStorageVolCreateXML; virStorageVolDestroy; virStorageVolFree; -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

On Mon, Oct 29, 2007 at 03:57:29AM +0000, Daniel P. Berrange wrote:
This patch defines the internal driver API for the storage API calls. It also provides the cache implementation for the virStoragePoolPtr and virStorageVolPtr objects. The virStorageVolPtr object is a little different in that it doesn't reference the virConnectPtr object directly. Instead it points to the virStoragePoolPtr object. This
Okay
makes the reference counting 'interesting', because when we get a virStorageVolPtr object, we have increment the count on both the pool and the connection. This was starting to get complex, so to keep it sane I don't bother with referencing counting on the virStorageVolPtr object itself.
So how do you get rid of it ? You assume they will always stay around ? Also what's the story about locking in that patch, you're trying to allow concurrent operations on multiple storage pools (which may be needed due to storage and network latencies) [...]
+ * Provides the connection pointer associated with a storage poolk. The
s/poolk/pool/ The patch code looks mostly common :-) Daniel -- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard@redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/

This patch defines the remote wire protocol for serializing all the storage API calls. There are 15 new calls for storage pools, and 9 calls for storage volumes. The style is following that of the network API calls. The serialization of virStorageVolPtr is slightly more complicated, because it has to have a nested virStoragePoolPtr serialized alongside it. remote.c | 629 ++++++++++++++++++++++++++++++++++++++++++ remote_dispatch_localvars.h | 42 ++ remote_dispatch_proc_switch.h | 201 +++++++++++++ remote_dispatch_prototypes.h | 25 + remote_protocol.c | 450 ++++++++++++++++++++++++++++++ remote_protocol.h | 367 ++++++++++++++++++++++++ remote_protocol.x | 238 +++++++++++++++ 7 files changed, 1951 insertions(+), 1 deletion(-) diff -r 89d154031d13 qemud/remote.c --- a/qemud/remote.c Sat Oct 27 17:52:41 2007 -0400 +++ b/qemud/remote.c Sat Oct 27 17:52:44 2007 -0400 @@ -57,8 +57,12 @@ static void remoteDispatchError (struct const char *fmt, ...); static virDomainPtr get_nonnull_domain (virConnectPtr conn, remote_nonnull_domain domain); static virNetworkPtr get_nonnull_network (virConnectPtr conn, remote_nonnull_network network); +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 void make_nonnull_domain (remote_nonnull_domain *dom_dst, virDomainPtr dom_src); static void make_nonnull_network (remote_nonnull_network *net_dst, virNetworkPtr net_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); #include "remote_dispatch_prototypes.h" @@ -1945,6 +1949,598 @@ remoteDispatchNumOfNetworks (struct qemu return 0; } + +/*************************************************************** + * STORAGE POOL APIS + ***************************************************************/ + + +static int +remoteDispatchListDefinedStoragePools (struct qemud_client *client, + remote_message_header *req, + remote_list_defined_storage_pools_args *args, + remote_list_defined_storage_pools_ret *ret) +{ + CHECK_CONN(client); + + if (args->maxnames > REMOTE_NETWORK_NAME_LIST_MAX) { + remoteDispatchError (client, req, + "maxnames > REMOTE_NETWORK_NAME_LIST_MAX"); + return -2; + } + + /* Allocate return buffer. */ + ret->names.names_val = calloc (args->maxnames, sizeof (char *)); + + ret->names.names_len = + virConnectListDefinedStoragePools (client->conn, + ret->names.names_val, args->maxnames); + if (ret->names.names_len == -1) return -1; + + return 0; +} + +static int +remoteDispatchListStoragePools (struct qemud_client *client, + remote_message_header *req, + remote_list_storage_pools_args *args, + remote_list_storage_pools_ret *ret) +{ + CHECK_CONN(client); + + if (args->maxnames > REMOTE_STORAGE_POOL_NAME_LIST_MAX) { + remoteDispatchError (client, req, + "maxnames > REMOTE_STORAGE_POOL_NAME_LIST_MAX"); + return -2; + } + + /* Allocate return buffer. */ + ret->names.names_val = calloc (args->maxnames, sizeof (char *)); + + ret->names.names_len = + virConnectListStoragePools (client->conn, + ret->names.names_val, args->maxnames); + if (ret->names.names_len == -1) return -1; + + return 0; +} + +static int +remoteDispatchStoragePoolCreate (struct qemud_client *client, + remote_message_header *req, + remote_storage_pool_create_args *args, + void *ret ATTRIBUTE_UNUSED) +{ + virStoragePoolPtr pool; + CHECK_CONN(client); + + pool = get_nonnull_storage_pool (client->conn, args->pool); + if (pool == NULL) { + remoteDispatchError (client, req, "storage_pool not found"); + return -2; + } + + if (virStoragePoolCreate (pool) == -1) { + virStoragePoolFree(pool); + return -1; + } + virStoragePoolFree(pool); + return 0; +} + +static int +remoteDispatchStoragePoolCreateXml (struct qemud_client *client, + remote_message_header *req, + remote_storage_pool_create_xml_args *args, + remote_storage_pool_create_xml_ret *ret) +{ + virStoragePoolPtr pool; + CHECK_CONN(client); + + pool = virStoragePoolCreateXML (client->conn, args->xml); + if (pool == NULL) return -1; + + make_nonnull_storage_pool (&ret->pool, pool); + virStoragePoolFree(pool); + return 0; +} + +static int +remoteDispatchStoragePoolDefineXml (struct qemud_client *client, + remote_message_header *req, + remote_storage_pool_define_xml_args *args, + remote_storage_pool_define_xml_ret *ret) +{ + virStoragePoolPtr pool; + CHECK_CONN(client); + + pool = virStoragePoolDefineXML (client->conn, args->xml); + if (pool == NULL) return -1; + + make_nonnull_storage_pool (&ret->pool, pool); + virStoragePoolFree(pool); + return 0; +} + +static int +remoteDispatchStoragePoolShutdown (struct qemud_client *client, + remote_message_header *req, + remote_storage_pool_shutdown_args *args, + void *ret ATTRIBUTE_UNUSED) +{ + virStoragePoolPtr pool; + CHECK_CONN(client); + + pool = get_nonnull_storage_pool (client->conn, args->pool); + if (pool == NULL) { + remoteDispatchError (client, req, "storage_pool not found"); + return -2; + } + + if (virStoragePoolShutdown (pool) == -1) { + virStoragePoolFree(pool); + return -1; + } + virStoragePoolFree(pool); + return 0; +} + +static int +remoteDispatchStoragePoolDestroy (struct qemud_client *client, + remote_message_header *req, + remote_storage_pool_destroy_args *args, + void *ret ATTRIBUTE_UNUSED) +{ + virStoragePoolPtr pool; + CHECK_CONN(client); + + pool = get_nonnull_storage_pool (client->conn, args->pool); + if (pool == NULL) { + remoteDispatchError (client, req, "storage_pool not found"); + return -2; + } + + if (virStoragePoolDestroy (pool) == -1) { + virStoragePoolFree(pool); + return -1; + } + virStoragePoolFree(pool); + return 0; +} + +static int +remoteDispatchStoragePoolGetInfo (struct qemud_client *client, + remote_message_header *req, + remote_storage_pool_get_info_args *args, + remote_storage_pool_get_info_ret *ret) +{ + virStoragePoolPtr pool; + virStoragePoolInfo info; + CHECK_CONN(client); + + pool = get_nonnull_storage_pool (client->conn, args->pool); + if (pool == NULL) { + remoteDispatchError (client, req, "storage_pool not found"); + return -2; + } + + if (virStoragePoolGetInfo (pool, &info) == -1) { + virStoragePoolFree(pool); + return -1; + } + + ret->state = info.state; + ret->allocation = info.allocation; + ret->capacity = info.capacity; + + virStoragePoolFree(pool); + + return 0; +} + +static int +remoteDispatchStoragePoolDumpXml (struct qemud_client *client, + remote_message_header *req, + remote_storage_pool_dump_xml_args *args, + remote_storage_pool_dump_xml_ret *ret) +{ + virStoragePoolPtr pool; + CHECK_CONN(client); + + pool = get_nonnull_storage_pool (client->conn, args->pool); + if (pool == NULL) { + remoteDispatchError (client, req, "storage_pool not found"); + return -2; + } + + /* remoteDispatchClientRequest will free this. */ + ret->xml = virStoragePoolGetXMLDesc (pool, args->flags); + if (!ret->xml) { + virStoragePoolFree(pool); + return -1; + } + virStoragePoolFree(pool); + return 0; +} + +static int +remoteDispatchStoragePoolGetAutostart (struct qemud_client *client, + remote_message_header *req, + remote_storage_pool_get_autostart_args *args, + remote_storage_pool_get_autostart_ret *ret) +{ + virStoragePoolPtr pool; + CHECK_CONN(client); + + pool = get_nonnull_storage_pool (client->conn, args->pool); + if (pool == NULL) { + remoteDispatchError (client, req, "storage_pool not found"); + return -2; + } + + if (virStoragePoolGetAutostart (pool, &ret->autostart) == -1) { + virStoragePoolFree(pool); + return -1; + } + virStoragePoolFree(pool); + return 0; +} + + +static int +remoteDispatchStoragePoolLookupByName (struct qemud_client *client, + remote_message_header *req, + remote_storage_pool_lookup_by_name_args *args, + remote_storage_pool_lookup_by_name_ret *ret) +{ + virStoragePoolPtr pool; + CHECK_CONN(client); + + pool = virStoragePoolLookupByName (client->conn, args->name); + if (pool == NULL) return -1; + + make_nonnull_storage_pool (&ret->pool, pool); + virStoragePoolFree(pool); + return 0; +} + +static int +remoteDispatchStoragePoolLookupByUuid (struct qemud_client *client, + remote_message_header *req, + remote_storage_pool_lookup_by_uuid_args *args, + remote_storage_pool_lookup_by_uuid_ret *ret) +{ + virStoragePoolPtr pool; + CHECK_CONN(client); + + pool = virStoragePoolLookupByUUID (client->conn, (unsigned char *) args->uuid); + if (pool == NULL) return -1; + + make_nonnull_storage_pool (&ret->pool, pool); + virStoragePoolFree(pool); + return 0; +} + +static int +remoteDispatchStoragePoolSetAutostart (struct qemud_client *client, + remote_message_header *req, + remote_storage_pool_set_autostart_args *args, + void *ret ATTRIBUTE_UNUSED) +{ + virStoragePoolPtr pool; + CHECK_CONN(client); + + pool = get_nonnull_storage_pool (client->conn, args->pool); + if (pool == NULL) { + remoteDispatchError (client, req, "storage_pool not found"); + return -2; + } + + if (virStoragePoolSetAutostart (pool, args->autostart) == -1) { + virStoragePoolFree(pool); + return -1; + } + virStoragePoolFree(pool); + return 0; +} + +static int +remoteDispatchStoragePoolUndefine (struct qemud_client *client, + remote_message_header *req, + remote_storage_pool_undefine_args *args, + void *ret ATTRIBUTE_UNUSED) +{ + virStoragePoolPtr pool; + CHECK_CONN(client); + + pool = get_nonnull_storage_pool (client->conn, args->pool); + if (pool == NULL) { + remoteDispatchError (client, req, "storage_pool not found"); + return -2; + } + + if (virStoragePoolUndefine (pool) == -1) { + virStoragePoolFree(pool); + return -1; + } + virStoragePoolFree(pool); + return 0; +} + +static int +remoteDispatchNumOfStoragePools (struct qemud_client *client, + remote_message_header *req, + void *args ATTRIBUTE_UNUSED, + remote_num_of_storage_pools_ret *ret) +{ + CHECK_CONN(client); + + ret->num = virConnectNumOfStoragePools (client->conn); + if (ret->num == -1) return -1; + + return 0; +} + +static int +remoteDispatchNumOfDefinedStoragePools (struct qemud_client *client, + remote_message_header *req, + void *args ATTRIBUTE_UNUSED, + remote_num_of_defined_storage_pools_ret *ret) +{ + CHECK_CONN(client); + + ret->num = virConnectNumOfDefinedStoragePools (client->conn); + if (ret->num == -1) return -1; + + return 0; +} + + +/*************************************************************** + * STORAGE VOL APIS + ***************************************************************/ + + +static int +remoteDispatchStoragePoolListVolumes (struct qemud_client *client, + remote_message_header *req, + remote_storage_pool_list_volumes_args *args, + remote_storage_pool_list_volumes_ret *ret) +{ + virStoragePoolPtr pool; + CHECK_CONN(client); + + if (args->maxnames > REMOTE_STORAGE_VOL_NAME_LIST_MAX) { + remoteDispatchError (client, req, + "maxnames > REMOTE_STORAGE_VOL_NAME_LIST_MAX"); + return -2; + } + + pool = get_nonnull_storage_pool (client->conn, args->pool); + if (pool == NULL) { + remoteDispatchError (client, req, "storage_pool not found"); + return -2; + } + + /* Allocate return buffer. */ + ret->names.names_val = calloc (args->maxnames, sizeof (char *)); + + ret->names.names_len = + virStoragePoolListVolumes (pool, + ret->names.names_val, args->maxnames); + virStoragePoolFree(pool); + if (ret->names.names_len == -1) return -1; + + return 0; +} + + +static int +remoteDispatchStorageVolCreateXml (struct qemud_client *client, + remote_message_header *req, + remote_storage_vol_create_xml_args *args, + remote_storage_vol_create_xml_ret *ret) +{ + virStoragePoolPtr pool; + virStorageVolPtr vol; + CHECK_CONN(client); + + pool = get_nonnull_storage_pool (client->conn, args->pool); + if (pool == NULL) { + remoteDispatchError (client, req, "storage_pool not found"); + return -2; + } + + vol = virStorageVolCreateXML (pool, args->xml, args->flags); + virStoragePoolFree(pool); + if (vol == NULL) return -1; + + make_nonnull_storage_vol (&ret->vol, vol); + virStorageVolFree(vol); + return 0; +} + + +static int +remoteDispatchStorageVolDestroy (struct qemud_client *client, + remote_message_header *req, + remote_storage_vol_destroy_args *args, + void *ret ATTRIBUTE_UNUSED) +{ + virStorageVolPtr vol; + CHECK_CONN(client); + + vol = get_nonnull_storage_vol (client->conn, args->vol); + if (vol == NULL) { + remoteDispatchError (client, req, "storage_vol not found"); + return -2; + } + + if (virStorageVolDestroy (vol) == -1) { + virStorageVolFree(vol); + return -1; + } + virStorageVolFree(vol); + return 0; +} + +static int +remoteDispatchStorageVolGetInfo (struct qemud_client *client, + remote_message_header *req, + remote_storage_vol_get_info_args *args, + remote_storage_vol_get_info_ret *ret) +{ + virStorageVolPtr vol; + virStorageVolInfo info; + CHECK_CONN(client); + + vol = get_nonnull_storage_vol (client->conn, args->vol); + if (vol == NULL) { + remoteDispatchError (client, req, "storage_vol not found"); + return -2; + } + + if (virStorageVolGetInfo (vol, &info) == -1) { + virStorageVolFree(vol); + return -1; + } + + ret->type = info.type; + ret->allocation = info.allocation; + ret->capacity = info.capacity; + + virStorageVolFree(vol); + + return 0; +} + +static int +remoteDispatchStorageVolDumpXml (struct qemud_client *client, + remote_message_header *req, + remote_storage_vol_dump_xml_args *args, + remote_storage_vol_dump_xml_ret *ret) +{ + virStorageVolPtr vol; + CHECK_CONN(client); + + vol = get_nonnull_storage_vol (client->conn, args->vol); + if (vol == NULL) { + remoteDispatchError (client, req, "storage_vol not found"); + return -2; + } + + /* remoteDispatchClientRequest will free this. */ + ret->xml = virStorageVolGetXMLDesc (vol, args->flags); + if (!ret->xml) { + virStorageVolFree(vol); + return -1; + } + virStorageVolFree(vol); + return 0; +} + + +static int +remoteDispatchStorageVolGetPath (struct qemud_client *client, + remote_message_header *req, + remote_storage_vol_get_path_args *args, + remote_storage_vol_get_path_ret *ret) +{ + virStorageVolPtr vol; + CHECK_CONN(client); + + vol = get_nonnull_storage_vol (client->conn, args->vol); + if (vol == NULL) { + remoteDispatchError (client, req, "storage_vol not found"); + return -2; + } + + /* remoteDispatchClientRequest will free this. */ + ret->name = virStorageVolGetPath (vol); + if (!ret->name) { + virStorageVolFree(vol); + return -1; + } + virStorageVolFree(vol); + return 0; +} + + +static int +remoteDispatchStorageVolLookupByName (struct qemud_client *client, + remote_message_header *req, + remote_storage_vol_lookup_by_name_args *args, + remote_storage_vol_lookup_by_name_ret *ret) +{ + virStoragePoolPtr pool; + virStorageVolPtr vol; + CHECK_CONN(client); + + pool = get_nonnull_storage_pool (client->conn, args->pool); + if (pool == NULL) { + remoteDispatchError (client, req, "storage_pool not found"); + return -2; + } + + + vol = virStorageVolLookupByName (pool, args->name); + virStoragePoolFree(pool); + if (vol == NULL) return -1; + + make_nonnull_storage_vol (&ret->vol, vol); + virStorageVolFree(vol); + return 0; +} + +static int +remoteDispatchStorageVolLookupByUuid (struct qemud_client *client, + remote_message_header *req, + remote_storage_vol_lookup_by_uuid_args *args, + remote_storage_vol_lookup_by_uuid_ret *ret) +{ + virStoragePoolPtr pool; + virStorageVolPtr vol; + CHECK_CONN(client); + + pool = get_nonnull_storage_pool (client->conn, args->pool); + if (pool == NULL) { + remoteDispatchError (client, req, "storage_pool not found"); + return -2; + } + + vol = virStorageVolLookupByUUID (pool, (unsigned char *) args->uuid); + virStoragePoolFree(pool); + if (vol == NULL) return -1; + + make_nonnull_storage_vol (&ret->vol, vol); + virStorageVolFree(vol); + return 0; +} + + +static int +remoteDispatchStoragePoolNumOfVolumes (struct qemud_client *client, + remote_message_header *req, + remote_storage_pool_num_of_volumes_args *args, + remote_storage_pool_num_of_volumes_ret *ret) +{ + virStoragePoolPtr pool; + CHECK_CONN(client); + + pool = get_nonnull_storage_pool (client->conn, args->pool); + if (pool == NULL) { + remoteDispatchError (client, req, "storage_pool not found"); + return -2; + } + + ret->num = virStoragePoolNumOfVolumes (pool); + virStoragePoolFree(pool); + if (ret->num == -1) return -1; + + return 0; +} + + /*----- Helpers. -----*/ /* get_nonnull_domain and get_nonnull_network turn an on-wire @@ -1971,6 +2567,24 @@ get_nonnull_network (virConnectPtr conn, return virGetNetwork (conn, network.name, BAD_CAST network.uuid); } +static virStoragePoolPtr +get_nonnull_storage_pool (virConnectPtr conn, remote_nonnull_storage_pool pool) +{ + return virGetStoragePool (conn, pool.name, BAD_CAST pool.uuid); +} + +static virStorageVolPtr +get_nonnull_storage_vol (virConnectPtr conn, remote_nonnull_storage_vol vol) +{ + virStorageVolPtr ret; + virStoragePoolPtr pool = get_nonnull_storage_pool(conn, vol.pool); + if (pool == NULL) + return NULL; + ret = virGetStorageVol (pool, vol.name, BAD_CAST vol.uuid); + virStoragePoolFree(pool); + return ret; +} + /* Make remote_nonnull_domain and remote_nonnull_network. */ static void make_nonnull_domain (remote_nonnull_domain *dom_dst, virDomainPtr dom_src) @@ -1985,6 +2599,21 @@ make_nonnull_network (remote_nonnull_net { net_dst->name = strdup (net_src->name); memcpy (net_dst->uuid, net_src->uuid, VIR_UUID_BUFLEN); +} + +static void +make_nonnull_storage_pool (remote_nonnull_storage_pool *pool_dst, virStoragePoolPtr pool_src) +{ + pool_dst->name = strdup (pool_src->name); + memcpy (pool_dst->uuid, pool_src->uuid, VIR_UUID_BUFLEN); +} + +static void +make_nonnull_storage_vol (remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_src) +{ + make_nonnull_storage_pool (&vol_dst->pool, vol_src->pool); + vol_dst->name = strdup (vol_src->name); + memcpy (vol_dst->uuid, vol_src->uuid, VIR_UUID_BUFLEN); } /* diff -r 89d154031d13 qemud/remote_dispatch_localvars.h --- a/qemud/remote_dispatch_localvars.h Sat Oct 27 17:52:41 2007 -0400 +++ b/qemud/remote_dispatch_localvars.h Sat Oct 27 17:55:07 2007 -0400 @@ -4,10 +4,14 @@ remote_domain_lookup_by_uuid_args lv_remote_domain_lookup_by_uuid_args; remote_domain_lookup_by_uuid_ret lv_remote_domain_lookup_by_uuid_ret; +remote_storage_pool_list_volumes_args lv_remote_storage_pool_list_volumes_args; +remote_storage_pool_list_volumes_ret lv_remote_storage_pool_list_volumes_ret; remote_domain_shutdown_args lv_remote_domain_shutdown_args; remote_list_defined_domains_args lv_remote_list_defined_domains_args; remote_list_defined_domains_ret lv_remote_list_defined_domains_ret; remote_get_capabilities_ret lv_remote_get_capabilities_ret; +remote_storage_vol_create_xml_args lv_remote_storage_vol_create_xml_args; +remote_storage_vol_create_xml_ret lv_remote_storage_vol_create_xml_ret; remote_domain_set_max_memory_args lv_remote_domain_set_max_memory_args; remote_domain_get_os_type_args lv_remote_domain_get_os_type_args; remote_domain_get_os_type_ret lv_remote_domain_get_os_type_ret; @@ -15,9 +19,13 @@ remote_domain_get_autostart_ret lv_remot remote_domain_get_autostart_ret lv_remote_domain_get_autostart_ret; remote_domain_set_vcpus_args lv_remote_domain_set_vcpus_args; remote_get_hostname_ret lv_remote_get_hostname_ret; +remote_storage_vol_lookup_by_uuid_args lv_remote_storage_vol_lookup_by_uuid_args; +remote_storage_vol_lookup_by_uuid_ret lv_remote_storage_vol_lookup_by_uuid_ret; remote_network_undefine_args lv_remote_network_undefine_args; remote_domain_create_args lv_remote_domain_create_args; remote_network_destroy_args lv_remote_network_destroy_args; +remote_storage_pool_lookup_by_uuid_args lv_remote_storage_pool_lookup_by_uuid_args; +remote_storage_pool_lookup_by_uuid_ret lv_remote_storage_pool_lookup_by_uuid_ret; remote_domain_pin_vcpu_args lv_remote_domain_pin_vcpu_args; remote_list_defined_networks_args lv_remote_list_defined_networks_args; remote_list_defined_networks_ret lv_remote_list_defined_networks_ret; @@ -33,19 +41,27 @@ remote_network_dump_xml_ret lv_remote_ne remote_network_dump_xml_ret lv_remote_network_dump_xml_ret; remote_domain_reboot_args lv_remote_domain_reboot_args; remote_domain_set_memory_args lv_remote_domain_set_memory_args; +remote_storage_pool_destroy_args lv_remote_storage_pool_destroy_args; remote_domain_create_linux_args lv_remote_domain_create_linux_args; remote_domain_create_linux_ret lv_remote_domain_create_linux_ret; remote_domain_set_scheduler_parameters_args lv_remote_domain_set_scheduler_parameters_args; remote_domain_interface_stats_args lv_remote_domain_interface_stats_args; remote_domain_interface_stats_ret lv_remote_domain_interface_stats_ret; +remote_storage_pool_dump_xml_args lv_remote_storage_pool_dump_xml_args; +remote_storage_pool_dump_xml_ret lv_remote_storage_pool_dump_xml_ret; +remote_storage_pool_create_xml_args lv_remote_storage_pool_create_xml_args; +remote_storage_pool_create_xml_ret lv_remote_storage_pool_create_xml_ret; remote_domain_get_max_vcpus_args lv_remote_domain_get_max_vcpus_args; remote_domain_get_max_vcpus_ret lv_remote_domain_get_max_vcpus_ret; remote_domain_get_info_args lv_remote_domain_get_info_args; remote_domain_get_info_ret lv_remote_domain_get_info_ret; +remote_storage_pool_num_of_volumes_args lv_remote_storage_pool_num_of_volumes_args; +remote_storage_pool_num_of_volumes_ret lv_remote_storage_pool_num_of_volumes_ret; remote_supports_feature_args lv_remote_supports_feature_args; remote_supports_feature_ret lv_remote_supports_feature_ret; remote_domain_lookup_by_name_args lv_remote_domain_lookup_by_name_args; remote_domain_lookup_by_name_ret lv_remote_domain_lookup_by_name_ret; +remote_storage_pool_set_autostart_args lv_remote_storage_pool_set_autostart_args; remote_domain_resume_args lv_remote_domain_resume_args; remote_network_get_bridge_name_args lv_remote_network_get_bridge_name_args; remote_network_get_bridge_name_ret lv_remote_network_get_bridge_name_ret; @@ -56,6 +72,7 @@ remote_domain_get_vcpus_ret lv_remote_do remote_domain_get_vcpus_ret lv_remote_domain_get_vcpus_ret; remote_domain_get_scheduler_parameters_args lv_remote_domain_get_scheduler_parameters_args; remote_domain_get_scheduler_parameters_ret lv_remote_domain_get_scheduler_parameters_ret; +remote_storage_vol_destroy_args lv_remote_storage_vol_destroy_args; remote_node_get_info_ret lv_remote_node_get_info_ret; remote_network_lookup_by_name_args lv_remote_network_lookup_by_name_args; remote_network_lookup_by_name_ret lv_remote_network_lookup_by_name_ret; @@ -64,6 +81,7 @@ remote_domain_block_stats_ret lv_remote_ remote_domain_block_stats_ret lv_remote_domain_block_stats_ret; remote_domain_detach_device_args lv_remote_domain_detach_device_args; remote_domain_save_args lv_remote_domain_save_args; +remote_num_of_storage_pools_ret lv_remote_num_of_storage_pools_ret; remote_domain_migrate_prepare_args lv_remote_domain_migrate_prepare_args; remote_domain_migrate_prepare_ret lv_remote_domain_migrate_prepare_ret; remote_domain_undefine_args lv_remote_domain_undefine_args; @@ -71,27 +89,51 @@ remote_domain_get_scheduler_type_ret lv_ remote_domain_get_scheduler_type_ret lv_remote_domain_get_scheduler_type_ret; remote_get_version_ret lv_remote_get_version_ret; remote_domain_suspend_args lv_remote_domain_suspend_args; +remote_storage_pool_lookup_by_name_args lv_remote_storage_pool_lookup_by_name_args; +remote_storage_pool_lookup_by_name_ret lv_remote_storage_pool_lookup_by_name_ret; remote_network_set_autostart_args lv_remote_network_set_autostart_args; remote_network_get_autostart_args lv_remote_network_get_autostart_args; remote_network_get_autostart_ret lv_remote_network_get_autostart_ret; +remote_storage_pool_create_args lv_remote_storage_pool_create_args; +remote_num_of_defined_storage_pools_ret lv_remote_num_of_defined_storage_pools_ret; remote_domain_core_dump_args lv_remote_domain_core_dump_args; +remote_list_defined_storage_pools_args lv_remote_list_defined_storage_pools_args; +remote_list_defined_storage_pools_ret lv_remote_list_defined_storage_pools_ret; remote_domain_get_max_memory_args lv_remote_domain_get_max_memory_args; remote_domain_get_max_memory_ret lv_remote_domain_get_max_memory_ret; remote_num_of_domains_ret lv_remote_num_of_domains_ret; remote_list_networks_args lv_remote_list_networks_args; remote_list_networks_ret lv_remote_list_networks_ret; +remote_storage_pool_undefine_args lv_remote_storage_pool_undefine_args; remote_domain_set_autostart_args lv_remote_domain_set_autostart_args; +remote_storage_pool_get_autostart_args lv_remote_storage_pool_get_autostart_args; +remote_storage_pool_get_autostart_ret lv_remote_storage_pool_get_autostart_ret; +remote_storage_vol_get_path_args lv_remote_storage_vol_get_path_args; +remote_storage_vol_get_path_ret lv_remote_storage_vol_get_path_ret; remote_domain_lookup_by_id_args lv_remote_domain_lookup_by_id_args; remote_domain_lookup_by_id_ret lv_remote_domain_lookup_by_id_ret; remote_domain_attach_device_args lv_remote_domain_attach_device_args; remote_num_of_networks_ret lv_remote_num_of_networks_ret; +remote_storage_pool_get_info_args lv_remote_storage_pool_get_info_args; +remote_storage_pool_get_info_ret lv_remote_storage_pool_get_info_ret; +remote_list_storage_pools_args lv_remote_list_storage_pools_args; +remote_list_storage_pools_ret lv_remote_list_storage_pools_ret; remote_domain_restore_args lv_remote_domain_restore_args; +remote_storage_pool_shutdown_args lv_remote_storage_pool_shutdown_args; remote_network_create_args lv_remote_network_create_args; remote_num_of_defined_networks_ret lv_remote_num_of_defined_networks_ret; +remote_storage_vol_lookup_by_name_args lv_remote_storage_vol_lookup_by_name_args; +remote_storage_vol_lookup_by_name_ret lv_remote_storage_vol_lookup_by_name_ret; +remote_storage_pool_define_xml_args lv_remote_storage_pool_define_xml_args; +remote_storage_pool_define_xml_ret lv_remote_storage_pool_define_xml_ret; remote_network_lookup_by_uuid_args lv_remote_network_lookup_by_uuid_args; remote_network_lookup_by_uuid_ret lv_remote_network_lookup_by_uuid_ret; +remote_storage_vol_get_info_args lv_remote_storage_vol_get_info_args; +remote_storage_vol_get_info_ret lv_remote_storage_vol_get_info_ret; remote_domain_define_xml_args lv_remote_domain_define_xml_args; remote_domain_define_xml_ret lv_remote_domain_define_xml_ret; +remote_storage_vol_dump_xml_args lv_remote_storage_vol_dump_xml_args; +remote_storage_vol_dump_xml_ret lv_remote_storage_vol_dump_xml_ret; remote_domain_dump_xml_args lv_remote_domain_dump_xml_args; remote_domain_dump_xml_ret lv_remote_domain_dump_xml_ret; remote_get_max_vcpus_args lv_remote_get_max_vcpus_args; diff -r 89d154031d13 qemud/remote_dispatch_proc_switch.h --- a/qemud/remote_dispatch_proc_switch.h Sat Oct 27 17:52:41 2007 -0400 +++ b/qemud/remote_dispatch_proc_switch.h Sat Oct 27 17:55:07 2007 -0400 @@ -332,6 +332,15 @@ case REMOTE_PROC_LIST_DEFINED_NETWORKS: ret = (char *) &lv_remote_list_defined_networks_ret; memset (&lv_remote_list_defined_networks_ret, 0, sizeof lv_remote_list_defined_networks_ret); break; +case REMOTE_PROC_LIST_DEFINED_STORAGE_POOLS: + fn = (dispatch_fn) remoteDispatchListDefinedStoragePools; + args_filter = (xdrproc_t) xdr_remote_list_defined_storage_pools_args; + args = (char *) &lv_remote_list_defined_storage_pools_args; + memset (&lv_remote_list_defined_storage_pools_args, 0, sizeof lv_remote_list_defined_storage_pools_args); + ret_filter = (xdrproc_t) xdr_remote_list_defined_storage_pools_ret; + ret = (char *) &lv_remote_list_defined_storage_pools_ret; + memset (&lv_remote_list_defined_storage_pools_ret, 0, sizeof lv_remote_list_defined_storage_pools_ret); + break; case REMOTE_PROC_LIST_DOMAINS: fn = (dispatch_fn) remoteDispatchListDomains; args_filter = (xdrproc_t) xdr_remote_list_domains_args; @@ -350,6 +359,15 @@ case REMOTE_PROC_LIST_NETWORKS: ret = (char *) &lv_remote_list_networks_ret; memset (&lv_remote_list_networks_ret, 0, sizeof lv_remote_list_networks_ret); break; +case REMOTE_PROC_LIST_STORAGE_POOLS: + fn = (dispatch_fn) remoteDispatchListStoragePools; + args_filter = (xdrproc_t) xdr_remote_list_storage_pools_args; + args = (char *) &lv_remote_list_storage_pools_args; + memset (&lv_remote_list_storage_pools_args, 0, sizeof lv_remote_list_storage_pools_args); + ret_filter = (xdrproc_t) xdr_remote_list_storage_pools_ret; + ret = (char *) &lv_remote_list_storage_pools_ret; + memset (&lv_remote_list_storage_pools_ret, 0, sizeof lv_remote_list_storage_pools_ret); + break; case REMOTE_PROC_NETWORK_CREATE: fn = (dispatch_fn) remoteDispatchNetworkCreate; args_filter = (xdrproc_t) xdr_remote_network_create_args; @@ -455,6 +473,12 @@ case REMOTE_PROC_NUM_OF_DEFINED_NETWORKS ret = (char *) &lv_remote_num_of_defined_networks_ret; memset (&lv_remote_num_of_defined_networks_ret, 0, sizeof lv_remote_num_of_defined_networks_ret); break; +case REMOTE_PROC_NUM_OF_DEFINED_STORAGE_POOLS: + fn = (dispatch_fn) remoteDispatchNumOfDefinedStoragePools; + ret_filter = (xdrproc_t) xdr_remote_num_of_defined_storage_pools_ret; + ret = (char *) &lv_remote_num_of_defined_storage_pools_ret; + memset (&lv_remote_num_of_defined_storage_pools_ret, 0, sizeof lv_remote_num_of_defined_storage_pools_ret); + break; case REMOTE_PROC_NUM_OF_DOMAINS: fn = (dispatch_fn) remoteDispatchNumOfDomains; ret_filter = (xdrproc_t) xdr_remote_num_of_domains_ret; @@ -467,11 +491,188 @@ case REMOTE_PROC_NUM_OF_NETWORKS: ret = (char *) &lv_remote_num_of_networks_ret; memset (&lv_remote_num_of_networks_ret, 0, sizeof lv_remote_num_of_networks_ret); break; +case REMOTE_PROC_NUM_OF_STORAGE_POOLS: + fn = (dispatch_fn) remoteDispatchNumOfStoragePools; + ret_filter = (xdrproc_t) xdr_remote_num_of_storage_pools_ret; + ret = (char *) &lv_remote_num_of_storage_pools_ret; + memset (&lv_remote_num_of_storage_pools_ret, 0, sizeof lv_remote_num_of_storage_pools_ret); + break; case REMOTE_PROC_OPEN: fn = (dispatch_fn) remoteDispatchOpen; args_filter = (xdrproc_t) xdr_remote_open_args; args = (char *) &lv_remote_open_args; memset (&lv_remote_open_args, 0, sizeof lv_remote_open_args); + break; +case REMOTE_PROC_STORAGE_POOL_CREATE: + fn = (dispatch_fn) remoteDispatchStoragePoolCreate; + args_filter = (xdrproc_t) xdr_remote_storage_pool_create_args; + args = (char *) &lv_remote_storage_pool_create_args; + memset (&lv_remote_storage_pool_create_args, 0, sizeof lv_remote_storage_pool_create_args); + break; +case REMOTE_PROC_STORAGE_POOL_CREATE_XML: + fn = (dispatch_fn) remoteDispatchStoragePoolCreateXml; + args_filter = (xdrproc_t) xdr_remote_storage_pool_create_xml_args; + args = (char *) &lv_remote_storage_pool_create_xml_args; + memset (&lv_remote_storage_pool_create_xml_args, 0, sizeof lv_remote_storage_pool_create_xml_args); + ret_filter = (xdrproc_t) xdr_remote_storage_pool_create_xml_ret; + ret = (char *) &lv_remote_storage_pool_create_xml_ret; + memset (&lv_remote_storage_pool_create_xml_ret, 0, sizeof lv_remote_storage_pool_create_xml_ret); + break; +case REMOTE_PROC_STORAGE_POOL_DEFINE_XML: + fn = (dispatch_fn) remoteDispatchStoragePoolDefineXml; + args_filter = (xdrproc_t) xdr_remote_storage_pool_define_xml_args; + args = (char *) &lv_remote_storage_pool_define_xml_args; + memset (&lv_remote_storage_pool_define_xml_args, 0, sizeof lv_remote_storage_pool_define_xml_args); + ret_filter = (xdrproc_t) xdr_remote_storage_pool_define_xml_ret; + ret = (char *) &lv_remote_storage_pool_define_xml_ret; + memset (&lv_remote_storage_pool_define_xml_ret, 0, sizeof lv_remote_storage_pool_define_xml_ret); + break; +case REMOTE_PROC_STORAGE_POOL_DESTROY: + fn = (dispatch_fn) remoteDispatchStoragePoolDestroy; + args_filter = (xdrproc_t) xdr_remote_storage_pool_destroy_args; + args = (char *) &lv_remote_storage_pool_destroy_args; + memset (&lv_remote_storage_pool_destroy_args, 0, sizeof lv_remote_storage_pool_destroy_args); + break; +case REMOTE_PROC_STORAGE_POOL_DUMP_XML: + fn = (dispatch_fn) remoteDispatchStoragePoolDumpXml; + args_filter = (xdrproc_t) xdr_remote_storage_pool_dump_xml_args; + args = (char *) &lv_remote_storage_pool_dump_xml_args; + memset (&lv_remote_storage_pool_dump_xml_args, 0, sizeof lv_remote_storage_pool_dump_xml_args); + ret_filter = (xdrproc_t) xdr_remote_storage_pool_dump_xml_ret; + ret = (char *) &lv_remote_storage_pool_dump_xml_ret; + memset (&lv_remote_storage_pool_dump_xml_ret, 0, sizeof lv_remote_storage_pool_dump_xml_ret); + break; +case REMOTE_PROC_STORAGE_POOL_GET_AUTOSTART: + fn = (dispatch_fn) remoteDispatchStoragePoolGetAutostart; + args_filter = (xdrproc_t) xdr_remote_storage_pool_get_autostart_args; + args = (char *) &lv_remote_storage_pool_get_autostart_args; + memset (&lv_remote_storage_pool_get_autostart_args, 0, sizeof lv_remote_storage_pool_get_autostart_args); + ret_filter = (xdrproc_t) xdr_remote_storage_pool_get_autostart_ret; + ret = (char *) &lv_remote_storage_pool_get_autostart_ret; + memset (&lv_remote_storage_pool_get_autostart_ret, 0, sizeof lv_remote_storage_pool_get_autostart_ret); + break; +case REMOTE_PROC_STORAGE_POOL_GET_INFO: + fn = (dispatch_fn) remoteDispatchStoragePoolGetInfo; + args_filter = (xdrproc_t) xdr_remote_storage_pool_get_info_args; + args = (char *) &lv_remote_storage_pool_get_info_args; + memset (&lv_remote_storage_pool_get_info_args, 0, sizeof lv_remote_storage_pool_get_info_args); + ret_filter = (xdrproc_t) xdr_remote_storage_pool_get_info_ret; + ret = (char *) &lv_remote_storage_pool_get_info_ret; + memset (&lv_remote_storage_pool_get_info_ret, 0, sizeof lv_remote_storage_pool_get_info_ret); + break; +case REMOTE_PROC_STORAGE_POOL_LIST_VOLUMES: + fn = (dispatch_fn) remoteDispatchStoragePoolListVolumes; + args_filter = (xdrproc_t) xdr_remote_storage_pool_list_volumes_args; + args = (char *) &lv_remote_storage_pool_list_volumes_args; + memset (&lv_remote_storage_pool_list_volumes_args, 0, sizeof lv_remote_storage_pool_list_volumes_args); + ret_filter = (xdrproc_t) xdr_remote_storage_pool_list_volumes_ret; + ret = (char *) &lv_remote_storage_pool_list_volumes_ret; + memset (&lv_remote_storage_pool_list_volumes_ret, 0, sizeof lv_remote_storage_pool_list_volumes_ret); + break; +case REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_NAME: + fn = (dispatch_fn) remoteDispatchStoragePoolLookupByName; + args_filter = (xdrproc_t) xdr_remote_storage_pool_lookup_by_name_args; + args = (char *) &lv_remote_storage_pool_lookup_by_name_args; + memset (&lv_remote_storage_pool_lookup_by_name_args, 0, sizeof lv_remote_storage_pool_lookup_by_name_args); + ret_filter = (xdrproc_t) xdr_remote_storage_pool_lookup_by_name_ret; + ret = (char *) &lv_remote_storage_pool_lookup_by_name_ret; + memset (&lv_remote_storage_pool_lookup_by_name_ret, 0, sizeof lv_remote_storage_pool_lookup_by_name_ret); + break; +case REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_UUID: + fn = (dispatch_fn) remoteDispatchStoragePoolLookupByUuid; + args_filter = (xdrproc_t) xdr_remote_storage_pool_lookup_by_uuid_args; + args = (char *) &lv_remote_storage_pool_lookup_by_uuid_args; + memset (&lv_remote_storage_pool_lookup_by_uuid_args, 0, sizeof lv_remote_storage_pool_lookup_by_uuid_args); + ret_filter = (xdrproc_t) xdr_remote_storage_pool_lookup_by_uuid_ret; + ret = (char *) &lv_remote_storage_pool_lookup_by_uuid_ret; + memset (&lv_remote_storage_pool_lookup_by_uuid_ret, 0, sizeof lv_remote_storage_pool_lookup_by_uuid_ret); + break; +case REMOTE_PROC_STORAGE_POOL_NUM_OF_VOLUMES: + fn = (dispatch_fn) remoteDispatchStoragePoolNumOfVolumes; + args_filter = (xdrproc_t) xdr_remote_storage_pool_num_of_volumes_args; + args = (char *) &lv_remote_storage_pool_num_of_volumes_args; + memset (&lv_remote_storage_pool_num_of_volumes_args, 0, sizeof lv_remote_storage_pool_num_of_volumes_args); + ret_filter = (xdrproc_t) xdr_remote_storage_pool_num_of_volumes_ret; + ret = (char *) &lv_remote_storage_pool_num_of_volumes_ret; + memset (&lv_remote_storage_pool_num_of_volumes_ret, 0, sizeof lv_remote_storage_pool_num_of_volumes_ret); + break; +case REMOTE_PROC_STORAGE_POOL_SET_AUTOSTART: + fn = (dispatch_fn) remoteDispatchStoragePoolSetAutostart; + args_filter = (xdrproc_t) xdr_remote_storage_pool_set_autostart_args; + args = (char *) &lv_remote_storage_pool_set_autostart_args; + memset (&lv_remote_storage_pool_set_autostart_args, 0, sizeof lv_remote_storage_pool_set_autostart_args); + break; +case REMOTE_PROC_STORAGE_POOL_SHUTDOWN: + fn = (dispatch_fn) remoteDispatchStoragePoolShutdown; + args_filter = (xdrproc_t) xdr_remote_storage_pool_shutdown_args; + args = (char *) &lv_remote_storage_pool_shutdown_args; + memset (&lv_remote_storage_pool_shutdown_args, 0, sizeof lv_remote_storage_pool_shutdown_args); + break; +case REMOTE_PROC_STORAGE_POOL_UNDEFINE: + fn = (dispatch_fn) remoteDispatchStoragePoolUndefine; + args_filter = (xdrproc_t) xdr_remote_storage_pool_undefine_args; + args = (char *) &lv_remote_storage_pool_undefine_args; + memset (&lv_remote_storage_pool_undefine_args, 0, sizeof lv_remote_storage_pool_undefine_args); + break; +case REMOTE_PROC_STORAGE_VOL_CREATE_XML: + fn = (dispatch_fn) remoteDispatchStorageVolCreateXml; + args_filter = (xdrproc_t) xdr_remote_storage_vol_create_xml_args; + args = (char *) &lv_remote_storage_vol_create_xml_args; + memset (&lv_remote_storage_vol_create_xml_args, 0, sizeof lv_remote_storage_vol_create_xml_args); + ret_filter = (xdrproc_t) xdr_remote_storage_vol_create_xml_ret; + ret = (char *) &lv_remote_storage_vol_create_xml_ret; + memset (&lv_remote_storage_vol_create_xml_ret, 0, sizeof lv_remote_storage_vol_create_xml_ret); + break; +case REMOTE_PROC_STORAGE_VOL_DESTROY: + fn = (dispatch_fn) remoteDispatchStorageVolDestroy; + args_filter = (xdrproc_t) xdr_remote_storage_vol_destroy_args; + args = (char *) &lv_remote_storage_vol_destroy_args; + memset (&lv_remote_storage_vol_destroy_args, 0, sizeof lv_remote_storage_vol_destroy_args); + break; +case REMOTE_PROC_STORAGE_VOL_DUMP_XML: + fn = (dispatch_fn) remoteDispatchStorageVolDumpXml; + args_filter = (xdrproc_t) xdr_remote_storage_vol_dump_xml_args; + args = (char *) &lv_remote_storage_vol_dump_xml_args; + memset (&lv_remote_storage_vol_dump_xml_args, 0, sizeof lv_remote_storage_vol_dump_xml_args); + ret_filter = (xdrproc_t) xdr_remote_storage_vol_dump_xml_ret; + ret = (char *) &lv_remote_storage_vol_dump_xml_ret; + memset (&lv_remote_storage_vol_dump_xml_ret, 0, sizeof lv_remote_storage_vol_dump_xml_ret); + break; +case REMOTE_PROC_STORAGE_VOL_GET_INFO: + fn = (dispatch_fn) remoteDispatchStorageVolGetInfo; + args_filter = (xdrproc_t) xdr_remote_storage_vol_get_info_args; + args = (char *) &lv_remote_storage_vol_get_info_args; + memset (&lv_remote_storage_vol_get_info_args, 0, sizeof lv_remote_storage_vol_get_info_args); + ret_filter = (xdrproc_t) xdr_remote_storage_vol_get_info_ret; + ret = (char *) &lv_remote_storage_vol_get_info_ret; + memset (&lv_remote_storage_vol_get_info_ret, 0, sizeof lv_remote_storage_vol_get_info_ret); + break; +case REMOTE_PROC_STORAGE_VOL_GET_PATH: + fn = (dispatch_fn) remoteDispatchStorageVolGetPath; + args_filter = (xdrproc_t) xdr_remote_storage_vol_get_path_args; + args = (char *) &lv_remote_storage_vol_get_path_args; + memset (&lv_remote_storage_vol_get_path_args, 0, sizeof lv_remote_storage_vol_get_path_args); + ret_filter = (xdrproc_t) xdr_remote_storage_vol_get_path_ret; + ret = (char *) &lv_remote_storage_vol_get_path_ret; + memset (&lv_remote_storage_vol_get_path_ret, 0, sizeof lv_remote_storage_vol_get_path_ret); + break; +case REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_NAME: + fn = (dispatch_fn) remoteDispatchStorageVolLookupByName; + args_filter = (xdrproc_t) xdr_remote_storage_vol_lookup_by_name_args; + args = (char *) &lv_remote_storage_vol_lookup_by_name_args; + memset (&lv_remote_storage_vol_lookup_by_name_args, 0, sizeof lv_remote_storage_vol_lookup_by_name_args); + ret_filter = (xdrproc_t) xdr_remote_storage_vol_lookup_by_name_ret; + ret = (char *) &lv_remote_storage_vol_lookup_by_name_ret; + memset (&lv_remote_storage_vol_lookup_by_name_ret, 0, sizeof lv_remote_storage_vol_lookup_by_name_ret); + break; +case REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_UUID: + fn = (dispatch_fn) remoteDispatchStorageVolLookupByUuid; + args_filter = (xdrproc_t) xdr_remote_storage_vol_lookup_by_uuid_args; + args = (char *) &lv_remote_storage_vol_lookup_by_uuid_args; + memset (&lv_remote_storage_vol_lookup_by_uuid_args, 0, sizeof lv_remote_storage_vol_lookup_by_uuid_args); + ret_filter = (xdrproc_t) xdr_remote_storage_vol_lookup_by_uuid_ret; + ret = (char *) &lv_remote_storage_vol_lookup_by_uuid_ret; + memset (&lv_remote_storage_vol_lookup_by_uuid_ret, 0, sizeof lv_remote_storage_vol_lookup_by_uuid_ret); break; case REMOTE_PROC_SUPPORTS_FEATURE: fn = (dispatch_fn) remoteDispatchSupportsFeature; diff -r 89d154031d13 qemud/remote_dispatch_prototypes.h --- a/qemud/remote_dispatch_prototypes.h Sat Oct 27 17:52:41 2007 -0400 +++ b/qemud/remote_dispatch_prototypes.h Sat Oct 27 17:55:07 2007 -0400 @@ -47,8 +47,10 @@ static int remoteDispatchGetVersion (str static int remoteDispatchGetVersion (struct qemud_client *client, remote_message_header *req, void *args, remote_get_version_ret *ret); static int remoteDispatchListDefinedDomains (struct qemud_client *client, remote_message_header *req, remote_list_defined_domains_args *args, remote_list_defined_domains_ret *ret); static int remoteDispatchListDefinedNetworks (struct qemud_client *client, remote_message_header *req, remote_list_defined_networks_args *args, remote_list_defined_networks_ret *ret); +static int remoteDispatchListDefinedStoragePools (struct qemud_client *client, remote_message_header *req, remote_list_defined_storage_pools_args *args, remote_list_defined_storage_pools_ret *ret); static int remoteDispatchListDomains (struct qemud_client *client, remote_message_header *req, remote_list_domains_args *args, remote_list_domains_ret *ret); static int remoteDispatchListNetworks (struct qemud_client *client, remote_message_header *req, remote_list_networks_args *args, remote_list_networks_ret *ret); +static int remoteDispatchListStoragePools (struct qemud_client *client, remote_message_header *req, remote_list_storage_pools_args *args, remote_list_storage_pools_ret *ret); static int remoteDispatchNetworkCreate (struct qemud_client *client, remote_message_header *req, remote_network_create_args *args, void *ret); static int remoteDispatchNetworkCreateXml (struct qemud_client *client, remote_message_header *req, remote_network_create_xml_args *args, remote_network_create_xml_ret *ret); static int remoteDispatchNetworkDefineXml (struct qemud_client *client, remote_message_header *req, remote_network_define_xml_args *args, remote_network_define_xml_ret *ret); @@ -63,7 +65,30 @@ static int remoteDispatchNodeGetInfo (st static int remoteDispatchNodeGetInfo (struct qemud_client *client, remote_message_header *req, void *args, remote_node_get_info_ret *ret); static int remoteDispatchNumOfDefinedDomains (struct qemud_client *client, remote_message_header *req, void *args, remote_num_of_defined_domains_ret *ret); static int remoteDispatchNumOfDefinedNetworks (struct qemud_client *client, remote_message_header *req, void *args, remote_num_of_defined_networks_ret *ret); +static int remoteDispatchNumOfDefinedStoragePools (struct qemud_client *client, remote_message_header *req, void *args, remote_num_of_defined_storage_pools_ret *ret); static int remoteDispatchNumOfDomains (struct qemud_client *client, remote_message_header *req, void *args, remote_num_of_domains_ret *ret); static int remoteDispatchNumOfNetworks (struct qemud_client *client, remote_message_header *req, void *args, remote_num_of_networks_ret *ret); +static int remoteDispatchNumOfStoragePools (struct qemud_client *client, remote_message_header *req, void *args, remote_num_of_storage_pools_ret *ret); static int remoteDispatchOpen (struct qemud_client *client, remote_message_header *req, remote_open_args *args, void *ret); +static int remoteDispatchStoragePoolCreate (struct qemud_client *client, remote_message_header *req, remote_storage_pool_create_args *args, void *ret); +static int remoteDispatchStoragePoolCreateXml (struct qemud_client *client, remote_message_header *req, remote_storage_pool_create_xml_args *args, remote_storage_pool_create_xml_ret *ret); +static int remoteDispatchStoragePoolDefineXml (struct qemud_client *client, remote_message_header *req, remote_storage_pool_define_xml_args *args, remote_storage_pool_define_xml_ret *ret); +static int remoteDispatchStoragePoolDestroy (struct qemud_client *client, remote_message_header *req, remote_storage_pool_destroy_args *args, void *ret); +static int remoteDispatchStoragePoolDumpXml (struct qemud_client *client, remote_message_header *req, remote_storage_pool_dump_xml_args *args, remote_storage_pool_dump_xml_ret *ret); +static int remoteDispatchStoragePoolGetAutostart (struct qemud_client *client, remote_message_header *req, remote_storage_pool_get_autostart_args *args, remote_storage_pool_get_autostart_ret *ret); +static int remoteDispatchStoragePoolGetInfo (struct qemud_client *client, remote_message_header *req, remote_storage_pool_get_info_args *args, remote_storage_pool_get_info_ret *ret); +static int remoteDispatchStoragePoolListVolumes (struct qemud_client *client, remote_message_header *req, remote_storage_pool_list_volumes_args *args, remote_storage_pool_list_volumes_ret *ret); +static int remoteDispatchStoragePoolLookupByName (struct qemud_client *client, remote_message_header *req, remote_storage_pool_lookup_by_name_args *args, remote_storage_pool_lookup_by_name_ret *ret); +static int remoteDispatchStoragePoolLookupByUuid (struct qemud_client *client, remote_message_header *req, remote_storage_pool_lookup_by_uuid_args *args, remote_storage_pool_lookup_by_uuid_ret *ret); +static int remoteDispatchStoragePoolNumOfVolumes (struct qemud_client *client, remote_message_header *req, remote_storage_pool_num_of_volumes_args *args, remote_storage_pool_num_of_volumes_ret *ret); +static int remoteDispatchStoragePoolSetAutostart (struct qemud_client *client, remote_message_header *req, remote_storage_pool_set_autostart_args *args, void *ret); +static int remoteDispatchStoragePoolShutdown (struct qemud_client *client, remote_message_header *req, remote_storage_pool_shutdown_args *args, void *ret); +static int remoteDispatchStoragePoolUndefine (struct qemud_client *client, remote_message_header *req, remote_storage_pool_undefine_args *args, void *ret); +static int remoteDispatchStorageVolCreateXml (struct qemud_client *client, remote_message_header *req, remote_storage_vol_create_xml_args *args, remote_storage_vol_create_xml_ret *ret); +static int remoteDispatchStorageVolDestroy (struct qemud_client *client, remote_message_header *req, remote_storage_vol_destroy_args *args, void *ret); +static int remoteDispatchStorageVolDumpXml (struct qemud_client *client, remote_message_header *req, remote_storage_vol_dump_xml_args *args, remote_storage_vol_dump_xml_ret *ret); +static int remoteDispatchStorageVolGetInfo (struct qemud_client *client, remote_message_header *req, remote_storage_vol_get_info_args *args, remote_storage_vol_get_info_ret *ret); +static int remoteDispatchStorageVolGetPath (struct qemud_client *client, remote_message_header *req, remote_storage_vol_get_path_args *args, remote_storage_vol_get_path_ret *ret); +static int remoteDispatchStorageVolLookupByName (struct qemud_client *client, remote_message_header *req, remote_storage_vol_lookup_by_name_args *args, remote_storage_vol_lookup_by_name_ret *ret); +static int remoteDispatchStorageVolLookupByUuid (struct qemud_client *client, remote_message_header *req, remote_storage_vol_lookup_by_uuid_args *args, remote_storage_vol_lookup_by_uuid_ret *ret); static int remoteDispatchSupportsFeature (struct qemud_client *client, remote_message_header *req, remote_supports_feature_args *args, remote_supports_feature_ret *ret); diff -r 89d154031d13 qemud/remote_protocol.c --- a/qemud/remote_protocol.c Sat Oct 27 17:52:41 2007 -0400 +++ b/qemud/remote_protocol.c Sat Oct 27 17:55:07 2007 -0400 @@ -58,6 +58,30 @@ xdr_remote_nonnull_network (XDR *xdrs, r } bool_t +xdr_remote_nonnull_storage_pool (XDR *xdrs, remote_nonnull_storage_pool *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->name)) + return FALSE; + if (!xdr_remote_uuid (xdrs, objp->uuid)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_nonnull_storage_vol (XDR *xdrs, remote_nonnull_storage_vol *objp) +{ + + if (!xdr_remote_nonnull_storage_pool (xdrs, &objp->pool)) + return FALSE; + if (!xdr_remote_nonnull_string (xdrs, &objp->name)) + return FALSE; + if (!xdr_remote_uuid (xdrs, objp->uuid)) + return FALSE; + return TRUE; +} + +bool_t xdr_remote_domain (XDR *xdrs, remote_domain *objp) { @@ -71,6 +95,24 @@ xdr_remote_network (XDR *xdrs, remote_ne { if (!xdr_pointer (xdrs, (char **)objp, sizeof (remote_nonnull_network), (xdrproc_t) xdr_remote_nonnull_network)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool (XDR *xdrs, remote_storage_pool *objp) +{ + + if (!xdr_pointer (xdrs, (char **)objp, sizeof (remote_nonnull_storage_pool), (xdrproc_t) xdr_remote_nonnull_storage_pool)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_vol (XDR *xdrs, remote_storage_vol *objp) +{ + + if (!xdr_pointer (xdrs, (char **)objp, sizeof (remote_nonnull_storage_vol), (xdrproc_t) xdr_remote_nonnull_storage_vol)) return FALSE; return TRUE; } @@ -1222,6 +1264,414 @@ xdr_remote_network_set_autostart_args (X } bool_t +xdr_remote_num_of_storage_pools_ret (XDR *xdrs, remote_num_of_storage_pools_ret *objp) +{ + + if (!xdr_int (xdrs, &objp->num)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_list_storage_pools_args (XDR *xdrs, remote_list_storage_pools_args *objp) +{ + + if (!xdr_int (xdrs, &objp->maxnames)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_list_storage_pools_ret (XDR *xdrs, remote_list_storage_pools_ret *objp) +{ + char **objp_cpp0 = (char **) (void *) &objp->names.names_val; + + if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->names.names_len, REMOTE_STORAGE_POOL_NAME_LIST_MAX, + sizeof (remote_nonnull_string), (xdrproc_t) xdr_remote_nonnull_string)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_num_of_defined_storage_pools_ret (XDR *xdrs, remote_num_of_defined_storage_pools_ret *objp) +{ + + if (!xdr_int (xdrs, &objp->num)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_list_defined_storage_pools_args (XDR *xdrs, remote_list_defined_storage_pools_args *objp) +{ + + if (!xdr_int (xdrs, &objp->maxnames)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_list_defined_storage_pools_ret (XDR *xdrs, remote_list_defined_storage_pools_ret *objp) +{ + char **objp_cpp0 = (char **) (void *) &objp->names.names_val; + + if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->names.names_len, REMOTE_STORAGE_POOL_NAME_LIST_MAX, + sizeof (remote_nonnull_string), (xdrproc_t) xdr_remote_nonnull_string)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool_lookup_by_uuid_args (XDR *xdrs, remote_storage_pool_lookup_by_uuid_args *objp) +{ + + if (!xdr_remote_uuid (xdrs, objp->uuid)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool_lookup_by_uuid_ret (XDR *xdrs, remote_storage_pool_lookup_by_uuid_ret *objp) +{ + + if (!xdr_remote_nonnull_storage_pool (xdrs, &objp->pool)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool_lookup_by_name_args (XDR *xdrs, remote_storage_pool_lookup_by_name_args *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->name)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool_lookup_by_name_ret (XDR *xdrs, remote_storage_pool_lookup_by_name_ret *objp) +{ + + if (!xdr_remote_nonnull_storage_pool (xdrs, &objp->pool)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool_create_xml_args (XDR *xdrs, remote_storage_pool_create_xml_args *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->xml)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool_create_xml_ret (XDR *xdrs, remote_storage_pool_create_xml_ret *objp) +{ + + if (!xdr_remote_nonnull_storage_pool (xdrs, &objp->pool)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool_define_xml_args (XDR *xdrs, remote_storage_pool_define_xml_args *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->xml)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool_define_xml_ret (XDR *xdrs, remote_storage_pool_define_xml_ret *objp) +{ + + if (!xdr_remote_nonnull_storage_pool (xdrs, &objp->pool)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool_undefine_args (XDR *xdrs, remote_storage_pool_undefine_args *objp) +{ + + if (!xdr_remote_nonnull_storage_pool (xdrs, &objp->pool)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool_create_args (XDR *xdrs, remote_storage_pool_create_args *objp) +{ + + if (!xdr_remote_nonnull_storage_pool (xdrs, &objp->pool)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool_shutdown_args (XDR *xdrs, remote_storage_pool_shutdown_args *objp) +{ + + if (!xdr_remote_nonnull_storage_pool (xdrs, &objp->pool)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool_destroy_args (XDR *xdrs, remote_storage_pool_destroy_args *objp) +{ + + if (!xdr_remote_nonnull_storage_pool (xdrs, &objp->pool)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool_dump_xml_args (XDR *xdrs, remote_storage_pool_dump_xml_args *objp) +{ + + if (!xdr_remote_nonnull_storage_pool (xdrs, &objp->pool)) + return FALSE; + if (!xdr_int (xdrs, &objp->flags)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool_dump_xml_ret (XDR *xdrs, remote_storage_pool_dump_xml_ret *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->xml)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool_get_info_args (XDR *xdrs, remote_storage_pool_get_info_args *objp) +{ + + if (!xdr_remote_nonnull_storage_pool (xdrs, &objp->pool)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool_get_info_ret (XDR *xdrs, remote_storage_pool_get_info_ret *objp) +{ + + if (!xdr_u_char (xdrs, &objp->state)) + return FALSE; + if (!xdr_u_quad_t (xdrs, &objp->capacity)) + return FALSE; + if (!xdr_u_quad_t (xdrs, &objp->allocation)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool_get_autostart_args (XDR *xdrs, remote_storage_pool_get_autostart_args *objp) +{ + + if (!xdr_remote_nonnull_storage_pool (xdrs, &objp->pool)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool_get_autostart_ret (XDR *xdrs, remote_storage_pool_get_autostart_ret *objp) +{ + + if (!xdr_int (xdrs, &objp->autostart)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool_set_autostart_args (XDR *xdrs, remote_storage_pool_set_autostart_args *objp) +{ + + if (!xdr_remote_nonnull_storage_pool (xdrs, &objp->pool)) + return FALSE; + if (!xdr_int (xdrs, &objp->autostart)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool_num_of_volumes_args (XDR *xdrs, remote_storage_pool_num_of_volumes_args *objp) +{ + + if (!xdr_remote_nonnull_storage_pool (xdrs, &objp->pool)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool_num_of_volumes_ret (XDR *xdrs, remote_storage_pool_num_of_volumes_ret *objp) +{ + + if (!xdr_int (xdrs, &objp->num)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool_list_volumes_args (XDR *xdrs, remote_storage_pool_list_volumes_args *objp) +{ + + if (!xdr_remote_nonnull_storage_pool (xdrs, &objp->pool)) + return FALSE; + if (!xdr_int (xdrs, &objp->maxnames)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_pool_list_volumes_ret (XDR *xdrs, remote_storage_pool_list_volumes_ret *objp) +{ + char **objp_cpp0 = (char **) (void *) &objp->names.names_val; + + if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->names.names_len, REMOTE_STORAGE_VOL_NAME_LIST_MAX, + sizeof (remote_nonnull_string), (xdrproc_t) xdr_remote_nonnull_string)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_vol_lookup_by_uuid_args (XDR *xdrs, remote_storage_vol_lookup_by_uuid_args *objp) +{ + + if (!xdr_remote_nonnull_storage_pool (xdrs, &objp->pool)) + return FALSE; + if (!xdr_remote_uuid (xdrs, objp->uuid)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_vol_lookup_by_uuid_ret (XDR *xdrs, remote_storage_vol_lookup_by_uuid_ret *objp) +{ + + if (!xdr_remote_nonnull_storage_vol (xdrs, &objp->vol)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_vol_lookup_by_name_args (XDR *xdrs, remote_storage_vol_lookup_by_name_args *objp) +{ + + if (!xdr_remote_nonnull_storage_pool (xdrs, &objp->pool)) + return FALSE; + if (!xdr_remote_nonnull_string (xdrs, &objp->name)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_vol_lookup_by_name_ret (XDR *xdrs, remote_storage_vol_lookup_by_name_ret *objp) +{ + + if (!xdr_remote_nonnull_storage_vol (xdrs, &objp->vol)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_vol_create_xml_args (XDR *xdrs, remote_storage_vol_create_xml_args *objp) +{ + + if (!xdr_remote_nonnull_storage_pool (xdrs, &objp->pool)) + return FALSE; + if (!xdr_remote_nonnull_string (xdrs, &objp->xml)) + return FALSE; + if (!xdr_int (xdrs, &objp->flags)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_vol_create_xml_ret (XDR *xdrs, remote_storage_vol_create_xml_ret *objp) +{ + + if (!xdr_remote_nonnull_storage_vol (xdrs, &objp->vol)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_vol_destroy_args (XDR *xdrs, remote_storage_vol_destroy_args *objp) +{ + + if (!xdr_remote_nonnull_storage_vol (xdrs, &objp->vol)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_vol_dump_xml_args (XDR *xdrs, remote_storage_vol_dump_xml_args *objp) +{ + + if (!xdr_remote_nonnull_storage_vol (xdrs, &objp->vol)) + return FALSE; + if (!xdr_int (xdrs, &objp->flags)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_vol_dump_xml_ret (XDR *xdrs, remote_storage_vol_dump_xml_ret *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->xml)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_vol_get_info_args (XDR *xdrs, remote_storage_vol_get_info_args *objp) +{ + + if (!xdr_remote_nonnull_storage_vol (xdrs, &objp->vol)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_vol_get_info_ret (XDR *xdrs, remote_storage_vol_get_info_ret *objp) +{ + + if (!xdr_char (xdrs, &objp->type)) + return FALSE; + if (!xdr_u_quad_t (xdrs, &objp->capacity)) + return FALSE; + if (!xdr_u_quad_t (xdrs, &objp->allocation)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_vol_get_path_args (XDR *xdrs, remote_storage_vol_get_path_args *objp) +{ + + if (!xdr_remote_nonnull_storage_vol (xdrs, &objp->vol)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_storage_vol_get_path_ret (XDR *xdrs, remote_storage_vol_get_path_ret *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->name)) + return FALSE; + return TRUE; +} + +bool_t xdr_remote_procedure (XDR *xdrs, remote_procedure *objp) { diff -r 89d154031d13 qemud/remote_protocol.h --- a/qemud/remote_protocol.h Sat Oct 27 17:52:41 2007 -0400 +++ b/qemud/remote_protocol.h Sat Oct 27 17:55:06 2007 -0400 @@ -27,6 +27,8 @@ typedef remote_nonnull_string *remote_st #define REMOTE_CPUMAPS_MAX 16384 #define REMOTE_MIGRATE_COOKIE_MAX 256 #define REMOTE_NETWORK_NAME_LIST_MAX 256 +#define REMOTE_STORAGE_POOL_NAME_LIST_MAX 256 +#define REMOTE_STORAGE_VOL_NAME_LIST_MAX 1024 #define REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX 16 typedef char remote_uuid[VIR_UUID_BUFLEN]; @@ -44,9 +46,26 @@ struct remote_nonnull_network { }; typedef struct remote_nonnull_network remote_nonnull_network; +struct remote_nonnull_storage_pool { + remote_nonnull_string name; + remote_uuid uuid; +}; +typedef struct remote_nonnull_storage_pool remote_nonnull_storage_pool; + +struct remote_nonnull_storage_vol { + remote_nonnull_storage_pool pool; + remote_nonnull_string name; + remote_uuid uuid; +}; +typedef struct remote_nonnull_storage_vol remote_nonnull_storage_vol; + typedef remote_nonnull_domain *remote_domain; typedef remote_nonnull_network *remote_network; + +typedef remote_nonnull_storage_pool *remote_storage_pool; + +typedef remote_nonnull_storage_vol *remote_storage_vol; struct remote_error { int code; @@ -659,6 +678,237 @@ struct remote_network_set_autostart_args int autostart; }; typedef struct remote_network_set_autostart_args remote_network_set_autostart_args; + +struct remote_num_of_storage_pools_ret { + int num; +}; +typedef struct remote_num_of_storage_pools_ret remote_num_of_storage_pools_ret; + +struct remote_list_storage_pools_args { + int maxnames; +}; +typedef struct remote_list_storage_pools_args remote_list_storage_pools_args; + +struct remote_list_storage_pools_ret { + struct { + u_int names_len; + remote_nonnull_string *names_val; + } names; +}; +typedef struct remote_list_storage_pools_ret remote_list_storage_pools_ret; + +struct remote_num_of_defined_storage_pools_ret { + int num; +}; +typedef struct remote_num_of_defined_storage_pools_ret remote_num_of_defined_storage_pools_ret; + +struct remote_list_defined_storage_pools_args { + int maxnames; +}; +typedef struct remote_list_defined_storage_pools_args remote_list_defined_storage_pools_args; + +struct remote_list_defined_storage_pools_ret { + struct { + u_int names_len; + remote_nonnull_string *names_val; + } names; +}; +typedef struct remote_list_defined_storage_pools_ret remote_list_defined_storage_pools_ret; + +struct remote_storage_pool_lookup_by_uuid_args { + remote_uuid uuid; +}; +typedef struct remote_storage_pool_lookup_by_uuid_args remote_storage_pool_lookup_by_uuid_args; + +struct remote_storage_pool_lookup_by_uuid_ret { + remote_nonnull_storage_pool pool; +}; +typedef struct remote_storage_pool_lookup_by_uuid_ret remote_storage_pool_lookup_by_uuid_ret; + +struct remote_storage_pool_lookup_by_name_args { + remote_nonnull_string name; +}; +typedef struct remote_storage_pool_lookup_by_name_args remote_storage_pool_lookup_by_name_args; + +struct remote_storage_pool_lookup_by_name_ret { + remote_nonnull_storage_pool pool; +}; +typedef struct remote_storage_pool_lookup_by_name_ret remote_storage_pool_lookup_by_name_ret; + +struct remote_storage_pool_create_xml_args { + remote_nonnull_string xml; +}; +typedef struct remote_storage_pool_create_xml_args remote_storage_pool_create_xml_args; + +struct remote_storage_pool_create_xml_ret { + remote_nonnull_storage_pool pool; +}; +typedef struct remote_storage_pool_create_xml_ret remote_storage_pool_create_xml_ret; + +struct remote_storage_pool_define_xml_args { + remote_nonnull_string xml; +}; +typedef struct remote_storage_pool_define_xml_args remote_storage_pool_define_xml_args; + +struct remote_storage_pool_define_xml_ret { + remote_nonnull_storage_pool pool; +}; +typedef struct remote_storage_pool_define_xml_ret remote_storage_pool_define_xml_ret; + +struct remote_storage_pool_undefine_args { + remote_nonnull_storage_pool pool; +}; +typedef struct remote_storage_pool_undefine_args remote_storage_pool_undefine_args; + +struct remote_storage_pool_create_args { + remote_nonnull_storage_pool pool; +}; +typedef struct remote_storage_pool_create_args remote_storage_pool_create_args; + +struct remote_storage_pool_shutdown_args { + remote_nonnull_storage_pool pool; +}; +typedef struct remote_storage_pool_shutdown_args remote_storage_pool_shutdown_args; + +struct remote_storage_pool_destroy_args { + remote_nonnull_storage_pool pool; +}; +typedef struct remote_storage_pool_destroy_args remote_storage_pool_destroy_args; + +struct remote_storage_pool_dump_xml_args { + remote_nonnull_storage_pool pool; + int flags; +}; +typedef struct remote_storage_pool_dump_xml_args remote_storage_pool_dump_xml_args; + +struct remote_storage_pool_dump_xml_ret { + remote_nonnull_string xml; +}; +typedef struct remote_storage_pool_dump_xml_ret remote_storage_pool_dump_xml_ret; + +struct remote_storage_pool_get_info_args { + remote_nonnull_storage_pool pool; +}; +typedef struct remote_storage_pool_get_info_args remote_storage_pool_get_info_args; + +struct remote_storage_pool_get_info_ret { + u_char state; + u_quad_t capacity; + u_quad_t allocation; +}; +typedef struct remote_storage_pool_get_info_ret remote_storage_pool_get_info_ret; + +struct remote_storage_pool_get_autostart_args { + remote_nonnull_storage_pool pool; +}; +typedef struct remote_storage_pool_get_autostart_args remote_storage_pool_get_autostart_args; + +struct remote_storage_pool_get_autostart_ret { + int autostart; +}; +typedef struct remote_storage_pool_get_autostart_ret remote_storage_pool_get_autostart_ret; + +struct remote_storage_pool_set_autostart_args { + remote_nonnull_storage_pool pool; + int autostart; +}; +typedef struct remote_storage_pool_set_autostart_args remote_storage_pool_set_autostart_args; + +struct remote_storage_pool_num_of_volumes_args { + remote_nonnull_storage_pool pool; +}; +typedef struct remote_storage_pool_num_of_volumes_args remote_storage_pool_num_of_volumes_args; + +struct remote_storage_pool_num_of_volumes_ret { + int num; +}; +typedef struct remote_storage_pool_num_of_volumes_ret remote_storage_pool_num_of_volumes_ret; + +struct remote_storage_pool_list_volumes_args { + remote_nonnull_storage_pool pool; + int maxnames; +}; +typedef struct remote_storage_pool_list_volumes_args remote_storage_pool_list_volumes_args; + +struct remote_storage_pool_list_volumes_ret { + struct { + u_int names_len; + remote_nonnull_string *names_val; + } names; +}; +typedef struct remote_storage_pool_list_volumes_ret remote_storage_pool_list_volumes_ret; + +struct remote_storage_vol_lookup_by_uuid_args { + remote_nonnull_storage_pool pool; + remote_uuid uuid; +}; +typedef struct remote_storage_vol_lookup_by_uuid_args remote_storage_vol_lookup_by_uuid_args; + +struct remote_storage_vol_lookup_by_uuid_ret { + remote_nonnull_storage_vol vol; +}; +typedef struct remote_storage_vol_lookup_by_uuid_ret remote_storage_vol_lookup_by_uuid_ret; + +struct remote_storage_vol_lookup_by_name_args { + remote_nonnull_storage_pool pool; + remote_nonnull_string name; +}; +typedef struct remote_storage_vol_lookup_by_name_args remote_storage_vol_lookup_by_name_args; + +struct remote_storage_vol_lookup_by_name_ret { + remote_nonnull_storage_vol vol; +}; +typedef struct remote_storage_vol_lookup_by_name_ret remote_storage_vol_lookup_by_name_ret; + +struct remote_storage_vol_create_xml_args { + remote_nonnull_storage_pool pool; + remote_nonnull_string xml; + int flags; +}; +typedef struct remote_storage_vol_create_xml_args remote_storage_vol_create_xml_args; + +struct remote_storage_vol_create_xml_ret { + remote_nonnull_storage_vol vol; +}; +typedef struct remote_storage_vol_create_xml_ret remote_storage_vol_create_xml_ret; + +struct remote_storage_vol_destroy_args { + remote_nonnull_storage_vol vol; +}; +typedef struct remote_storage_vol_destroy_args remote_storage_vol_destroy_args; + +struct remote_storage_vol_dump_xml_args { + remote_nonnull_storage_vol vol; + int flags; +}; +typedef struct remote_storage_vol_dump_xml_args remote_storage_vol_dump_xml_args; + +struct remote_storage_vol_dump_xml_ret { + remote_nonnull_string xml; +}; +typedef struct remote_storage_vol_dump_xml_ret remote_storage_vol_dump_xml_ret; + +struct remote_storage_vol_get_info_args { + remote_nonnull_storage_vol vol; +}; +typedef struct remote_storage_vol_get_info_args remote_storage_vol_get_info_args; + +struct remote_storage_vol_get_info_ret { + char type; + u_quad_t capacity; + u_quad_t allocation; +}; +typedef struct remote_storage_vol_get_info_ret remote_storage_vol_get_info_ret; + +struct remote_storage_vol_get_path_args { + remote_nonnull_storage_vol vol; +}; +typedef struct remote_storage_vol_get_path_args remote_storage_vol_get_path_args; + +struct remote_storage_vol_get_path_ret { + remote_nonnull_string name; +}; +typedef struct remote_storage_vol_get_path_ret remote_storage_vol_get_path_ret; #define REMOTE_PROGRAM 0x20008086 #define REMOTE_PROTOCOL_VERSION 1 @@ -728,6 +978,31 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_MIGRATE_FINISH = 63, REMOTE_PROC_DOMAIN_BLOCK_STATS = 64, REMOTE_PROC_DOMAIN_INTERFACE_STATS = 65, + REMOTE_PROC_NUM_OF_STORAGE_POOLS = 66, + REMOTE_PROC_LIST_STORAGE_POOLS = 67, + REMOTE_PROC_NUM_OF_DEFINED_STORAGE_POOLS = 68, + REMOTE_PROC_LIST_DEFINED_STORAGE_POOLS = 69, + REMOTE_PROC_STORAGE_POOL_CREATE_XML = 70, + REMOTE_PROC_STORAGE_POOL_DEFINE_XML = 71, + REMOTE_PROC_STORAGE_POOL_CREATE = 72, + REMOTE_PROC_STORAGE_POOL_SHUTDOWN = 73, + REMOTE_PROC_STORAGE_POOL_DESTROY = 74, + REMOTE_PROC_STORAGE_POOL_UNDEFINE = 75, + REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_NAME = 76, + REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_UUID = 77, + REMOTE_PROC_STORAGE_POOL_GET_INFO = 78, + REMOTE_PROC_STORAGE_POOL_DUMP_XML = 79, + REMOTE_PROC_STORAGE_POOL_GET_AUTOSTART = 80, + REMOTE_PROC_STORAGE_POOL_SET_AUTOSTART = 81, + REMOTE_PROC_STORAGE_POOL_NUM_OF_VOLUMES = 82, + REMOTE_PROC_STORAGE_POOL_LIST_VOLUMES = 83, + REMOTE_PROC_STORAGE_VOL_CREATE_XML = 84, + REMOTE_PROC_STORAGE_VOL_DESTROY = 85, + REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_NAME = 86, + REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_UUID = 87, + REMOTE_PROC_STORAGE_VOL_GET_INFO = 88, + REMOTE_PROC_STORAGE_VOL_DUMP_XML = 89, + REMOTE_PROC_STORAGE_VOL_GET_PATH = 90, }; typedef enum remote_procedure remote_procedure; @@ -762,8 +1037,12 @@ extern bool_t xdr_remote_uuid (XDR *, r extern bool_t xdr_remote_uuid (XDR *, remote_uuid); extern bool_t xdr_remote_nonnull_domain (XDR *, remote_nonnull_domain*); extern bool_t xdr_remote_nonnull_network (XDR *, remote_nonnull_network*); +extern bool_t xdr_remote_nonnull_storage_pool (XDR *, remote_nonnull_storage_pool*); +extern bool_t xdr_remote_nonnull_storage_vol (XDR *, remote_nonnull_storage_vol*); extern bool_t xdr_remote_domain (XDR *, remote_domain*); extern bool_t xdr_remote_network (XDR *, remote_network*); +extern bool_t xdr_remote_storage_pool (XDR *, remote_storage_pool*); +extern bool_t xdr_remote_storage_vol (XDR *, remote_storage_vol*); extern bool_t xdr_remote_error (XDR *, remote_error*); extern bool_t xdr_remote_vcpu_info (XDR *, remote_vcpu_info*); extern bool_t xdr_remote_sched_param_value (XDR *, remote_sched_param_value*); @@ -863,6 +1142,48 @@ extern bool_t xdr_remote_network_get_au extern bool_t xdr_remote_network_get_autostart_args (XDR *, remote_network_get_autostart_args*); extern bool_t xdr_remote_network_get_autostart_ret (XDR *, remote_network_get_autostart_ret*); extern bool_t xdr_remote_network_set_autostart_args (XDR *, remote_network_set_autostart_args*); +extern bool_t xdr_remote_num_of_storage_pools_ret (XDR *, remote_num_of_storage_pools_ret*); +extern bool_t xdr_remote_list_storage_pools_args (XDR *, remote_list_storage_pools_args*); +extern bool_t xdr_remote_list_storage_pools_ret (XDR *, remote_list_storage_pools_ret*); +extern bool_t xdr_remote_num_of_defined_storage_pools_ret (XDR *, remote_num_of_defined_storage_pools_ret*); +extern bool_t xdr_remote_list_defined_storage_pools_args (XDR *, remote_list_defined_storage_pools_args*); +extern bool_t xdr_remote_list_defined_storage_pools_ret (XDR *, remote_list_defined_storage_pools_ret*); +extern bool_t xdr_remote_storage_pool_lookup_by_uuid_args (XDR *, remote_storage_pool_lookup_by_uuid_args*); +extern bool_t xdr_remote_storage_pool_lookup_by_uuid_ret (XDR *, remote_storage_pool_lookup_by_uuid_ret*); +extern bool_t xdr_remote_storage_pool_lookup_by_name_args (XDR *, remote_storage_pool_lookup_by_name_args*); +extern bool_t xdr_remote_storage_pool_lookup_by_name_ret (XDR *, remote_storage_pool_lookup_by_name_ret*); +extern bool_t xdr_remote_storage_pool_create_xml_args (XDR *, remote_storage_pool_create_xml_args*); +extern bool_t xdr_remote_storage_pool_create_xml_ret (XDR *, remote_storage_pool_create_xml_ret*); +extern bool_t xdr_remote_storage_pool_define_xml_args (XDR *, remote_storage_pool_define_xml_args*); +extern bool_t xdr_remote_storage_pool_define_xml_ret (XDR *, remote_storage_pool_define_xml_ret*); +extern bool_t xdr_remote_storage_pool_undefine_args (XDR *, remote_storage_pool_undefine_args*); +extern bool_t xdr_remote_storage_pool_create_args (XDR *, remote_storage_pool_create_args*); +extern bool_t xdr_remote_storage_pool_shutdown_args (XDR *, remote_storage_pool_shutdown_args*); +extern bool_t xdr_remote_storage_pool_destroy_args (XDR *, remote_storage_pool_destroy_args*); +extern bool_t xdr_remote_storage_pool_dump_xml_args (XDR *, remote_storage_pool_dump_xml_args*); +extern bool_t xdr_remote_storage_pool_dump_xml_ret (XDR *, remote_storage_pool_dump_xml_ret*); +extern bool_t xdr_remote_storage_pool_get_info_args (XDR *, remote_storage_pool_get_info_args*); +extern bool_t xdr_remote_storage_pool_get_info_ret (XDR *, remote_storage_pool_get_info_ret*); +extern bool_t xdr_remote_storage_pool_get_autostart_args (XDR *, remote_storage_pool_get_autostart_args*); +extern bool_t xdr_remote_storage_pool_get_autostart_ret (XDR *, remote_storage_pool_get_autostart_ret*); +extern bool_t xdr_remote_storage_pool_set_autostart_args (XDR *, remote_storage_pool_set_autostart_args*); +extern bool_t xdr_remote_storage_pool_num_of_volumes_args (XDR *, remote_storage_pool_num_of_volumes_args*); +extern bool_t xdr_remote_storage_pool_num_of_volumes_ret (XDR *, remote_storage_pool_num_of_volumes_ret*); +extern bool_t xdr_remote_storage_pool_list_volumes_args (XDR *, remote_storage_pool_list_volumes_args*); +extern bool_t xdr_remote_storage_pool_list_volumes_ret (XDR *, remote_storage_pool_list_volumes_ret*); +extern bool_t xdr_remote_storage_vol_lookup_by_uuid_args (XDR *, remote_storage_vol_lookup_by_uuid_args*); +extern bool_t xdr_remote_storage_vol_lookup_by_uuid_ret (XDR *, remote_storage_vol_lookup_by_uuid_ret*); +extern bool_t xdr_remote_storage_vol_lookup_by_name_args (XDR *, remote_storage_vol_lookup_by_name_args*); +extern bool_t xdr_remote_storage_vol_lookup_by_name_ret (XDR *, remote_storage_vol_lookup_by_name_ret*); +extern bool_t xdr_remote_storage_vol_create_xml_args (XDR *, remote_storage_vol_create_xml_args*); +extern bool_t xdr_remote_storage_vol_create_xml_ret (XDR *, remote_storage_vol_create_xml_ret*); +extern bool_t xdr_remote_storage_vol_destroy_args (XDR *, remote_storage_vol_destroy_args*); +extern bool_t xdr_remote_storage_vol_dump_xml_args (XDR *, remote_storage_vol_dump_xml_args*); +extern bool_t xdr_remote_storage_vol_dump_xml_ret (XDR *, remote_storage_vol_dump_xml_ret*); +extern bool_t xdr_remote_storage_vol_get_info_args (XDR *, remote_storage_vol_get_info_args*); +extern bool_t xdr_remote_storage_vol_get_info_ret (XDR *, remote_storage_vol_get_info_ret*); +extern bool_t xdr_remote_storage_vol_get_path_args (XDR *, remote_storage_vol_get_path_args*); +extern bool_t xdr_remote_storage_vol_get_path_ret (XDR *, remote_storage_vol_get_path_ret*); extern bool_t xdr_remote_procedure (XDR *, remote_procedure*); extern bool_t xdr_remote_message_direction (XDR *, remote_message_direction*); extern bool_t xdr_remote_message_status (XDR *, remote_message_status*); @@ -874,8 +1195,12 @@ extern bool_t xdr_remote_uuid (); extern bool_t xdr_remote_uuid (); extern bool_t xdr_remote_nonnull_domain (); extern bool_t xdr_remote_nonnull_network (); +extern bool_t xdr_remote_nonnull_storage_pool (); +extern bool_t xdr_remote_nonnull_storage_vol (); extern bool_t xdr_remote_domain (); extern bool_t xdr_remote_network (); +extern bool_t xdr_remote_storage_pool (); +extern bool_t xdr_remote_storage_vol (); extern bool_t xdr_remote_error (); extern bool_t xdr_remote_vcpu_info (); extern bool_t xdr_remote_sched_param_value (); @@ -975,6 +1300,48 @@ extern bool_t xdr_remote_network_get_aut extern bool_t xdr_remote_network_get_autostart_args (); extern bool_t xdr_remote_network_get_autostart_ret (); extern bool_t xdr_remote_network_set_autostart_args (); +extern bool_t xdr_remote_num_of_storage_pools_ret (); +extern bool_t xdr_remote_list_storage_pools_args (); +extern bool_t xdr_remote_list_storage_pools_ret (); +extern bool_t xdr_remote_num_of_defined_storage_pools_ret (); +extern bool_t xdr_remote_list_defined_storage_pools_args (); +extern bool_t xdr_remote_list_defined_storage_pools_ret (); +extern bool_t xdr_remote_storage_pool_lookup_by_uuid_args (); +extern bool_t xdr_remote_storage_pool_lookup_by_uuid_ret (); +extern bool_t xdr_remote_storage_pool_lookup_by_name_args (); +extern bool_t xdr_remote_storage_pool_lookup_by_name_ret (); +extern bool_t xdr_remote_storage_pool_create_xml_args (); +extern bool_t xdr_remote_storage_pool_create_xml_ret (); +extern bool_t xdr_remote_storage_pool_define_xml_args (); +extern bool_t xdr_remote_storage_pool_define_xml_ret (); +extern bool_t xdr_remote_storage_pool_undefine_args (); +extern bool_t xdr_remote_storage_pool_create_args (); +extern bool_t xdr_remote_storage_pool_shutdown_args (); +extern bool_t xdr_remote_storage_pool_destroy_args (); +extern bool_t xdr_remote_storage_pool_dump_xml_args (); +extern bool_t xdr_remote_storage_pool_dump_xml_ret (); +extern bool_t xdr_remote_storage_pool_get_info_args (); +extern bool_t xdr_remote_storage_pool_get_info_ret (); +extern bool_t xdr_remote_storage_pool_get_autostart_args (); +extern bool_t xdr_remote_storage_pool_get_autostart_ret (); +extern bool_t xdr_remote_storage_pool_set_autostart_args (); +extern bool_t xdr_remote_storage_pool_num_of_volumes_args (); +extern bool_t xdr_remote_storage_pool_num_of_volumes_ret (); +extern bool_t xdr_remote_storage_pool_list_volumes_args (); +extern bool_t xdr_remote_storage_pool_list_volumes_ret (); +extern bool_t xdr_remote_storage_vol_lookup_by_uuid_args (); +extern bool_t xdr_remote_storage_vol_lookup_by_uuid_ret (); +extern bool_t xdr_remote_storage_vol_lookup_by_name_args (); +extern bool_t xdr_remote_storage_vol_lookup_by_name_ret (); +extern bool_t xdr_remote_storage_vol_create_xml_args (); +extern bool_t xdr_remote_storage_vol_create_xml_ret (); +extern bool_t xdr_remote_storage_vol_destroy_args (); +extern bool_t xdr_remote_storage_vol_dump_xml_args (); +extern bool_t xdr_remote_storage_vol_dump_xml_ret (); +extern bool_t xdr_remote_storage_vol_get_info_args (); +extern bool_t xdr_remote_storage_vol_get_info_ret (); +extern bool_t xdr_remote_storage_vol_get_path_args (); +extern bool_t xdr_remote_storage_vol_get_path_ret (); extern bool_t xdr_remote_procedure (); extern bool_t xdr_remote_message_direction (); extern bool_t xdr_remote_message_status (); diff -r 89d154031d13 qemud/remote_protocol.x --- a/qemud/remote_protocol.x Sat Oct 27 17:52:41 2007 -0400 +++ b/qemud/remote_protocol.x Sat Oct 27 17:55:05 2007 -0400 @@ -78,6 +78,12 @@ const REMOTE_MIGRATE_COOKIE_MAX = 256; /* Upper limit on lists of network names. */ const REMOTE_NETWORK_NAME_LIST_MAX = 256; +/* Upper limit on lists of storage pool names. */ +const REMOTE_STORAGE_POOL_NAME_LIST_MAX = 256; + +/* Upper limit on lists of storage vol names. */ +const REMOTE_STORAGE_VOL_NAME_LIST_MAX = 1024; + /* Upper limit on list of scheduler parameters. */ const REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX = 16; @@ -93,6 +99,19 @@ struct remote_nonnull_domain { /* A network which may not be NULL. */ struct remote_nonnull_network { + remote_nonnull_string name; + remote_uuid uuid; +}; + +/* A storage pool which may not be NULL. */ +struct remote_nonnull_storage_pool { + remote_nonnull_string name; + remote_uuid uuid; +}; + +/* A storage vol which may not be NULL. */ +struct remote_nonnull_storage_vol { + remote_nonnull_storage_pool pool; remote_nonnull_string name; remote_uuid uuid; }; @@ -100,6 +119,8 @@ struct remote_nonnull_network { /* A domain or network which may be NULL. */ typedef remote_nonnull_domain *remote_domain; typedef remote_nonnull_network *remote_network; +typedef remote_nonnull_storage_pool *remote_storage_pool; +typedef remote_nonnull_storage_vol *remote_storage_vol; /* Error message. See <virterror.h> for explanation of fields. */ @@ -610,6 +631,195 @@ struct remote_network_set_autostart_args struct remote_network_set_autostart_args { remote_nonnull_network net; int autostart; +}; + + + + +/* Storage pool calls: */ + +struct remote_num_of_storage_pools_ret { + int num; +}; + +struct remote_list_storage_pools_args { + int maxnames; +}; + +struct remote_list_storage_pools_ret { + remote_nonnull_string names<REMOTE_STORAGE_POOL_NAME_LIST_MAX>; +}; + +struct remote_num_of_defined_storage_pools_ret { + int num; +}; + +struct remote_list_defined_storage_pools_args { + int maxnames; +}; + +struct remote_list_defined_storage_pools_ret { + remote_nonnull_string names<REMOTE_STORAGE_POOL_NAME_LIST_MAX>; +}; + +struct remote_storage_pool_lookup_by_uuid_args { + remote_uuid uuid; +}; + +struct remote_storage_pool_lookup_by_uuid_ret { + remote_nonnull_storage_pool pool; +}; + +struct remote_storage_pool_lookup_by_name_args { + remote_nonnull_string name; +}; + +struct remote_storage_pool_lookup_by_name_ret { + remote_nonnull_storage_pool pool; +}; + +struct remote_storage_pool_create_xml_args { + remote_nonnull_string xml; +}; + +struct remote_storage_pool_create_xml_ret { + remote_nonnull_storage_pool pool; +}; + +struct remote_storage_pool_define_xml_args { + remote_nonnull_string xml; +}; + +struct remote_storage_pool_define_xml_ret { + remote_nonnull_storage_pool pool; +}; + +struct remote_storage_pool_undefine_args { + remote_nonnull_storage_pool pool; +}; + +struct remote_storage_pool_create_args { + remote_nonnull_storage_pool pool; +}; + +struct remote_storage_pool_shutdown_args { + remote_nonnull_storage_pool pool; +}; + +struct remote_storage_pool_destroy_args { + remote_nonnull_storage_pool pool; +}; + +struct remote_storage_pool_dump_xml_args { + remote_nonnull_storage_pool pool; + int flags; +}; + +struct remote_storage_pool_dump_xml_ret { + remote_nonnull_string xml; +}; + +struct remote_storage_pool_get_info_args { + remote_nonnull_storage_pool pool; +}; + +struct remote_storage_pool_get_info_ret { + unsigned char state; + unsigned hyper capacity; + unsigned hyper allocation; +}; + +struct remote_storage_pool_get_autostart_args { + remote_nonnull_storage_pool pool; +}; + +struct remote_storage_pool_get_autostart_ret { + int autostart; +}; + +struct remote_storage_pool_set_autostart_args { + remote_nonnull_storage_pool pool; + int autostart; +}; + + + +/* Storage vol calls: */ + +struct remote_storage_pool_num_of_volumes_args { + remote_nonnull_storage_pool pool; +}; + +struct remote_storage_pool_num_of_volumes_ret { + int num; +}; + +struct remote_storage_pool_list_volumes_args { + remote_nonnull_storage_pool pool; + int maxnames; +}; + +struct remote_storage_pool_list_volumes_ret { + remote_nonnull_string names<REMOTE_STORAGE_VOL_NAME_LIST_MAX>; +}; + +struct remote_storage_vol_lookup_by_uuid_args { + remote_nonnull_storage_pool pool; + remote_uuid uuid; +}; + +struct remote_storage_vol_lookup_by_uuid_ret { + remote_nonnull_storage_vol vol; +}; + +struct remote_storage_vol_lookup_by_name_args { + remote_nonnull_storage_pool pool; + remote_nonnull_string name; +}; + +struct remote_storage_vol_lookup_by_name_ret { + remote_nonnull_storage_vol vol; +}; + +struct remote_storage_vol_create_xml_args { + remote_nonnull_storage_pool pool; + remote_nonnull_string xml; + int flags; +}; + +struct remote_storage_vol_create_xml_ret { + remote_nonnull_storage_vol vol; +}; + +struct remote_storage_vol_destroy_args { + remote_nonnull_storage_vol vol; +}; + +struct remote_storage_vol_dump_xml_args { + remote_nonnull_storage_vol vol; + int flags; +}; + +struct remote_storage_vol_dump_xml_ret { + remote_nonnull_string xml; +}; + +struct remote_storage_vol_get_info_args { + remote_nonnull_storage_vol vol; +}; + +struct remote_storage_vol_get_info_ret { + char type; + unsigned hyper capacity; + unsigned hyper allocation; +}; + +struct remote_storage_vol_get_path_args { + remote_nonnull_storage_vol vol; +}; + +struct remote_storage_vol_get_path_ret { + remote_nonnull_string name; }; /*----- Protocol. -----*/ @@ -683,7 +893,33 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_MIGRATE_PERFORM = 62, REMOTE_PROC_DOMAIN_MIGRATE_FINISH = 63, REMOTE_PROC_DOMAIN_BLOCK_STATS = 64, - REMOTE_PROC_DOMAIN_INTERFACE_STATS = 65 + REMOTE_PROC_DOMAIN_INTERFACE_STATS = 65, + REMOTE_PROC_NUM_OF_STORAGE_POOLS = 66, + REMOTE_PROC_LIST_STORAGE_POOLS = 67, + REMOTE_PROC_NUM_OF_DEFINED_STORAGE_POOLS = 68, + REMOTE_PROC_LIST_DEFINED_STORAGE_POOLS = 69, + REMOTE_PROC_STORAGE_POOL_CREATE_XML = 70, + REMOTE_PROC_STORAGE_POOL_DEFINE_XML = 71, + REMOTE_PROC_STORAGE_POOL_CREATE = 72, + REMOTE_PROC_STORAGE_POOL_SHUTDOWN = 73, + REMOTE_PROC_STORAGE_POOL_DESTROY = 74, + REMOTE_PROC_STORAGE_POOL_UNDEFINE = 75, + REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_NAME = 76, + REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_UUID = 77, + REMOTE_PROC_STORAGE_POOL_GET_INFO = 78, + REMOTE_PROC_STORAGE_POOL_DUMP_XML = 79, + REMOTE_PROC_STORAGE_POOL_GET_AUTOSTART = 80, + REMOTE_PROC_STORAGE_POOL_SET_AUTOSTART = 81, + + REMOTE_PROC_STORAGE_POOL_NUM_OF_VOLUMES = 82, + REMOTE_PROC_STORAGE_POOL_LIST_VOLUMES = 83, + REMOTE_PROC_STORAGE_VOL_CREATE_XML = 84, + REMOTE_PROC_STORAGE_VOL_DESTROY = 85, + REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_NAME = 86, + REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_UUID = 87, + REMOTE_PROC_STORAGE_VOL_GET_INFO = 88, + REMOTE_PROC_STORAGE_VOL_DUMP_XML = 89, + REMOTE_PROC_STORAGE_VOL_GET_PATH = 90 }; /* Custom RPC structure. */ -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

Daniel P. Berrange wrote:
This patch defines the remote wire protocol for serializing all the storage API calls. There are 15 new calls for storage pools, and 9 calls for storage volumes. The style is following that of the network API calls. The serialization of virStorageVolPtr is slightly more complicated, because it has to have a nested virStoragePoolPtr serialized alongside it.
As a general comment, I don't think it's worth implementing the remote part of any patch before the local parts have been reviewed and accepted in principle. The remote work should just be a mechanical implementation (except for features which someone depend on remote, which from my brief look this one doesn't). The disadvantage of doing all the remote stuff early is it makes the patch as a whole much harder to change. Rich. -- Emerging Technologies, Red Hat - http://et.redhat.com/~rjones/ Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SL4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 03798903

This provides the implementation of the remote driver client end. In the same way as the network APIs, all the storage API calls have to go to server, since the APIs have state to maintain. So things are setup such that no matter what hypervisor is being used, this remote driver will provide the storage API impls. The implementation here is just the methodical serialization & de-serialization of objects to/from the XDR wire format. The style follows that of the network APIs. remote_internal.c | 722 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 716 insertions(+), 6 deletions(-) diff -r 658fbf7974c1 src/remote_internal.c --- a/src/remote_internal.c Sun Oct 28 14:34:26 2007 -0400 +++ b/src/remote_internal.c Sun Oct 28 22:44:25 2007 -0400 @@ -70,7 +70,7 @@ struct private_data { char *type; /* Cached return from remoteType. */ int counter; /* Generates serial numbers for RPC. */ char *uri; /* Original (remote) URI. */ - int networkOnly; /* Only used for network API */ + int localUses; /* Ref count for private data */ }; #define GET_PRIVATE(conn,retcode) \ @@ -89,13 +89,25 @@ struct private_data { return (retcode); \ } +#define GET_STORAGE_PRIVATE(conn,retcode) \ + struct private_data *priv = (struct private_data *) (conn)->storagePrivateData; \ + if (!priv || priv->magic != MAGIC) { \ + error (conn, VIR_ERR_INVALID_ARG, \ + "tried to use a closed or uninitialised handle"); \ + return (retcode); \ + } + static int call (virConnectPtr conn, struct private_data *priv, int in_open, int proc_nr, xdrproc_t args_filter, char *args, xdrproc_t ret_filter, char *ret); static void error (virConnectPtr conn, virErrorNumber code, const char *info); static void server_error (virConnectPtr conn, remote_error *err); static virDomainPtr get_nonnull_domain (virConnectPtr conn, remote_nonnull_domain domain); static virNetworkPtr get_nonnull_network (virConnectPtr conn, remote_nonnull_network network); +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 void make_nonnull_domain (remote_nonnull_domain *dom_dst, virDomainPtr dom_src); static void make_nonnull_network (remote_nonnull_network *net_dst, virNetworkPtr net_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); /*----------------------------------------------------------------------*/ @@ -2414,7 +2426,7 @@ remoteNetworkOpen (virConnectPtr conn, free(priv); } else { priv->magic = MAGIC; - priv->networkOnly = 1; + priv->localUses = 1; conn->networkPrivateData = priv; } return ret; @@ -2426,10 +2438,13 @@ remoteNetworkClose (virConnectPtr conn) { int ret = 0; GET_NETWORK_PRIVATE (conn, -1); - if (priv->networkOnly) { - ret = doRemoteClose(conn, priv); - free(priv); - conn->networkPrivateData = NULL; + if (priv->localUses) { + priv->localUses--; + if (!priv->localUses) { + ret = doRemoteClose(conn, priv); + free(priv); + conn->networkPrivateData = NULL; + } } return ret; } @@ -2756,6 +2771,634 @@ remoteNetworkSetAutostart (virNetworkPtr return 0; } + + + + +/*----------------------------------------------------------------------*/ + +static int +remoteStorageOpen (virConnectPtr conn, + const char *uri_str, + int flags) +{ + if (inside_daemon) + return VIR_DRV_OPEN_DECLINED; + + if (conn && + conn->driver && + strcmp (conn->driver->name, "remote") == 0) { + /* If we're here, the remote driver is already + * in use due to a) a QEMU uri, or b) a remote + * URI. So we can re-use existing connection + */ + conn->storagePrivateData = conn->privateData; + return VIR_DRV_OPEN_SUCCESS; + } else if (conn->networkDriver && + strcmp (conn->networkDriver->name, "remote") == 0) { + conn->storagePrivateData = conn->networkPrivateData; + ((struct private_data *)conn->storagePrivateData)->localUses++; + return VIR_DRV_OPEN_SUCCESS; + } else { + /* Using a non-remote driver, so we need to open a + * new connection for network APIs, forcing it to + * use the UNIX transport. This handles Xen driver + * which doesn't have its own impl of the network APIs. + */ + struct private_data *priv = malloc (sizeof(struct private_data)); + int ret, rflags = 0; + if (!priv) { + error (NULL, VIR_ERR_NO_MEMORY, "struct private_data"); + return VIR_DRV_OPEN_ERROR; + } + if (flags & VIR_DRV_OPEN_RO) + rflags |= VIR_DRV_OPEN_REMOTE_RO; + rflags |= VIR_DRV_OPEN_REMOTE_UNIX; + + memset(priv, 0, sizeof(struct private_data)); + priv->magic = DEAD; + priv->sock = -1; + ret = doRemoteOpen(conn, priv, uri_str, rflags); + if (ret != VIR_DRV_OPEN_SUCCESS) { + conn->storagePrivateData = NULL; + free(priv); + } else { + priv->magic = MAGIC; + priv->localUses = 1; + conn->storagePrivateData = priv; + } + return ret; + } +} + +static int +remoteStorageClose (virConnectPtr conn) +{ + int ret = 0; + GET_STORAGE_PRIVATE (conn, -1); + if (priv->localUses) { + priv->localUses--; + if (!priv->localUses) { + ret = doRemoteClose(conn, priv); + free(priv); + conn->storagePrivateData = NULL; + } + } + return ret; +} + +static int +remoteNumOfStoragePools (virConnectPtr conn) +{ + remote_num_of_storage_pools_ret ret; + GET_STORAGE_PRIVATE (conn, -1); + + memset (&ret, 0, sizeof ret); + if (call (conn, priv, 0, REMOTE_PROC_NUM_OF_STORAGE_POOLS, + (xdrproc_t) xdr_void, (char *) NULL, + (xdrproc_t) xdr_remote_num_of_storage_pools_ret, (char *) &ret) == -1) + return -1; + + return ret.num; +} + +static int +remoteListStoragePools (virConnectPtr conn, char **const names, int maxnames) +{ + int i; + remote_list_storage_pools_args args; + remote_list_storage_pools_ret ret; + GET_STORAGE_PRIVATE (conn, -1); + + if (maxnames > REMOTE_STORAGE_POOL_NAME_LIST_MAX) { + error (conn, VIR_ERR_RPC, "maxnames > REMOTE_STORAGE_POOL_NAME_LIST_MAX"); + return -1; + } + args.maxnames = maxnames; + + memset (&ret, 0, sizeof ret); + if (call (conn, priv, 0, REMOTE_PROC_LIST_STORAGE_POOLS, + (xdrproc_t) xdr_remote_list_storage_pools_args, (char *) &args, + (xdrproc_t) xdr_remote_list_storage_pools_ret, (char *) &ret) == -1) + return -1; + + if (ret.names.names_len > maxnames) { + error (conn, VIR_ERR_RPC, "ret.names.names_len > maxnames"); + xdr_free ((xdrproc_t) xdr_remote_list_storage_pools_ret, (char *) &ret); + return -1; + } + + /* This call is caller-frees (although that isn't clear from + * the documentation). However xdr_free will free up both the + * names and the list of pointers, so we have to strdup the + * names here. + */ + for (i = 0; i < ret.names.names_len; ++i) + names[i] = strdup (ret.names.names_val[i]); + + xdr_free ((xdrproc_t) xdr_remote_list_storage_pools_ret, (char *) &ret); + + return ret.names.names_len; +} + +static int +remoteNumOfDefinedStoragePools (virConnectPtr conn) +{ + remote_num_of_defined_storage_pools_ret ret; + GET_STORAGE_PRIVATE (conn, -1); + + memset (&ret, 0, sizeof ret); + if (call (conn, priv, 0, REMOTE_PROC_NUM_OF_DEFINED_STORAGE_POOLS, + (xdrproc_t) xdr_void, (char *) NULL, + (xdrproc_t) xdr_remote_num_of_defined_storage_pools_ret, (char *) &ret) == -1) + return -1; + + return ret.num; +} + +static int +remoteListDefinedStoragePools (virConnectPtr conn, + char **const names, int maxnames) +{ + int i; + remote_list_defined_storage_pools_args args; + remote_list_defined_storage_pools_ret ret; + GET_STORAGE_PRIVATE (conn, -1); + + if (maxnames > REMOTE_STORAGE_POOL_NAME_LIST_MAX) { + error (conn, VIR_ERR_RPC, "maxnames > REMOTE_STORAGE_POOL_NAME_LIST_MAX"); + return -1; + } + args.maxnames = maxnames; + + memset (&ret, 0, sizeof ret); + if (call (conn, priv, 0, REMOTE_PROC_LIST_DEFINED_STORAGE_POOLS, + (xdrproc_t) xdr_remote_list_defined_storage_pools_args, (char *) &args, + (xdrproc_t) xdr_remote_list_defined_storage_pools_ret, (char *) &ret) == -1) + return -1; + + if (ret.names.names_len > maxnames) { + error (conn, VIR_ERR_RPC, "ret.names.names_len > maxnames"); + xdr_free ((xdrproc_t) xdr_remote_list_defined_storage_pools_ret, (char *) &ret); + return -1; + } + + /* This call is caller-frees (although that isn't clear from + * the documentation). However xdr_free will free up both the + * names and the list of pointers, so we have to strdup the + * names here. + */ + for (i = 0; i < ret.names.names_len; ++i) + names[i] = strdup (ret.names.names_val[i]); + + xdr_free ((xdrproc_t) xdr_remote_list_defined_storage_pools_ret, (char *) &ret); + + return ret.names.names_len; +} + +static virStoragePoolPtr +remoteStoragePoolLookupByUUID (virConnectPtr conn, + const unsigned char *uuid) +{ + virStoragePoolPtr pool; + remote_storage_pool_lookup_by_uuid_args args; + remote_storage_pool_lookup_by_uuid_ret ret; + GET_STORAGE_PRIVATE (conn, NULL); + + memcpy (args.uuid, uuid, VIR_UUID_BUFLEN); + + memset (&ret, 0, sizeof ret); + if (call (conn, priv, 0, REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_UUID, + (xdrproc_t) xdr_remote_storage_pool_lookup_by_uuid_args, (char *) &args, + (xdrproc_t) xdr_remote_storage_pool_lookup_by_uuid_ret, (char *) &ret) == -1) + return NULL; + + pool = get_nonnull_storage_pool (conn, ret.pool); + xdr_free ((xdrproc_t) &xdr_remote_storage_pool_lookup_by_uuid_ret, (char *) &ret); + + return pool; +} + +static virStoragePoolPtr +remoteStoragePoolLookupByName (virConnectPtr conn, + const char *name) +{ + virStoragePoolPtr pool; + remote_storage_pool_lookup_by_name_args args; + remote_storage_pool_lookup_by_name_ret ret; + GET_STORAGE_PRIVATE (conn, NULL); + + args.name = (char *) name; + + memset (&ret, 0, sizeof ret); + if (call (conn, priv, 0, REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_NAME, + (xdrproc_t) xdr_remote_storage_pool_lookup_by_name_args, (char *) &args, + (xdrproc_t) xdr_remote_storage_pool_lookup_by_name_ret, (char *) &ret) == -1) + return NULL; + + pool = get_nonnull_storage_pool (conn, ret.pool); + xdr_free ((xdrproc_t) &xdr_remote_storage_pool_lookup_by_name_ret, (char *) &ret); + + return pool; +} + +static virStoragePoolPtr +remoteStoragePoolCreateXML (virConnectPtr conn, const char *xmlDesc) +{ + virStoragePoolPtr pool; + remote_storage_pool_create_xml_args args; + remote_storage_pool_create_xml_ret ret; + GET_STORAGE_PRIVATE (conn, NULL); + + args.xml = (char *) xmlDesc; + + memset (&ret, 0, sizeof ret); + if (call (conn, priv, 0, REMOTE_PROC_STORAGE_POOL_CREATE_XML, + (xdrproc_t) xdr_remote_storage_pool_create_xml_args, (char *) &args, + (xdrproc_t) xdr_remote_storage_pool_create_xml_ret, (char *) &ret) == -1) + return NULL; + + pool = get_nonnull_storage_pool (conn, ret.pool); + xdr_free ((xdrproc_t) &xdr_remote_storage_pool_create_xml_ret, (char *) &ret); + + return pool; +} + +static virStoragePoolPtr +remoteStoragePoolDefineXML (virConnectPtr conn, const char *xml) +{ + virStoragePoolPtr pool; + remote_storage_pool_define_xml_args args; + remote_storage_pool_define_xml_ret ret; + GET_STORAGE_PRIVATE (conn, NULL); + + args.xml = (char *) xml; + + memset (&ret, 0, sizeof ret); + if (call (conn, priv, 0, REMOTE_PROC_STORAGE_POOL_DEFINE_XML, + (xdrproc_t) xdr_remote_storage_pool_define_xml_args, (char *) &args, + (xdrproc_t) xdr_remote_storage_pool_define_xml_ret, (char *) &ret) == -1) + return NULL; + + pool = get_nonnull_storage_pool (conn, ret.pool); + xdr_free ((xdrproc_t) &xdr_remote_storage_pool_define_xml_ret, (char *) &ret); + + return pool; +} + +static int +remoteStoragePoolUndefine (virStoragePoolPtr pool) +{ + remote_storage_pool_undefine_args args; + GET_STORAGE_PRIVATE (pool->conn, -1); + + make_nonnull_storage_pool (&args.pool, pool); + + if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_POOL_UNDEFINE, + (xdrproc_t) xdr_remote_storage_pool_undefine_args, (char *) &args, + (xdrproc_t) xdr_void, (char *) NULL) == -1) + return -1; + + return 0; +} + +static int +remoteStoragePoolCreate (virStoragePoolPtr pool) +{ + remote_storage_pool_create_args args; + GET_STORAGE_PRIVATE (pool->conn, -1); + + make_nonnull_storage_pool (&args.pool, pool); + + if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_POOL_CREATE, + (xdrproc_t) xdr_remote_storage_pool_create_args, (char *) &args, + (xdrproc_t) xdr_void, (char *) NULL) == -1) + return -1; + + return 0; +} + +static int +remoteStoragePoolShutdown (virStoragePoolPtr pool) +{ + remote_storage_pool_destroy_args args; + GET_STORAGE_PRIVATE (pool->conn, -1); + + make_nonnull_storage_pool (&args.pool, pool); + + if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_POOL_DESTROY, + (xdrproc_t) xdr_remote_storage_pool_destroy_args, (char *) &args, + (xdrproc_t) xdr_void, (char *) NULL) == -1) + return -1; + + return 0; +} + +static int +remoteStoragePoolDestroy (virStoragePoolPtr pool) +{ + remote_storage_pool_destroy_args args; + GET_STORAGE_PRIVATE (pool->conn, -1); + + make_nonnull_storage_pool (&args.pool, pool); + + if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_POOL_DESTROY, + (xdrproc_t) xdr_remote_storage_pool_destroy_args, (char *) &args, + (xdrproc_t) xdr_void, (char *) NULL) == -1) + return -1; + + return 0; +} + +static int +remoteStoragePoolGetInfo (virStoragePoolPtr pool, virStoragePoolInfoPtr info) +{ + remote_storage_pool_get_info_args args; + remote_storage_pool_get_info_ret ret; + GET_STORAGE_PRIVATE (pool->conn, -1); + + make_nonnull_storage_pool (&args.pool, pool); + + memset (&ret, 0, sizeof ret); + if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_POOL_GET_INFO, + (xdrproc_t) xdr_remote_storage_pool_get_info_args, (char *) &args, + (xdrproc_t) xdr_remote_storage_pool_get_info_ret, (char *) &ret) == -1) + return -1; + + info->state = ret.state; + info->capacity = ret.capacity; + info->allocation = ret.allocation; + + return 0; +} + +static char * +remoteStoragePoolDumpXML (virStoragePoolPtr pool, int flags) +{ + remote_storage_pool_dump_xml_args args; + remote_storage_pool_dump_xml_ret ret; + GET_STORAGE_PRIVATE (pool->conn, NULL); + + make_nonnull_storage_pool (&args.pool, pool); + args.flags = flags; + + memset (&ret, 0, sizeof ret); + if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_POOL_DUMP_XML, + (xdrproc_t) xdr_remote_storage_pool_dump_xml_args, (char *) &args, + (xdrproc_t) xdr_remote_storage_pool_dump_xml_ret, (char *) &ret) == -1) + return NULL; + + /* Caller frees. */ + return ret.xml; +} + +static int +remoteStoragePoolGetAutostart (virStoragePoolPtr pool, int *autostart) +{ + remote_storage_pool_get_autostart_args args; + remote_storage_pool_get_autostart_ret ret; + GET_STORAGE_PRIVATE (pool->conn, -1); + + make_nonnull_storage_pool (&args.pool, pool); + + memset (&ret, 0, sizeof ret); + if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_POOL_GET_AUTOSTART, + (xdrproc_t) xdr_remote_storage_pool_get_autostart_args, (char *) &args, + (xdrproc_t) xdr_remote_storage_pool_get_autostart_ret, (char *) &ret) == -1) + return -1; + + if (autostart) *autostart = ret.autostart; + + return 0; +} + +static int +remoteStoragePoolSetAutostart (virStoragePoolPtr pool, int autostart) +{ + remote_storage_pool_set_autostart_args args; + GET_STORAGE_PRIVATE (pool->conn, -1); + + make_nonnull_storage_pool (&args.pool, pool); + args.autostart = autostart; + + if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_POOL_SET_AUTOSTART, + (xdrproc_t) xdr_remote_storage_pool_set_autostart_args, (char *) &args, + (xdrproc_t) xdr_void, (char *) NULL) == -1) + return -1; + + return 0; +} + + +static int +remoteStoragePoolNumOfVolumes (virStoragePoolPtr pool) +{ + remote_storage_pool_num_of_volumes_args args; + remote_storage_pool_num_of_volumes_ret ret; + GET_STORAGE_PRIVATE (pool->conn, -1); + + make_nonnull_storage_pool(&args.pool, pool); + + memset (&ret, 0, sizeof ret); + if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_POOL_NUM_OF_VOLUMES, + (xdrproc_t) xdr_remote_storage_pool_num_of_volumes_args, (char *) &args, + (xdrproc_t) xdr_remote_storage_pool_num_of_volumes_ret, (char *) &ret) == -1) + return -1; + + return ret.num; +} + +static int +remoteStoragePoolListVolumes (virStoragePoolPtr pool, char **const names, int maxnames) +{ + int i; + remote_storage_pool_list_volumes_args args; + remote_storage_pool_list_volumes_ret ret; + GET_STORAGE_PRIVATE (pool->conn, -1); + + if (maxnames > REMOTE_STORAGE_VOL_NAME_LIST_MAX) { + error (pool->conn, VIR_ERR_RPC, "maxnames > REMOTE_STORAGE_VOL_NAME_LIST_MAX"); + return -1; + } + args.maxnames = maxnames; + make_nonnull_storage_pool(&args.pool, pool); + + memset (&ret, 0, sizeof ret); + if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_POOL_LIST_VOLUMES, + (xdrproc_t) xdr_remote_storage_pool_list_volumes_args, (char *) &args, + (xdrproc_t) xdr_remote_storage_pool_list_volumes_ret, (char *) &ret) == -1) + return -1; + + if (ret.names.names_len > maxnames) { + error (pool->conn, VIR_ERR_RPC, "ret.names.names_len > maxnames"); + xdr_free ((xdrproc_t) xdr_remote_storage_pool_list_volumes_ret, (char *) &ret); + return -1; + } + + /* This call is caller-frees (although that isn't clear from + * the documentation). However xdr_free will free up both the + * names and the list of pointers, so we have to strdup the + * names here. + */ + for (i = 0; i < ret.names.names_len; ++i) + names[i] = strdup (ret.names.names_val[i]); + + xdr_free ((xdrproc_t) xdr_remote_storage_pool_list_volumes_ret, (char *) &ret); + + return ret.names.names_len; +} + + + +static virStorageVolPtr +remoteStorageVolLookupByUUID (virStoragePoolPtr pool, + const unsigned char *uuid) +{ + virStorageVolPtr vol; + remote_storage_vol_lookup_by_uuid_args args; + remote_storage_vol_lookup_by_uuid_ret ret; + GET_STORAGE_PRIVATE (pool->conn, NULL); + + make_nonnull_storage_pool(&args.pool, pool); + memcpy (args.uuid, uuid, VIR_UUID_BUFLEN); + + memset (&ret, 0, sizeof ret); + if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_UUID, + (xdrproc_t) xdr_remote_storage_vol_lookup_by_uuid_args, (char *) &args, + (xdrproc_t) xdr_remote_storage_vol_lookup_by_uuid_ret, (char *) &ret) == -1) + return NULL; + + vol = get_nonnull_storage_vol (pool->conn, ret.vol); + xdr_free ((xdrproc_t) &xdr_remote_storage_vol_lookup_by_uuid_ret, (char *) &ret); + + return vol; +} + +static virStorageVolPtr +remoteStorageVolLookupByName (virStoragePoolPtr pool, + const char *name) +{ + virStorageVolPtr vol; + remote_storage_vol_lookup_by_name_args args; + remote_storage_vol_lookup_by_name_ret ret; + GET_STORAGE_PRIVATE (pool->conn, NULL); + + make_nonnull_storage_pool(&args.pool, pool); + args.name = (char *) name; + + memset (&ret, 0, sizeof ret); + if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_NAME, + (xdrproc_t) xdr_remote_storage_vol_lookup_by_name_args, (char *) &args, + (xdrproc_t) xdr_remote_storage_vol_lookup_by_name_ret, (char *) &ret) == -1) + return NULL; + + vol = get_nonnull_storage_vol (pool->conn, ret.vol); + xdr_free ((xdrproc_t) &xdr_remote_storage_vol_lookup_by_name_ret, (char *) &ret); + + return vol; +} + +static virStorageVolPtr +remoteStorageVolCreateXML (virStoragePoolPtr pool, const char *xmlDesc, int flags) +{ + virStorageVolPtr vol; + remote_storage_vol_create_xml_args args; + remote_storage_vol_create_xml_ret ret; + GET_STORAGE_PRIVATE (pool->conn, NULL); + + make_nonnull_storage_pool(&args.pool, pool); + args.xml = (char *) xmlDesc; + args.flags = flags; + + memset (&ret, 0, sizeof ret); + if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_VOL_CREATE_XML, + (xdrproc_t) xdr_remote_storage_vol_create_xml_args, (char *) &args, + (xdrproc_t) xdr_remote_storage_vol_create_xml_ret, (char *) &ret) == -1) + return NULL; + + vol = get_nonnull_storage_vol (pool->conn, ret.vol); + xdr_free ((xdrproc_t) &xdr_remote_storage_vol_create_xml_ret, (char *) &ret); + + return vol; +} + +static int +remoteStorageVolDestroy (virStorageVolPtr vol) +{ + remote_storage_vol_destroy_args args; + GET_STORAGE_PRIVATE (vol->pool->conn, -1); + + make_nonnull_storage_vol (&args.vol, vol); + + if (call (vol->pool->conn, priv, 0, REMOTE_PROC_STORAGE_VOL_DESTROY, + (xdrproc_t) xdr_remote_storage_vol_destroy_args, (char *) &args, + (xdrproc_t) xdr_void, (char *) NULL) == -1) + return -1; + + return 0; +} + +static int +remoteStorageVolGetInfo (virStorageVolPtr vol, virStorageVolInfoPtr info) +{ + remote_storage_vol_get_info_args args; + remote_storage_vol_get_info_ret ret; + GET_STORAGE_PRIVATE (vol->pool->conn, -1); + + make_nonnull_storage_vol (&args.vol, vol); + + memset (&ret, 0, sizeof ret); + if (call (vol->pool->conn, priv, 0, REMOTE_PROC_STORAGE_VOL_GET_INFO, + (xdrproc_t) xdr_remote_storage_vol_get_info_args, (char *) &args, + (xdrproc_t) xdr_remote_storage_vol_get_info_ret, (char *) &ret) == -1) + return -1; + + info->type = ret.type; + info->capacity = ret.capacity; + info->allocation = ret.allocation; + + return 0; +} + +static char * +remoteStorageVolDumpXML (virStorageVolPtr vol, int flags) +{ + remote_storage_vol_dump_xml_args args; + remote_storage_vol_dump_xml_ret ret; + GET_STORAGE_PRIVATE (vol->pool->conn, NULL); + + make_nonnull_storage_vol (&args.vol, vol); + args.flags = flags; + + memset (&ret, 0, sizeof ret); + if (call (vol->pool->conn, priv, 0, REMOTE_PROC_STORAGE_VOL_DUMP_XML, + (xdrproc_t) xdr_remote_storage_vol_dump_xml_args, (char *) &args, + (xdrproc_t) xdr_remote_storage_vol_dump_xml_ret, (char *) &ret) == -1) + return NULL; + + /* Caller frees. */ + return ret.xml; +} + +static char * +remoteStorageVolGetPath (virStorageVolPtr vol) +{ + remote_storage_vol_get_path_args args; + remote_storage_vol_get_path_ret ret; + GET_NETWORK_PRIVATE (vol->pool->conn, NULL); + + make_nonnull_storage_vol (&args.vol, vol); + + memset (&ret, 0, sizeof ret); + if (call (vol->pool->conn, priv, 0, REMOTE_PROC_STORAGE_VOL_GET_PATH, + (xdrproc_t) xdr_remote_storage_vol_get_path_args, (char *) &args, + (xdrproc_t) xdr_remote_storage_vol_get_path_ret, (char *) &ret) == -1) + return NULL; + + /* Caller frees. */ + return ret.name; +} + /*----------------------------------------------------------------------*/ @@ -3096,6 +3739,25 @@ get_nonnull_network (virConnectPtr conn, return virGetNetwork (conn, network.name, BAD_CAST network.uuid); } +static virStoragePoolPtr +get_nonnull_storage_pool (virConnectPtr conn, remote_nonnull_storage_pool pool) +{ + return virGetStoragePool (conn, pool.name, BAD_CAST pool.uuid); +} + +static virStorageVolPtr +get_nonnull_storage_vol (virConnectPtr conn, remote_nonnull_storage_vol vol) +{ + virStoragePoolPtr pool; + virStorageVolPtr ret; + pool = get_nonnull_storage_pool (conn, vol.pool); + if (pool == NULL) + return NULL; + ret = virGetStorageVol (pool, vol.name, BAD_CAST vol.uuid); + virStoragePoolFree(pool); + return ret; +} + /* Make remote_nonnull_domain and remote_nonnull_network. */ static void make_nonnull_domain (remote_nonnull_domain *dom_dst, virDomainPtr dom_src) @@ -3110,6 +3772,21 @@ make_nonnull_network (remote_nonnull_net { net_dst->name = net_src->name; memcpy (net_dst->uuid, net_src->uuid, VIR_UUID_BUFLEN); +} + +static void +make_nonnull_storage_pool (remote_nonnull_storage_pool *pool_dst, virStoragePoolPtr pool_src) +{ + pool_dst->name = pool_src->name; + memcpy (pool_dst->uuid, pool_src->uuid, VIR_UUID_BUFLEN); +} + +static void +make_nonnull_storage_vol (remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_src) +{ + make_nonnull_storage_pool(&vol_dst->pool, vol_src->pool); + vol_dst->name = vol_src->name; + memcpy (vol_dst->uuid, vol_src->uuid, VIR_UUID_BUFLEN); } /*----------------------------------------------------------------------*/ @@ -3193,6 +3870,38 @@ static virNetworkDriver network_driver = .networkSetAutostart = remoteNetworkSetAutostart, }; +static virStorageDriver storage_driver = { + .name = "remote", + .open = remoteStorageOpen, + .close = remoteStorageClose, + .numOfPools = remoteNumOfStoragePools, + .listPools = remoteListStoragePools, + .numOfDefinedPools = remoteNumOfDefinedStoragePools, + .listDefinedPools = remoteListDefinedStoragePools, + .poolLookupByUUID = remoteStoragePoolLookupByUUID, + .poolLookupByName = remoteStoragePoolLookupByName, + .poolCreateXML = remoteStoragePoolCreateXML, + .poolDefineXML = remoteStoragePoolDefineXML, + .poolUndefine = remoteStoragePoolUndefine, + .poolCreate = remoteStoragePoolCreate, + .poolShutdown = remoteStoragePoolShutdown, + .poolDestroy = remoteStoragePoolDestroy, + .poolGetInfo = remoteStoragePoolGetInfo, + .poolGetXMLDesc = remoteStoragePoolDumpXML, + .poolGetAutostart = remoteStoragePoolGetAutostart, + .poolSetAutostart = remoteStoragePoolSetAutostart, + + .poolNumOfVolumes = remoteStoragePoolNumOfVolumes, + .poolListVolumes = remoteStoragePoolListVolumes, + .volLookupByUUID = remoteStorageVolLookupByUUID, + .volLookupByName = remoteStorageVolLookupByName, + .volCreateXML = remoteStorageVolCreateXML, + .volDestroy = remoteStorageVolDestroy, + .volGetInfo = remoteStorageVolGetInfo, + .volGetXMLDesc = remoteStorageVolDumpXML, + .volGetPath = remoteStorageVolGetPath, +}; + static virStateDriver state_driver = { remoteStartup, NULL, @@ -3212,6 +3921,7 @@ remoteRegister (void) { if (virRegisterDriver (&driver) == -1) return -1; if (virRegisterNetworkDriver (&network_driver) == -1) return -1; + if (virRegisterStorageDriver (&storage_driver) == -1) return -1; if (virRegisterStateDriver (&state_driver) == -1) return -1; return 0; -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

This adds a bunch of new virsh commands to expose all the capabilities of the storage APIs For dealing with storage pools: pool-autostart autostart a pool pool-create create a pool from an XML file pool-define define (but don't start) a pool from an XML file pool-destroy destroy a pool pool-dumpxml pool information in XML pool-list list pools pool-name convert a pool UUID to pool name pool-start start a (previously defined) inactive pool pool-undefine undefine an inactive pool pool-uuid convert a pool name to pool UUID NB, there is a 'pool-info' command missing here which would get usage stats. For dealing with volumes within a pool vol-create create a vol from an XML file vol-delete destroy a vol vol-dumpxml vol information in XML vol-list list vols vol-path convert a vol UUID to vol path vol-name convert a vol UUID to vol name vol-uuid convert a vol name to vol UUID NB, there is a 'vol-info' command missing here which would get usage stats. Both the missing methods will be added. See the next mail for example usage of some of these commands. The actual implementation is pretty uninteresting - its basically the same way the corresponding net-XXXX commands are implemented. virsh.c | 989 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 989 insertions(+) diff -r 20927d94d31e src/virsh.c --- a/src/virsh.c Sat Oct 27 18:23:02 2007 -0400 +++ b/src/virsh.c Sat Oct 27 19:15:10 2007 -0400 @@ -252,6 +252,23 @@ static virNetworkPtr vshCommandOptNetwor /* default is lookup by Name and UUID */ #define vshCommandOptNetwork(_ctl, _cmd, _optname, _name) \ vshCommandOptNetworkBy(_ctl, _cmd, _optname, _name, \ + VSH_BYUUID|VSH_BYNAME) + +static virStoragePoolPtr vshCommandOptPoolBy(vshControl * ctl, vshCmd * cmd, + const char *optname, char **name, int flag); + +/* default is lookup by Name and UUID */ +#define vshCommandOptPool(_ctl, _cmd, _optname, _name) \ + vshCommandOptPoolBy(_ctl, _cmd, _optname, _name, \ + VSH_BYUUID|VSH_BYNAME) + +static virStorageVolPtr vshCommandOptVolBy(vshControl * ctl, vshCmd * cmd, + virStoragePoolPtr pool, + const char *optname, char **name, int flag); + +/* default is lookup by Name and UUID */ +#define vshCommandOptVol(_ctl, _cmd, _pool, _optname, _name) \ + vshCommandOptVolBy(_ctl, _cmd, _pool, _optname, _name, \ VSH_BYUUID|VSH_BYNAME) static void vshPrintExtra(vshControl * ctl, const char *format, ...); @@ -2754,6 +2771,881 @@ cmdNetworkUuid(vshControl * ctl, vshCmd return TRUE; } + + + + + + + + + + + + + +/* + * "pool-autostart" command + */ +static vshCmdInfo info_pool_autostart[] = { + {"syntax", "pool-autostart [--disable] <pool>"}, + {"help", gettext_noop("autostart a pool")}, + {"desc", + gettext_noop("Configure a pool to be automatically started at boot.")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_pool_autostart[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("pool name or uuid")}, + {"disable", VSH_OT_BOOL, 0, gettext_noop("disable autostarting")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdPoolAutostart(vshControl * ctl, vshCmd * cmd) +{ + virStoragePoolPtr pool; + char *name; + int autostart; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) + return FALSE; + + autostart = !vshCommandOptBool(cmd, "disable"); + + if (virStoragePoolSetAutostart(pool, autostart) < 0) { + if (autostart) + vshError(ctl, FALSE, _("failed to mark pool %s as autostarted"), + name); + else + vshError(ctl, FALSE,_("failed to unmark pool %s as autostarted"), + name); + virStoragePoolFree(pool); + return FALSE; + } + + if (autostart) + vshPrint(ctl, _("Pool %s marked as autostarted\n"), name); + else + vshPrint(ctl, _("Pool %s unmarked as autostarted\n"), name); + + return TRUE; +} + +/* + * "pool-create" command + */ +static vshCmdInfo info_pool_create[] = { + {"syntax", "create a pool from an XML <file>"}, + {"help", gettext_noop("create a pool from an XML file")}, + {"desc", gettext_noop("Create a pool.")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_pool_create[] = { + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("file containing an XML pool description")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdPoolCreate(vshControl * ctl, vshCmd * cmd) +{ + virStoragePoolPtr pool; + char *from; + int found; + int ret = TRUE; + char *buffer; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + from = vshCommandOptString(cmd, "file", &found); + if (!found) + return FALSE; + + buffer = readFile (ctl, from); + if (buffer == NULL) return FALSE; + + pool = virStoragePoolCreateXML(ctl->conn, buffer); + free (buffer); + + if (pool != NULL) { + vshPrint(ctl, _("Pool %s created from %s\n"), + virStoragePoolGetName(pool), from); + } else { + vshError(ctl, FALSE, _("Failed to create pool from %s"), from); + ret = FALSE; + } + return ret; +} + + +/* + * "pool-define" command + */ +static vshCmdInfo info_pool_define[] = { + {"syntax", "define a pool from an XML <file>"}, + {"help", gettext_noop("define (but don't start) a pool from an XML file")}, + {"desc", gettext_noop("Define a pool.")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_pool_define[] = { + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("file containing an XML pool description")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdPoolDefine(vshControl * ctl, vshCmd * cmd) +{ + virStoragePoolPtr pool; + char *from; + int found; + int ret = TRUE; + char *buffer; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + from = vshCommandOptString(cmd, "file", &found); + if (!found) + return FALSE; + + buffer = readFile (ctl, from); + if (buffer == NULL) return FALSE; + + pool = virStoragePoolDefineXML(ctl->conn, buffer); + free (buffer); + + if (pool != NULL) { + vshPrint(ctl, _("Pool %s defined from %s\n"), + virStoragePoolGetName(pool), from); + } else { + vshError(ctl, FALSE, _("Failed to define pool from %s"), from); + ret = FALSE; + } + return ret; +} + + +/* + * "pool-destroy" command + */ +static vshCmdInfo info_pool_destroy[] = { + {"syntax", "pool-destroy <pool>"}, + {"help", gettext_noop("destroy a pool")}, + {"desc", gettext_noop("Destroy a given pool.")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_pool_destroy[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("pool name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdPoolDestroy(vshControl * ctl, vshCmd * cmd) +{ + virStoragePoolPtr pool; + int ret = TRUE; + char *name; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) + return FALSE; + + if (virStoragePoolDestroy(pool) == 0) { + vshPrint(ctl, _("Pool %s destroyed\n"), name); + } else { + vshError(ctl, FALSE, _("Failed to destroy pool %s"), name); + ret = FALSE; + virStoragePoolFree(pool); + } + + return ret; +} + + +/* + * "pool-dumpxml" command + */ +static vshCmdInfo info_pool_dumpxml[] = { + {"syntax", "pool-dumpxml <pool>"}, + {"help", gettext_noop("pool information in XML")}, + {"desc", gettext_noop("Output the pool information as an XML dump to stdout.")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_pool_dumpxml[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("pool name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdPoolDumpXML(vshControl * ctl, vshCmd * cmd) +{ + virStoragePoolPtr pool; + int ret = TRUE; + char *dump; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) + return FALSE; + + dump = virStoragePoolGetXMLDesc(pool, 0); + if (dump != NULL) { + printf("%s", dump); + free(dump); + } else { + ret = FALSE; + } + + virStoragePoolFree(pool); + return ret; +} + + +/* + * "pool-list" command + */ +static vshCmdInfo info_pool_list[] = { + {"syntax", "pool-list [ --inactive | --all ]"}, + {"help", gettext_noop("list pools")}, + {"desc", gettext_noop("Returns list of pools.")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_pool_list[] = { + {"inactive", VSH_OT_BOOL, 0, gettext_noop("list inactive pools")}, + {"all", VSH_OT_BOOL, 0, gettext_noop("list inactive & active pools")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdPoolList(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED) +{ + int inactive = vshCommandOptBool(cmd, "inactive"); + int all = vshCommandOptBool(cmd, "all"); + int active = !inactive || all ? 1 : 0; + int maxactive = 0, maxinactive = 0, i; + char **activeNames = NULL, **inactiveNames = NULL; + inactive |= all; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (active) { + maxactive = virConnectNumOfStoragePools(ctl->conn); + if (maxactive < 0) { + vshError(ctl, FALSE, _("Failed to list active pools")); + return FALSE; + } + if (maxactive) { + activeNames = vshMalloc(ctl, sizeof(char *) * maxactive); + + if ((maxactive = virConnectListStoragePools(ctl->conn, activeNames, + maxactive)) < 0) { + vshError(ctl, FALSE, _("Failed to list active pools")); + free(activeNames); + return FALSE; + } + + qsort(&activeNames[0], maxactive, sizeof(char *), namesorter); + } + } + if (inactive) { + maxinactive = virConnectNumOfDefinedStoragePools(ctl->conn); + if (maxinactive < 0) { + vshError(ctl, FALSE, _("Failed to list inactive pools")); + if (activeNames) + free(activeNames); + return FALSE; + } + if (maxinactive) { + inactiveNames = vshMalloc(ctl, sizeof(char *) * maxinactive); + + if ((maxinactive = virConnectListDefinedStoragePools(ctl->conn, inactiveNames, maxinactive)) < 0) { + vshError(ctl, FALSE, _("Failed to list inactive pools")); + if (activeNames) + free(activeNames); + free(inactiveNames); + return FALSE; + } + + qsort(&inactiveNames[0], maxinactive, sizeof(char*), namesorter); + } + } + vshPrintExtra(ctl, "%-20s %-10s %-10s\n", _("Name"), _("State"), _("Autostart")); + vshPrintExtra(ctl, "-----------------------------------------\n"); + + for (i = 0; i < maxactive; i++) { + virStoragePoolPtr pool = virStoragePoolLookupByName(ctl->conn, activeNames[i]); + const char *autostartStr; + int autostart = 0; + + /* this kind of work with pools is not atomic operation */ + if (!pool) { + free(activeNames[i]); + continue; + } + + if (virStoragePoolGetAutostart(pool, &autostart) < 0) + autostartStr = _("no autostart"); + else + autostartStr = autostart ? "yes" : "no"; + + vshPrint(ctl, "%-20s %-10s %-10s\n", + virStoragePoolGetName(pool), + _("active"), + autostartStr); + virStoragePoolFree(pool); + free(activeNames[i]); + } + for (i = 0; i < maxinactive; i++) { + virStoragePoolPtr pool = virStoragePoolLookupByName(ctl->conn, inactiveNames[i]); + const char *autostartStr; + int autostart = 0; + + /* this kind of work with pools is not atomic operation */ + if (!pool) { + free(inactiveNames[i]); + continue; + } + + if (virStoragePoolGetAutostart(pool, &autostart) < 0) + autostartStr = _("no autostart"); + else + autostartStr = autostart ? "yes" : "no"; + + vshPrint(ctl, "%-20s %s %s\n", + inactiveNames[i], + _("inactive"), + autostartStr); + + virStoragePoolFree(pool); + free(inactiveNames[i]); + } + if (activeNames) + free(activeNames); + if (inactiveNames) + free(inactiveNames); + return TRUE; +} + + +/* + * "pool-name" command + */ +static vshCmdInfo info_pool_name[] = { + {"syntax", "pool-name <pool>"}, + {"help", gettext_noop("convert a pool UUID to pool name")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_pool_name[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("pool uuid")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdPoolName(vshControl * ctl, vshCmd * cmd) +{ + virStoragePoolPtr pool; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, + VSH_BYUUID))) + return FALSE; + + vshPrint(ctl, "%s\n", virStoragePoolGetName(pool)); + virStoragePoolFree(pool); + return TRUE; +} + + +/* + * "pool-start" command + */ +static vshCmdInfo info_pool_start[] = { + {"syntax", "start <pool>"}, + {"help", gettext_noop("start a (previously defined) inactive pool")}, + {"desc", gettext_noop("Start a pool.")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_pool_start[] = { + {"name", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("name of the inactive pool")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdPoolStart(vshControl * ctl, vshCmd * cmd) +{ + virStoragePoolPtr pool; + int ret = TRUE; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(pool = vshCommandOptPoolBy(ctl, cmd, "name", NULL, VSH_BYNAME))) + return FALSE; + + if (virStoragePoolCreate(pool) == 0) { + vshPrint(ctl, _("Pool %s started\n"), + virStoragePoolGetName(pool)); + } else { + vshError(ctl, FALSE, _("Failed to start pool %s"), + virStoragePoolGetName(pool)); + ret = FALSE; + } + return ret; +} + + +/* + * "pool-undefine" command + */ +static vshCmdInfo info_pool_undefine[] = { + {"syntax", "pool-undefine <pool>"}, + {"help", gettext_noop("undefine an inactive pool")}, + {"desc", gettext_noop("Undefine the configuration for an inactive pool.")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_pool_undefine[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdPoolUndefine(vshControl * ctl, vshCmd * cmd) +{ + virStoragePoolPtr pool; + int ret = TRUE; + char *name; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) + return FALSE; + + if (virStoragePoolUndefine(pool) == 0) { + vshPrint(ctl, _("Pool %s has been undefined\n"), name); + } else { + vshError(ctl, FALSE, _("Failed to undefine pool %s"), name); + ret = FALSE; + } + + return ret; +} + + +/* + * "pool-uuid" command + */ +static vshCmdInfo info_pool_uuid[] = { + {"syntax", "pool-uuid <pool>"}, + {"help", gettext_noop("convert a pool name to pool UUID")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_pool_uuid[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("pool name")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdPoolUuid(vshControl * ctl, vshCmd * cmd) +{ + virStoragePoolPtr pool; + char uuid[VIR_UUID_STRING_BUFLEN]; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, + VSH_BYNAME))) + return FALSE; + + if (virStoragePoolGetUUIDString(pool, uuid) != -1) + vshPrint(ctl, "%s\n", uuid); + else + vshError(ctl, FALSE, _("failed to get pool UUID")); + + return TRUE; +} + + + + +/* + * "vol-create" command + */ +static vshCmdInfo info_vol_create[] = { + {"syntax", "create <pool> <file>"}, + {"help", gettext_noop("create a vol from an XML file")}, + {"desc", gettext_noop("Create a vol.")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_vol_create[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("pool name or uuid")}, + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("file containing an XML vol description")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdVolCreate(vshControl * ctl, vshCmd * cmd) +{ + virStoragePoolPtr pool; + virStorageVolPtr vol; + char *from; + int found; + int ret = TRUE; + char *buffer; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) + return FALSE; + + from = vshCommandOptString(cmd, "file", &found); + if (!found) + return FALSE; + + buffer = readFile (ctl, from); + if (buffer == NULL) return FALSE; + + vol = virStorageVolCreateXML(pool, buffer, 0); + free (buffer); + virStoragePoolFree(pool); + + if (vol != NULL) { + vshPrint(ctl, _("Vol %s created from %s\n"), + virStorageVolGetName(vol), from); + } else { + vshError(ctl, FALSE, _("Failed to create vol from %s"), from); + ret = FALSE; + } + return ret; +} + + +/* + * "vol-destroy" command + */ +static vshCmdInfo info_vol_destroy[] = { + {"syntax", "vol-destroy <pool> <vol>"}, + {"help", gettext_noop("destroy a vol")}, + {"desc", gettext_noop("Destroy a given vol.")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_vol_destroy[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("pool name or uuid")}, + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("vol name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdVolDestroy(vshControl * ctl, vshCmd * cmd) +{ + virStoragePoolPtr pool; + virStorageVolPtr vol; + int ret = TRUE; + char *name; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) + return FALSE; + + if (!(vol = vshCommandOptVol(ctl, cmd, pool, "vol", &name))) { + virStoragePoolFree(pool); + return FALSE; + } + virStoragePoolFree(pool); + + if (virStorageVolDestroy(vol) == 0) { + vshPrint(ctl, _("Vol %s destroyed\n"), name); + } else { + vshError(ctl, FALSE, _("Failed to destroy vol %s"), name); + ret = FALSE; + virStorageVolFree(vol); + } + + return ret; +} + + +/* + * "vol-dumpxml" command + */ +static vshCmdInfo info_vol_dumpxml[] = { + {"syntax", "vol-dumpxml <pool> <vol>"}, + {"help", gettext_noop("vol information in XML")}, + {"desc", gettext_noop("Output the vol information as an XML dump to stdout.")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_vol_dumpxml[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("pool name or uuid")}, + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("vol name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdVolDumpXML(vshControl * ctl, vshCmd * cmd) +{ + virStoragePoolPtr pool; + virStorageVolPtr vol; + int ret = TRUE; + char *dump; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) + return FALSE; + + if (!(vol = vshCommandOptVol(ctl, cmd, pool, "vol", NULL))) + return FALSE; + virStoragePoolFree(pool); + + dump = virStorageVolGetXMLDesc(vol, 0); + if (dump != NULL) { + printf("%s", dump); + free(dump); + } else { + ret = FALSE; + } + + virStorageVolFree(vol); + return ret; +} + + +/* + * "vol-list" command + */ +static vshCmdInfo info_vol_list[] = { + {"syntax", "vol-list <pool>"}, + {"help", gettext_noop("list vols")}, + {"desc", gettext_noop("Returns list of vols.")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_vol_list[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdVolList(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED) +{ + virStoragePoolPtr pool; + int maxactive = 0, i; + char **activeNames = NULL; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) + return FALSE; + + maxactive = virStoragePoolNumOfVolumes(pool); + if (maxactive < 0) { + virStoragePoolFree(pool); + vshError(ctl, FALSE, _("Failed to list active vols")); + return FALSE; + } + if (maxactive) { + activeNames = vshMalloc(ctl, sizeof(char *) * maxactive); + + if ((maxactive = virStoragePoolListVolumes(pool, activeNames, + maxactive)) < 0) { + vshError(ctl, FALSE, _("Failed to list active vols")); + free(activeNames); + virStoragePoolFree(pool); + return FALSE; + } + + qsort(&activeNames[0], maxactive, sizeof(char *), namesorter); + } + vshPrintExtra(ctl, "%-20s %-10s %-10s\n", _("Name"), _("Type"), _("Path")); + vshPrintExtra(ctl, "-----------------------------------------\n"); + + for (i = 0; i < maxactive; i++) { + virStorageVolPtr vol = virStorageVolLookupByName(pool, activeNames[i]); + char *path; + virStorageVolInfo info; + + /* this kind of work with vols is not atomic operation */ + if (!vol) { + free(activeNames[i]); + continue; + } + + if (virStorageVolGetInfo(vol, &info) < 0) { + virStorageVolFree(vol); + continue; + } + + if ((path = virStorageVolGetPath(vol)) == NULL) { + virStorageVolFree(vol); + continue; + } + + + vshPrint(ctl, "%-20s %-10s %-10s\n", + virStorageVolGetName(vol), + info.type == VIR_STORAGE_POOL_FILE ? "file" : "block", + path); + free(path); + virStorageVolFree(vol); + free(activeNames[i]); + } + if (activeNames) + free(activeNames); + virStoragePoolFree(pool); + return TRUE; +} + + +/* + * "vol-name" command + */ +static vshCmdInfo info_vol_name[] = { + {"syntax", "vol-name <pool> <vol>"}, + {"help", gettext_noop("convert a vol UUID to vol name")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_vol_name[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("pool name or uuid")}, + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("vol uuid")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdVolName(vshControl * ctl, vshCmd * cmd) +{ + virStoragePoolPtr pool; + virStorageVolPtr vol; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) + return FALSE; + + if (!(vol = vshCommandOptVolBy(ctl, cmd, pool, "vol", NULL, + VSH_BYUUID))) { + virStoragePoolFree(pool); + return FALSE; + } + virStoragePoolFree(pool); + + vshPrint(ctl, "%s\n", virStorageVolGetName(vol)); + virStorageVolFree(vol); + return TRUE; +} + + + +/* + * "vol-path" command + */ +static vshCmdInfo info_vol_path[] = { + {"syntax", "vol-path <pool> <vol>"}, + {"help", gettext_noop("convert a vol UUID to vol path")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_vol_path[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("pool name or uuid")}, + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("vol uuid")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdVolPath(vshControl * ctl, vshCmd * cmd) +{ + virStoragePoolPtr pool; + virStorageVolPtr vol; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) + return FALSE; + if (!(vol = vshCommandOptVolBy(ctl, cmd, pool, "vol", NULL, + VSH_BYUUID))) { + virStoragePoolFree(pool); + return FALSE; + } + virStoragePoolFree(pool); + + vshPrint(ctl, "%s\n", virStorageVolGetPath(vol)); + virStorageVolFree(vol); + return TRUE; +} + + + + +/* + * "vol-uuid" command + */ +static vshCmdInfo info_vol_uuid[] = { + {"syntax", "vol-uuid <pool> <vol>"}, + {"help", gettext_noop("convert a vol name to vol UUID")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_vol_uuid[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("pool name or uuid")}, + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("vol name")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdVolUuid(vshControl * ctl, vshCmd * cmd) +{ + virStoragePoolPtr pool; + virStorageVolPtr vol; + char uuid[VIR_UUID_STRING_BUFLEN]; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) + return FALSE; + + if (!(vol = vshCommandOptVolBy(ctl, cmd, pool, "vol", NULL, + VSH_BYNAME))) { + virStoragePoolFree(pool); + return FALSE; + } + virStoragePoolFree(pool); + + if (virStorageVolGetUUIDString(vol, uuid) != -1) + vshPrint(ctl, "%s\n", uuid); + else + vshError(ctl, FALSE, _("failed to get vol UUID")); + + return TRUE; +} + + /* @@ -3707,6 +4599,7 @@ static vshCmdDef commands[] = { {"hostname", cmdHostname, NULL, info_hostname}, {"list", cmdList, opts_list, info_list}, {"migrate", cmdMigrate, opts_migrate, info_migrate}, + {"net-autostart", cmdNetworkAutostart, opts_network_autostart, info_network_autostart}, {"net-create", cmdNetworkCreate, opts_network_create, info_network_create}, {"net-define", cmdNetworkDefine, opts_network_define, info_network_define}, @@ -3718,6 +4611,18 @@ static vshCmdDef commands[] = { {"net-undefine", cmdNetworkUndefine, opts_network_undefine, info_network_undefine}, {"net-uuid", cmdNetworkUuid, opts_network_uuid, info_network_uuid}, {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo}, + + {"pool-autostart", cmdPoolAutostart, opts_pool_autostart, info_pool_autostart}, + {"pool-create", cmdPoolCreate, opts_pool_create, info_pool_create}, + {"pool-define", cmdPoolDefine, opts_pool_define, info_pool_define}, + {"pool-destroy", cmdPoolDestroy, opts_pool_destroy, info_pool_destroy}, + {"pool-dumpxml", cmdPoolDumpXML, opts_pool_dumpxml, info_pool_dumpxml}, + {"pool-list", cmdPoolList, opts_pool_list, info_pool_list}, + {"pool-name", cmdPoolName, opts_pool_name, info_pool_name}, + {"pool-start", cmdPoolStart, opts_pool_start, info_pool_start}, + {"pool-undefine", cmdPoolUndefine, opts_pool_undefine, info_pool_undefine}, + {"pool-uuid", cmdPoolUuid, opts_pool_uuid, info_pool_uuid}, + {"quit", cmdQuit, NULL, info_quit}, {"reboot", cmdReboot, opts_reboot, info_reboot}, {"restore", cmdRestore, opts_restore, info_restore}, @@ -3733,6 +4638,15 @@ static vshCmdDef commands[] = { {"ttyconsole", cmdTTYConsole, opts_ttyconsole, info_ttyconsole}, {"undefine", cmdUndefine, opts_undefine, info_undefine}, {"uri", cmdURI, NULL, info_uri}, + + {"vol-create", cmdVolCreate, opts_vol_create, info_vol_create}, + {"vol-delete", cmdVolDestroy, opts_vol_destroy, info_vol_destroy}, + {"vol-dumpxml", cmdVolDumpXML, opts_vol_dumpxml, info_vol_dumpxml}, + {"vol-list", cmdVolList, opts_vol_list, info_vol_list}, + {"vol-path", cmdVolPath, opts_vol_path, info_vol_path}, + {"vol-name", cmdVolName, opts_vol_name, info_vol_name}, + {"vol-uuid", cmdVolUuid, opts_vol_uuid, info_vol_uuid}, + {"vcpuinfo", cmdVcpuinfo, opts_vcpuinfo, info_vcpuinfo}, {"vcpupin", cmdVcpupin, opts_vcpupin, info_vcpupin}, {"version", cmdVersion, NULL, info_version}, @@ -4058,6 +4972,81 @@ vshCommandOptNetworkBy(vshControl * ctl, vshError(ctl, FALSE, _("failed to get network '%s'"), n); return network; +} + +static virStoragePoolPtr +vshCommandOptPoolBy(vshControl * ctl, vshCmd * cmd, const char *optname, + char **name, int flag) +{ + virStoragePoolPtr pool = NULL; + char *n; + + if (!(n = vshCommandOptString(cmd, optname, NULL))) { + vshError(ctl, FALSE, _("undefined pool name")); + return NULL; + } + + vshDebug(ctl, 5, "%s: found option <%s>: %s\n", + cmd->def->name, optname, n); + + if (name) + *name = n; + + /* try it by UUID */ + if (pool==NULL && (flag & VSH_BYUUID) && strlen(n)==VIR_UUID_STRING_BUFLEN-1) { + vshDebug(ctl, 5, "%s: <%s> trying as pool UUID\n", + cmd->def->name, optname); + pool = virStoragePoolLookupByUUIDString(ctl->conn, n); + } + /* try it by NAME */ + if (pool==NULL && (flag & VSH_BYNAME)) { + vshDebug(ctl, 5, "%s: <%s> trying as pool NAME\n", + cmd->def->name, optname); + pool = virStoragePoolLookupByName(ctl->conn, n); + } + + if (!pool) + vshError(ctl, FALSE, _("failed to get pool '%s'"), n); + + return pool; +} + +static virStorageVolPtr +vshCommandOptVolBy(vshControl * ctl, vshCmd * cmd, virStoragePoolPtr pool, + const char *optname, + char **name, int flag) +{ + virStorageVolPtr vol = NULL; + char *n; + + if (!(n = vshCommandOptString(cmd, optname, NULL))) { + vshError(ctl, FALSE, _("undefined vol name")); + return NULL; + } + + vshDebug(ctl, 5, "%s: found option <%s>: %s\n", + cmd->def->name, optname, n); + + if (name) + *name = n; + + /* try it by UUID */ + if (vol==NULL && (flag & VSH_BYUUID) && strlen(n)==VIR_UUID_STRING_BUFLEN-1) { + vshDebug(ctl, 5, "%s: <%s> trying as vol UUID\n", + cmd->def->name, optname); + vol = virStorageVolLookupByUUIDString(pool, n); + } + /* try it by NAME */ + if (vol==NULL && (flag & VSH_BYNAME)) { + vshDebug(ctl, 5, "%s: <%s> trying as vol NAME\n", + cmd->def->name, optname); + vol = virStorageVolLookupByName(pool, n); + } + + if (!vol) + vshError(ctl, FALSE, _("failed to get vol '%s'"), n); + + return vol; } /* -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

On Mon, Oct 29, 2007 at 03:59:39AM +0000, Daniel P. Berrange wrote:
This adds a bunch of new virsh commands to expose all the capabilities of the storage APIs
For dealing with storage pools:
pool-autostart autostart a pool pool-create create a pool from an XML file pool-define define (but don't start) a pool from an XML file pool-destroy destroy a pool pool-dumpxml pool information in XML pool-list list pools pool-name convert a pool UUID to pool name pool-start start a (previously defined) inactive pool pool-undefine undefine an inactive pool pool-uuid convert a pool name to pool UUID
NB, there is a 'pool-info' command missing here which would get usage stats.
For dealing with volumes within a pool
vol-create create a vol from an XML file vol-delete destroy a vol vol-dumpxml vol information in XML vol-list list vols vol-path convert a vol UUID to vol path vol-name convert a vol UUID to vol name vol-uuid convert a vol name to vol UUID
NB, there is a 'vol-info' command missing here which would get usage stats. Both the missing methods will be added.
See the next mail for example usage of some of these commands.
The actual implementation is pretty uninteresting - its basically the same way the corresponding net-XXXX commands are implemented.
Sounds fine to me ! Daniel -- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard@redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/

This patch introduces the main storage driver. This is quite a large driver and so is split across several modules - storage_driver.c/.h - implements the public API calls glueing together the storage object handling, to the storage backend impls - storage_conf.c/.h - routines for parsing & formating XML, and managing the in-memory structs representing the storage objects. - storage_backend.h - defines a contract for storage pool backends - storage_backend_XXX.c - one file each for disk, iscsi, lvm, dir storage pools The storage_driver & storage_conf files are both structured to follow the same style as the QEMU network driver. In fact the storage_conf file has many routines that are 100% cut+paste from the QEMU driver. To address this obvious flaw I will pull some of these routines out into separate modules which can be easily shared between drivers. These are mostly convenience routines for dealing with file I/O making directories & symlink comparisons. At this time all the storage backends are empty stubs, except for the local directory driver. Implementing new backends requires about 6-8 methods to be provided - significantly less than the number of methods in the public libvirt storage API, since most are handled higher up the stack. The directory pool impl is sufficient to manage '/var/lib/xen/images' using raw files only. As an example, lets create a pool to manage xen images... # cat > pool-xen.xml <<EOF <pool type="dir"> <name>xenimages</name> <target dir="/var/lib/xen/images"/> <permissions> <mode>0700</mode> <owner>0</owner> <group>0</group> </permissions> </pool> EOF # virsh pool-define pool-xen.xml # virsh pool-list --all Name State Autostart ----------------------------------------- xenimages inactive no Until a pool is started you can't do much with it. Starting a pool takes care of mounting a disk, logging into the iSCSI server, or activating the LVM volume. In the case of a local dir, activating it merely loads the volumes from disk # virsh pool-autostart xenimages # virsh pool-start xenimages # virsh pool-list Name State Autostart ----------------------------------------- xenimages active yes Now we can list volumes available in the pool... # virsh vol-list xenimages Name Type Path ----------------------------------------- None there yet, so lets create one. Notice how can we create sparse vs fully-allocate images by tweaking capacity vs allocation in the XML. The permissions should inherit from the pool, but currently they're compulsory. # cat > vol-demo.xml <<EOF <volume type="file"> <name>demo</name> <capacity>10000000000000</capacity> <allocation>100000</allocation> <permissions> <mode>0700</mode> <owner>0</owner> <group>0</group> </permissions> </volume> EOF # virsh vol-create xenimages vol-demo.xml # virsh vol-list xenimages Name Type Path ----------------------------------------- demo file /var/lib/xen/images/demo And lets check the file was actually created... # ls -lsh /var/lib/xen/images total 108K 108K -rwx------ 1 root root 1.3G Oct 28 22:32 demo There's a bunch more virsh commands, but that's the interesting ones all covered. b/src/storage_backend.h | 57 + b/src/storage_backend_disk.c | 73 ++ b/src/storage_backend_disk.h | 29 b/src/storage_backend_fs.c | 258 ++++++++ b/src/storage_backend_fs.h | 30 b/src/storage_backend_iscsi.c | 75 ++ b/src/storage_backend_iscsi.h | 29 b/src/storage_backend_lvm.c | 74 ++ b/src/storage_backend_lvm.h | 29 b/src/storage_conf.c | 1333 ++++++++++++++++++++++++++++++++++++++++++ b/src/storage_conf.h | 222 ++++++ b/src/storage_driver.c | 996 +++++++++++++++++++++++++++++++ b/src/storage_driver.h | 6 include/libvirt/virterror.h | 3 src/Makefile.am | 7 src/virterror.c | 33 + 16 files changed, 3254 insertions(+) diff -r f57805779ece include/libvirt/virterror.h --- a/include/libvirt/virterror.h Sun Oct 28 22:45:04 2007 -0400 +++ b/include/libvirt/virterror.h Sun Oct 28 22:45:04 2007 -0400 @@ -52,6 +52,7 @@ typedef enum { VIR_FROM_TEST, /* Error from test driver */ VIR_FROM_REMOTE, /* Error from remote driver */ VIR_FROM_OPENVZ, /* Error from OpenVZ driver */ + VIR_FROM_STORAGE, /* Error from Storage driver */ } virErrorDomain; @@ -132,6 +133,8 @@ typedef enum { VIR_ERR_INVALID_STORAGE_POOL, /* invalid storage pool object */ VIR_ERR_INVALID_STORAGE_VOL, /* invalid storage vol object */ VIR_WAR_NO_STORAGE, /* failed to start storage */ + VIR_ERR_NO_STORAGE_POOL, /* storage pool not found */ + VIR_ERR_NO_STORAGE_VOL, /* storage pool not found */ } virErrorNumber; /** diff -r f57805779ece src/Makefile.am --- a/src/Makefile.am Sun Oct 28 22:45:04 2007 -0400 +++ b/src/Makefile.am Sun Oct 28 22:45:04 2007 -0400 @@ -57,6 +57,13 @@ CLIENT_SOURCES = \ openvz_conf.c openvz_conf.h \ openvz_driver.c openvz_driver.h \ nodeinfo.h nodeinfo.c \ + storage_conf.h storage_conf.c \ + storage_driver.h storage_driver.c \ + storage_backend.h \ + storage_backend_iscsi.h storage_backend_iscsi.c \ + storage_backend_disk.h storage_backend_disk.c \ + storage_backend_fs.h storage_backend_fs.c \ + storage_backend_lvm.h storage_backend_lvm.c \ util.c util.h SERVER_SOURCES = \ diff -r f57805779ece src/storage_backend.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/storage_backend.h Sun Oct 28 22:45:04 2007 -0400 @@ -0,0 +1,57 @@ +#ifndef __VIR_STORAGE_BACKEND_H__ +#define __VIR_STORAGE_BACKEND_H__ + +#include <libvirt/libvirt.h> +#include "storage_conf.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + typedef int (*virStoragePoolBackendCreate)(virStoragePoolObjPtr pool); + typedef int (*virStoragePoolBackendStart)(virStoragePoolObjPtr pool); + typedef int (*virStoragePoolBackendStop)(virStoragePoolObjPtr pool); + typedef int (*virStoragePoolBackendDestroy)(virStoragePoolObjPtr pool); + + typedef int (*virStoragePoolBackendGetInfo)(virStoragePoolObjPtr pool, virStoragePoolInfoPtr info); + typedef int (*virStoragePoolBackendVolCreate)(virStoragePoolObjPtr pool, virStorageVolDefPtr vol); + typedef int (*virStoragePoolBackendVolDelete)(virStoragePoolObjPtr pool, virStorageVolDefPtr vol); + typedef int (*virStoragePoolBackendVolGetInfo)(virStoragePoolObjPtr pool, virStorageVolDefPtr vol, virStorageVolInfoPtr info); + + + typedef struct _virStoragePoolBackend virStoragePoolBackend; + typedef virStoragePoolBackend *virStoragePoolBackendPtr; + + struct _virStoragePoolBackend { + int type; + + virStoragePoolBackendCreate create; + virStoragePoolBackendStart start; + virStoragePoolBackendStop stop; + virStoragePoolBackendDestroy destroy; + + virStoragePoolBackendGetInfo getInfo; + virStoragePoolBackendVolCreate volCreate; + virStoragePoolBackendVolDelete volDelete; + virStoragePoolBackendVolGetInfo volGetInfo; + }; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __VIR_STORAGE_BACKEND_H__ */ + +/* + * vim: set tabstop=4: + * vim: set shiftwidth=4: + * vim: set expandtab: + */ +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -r f57805779ece src/storage_backend_disk.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/storage_backend_disk.c Sun Oct 28 22:45:04 2007 -0400 @@ -0,0 +1,73 @@ +#include "storage_backend_disk.h" + + +static int virStoragePoolBackendDiskCreate(virStoragePoolObjPtr pool) +{ + /* create partition table, if not initialized */ + return -1; +} +static int virStoragePoolBackendDiskStart(virStoragePoolObjPtr pool) +{ + /* partition names */ + return -1; +} +static int virStoragePoolBackendDiskStop(virStoragePoolObjPtr pool) +{ + return -1; +} +static int virStoragePoolBackendDiskDestroy(virStoragePoolObjPtr pool) +{ + return -1; +} + +static int virStoragePoolBackendDiskGetInfo(virStoragePoolObjPtr pool, virStoragePoolInfoPtr info) +{ + /* block size */ + return -1; +} + + +static int virStoragePoolBackendDiskVolCreate(virStoragePoolObjPtr pool, virStorageVolDefPtr vol) +{ + /* Add a partition */ + return -1; +} +static int virStoragePoolBackendDiskVolDelete(virStoragePoolObjPtr pool, virStorageVolDefPtr vol) +{ + /* delete a partition */ + return -1; +} +static int virStoragePoolBackendDiskVolGetInfo(virStoragePoolObjPtr pool, virStorageVolDefPtr vol, virStorageVolInfoPtr info) +{ + /* partition size */ + return -1; +} + + +virStoragePoolBackend virStoragePoolBackendDisk = { + .type = VIR_STORAGE_POOL_DISK, + + .create = virStoragePoolBackendDiskCreate, + .start = virStoragePoolBackendDiskStart, + .stop = virStoragePoolBackendDiskStop, + .destroy = virStoragePoolBackendDiskDestroy, + + .getInfo = virStoragePoolBackendDiskGetInfo, + .volCreate = virStoragePoolBackendDiskVolCreate, + .volDelete = virStoragePoolBackendDiskVolDelete, + .volGetInfo = virStoragePoolBackendDiskVolGetInfo, +}; + +/* + * vim: set tabstop=4: + * vim: set shiftwidth=4: + * vim: set expandtab: + */ +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -r f57805779ece src/storage_backend_disk.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/storage_backend_disk.h Sun Oct 28 22:45:04 2007 -0400 @@ -0,0 +1,29 @@ +#ifndef __VIR_STORAGE_BACKEND_DISK_H__ +#define __VIR_STORAGE_BACKEND_DISK_H__ + +#include "storage_backend.h" + +#ifdef __cplusplus +extern "C" { +#endif + + extern virStoragePoolBackend virStoragePoolBackendDisk; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __VIR_STORAGE_BACKEND_DISK_H__ */ + +/* + * vim: set tabstop=4: + * vim: set shiftwidth=4: + * vim: set expandtab: + */ +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -r f57805779ece src/storage_backend_fs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/storage_backend_fs.c Sun Oct 28 22:45:04 2007 -0400 @@ -0,0 +1,258 @@ +#include <sys/statvfs.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +#include "storage_backend_fs.h" + + +static int virStoragePoolBackendFileSystemCreate(virStoragePoolObjPtr pool) +{ + /* format the block device, if not already formatted */ + return -1; +} +static int virStoragePoolBackendFileSystemStart(virStoragePoolObjPtr pool) +{ + DIR *dir; + struct dirent *ent; + + if (virStorageEnsureDir(pool->def->target) < 0) { + virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, "cannot statvfs path '%s': %d (%s)", + pool->def->target, errno, strerror(errno)); + return -1; + } + + /* XXX mount volume for FS */ + + if (!(dir = opendir(pool->def->target))) { + virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, "cannot open path '%s': %d (%s)", + pool->def->target, errno, strerror(errno)); + return -1; + } + + while ((ent = readdir(dir)) != NULL) { + virStorageVolDefPtr vol; + struct stat sb; + + if (ent->d_name[0] == '.') + continue; + + vol = calloc(1, sizeof(virStorageVolDef)); + if (vol == NULL) + goto no_memory; + vol->name = strdup(ent->d_name); + if (vol->name == NULL) + goto no_memory; + /* XXX other format probes */ + vol->format = VIR_STORAGE_VOL_RAW; + vol->target = malloc(strlen(pool->def->target) + 1 + strlen(vol->name) + 1); + if (vol->target == NULL) + goto no_memory; + strcpy(vol->target, pool->def->target); + strcat(vol->target, "/"); + strcat(vol->target, vol->name); + + if (stat(vol->target, &sb) < 0) { + virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, "cannot stat file '%s': %d (%s)", + vol->target, errno, strerror(errno)); + goto failed; + } + + vol->capacity = sb.st_size; + vol->allocation = (unsigned long long)sb.st_blocks * (unsigned long long)512; + vol->perms.mode = sb.st_mode; + vol->perms.uid = sb.st_uid; + vol->perms.gid = sb.st_gid; + + vol->next = pool->volumes; + pool->volumes = vol; + pool->nvolumes++; + continue; + + no_memory: + virStorageReportError(NULL, VIR_ERR_NO_MEMORY, "volume"); + failed: + if (vol->name) free(vol->name); + if (vol->target) free(vol->target); + free(vol); + goto cleanup; + } + closedir(dir); + return 0; + + cleanup: + closedir(dir); + return -1; +} + +static int virStoragePoolBackendFileSystemStop(virStoragePoolObjPtr pool) +{ + virStorageVolDefPtr vol; + + vol = pool->volumes; + while (vol) { + virStorageVolDefPtr next = vol->next; + virStorageVolDefFree(vol); + vol = next; + } + pool->volumes = NULL; + pool->nvolumes = 0; + + /* XXX Unmount the disk */ + return 0; +} +static int virStoragePoolBackendFileSystemDestroy(virStoragePoolObjPtr pool) +{ + /* nada */ + return -1; +} + + +static int virStoragePoolBackendFileSystemGetInfo(virStoragePoolObjPtr pool, virStoragePoolInfoPtr info) +{ + struct statvfs sb; + + if (statvfs(pool->def->target, &sb) < 0) { + virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, "cannot statvfs path '%s': %d (%s)", + pool->def->target, errno, strerror(errno)); + return -1; + } + + if (virStoragePoolObjIsActive(pool)) + info->state = VIR_STORAGE_POOL_ACTIVE; + else + info->state = VIR_STORAGE_POOL_INACTIVE; + + info->capacity = (unsigned long long)sb.f_frsize * (unsigned long long)sb.f_blocks; + info->allocation = info->capacity - ((unsigned long long)sb.f_bfree * (unsigned long long)sb.f_bsize); + + return -1; +} + +static int virStoragePoolBackendFileSystemVolCreate(virStoragePoolObjPtr pool, virStorageVolDefPtr vol) +{ + int fd; + + vol->target = malloc(strlen(pool->def->target) + 1 + strlen(vol->name) + 1); + if (vol->target == NULL) { + virStorageReportError(NULL, VIR_ERR_NO_MEMORY, "target"); + return -1; + } + strcpy(vol->target, pool->def->target); + strcat(vol->target, "/"); + strcat(vol->target, vol->name); + + if ((fd = open(vol->target, O_WRONLY | O_CREAT, vol->perms.mode)) < 0) { + virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, "cannot create path '%s': %d (%s)", + vol->target, errno, strerror(errno)); + return -1; + } + + /* Pre-allocate any data if requested */ + if (vol->allocation) { + unsigned long long remain = vol->allocation; + char zeros[4096]; + memset(zeros, 0, sizeof(zeros)); + while (remain) { + int bytes = sizeof(zeros); + if (bytes > remain) + bytes = remain; + if ((bytes = write(fd, zeros, bytes)) < 0) { + virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, "cannot fill file '%s': %d (%s)", + vol->target, errno, strerror(errno)); + close(fd); + return -1; + } + remain -= bytes; + } + } + + /* Now seek to final size, possibly making the file sparse */ + if (ftruncate(fd, vol->capacity) < 0) { + virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, "cannot extend file '%s': %d (%s)", + vol->target, errno, strerror(errno)); + close(fd); + return -1; + } + + if (close(fd) < 0) { + virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, "cannot close file '%s': %d (%s)", + vol->target, errno, strerror(errno)); + return -1; + } + + return 0; +} + +static int virStoragePoolBackendFileSystemVolDelete(virStoragePoolObjPtr pool, virStorageVolDefPtr vol) +{ + if (unlink(vol->target) < 0) { + virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, "cannot unlink file '%s': %d (%s)", + vol->target, errno, strerror(errno)); + return -1; + } + return 0; +} + +static int virStoragePoolBackendFileSystemVolGetInfo(virStoragePoolObjPtr pool, virStorageVolDefPtr vol, virStorageVolInfoPtr info) +{ + struct stat sb; + + if (stat(vol->target, &sb) < 0) { + virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, "cannot stat file '%s': %d (%s)", + vol->target, errno, strerror(errno)); + return -1; + } + + info->type = VIR_STORAGE_POOL_FILE; + info->capacity = sb.st_size; + info->allocation = (unsigned long long)sb.st_blocks * (unsigned long long)512; + + return 0; +} + + +virStoragePoolBackend virStoragePoolBackendFileSystem = { + .type = VIR_STORAGE_POOL_FS, + + .create = virStoragePoolBackendFileSystemCreate, + .start = virStoragePoolBackendFileSystemStart, + .stop = virStoragePoolBackendFileSystemStop, + .destroy = virStoragePoolBackendFileSystemDestroy, + + .getInfo = virStoragePoolBackendFileSystemGetInfo, + .volCreate = virStoragePoolBackendFileSystemVolCreate, + .volDelete = virStoragePoolBackendFileSystemVolDelete, + .volGetInfo = virStoragePoolBackendFileSystemVolGetInfo, +}; + +virStoragePoolBackend virStoragePoolBackendDirectory = { + .type = VIR_STORAGE_POOL_DIR, + + .create = virStoragePoolBackendFileSystemCreate, + .start = virStoragePoolBackendFileSystemStart, + .stop = virStoragePoolBackendFileSystemStop, + .destroy = virStoragePoolBackendFileSystemDestroy, + + .getInfo = virStoragePoolBackendFileSystemGetInfo, + .volCreate = virStoragePoolBackendFileSystemVolCreate, + .volDelete = virStoragePoolBackendFileSystemVolDelete, + .volGetInfo = virStoragePoolBackendFileSystemVolGetInfo, +}; + +/* + * vim: set tabstop=4: + * vim: set shiftwidth=4: + * vim: set expandtab: + */ +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -r f57805779ece src/storage_backend_fs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/storage_backend_fs.h Sun Oct 28 22:45:04 2007 -0400 @@ -0,0 +1,30 @@ +#ifndef __VIR_STORAGE_BACKEND_FS_H__ +#define __VIR_STORAGE_BACKEND_FS_H__ + +#include "storage_backend.h" + +#ifdef __cplusplus +extern "C" { +#endif + + extern virStoragePoolBackend virStoragePoolBackendFileSystem; + extern virStoragePoolBackend virStoragePoolBackendDirectory; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __VIR_STORAGE_BACKEND_FS_H__ */ + +/* + * vim: set tabstop=4: + * vim: set shiftwidth=4: + * vim: set expandtab: + */ +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -r f57805779ece src/storage_backend_iscsi.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/storage_backend_iscsi.c Sun Oct 28 22:45:04 2007 -0400 @@ -0,0 +1,75 @@ +#include "storage_backend_iscsi.h" + + +static int virStoragePoolBackendISCSICreate(virStoragePoolObjPtr pool) +{ + /* nada */ + return -1; +} +static int virStoragePoolBackendISCSIStart(virStoragePoolObjPtr pool) +{ + /* login to iscsi server */ + /* list LUNs for target */ + return -1; +} +static int virStoragePoolBackendISCSIStop(virStoragePoolObjPtr pool) +{ + /* logout of iscsi server */ + return -1; +} +static int virStoragePoolBackendISCSIDestroy(virStoragePoolObjPtr pool) +{ + /* nada */ + return -1; +} + +static int virStoragePoolBackendISCSIGetInfo(virStoragePoolObjPtr pool, virStoragePoolInfoPtr info) +{ + /* target size - unavailable */ + return -1; +} + +static int virStoragePoolBackendISCSIVolCreate(virStoragePoolObjPtr pool, virStorageVolDefPtr vol) +{ + /* Nada */ + return -1; +} +static int virStoragePoolBackendISCSIVolDelete(virStoragePoolObjPtr pool, virStorageVolDefPtr vol) +{ + /* Nada */ + return -1; +} +static int virStoragePoolBackendISCSIVolGetInfo(virStoragePoolObjPtr pool, virStorageVolDefPtr vol, virStorageVolInfoPtr info) +{ + /* block device size */ + return -1; +} + + +virStoragePoolBackend virStoragePoolBackendISCSI = { + .type = VIR_STORAGE_POOL_ISCSI, + + .create = virStoragePoolBackendISCSICreate, + .start = virStoragePoolBackendISCSIStart, + .stop = virStoragePoolBackendISCSIStop, + .destroy = virStoragePoolBackendISCSIDestroy, + + .getInfo = virStoragePoolBackendISCSIGetInfo, + .volCreate = virStoragePoolBackendISCSIVolCreate, + .volDelete = virStoragePoolBackendISCSIVolDelete, + .volGetInfo = virStoragePoolBackendISCSIVolGetInfo, +}; + +/* + * vim: set tabstop=4: + * vim: set shiftwidth=4: + * vim: set expandtab: + */ +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -r f57805779ece src/storage_backend_iscsi.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/storage_backend_iscsi.h Sun Oct 28 22:45:04 2007 -0400 @@ -0,0 +1,29 @@ +#ifndef __VIR_STORAGE_BACKEND_ISCSI_H__ +#define __VIR_STORAGE_BACKEND_ISCSI_H__ + +#include "storage_backend.h" + +#ifdef __cplusplus +extern "C" { +#endif + + extern virStoragePoolBackend virStoragePoolBackendISCSI; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __VIR_STORAGE_BACKEND_ISCSI_H__ */ + +/* + * vim: set tabstop=4: + * vim: set shiftwidth=4: + * vim: set expandtab: + */ +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -r f57805779ece src/storage_backend_lvm.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/storage_backend_lvm.c Sun Oct 28 22:45:04 2007 -0400 @@ -0,0 +1,74 @@ +#include "storage_backend_lvm.h" + + +static int virStoragePoolBackendLVMCreate(virStoragePoolObjPtr pool) +{ + /* vgcreate */ + return -1; +} +static int virStoragePoolBackendLVMStart(virStoragePoolObjPtr pool) +{ + /* vgchange -y */ + return -1; +} +static int virStoragePoolBackendLVMStop(virStoragePoolObjPtr pool) +{ + /* vgchange -n */ + return -1; +} +static int virStoragePoolBackendLVMDestroy(virStoragePoolObjPtr pool) +{ + /* vgdestroy */ + return -1; +} + +static int virStoragePoolBackendLVMGetInfo(virStoragePoolObjPtr pool, virStoragePoolInfoPtr info) +{ + /* target size - unavailable */ + return -1; +} + +static int virStoragePoolBackendLVMVolCreate(virStoragePoolObjPtr pool, virStorageVolDefPtr vol) +{ + /* lvcreate */ + return -1; +} +static int virStoragePoolBackendLVMVolDelete(virStoragePoolObjPtr pool, virStorageVolDefPtr vol) +{ + /* lvdestroy */ + return -1; +} +static int virStoragePoolBackendLVMVolGetInfo(virStoragePoolObjPtr pool, virStorageVolDefPtr vol, virStorageVolInfoPtr info) +{ + /* lvdisplay */ + return -1; +} + + +virStoragePoolBackend virStoragePoolBackendLVM = { + .type = VIR_STORAGE_POOL_LVM, + + .create = virStoragePoolBackendLVMCreate, + .start = virStoragePoolBackendLVMStart, + .stop = virStoragePoolBackendLVMStop, + .destroy = virStoragePoolBackendLVMDestroy, + + .getInfo = virStoragePoolBackendLVMGetInfo, + .volCreate = virStoragePoolBackendLVMVolCreate, + .volDelete = virStoragePoolBackendLVMVolDelete, + .volGetInfo = virStoragePoolBackendLVMVolGetInfo, +}; + +/* + * vim: set tabstop=4: + * vim: set shiftwidth=4: + * vim: set expandtab: + */ +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -r f57805779ece src/storage_backend_lvm.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/storage_backend_lvm.h Sun Oct 28 22:45:04 2007 -0400 @@ -0,0 +1,29 @@ +#ifndef __VIR_STORAGE_BACKEND_LVM_H__ +#define __VIR_STORAGE_BACKEND_LVM_H__ + +#include "storage_backend.h" + +#ifdef __cplusplus +extern "C" { +#endif + + extern virStoragePoolBackend virStoragePoolBackendLVM; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __VIR_STORAGE_BACKEND_LVM_H__ */ + +/* + * vim: set tabstop=4: + * vim: set shiftwidth=4: + * vim: set expandtab: + */ +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -r f57805779ece src/storage_conf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/storage_conf.c Sun Oct 28 22:45:04 2007 -0400 @@ -0,0 +1,1333 @@ + +#include <libvirt/libvirt.h> +#include <libvirt/virterror.h> + +#include <libxml/parser.h> +#include <libxml/tree.h> +#include <libxml/xpath.h> +#include <libxml/uri.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 "storage_conf.h" +#include "xml.h" +#include "uuid.h" +#include "buf.h" + +#define virStorageLog(msg...) fprintf(stderr, msg) + +void +virStorageReportError(virConnectPtr conn, int code, const char *fmt, ...) { + va_list args; + char errorMessage[1024]; + + if (fmt) { + va_start(args, fmt); + vsnprintf(errorMessage, sizeof(errorMessage)-1, fmt, args); + va_end(args); + } else { + errorMessage[0] = '\0'; + } + virStorageLog("%s", errorMessage); + __virRaiseError(conn, NULL, NULL, VIR_FROM_STORAGE, code, VIR_ERR_ERROR, + NULL, NULL, NULL, -1, -1, errorMessage); +} + +/* Build up a fully qualfiied path for a config file to be + * associated with a persistent guest or network */ +static int +virStorageMakeConfigPath(const char *configDir, + const char *name, + const char *ext, + char *buf, + unsigned int buflen) { + if ((strlen(configDir) + 1 + strlen(name) + (ext ? strlen(ext) : 0) + 1) > buflen) + return -1; + + strcpy(buf, configDir); + strcat(buf, "/"); + strcat(buf, name); + if (ext) + strcat(buf, ext); + return 0; +} + +int +virStorageEnsureDir(const char *path) +{ + struct stat st; + char parent[PATH_MAX]; + char *p; + int err; + + if (stat(path, &st) >= 0) + return 0; + + strncpy(parent, path, PATH_MAX); + parent[PATH_MAX - 1] = '\0'; + + if (!(p = strrchr(parent, '/'))) + return EINVAL; + + if (p == parent) + return EPERM; + + *p = '\0'; + + if ((err = virStorageEnsureDir(parent))) + return err; + + if (mkdir(path, 0777) < 0 && errno != EEXIST) + return errno; + + return 0; +} + + +static int +compareFileToNameSuffix(const char *file, + const char *name, + const char *suffix) { + int filelen = strlen(file); + int namelen = strlen(name); + int suffixlen = strlen(suffix); + + if (filelen == (namelen + suffixlen) && + !strncmp(file, name, namelen) && + !strncmp(file + namelen, suffix, suffixlen)) + return 1; + else + return 0; +} + +static int +hasSuffix(const char *str, + const char *suffix) +{ + int len = strlen(str); + int suffixlen = strlen(suffix); + + if (len < suffixlen) + return 0; + + return strcmp(str + len - suffixlen, suffix) == 0; +} + +static int +checkLinkPointsTo(const char *checkLink, + const char *checkDest) +{ + char dest[PATH_MAX]; + char real[PATH_MAX]; + char checkReal[PATH_MAX]; + int n; + int passed = 0; + + /* read the link destination */ + if ((n = readlink(checkLink, dest, PATH_MAX)) < 0) { + switch (errno) { + case ENOENT: + case ENOTDIR: + break; + + case EINVAL: + virStorageLog("Autostart file '%s' is not a symlink", + checkLink); + break; + + default: + virStorageLog("Failed to read autostart symlink '%s': %s", + checkLink, strerror(errno)); + break; + } + + goto failed; + } else if (n >= PATH_MAX) { + virStorageLog("Symlink '%s' contents too long to fit in buffer", + checkLink); + goto failed; + } + + dest[n] = '\0'; + + /* make absolute */ + if (dest[0] != '/') { + char dir[PATH_MAX]; + char tmp[PATH_MAX]; + char *p; + + strncpy(dir, checkLink, PATH_MAX); + dir[PATH_MAX] = '\0'; + + if (!(p = strrchr(dir, '/'))) { + virStorageLog("Symlink path '%s' is not absolute", checkLink); + goto failed; + } + + if (p == dir) /* handle unlikely root dir case */ + p++; + + *p = '\0'; + + if (virStorageMakeConfigPath(dir, dest, NULL, tmp, PATH_MAX) < 0) { + virStorageLog("Path '%s/%s' is too long", dir, dest); + goto failed; + } + + strncpy(dest, tmp, PATH_MAX); + dest[PATH_MAX] = '\0'; + } + + /* canonicalize both paths */ + if (!realpath(dest, real)) { + virStorageLog("Failed to expand path '%s' :%s", + dest, strerror(errno)); + strncpy(real, dest, PATH_MAX); + real[PATH_MAX] = '\0'; + } + + if (!realpath(checkDest, checkReal)) { + virStorageLog("Failed to expand path '%s' :%s", + checkDest, strerror(errno)); + strncpy(checkReal, checkDest, PATH_MAX); + checkReal[PATH_MAX] = '\0'; + } + + /* compare */ + if (strcmp(checkReal, real) != 0) { + virStorageLog("Autostart link '%s' is not a symlink to '%s', ignoring", + checkLink, checkReal); + goto failed; + } + + passed = 1; + + failed: + return passed; +} + +static int +virStorageReadFile(const char *path, + char *buf, + int maxlen) { + FILE *fh; + struct stat st; + int ret = 0; + + if (!(fh = fopen(path, "r"))) { + virStorageLog("Failed to open file '%s': %s", + path, strerror(errno)); + goto error; + } + + if (fstat(fileno(fh), &st) < 0) { + virStorageLog("Failed to stat file '%s': %s", + path, strerror(errno)); + goto error; + } + + if (S_ISDIR(st.st_mode)) { + virStorageLog("Ignoring directory '%s' - clearly not a config file", path); + goto error; + } + + if (st.st_size >= maxlen) { + virStorageLog("File '%s' is too large", path); + goto error; + } + + if ((ret = fread(buf, st.st_size, 1, fh)) != 1) { + virStorageLog("Failed to read config file '%s': %s", + path, strerror(errno)); + goto error; + } + + buf[st.st_size] = '\0'; + + ret = 1; + + error: + if (fh) + fclose(fh); + + return ret; +} + + +void virStorageVolDefFree(virStorageVolDefPtr def) { + if (def->name) + free(def->name); + + if (def->format == VIR_STORAGE_VOL_QCOW2 && + def->formatOpts.qcow2.passwd) { + free(def->formatOpts.qcow2.passwd); + } + + if (def->target) + free(def->target); + if (def->perms.label) + free(def->perms.label); + free(def); +} + +void virStoragePoolDefFree(virStoragePoolDefPtr def) { + if (def->name) + free(def->name); + + if (def->srcType == VIR_STORAGE_POOL_SRC_REMOTE) { + if (def->src.remote.hostname) + free(def->src.remote.hostname); + if (def->src.remote.export) + free(def->src.remote.export); + } else { + int i; + for (i = 0 ; i < def->src.local.ndev ; i++) { + if (def->src.local.devs[i]) + free(def->src.local.devs[i]); + } + free(def->src.local.devs); + } + + if (def->target) + free(def->target); + if (def->perms.label) + free(def->perms.label); + free(def); +} + + +void virStoragePoolObjFree(virStoragePoolObjPtr obj) { + if (obj->def) + virStoragePoolDefFree(obj->def); + if (obj->newDef) + virStoragePoolDefFree(obj->newDef); + + free(obj->configFile); + free(obj->autostartLink); + free(obj); +} + +void virStoragePoolObjRemove(virStorageDriverStatePtr driver, + virStoragePoolObjPtr pool) +{ + virStoragePoolObjPtr prev = NULL, curr; + + curr = driver->pools; + while (curr != pool) { + prev = curr; + curr = curr->next; + } + + if (curr) { + if (prev) + prev->next = curr->next; + else + driver->pools = curr->next; + + driver->ninactivePools--; + } + + virStoragePoolObjFree(pool); +} + + +static int virStoragePoolDefTypeFromString(const char *type) { + if (STREQ(type, "dir")) + return VIR_STORAGE_POOL_DIR; + else if (STREQ(type, "fs")) + return VIR_STORAGE_POOL_FS; + else if (STREQ(type, "lvm")) + return VIR_STORAGE_POOL_LVM; + else if (STREQ(type, "disk")) + return VIR_STORAGE_POOL_DISK; + else if (STREQ(type, "iscsi")) + return VIR_STORAGE_POOL_ISCSI; + return -1; +} + +static const char *virStoragePoolDefTypeToString(int type) { + switch (type) { + case VIR_STORAGE_POOL_DIR: + return "dir"; + case VIR_STORAGE_POOL_FS: + return "fs"; + case VIR_STORAGE_POOL_LVM: + return "lvm"; + case VIR_STORAGE_POOL_DISK: + return "disk"; + case VIR_STORAGE_POOL_ISCSI: + return "iscsi"; + } + return NULL; +} + +static int virStorageVolDefFormatFromString(const char *format) { + if (STREQ(format, "raw")) + return VIR_STORAGE_VOL_RAW; + else if (STREQ(format, "qcow")) + return VIR_STORAGE_VOL_QCOW; + else if (STREQ(format, "qcow2")) + return VIR_STORAGE_VOL_QCOW2; + else if (STREQ(format, "vvfat")) + return VIR_STORAGE_VOL_VVFAT; + else if (STREQ(format, "vpc")) + return VIR_STORAGE_VOL_VPC; + else if (STREQ(format, "bochs")) + return VIR_STORAGE_VOL_BOCHS; + else if (STREQ(format, "dmg")) + return VIR_STORAGE_VOL_DMG; + else if (STREQ(format, "cloop")) + return VIR_STORAGE_VOL_CLOOP; + else if (STREQ(format, "vmdk")) + return VIR_STORAGE_VOL_VMDK; + else if (STREQ(format, "cow")) + return VIR_STORAGE_VOL_COW; + + return -1; +} + +static const char *virStorageVolDefFormatToString(int format) { + switch (format) { + case VIR_STORAGE_VOL_RAW: + return "raw"; + case VIR_STORAGE_VOL_QCOW: + return "qcow"; + case VIR_STORAGE_VOL_QCOW2: + return "qcow2"; + case VIR_STORAGE_VOL_VVFAT: + return "vvfat"; + case VIR_STORAGE_VOL_VPC: + return "vpc"; + case VIR_STORAGE_VOL_BOCHS: + return "bochs"; + case VIR_STORAGE_VOL_DMG: + return "dmg"; + case VIR_STORAGE_VOL_CLOOP: + return "cloop"; + case VIR_STORAGE_VOL_VMDK: + return "vmdk"; + case VIR_STORAGE_VOL_COW: + return "cow"; + } + return NULL; +} + +static int virStoragePoolDefParseSrcLocal(virConnectPtr conn, xmlXPathContextPtr ctxt, virStoragePoolSrcLocalPtr src) { + double count; + xmlNodePtr *nodes; + int i; + + if (virXPathNumber("count(/pool/source[@type='local'])", ctxt, &count) < 0) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing source element"); + return -1; + } + + /* Arbitrary cap */ + if (count > 50) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "too many source elements"); + return -1; + } + + src->ndev = (int)count; + src->devs = calloc(src->ndev, sizeof(char*)); + + if (virXPathNodeSet("/pool/source[@type='local']", ctxt, &nodes) < 0) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "cannot extract source nodes"); + return -1; + } + + for (i = 0 ; i < src->ndev ; i++) { + src->devs[i] = (char *)xmlGetProp(nodes[i], BAD_CAST "dev"); + if (src->devs[i] == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing source dev attribute"); + return -1; + } + } + + return 0; +} + +static int virStoragePoolDefParseSrcRemote(virConnectPtr conn, xmlXPathContextPtr ctxt, virStoragePoolSrcRemotePtr src) { + src->hostname = virXPathString("string(/pool/source/@host)", ctxt); + if (src->hostname == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing source host attribute"); + return -1; + } + + src->export = virXPathString("string(/pool/source/@export)", ctxt); + if (src->export == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing source export attribute"); + return -1; + } + + return 0; +} + + +static int virStoragePoolDefParseAuthChap(virConnectPtr conn, xmlXPathContextPtr ctxt, virStoragePoolAuthChapPtr auth) { + auth->login = virXPathString("string(/pool/source/auth/@login)", ctxt); + if (auth->login == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing auth host attribute"); + return -1; + } + + auth->passwd = virXPathString("string(/pool/source/auth/@passwd)", ctxt); + if (auth->passwd == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing auth passwd attribute"); + return -1; + } + + return 0; +} + + +static int virStoragePoolDefParsePerms(virConnectPtr conn, xmlXPathContextPtr ctxt, virStoragePermsPtr perms) { + char *mode; + long v; + + mode = virXPathString("string(/pool/permissions/mode)", ctxt); + if (!mode) { + perms->mode = 0700; + } else { + char *end; + printf("[%s]\n", mode); + perms->mode = strtol(mode, &end, 8); + if (end && *end) { + printf("[%s]\n", end); + virStorageReportError(conn, VIR_ERR_XML_ERROR, "malformed octal mode"); + return -1; + } + } + + if (virXPathLong("number(/pool/permissions/owner)", ctxt, &v) < 0) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing owner element"); + return -1; + } + perms->uid = (int)v; + if (virXPathLong("number(/pool/permissions/group)", ctxt, &v) < 0) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing owner element"); + return -1; + } + perms->gid = (int)v; + + perms->label = virXPathString("string(/pool/permissions/label)", ctxt); + + return 0; +} + + +static virStoragePoolDefPtr virStoragePoolDefParseDoc(virConnectPtr conn, xmlXPathContextPtr ctxt, xmlNodePtr root) { + virStoragePoolDefPtr ret = calloc(1, sizeof(virStoragePoolDef)); + xmlChar *type = NULL; + char *uuid = NULL; + char *srcType = NULL; + char *authType = NULL; + + if (ret == NULL) + return NULL; + + if (STRNEQ((const char *)root->name, "pool")) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "unknown root element"); + goto cleanup; + } + + type = xmlGetProp(root, BAD_CAST "type"); + ret->type = virStoragePoolDefTypeFromString((const char *)type); + if (ret->type < 0) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "unsupported storage pool %s", (const char *)type); + goto cleanup; + } + xmlFree(type); + type = NULL; + + ret->name = virXPathString("string(/pool/name)", ctxt); + if (ret->name == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing name element"); + goto cleanup; + } + + uuid = virXPathString("string(/pool/uuid)", ctxt); + if (uuid == NULL) { + if (virUUIDGenerate(ret->uuid) < 0) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "unable to generate uuid"); + goto cleanup; + } + } else { + if (virUUIDParse(uuid, ret->uuid) < 0) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "malformed uuid element"); + goto cleanup; + } + free(uuid); + uuid = NULL; + } + + + if (type == VIR_STORAGE_POOL_DIR) { + ret->srcType = VIR_STORAGE_POOL_SRC_NONE; + } else { + srcType = virXPathString("string(/pool/source/@type)", ctxt); + if (srcType == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing type attribute on source element"); + goto cleanup; + } + if (STREQ(srcType, "local")) { + ret->srcType = VIR_STORAGE_POOL_SRC_LOCAL; + } else { + ret->srcType = VIR_STORAGE_POOL_SRC_REMOTE; + } + free(srcType); + srcType = NULL; + + if (ret->srcType == VIR_STORAGE_POOL_SRC_LOCAL) { + if (virStoragePoolDefParseSrcLocal(conn, ctxt, &ret->src.local) < 0) + goto cleanup; + } else { + if (virStoragePoolDefParseSrcRemote(conn, ctxt, &ret->src.remote) < 0) + goto cleanup; + } + } + + + + + authType = virXPathString("string(/pool/auth/@type)", ctxt); + if (authType == NULL) { + ret->authType = VIR_STORAGE_POOL_AUTH_NONE; + } else { + if (STREQ(authType, "chap")) { + ret->authType = VIR_STORAGE_POOL_AUTH_CHAP; + } else { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "unknown auth type '%s'", (const char *)authType); + goto cleanup; + } + free(authType); + authType = NULL; + } + + if (ret->srcType == VIR_STORAGE_POOL_AUTH_CHAP) { + if (virStoragePoolDefParseAuthChap(conn, ctxt, &ret->auth.chap) < 0) + goto cleanup; + } + + + + if (ret->type == VIR_STORAGE_POOL_DIR || + ret->type == VIR_STORAGE_POOL_FS) { + ret->target = virXPathString("string(/pool/target/@dir)", ctxt); + if (ret->target == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing target dir attribute"); + goto cleanup; + } + } else if (ret->type == VIR_STORAGE_POOL_LVM) { + ret->target = virXPathString("string(/pool/target/@name)", ctxt); + if (ret->target == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing target name attribute"); + goto cleanup; + } + } + + if (virStoragePoolDefParsePerms(conn, ctxt, &ret->perms) < 0) + goto cleanup; + + return ret; + + cleanup: + if (uuid) + free(uuid); + if (type) + xmlFree(type); + if (srcType) + xmlFree(srcType); + if (authType) + xmlFree(authType); + virStoragePoolDefFree(ret); + return NULL; +} + +virStoragePoolDefPtr virStoragePoolDefParse(virConnectPtr conn, const char *xmlStr, const char *filename) { + virStoragePoolDefPtr ret = NULL; + xmlDocPtr xml = NULL; + xmlNodePtr node = NULL; + xmlXPathContextPtr ctxt = NULL; + + if (!(xml = xmlReadDoc(BAD_CAST xmlStr, filename ? filename : "storage.xml", NULL, + XML_PARSE_NOENT | XML_PARSE_NONET | + XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "malformed xml document"); + goto cleanup; + } + + ctxt = xmlXPathNewContext(xml); + if (ctxt == NULL) { + virStorageReportError(conn, VIR_ERR_NO_MEMORY, "xmlXPathContext"); + goto cleanup; + } + + node = xmlDocGetRootElement(xml); + if (node == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing root element"); + goto cleanup; + } + + ret = virStoragePoolDefParseDoc(conn, ctxt, node); + + xmlXPathFreeContext(ctxt); + xmlFreeDoc(xml); + + return ret; + + cleanup: + if (ctxt) + xmlXPathFreeContext(ctxt); + if (xml) + xmlFreeDoc(xml); + return NULL; +} + + +char *virStoragePoolDefFormat(virConnectPtr conn, virStoragePoolDefPtr def) { + virBufferPtr buf = virBufferNew(8192); + const char *type; + char uuid[VIR_UUID_STRING_BUFLEN]; + if (!buf) + goto no_memory; + + type = virStoragePoolDefTypeToString(def->type); + if (!type) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "unexpected pool type"); + goto cleanup; + } + if (virBufferVSprintf(buf, "<pool type='%s'>\n", type) < 0) + goto no_memory; + + if (virBufferVSprintf(buf," <name>%s</name>\n", def->name) < 0) + goto no_memory; + + virUUIDFormat(def->uuid, uuid); + if (virBufferVSprintf(buf," <uuid>%s</uuid>\n", uuid) < 0) + goto no_memory; + + if (def->srcType == VIR_STORAGE_POOL_SRC_LOCAL) { + int i; + for (i = 0 ; i < def->src.local.ndev ; i++) { + if (virBufferVSprintf(buf," <source type='local' dev='%s'/>\n", + def->src.local.devs[i]) < 0) + goto no_memory; + } + } else if (def->srcType == VIR_STORAGE_POOL_SRC_REMOTE) { + if (virBufferVSprintf(buf," <source type='remote' host='%s' export='%s'>\n", + def->src.remote.hostname, def->src.remote.export) < 0) + goto no_memory; + if (def->authType == VIR_STORAGE_POOL_AUTH_CHAP) { + if (virBufferVSprintf(buf," <auth type='chap' login='%s' passwd='%s'>\n", + def->auth.chap.login, def->auth.chap.passwd) < 0) + goto no_memory; + } + if (virBufferAdd(buf," </source>\n", -1) < 0) + goto no_memory; + } + + + if (def->target) { + if (def->type == VIR_STORAGE_POOL_DIR || + def->type == VIR_STORAGE_POOL_FS) { + if (virBufferVSprintf(buf," <target dir='%s'/>\n", def->target) < 0) + goto no_memory; + } else if (def->type == VIR_STORAGE_POOL_LVM) { + if (virBufferVSprintf(buf," <target name='%s'/>\n", def->target) < 0) + goto no_memory; + } + } + + if (virBufferAdd(buf," <permissions>\n", -1) < 0) + goto no_memory; + if (virBufferVSprintf(buf," <mode>0%o</mode>\n", def->perms.mode) < 0) + goto no_memory; + if (virBufferVSprintf(buf," <owner>%d</owner>\n", def->perms.uid) < 0) + goto no_memory; + if (virBufferVSprintf(buf," <group>%d</group>\n", def->perms.gid) < 0) + goto no_memory; + + if (def->perms.label) { + if (virBufferVSprintf(buf," <label>%s</label>\n", def->perms.label) < 0) + goto no_memory; + } + if (virBufferAdd(buf," </permissions>\n", -1) < 0) + goto no_memory; + + if (virBufferAdd(buf,"</pool>\n", -1) < 0) + goto no_memory; + + return virBufferContentAndFree(buf); + + no_memory: + virStorageReportError(conn, VIR_ERR_NO_MEMORY, "xml"); + cleanup: + if (buf) virBufferFree(buf); + return NULL; +} + + +static int virStorageVolDefParsePerms(virConnectPtr conn, xmlXPathContextPtr ctxt, virStoragePermsPtr perms) { + char *mode; + long v; + + mode = virXPathString("string(/volume/permissions/mode)", ctxt); + if (!mode) { + perms->mode = 0700; + } else { + char *end; + printf("[%s]\n", mode); + perms->mode = strtol(mode, &end, 8); + if (end && *end) { + printf("[%s]\n", end); + virStorageReportError(conn, VIR_ERR_XML_ERROR, "malformed octal mode"); + return -1; + } + } + + if (virXPathLong("number(/volume/permissions/owner)", ctxt, &v) < 0) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing owner element"); + return -1; + } + perms->uid = (int)v; + if (virXPathLong("number(/volume/permissions/group)", ctxt, &v) < 0) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing owner element"); + return -1; + } + perms->gid = (int)v; + + perms->label = virXPathString("string(/volume/permissions/label)", ctxt); + + return 0; +} + + + +static virStorageVolDefPtr virStorageVolDefParseDoc(virConnectPtr conn, xmlXPathContextPtr ctxt, xmlNodePtr root) { + virStorageVolDefPtr ret = calloc(1, sizeof(virStorageVolDef)); + xmlChar *type = NULL; + char *allocation = NULL; + char *capacity = NULL; + char *uuid = NULL; + char *formatType = NULL; + char *end; + + if (ret == NULL) + return NULL; + + if (STRNEQ((const char *)root->name, "volume")) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "unknown root element"); + goto cleanup; + } + + type = xmlGetProp(root, BAD_CAST "type"); + if (STREQ((const char*)type, "file")) + ret->type = VIR_STORAGE_VOL_FILE; + else + ret->type = VIR_STORAGE_VOL_BLOCK; + xmlFree(type); + type = NULL; + + ret->name = virXPathString("string(/volume/name)", ctxt); + if (ret->name == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing name element"); + goto cleanup; + } + + uuid = virXPathString("string(/volume/uuid)", ctxt); + if (uuid == NULL) { + if (virUUIDGenerate(ret->uuid) < 0) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "unable to generate uuid"); + goto cleanup; + } + } else { + if (virUUIDParse(uuid, ret->uuid) < 0) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "malformed uuid element"); + goto cleanup; + } + free(uuid); + uuid = NULL; + } + + capacity = virXPathString("string(/volume/capacity)", ctxt); + if (capacity == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing capacity element"); + goto cleanup; + } + ret->capacity = strtoull(capacity, &end, 10); + if (end && *end) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "malformed capacity element"); + goto cleanup; + } + free(capacity); + capacity = NULL; + + allocation = virXPathString("string(/volume/allocation)", ctxt); + if (allocation) { + ret->allocation = strtoull(allocation, &end, 10); + if (end && *end) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "malformed allocation element"); + goto cleanup; + } + free(allocation); + allocation = NULL; + } + + formatType = virXPathString("string(/volume/format/@type)", ctxt); + if (formatType == NULL) { + ret->format = VIR_STORAGE_VOL_RAW; + } else { + ret->format = virStorageVolDefFormatFromString((const char *)formatType); + if (ret->format < 0) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "unsupported storage volume format %s", (const char *)formatType); + goto cleanup; + } + xmlFree(formatType); + formatType = NULL; + } + + if (virStorageVolDefParsePerms(conn, ctxt, &ret->perms) < 0) + goto cleanup; + + return ret; + + cleanup: + if (allocation) + free(allocation); + if (capacity) + free(capacity); + if (uuid) + free(uuid); + if (type) + xmlFree(type); + if (formatType) + xmlFree(formatType); + virStorageVolDefFree(ret); + return NULL; +} + + +virStorageVolDefPtr virStorageVolDefParse(virConnectPtr conn, const char *xmlStr, const char *filename) { + virStorageVolDefPtr ret = NULL; + xmlDocPtr xml = NULL; + xmlNodePtr node = NULL; + xmlXPathContextPtr ctxt = NULL; + + if (!(xml = xmlReadDoc(BAD_CAST xmlStr, filename ? filename : "storage.xml", NULL, + XML_PARSE_NOENT | XML_PARSE_NONET | + XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "malformed xml document"); + goto cleanup; + } + + ctxt = xmlXPathNewContext(xml); + if (ctxt == NULL) { + virStorageReportError(conn, VIR_ERR_NO_MEMORY, "xmlXPathContext"); + goto cleanup; + } + + node = xmlDocGetRootElement(xml); + if (node == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing root element"); + goto cleanup; + } + + ret = virStorageVolDefParseDoc(conn, ctxt, node); + + xmlXPathFreeContext(ctxt); + xmlFreeDoc(xml); + + return ret; + + cleanup: + if (ctxt) + xmlXPathFreeContext(ctxt); + if (xml) + xmlFreeDoc(xml); + return NULL; +} + + + +char *virStorageVolDefFormat(virConnectPtr conn, virStorageVolDefPtr def) { + virBufferPtr buf = virBufferNew(8192); + char uuid[VIR_UUID_STRING_BUFLEN]; + if (!buf) + goto no_memory; + + if (virBufferVSprintf(buf, "<volume type='%s'>\n", def->type == VIR_STORAGE_VOL_FILE ? "file" : "block") < 0) + goto no_memory; + + if (virBufferVSprintf(buf," <name>%s</name>\n", def->name) < 0) + goto no_memory; + + virUUIDFormat(def->uuid, uuid); + if (virBufferVSprintf(buf," <uuid>%s</uuid>\n", uuid) < 0) + goto no_memory; + + if (virBufferVSprintf(buf," <capacity>%llu</capacity>\n", def->capacity) < 0) + goto no_memory; + if (virBufferVSprintf(buf," <allocation>%llu</allocation>\n", def->allocation) < 0) + goto no_memory; + + + if (def->type == VIR_STORAGE_VOL_FILE) { + const char *format = virStorageVolDefFormatToString(def->format); + if (format == NULL) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "unexpected volume format %s", def->format); + goto cleanup; + } + if (def->format == VIR_STORAGE_VOL_QCOW2) { + if (virBufferVSprintf(buf," <format type='%s'/>\n", format) < 0) + goto no_memory; + if (def->formatOpts.qcow2.compress) { + if (virBufferAdd(buf," <compressed/>\n", -1) < 0) + goto no_memory; + } + if (def->formatOpts.qcow2.encrypted) { + if (virBufferAdd(buf," <encrypted/>\n", -1) < 0) + goto no_memory; + } + if (virBufferAdd(buf," </format>\n", -1) < 0) + goto no_memory; + } else { + if (virBufferVSprintf(buf," <format type='%s'/>\n", format) < 0) + goto no_memory; + } + } + + if (def->target) { + if (def->type == VIR_STORAGE_POOL_FILE) { + if (virBufferVSprintf(buf," <target file='%s'/>\n", def->target) < 0) + goto no_memory; + } else { + if (virBufferVSprintf(buf," <target dev='%s'/>\n", def->target) < 0) + goto no_memory; + } + } + + if (virBufferAdd(buf," <permissions>\n", -1) < 0) + goto no_memory; + if (virBufferVSprintf(buf," <mode>0%o</mode>\n", def->perms.mode) < 0) + goto no_memory; + if (virBufferVSprintf(buf," <owner>%d</owner>\n", def->perms.uid) < 0) + goto no_memory; + if (virBufferVSprintf(buf," <group>%d</group>\n", def->perms.gid) < 0) + goto no_memory; + + if (def->perms.label) { + if (virBufferVSprintf(buf," <label>%s</label>\n", def->perms.label) < 0) + goto no_memory; + } + if (virBufferAdd(buf," </permissions>\n", -1) < 0) + goto no_memory; + + if (virBufferAdd(buf,"</volume>\n", -1) < 0) + goto no_memory; + + return virBufferContentAndFree(buf); + + no_memory: + virStorageReportError(conn, VIR_ERR_NO_MEMORY, "xml"); + cleanup: + if (buf) virBufferFree(buf); + return NULL; +} + + +virStoragePoolObjPtr virStoragePoolObjFindByUUID(virStorageDriverStatePtr driver, + const unsigned char *uuid) { + virStoragePoolObjPtr pool = driver->pools; + + while (pool) { + if (!memcmp(pool->def->uuid, uuid, VIR_UUID_BUFLEN)) + return pool; + pool = pool->next; + } + + return NULL; +} + +virStoragePoolObjPtr virStoragePoolObjFindByName(virStorageDriverStatePtr driver, + const char *name) { + virStoragePoolObjPtr pool = driver->pools; + + while (pool) { + if (STREQ(pool->def->name, name)) + return pool; + pool = pool->next; + } + + return NULL; +} + + +virStorageVolDefPtr virStorageVolDefFindByUUID(virStoragePoolObjPtr pool, + const unsigned char *uuid) { + virStorageVolDefPtr vol = pool->volumes; + + while (vol) { + if (!memcmp(vol->uuid, uuid, VIR_UUID_BUFLEN)) + return vol; + vol = vol->next; + } + + return NULL; +} + +virStorageVolDefPtr virStorageVolDefFindByName(virStoragePoolObjPtr pool, + const char *name) { + virStorageVolDefPtr vol = pool->volumes; + + while (vol) { + if (STREQ(vol->name, name)) + return vol; + vol = vol->next; + } + + return NULL; +} + +virStoragePoolObjPtr virStoragePoolObjAssignDef(virConnectPtr conn, + virStorageDriverStatePtr driver, + virStoragePoolDefPtr def) { + virStoragePoolObjPtr pool; + + if ((pool = virStoragePoolObjFindByName(driver, def->name))) { + if (!virStoragePoolObjIsActive(pool)) { + virStoragePoolDefFree(pool->def); + pool->def = def; + } else { + if (pool->newDef) + virStoragePoolDefFree(pool->newDef); + pool->newDef = def; + } + return pool; + } + + if (!(pool = calloc(1, sizeof(virStoragePoolObj)))) { + virStorageReportError(conn, VIR_ERR_NO_MEMORY, "pool"); + return NULL; + } + + pool->active = 0; + pool->def = def; + pool->next = driver->pools; + + driver->pools = pool; + driver->ninactivePools++; + printf("inactive %d\n", driver->ninactivePools); + return pool; +} + +static virStoragePoolObjPtr +virStoragePoolObjLoad(virStorageDriverStatePtr driver, + const char *file, + const char *path, + const char *xml, + const char *autostartLink) { + virStoragePoolDefPtr def; + virStoragePoolObjPtr pool; + + if (!(def = virStoragePoolDefParse(NULL, xml, file))) { + virErrorPtr err = virGetLastError(); + virStorageLog("Error parsing storage pool config '%s' : %s", + path, err->message); + return NULL; + } + + if (!compareFileToNameSuffix(file, def->name, ".xml")) { + virStorageLog("Storage Pool config filename '%s' does not match pool name '%s'", + path, def->name); + virStoragePoolDefFree(def); + return NULL; + } + + if (!(pool = virStoragePoolObjAssignDef(NULL, driver, def))) { + virStorageLog("Failed to load storage pool config '%s': out of memory", path); + virStoragePoolDefFree(def); + return NULL; + } + + pool->configFile = strdup(path); + if (pool->configFile == NULL) { + virStorageLog("Failed to load storage pool config '%s': out of memory", path); + virStoragePoolDefFree(def); + return NULL; + } + pool->autostartLink = strdup(autostartLink); + if (pool->autostartLink == NULL) { + virStorageLog("Failed to load storage pool config '%s': out of memory", path); + virStoragePoolDefFree(def); + return NULL; + } + + pool->autostart = checkLinkPointsTo(pool->autostartLink, pool->configFile); + + return pool; +} + + +int virStoragePoolObjScanConfigs(virStorageDriverStatePtr driver) { + DIR *dir; + struct dirent *entry; + + if (!(dir = opendir(driver->configDir))) { + if (errno == ENOENT) + return 0; + virStorageLog("Failed to open dir '%s': %s", + driver->configDir, strerror(errno)); + return -1; + } + + while ((entry = readdir(dir))) { + char xml[8192]; + char path[PATH_MAX]; + char autostartLink[PATH_MAX]; + + if (entry->d_name[0] == '.') + continue; + + if (!hasSuffix(entry->d_name, ".xml")) + continue; + + if (virStorageMakeConfigPath(driver->configDir, entry->d_name, NULL, path, PATH_MAX) < 0) { + virStorageLog("Config filename '%s/%s' is too long", + driver->configDir, entry->d_name); + continue; + } + + if (virStorageMakeConfigPath(driver->autostartDir, entry->d_name, NULL, autostartLink, PATH_MAX) < 0) { + virStorageLog("Autostart link path '%s/%s' is too long", + driver->autostartDir, entry->d_name); + continue; + } + + if (!virStorageReadFile(path, xml, sizeof(xml))) + continue; + + virStoragePoolObjLoad(driver, entry->d_name, path, xml, autostartLink); + } + + closedir(dir); + + return 0; +} + +int virStoragePoolObjSaveDef(virConnectPtr conn, + virStorageDriverStatePtr driver, + virStoragePoolObjPtr pool, + virStoragePoolDefPtr def) { + char *xml; + int fd = -1, ret = -1; + int towrite; + + if (!pool->configFile) { + int err; + char path[PATH_MAX]; + + if ((err = virStorageEnsureDir(driver->configDir))) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + "cannot create config directory %s: %s", + driver->configDir, strerror(err)); + return -1; + } + + if (virStorageMakeConfigPath(driver->configDir, def->name, ".xml", + path, sizeof(path)) < 0) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + "cannot construct config file path"); + return -1; + } + if (!(pool->configFile = strdup(path))) { + virStorageReportError(conn, VIR_ERR_NO_MEMORY, "configFile"); + return -1; + } + + if (virStorageMakeConfigPath(driver->autostartDir, def->name, ".xml", + path, sizeof(path)) < 0) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + "cannot construct autostart link path"); + free(pool->configFile); + pool->configFile = NULL; + return -1; + } + if (!(pool->autostartLink = strdup(path))) { + virStorageReportError(conn, VIR_ERR_NO_MEMORY, "configFile"); + free(pool->configFile); + pool->configFile = NULL; + return -1; + } + } + + if (!(xml = virStoragePoolDefFormat(conn, def))) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + "failed to generate XML"); + return -1; + } + + if ((fd = open(pool->configFile, + O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR )) < 0) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + "cannot create config file %s: %s", + pool->configFile, strerror(errno)); + goto cleanup; + } + + towrite = strlen(xml); + if (write(fd, xml, towrite) != towrite) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + "cannot write config file %s: %s", + pool->configFile, strerror(errno)); + goto cleanup; + } + + if (close(fd) < 0) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + "cannot save config file %s: %s", + pool->configFile, strerror(errno)); + goto cleanup; + } + + ret = 0; + + cleanup: + if (fd != -1) + close(fd); + + free(xml); + + return ret; +} + +int virStoragePoolObjDeleteDef(virConnectPtr conn, virStoragePoolObjPtr pool) { + if (!pool->configFile) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "no config file for %s", pool->def->name); + return -1; + } + + if (unlink(pool->configFile) < 0) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "cannot remove config for %s", pool->def->name); + return -1; + } + + return 0; +} + +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -r f57805779ece src/storage_conf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/storage_conf.h Sun Oct 28 22:45:04 2007 -0400 @@ -0,0 +1,222 @@ + +#ifndef __VIR_STORAGE_DRIVER_H__ +#define __VIR_STORAGE_DRIVER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +#include <libvirt/libvirt.h> +#include "internal.h" + + typedef struct _virStoragePerms virStoragePerms; + typedef virStoragePerms *virStoragePermsPtr; + struct _virStoragePerms { + int mode; + int uid; + int gid; + char *label; + }; + + + + enum virStorageVolType { + VIR_STORAGE_VOL_FILE, + VIR_STORAGE_VOL_BLOCK, + }; + + enum virStorageVolFormat { + VIR_STORAGE_VOL_RAW, + VIR_STORAGE_VOL_QCOW, + VIR_STORAGE_VOL_QCOW2, + VIR_STORAGE_VOL_VVFAT, + VIR_STORAGE_VOL_VPC, + VIR_STORAGE_VOL_BOCHS, + VIR_STORAGE_VOL_DMG, + VIR_STORAGE_VOL_CLOOP, + VIR_STORAGE_VOL_VMDK, + VIR_STORAGE_VOL_COW, + }; + + typedef struct _virStorageVolDef virStorageVolDef; + typedef virStorageVolDef *virStorageVolDefPtr; + struct _virStorageVolDef { + char *name; + unsigned char uuid[VIR_UUID_BUFLEN]; + int type; + int format; + union { + struct { + int compress :1; + int encrypted :1; + char *passwd; + } qcow2; + } formatOpts; + virStoragePerms perms; + char *target; + unsigned long long allocation; + unsigned long long capacity; + + virStorageVolDefPtr next; + }; + + enum virStoragePoolType { + VIR_STORAGE_POOL_DIR, + VIR_STORAGE_POOL_FS, + VIR_STORAGE_POOL_LVM, + VIR_STORAGE_POOL_DISK, + VIR_STORAGE_POOL_ISCSI, + }; + + enum virStoragePoolSrcType { + VIR_STORAGE_POOL_SRC_NONE, + VIR_STORAGE_POOL_SRC_LOCAL, + VIR_STORAGE_POOL_SRC_REMOTE, + }; + + enum virStoragePoolAuthType { + VIR_STORAGE_POOL_AUTH_NONE, + VIR_STORAGE_POOL_AUTH_CHAP, + }; + + typedef struct _virStoragePoolAuthChap virStoragePoolAuthChap; + typedef virStoragePoolAuthChap *virStoragePoolAuthChapPtr; + struct _virStoragePoolAuthChap { + char *login; + char *passwd; + }; + + typedef struct _virStoragePoolSrcRemote virStoragePoolSrcRemote; + typedef virStoragePoolSrcRemote *virStoragePoolSrcRemotePtr; + struct _virStoragePoolSrcRemote { + char *hostname; + char *export; + }; + + typedef struct _virStoragePoolSrcLocal virStoragePoolSrcLocal; + typedef virStoragePoolSrcLocal *virStoragePoolSrcLocalPtr; + struct _virStoragePoolSrcLocal { + int ndev; + char **devs; + }; + + typedef struct _virStoragePoolDef virStoragePoolDef; + typedef virStoragePoolDef *virStoragePoolDefPtr; + + struct _virStoragePoolDef { + /* General metadata */ + char *name; + unsigned char uuid[VIR_UUID_BUFLEN]; + int type; /* virStoragePoolType */ + + + /* Source info */ + int srcType; /* virStoragePoolSrcType */ + union { + virStoragePoolSrcRemote remote; + virStoragePoolSrcLocal local; + } src; + + int authType; /* virStoragePoolAuthType */ + union { + virStoragePoolAuthChap chap; + } auth; + + + /* Local filesystem mapping */ + char *target; + virStoragePerms perms; + }; + + typedef struct _virStoragePoolObj virStoragePoolObj; + typedef virStoragePoolObj *virStoragePoolObjPtr; + + struct _virStoragePoolObj { + char *configFile; + char *autostartLink; + int active; + int autostart; + + virStoragePoolDefPtr def; + virStoragePoolDefPtr newDef; + + int nvolumes; + virStorageVolDefPtr volumes; + + virStoragePoolObjPtr next; + }; + + typedef struct _virStorageDriverState virStorageDriverState; + typedef virStorageDriverState *virStorageDriverStatePtr; + + struct _virStorageDriverState { + int nactivePools; + int ninactivePools; + virStoragePoolObjPtr pools; + char *configDir; + char *autostartDir; + }; + + + static inline int virStoragePoolObjIsActive(virStoragePoolObjPtr pool) { + return pool->active; + } + + int virStorageEnsureDir(const char *path); + + void virStorageReportError(virConnectPtr conn, int code, const char *fmt, ...); + + int virStoragePoolObjScanConfigs(virStorageDriverStatePtr driver); + + virStoragePoolObjPtr virStoragePoolObjFindByUUID(virStorageDriverStatePtr driver, + const unsigned char *uuid); + virStoragePoolObjPtr virStoragePoolObjFindByName(virStorageDriverStatePtr driver, + const char *name); + + virStorageVolDefPtr virStorageVolDefFindByUUID(virStoragePoolObjPtr pool, + const unsigned char *uuid); + virStorageVolDefPtr virStorageVolDefFindByName(virStoragePoolObjPtr pool, + const char *name); + + virStoragePoolDefPtr virStoragePoolDefParse(virConnectPtr conn, const char *xml, const char *filename); + char *virStoragePoolDefFormat(virConnectPtr conn, virStoragePoolDefPtr def); + + virStorageVolDefPtr virStorageVolDefParse(virConnectPtr conn, const char *xml, const char *filename); + char *virStorageVolDefFormat(virConnectPtr conn, virStorageVolDefPtr def); + + virStoragePoolObjPtr virStoragePoolObjAssignDef(virConnectPtr conn, + virStorageDriverStatePtr driver, + virStoragePoolDefPtr def); + + int virStoragePoolObjSaveDef(virConnectPtr conn, + virStorageDriverStatePtr driver, + virStoragePoolObjPtr pool, + virStoragePoolDefPtr def); + int virStoragePoolObjDeleteDef(virConnectPtr conn, virStoragePoolObjPtr pool); + + void virStorageVolDefFree(virStorageVolDefPtr def); + void virStoragePoolDefFree(virStoragePoolDefPtr def); + void virStoragePoolObjFree(virStoragePoolObjPtr pool); + void virStoragePoolObjRemove(virStorageDriverStatePtr driver, + virStoragePoolObjPtr pool); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __VIR_STORAGE_DRIVER_H__ */ + + +/* + * vim: set tabstop=4: + * vim: set shiftwidth=4: + * vim: set expandtab: + */ +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -r f57805779ece src/storage_driver.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/storage_driver.c Sun Oct 28 22:45:04 2007 -0400 @@ -0,0 +1,996 @@ + +#define _GNU_SOURCE +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <pwd.h> +#include <errno.h> + +#include "driver.h" +#include "storage_driver.h" +#include "storage_conf.h" + +#include "storage_backend.h" +#include "storage_backend_iscsi.h" +#include "storage_backend_lvm.h" +#include "storage_backend_disk.h" +#include "storage_backend_fs.h" + +#define storageLog(msg...) fprintf(stderr, msg) + +static virStorageDriverStatePtr driverState; +static virStoragePoolBackendPtr backends[] = { + &virStoragePoolBackendDirectory, + &virStoragePoolBackendFileSystem, + &virStoragePoolBackendDisk, + &virStoragePoolBackendLVM, + &virStoragePoolBackendISCSI, +}; + +static int storageDriverShutdown(void); + +static virStoragePoolBackendPtr storageBackend(int type) { + int i; + for (i = 0 ; i < (sizeof(backends)/sizeof(backends[0])) ; i++) + if (backends[i]->type == type) + return backends[i]; + + virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, "missing backend for pool type %d", type); + return NULL; +} + + +static void storageDriverAutostart(virStorageDriverStatePtr driver) { + virStoragePoolObjPtr pool; + + pool = driver->pools; + while (pool != NULL) { + virStoragePoolObjPtr next = pool->next; + + if (pool->autostart && + !virStoragePoolObjIsActive(pool)) { + virStoragePoolBackendPtr backend; + if ((backend = storageBackend(pool->def->type)) == NULL) { + storageLog("Missing backend %d", + pool->def->type); + pool = next; + continue; + } + + if (backend->start(pool) < 0) { + virErrorPtr err = virGetLastError(); + storageLog("Failed to autostart storage pool '%s': %s", + pool->def->name, err->message); + } + pool->active = 1; + driver->nactivePools++; + driver->ninactivePools--; + } + + pool = next; + } +} + +/** + * virStorageStartup: + * + * Initialization function for the QEmu daemon + */ +static int +storageDriverStartup(void) { + uid_t uid = geteuid(); + struct passwd *pw; + char *base = NULL; + char driverConf[PATH_MAX]; + + if (!(driverState = calloc(1, sizeof(virStorageDriverState)))) { + return -1; + } + + if (!uid) { + if ((base = strdup (SYSCONF_DIR "/libvirt")) == NULL) + goto out_of_memory; + } else { + if (!(pw = getpwuid(uid))) { + storageLog("Failed to find user record for uid '%d': %s", + uid, strerror(errno)); + goto out_of_memory; + } + + if (asprintf (&base, "%s/.libvirt", pw->pw_dir) == -1) { + storageLog("out of memory in asprintf"); + goto out_of_memory; + } + } + + /* Configuration paths are either ~/.libvirt/storage/... (session) or + * /etc/libvirt/storage/... (system). + */ + if (snprintf (driverConf, sizeof(driverConf), "%s/storage.conf", base) == -1) + goto out_of_memory; + driverConf[sizeof(driverConf)-1] = '\0'; + + if (asprintf (&driverState->configDir, "%s/storage", base) == -1) + goto out_of_memory; + + if (asprintf (&driverState->autostartDir, "%s/storage/autostart", base) == -1) + goto out_of_memory; + + free(base); + + /* + if (virStorageLoadDriverConfig(driver, driverConf) < 0) { + virStorageDriverShutdown(); + return -1; + } + */ + + if (virStoragePoolObjScanConfigs(driverState) < 0) { + storageDriverShutdown(); + return -1; + } + storageDriverAutostart(driverState); + + return 0; + + out_of_memory: + storageLog("virStorageStartup: out of memory"); + if (base) free (base); + free(driverState); + driverState = NULL; + return -1; +} + +/** + * virStorageReload: + * + * Function to restart the storage driver, it will recheck the configuration + * files and update its state + */ +static int +storageDriverReload(void) { + virStoragePoolObjScanConfigs(driverState); + storageDriverAutostart(driverState); + + return 0; +} + +/** + * virStorageActive: + * + * Checks if the storage driver is active, i.e. has an active pool + * + * Returns 1 if active, 0 otherwise + */ +static int +storageDriverActive(void) { + /* If we've any active networks or guests, then we + * mark this driver as active + */ + if (driverState->nactivePools) + return 1; + + /* Otherwise we're happy to deal with a shutdown */ + return 0; +} + +/** + * virStorageShutdown: + * + * Shutdown the storage driver, it will stop all active storage pools + */ +static int +storageDriverShutdown(void) { + virStoragePoolObjPtr pool; + + if (!driverState) + return -1; + + /* shutdown active networks */ + pool = driverState->pools; + while (pool) { + virStoragePoolObjPtr next = pool->next; + if (virStoragePoolObjIsActive(pool)) { + virStoragePoolBackendPtr backend; + if ((backend = storageBackend(pool->def->type)) == NULL) { + storageLog("Missing backend"); + continue; + } + + if (backend->stop(pool) < 0) { + virErrorPtr err = virGetLastError(); + storageLog("Failed to stop storage pool '%s': %s", + pool->def->name, err->message); + } + } + pool = next; + } + + /* free inactive networks */ + pool = driverState->pools; + while (pool) { + virStoragePoolObjPtr next = pool->next; + virStoragePoolObjFree(pool); + pool = next; + } + driverState->pools = NULL; + driverState->nactivePools = 0; + driverState->ninactivePools = 0; + + if (driverState->configDir) + free(driverState->configDir); + if (driverState->autostartDir) + free(driverState->autostartDir); + + free(driverState); + driverState = NULL; + + return 0; +} + + + +static virStoragePoolPtr storagePoolLookupByUUID(virConnectPtr conn, + const unsigned char *uuid) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, uuid); + virStoragePoolPtr ret; + + if (!pool) { + virStorageReportError(conn, VIR_ERR_NO_STORAGE_POOL, "no pool with matching uuid"); + return NULL; + } + + ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid); + return ret; +} + +static virStoragePoolPtr storagePoolLookupByName(virConnectPtr conn, + const char *name) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByName(driver, name); + virStoragePoolPtr ret; + + if (!pool) { + virStorageReportError(conn, VIR_ERR_NO_STORAGE_POOL, "no pool with matching name"); + return NULL; + } + + ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid); + return ret; +} + +static virDrvOpenStatus storageOpen(virConnectPtr conn, + const char *name ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED) { + if (!driverState) + return VIR_DRV_OPEN_DECLINED; + + conn->storagePrivateData = driverState; + return VIR_DRV_OPEN_SUCCESS; +} + +static int storageClose(virConnectPtr conn) { + conn->storagePrivateData = NULL; + return 0; +} + +static int storageNumPools(virConnectPtr conn) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)conn->storagePrivateData; + printf("<<< %d \n", driver->nactivePools); + return driver->nactivePools; +} + +static int storageListPools(virConnectPtr conn, char **const names, int nnames) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)conn->storagePrivateData; + virStoragePoolObjPtr pool = driver->pools; + int got = 0, i; + while (pool && got < nnames) { + if (virStoragePoolObjIsActive(pool)) { + if (!(names[got] = strdup(pool->def->name))) { + virStorageReportError(conn, VIR_ERR_NO_MEMORY, "names"); + goto cleanup; + } + got++; + } + pool = pool->next; + } + return got; + + cleanup: + for (i = 0 ; i < got ; i++) + free(names[i]); + return -1; +} + +static int storageNumDefinedPools(virConnectPtr conn) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)conn->storagePrivateData; + printf(">>> %d \n", driver->ninactivePools); + return driver->ninactivePools; +} + +static int storageListDefinedPools(virConnectPtr conn, char **const names, int nnames) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)conn->storagePrivateData; + virStoragePoolObjPtr pool = driver->pools; + int got = 0, i; + while (pool && got < nnames) { + if (!virStoragePoolObjIsActive(pool)) { + if (!(names[got] = strdup(pool->def->name))) { + virStorageReportError(conn, VIR_ERR_NO_MEMORY, "names"); + goto cleanup; + } + got++; + } + pool = pool->next; + } + return got; + + cleanup: + for (i = 0 ; i < got ; i++) + free(names[i]); + return -1; +} + +static virStoragePoolPtr storagePoolCreate(virConnectPtr conn, const char *xml) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr )conn->storagePrivateData; + virStoragePoolDefPtr def; + virStoragePoolObjPtr pool; + virStoragePoolPtr ret; + virStoragePoolBackendPtr backend; + + printf("Create %p %d %d\n", driver->pools, driver->nactivePools, driver->ninactivePools); + if (!(def = virStoragePoolDefParse(conn, xml, NULL))) + return NULL; + + if ((backend = storageBackend(def->type)) == NULL) { + virStoragePoolDefFree(def); + return NULL; + } + + if (!(pool = virStoragePoolObjAssignDef(conn, driver, def))) { + virStoragePoolDefFree(def); + return NULL; + } + + if (backend->start(pool) < 0) { + virStoragePoolObjRemove(driver, pool); + return NULL; + } + pool->active = 1; + driver->nactivePools++; + driver->ninactivePools--; + + ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid); + printf("Created %p %d %d\n", driver->pools, driver->nactivePools, driver->ninactivePools); + return ret; +} + +static virStoragePoolPtr storagePoolDefine(virConnectPtr conn, const char *xml) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr )conn->storagePrivateData; + virStoragePoolDefPtr def; + virStoragePoolObjPtr pool; + virStoragePoolPtr ret; + virStoragePoolBackendPtr backend; + + if (!(def = virStoragePoolDefParse(conn, xml, NULL))) + return NULL; + + if ((backend = storageBackend(def->type)) == NULL) { + virStoragePoolDefFree(def); + return NULL; + } + + if (!(pool = virStoragePoolObjAssignDef(conn, driver, def))) { + virStoragePoolDefFree(def); + return NULL; + } + + if (virStoragePoolObjSaveDef(conn, driver, pool, def) < 0) { + virStoragePoolObjRemove(driver, pool); + return NULL; + } + + ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid); + return ret; +} + +static int storagePoolUndefine(virStoragePoolPtr obj) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + "no storage pool with matching uuid"); + return -1; + } + + if (virStoragePoolObjDeleteDef(obj->conn, pool) < 0) + return -1; + + if (unlink(pool->autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) + storageLog("Failed to delete autostart link '%s': %s", + pool->autostartLink, strerror(errno)); + + free(pool->configFile); + pool->configFile = NULL; + free(pool->autostartLink); + pool->autostartLink = NULL; + + virStoragePoolObjRemove(driver, pool); + + return 0; +} + +static int storagePoolStart(virStoragePoolPtr obj) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + virStoragePoolBackendPtr backend; + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + "no storage pool with matching uuid"); + return -1; + } + + if ((backend = storageBackend(pool->def->type)) == NULL) { + return -1; + } + + if (virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, "pool already active"); + return -1; + } + if (backend->start(pool) < 0) + return -1; + + pool->active = 1; + driver->nactivePools++; + driver->ninactivePools--; + + return 0; +} + +static int storagePoolShutdown(virStoragePoolPtr obj) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + virStoragePoolBackendPtr backend; + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + "no stoage pool with matching uuid"); + return -1; + } + + if ((backend = storageBackend(pool->def->type)) == NULL) { + return -1; + } + + if (!virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + "storage pool is not active"); + return -1; + } + + if (backend->stop(pool) < 0) + return -1; + + pool->active = 0; + driver->nactivePools--; + driver->ninactivePools++; + + return 0; +} + +static int storagePoolDestroy(virStoragePoolPtr obj) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + virStoragePoolBackendPtr backend; + int ret = 0; + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + "no stoage pool with matching uuid"); + return -1; + } + + if ((backend = storageBackend(pool->def->type)) == NULL) { + return -1; + } + + if (!virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + "storage pool is not active"); + return -1; + } + ret = backend->stop(pool); + + if (ret == 0) { + pool->active = 0; + driver->nactivePools--; + driver->ninactivePools++; + } + + virFreeStoragePool(obj->conn, obj); + + return ret; +} + +static int storagePoolGetInfo(virStoragePoolPtr obj, virStoragePoolInfoPtr info) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + virStoragePoolBackendPtr backend; + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + "no storage pool with matching uuid"); + return -1; + } + + if ((backend = storageBackend(pool->def->type)) == NULL) { + return -1; + } + + memset(info, 0, sizeof(virStoragePoolInfo)); + if (pool->active) + info->state = VIR_STORAGE_POOL_ACTIVE; + else + info->state = VIR_STORAGE_POOL_INACTIVE; + + return 0; +} + +static char *storagePoolDumpXML(virStoragePoolPtr obj, int flags ATTRIBUTE_UNUSED) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + "no storage pool with matching uuid"); + return NULL; + } + + return virStoragePoolDefFormat(obj->conn, pool->def); +} + +static int storagePoolGetAutostart(virStoragePoolPtr obj, + int *autostart) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + "no pool with matching uuid"); + return -1; + } + + if (!pool->configFile) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_ARG, + "pool has no config file"); + return -1; + } + + *autostart = pool->autostart; + + return 0; +} + +static int storagePoolSetAutostart(virStoragePoolPtr obj, + int autostart) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + "no pool with matching uuid"); + return -1; + } + + if (!pool->configFile) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_ARG, + "pool has no config file"); + return -1; + } + + autostart = (autostart != 0); + + if (pool->autostart == autostart) + return 0; + + if (autostart) { + int err; + + if ((err = virStorageEnsureDir(driver->autostartDir))) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + "cannot create autostart directory %s: %s", + driver->autostartDir, strerror(err)); + return -1; + } + + if (symlink(pool->configFile, pool->autostartLink) < 0) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + "Failed to create symlink '%s' to '%s': %s", + pool->autostartLink, pool->configFile, strerror(errno)); + return -1; + } + } else { + if (unlink(pool->autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + "Failed to delete symlink '%s': %s", + pool->autostartLink, strerror(errno)); + return -1; + } + } + + pool->autostart = autostart; + + return 0; +} + + +static int storagePoolNumVolumes(virStoragePoolPtr obj) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + "no storage pool with matching uuid"); + return -1; + } + + if (!virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + "storage pool is not active"); + return -1; + } + + return pool->nvolumes; +} + +static int storagePoolListVolumes(virStoragePoolPtr obj, char **const names, int maxnames) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + int i = 0; + virStorageVolDefPtr vol; + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + "no storage pool with matching uuid"); + return -1; + } + + if (!virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + "storage pool is not active"); + return -1; + } + + memset(names, 0, maxnames); + vol = pool->volumes; + while (vol && i < maxnames) { + names[i] = strdup(vol->name); + if (names[i] == NULL) { + virStorageReportError(obj->conn, VIR_ERR_NO_MEMORY, "name"); + goto cleanup; + } + vol = vol->next; + i++; + } + + return i; + + cleanup: + for (i = 0 ; i < maxnames ; i++) { + if (names[i]) { + free(names[i]); + names[i] = NULL; + } + } + return -1; +} + +static virStorageVolPtr storageVolumeLookupByName(virStoragePoolPtr obj, const char *name) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + virStorageVolDefPtr vol; + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + "no storage pool with matching uuid"); + return NULL; + } + + if (!virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + "storage pool is not active"); + return NULL; + } + + vol = virStorageVolDefFindByName(pool, name); + + if (!vol) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + "no storage vol with matching name"); + return NULL; + } + + return virGetStorageVol(obj, vol->name, vol->uuid); +} + +static virStorageVolPtr storageVolumeLookupByUUID(virStoragePoolPtr obj, const unsigned char *uuid) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + virStorageVolDefPtr vol; + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + "no storage pool with matching uuid"); + return NULL; + } + + if (!virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + "storage pool is not active"); + return NULL; + } + + vol = virStorageVolDefFindByUUID(pool, uuid); + + if (!vol) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + "no storage vol with matching name"); + return NULL; + } + + return virGetStorageVol(obj, vol->name, vol->uuid); +} + +static virStorageVolPtr storageVolumeCreateXML(virStoragePoolPtr obj, const char *xmldesc, int flags ATTRIBUTE_UNUSED) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + virStoragePoolBackendPtr backend; + virStorageVolDefPtr vol; + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + "no storage pool with matching uuid"); + return NULL; + } + + if (!virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + "storage pool is not active"); + return NULL; + } + + if ((backend = storageBackend(pool->def->type)) == NULL) + return NULL; + + vol = virStorageVolDefParse(obj->conn, xmldesc, NULL); + if (vol == NULL) + return NULL; + + if (virStorageVolDefFindByName(pool, vol->name)) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + "storage vol already exists"); + virStorageVolDefFree(vol); + return NULL; + } + + + if (backend->volCreate(pool, vol) < 0) { + virStorageVolDefFree(vol); + return NULL; + } + + vol->next = pool->volumes; + pool->volumes = vol; + pool->nvolumes++; + + return virGetStorageVol(obj, vol->name, vol->uuid); +} + +static int storageVolumeDestroy(virStorageVolPtr obj) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->pool->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->pool->uuid); + virStoragePoolBackendPtr backend; + virStorageVolDefPtr vol, tmp, prev; + + if (!pool) { + virStorageReportError(obj->pool->conn, VIR_ERR_INVALID_STORAGE_POOL, + "no storage pool with matching uuid"); + return -1; + } + + if (!virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->pool->conn, VIR_ERR_INTERNAL_ERROR, + "storage pool is not active"); + return -1; + } + + if ((backend = storageBackend(pool->def->type)) == NULL) + return -1; + + vol = virStorageVolDefFindByName(pool, obj->name); + + if (!vol) { + virStorageReportError(obj->pool->conn, VIR_ERR_INVALID_STORAGE_POOL, + "no storage vol with matching name"); + return -1; + } + + if (backend->volDelete(pool, vol) < 0) { + return -1; + } + + prev = NULL; + tmp = pool->volumes; + while (tmp) { + if (tmp == vol) { + break; + } + prev = tmp; + tmp = tmp->next; + } + if (prev) { + prev->next = vol->next; + } else { + pool->volumes = vol->next; + } + pool->nvolumes--; + virStorageVolDefFree(vol); + + return 0; +} + +static int storageVolumeGetInfo(virStorageVolPtr obj, virStorageVolInfoPtr info) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->pool->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->pool->uuid); + virStoragePoolBackendPtr backend; + virStorageVolDefPtr vol; + + if (!pool) { + virStorageReportError(obj->pool->conn, VIR_ERR_INVALID_STORAGE_POOL, + "no storage pool with matching uuid"); + return -1; + } + + if (!virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->pool->conn, VIR_ERR_INTERNAL_ERROR, + "storage pool is not active"); + return -1; + } + + vol = virStorageVolDefFindByName(pool, obj->name); + + if (!vol) { + virStorageReportError(obj->pool->conn, VIR_ERR_INVALID_STORAGE_POOL, + "no storage vol with matching name"); + return -1; + } + + if ((backend = storageBackend(pool->def->type)) == NULL) + return -1; + + return backend->volGetInfo(pool, vol, info); +} + +static char *storageVolumeGetXMLDesc(virStorageVolPtr obj, int flags ATTRIBUTE_UNUSED) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->pool->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->pool->uuid); + virStorageVolDefPtr vol; + + if (!pool) { + virStorageReportError(obj->pool->conn, VIR_ERR_INVALID_STORAGE_POOL, + "no storage pool with matching uuid"); + return NULL; + } + + if (!virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->pool->conn, VIR_ERR_INTERNAL_ERROR, + "storage pool is not active"); + return NULL; + } + + vol = virStorageVolDefFindByName(pool, obj->name); + + if (!vol) { + virStorageReportError(obj->pool->conn, VIR_ERR_INVALID_STORAGE_POOL, + "no storage vol with matching name"); + return NULL; + } + + return virStorageVolDefFormat(obj->pool->conn, vol); +} + +static char *storageVolumeGetPath(virStorageVolPtr obj) { + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->pool->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->pool->uuid); + virStorageVolDefPtr vol; + char *ret; + + if (!pool) { + virStorageReportError(obj->pool->conn, VIR_ERR_INVALID_STORAGE_POOL, + "no storage pool with matching uuid"); + return NULL; + } + + if (!virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->pool->conn, VIR_ERR_INTERNAL_ERROR, + "storage pool is not active"); + return NULL; + } + + vol = virStorageVolDefFindByName(pool, obj->name); + + if (!vol) { + virStorageReportError(obj->pool->conn, VIR_ERR_INVALID_STORAGE_POOL, + "no storage vol with matching name"); + return NULL; + } + + ret = strdup(vol->target); + if (ret == NULL) { + virStorageReportError(obj->pool->conn, VIR_ERR_NO_MEMORY, "path"); + return NULL; + } + return ret; +} + + + + + +static virStorageDriver storageDriver = { + "storage", + storageOpen, + storageClose, + storageNumPools, + storageListPools, + storageNumDefinedPools, + storageListDefinedPools, + storagePoolLookupByName, + storagePoolLookupByUUID, + storagePoolCreate, + storagePoolDefine, + storagePoolUndefine, + storagePoolStart, + storagePoolShutdown, + storagePoolDestroy, + storagePoolGetInfo, + storagePoolDumpXML, + storagePoolGetAutostart, + storagePoolSetAutostart, + storagePoolNumVolumes, + storagePoolListVolumes, + storageVolumeLookupByName, + storageVolumeLookupByUUID, + storageVolumeCreateXML, + storageVolumeDestroy, + storageVolumeGetInfo, + storageVolumeGetXMLDesc, + storageVolumeGetPath +}; + + +static virStateDriver stateDriver = { + storageDriverStartup, + storageDriverShutdown, + storageDriverReload, + storageDriverActive, +}; + +int storageRegister(void) { + virRegisterStorageDriver(&storageDriver); + virRegisterStateDriver(&stateDriver); + return 0; +} + +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ + diff -r f57805779ece src/storage_driver.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/storage_driver.h Sun Oct 28 22:45:04 2007 -0400 @@ -0,0 +1,6 @@ + + +#include "storage_conf.h" + + +int storageRegister(void); diff -r f57805779ece src/virterror.c --- a/src/virterror.c Sun Oct 28 22:45:04 2007 -0400 +++ b/src/virterror.c Sun Oct 28 22:45:04 2007 -0400 @@ -280,6 +280,9 @@ virDefaultErrorFunc(virErrorPtr err) case VIR_FROM_REMOTE: dom = "Remote "; break; + case VIR_FROM_STORAGE: + dom = "Storage "; + break; } if ((err->dom != NULL) && (err->code != VIR_ERR_INVALID_DOMAIN)) { domain = err->dom->name; @@ -652,6 +655,36 @@ __virErrorMsg(virErrorNumber error, cons else errmsg = _("invalid MAC adress: %s"); break; + case VIR_ERR_NO_STORAGE_POOL: + if (info == NULL) + errmsg = _("Storage pool not found"); + else + errmsg = _("Storage pool not found: %s"); + break; + case VIR_ERR_NO_STORAGE_VOL: + if (info == NULL) + errmsg = _("Storage volume not found"); + else + errmsg = _("Storage volume not found: %s"); + break; + case VIR_ERR_INVALID_STORAGE_POOL: + if (info == NULL) + errmsg = _("invalid storage pool pointer in"); + else + errmsg = _("invalid storage pool pointer in %s"); + break; + case VIR_ERR_INVALID_STORAGE_VOL: + if (info == NULL) + errmsg = _("invalid storage volume pointer in"); + else + errmsg = _("invalid storage volume pointer in %s"); + break; + case VIR_WAR_NO_STORAGE: + if (info == NULL) + errmsg = _("Failed to find a storage driver"); + else + errmsg = _("Failed to find a storage driver: %s"); + break; } return (errmsg); } -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

As a first observation, I'm getting warnings like: storage_backend_iscsi.c: In function 'virStoragePoolBackendISCSICreate': storage_backend_iscsi.c:4: warning: unused parameter 'pool' storage_backend_iscsi.c: In function 'virStoragePoolBackendISCSIStart': storage_backend_iscsi.c:9: warning: unused parameter 'pool' storage_backend_lvm.c: In function 'virStoragePoolBackendLVMCreate': storage_backend_lvm.c:4: warning: unused parameter 'pool' storage_backend_lvm.c: In function 'virStoragePoolBackendLVMStart': storage_backend_lvm.c:9: warning: unused parameter 'pool' etc. `--enable-compile-warnings=error' should catch these. Rich. -- Emerging Technologies, Red Hat - http://et.redhat.com/~rjones/ Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SL4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 03798903

General comments. (I haven't yet read the patches line by line, but there are some things that I noticed that we can get back to later.) I patched up my libvirt with all the patches (the remote patches turned out to be necessary after all for reasons I now understand -- see below). Out of the box, I can do: # virsh pool-list Name State Autostart ----------------------------------------- Now I have to add my storage pools manually. Even after reading previous mail on the XML formats, it was very unclear what the correct format to use was: # cat /tmp/pool.xml <pool type="fs"> <name>xenimages</name> <uuid>12345678-1234-1234-1234-123456781234</uuid> <target dir="/var/lib/xen/images"/> <permissions> <mode>0700</mode> <owner>0</owner> <group>0</group> <label>xen_image_t</label> </permissions> </pool> # src/virsh pool-create /tmp/pool.xml Pool xenimages created from /tmp/pool.xml The first problem here is that we've got the "secret config files" again. I know that Xen made this idiotic mistake of hiding the config files from the world, and in libvirt we have to work around it for domains, but there's no particular reason why we have to copy this bad, non-Unix-like design decision into other parts of our API. I was envisaging a much more straightforward config file: /etc/libvirt.conf ------------------- disk_storage_pools: [ "/var/lib/xen/images" ] lvm_volgroups: [ "/dev/MyXenImages" ] ------------------------------------- With this, you don't need to put storage logic into libvirtd. It can all be discovered on demand, just using the config file and the commands already included in storage_backend_*.c The upshot is that we don't need a daemon to manage storage pools, except in the remote case where it's just there to do things remotely. (To be fair, the proposed patch seems to have a config file in /etc/libvirt/storage/storage.conf, but it's not implemented at the moment and it is unclear what will go in here, and whether a suitable default can be created to allow storage pools to default to something sensible on Fedora). # src/virsh pool-list Name State Autostart ----------------------------------------- libvir: Storage error : pool has no config file xenimages active no autostart There's no pool-info binding in virsh yet, but there is a corresponding call at the libvirt level and thankfully the output is a struct. Create a volume: # cat /tmp/vol.xml <volume> <name>tempvol</name> <uuid>12345678-1234-1234-1234-123456781234</uuid> <capacity>100000</capacity> <allocation>100000</allocation> <format> <type>raw</type> </format> <permissions> <mode>0700</mode> <owner>0</owner> <group>0</group> <label>xen_image_t</label> </permissions> </volume> # src/virsh vol-create xenimages /tmp/vol.xml (libvirtd dumped core at this point) And I still don't think that passing XML descriptions is a good idea. But because you're envisaging being able to create complex volumes like qcow, encrypted, etc., I will temper this by saying that we should have a small core XML which all drivers MUST support. For example, every driver must support pools and volumes described like this (verbatim, with no extra fields): <pool type="xxx"> <name>xenimages</name> <!-- target should make sense for the xxx driver, eg. path for fs, LUN name for iSCSI, etc. There is no need for the dir=... attribute --> <target>/var/lib/xen/images</target> <!-- permissions should default to sensible values --> </pool> and: <volume> <name>tempvol</name> <!-- I noticed that units are missing from original --> <capacity unit="GiB">10</capacity> <!-- permissions and format should default to sensible --> </volume> Rich. -- Emerging Technologies, Red Hat - http://et.redhat.com/~rjones/ Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SL4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 03798903

On Mon, Oct 29, 2007 at 12:03:34PM +0000, Richard W.M. Jones wrote:
General comments. (I haven't yet read the patches line by line, but there are some things that I noticed that we can get back to later.)
I patched up my libvirt with all the patches (the remote patches turned out to be necessary after all for reasons I now understand -- see below).
Out of the box, I can do:
# virsh pool-list Name State Autostart -----------------------------------------
Now I have to add my storage pools manually. Even after reading previous mail on the XML formats, it was very unclear what the correct format to use was:
# cat /tmp/pool.xml <pool type="fs"> <name>xenimages</name> <uuid>12345678-1234-1234-1234-123456781234</uuid> <target dir="/var/lib/xen/images"/> <permissions> <mode>0700</mode> <owner>0</owner> <group>0</group> <label>xen_image_t</label> </permissions> </pool>
# src/virsh pool-create /tmp/pool.xml Pool xenimages created from /tmp/pool.xml
As we did with virsh attach-disk/attach-interface, vs attach-device I think it would be helpful to provide a 'virsh vol-create' variant which took a handful of explicit args as an alternative to the XML, eg virsh pool-create --type fs xenimages /var/lib/xen/images It wouldn't have the full capabilities to set every single XML attribute/element, but would be good enough so that admins didn't need to write the XML for the 95% common case.
The first problem here is that we've got the "secret config files" again. I know that Xen made this idiotic mistake of hiding the config files from the world, and in libvirt we have to work around it for domains, but there's no particular reason why we have to copy this bad, non-Unix-like design decision into other parts of our API.
The config file are not hidden/secret - they're in the usual libvirt daemon config location /etc/libvirt/storage/[pool name].xml As we do with the 'default' network, we can easily ship a canned config file for say, /var/lib/virt/images as a local directory based pool. Any other type of pool is going to be site-specific, but we can provide a selection of common example configs as needed.
I was envisaging a much more straightforward config file:
/etc/libvirt.conf -------------------
disk_storage_pools: [ "/var/lib/xen/images" ] lvm_volgroups: [ "/dev/MyXenImages" ] -------------------------------------
That is not sufficient to describe all the metadata for the different types of storage pool.
With this, you don't need to put storage logic into libvirtd. It can all be discovered on demand, just using the config file and the commands already included in storage_backend_*.c The upshot is that we don't need a daemon to manage storage pools, except in the remote case where it's just there to do things remotely.
To be honest even in the local case we need the daemon. The only reason we previously get away without having a daemon when running locally, is that the entire virt-manager app has run as root. Long term I think pretty much all libvirt clients will be going via the daemon, whether local or remote.
(To be fair, the proposed patch seems to have a config file in /etc/libvirt/storage/storage.conf, but it's not implemented at the moment and it is unclear what will go in here, and whether a suitable default can be created to allow storage pools to default to something sensible on Fedora).
# src/virsh pool-list Name State Autostart ----------------------------------------- libvir: Storage error : pool has no config file xenimages active no autostart
Opps, that error message is a bug.
There's no pool-info binding in virsh yet, but there is a corresponding call at the libvirt level and thankfully the output is a struct.
Yep, I was planning to add a pool-info API to list the capacity vs allocation of the pool & name, uuid, etc, as with dom-info. Likeiwise for the vol-info API
Create a volume:
# cat /tmp/vol.xml <volume> <name>tempvol</name> <uuid>12345678-1234-1234-1234-123456781234</uuid> <capacity>100000</capacity> <allocation>100000</allocation> <format> <type>raw</type> </format> <permissions> <mode>0700</mode> <owner>0</owner> <group>0</group> <label>xen_image_t</label> </permissions> </volume>
# src/virsh vol-create xenimages /tmp/vol.xml (libvirtd dumped core at this point)
The format type was not quite right <format type='raw'>. It obviously shouldn't dump core though! NB, <format> is actually optional - it defaults to raw. Permissions should be optional, but currently aren't. Allocation is optional too, without it, you will get a sparse file.
And I still don't think that passing XML descriptions is a good idea.
But because you're envisaging being able to create complex volumes like qcow, encrypted, etc., I will temper this by saying that we should have a small core XML which all drivers MUST support.
For example, every driver must support pools and volumes described like this (verbatim, with no extra fields):
<pool type="xxx"> <name>xenimages</name> <!-- target should make sense for the xxx driver, eg. path for fs, LUN name for iSCSI, etc. There is no need for the dir=... attribute --> <target>/var/lib/xen/images</target> <!-- permissions should default to sensible values --> </pool>
Yep, I intended permissions to be optional. Not all pools have a target, some only have a source. Basically name,and either target or source is the minimal set. Everything else should be optional.
and:
<volume> <name>tempvol</name> <!-- I noticed that units are missing from original --> <capacity unit="GiB">10</capacity> <!-- permissions and format should default to sensible --> </volume>
Yes, adding units is a good idea. That looks good as a minimal dataset. Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

On Mon, Oct 29, 2007 at 01:52:04PM +0000, Daniel P. Berrange wrote:
On Mon, Oct 29, 2007 at 12:03:34PM +0000, Richard W.M. Jones wrote:
I was envisaging a much more straightforward config file:
/etc/libvirt.conf -------------------
disk_storage_pools: [ "/var/lib/xen/images" ] lvm_volgroups: [ "/dev/MyXenImages" ] -------------------------------------
That is not sufficient to describe all the metadata for the different types of storage pool.
To expand on that slightly. In the case of LVM volume groups. If the volume group already exists it may be sufficient to just provide the target path. There may be times though when the volgroup does not yet exist. In this scenario, the multiple <source dev='/dev/sda1'/> elements in the XMLdescription will be used as paths for the physical volumes and a new VG created from them. Similarly, when dumping the XML this will tell you what devices are part of the pool.
With this, you don't need to put storage logic into libvirtd. It can all be discovered on demand, just using the config file and the commands already included in storage_backend_*.c The upshot is that we don't need a daemon to manage storage pools, except in the remote case where it's just there to do things remotely.
To be honest even in the local case we need the daemon. The only reason we previously get away without having a daemon when running locally, is that the entire virt-manager app has run as root. Long term I think pretty much all libvirt clients will be going via the daemon, whether local or remote.
THe more compelling reason for having the stateful driver in the daemon is that some storage needs to be activated manually & wont be explicitly available when a machine boots. This is what the autostart capability allows for - when the daemon starts will be automatically start all virtual networks, and all storage pools which need activation. This will typically mean logging into the iSCSI server, or mounting the disk on a path. There may be dependancies here - mounting the disk, may first require that the iSCSI server is activated, so we can't simply stick the disk mounts into /etc/fstab for auto mounting in that way. Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

Daniel P. Berrange wrote:
On Mon, Oct 29, 2007 at 01:52:04PM +0000, Daniel P. Berrange wrote:
On Mon, Oct 29, 2007 at 12:03:34PM +0000, Richard W.M. Jones wrote:
I was envisaging a much more straightforward config file:
/etc/libvirt.conf -------------------
disk_storage_pools: [ "/var/lib/xen/images" ] lvm_volgroups: [ "/dev/MyXenImages" ] ------------------------------------- That is not sufficient to describe all the metadata for the different types of storage pool.
To expand on that slightly. In the case of LVM volume groups. If the volume group already exists it may be sufficient to just provide the target path. There may be times though when the volgroup does not yet exist. In this scenario, the multiple <source dev='/dev/sda1'/> elements in the XMLdescription will be used as paths for the physical volumes and a new VG created from them. Similarly, when dumping the XML this will tell you what devices are part of the pool.
I would have said that creating VGs was outside the scope of what libvirt should be trying to do. Sounds like a real edge case that hardly any actual sys admins will exercise, since they can do a one-off VG creation when they install their server.
With this, you don't need to put storage logic into libvirtd. It can all be discovered on demand, just using the config file and the commands already included in storage_backend_*.c The upshot is that we don't need a daemon to manage storage pools, except in the remote case where it's just there to do things remotely. To be honest even in the local case we need the daemon. The only reason we previously get away without having a daemon when running locally, is that the entire virt-manager app has run as root. Long term I think pretty much all libvirt clients will be going via the daemon, whether local or remote.
THe more compelling reason for having the stateful driver in the daemon is that some storage needs to be activated manually & wont be explicitly available when a machine boots. This is what the autostart capability allows for - when the daemon starts will be automatically start all virtual networks, and all storage pools which need activation. This will typically mean logging into the iSCSI server, or mounting the disk on a path. There may be dependancies here - mounting the disk, may first require that the iSCSI server is activated, so we can't simply stick the disk mounts into /etc/fstab for auto mounting in that way.
Well possibly, but possibly also it's better to leave this up to device-dependent /etc/init.d scripts. Rich. -- Emerging Technologies, Red Hat - http://et.redhat.com/~rjones/ Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SL4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 03798903

On Mon, Oct 29, 2007 at 02:50:43PM +0000, Richard W.M. Jones wrote:
Daniel P. Berrange wrote:
On Mon, Oct 29, 2007 at 01:52:04PM +0000, Daniel P. Berrange wrote:
On Mon, Oct 29, 2007 at 12:03:34PM +0000, Richard W.M. Jones wrote:
I was envisaging a much more straightforward config file:
/etc/libvirt.conf -------------------
disk_storage_pools: [ "/var/lib/xen/images" ] lvm_volgroups: [ "/dev/MyXenImages" ] ------------------------------------- That is not sufficient to describe all the metadata for the different types of storage pool.
To expand on that slightly. In the case of LVM volume groups. If the volume group already exists it may be sufficient to just provide the target path. There may be times though when the volgroup does not yet exist. In this scenario, the multiple <source dev='/dev/sda1'/> elements in the XMLdescription will be used as paths for the physical volumes and a new VG created from them. Similarly, when dumping the XML this will tell you what devices are part of the pool.
I would have said that creating VGs was outside the scope of what libvirt should be trying to do. Sounds like a real edge case that hardly any actual sys admins will exercise, since they can do a one-off VG creation when they install their server.
The use case I was thinking about s the context of iSCSI. The sysadmin team managing the iSCSI storage volumes may provide you a target with a couple of LUNS. You wish to put those LUNS into an LVM volume on the host, thus enabling you to carve up the iSCSI storage locally to your host without needing to roundtrip through the storage sysadmin team every time. So being able to create LVM VGs is pretty critical if we want this kind of remote management of the iSCSI storage. Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

Daniel P. Berrange wrote:
As we did with virsh attach-disk/attach-interface, vs attach-device I think it would be helpful to provide a 'virsh vol-create' variant which took a handful of explicit args as an alternative to the XML,
eg virsh pool-create --type fs xenimages /var/lib/xen/images
Yes, vital really, and even better if it's a libvirt call.
NB, <format> is actually optional - it defaults to raw. Permissions should be optional, but currently aren't. Allocation is optional too, without it, you will get a sparse file.
I didn't really understand the semantics of <allocation>. It should be <sparse/> AFAICS. This underlines actually why XML is so much more slippery than real typing.
<pool type="xxx"> <name>xenimages</name> <!-- target should make sense for the xxx driver, eg. path for fs, LUN name for iSCSI, etc. There is no need for the dir=... attribute --> <target>/var/lib/xen/images</target> <!-- permissions should default to sensible values --> </pool>
Yep, I intended permissions to be optional. Not all pools have a target, some only have a source. Basically name,and either target or source is the minimal set. Everything else should be optional.
But to avoid lots of switch/case in the caller we should also avoid using an attribute name (<target> vs <target dir=...>). Rich. -- Emerging Technologies, Red Hat - http://et.redhat.com/~rjones/ Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SL4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 03798903

On Mon, Oct 29, 2007 at 02:49:16PM +0000, Richard W.M. Jones wrote:
Daniel P. Berrange wrote:
As we did with virsh attach-disk/attach-interface, vs attach-device I think it would be helpful to provide a 'virsh vol-create' variant which took a handful of explicit args as an alternative to the XML,
eg virsh pool-create --type fs xenimages /var/lib/xen/images
Yes, vital really, and even better if it's a libvirt call.
NB, <format> is actually optional - it defaults to raw. Permissions should be optional, but currently aren't. Allocation is optional too, without it, you will get a sparse file.
I didn't really understand the semantics of <allocation>. It should be <sparse/> AFAICS. This underlines actually why XML is so much more slippery than real typing.
Basically, capacity is intended to be the logical size, while allocation is the amount of space used on the host. So in the case of raw files, capacity is the size we ftruncate to, while allocation is actual disk blocks consumed. With VMDK / QCOw & other auto-grow disk formats, capacity is a piece of metadata embedded in the disk metdata - they don't use sparse files on the host disk, while again allocation is disks blocks allocated up front. So sparse is only really a concept for raw files where you litterally do have a sparsely allocated file on the filesystem. IIRC some logical volume managers also have a concept of volume size, vs volume allocation, allowing blocks from the VG to be dynamically allocated to LV, rather than fixed upfront. Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

"Daniel P. Berrange" <berrange@redhat.com> wrote:
Since the previous discussions didn't really end up anywhere conclusive I decided it would be better to have a crack at getting some working code to illustrate my ideas. Thus, the following series of 7 patches provide
Hi Dan, Impressive work! It's taken me a while just to digest all of this. ...
Some open questions
- Is it worth bothering with a UUID for individual storage volumes. It is possible to construct a globally unique identifier for most volumes, by combing various bits of metadata we have such as device unique ID, inode, iSCSI target & LUN, etc There isn't really any UUID that fits into the classic libvirt 16 byte UUID. I've implemented (randomly generated) UUIDs for the virStorageVolPtr object, but I'm inclined to remove them, since its not much use if they change each time the libvirtd daemon is restarted.
The 'name' field provides a unique identifier scoped to the storage pool. I think we could add a 'char *key' field, as an arbitrary opaque string, forming a globally unique identifier for the volume. This would serve same purpose as UUID, but without the 16 bytes constraint which we can't usefully provide.
That sounds good. And with it being opaque, no one will be tempted (or able) to rely on it.
- For the local directory backend, I've got the ability to choose between file formats on a per-volume basis. eg, /var/lib/xen/images can contain a mix of raw, qcow, vmdk, etc files. This is nice & flexible for the user, but a more complex thing to implement, since it means we have to probe each volume and try & figure out its format each
Have there been requests for this feature? The probe-and-recognize part doesn't sound too hard, but if a large majority of use cases have homogeneous volumes-per-pool, then for starters at least, maybe we can avoid the complexity. A possible compromise (albeit ugly), _if_ we can dictate naming policy: let part of a volume name (suffix, substring, component, whatever) tell libvirtd its type. As I said, ugly, and hence probably not worth considering, but I had to say it :-)
time we list volumes. If we constrained the choice between formats to be at the pool level instead of the volume level we could avoid probing & thus simplify the code. This is what XenAPI does.
- If creating non-sparse files, it can take a very long time to do the I/O to fill in the image. In virt-intsall/virt-manager we have nice incremental progress display. The API I've got currently though is blocking. This blocks the calling application. It also blocks the entire libvirtd daemon since we are single process. There are a couple of ways we can address this:
1 Allow the libvirtd daemon to serve each client connection in a separate thread. We'd need to adding some mutex locking to the QEMU driver and the storage driver to handle this. It would have been nice to avoid threads, but I don't think we can much longer.
2 For long running operations, spawn off a worker thread (or process) to perform the operation. Don't send a reply to the RPC message, instead just put the client on a 'wait queue', and get on with serving other clients. When the worker thread completes, send the RPC reply to the original client.
3 Having the virStorageVolCreate() method return immediately, giving back the client app some kind of 'job id'. The client app can poll on another API virStorageVolJob() method to determine how far through the task has got. The implementation in the driver would have to spawn a worker thread to do the actual long operation.
I like the idea of spawning off a thread for a very precise and limited-scope task. On first reading, I preferred your #2 worker-thread-based solution. Then, client apps simply wait -- i.e., don't have to poll. But we'd still need another interface for progress feedback, so #3 starts to look better: client progress feedback might come almost for free, while polling to check for completion.
Possibly we can allow creation to be async or blocking by making use of the 'flags' field to virStorageVolCreate() method, eg VIR_STORAGE_ASYNC. If we make async behaviour optional, we still need some work in the daemon to avoid blocking all clients.
This problem will also impact us when we add cloning of existing volumes. It already sort of hits us when saving & restoring VMs if they have large amounts of memory. So perhaps we need togo for the general solution of making the daemon threaded per client connection. The ASYNC flag may still be useful anyway to get the incremental progress feedback in the UI.
Could we just treat that as another type of task to hand out to a worker thread? Otherwise, this (#1) sounds a lot more invasive, but that's just my relatively uninformed impression.

On Wed, Oct 31, 2007 at 02:16:26PM +0100, Jim Meyering wrote:
"Daniel P. Berrange" <berrange@redhat.com> wrote:
- For the local directory backend, I've got the ability to choose between file formats on a per-volume basis. eg, /var/lib/xen/images can contain a mix of raw, qcow, vmdk, etc files. This is nice & flexible for the user, but a more complex thing to implement, since it means we have to probe each volume and try & figure out its format each
Have there been requests for this feature? The probe-and-recognize part doesn't sound too hard, but if a large majority of use cases have homogeneous volumes-per-pool, then for starters at least, maybe we can avoid the complexity.
The 'qemu-img' command has an 'info' command to get back metadata for all the different formats it knows about. I've realized we already need to run this command to get disk capacity out for non-raw files, so we'd be doing the probe & recognie bit anyway.
A possible compromise (albeit ugly), _if_ we can dictate naming policy: let part of a volume name (suffix, substring, component, whatever) tell libvirtd its type. As I said, ugly, and hence probably not worth considering, but I had to say it :-)
Yeah I thought about this, but I think I'd like to be able to have libvirt manage a storage pool that was previously created by an admin, which means we can't really assume that al the files are the same format, or that they have a consistent file extension.
- If creating non-sparse files, it can take a very long time to do the I/O to fill in the image. In virt-intsall/virt-manager we have nice incremental progress display. The API I've got currently though is blocking. This blocks the calling application. It also blocks the entire libvirtd daemon since we are single process. There are a couple of ways we can address this:
1 Allow the libvirtd daemon to serve each client connection in a separate thread. We'd need to adding some mutex locking to the QEMU driver and the storage driver to handle this. It would have been nice to avoid threads, but I don't think we can much longer.
2 For long running operations, spawn off a worker thread (or process) to perform the operation. Don't send a reply to the RPC message, instead just put the client on a 'wait queue', and get on with serving other clients. When the worker thread completes, send the RPC reply to the original client.
3 Having the virStorageVolCreate() method return immediately, giving back the client app some kind of 'job id'. The client app can poll on another API virStorageVolJob() method to determine how far through the task has got. The implementation in the driver would have to spawn a worker thread to do the actual long operation.
I like the idea of spawning off a thread for a very precise and limited-scope task.
On first reading, I preferred your #2 worker-thread-based solution. Then, client apps simply wait -- i.e., don't have to poll. But we'd still need another interface for progress feedback, so #3 starts to look better: client progress feedback might come almost for free, while polling to check for completion.
Possibly we can allow creation to be async or blocking by making use of the 'flags' field to virStorageVolCreate() method, eg VIR_STORAGE_ASYNC. If we make async behaviour optional, we still need some work in the daemon to avoid blocking all clients.
This problem will also impact us when we add cloning of existing volumes. It already sort of hits us when saving & restoring VMs if they have large amounts of memory. So perhaps we need togo for the general solution of making the daemon threaded per client connection. The ASYNC flag may still be useful anyway to get the incremental progress feedback in the UI.
Could we just treat that as another type of task to hand out to a worker thread?
Yes, that could work - we'd basically end up doing a combo of #2 and #3 in that case. Always do the long jobs in a dedicated worker thread. If client uses the ASYNC flag they can poll for completion/progress. if they don't use ASYNC flag, we can just stuff them on a wait queue until the job worker thread finishes.
Otherwise, this (#1) sounds a lot more invasive, but that's just my relatively uninformed impression.
Yes, option #1 is defintely much much more invasive. At the very least we'll need to put in significant mutex locking for the QEMU driver global state. Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
participants (4)
-
Daniel P. Berrange
-
Daniel Veillard
-
Jim Meyering
-
Richard W.M. Jones