[libvirt] PATCH: 0/12: Modular build & node devices integration

The following series of patches are updated version of patches 7-11 of this series http://www.redhat.com/archives/libvir-list/2008-October/msg00718.html And integrating David Lively's node device patches ontop Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

This patch changes the makefile to build all drivers as libtool convenience libraries. Daniel diff -r 99484df67fe0 src/Makefile.am --- a/src/Makefile.am Fri Nov 07 11:53:35 2008 +0000 +++ b/src/Makefile.am Fri Nov 07 11:54:20 2008 +0000 @@ -6,11 +6,7 @@ -I@top_srcdir@/include \ -I@top_srcdir@/qemud \ $(LIBXML_CFLAGS) \ - $(GNUTLS_CFLAGS) \ - $(SASL_CFLAGS) \ $(SELINUX_CFLAGS) \ - $(NUMACTL_CFLAGS) \ - $(XEN_CFLAGS) \ -DBINDIR=\""$(libexecdir)"\" \ -DSBINDIR=\""$(sbindir)"\" \ -DSYSCONF_DIR="\"$(sysconfdir)\"" \ @@ -18,10 +14,6 @@ -DLOCAL_STATE_DIR=\""$(localstatedir)"\" \ -DGETTEXT_PACKAGE=\"$(PACKAGE)\" \ $(WARN_CFLAGS) - -DEPS = libvirt.la -LDADDS = @STATIC_BINARIES@ $(WARN_CFLAGS) libvirt.la ../gnulib/lib/libgnu.la -VIRSH_LIBS = @VIRSH_LIBS@ confdir = $(sysconfdir)/libvirt/ conf_DATA = qemu.conf @@ -40,7 +32,7 @@ # These files are not related to driver APIs. Simply generic # helper APIs for various purposes -GENERIC_LIB_SOURCES = \ +UTIL_SOURCES = \ bridge.c bridge.h \ buf.c buf.h \ conf.c conf.h \ @@ -54,6 +46,16 @@ virterror.c virterror_internal.h \ logging.c logging.h \ xml.c xml.h + +# Internal generic driver infrastructure +DRIVER_SOURCES = \ + driver.h \ + internal.h \ + datatypes.c datatypes.h \ + domain_event.c domain_event.h \ + stats_linux.c stats_linux.h \ + libvirt.c libvirt_internal.h + # Domain driver generic impl APIs DOMAIN_CONF_SOURCES = \ @@ -147,62 +149,91 @@ # # First deal with sources usable in non-daemon context -libvirt_la_SOURCES = \ - driver.h \ - internal.h \ - datatypes.c datatypes.h \ - domain_event.c domain_event.h \ - stats_linux.c stats_linux.h \ - libvirt.c libvirt_internal.h \ - $(GENERIC_LIB_SOURCES) \ +noinst_LTLIBRARIES = libvirt_util.la +libvirt_la_LIBADD = libvirt_util.la +libvirt_util_la_SOURCES = \ + $(UTIL_SOURCES) + +noinst_LTLIBRARIES += libvirt_driver.la +libvirt_la_LIBADD += libvirt_driver.la +libvirt_driver_la_SOURCES = \ + $(DRIVER_SOURCES) \ $(DOMAIN_CONF_SOURCES) \ $(NETWORK_CONF_SOURCES) \ $(STORAGE_CONF_SOURCES) if WITH_TEST -libvirt_la_SOURCES += $(TEST_DRIVER_SOURCES) +noinst_LTLIBRARIES += libvirt_driver_test.la +libvirt_la_LIBADD += libvirt_driver_test.la +libvirt_driver_test_la_SOURCES = $(TEST_DRIVER_SOURCES) endif if WITH_REMOTE -libvirt_la_SOURCES += $(REMOTE_DRIVER_SOURCES) +noinst_LTLIBRARIES += libvirt_driver_remote.la +libvirt_la_LIBADD += libvirt_driver_remote.la +libvirt_driver_remote_la_CFLAGS = \ + $(GNUTLS_CFLAGS) \ + $(SASL_CFLAGS) +libvirt_driver_remote_la_LDFLAGS = \ + $(GNUTLS_LIBS) \ + $(SASL_LIBS) +libvirt_driver_remote_la_SOURCES = $(REMOTE_DRIVER_SOURCES) endif if WITH_XEN -libvirt_la_SOURCES += $(XEN_DRIVER_SOURCES) +noinst_LTLIBRARIES += libvirt_driver_xen.la +libvirt_la_LIBADD += libvirt_driver_xen.la +libvirt_driver_xen_la_CFLAGS = $(XEN_CFLAGS) +libvirt_driver_xen_la_LDFLAGS = $(XEN_LIBS) +libvirt_driver_xen_la_SOURCES = $(XEN_DRIVER_SOURCES) endif if WITH_OPENVZ -libvirt_la_SOURCES += $(OPENVZ_DRIVER_SOURCES) +noinst_LTLIBRARIES += libvirt_driver_openvz.la +libvirt_la_LIBADD += libvirt_driver_openvz.la +libvirt_driver_openvz_la_SOURCES = $(OPENVZ_DRIVER_SOURCES) endif if WITH_QEMU -libvirt_la_SOURCES += $(QEMU_DRIVER_SOURCES) +noinst_LTLIBRARIES += libvirt_driver_qemu.la +libvirt_la_LIBADD += libvirt_driver_qemu.la +libvirt_driver_qemu_la_CFLAGS = $(NUMACTL_CFLAGS) +libvirt_driver_qemu_la_LDFLAGS = $(NUMACTL_LIBS) +libvirt_driver_qemu_la_SOURCES = $(QEMU_DRIVER_SOURCES) endif if WITH_LXC -libvirt_la_SOURCES += $(LXC_DRIVER_SOURCES) +noinst_LTLIBRARIES += libvirt_driver_lxc.la +libvirt_la_LIBADD += libvirt_driver_lxc.la +libvirt_driver_lxc_la_SOURCES = $(LXC_DRIVER_SOURCES) endif if WITH_NETWORK -libvirt_la_SOURCES += $(NETWORK_DRIVER_SOURCES) +noinst_LTLIBRARIES += libvirt_driver_network.la +libvirt_la_LIBADD += libvirt_driver_network.la +libvirt_driver_network_la_SOURCES = $(NETWORK_DRIVER_SOURCES) endif +# Needed to keep automake quiet about conditionals +libvirt_driver_storage_la_SOURCES = if WITH_STORAGE_DIR -libvirt_la_SOURCES += $(STORAGE_DRIVER_SOURCES) -libvirt_la_SOURCES += $(STORAGE_DRIVER_FS_SOURCES) +noinst_LTLIBRARIES += libvirt_driver_storage.la +libvirt_la_LIBADD += libvirt_driver_storage.la +libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_SOURCES) +libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_FS_SOURCES) endif if WITH_STORAGE_LVM -libvirt_la_SOURCES += $(STORAGE_DRIVER_LVM_SOURCES) +libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_LVM_SOURCES) endif if WITH_STORAGE_ISCSI -libvirt_la_SOURCES += $(STORAGE_DRIVER_ISCSI_SOURCES) +libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_ISCSI_SOURCES) endif if WITH_STORAGE_DISK -libvirt_la_SOURCES += $(STORAGE_DRIVER_DISK_SOURCES) +libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_DISK_SOURCES) endif # Add all conditional sources just in case... @@ -221,8 +252,9 @@ $(STORAGE_DRIVER_DISK_SOURCES) -libvirt_la_LIBADD = $(LIBXML_LIBS) $(GNUTLS_LIBS) $(SASL_LIBS) $(SELINUX_LIBS) \ - $(NUMACTL_LIBS) $(XEN_LIBS) \ +# Empty source list - it merely links a bunch of convenience libs together +libvirt_la_SOURCES = +libvirt_la_LIBADD += $(LIBXML_LIBS) $(SELINUX_LIBS) \ @CYGWIN_EXTRA_LIBADD@ ../gnulib/lib/libgnu.la libvirt_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libvirt_sym.version \ -version-info @LIBVIRT_VERSION_INFO@ \ @@ -233,7 +265,7 @@ # Create an automake "convenience library" version of libvirt_la, # just for testing, since the test harness requires access to internal # bits and pieces that we don't want to make publicly accessible. -noinst_LTLIBRARIES = libvirt_test.la +noinst_LTLIBRARIES += libvirt_test.la # Convert libvirt_sym.version # to libvirt_test_sym.version, and @@ -257,8 +289,12 @@ virsh.c virsh_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDFLAGS) -virsh_DEPENDENCIES = $(DEPS) -virsh_LDADD = $(LDADDS) $(VIRSH_LIBS) +virsh_LDADD = \ + $(STATIC_BINARIES) \ + $(WARN_CFLAGS) \ + libvirt.la \ + ../gnulib/lib/libgnu.la \ + $(VIRSH_LIBS) virsh_CFLAGS = $(COVERAGE_CFLAGS) $(READLINE_CFLAGS) BUILT_SOURCES = virsh-net-edit.c virsh-pool-edit.c @@ -295,7 +331,6 @@ if WITH_WIN_ICON virsh_LDADD += virsh_win_icon.$(OBJEXT) -virsh_DEPENDENCIES += virsh_win_icon.$(OBJEXT) # Before you edit virsh_win_icon.rc, please note the following # limitations of the resource file format: @@ -341,7 +376,7 @@ libvirt_lxc_SOURCES = \ $(LXC_CONTROLLER_SOURCES) \ - $(GENERIC_LIB_SOURCES) \ + $(UTIL_SOURCES) \ $(DOMAIN_CONF_SOURCES) libvirt_lxc_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDCFLAGS) libvirt_lxc_LDADD = $(LIBXML_LIBS) ../gnulib/lib/libgnu.la -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Thu, Nov 13, 2008 at 05:20:26PM +0000, Daniel P. Berrange wrote:
This patch changes the makefile to build all drivers as libtool convenience libraries.
Okay, +1 Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

This patch changes the way we use linker scripts to have fully versioned symbols, and a versioned private section for symbols needed by libvirtd and virsh. Daniel diff -r bbf3d0bc9d49 configure.in --- a/configure.in Tue Nov 11 17:28:27 2008 +0000 +++ b/configure.in Tue Nov 11 17:28:31 2008 +0000 @@ -1076,6 +1076,7 @@ gnulib/lib/Makefile \ gnulib/tests/Makefile \ libvirt.pc libvirt.spec mingw32-libvirt.spec \ + src/libvirt_sym.version \ po/Makefile.in \ include/libvirt/Makefile include/libvirt/libvirt.h \ python/Makefile python/tests/Makefile \ diff -r bbf3d0bc9d49 qemud/Makefile.am --- a/qemud/Makefile.am Tue Nov 11 17:28:27 2008 +0000 +++ b/qemud/Makefile.am Tue Nov 11 17:28:31 2008 +0000 @@ -7,8 +7,7 @@ remote_dispatch_prototypes.h \ remote_dispatch_localvars.h \ remote_dispatch_proc_switch.h \ - remote_protocol.h remote_protocol.c \ - $(srcdir)/../src/util-lib.c + remote_protocol.h remote_protocol.c AVAHI_SOURCES = \ mdns.c mdns.h diff -r bbf3d0bc9d49 qemud/remote.c --- a/qemud/remote.c Tue Nov 11 17:28:27 2008 +0000 +++ b/qemud/remote.c Tue Nov 11 17:28:31 2008 +0000 @@ -487,7 +487,7 @@ { CHECK_CONN(client); - ret->supported = __virDrvSupportsFeature (client->conn, args->feature); + ret->supported = virDrvSupportsFeature (client->conn, args->feature); if (ret->supported == -1) return -1; return 0; @@ -1396,9 +1396,9 @@ return -2; } - r = __virDomainMigratePrepare (client->conn, &cookie, &cookielen, - uri_in, uri_out, - args->flags, dname, args->resource); + r = virDomainMigratePrepare (client->conn, &cookie, &cookielen, + uri_in, uri_out, + args->flags, dname, args->resource); if (r == -1) { VIR_FREE(uri_out); return -1; @@ -1439,11 +1439,11 @@ dname = args->dname == NULL ? NULL : *args->dname; - r = __virDomainMigratePerform (dom, - args->cookie.cookie_val, - args->cookie.cookie_len, - args->uri, - args->flags, dname, args->resource); + r = virDomainMigratePerform (dom, + args->cookie.cookie_val, + args->cookie.cookie_len, + args->uri, + args->flags, dname, args->resource); virDomainFree (dom); if (r == -1) return -1; @@ -1460,11 +1460,11 @@ virDomainPtr ddom; CHECK_CONN (client); - ddom = __virDomainMigrateFinish (client->conn, args->dname, - args->cookie.cookie_val, - args->cookie.cookie_len, - args->uri, - args->flags); + ddom = virDomainMigrateFinish (client->conn, args->dname, + args->cookie.cookie_val, + args->cookie.cookie_len, + args->uri, + args->flags); if (ddom == NULL) return -1; make_nonnull_domain (&ret->ddom, ddom); diff -r bbf3d0bc9d49 src/Makefile.am --- a/src/Makefile.am Tue Nov 11 17:28:27 2008 +0000 +++ b/src/Makefile.am Tue Nov 11 17:28:31 2008 +0000 @@ -285,7 +285,6 @@ virsh_SOURCES = \ console.c console.h \ - util-lib.c util-lib.h \ virsh.c virsh_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDFLAGS) diff -r bbf3d0bc9d49 src/buf.c --- a/src/buf.c Tue Nov 11 17:28:27 2008 +0000 +++ b/src/buf.c Tue Nov 11 17:28:31 2008 +0000 @@ -88,7 +88,7 @@ * */ void -__virBufferAdd(const virBufferPtr buf, const char *str, int len) +virBufferAdd(const virBufferPtr buf, const char *str, int len) { unsigned int needSize; @@ -120,7 +120,7 @@ * */ void -__virBufferAddChar (virBufferPtr buf, char c) +virBufferAddChar (virBufferPtr buf, char c) { unsigned int needSize; @@ -150,7 +150,7 @@ * Returns the buffer content or NULL in case of error. */ char * -__virBufferContentAndReset(const virBufferPtr buf) +virBufferContentAndReset(const virBufferPtr buf) { char *str; if (buf == NULL) @@ -176,7 +176,7 @@ * Return true if in error, 0 if normal */ int -__virBufferError(const virBufferPtr buf) +virBufferError(const virBufferPtr buf) { if (buf == NULL) return 1; @@ -208,7 +208,7 @@ * Do a formatted print to an XML buffer. */ void -__virBufferVSprintf(const virBufferPtr buf, const char *format, ...) +virBufferVSprintf(const virBufferPtr buf, const char *format, ...) { int size, count, grow_size; va_list locarg, argptr; diff -r bbf3d0bc9d49 src/buf.h --- a/src/buf.h Tue Nov 11 17:28:27 2008 +0000 +++ b/src/buf.h Tue Nov 11 17:28:31 2008 +0000 @@ -34,25 +34,18 @@ }; #endif -char *__virBufferContentAndReset(const virBufferPtr buf); -int __virBufferError(const virBufferPtr buf); +char *virBufferContentAndReset(const virBufferPtr buf); +int virBufferError(const virBufferPtr buf); unsigned int virBufferUse(const virBufferPtr buf); -void __virBufferAdd(const virBufferPtr buf, const char *str, int len); -void __virBufferAddChar(const virBufferPtr buf, char c); -void __virBufferVSprintf(const virBufferPtr buf, const char *format, ...) +void virBufferAdd(const virBufferPtr buf, const char *str, int len); +void virBufferAddChar(const virBufferPtr buf, char c); +void virBufferVSprintf(const virBufferPtr buf, const char *format, ...) ATTRIBUTE_FORMAT(printf, 2, 3); void virBufferStrcat(const virBufferPtr buf, ...); void virBufferEscapeString(const virBufferPtr buf, const char *format, const char *str); void virBufferURIEncodeString (const virBufferPtr buf, const char *str); #define virBufferAddLit(buf_, literal_string_) \ - __virBufferAdd (buf_, "" literal_string_ "", sizeof literal_string_ - 1) - -#define virBufferAdd(b,s,l) __virBufferAdd((b),(s),(l)) -#define virBufferAddChar(b,c) __virBufferAddChar((b),(c)) -#define virBufferVSprintf(b,f,...) __virBufferVSprintf((b),(f), __VA_ARGS__) - -#define virBufferContentAndReset(b) __virBufferContentAndReset((b)) -#define virBufferError(b) __virBufferError((b)) + virBufferAdd (buf_, "" literal_string_ "", sizeof literal_string_ - 1) #endif /* __VIR_BUFFER_H__ */ diff -r bbf3d0bc9d49 src/conf.c --- a/src/conf.c Tue Nov 11 17:28:27 2008 +0000 +++ b/src/conf.c Tue Nov 11 17:28:31 2008 +0000 @@ -142,7 +142,7 @@ * Free a value */ void -__virConfFreeValue(virConfValuePtr val) +virConfFreeValue(virConfValuePtr val) { if (val == NULL) return; @@ -156,7 +156,7 @@ } virConfPtr -__virConfNew(void) +virConfNew(void) { virConfPtr ret; @@ -691,7 +691,7 @@ #define MAX_CONFIG_FILE_SIZE (1024*1024*10) /** - * __virConfReadFile: + * virConfReadFile: * @filename: the path to the configuration file. * * Reads a configuration file. @@ -700,7 +700,7 @@ * read or parse the file, use virConfFree() to free the data. */ virConfPtr -__virConfReadFile(const char *filename) +virConfReadFile(const char *filename) { char *content; int len; @@ -724,7 +724,7 @@ } /** - * __virConfReadMem: + * virConfReadMem: * @memory: pointer to the content of the configuration file * @len: length in byte * @@ -735,7 +735,7 @@ * parse the content, use virConfFree() to free the data. */ virConfPtr -__virConfReadMem(const char *memory, int len) +virConfReadMem(const char *memory, int len) { if ((memory == NULL) || (len < 0)) { virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); @@ -748,7 +748,7 @@ } /** - * __virConfFree: + * virConfFree: * @conf: a configuration file handle * * Frees all data associated to the handle @@ -756,7 +756,7 @@ * Returns 0 in case of success, -1 in case of error. */ int -__virConfFree(virConfPtr conf) +virConfFree(virConfPtr conf) { virConfEntryPtr tmp; if (conf == NULL) { @@ -779,7 +779,7 @@ } /** - * __virConfGetValue: + * virConfGetValue: * @conf: a configuration file handle * @entry: the name of the entry * @@ -789,7 +789,7 @@ * associated will be freed when virConfFree() is called */ virConfValuePtr -__virConfGetValue(virConfPtr conf, const char *setting) +virConfGetValue(virConfPtr conf, const char *setting) { virConfEntryPtr cur; @@ -803,7 +803,7 @@ } /** - * __virConfSetValue: + * virConfSetValue: * @conf: a configuration file handle * @entry: the name of the entry * @value: the new configuration value @@ -816,9 +816,9 @@ * Returns 0 on success, or -1 on failure. */ int -__virConfSetValue (virConfPtr conf, - const char *setting, - virConfValuePtr value) +virConfSetValue (virConfPtr conf, + const char *setting, + virConfValuePtr value) { virConfEntryPtr cur, prev = NULL; @@ -861,7 +861,7 @@ /** - * __virConfWriteFile: + * virConfWriteFile: * @filename: the path to the configuration file. * @conf: the conf * @@ -870,7 +870,7 @@ * Returns the number of bytes written or -1 in case of error. */ int -__virConfWriteFile(const char *filename, virConfPtr conf) +virConfWriteFile(const char *filename, virConfPtr conf) { virBuffer buf = VIR_BUFFER_INITIALIZER; virConfEntryPtr cur; @@ -915,7 +915,7 @@ } /** - * __virConfWriteMem: + * virConfWriteMem: * @memory: pointer to the memory to store the config file * @len: pointer to the length in bytes of the store, on output the size * @conf: the conf @@ -928,7 +928,7 @@ * Returns the number of bytes written or -1 in case of error. */ int -__virConfWriteMem(char *memory, int *len, virConfPtr conf) +virConfWriteMem(char *memory, int *len, virConfPtr conf) { virBuffer buf = VIR_BUFFER_INITIALIZER; virConfEntryPtr cur; diff -r bbf3d0bc9d49 src/conf.h --- a/src/conf.h Tue Nov 11 17:28:27 2008 +0000 +++ b/src/conf.h Tue Nov 11 17:28:31 2008 +0000 @@ -61,32 +61,22 @@ typedef struct _virConf virConf; typedef virConf *virConfPtr; -virConfPtr __virConfNew (void); -virConfPtr __virConfReadFile (const char *filename); -virConfPtr __virConfReadMem (const char *memory, +virConfPtr virConfNew (void); +virConfPtr virConfReadFile (const char *filename); +virConfPtr virConfReadMem (const char *memory, int len); -int __virConfFree (virConfPtr conf); -void __virConfFreeValue (virConfValuePtr val); +int virConfFree (virConfPtr conf); +void virConfFreeValue (virConfValuePtr val); -virConfValuePtr __virConfGetValue (virConfPtr conf, +virConfValuePtr virConfGetValue (virConfPtr conf, const char *setting); -int __virConfSetValue (virConfPtr conf, +int virConfSetValue (virConfPtr conf, const char *setting, virConfValuePtr value); -int __virConfWriteFile (const char *filename, +int virConfWriteFile (const char *filename, virConfPtr conf); -int __virConfWriteMem (char *memory, +int virConfWriteMem (char *memory, int *len, virConfPtr conf); -#define virConfNew() __virConfNew() -#define virConfReadFile(f) __virConfReadFile((f)) -#define virConfReadMem(m,l) __virConfReadMem((m),(l)) -#define virConfFree(c) __virConfFree((c)) -#define virConfFreeValue(v) __virConfFreeValue((v)) -#define virConfGetValue(c,s) __virConfGetValue((c),(s)) -#define virConfSetValue(c,s,v) __virConfSetValue((c),(s),(v)) -#define virConfWriteFile(f,c) __virConfWriteFile((f),(c)) -#define virConfWriteMem(m,l,c) __virConfWriteMem((m),(l),(c)) - #endif /* __VIR_CONF_H__ */ diff -r bbf3d0bc9d49 src/console.c --- a/src/console.c Tue Nov 11 17:28:27 2008 +0000 +++ b/src/console.c Tue Nov 11 17:28:31 2008 +0000 @@ -37,7 +37,7 @@ #include "console.h" #include "internal.h" -#include "util-lib.h" +#include "util.h" /* ie Ctrl-] as per telnet */ #define CTRL_CLOSE_BRACKET '\35' diff -r bbf3d0bc9d49 src/datatypes.c --- a/src/datatypes.c Tue Nov 11 17:28:27 2008 +0000 +++ b/src/datatypes.c Tue Nov 11 17:28:31 2008 +0000 @@ -239,7 +239,7 @@ * Returns a pointer to the domain, or NULL in case of failure */ virDomainPtr -__virGetDomain(virConnectPtr conn, const char *name, const unsigned char *uuid) { +virGetDomain(virConnectPtr conn, const char *name, const unsigned char *uuid) { virDomainPtr ret = NULL; if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (uuid == NULL)) { @@ -379,7 +379,7 @@ * Returns a pointer to the network, or NULL in case of failure */ virNetworkPtr -__virGetNetwork(virConnectPtr conn, const char *name, const unsigned char *uuid) { +virGetNetwork(virConnectPtr conn, const char *name, const unsigned char *uuid) { virNetworkPtr ret = NULL; if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (uuid == NULL)) { @@ -516,7 +516,7 @@ * Returns a pointer to the network, or NULL in case of failure */ virStoragePoolPtr -__virGetStoragePool(virConnectPtr conn, const char *name, const unsigned char *uuid) { +virGetStoragePool(virConnectPtr conn, const char *name, const unsigned char *uuid) { virStoragePoolPtr ret = NULL; if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (uuid == NULL)) { @@ -650,7 +650,7 @@ * Returns a pointer to the storage vol, or NULL in case of failure */ virStorageVolPtr -__virGetStorageVol(virConnectPtr conn, const char *pool, const char *name, const char *key) { +virGetStorageVol(virConnectPtr conn, const char *pool, const char *name, const char *key) { virStorageVolPtr ret = NULL; if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (key == NULL)) { diff -r bbf3d0bc9d49 src/datatypes.h --- a/src/datatypes.h Tue Nov 11 17:28:27 2008 +0000 +++ b/src/datatypes.h Tue Nov 11 17:28:31 2008 +0000 @@ -184,29 +184,23 @@ virConnectPtr virGetConnect(void); int virUnrefConnect(virConnectPtr conn); -virDomainPtr __virGetDomain(virConnectPtr conn, +virDomainPtr virGetDomain(virConnectPtr conn, const char *name, const unsigned char *uuid); int virUnrefDomain(virDomainPtr domain); -virNetworkPtr __virGetNetwork(virConnectPtr conn, +virNetworkPtr virGetNetwork(virConnectPtr conn, const char *name, const unsigned char *uuid); int virUnrefNetwork(virNetworkPtr network); -virStoragePoolPtr __virGetStoragePool(virConnectPtr conn, +virStoragePoolPtr virGetStoragePool(virConnectPtr conn, const char *name, const unsigned char *uuid); int virUnrefStoragePool(virStoragePoolPtr pool); -virStorageVolPtr __virGetStorageVol(virConnectPtr conn, +virStorageVolPtr virGetStorageVol(virConnectPtr conn, const char *pool, const char *name, const char *key); int virUnrefStorageVol(virStorageVolPtr vol); -#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,p,n,u) __virGetStorageVol((c),(p),(n),(u)) - - #endif diff -r bbf3d0bc9d49 src/driver.h --- a/src/driver.h Tue Nov 11 17:28:27 2008 +0000 +++ b/src/driver.h Tue Nov 11 17:28:31 2008 +0000 @@ -73,7 +73,7 @@ typedef int (*virDrvClose) (virConnectPtr conn); typedef int - (*virDrvSupportsFeature) (virConnectPtr conn, int feature); + (*virDrvDrvSupportsFeature) (virConnectPtr conn, int feature); typedef const char * (*virDrvGetType) (virConnectPtr conn); typedef int @@ -305,7 +305,7 @@ virDrvProbe probe; virDrvOpen open; virDrvClose close; - virDrvSupportsFeature supports_feature; + virDrvDrvSupportsFeature supports_feature; virDrvGetType type; virDrvGetVersion version; virDrvGetHostname getHostname; diff -r bbf3d0bc9d49 src/libvirt.c --- a/src/libvirt.c Tue Nov 11 17:28:27 2008 +0000 +++ b/src/libvirt.c Tue Nov 11 17:28:31 2008 +0000 @@ -579,7 +579,7 @@ return virStateDriverTabCount++; } -int __virStateInitialize(void) { +int virStateInitialize(void) { int i, ret = 0; if (virInitialize() < 0) @@ -593,7 +593,7 @@ return ret; } -int __virStateCleanup(void) { +int virStateCleanup(void) { int i, ret = 0; for (i = 0 ; i < virStateDriverTabCount ; i++) { @@ -604,7 +604,7 @@ return ret; } -int __virStateReload(void) { +int virStateReload(void) { int i, ret = 0; for (i = 0 ; i < virStateDriverTabCount ; i++) { @@ -615,7 +615,7 @@ return ret; } -int __virStateActive(void) { +int virStateActive(void) { int i, ret = 0; for (i = 0 ; i < virStateDriverTabCount ; i++) { @@ -967,7 +967,7 @@ * implementation of driver features in the remote case. */ int -__virDrvSupportsFeature (virConnectPtr conn, int feature) +virDrvSupportsFeature (virConnectPtr conn, int feature) { DEBUG("conn=%p, feature=%d", conn, feature); @@ -2255,7 +2255,7 @@ * implementation of migration in the remote case. */ int -__virDomainMigratePrepare (virConnectPtr dconn, +virDomainMigratePrepare (virConnectPtr dconn, char **cookie, int *cookielen, const char *uri_in, @@ -2284,7 +2284,7 @@ * implementation of migration in the remote case. */ int -__virDomainMigratePerform (virDomainPtr domain, +virDomainMigratePerform (virDomainPtr domain, const char *cookie, int cookielen, const char *uri, @@ -2314,7 +2314,7 @@ * implementation of migration in the remote case. */ virDomainPtr -__virDomainMigrateFinish (virConnectPtr dconn, +virDomainMigrateFinish (virConnectPtr dconn, const char *dname, const char *cookie, int cookielen, diff -r bbf3d0bc9d49 src/libvirt_internal.h --- a/src/libvirt_internal.h Tue Nov 11 17:28:27 2008 +0000 +++ b/src/libvirt_internal.h Tue Nov 11 17:28:31 2008 +0000 @@ -26,39 +26,35 @@ #ifdef WITH_LIBVIRTD -int __virStateInitialize(void); -int __virStateCleanup(void); -int __virStateReload(void); -int __virStateActive(void); -#define virStateInitialize() __virStateInitialize() -#define virStateCleanup() __virStateCleanup() -#define virStateReload() __virStateReload() -#define virStateActive() __virStateActive() +int virStateInitialize(void); +int virStateCleanup(void); +int virStateReload(void); +int virStateActive(void); #endif -int __virDrvSupportsFeature (virConnectPtr conn, int feature); +int virDrvSupportsFeature (virConnectPtr conn, int feature); -int __virDomainMigratePrepare (virConnectPtr dconn, - char **cookie, - int *cookielen, - const char *uri_in, - char **uri_out, - unsigned long flags, - const char *dname, - unsigned long bandwidth); -int __virDomainMigratePerform (virDomainPtr domain, - const char *cookie, - int cookielen, - const char *uri, - unsigned long flags, - const char *dname, - unsigned long bandwidth); -virDomainPtr __virDomainMigrateFinish (virConnectPtr dconn, - const char *dname, - const char *cookie, - int cookielen, - const char *uri, - unsigned long flags); +int virDomainMigratePrepare (virConnectPtr dconn, + char **cookie, + int *cookielen, + const char *uri_in, + char **uri_out, + unsigned long flags, + const char *dname, + unsigned long bandwidth); +int virDomainMigratePerform (virDomainPtr domain, + const char *cookie, + int cookielen, + const char *uri, + unsigned long flags, + const char *dname, + unsigned long bandwidth); +virDomainPtr virDomainMigrateFinish (virConnectPtr dconn, + const char *dname, + const char *cookie, + int cookielen, + const char *uri, + unsigned long flags); #endif diff -r bbf3d0bc9d49 src/libvirt_sym.version --- a/src/libvirt_sym.version Tue Nov 11 17:28:27 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,203 +0,0 @@ -{ - global: - virInitialize; - virConnectOpen; - virConnectOpenReadOnly; - virConnectOpenAuth; - virConnectAuthPtrDefault; - - virConnectClose; - virConnectGetType; - virConnectGetVersion; - virConnectGetHostname; - virConnectGetURI; - virDomainGetConnect; - virConnectListDomains; - virConnectNumOfDomains; - virDomainCreate; - virDomainCreateLinux; - virDomainCreateXML; - virDomainDefineXML; - virDomainDestroy; - virDomainFree; - virDomainGetID; - virDomainGetUUID; - virDomainGetUUIDString; - virDomainGetInfo; - virNodeGetCellsFreeMemory; - virDomainGetMaxMemory; - virDomainGetName; - virDomainGetOSType; - virDomainGetXMLDesc; - virDomainLookupByID; - virDomainLookupByName; - virDomainLookupByUUID; - virDomainLookupByUUIDString; - virDomainRestore; - virDomainResume; - virDomainSave; - virDomainCoreDump; - virDomainSetMemory; - virDomainSetMaxMemory; - virDomainShutdown; - virDomainReboot; - virDomainSuspend; - virConnectListDefinedDomains; - virConnectNumOfDefinedDomains; - virConnectGetMaxVcpus; - virDomainUndefine; - virDomainGetAutostart; - virDomainSetAutostart; - virGetVersion; - virCopyLastError; - virConnSetErrorFunc; - virResetLastError; - virErrorFunc; - virResetError; - virConnGetLastError; - virGetLastError; - virSetErrorFunc; - virConnCopyLastError; - virConnResetLastError; - virDefaultErrorFunc; - virNodeGetInfo; - virConnectGetCapabilities; - virNodeGetCellsFreeMemory; - virNodeGetFreeMemory; - - virDomainSetVcpus; - virDomainPinVcpu; - virDomainGetVcpus; - virDomainGetMaxVcpus; - virDomainGetSchedulerType; - virDomainGetSchedulerParameters; - virDomainSetSchedulerParameters; - virDomainBlockStats; - virDomainInterfaceStats; - virDomainBlockPeek; - virDomainMemoryPeek; - virDomainAttachDevice; - virDomainDetachDevice; - - virDomainMigrate; - - virNetworkGetConnect; - virConnectNumOfNetworks; - virConnectListNetworks; - virConnectNumOfDefinedNetworks; - virConnectListDefinedNetworks; - virNetworkLookupByName; - virNetworkLookupByUUID; - virNetworkLookupByUUIDString; - virNetworkCreateXML; - virNetworkDefineXML; - virNetworkUndefine; - virNetworkCreate; - virNetworkDestroy; - virNetworkFree; - virNetworkGetName; - virNetworkGetUUID; - virNetworkGetUUIDString; - virNetworkGetXMLDesc; - virNetworkGetBridgeName; - virNetworkGetAutostart; - virNetworkSetAutostart; - - virStoragePoolGetConnect; - virConnectNumOfStoragePools; - virConnectNumOfDefinedStoragePools; - virConnectListStoragePools; - virConnectListDefinedStoragePools; - virConnectFindStoragePoolSources; - virStoragePoolLookupByName; - virStoragePoolLookupByUUID; - virStoragePoolLookupByUUIDString; - virStoragePoolLookupByVolume; - virStoragePoolCreateXML; - virStoragePoolDefineXML; - virStoragePoolUndefine; - virStoragePoolCreate; - virStoragePoolBuild; - virStoragePoolDestroy; - virStoragePoolDelete; - virStoragePoolRefresh; - virStoragePoolFree; - virStoragePoolGetName; - virStoragePoolGetUUID; - virStoragePoolGetUUIDString; - virStoragePoolGetInfo; - virStoragePoolGetXMLDesc; - virStoragePoolSetAutostart; - virStoragePoolGetAutostart; - virStoragePoolNumOfVolumes; - virStoragePoolListVolumes; - - virConnectNumOfStorageVolumes; - virConnectListStorageVolumes; - virStorageVolGetConnect; - virStorageVolLookupByName; - virStorageVolLookupByKey; - virStorageVolLookupByPath; - virStorageVolCreateXML; - virStorageVolDelete; - virStorageVolFree; - virStorageVolGetName; - virStorageVolGetKey; - virStorageVolGetInfo; - virStorageVolGetXMLDesc; - virStorageVolGetPath; - - virEventRegisterImpl; - virConnectDomainEventRegister; - virConnectDomainEventDeregister; - - /* Symbols with __ are private only - for use by the libvirtd daemon. - They are not part of stable ABI - guarentee provided for the public - symbols above */ - - __virConfNew; - __virConfReadFile; - __virConfReadMem; - __virConfFree; - __virConfGetValue; - __virConfSetValue; - __virConfWriteFile; - __virConfWriteMem; - - __virGetDomain; - __virGetNetwork; - __virGetStoragePool; - __virGetStorageVol; - - __virStateInitialize; - __virStateCleanup; - __virStateReload; - __virStateActive; - __virStateSigDispatcher; - - __virDrvSupportsFeature; - - __virDomainMigratePrepare; - __virDomainMigratePerform; - __virDomainMigrateFinish; - - __virFileReadAll; - __virStrToLong_i; - __virStrToLong_ull; - - __virBufferVSprintf; - __virBufferAdd; - __virBufferAddChar; - __virBufferContentAndReset; - __virBufferError; - - __virMacAddrCompare; - - __virAlloc; - __virAllocN; - __virReallocN; - __virFree; - local: *; -}; diff -r bbf3d0bc9d49 src/libvirt_sym.version.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libvirt_sym.version.in Tue Nov 11 17:28:31 2008 +0000 @@ -0,0 +1,318 @@ +/* + * WARNING: libvirt_sym.version.in is the master file + * + * WARNING: libvirt_sym.version is auto-generated by configure + */ + +/* + * First officially exported symbols, for which header + * file definitions are installed in /usr/include/libvirt + * either from libvirt.h and virterror.h + * + * Versions here are *fixed* to match the libvirt version + * at which the symbol was introduced. This ensures that + * a new client app requiring symbol foo() can't accidentally + * run with old libvirt.so not providing foo() - the global + * soname version info can't enforce this since we never + * change the soname + */ +LIBVIRT_0.0.3 { + global: + virConnectClose; + virConnectGetType; + virConnectGetVersion; + virConnectListDomains; + virConnectNumOfDomains; + virConnectOpen; + virConnectOpenReadOnly; + + virDomainCreateLinux; + virDomainDestroy; + virDomainFree; + virDomainGetID; + virDomainGetInfo; + virDomainGetMaxMemory; + virDomainGetName; + virDomainGetOSType; + virDomainGetXMLDesc; + virDomainLookupByID; + virDomainLookupByName; + virDomainRestore; + virDomainResume; + virDomainSave; + virDomainSetMaxMemory; + virDomainShutdown; + virDomainSuspend; + + virGetVersion; +}; + +LIBVIRT_0.0.5 { + global: + virDomainLookupByUUID; + virDomainGetUUID; +} LIBVIRT_0.0.3; + +LIBVIRT_0.1.0 { + global: + virInitialize; + virNodeGetInfo; + virDomainReboot; + + virCopyLastError; + virConnSetErrorFunc; + virResetLastError; + virErrorFunc; + virResetError; + virConnGetLastError; + virGetLastError; + virSetErrorFunc; + virConnCopyLastError; + virConnResetLastError; + virDefaultErrorFunc; +} LIBVIRT_0.0.5; + +LIBVIRT_0.1.1 { + global: + virDomainLookupByUUIDString; + virDomainGetUUIDString; + virDomainSetMemory; + virDomainDefineXML; + virDomainCreate; + virDomainUndefine; + virConnectListDefinedDomains; +} LIBVIRT_0.1.0; + +LIBVIRT_0.1.4 { + global: + virDomainSetVcpus; + virDomainPinVcpu; + virDomainGetVcpus; +} LIBVIRT_0.1.1; + +LIBVIRT_0.1.5 { + global: + virConnectNumOfDefinedDomains; +} LIBVIRT_0.1.4; + +LIBVIRT_0.1.9 { + global: + virDomainCoreDump; + virDomainAttachDevice; + virDomainDetachDevice; +} LIBVIRT_0.1.5; + +LIBVIRT_0.2.0 { + global: + virConnectNumOfNetworks; + virConnectListNetworks; + virConnectNumOfDefinedNetworks; + virConnectListDefinedNetworks; + virNetworkLookupByName; + virNetworkLookupByUUID; + virNetworkLookupByUUIDString; + virNetworkCreateXML; + virNetworkDefineXML; + virNetworkUndefine; + virNetworkCreate; + virNetworkDestroy; + virNetworkFree; + virNetworkGetName; + virNetworkGetUUID; + virNetworkGetUUIDString; + virNetworkGetXMLDesc; + virNetworkGetBridgeName; +} LIBVIRT_0.1.9; + +LIBVIRT_0.2.1 { + global: + virConnectGetCapabilities; + virConnectGetMaxVcpus; + virDomainGetMaxVcpus; + virDomainGetAutostart; + virDomainSetAutostart; + virNetworkGetAutostart; + virNetworkSetAutostart; +} LIBVIRT_0.2.0; + +LIBVIRT_0.2.3 { + global: + virDomainGetSchedulerType; + virDomainGetSchedulerParameters; + virDomainSetSchedulerParameters; +} LIBVIRT_0.2.1; + +LIBVIRT_0.3.0 { + global: + virConnectGetHostname; + virConnectGetURI; + virDomainGetConnect; + virNetworkGetConnect; +} LIBVIRT_0.2.3; + +LIBVIRT_0.3.2 { + global: + virDomainMigrate; + virDomainBlockStats; + virDomainInterfaceStats; +} LIBVIRT_0.3.0; + +LIBVIRT_0.3.3 { + global: + virNodeGetCellsFreeMemory; + virNodeGetFreeMemory; +} LIBVIRT_0.3.2; + +LIBVIRT_0.4.0 { + global: + virConnectOpenAuth; + virConnectAuthPtrDefault; +} LIBVIRT_0.3.3; + +LIBVIRT_0.4.1 { + global: + virStoragePoolGetConnect; + virConnectNumOfStoragePools; + virConnectNumOfDefinedStoragePools; + virConnectListStoragePools; + virConnectListDefinedStoragePools; + virStoragePoolLookupByName; + virStoragePoolLookupByUUID; + virStoragePoolLookupByUUIDString; + virStoragePoolLookupByVolume; + virStoragePoolCreateXML; + virStoragePoolDefineXML; + virStoragePoolUndefine; + virStoragePoolCreate; + virStoragePoolBuild; + virStoragePoolDestroy; + virStoragePoolDelete; + virStoragePoolRefresh; + virStoragePoolFree; + virStoragePoolGetName; + virStoragePoolGetUUID; + virStoragePoolGetUUIDString; + virStoragePoolGetInfo; + virStoragePoolGetXMLDesc; + virStoragePoolSetAutostart; + virStoragePoolGetAutostart; + virStoragePoolNumOfVolumes; + virStoragePoolListVolumes; + + virConnectNumOfStorageVolumes; + virConnectListStorageVolumes; + virStorageVolGetConnect; + virStorageVolLookupByName; + virStorageVolLookupByKey; + virStorageVolLookupByPath; + virStorageVolCreateXML; + virStorageVolDelete; + virStorageVolFree; + virStorageVolGetName; + virStorageVolGetKey; + virStorageVolGetInfo; + virStorageVolGetXMLDesc; + virStorageVolGetPath; +} LIBVIRT_0.4.0; + +LIBVIRT_0.4.2 { + global: + virDomainBlockPeek; + virDomainMemoryPeek; +} LIBVIRT_0.4.1; + +LIBVIRT_0.4.5 { + global: + virConnectFindStoragePoolSources; +} LIBVIRT_0.4.2; + +LIBVIRT_0.5.0 { + global: + virDomainCreateXML; + virEventRegisterImpl; + virConnectDomainEventRegister; + virConnectDomainEventDeregister; +} LIBVIRT_0.4.5; + +/* .... define new API here using predicted next version number .... */ + + + + +/* + * Finally these symbols are private and semantics may change + * on every release, hence the version number is spliced in at + * build time. This ensures that if libvirtd, virsh, or a driver + * module was built against one libvirt release, it will refuse + * to load with another where symbols may have same names but + * different semantics. + * + * No header files are provided outside the source tree. + * + * Keep this section ordered alphabetically by header file name + * + * Symbols here are only for use by virsh, libvirtd and dlopen + * driver modules + */ +LIBVIRT_PRIVATE_@VERSION@ { + + global: + + /* buf.h */ + virBufferVSprintf; + virBufferAdd; + virBufferAddChar; + virBufferContentAndReset; + virBufferError; + + + /* conf.h */ + virConfNew; + virConfReadFile; + virConfReadMem; + virConfFree; + virConfGetValue; + virConfSetValue; + virConfWriteFile; + virConfWriteMem; + + + /* datatypes.h */ + virGetDomain; + virGetNetwork; + virGetStoragePool; + virGetStorageVol; + + + /* libvirt_internal.h */ + virStateInitialize; + virStateCleanup; + virStateReload; + virStateActive; + virStateSigDispatcher; + virDrvSupportsFeature; + virDomainMigratePrepare; + virDomainMigratePerform; + virDomainMigrateFinish; + + + /* memory.h */ + virAlloc; + virAllocN; + virReallocN; + virFree; + + + /* util.h */ + virFileReadAll; + virStrToLong_i; + virStrToLong_ull; + saferead; + safewrite; + virMacAddrCompare; + + + /* Finally everything else is totally private */ + local: + *; +}; diff -r bbf3d0bc9d49 src/memory.c --- a/src/memory.c Tue Nov 11 17:28:27 2008 +0000 +++ b/src/memory.c Tue Nov 11 17:28:31 2008 +0000 @@ -88,7 +88,7 @@ * * Returns -1 on failure to allocate, zero on success */ -int __virAlloc(void *ptrptr, size_t size) +int virAlloc(void *ptrptr, size_t size) { #if TEST_OOM if (virAllocTestFail()) { @@ -116,7 +116,7 @@ * * Returns -1 on failure to allocate, zero on success */ -int __virAllocN(void *ptrptr, size_t size, size_t count) +int virAllocN(void *ptrptr, size_t size, size_t count) { #if TEST_OOM if (virAllocTestFail()) { @@ -145,7 +145,7 @@ * * Returns -1 on failure to allocate, zero on success */ -int __virReallocN(void *ptrptr, size_t size, size_t count) +int virReallocN(void *ptrptr, size_t size, size_t count) { void *tmp; #if TEST_OOM @@ -172,7 +172,7 @@ * the 'ptrptr' variable. After release, 'ptrptr' will be * updated to point to NULL. */ -void __virFree(void *ptrptr) +void virFree(void *ptrptr) { free(*(void**)ptrptr); *(void**)ptrptr = NULL; diff -r bbf3d0bc9d49 src/memory.h --- a/src/memory.h Tue Nov 11 17:28:27 2008 +0000 +++ b/src/memory.h Tue Nov 11 17:28:31 2008 +0000 @@ -45,10 +45,10 @@ /* Don't call these directly - use the macros below */ -int __virAlloc(void *ptrptr, size_t size) ATTRIBUTE_RETURN_CHECK; -int __virAllocN(void *ptrptr, size_t size, size_t count) ATTRIBUTE_RETURN_CHECK; -int __virReallocN(void *ptrptr, size_t size, size_t count) ATTRIBUTE_RETURN_CHECK; -void __virFree(void *ptrptr); +int virAlloc(void *ptrptr, size_t size) ATTRIBUTE_RETURN_CHECK; +int virAllocN(void *ptrptr, size_t size, size_t count) ATTRIBUTE_RETURN_CHECK; +int virReallocN(void *ptrptr, size_t size, size_t count) ATTRIBUTE_RETURN_CHECK; +void virFree(void *ptrptr); /** * VIR_ALLOC: @@ -60,7 +60,7 @@ * * Returns -1 on failure, 0 on success */ -#define VIR_ALLOC(ptr) __virAlloc(&(ptr), sizeof(*(ptr))) +#define VIR_ALLOC(ptr) virAlloc(&(ptr), sizeof(*(ptr))) /** * VIR_ALLOC_N: @@ -73,7 +73,7 @@ * * Returns -1 on failure, 0 on success */ -#define VIR_ALLOC_N(ptr, count) __virAllocN(&(ptr), sizeof(*(ptr)), (count)) +#define VIR_ALLOC_N(ptr, count) virAllocN(&(ptr), sizeof(*(ptr)), (count)) /** * VIR_REALLOC_N: @@ -86,7 +86,7 @@ * * Returns -1 on failure, 0 on success */ -#define VIR_REALLOC_N(ptr, count) __virReallocN(&(ptr), sizeof(*(ptr)), (count)) +#define VIR_REALLOC_N(ptr, count) virReallocN(&(ptr), sizeof(*(ptr)), (count)) /** * VIR_FREE: @@ -95,7 +95,7 @@ * Free the memory stored in 'ptr' and update to point * to NULL. */ -#define VIR_FREE(ptr) __virFree(&(ptr)) +#define VIR_FREE(ptr) virFree(&(ptr)) #if TEST_OOM diff -r bbf3d0bc9d49 src/util-lib.c --- a/src/util-lib.c Tue Nov 11 17:28:27 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * common, generic utility functions - * - * Copyright (C) 2006, 2007, 2008 Red Hat, Inc. - * See COPYING.LIB for the License of this software - */ - -#include <config.h> - -#include <unistd.h> -#include <errno.h> - -#include "util-lib.h" - -/* Like read(), but restarts after EINTR */ -int saferead(int fd, void *buf, size_t count) -{ - size_t nread = 0; - while (count > 0) { - ssize_t r = read(fd, buf, count); - if (r < 0 && errno == EINTR) - continue; - if (r < 0) - return r; - if (r == 0) - return nread; - buf = (char *)buf + r; - count -= r; - nread += r; - } - return nread; -} - -/* Like write(), but restarts after EINTR */ -ssize_t safewrite(int fd, const void *buf, size_t count) -{ - size_t nwritten = 0; - while (count > 0) { - ssize_t r = write(fd, buf, count); - - if (r < 0 && errno == EINTR) - continue; - if (r < 0) - return r; - if (r == 0) - return nwritten; - buf = (const char *)buf + r; - count -= r; - nwritten += r; - } - return nwritten; -} diff -r bbf3d0bc9d49 src/util-lib.h --- a/src/util-lib.h Tue Nov 11 17:28:27 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -/* - * private utility functions - * - * Copyright (C) 2008 Red Hat, Inc. - * See COPYING.LIB for the License of this software - */ - -#ifndef __UTIL_LIB_H__ -#define __UTIL_LIB_H__ - -#include <sys/types.h> - -/* - * To avoid a double definition of the function when compiling - * programs using both util-lib and libvirt, like virsh - */ -#ifdef IN_LIBVIRT -#define saferead libvirt_saferead -#define safewrite libvirt_safewrite -#endif - -int saferead(int fd, void *buf, size_t count); -ssize_t safewrite(int fd, const void *buf, size_t count); - -#endif diff -r bbf3d0bc9d49 src/util.c --- a/src/util.c Tue Nov 11 17:28:27 2008 +0000 +++ b/src/util.c Tue Nov 11 17:28:31 2008 +0000 @@ -54,7 +54,6 @@ #include "buf.h" #include "util.h" #include "memory.h" -#include "util-lib.c" #ifndef NSIG # define NSIG 32 @@ -66,11 +65,51 @@ #define virLog(msg...) fprintf(stderr, msg) -#ifndef PROXY #define ReportError(conn, code, fmt...) \ virReportErrorHelper(conn, VIR_FROM_NONE, code, __FILE__, \ __FUNCTION__, __LINE__, fmt) + +/* Like read(), but restarts after EINTR */ +int saferead(int fd, void *buf, size_t count) +{ + size_t nread = 0; + while (count > 0) { + ssize_t r = read(fd, buf, count); + if (r < 0 && errno == EINTR) + continue; + if (r < 0) + return r; + if (r == 0) + return nread; + buf = (char *)buf + r; + count -= r; + nread += r; + } + return nread; +} + +/* Like write(), but restarts after EINTR */ +ssize_t safewrite(int fd, const void *buf, size_t count) +{ + size_t nwritten = 0; + while (count > 0) { + ssize_t r = write(fd, buf, count); + + if (r < 0 && errno == EINTR) + continue; + if (r < 0) + return r; + if (r == 0) + return nwritten; + buf = (const char *)buf + r; + count -= r; + nwritten += r; + } + return nwritten; +} + +#ifndef PROXY int virFileStripSuffix(char *str, const char *suffix) @@ -675,7 +714,7 @@ } /* Like virFileReadLimFP, but use a file descriptor rather than a FILE*. */ -int __virFileReadLimFD(int fd_arg, int maxlen, char **buf) +int virFileReadLimFD(int fd_arg, int maxlen, char **buf) { int fd = dup (fd_arg); if (fd >= 0) { @@ -695,7 +734,7 @@ return -1; } -int __virFileReadAll(const char *path, int maxlen, char **buf) +int virFileReadAll(const char *path, int maxlen, char **buf) { FILE *fh = fopen(path, "r"); if (fh == NULL) { @@ -985,7 +1024,7 @@ validity. This function is careful to return -1 when the string S represents a number that is not representable as an "int". */ int -__virStrToLong_i(char const *s, char **end_ptr, int base, int *result) +virStrToLong_i(char const *s, char **end_ptr, int base, int *result) { long int val; char *p; @@ -1042,7 +1081,7 @@ /* Just like virStrToLong_i, above, but produce an "unsigned long long" value. */ int -__virStrToLong_ull(char const *s, char **end_ptr, int base, unsigned long long *result) +virStrToLong_ull(char const *s, char **end_ptr, int base, unsigned long long *result) { unsigned long long val; char *p; @@ -1114,7 +1153,7 @@ * as well as leading zeros. */ int -__virMacAddrCompare (const char *p, const char *q) +virMacAddrCompare (const char *p, const char *q) { unsigned char c, d; do { diff -r bbf3d0bc9d49 src/util.h --- a/src/util.h Tue Nov 11 17:28:27 2008 +0000 +++ b/src/util.h Tue Nov 11 17:28:31 2008 +0000 @@ -25,9 +25,11 @@ #ifndef __VIR_UTIL_H__ #define __VIR_UTIL_H__ -#include "util-lib.h" #include "verify.h" #include <sys/select.h> + +int saferead(int fd, void *buf, size_t count); +ssize_t safewrite(int fd, const void *buf, size_t count); enum { VIR_EXEC_NONE = 0, @@ -46,11 +48,9 @@ int flags); int virRun(virConnectPtr conn, const char *const*argv, int *status); -int __virFileReadLimFD(int fd, int maxlen, char **buf); -#define virFileReadLimFD(fd,m,b) __virFileReadLimFD((fd),(m),(b)) +int virFileReadLimFD(int fd, int maxlen, char **buf); -int __virFileReadAll(const char *path, int maxlen, char **buf); -#define virFileReadAll(p,m,b) __virFileReadAll((p),(m),(b)) +int virFileReadAll(const char *path, int maxlen, char **buf); int virFileMatchesNameSuffix(const char *file, const char *name, @@ -90,11 +90,10 @@ char *virArgvToString(const char *const *argv); -int __virStrToLong_i(char const *s, +int virStrToLong_i(char const *s, char **end_ptr, int base, int *result); -#define virStrToLong_i(s,e,b,r) __virStrToLong_i((s),(e),(b),(r)) int virStrToLong_ui(char const *s, char **end_ptr, @@ -104,14 +103,12 @@ char **end_ptr, int base, long long *result); -int __virStrToLong_ull(char const *s, - char **end_ptr, - int base, - unsigned long long *result); -#define virStrToLong_ull(s,e,b,r) __virStrToLong_ull((s),(e),(b),(r)) +int virStrToLong_ull(char const *s, + char **end_ptr, + int base, + unsigned long long *result); -int __virMacAddrCompare (const char *mac1, const char *mac2); -#define virMacAddrCompare(mac1,mac2) __virMacAddrCompare((mac1),(mac2)) +int virMacAddrCompare (const char *mac1, const char *mac2); void virSkipSpaces(const char **str); int virParseNumber(const char **str); diff -r bbf3d0bc9d49 src/virsh.c --- a/src/virsh.c Tue Nov 11 17:28:27 2008 +0000 +++ b/src/virsh.c Tue Nov 11 17:28:31 2008 +0000 @@ -47,7 +47,6 @@ #include "buf.h" #include "console.h" #include "util.h" -#include "util-lib.h" static char *progname; -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Thu, Nov 13, 2008 at 05:21:23PM +0000, Daniel P. Berrange wrote:
This patch changes the way we use linker scripts to have fully versioned symbols, and a versioned private section for symbols needed by libvirtd and virsh.
Just a couple of questions:
+++ b/src/driver.h Tue Nov 11 17:28:31 2008 +0000 @@ -73,7 +73,7 @@ typedef int (*virDrvClose) (virConnectPtr conn); typedef int - (*virDrvSupportsFeature) (virConnectPtr conn, int feature); + (*virDrvDrvSupportsFeature) (virConnectPtr conn, int feature);
I miss the point ... err why ? ...]
diff -r bbf3d0bc9d49 src/libvirt_sym.version.in [...] +LIBVIRT_0.5.0 { + global: + virDomainCreateXML; + virEventRegisterImpl; + virConnectDomainEventRegister; + virConnectDomainEventDeregister; +} LIBVIRT_0.4.5; + +/* .... define new API here using predicted next version number .... */
So basically as part of doing a release I should guess the new version number and make a template empty section here, commited after tagging the release. Looks fine to me, and we need this, +1 Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Thu, Nov 13, 2008 at 06:31:04PM +0100, Daniel Veillard wrote:
On Thu, Nov 13, 2008 at 05:21:23PM +0000, Daniel P. Berrange wrote:
This patch changes the way we use linker scripts to have fully versioned symbols, and a versioned private section for symbols needed by libvirtd and virsh.
Just a couple of questions:
+++ b/src/driver.h Tue Nov 11 17:28:31 2008 +0000 @@ -73,7 +73,7 @@ typedef int (*virDrvClose) (virConnectPtr conn); typedef int - (*virDrvSupportsFeature) (virConnectPtr conn, int feature); + (*virDrvDrvSupportsFeature) (virConnectPtr conn, int feature);
I miss the point ... err why ?
When I removed the __ from the 'private' symbols exported, this internal driver typedef now clashes with the following public symbol:
- ret->supported = __virDrvSupportsFeature (client->conn, args->feature); + ret->supported = virDrvSupportsFeature (client->conn, args->feature); if (ret->supported == -1) return -1;
The DrvDrv looks a little odd, but it is actually consistent with the naming for driver.h, which is basically s/vir/virDrv/ against the public API :-)
...]
diff -r bbf3d0bc9d49 src/libvirt_sym.version.in [...] +LIBVIRT_0.5.0 { + global: + virDomainCreateXML; + virEventRegisterImpl; + virConnectDomainEventRegister; + virConnectDomainEventDeregister; +} LIBVIRT_0.4.5; + +/* .... define new API here using predicted next version number .... */
So basically as part of doing a release I should guess the new version number and make a template empty section here, commited after tagging the release.
Yeah, that'd be a reasonable thing todo - just add .1 to the existing version. If we end up adding lots of new symbols, it'll be fairly obvious that we should increment a major version number instead. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Thu, Nov 13, 2008 at 09:44:42PM +0000, Daniel P. Berrange wrote:
On Thu, Nov 13, 2008 at 06:31:04PM +0100, Daniel Veillard wrote: When I removed the __ from the 'private' symbols exported, this internal driver typedef now clashes with the following public symbol:
okay, just one more thing, as I'm commiting the QEmu/KVM migration patch the __ cleanup will be needed for __virDomainMigratePrepare2 and __virDomainMigrateFinish2 which are introduced there, I guess it makes sense to clean them as this patch is applied too, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Thu, Nov 13, 2008 at 05:21:23PM +0000, Daniel P. Berrange wrote:
This patch changes the way we use linker scripts to have fully versioned symbols, and a versioned private section for symbols needed by libvirtd and virsh.
If you look at the version script below, you'll see that I've added an explicit version section for each version in which we introduced a symbol. Some people at Red Hat have suggested to me offlist that this is overkil, and we could just have one section named 0.5.0 for all our existing symbols, and then just add new sections for each subsequent release. I kind of like the idea of representing all the releases in which we added symbols, but functionally it doesn't matter which style we pick for our existing symbols. Anyone else have an opinion ?
diff -r bbf3d0bc9d49 src/libvirt_sym.version.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libvirt_sym.version.in Tue Nov 11 17:28:31 2008 +0000 @@ -0,0 +1,318 @@ +/* + * WARNING: libvirt_sym.version.in is the master file + * + * WARNING: libvirt_sym.version is auto-generated by configure + */ + +/* + * First officially exported symbols, for which header + * file definitions are installed in /usr/include/libvirt + * either from libvirt.h and virterror.h + * + * Versions here are *fixed* to match the libvirt version + * at which the symbol was introduced. This ensures that + * a new client app requiring symbol foo() can't accidentally + * run with old libvirt.so not providing foo() - the global + * soname version info can't enforce this since we never + * change the soname + */ +LIBVIRT_0.0.3 { + global: + virConnectClose; + virConnectGetType; + virConnectGetVersion; + virConnectListDomains; + virConnectNumOfDomains; + virConnectOpen; + virConnectOpenReadOnly; + + virDomainCreateLinux; + virDomainDestroy; + virDomainFree; + virDomainGetID; + virDomainGetInfo; + virDomainGetMaxMemory; + virDomainGetName; + virDomainGetOSType; + virDomainGetXMLDesc; + virDomainLookupByID; + virDomainLookupByName; + virDomainRestore; + virDomainResume; + virDomainSave; + virDomainSetMaxMemory; + virDomainShutdown; + virDomainSuspend; + + virGetVersion; +}; + +LIBVIRT_0.0.5 { + global: + virDomainLookupByUUID; + virDomainGetUUID; +} LIBVIRT_0.0.3; + +LIBVIRT_0.1.0 { + global: + virInitialize; + virNodeGetInfo; + virDomainReboot; + + virCopyLastError; + virConnSetErrorFunc; + virResetLastError; + virErrorFunc; + virResetError; + virConnGetLastError; + virGetLastError; + virSetErrorFunc; + virConnCopyLastError; + virConnResetLastError; + virDefaultErrorFunc; +} LIBVIRT_0.0.5; + +LIBVIRT_0.1.1 { + global: + virDomainLookupByUUIDString; + virDomainGetUUIDString; + virDomainSetMemory; + virDomainDefineXML; + virDomainCreate; + virDomainUndefine; + virConnectListDefinedDomains; +} LIBVIRT_0.1.0; + +LIBVIRT_0.1.4 { + global: + virDomainSetVcpus; + virDomainPinVcpu; + virDomainGetVcpus; +} LIBVIRT_0.1.1; + +LIBVIRT_0.1.5 { + global: + virConnectNumOfDefinedDomains; +} LIBVIRT_0.1.4; + +LIBVIRT_0.1.9 { + global: + virDomainCoreDump; + virDomainAttachDevice; + virDomainDetachDevice; +} LIBVIRT_0.1.5; + +LIBVIRT_0.2.0 { + global: + virConnectNumOfNetworks; + virConnectListNetworks; + virConnectNumOfDefinedNetworks; + virConnectListDefinedNetworks; + virNetworkLookupByName; + virNetworkLookupByUUID; + virNetworkLookupByUUIDString; + virNetworkCreateXML; + virNetworkDefineXML; + virNetworkUndefine; + virNetworkCreate; + virNetworkDestroy; + virNetworkFree; + virNetworkGetName; + virNetworkGetUUID; + virNetworkGetUUIDString; + virNetworkGetXMLDesc; + virNetworkGetBridgeName; +} LIBVIRT_0.1.9; + +LIBVIRT_0.2.1 { + global: + virConnectGetCapabilities; + virConnectGetMaxVcpus; + virDomainGetMaxVcpus; + virDomainGetAutostart; + virDomainSetAutostart; + virNetworkGetAutostart; + virNetworkSetAutostart; +} LIBVIRT_0.2.0; + +LIBVIRT_0.2.3 { + global: + virDomainGetSchedulerType; + virDomainGetSchedulerParameters; + virDomainSetSchedulerParameters; +} LIBVIRT_0.2.1; + +LIBVIRT_0.3.0 { + global: + virConnectGetHostname; + virConnectGetURI; + virDomainGetConnect; + virNetworkGetConnect; +} LIBVIRT_0.2.3; + +LIBVIRT_0.3.2 { + global: + virDomainMigrate; + virDomainBlockStats; + virDomainInterfaceStats; +} LIBVIRT_0.3.0; + +LIBVIRT_0.3.3 { + global: + virNodeGetCellsFreeMemory; + virNodeGetFreeMemory; +} LIBVIRT_0.3.2; + +LIBVIRT_0.4.0 { + global: + virConnectOpenAuth; + virConnectAuthPtrDefault; +} LIBVIRT_0.3.3; + +LIBVIRT_0.4.1 { + global: + virStoragePoolGetConnect; + virConnectNumOfStoragePools; + virConnectNumOfDefinedStoragePools; + virConnectListStoragePools; + virConnectListDefinedStoragePools; + virStoragePoolLookupByName; + virStoragePoolLookupByUUID; + virStoragePoolLookupByUUIDString; + virStoragePoolLookupByVolume; + virStoragePoolCreateXML; + virStoragePoolDefineXML; + virStoragePoolUndefine; + virStoragePoolCreate; + virStoragePoolBuild; + virStoragePoolDestroy; + virStoragePoolDelete; + virStoragePoolRefresh; + virStoragePoolFree; + virStoragePoolGetName; + virStoragePoolGetUUID; + virStoragePoolGetUUIDString; + virStoragePoolGetInfo; + virStoragePoolGetXMLDesc; + virStoragePoolSetAutostart; + virStoragePoolGetAutostart; + virStoragePoolNumOfVolumes; + virStoragePoolListVolumes; + + virConnectNumOfStorageVolumes; + virConnectListStorageVolumes; + virStorageVolGetConnect; + virStorageVolLookupByName; + virStorageVolLookupByKey; + virStorageVolLookupByPath; + virStorageVolCreateXML; + virStorageVolDelete; + virStorageVolFree; + virStorageVolGetName; + virStorageVolGetKey; + virStorageVolGetInfo; + virStorageVolGetXMLDesc; + virStorageVolGetPath; +} LIBVIRT_0.4.0; + +LIBVIRT_0.4.2 { + global: + virDomainBlockPeek; + virDomainMemoryPeek; +} LIBVIRT_0.4.1; + +LIBVIRT_0.4.5 { + global: + virConnectFindStoragePoolSources; +} LIBVIRT_0.4.2; + +LIBVIRT_0.5.0 { + global: + virDomainCreateXML; + virEventRegisterImpl; + virConnectDomainEventRegister; + virConnectDomainEventDeregister; +} LIBVIRT_0.4.5; + +/* .... define new API here using predicted next version number .... */ + + + + +/* + * Finally these symbols are private and semantics may change + * on every release, hence the version number is spliced in at + * build time. This ensures that if libvirtd, virsh, or a driver + * module was built against one libvirt release, it will refuse + * to load with another where symbols may have same names but + * different semantics. + * + * No header files are provided outside the source tree. + * + * Keep this section ordered alphabetically by header file name + * + * Symbols here are only for use by virsh, libvirtd and dlopen + * driver modules + */ +LIBVIRT_PRIVATE_@VERSION@ { + + global: + + /* buf.h */ + virBufferVSprintf; + virBufferAdd; + virBufferAddChar; + virBufferContentAndReset; + virBufferError; + + + /* conf.h */ + virConfNew; + virConfReadFile; + virConfReadMem; + virConfFree; + virConfGetValue; + virConfSetValue; + virConfWriteFile; + virConfWriteMem; + + + /* datatypes.h */ + virGetDomain; + virGetNetwork; + virGetStoragePool; + virGetStorageVol; + + + /* libvirt_internal.h */ + virStateInitialize; + virStateCleanup; + virStateReload; + virStateActive; + virStateSigDispatcher; + virDrvSupportsFeature; + virDomainMigratePrepare; + virDomainMigratePerform; + virDomainMigrateFinish; + + + /* memory.h */ + virAlloc; + virAllocN; + virReallocN; + virFree; + + + /* util.h */ + virFileReadAll; + virStrToLong_i; + virStrToLong_ull; + saferead; + safewrite; + virMacAddrCompare; + + + /* Finally everything else is totally private */ + local: + *; +};
Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Fri, Nov 14, 2008 at 10:37:51AM +0000, Daniel P. Berrange wrote:
On Thu, Nov 13, 2008 at 05:21:23PM +0000, Daniel P. Berrange wrote:
This patch changes the way we use linker scripts to have fully versioned symbols, and a versioned private section for symbols needed by libvirtd and virsh.
If you look at the version script below, you'll see that I've added an explicit version section for each version in which we introduced a symbol. Some people at Red Hat have suggested to me offlist that this is overkil, and we could just have one section named 0.5.0 for all our existing symbols, and then just add new sections for each subsequent release.
I kind of like the idea of representing all the releases in which we added symbols, but functionally it doesn't matter which style we pick for our existing symbols. Anyone else have an opinion ?
keeping the log may also help maintaining http://libvirt.org/hvsupport.html so I'm in favor of the full list Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

My previous patch for refactoring the storage backends broke the test driver's storage capabilities. The problem was that it made the backends private to the storage driver, but part of them was in fact needed by the XML parsers. This patch pulls a bunch of code out of the storage_backenmd file, and individual drivers and puts it straight into storage_conf.c/h for generic use by the parser. The storage backends are not totally private to the storage driver, and the test driver's storage impl still works Daniel diff -r 19c9bab70d15 src/Makefile.am --- a/src/Makefile.am Wed Nov 12 16:38:19 2008 +0000 +++ b/src/Makefile.am Wed Nov 12 21:05:13 2008 +0000 @@ -69,8 +69,7 @@ # Storage driver generic impl APIs STORAGE_CONF_SOURCES = \ - storage_conf.h storage_conf.c \ - storage_backend.h storage_backend.c + storage_conf.h storage_conf.c # The remote RPC driver, covering domains, storage, networks, etc @@ -123,7 +122,8 @@ # And finally storage backend specific impls STORAGE_DRIVER_SOURCES = \ - storage_driver.h storage_driver.c + storage_driver.h storage_driver.c \ + storage_backend.h storage_backend.c STORAGE_DRIVER_FS_SOURCES = \ storage_backend_fs.h storage_backend_fs.c diff -r 19c9bab70d15 src/storage_backend.c --- a/src/storage_backend.c Wed Nov 12 16:38:19 2008 +0000 +++ b/src/storage_backend.c Wed Nov 12 21:05:13 2008 +0000 @@ -24,6 +24,7 @@ #include <config.h> #include <string.h> +#include <stdio.h> #if HAVE_REGEX_H #include <regex.h> #endif @@ -60,10 +61,6 @@ #include "storage_backend_fs.h" #endif -VIR_ENUM_IMPL(virStorageBackendPartTable, - VIR_STORAGE_POOL_DISK_LAST, - "unknown", "dos", "dvh", "gpt", - "mac", "bsd", "pc98", "sun", "lvm2"); static virStorageBackendPtr backends[] = { #if WITH_STORAGE_DIR @@ -95,81 +92,6 @@ virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, _("missing backend for pool type %d"), type); - return NULL; -} - -virStorageBackendPoolOptionsPtr -virStorageBackendPoolOptionsForType(int type) { - virStorageBackendPtr backend = virStorageBackendForType(type); - if (backend == NULL) - return NULL; - return &backend->poolOptions; -} - -virStorageBackendVolOptionsPtr -virStorageBackendVolOptionsForType(int type) { - virStorageBackendPtr backend = virStorageBackendForType(type); - if (backend == NULL) - return NULL; - return &backend->volOptions; -} - - -int -virStorageBackendFromString(const char *type) { - if (STREQ(type, "dir")) - return VIR_STORAGE_POOL_DIR; -#if WITH_STORAGE_FS - if (STREQ(type, "fs")) - return VIR_STORAGE_POOL_FS; - if (STREQ(type, "netfs")) - return VIR_STORAGE_POOL_NETFS; -#endif -#if WITH_STORAGE_LVM - if (STREQ(type, "logical")) - return VIR_STORAGE_POOL_LOGICAL; -#endif -#if WITH_STORAGE_ISCSI - if (STREQ(type, "iscsi")) - return VIR_STORAGE_POOL_ISCSI; -#endif -#if WITH_STORAGE_DISK - if (STREQ(type, "disk")) - return VIR_STORAGE_POOL_DISK; -#endif - - virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, - _("unknown storage backend type %s"), type); - return -1; -} - -const char * -virStorageBackendToString(int type) { - switch (type) { - case VIR_STORAGE_POOL_DIR: - return "dir"; -#if WITH_STORAGE_FS - case VIR_STORAGE_POOL_FS: - return "fs"; - case VIR_STORAGE_POOL_NETFS: - return "netfs"; -#endif -#if WITH_STORAGE_LVM - case VIR_STORAGE_POOL_LOGICAL: - return "logical"; -#endif -#if WITH_STORAGE_ISCSI - case VIR_STORAGE_POOL_ISCSI: - return "iscsi"; -#endif -#if WITH_STORAGE_DISK - case VIR_STORAGE_POOL_DISK: - return "disk"; -#endif - } - - virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, - _("unknown storage backend type %d"), type); return NULL; } @@ -197,6 +119,13 @@ return ret; } + +struct diskType { + int part_table_type; + unsigned short offset; + unsigned short length; + unsigned long long magic; +}; static struct diskType const disk_types[] = { { VIR_STORAGE_POOL_DISK_LVM2, 0x218, 8, 0x31303020324D564CULL }, @@ -367,6 +296,12 @@ if (pool->def->target.path == NULL || STREQ(pool->def->target.path, "/dev") || STREQ(pool->def->target.path, "/dev/")) + goto ret_strdup; + + /* Skip whole thing for a pool which isn't in /dev + * so we don't mess will filesystem/dir based pools + */ + if (!STRPREFIX(pool->def->target.path, "/dev")) goto ret_strdup; /* The pool is pointing somewhere like /dev/disk/by-path diff -r 19c9bab70d15 src/storage_backend.h --- a/src/storage_backend.h Wed Nov 12 16:38:19 2008 +0000 +++ b/src/storage_backend.h Wed Nov 12 21:05:13 2008 +0000 @@ -24,67 +24,8 @@ #ifndef __VIR_STORAGE_BACKEND_H__ #define __VIR_STORAGE_BACKEND_H__ -#include <libvirt/libvirt.h> +#include "internal.h" #include "storage_conf.h" -#include "util.h" - - -typedef const char *(*virStorageVolFormatToString)(int format); -typedef int (*virStorageVolFormatFromString)(const char *format); - -typedef const char *(*virStoragePoolFormatToString)(int format); -typedef int (*virStoragePoolFormatFromString)(const char *format); - -typedef struct _virStorageBackendVolOptions virStorageBackendVolOptions; -typedef virStorageBackendVolOptions *virStorageBackendVolOptionsPtr; -struct _virStorageBackendVolOptions { - virStorageVolFormatToString formatToString; - virStorageVolFormatFromString formatFromString; -}; - - -/* Flags to indicate mandatory components in the pool source */ -enum { - VIR_STORAGE_BACKEND_POOL_SOURCE_HOST = (1<<0), - VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE = (1<<1), - VIR_STORAGE_BACKEND_POOL_SOURCE_DIR = (1<<2), - VIR_STORAGE_BACKEND_POOL_SOURCE_ADAPTER = (1<<3), - VIR_STORAGE_BACKEND_POOL_SOURCE_NAME = (1<<4), - VIR_STORAGE_BACKEND_POOL_STABLE_PATH = (1<<5), -}; - -enum partTableType { - VIR_STORAGE_POOL_DISK_UNKNOWN = 0, - VIR_STORAGE_POOL_DISK_DOS = 1, - VIR_STORAGE_POOL_DISK_DVH, - VIR_STORAGE_POOL_DISK_GPT, - VIR_STORAGE_POOL_DISK_MAC, - VIR_STORAGE_POOL_DISK_BSD, - VIR_STORAGE_POOL_DISK_PC98, - VIR_STORAGE_POOL_DISK_SUN, - VIR_STORAGE_POOL_DISK_LVM2, - VIR_STORAGE_POOL_DISK_LAST, -}; - -struct diskType { - enum partTableType part_table_type; - unsigned short offset; - unsigned short length; - unsigned long long magic; -}; -VIR_ENUM_DECL(virStorageBackendPartTable); - -typedef struct _virStorageBackendPoolOptions virStorageBackendPoolOptions; -typedef virStorageBackendPoolOptions *virStorageBackendPoolOptionsPtr; -struct _virStorageBackendPoolOptions { - int flags; - int defaultFormat; - virStoragePoolFormatToString formatToString; - virStoragePoolFormatFromString formatFromString; -}; - -#define SOURCES_START_TAG "<sources>" -#define SOURCES_END_TAG "</sources>" typedef char * (*virStorageBackendFindPoolSources)(virConnectPtr conn, const char *srcSpec, unsigned int flags); typedef int (*virStorageBackendStartPool)(virConnectPtr conn, virStoragePoolObjPtr pool); @@ -114,19 +55,10 @@ virStorageBackendCreateVol createVol; virStorageBackendRefreshVol refreshVol; virStorageBackendDeleteVol deleteVol; - - virStorageBackendPoolOptions poolOptions; - virStorageBackendVolOptions volOptions; - - int volType; }; +virStorageBackendPtr virStorageBackendForType(int type); -virStorageBackendPtr virStorageBackendForType(int type); -virStorageBackendPoolOptionsPtr virStorageBackendPoolOptionsForType(int type); -virStorageBackendVolOptionsPtr virStorageBackendVolOptionsForType(int type); -int virStorageBackendFromString(const char *type); -const char *virStorageBackendToString(int type); int virStorageBackendUpdateVolInfo(virConnectPtr conn, virStorageVolDefPtr vol, diff -r 19c9bab70d15 src/storage_backend_disk.c --- a/src/storage_backend_disk.c Wed Nov 12 16:38:19 2008 +0000 +++ b/src/storage_backend_disk.c Wed Nov 12 21:05:13 2008 +0000 @@ -24,40 +24,13 @@ #include <config.h> #include <string.h> #include <unistd.h> +#include <stdio.h> #include "virterror_internal.h" #include "logging.h" #include "storage_backend_disk.h" #include "util.h" #include "memory.h" - -/* - * XXX these are basically partition types. - * - * fdisk has a bazillion partition ID types - * parted has practically none, and splits the - * info across 3 different attributes. - * - * So this is a semi-generic set - */ -enum { - VIR_STORAGE_VOL_DISK_NONE = 0, - VIR_STORAGE_VOL_DISK_LINUX, - VIR_STORAGE_VOL_DISK_FAT16, - VIR_STORAGE_VOL_DISK_FAT32, - VIR_STORAGE_VOL_DISK_LINUX_SWAP, - VIR_STORAGE_VOL_DISK_LINUX_LVM, - VIR_STORAGE_VOL_DISK_LINUX_RAID, - VIR_STORAGE_VOL_DISK_EXTENDED, - VIR_STORAGE_VOL_DISK_LAST, -}; -VIR_ENUM_DECL(virStorageBackendDiskVol); -VIR_ENUM_IMPL(virStorageBackendDiskVol, - VIR_STORAGE_VOL_DISK_LAST, - "none", "linux", "fat16", - "fat32", "linux-swap", - "linux-lvm", "linux-raid", - "extended"); #define PARTHELPER BINDIR "/libvirt_parthelper" @@ -154,6 +127,8 @@ if (virStorageBackendUpdateVolInfo(conn, vol, 1) < 0) return -1; + vol->type = VIR_STORAGE_VOL_BLOCK; + /* The above gets allocation wrong for * extended partitions, so overwrite it */ vol->allocation = vol->capacity = @@ -306,7 +281,7 @@ "mklabel", "--script", ((pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) ? "msdos" : - virStorageBackendPartTableTypeToString(pool->def->source.format)), + virStoragePoolFormatDiskTypeToString(pool->def->source.format)), NULL, }; @@ -445,18 +420,4 @@ .createVol = virStorageBackendDiskCreateVol, .deleteVol = virStorageBackendDiskDeleteVol, - - .poolOptions = { - .flags = (VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE| - VIR_STORAGE_BACKEND_POOL_STABLE_PATH), - .defaultFormat = VIR_STORAGE_POOL_DISK_UNKNOWN, - .formatFromString = virStorageBackendPartTableTypeFromString, - .formatToString = virStorageBackendPartTableTypeToString, - }, - .volOptions = { - .formatFromString = virStorageBackendDiskVolTypeFromString, - .formatToString = virStorageBackendDiskVolTypeToString, - }, - - .volType = VIR_STORAGE_VOL_BLOCK, }; diff -r 19c9bab70d15 src/storage_backend_fs.c --- a/src/storage_backend_fs.c Wed Nov 12 16:38:19 2008 +0000 +++ b/src/storage_backend_fs.c Wed Nov 12 21:05:13 2008 +0000 @@ -47,59 +47,6 @@ #include "memory.h" #include "xml.h" -enum { - VIR_STORAGE_POOL_FS_AUTO = 0, - VIR_STORAGE_POOL_FS_EXT2, - VIR_STORAGE_POOL_FS_EXT3, - VIR_STORAGE_POOL_FS_EXT4, - VIR_STORAGE_POOL_FS_UFS, - VIR_STORAGE_POOL_FS_ISO, - VIR_STORAGE_POOL_FS_UDF, - VIR_STORAGE_POOL_FS_GFS, - VIR_STORAGE_POOL_FS_GFS2, - VIR_STORAGE_POOL_FS_VFAT, - VIR_STORAGE_POOL_FS_HFSPLUS, - VIR_STORAGE_POOL_FS_XFS, - VIR_STORAGE_POOL_FS_LAST, -}; -VIR_ENUM_DECL(virStorageBackendFileSystemPool); -VIR_ENUM_IMPL(virStorageBackendFileSystemPool, - VIR_STORAGE_POOL_FS_LAST, - "auto", "ext2", "ext3", - "ext4", "ufs", "iso9660", "udf", - "gfs", "gfs2", "vfat", "hfs+", "xfs"); - -enum { - VIR_STORAGE_POOL_NETFS_AUTO = 0, - VIR_STORAGE_POOL_NETFS_NFS, - VIR_STORAGE_POOL_NETFS_LAST, -}; -VIR_ENUM_DECL(virStorageBackendFileSystemNetPool); -VIR_ENUM_IMPL(virStorageBackendFileSystemNetPool, - VIR_STORAGE_POOL_NETFS_LAST, - "auto", "nfs"); - - -enum { - VIR_STORAGE_VOL_RAW = 0, - VIR_STORAGE_VOL_DIR, - VIR_STORAGE_VOL_BOCHS, - VIR_STORAGE_VOL_CLOOP, - VIR_STORAGE_VOL_COW, - VIR_STORAGE_VOL_DMG, - VIR_STORAGE_VOL_ISO, - VIR_STORAGE_VOL_QCOW, - VIR_STORAGE_VOL_QCOW2, - VIR_STORAGE_VOL_VMDK, - VIR_STORAGE_VOL_VPC, - VIR_STORAGE_VOL_LAST, -}; -VIR_ENUM_DECL(virStorageBackendFileSystemVol); -VIR_ENUM_IMPL(virStorageBackendFileSystemVol, - VIR_STORAGE_VOL_LAST, - "raw", "dir", "bochs", - "cloop", "cow", "dmg", "iso", - "qcow", "qcow2", "vmdk", "vpc"); /* Either 'magic' or 'extension' *must* be provided */ struct FileTypeInfo { @@ -130,45 +77,45 @@ __LITTLE_ENDIAN, -1, 0, -1, 0, 0 }, */ /* Cow */ - { VIR_STORAGE_VOL_COW, "OOOM", NULL, + { VIR_STORAGE_VOL_FILE_COW, "OOOM", NULL, __BIG_ENDIAN, 4, 2, 4+4+1024+4, 8, 1 }, /* DMG */ /* XXX QEMU says there's no magic for dmg, but we should check... */ - { VIR_STORAGE_VOL_DMG, NULL, ".dmg", + { VIR_STORAGE_VOL_FILE_DMG, NULL, ".dmg", 0, -1, 0, -1, 0, 0 }, /* XXX there's probably some magic for iso we can validate too... */ - { VIR_STORAGE_VOL_ISO, NULL, ".iso", + { VIR_STORAGE_VOL_FILE_ISO, NULL, ".iso", 0, -1, 0, -1, 0, 0 }, /* Parallels */ /* XXX Untested - { VIR_STORAGE_VOL_PARALLELS, "WithoutFreeSpace", NULL, + { VIR_STORAGE_VOL_FILE_PARALLELS, "WithoutFreeSpace", NULL, __LITTLE_ENDIAN, 16, 2, 16+4+4+4+4, 4, 512 }, */ /* QCow */ - { VIR_STORAGE_VOL_QCOW, "QFI", NULL, + { VIR_STORAGE_VOL_FILE_QCOW, "QFI", NULL, __BIG_ENDIAN, 4, 1, 4+4+8+4+4, 8, 1 }, /* QCow 2 */ - { VIR_STORAGE_VOL_QCOW2, "QFI", NULL, + { VIR_STORAGE_VOL_FILE_QCOW2, "QFI", NULL, __BIG_ENDIAN, 4, 2, 4+4+8+4+4, 8, 1 }, /* VMDK 3 */ /* XXX Untested - { VIR_STORAGE_VOL_VMDK, "COWD", NULL, + { VIR_STORAGE_VOL_FILE_VMDK, "COWD", NULL, __LITTLE_ENDIAN, 4, 1, 4+4+4, 4, 512 }, */ /* VMDK 4 */ - { VIR_STORAGE_VOL_VMDK, "KDMV", NULL, + { VIR_STORAGE_VOL_FILE_VMDK, "KDMV", NULL, __LITTLE_ENDIAN, 4, 1, 4+4+4, 8, 512 }, /* Connectix / VirtualPC */ /* XXX Untested - { VIR_STORAGE_VOL_VPC, "conectix", NULL, + { VIR_STORAGE_VOL_FILE_VPC, "conectix", NULL, __BIG_ENDIAN, -1, 0, -1, 0, 0}, */ @@ -288,7 +235,7 @@ } /* All fails, so call it a raw file */ - def->target.format = VIR_STORAGE_VOL_RAW; + def->target.format = VIR_STORAGE_VOL_FILE_RAW; return 0; } @@ -486,8 +433,8 @@ MOUNT, "-t", pool->def->type == VIR_STORAGE_POOL_FS ? - virStorageBackendFileSystemPoolTypeToString(pool->def->source.format) : - virStorageBackendFileSystemNetPoolTypeToString(pool->def->source.format), + virStoragePoolFormatFileSystemTypeToString(pool->def->source.format) : + virStoragePoolFormatFileSystemNetTypeToString(pool->def->source.format), NULL, /* Fill in shortly - careful not to add extra fields before this */ pool->def->target.path, @@ -689,7 +636,8 @@ if ((vol->name = strdup(ent->d_name)) == NULL) goto no_memory; - vol->target.format = VIR_STORAGE_VOL_RAW; /* Real value is filled in during probe */ + vol->type = VIR_STORAGE_VOL_FILE; + vol->target.format = VIR_STORAGE_VOL_FILE_RAW; /* Real value is filled in during probe */ if (VIR_ALLOC_N(vol->target.path, strlen(pool->def->target.path) + 1 + strlen(vol->name) + 1) < 0) goto no_memory; @@ -815,6 +763,7 @@ virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s", _("target")); return -1; } + vol->type = VIR_STORAGE_VOL_FILE; strcpy(vol->target.path, pool->def->target.path); strcat(vol->target.path, "/"); strcat(vol->target.path, vol->name); @@ -825,7 +774,7 @@ return -1; } - if (vol->target.format == VIR_STORAGE_VOL_RAW) { + if (vol->target.format == VIR_STORAGE_VOL_FILE_RAW) { if ((fd = open(vol->target.path, O_RDWR | O_CREAT | O_EXCL, vol->target.perms.mode)) < 0) { virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, @@ -865,7 +814,7 @@ close(fd); return -1; } - } else if (vol->target.format == VIR_STORAGE_VOL_DIR) { + } else if (vol->target.format == VIR_STORAGE_VOL_FILE_DIR) { if (mkdir(vol->target.path, vol->target.perms.mode) < 0) { virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, _("cannot create path '%s': %s"), @@ -885,7 +834,7 @@ char size[100]; const char *imgargv[7]; - if ((type = virStorageBackendFileSystemVolTypeToString(vol->target.format)) == NULL) { + if ((type = virStorageVolFormatFileSystemTypeToString(vol->target.format)) == NULL) { virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, _("unknown storage vol type %d"), vol->target.format); @@ -923,7 +872,7 @@ char size[100]; const char *imgargv[4]; - if (vol->target.format != VIR_STORAGE_VOL_QCOW2) { + if (vol->target.format != VIR_STORAGE_VOL_FILE_QCOW2) { virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, _("unsupported storage vol type %d"), vol->target.format); @@ -1040,12 +989,6 @@ .createVol = virStorageBackendFileSystemVolCreate, .refreshVol = virStorageBackendFileSystemVolRefresh, .deleteVol = virStorageBackendFileSystemVolDelete, - - .volOptions = { - .formatFromString = virStorageBackendFileSystemVolTypeFromString, - .formatToString = virStorageBackendFileSystemVolTypeToString, - }, - .volType = VIR_STORAGE_VOL_FILE, }; #if WITH_STORAGE_FS @@ -1060,17 +1003,6 @@ .createVol = virStorageBackendFileSystemVolCreate, .refreshVol = virStorageBackendFileSystemVolRefresh, .deleteVol = virStorageBackendFileSystemVolDelete, - - .poolOptions = { - .flags = (VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE), - .formatFromString = virStorageBackendFileSystemPoolTypeFromString, - .formatToString = virStorageBackendFileSystemPoolTypeToString, - }, - .volOptions = { - .formatFromString = virStorageBackendFileSystemVolTypeFromString, - .formatToString = virStorageBackendFileSystemVolTypeToString, - }, - .volType = VIR_STORAGE_VOL_FILE, }; virStorageBackend virStorageBackendNetFileSystem = { .type = VIR_STORAGE_POOL_NETFS, @@ -1084,18 +1016,5 @@ .createVol = virStorageBackendFileSystemVolCreate, .refreshVol = virStorageBackendFileSystemVolRefresh, .deleteVol = virStorageBackendFileSystemVolDelete, - - .poolOptions = { - .flags = (VIR_STORAGE_BACKEND_POOL_SOURCE_HOST | - VIR_STORAGE_BACKEND_POOL_SOURCE_DIR), - .defaultFormat = VIR_STORAGE_POOL_FS_AUTO, - .formatFromString = virStorageBackendFileSystemNetPoolTypeFromString, - .formatToString = virStorageBackendFileSystemNetPoolTypeToString, - }, - .volOptions = { - .formatFromString = virStorageBackendFileSystemVolTypeFromString, - .formatToString = virStorageBackendFileSystemVolTypeToString, - }, - .volType = VIR_STORAGE_VOL_FILE, }; #endif /* WITH_STORAGE_FS */ diff -r 19c9bab70d15 src/storage_backend_iscsi.c --- a/src/storage_backend_iscsi.c Wed Nov 12 16:38:19 2008 +0000 +++ b/src/storage_backend_iscsi.c Wed Nov 12 21:05:13 2008 +0000 @@ -177,6 +177,8 @@ virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s", _("volume")); goto cleanup; } + + vol->type = VIR_STORAGE_VOL_BLOCK; if (asprintf(&(vol->name), "lun-%d", lun) < 0) { virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s", _("name")); @@ -641,15 +643,4 @@ .startPool = virStorageBackendISCSIStartPool, .refreshPool = virStorageBackendISCSIRefreshPool, .stopPool = virStorageBackendISCSIStopPool, - - .poolOptions = { - .flags = (VIR_STORAGE_BACKEND_POOL_SOURCE_HOST | - VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE | - VIR_STORAGE_BACKEND_POOL_STABLE_PATH) - }, - - .volType = VIR_STORAGE_VOL_BLOCK, - .volOptions = { - .formatToString = virStorageBackendPartTableTypeToString, - } }; diff -r 19c9bab70d15 src/storage_backend_logical.c --- a/src/storage_backend_logical.c Wed Nov 12 16:38:19 2008 +0000 +++ b/src/storage_backend_logical.c Wed Nov 12 21:05:13 2008 +0000 @@ -39,15 +39,6 @@ #define PV_BLANK_SECTOR_SIZE 512 -enum { - VIR_STORAGE_POOL_LOGICAL_UNKNOWN = 0, - VIR_STORAGE_POOL_LOGICAL_LVM2 = 1, - VIR_STORAGE_POOL_LOGICAL_LAST, -}; -VIR_ENUM_DECL(virStorageBackendLogicalPool); -VIR_ENUM_IMPL(virStorageBackendLogicalPool, - VIR_STORAGE_POOL_LOGICAL_LAST, - "unknown", "lvm2"); static int virStorageBackendLogicalSetActive(virConnectPtr conn, @@ -94,6 +85,8 @@ virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s", _("volume")); return -1; } + + vol->type = VIR_STORAGE_VOL_BLOCK; if ((vol->name = strdup(groups[0])) == NULL) { virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s", _("volume")); @@ -574,6 +567,8 @@ snprintf(size, sizeof(size)-1, "%lluK", vol->capacity/1024); size[sizeof(size)-1] = '\0'; + vol->type = VIR_STORAGE_VOL_BLOCK; + if (vol->target.path != NULL) { /* A target path passed to CreateVol has no meaning */ VIR_FREE(vol->target.path); @@ -666,14 +661,4 @@ .deletePool = virStorageBackendLogicalDeletePool, .createVol = virStorageBackendLogicalCreateVol, .deleteVol = virStorageBackendLogicalDeleteVol, - - .poolOptions = { - .flags = (VIR_STORAGE_BACKEND_POOL_SOURCE_NAME | - VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE), - .defaultFormat = VIR_STORAGE_POOL_LOGICAL_LVM2, - .formatFromString = virStorageBackendLogicalPoolTypeFromString, - .formatToString = virStorageBackendLogicalPoolTypeToString, - }, - - .volType = VIR_STORAGE_VOL_BLOCK, }; diff -r 19c9bab70d15 src/storage_conf.c --- a/src/storage_conf.c Wed Nov 12 16:38:19 2008 +0000 +++ b/src/storage_conf.c Wed Nov 12 21:05:13 2008 +0000 @@ -36,7 +36,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "storage_conf.h" -#include "storage_backend.h" + #include "xml.h" #include "uuid.h" #include "buf.h" @@ -44,6 +44,181 @@ #include "memory.h" #define virStorageLog(msg...) fprintf(stderr, msg) + +VIR_ENUM_IMPL(virStoragePool, + VIR_STORAGE_POOL_LAST, + "dir", "fs", "netfs", + "logical", "disk", "iscsi", + "scsi"); + +VIR_ENUM_IMPL(virStoragePoolFormatFileSystem, + VIR_STORAGE_POOL_FS_LAST, + "auto", "ext2", "ext3", + "ext4", "ufs", "iso9660", "udf", + "gfs", "gfs2", "vfat", "hfs+", "xfs"); + +VIR_ENUM_IMPL(virStoragePoolFormatFileSystemNet, + VIR_STORAGE_POOL_NETFS_LAST, + "auto", "nfs"); + +VIR_ENUM_IMPL(virStoragePoolFormatDisk, + VIR_STORAGE_POOL_DISK_LAST, + "unknown", "dos", "dvh", "gpt", + "mac", "bsd", "pc98", "sun", "lvm2"); + +VIR_ENUM_IMPL(virStoragePoolFormatLogical, + VIR_STORAGE_POOL_LOGICAL_LAST, + "unknown", "lvm2"); + + +VIR_ENUM_IMPL(virStorageVolFormatDisk, + VIR_STORAGE_VOL_DISK_LAST, + "none", "linux", "fat16", + "fat32", "linux-swap", + "linux-lvm", "linux-raid", + "extended"); + +VIR_ENUM_IMPL(virStorageVolFormatFileSystem, + VIR_STORAGE_VOL_FILE_LAST, + "raw", "dir", "bochs", + "cloop", "cow", "dmg", "iso", + "qcow", "qcow2", "vmdk", "vpc"); + + +typedef const char *(*virStorageVolFormatToString)(int format); +typedef int (*virStorageVolFormatFromString)(const char *format); + +typedef const char *(*virStoragePoolFormatToString)(int format); +typedef int (*virStoragePoolFormatFromString)(const char *format); + +typedef struct _virStorageVolOptions virStorageVolOptions; +typedef virStorageVolOptions *virStorageVolOptionsPtr; +struct _virStorageVolOptions { + virStorageVolFormatToString formatToString; + virStorageVolFormatFromString formatFromString; +}; + +/* Flags to indicate mandatory components in the pool source */ +enum { + VIR_STORAGE_POOL_SOURCE_HOST = (1<<0), + VIR_STORAGE_POOL_SOURCE_DEVICE = (1<<1), + VIR_STORAGE_POOL_SOURCE_DIR = (1<<2), + VIR_STORAGE_POOL_SOURCE_ADAPTER = (1<<3), + VIR_STORAGE_POOL_SOURCE_NAME = (1<<4), +}; + + + +typedef struct _virStoragePoolOptions virStoragePoolOptions; +typedef virStoragePoolOptions *virStoragePoolOptionsPtr; +struct _virStoragePoolOptions { + int flags; + int defaultFormat; + virStoragePoolFormatToString formatToString; + virStoragePoolFormatFromString formatFromString; +}; + +typedef struct _virStoragePoolTypeInfo virStoragePoolTypeInfo; +typedef virStoragePoolTypeInfo *virStoragePoolTypeInfoPtr; + +struct _virStoragePoolTypeInfo { + int poolType; + virStoragePoolOptions poolOptions; + virStorageVolOptions volOptions; +}; + +static virStoragePoolTypeInfo poolTypeInfo[] = { + { .poolType = VIR_STORAGE_POOL_LOGICAL, + .poolOptions = { + .flags = (VIR_STORAGE_POOL_SOURCE_NAME | + VIR_STORAGE_POOL_SOURCE_DEVICE), + .defaultFormat = VIR_STORAGE_POOL_LOGICAL_LVM2, + .formatFromString = virStoragePoolFormatLogicalTypeFromString, + .formatToString = virStoragePoolFormatLogicalTypeToString, + }, + }, + { .poolType = VIR_STORAGE_POOL_DIR, + .volOptions = { + .formatFromString = virStorageVolFormatFileSystemTypeFromString, + .formatToString = virStorageVolFormatFileSystemTypeToString, + }, + }, + { .poolType = VIR_STORAGE_POOL_FS, + .poolOptions = { + .flags = (VIR_STORAGE_POOL_SOURCE_DEVICE), + .formatFromString = virStoragePoolFormatFileSystemTypeFromString, + .formatToString = virStoragePoolFormatFileSystemTypeToString, + }, + .volOptions = { + .formatFromString = virStorageVolFormatFileSystemTypeFromString, + .formatToString = virStorageVolFormatFileSystemTypeToString, + }, + }, + { .poolType = VIR_STORAGE_POOL_NETFS, + .poolOptions = { + .flags = (VIR_STORAGE_POOL_SOURCE_HOST | + VIR_STORAGE_POOL_SOURCE_DIR), + .defaultFormat = VIR_STORAGE_POOL_FS_AUTO, + .formatFromString = virStoragePoolFormatFileSystemNetTypeFromString, + .formatToString = virStoragePoolFormatFileSystemNetTypeToString, + }, + .volOptions = { + .formatFromString = virStorageVolFormatFileSystemTypeFromString, + .formatToString = virStorageVolFormatFileSystemTypeToString, + }, + }, + { .poolType = VIR_STORAGE_POOL_ISCSI, + .poolOptions = { + .flags = (VIR_STORAGE_POOL_SOURCE_HOST | + VIR_STORAGE_POOL_SOURCE_DEVICE), + }, + .volOptions = { + .formatToString = virStoragePoolFormatDiskTypeToString, + } + }, + { .poolType = VIR_STORAGE_POOL_DISK, + .poolOptions = { + .flags = (VIR_STORAGE_POOL_SOURCE_DEVICE), + .defaultFormat = VIR_STORAGE_POOL_DISK_UNKNOWN, + .formatFromString = virStoragePoolFormatDiskTypeFromString, + .formatToString = virStoragePoolFormatDiskTypeToString, + }, + .volOptions = { + .formatFromString = virStorageVolFormatDiskTypeFromString, + .formatToString = virStorageVolFormatDiskTypeToString, + }, + } +}; + + +static virStoragePoolTypeInfoPtr +virStoragePoolTypeInfoLookup(int type) { + unsigned int i; + for (i = 0; i < ARRAY_CARDINALITY(poolTypeInfo) ; i++) + if (poolTypeInfo[i].poolType == type) + return &poolTypeInfo[i]; + + virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, + _("missing backend for pool type %d"), type); + return NULL; +} + +static virStoragePoolOptionsPtr +virStoragePoolOptionsForPoolType(int type) { + virStoragePoolTypeInfoPtr backend = virStoragePoolTypeInfoLookup(type); + if (backend == NULL) + return NULL; + return &backend->poolOptions; +} + +static virStorageVolOptionsPtr +virStorageVolOptionsForPoolType(int type) { + virStoragePoolTypeInfoPtr backend = virStoragePoolTypeInfoLookup(type); + if (backend == NULL) + return NULL; + return &backend->volOptions; +} + void virStorageVolDefFree(virStorageVolDefPtr def) { @@ -224,7 +399,7 @@ virStoragePoolDefParseDoc(virConnectPtr conn, xmlXPathContextPtr ctxt, xmlNodePtr root) { - virStorageBackendPoolOptionsPtr options; + virStoragePoolOptionsPtr options; virStoragePoolDefPtr ret; xmlChar *type = NULL; char *uuid = NULL; @@ -238,23 +413,27 @@ if (STRNEQ((const char *)root->name, "pool")) { virStorageReportError(conn, VIR_ERR_XML_ERROR, - "%s", _("unknown root elementi for storage pool")); + "%s", _("unknown root element for storage pool")); goto cleanup; } type = xmlGetProp(root, BAD_CAST "type"); - if ((ret->type = virStorageBackendFromString((const char *)type)) < 0) + if ((ret->type = virStoragePoolTypeFromString((const char *)type)) < 0) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("unknown storage pool type %s"), (const char*)type); goto cleanup; + } + xmlFree(type); type = NULL; - if ((options = virStorageBackendPoolOptionsForType(ret->type)) == NULL) { + if ((options = virStoragePoolOptionsForPoolType(ret->type)) == NULL) { goto cleanup; } ret->name = virXPathString(conn, "string(/pool/name)", ctxt); if (ret->name == NULL && - options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_NAME) + options->flags & VIR_STORAGE_POOL_SOURCE_NAME) ret->name = virXPathString(conn, "string(/pool/source/name)", ctxt); if (ret->name == NULL) { virStorageReportError(conn, VIR_ERR_XML_ERROR, @@ -294,14 +473,14 @@ VIR_FREE(format); } - if (options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_HOST) { + if (options->flags & VIR_STORAGE_POOL_SOURCE_HOST) { if ((ret->source.host.name = virXPathString(conn, "string(/pool/source/host/@name)", ctxt)) == NULL) { virStorageReportError(conn, VIR_ERR_XML_ERROR, "%s", _("missing storage pool source host name")); goto cleanup; } } - if (options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE) { + if (options->flags & VIR_STORAGE_POOL_SOURCE_DEVICE) { xmlNodePtr *nodeset = NULL; int nsource, i; @@ -328,14 +507,14 @@ VIR_FREE(nodeset); ret->source.ndevice = nsource; } - if (options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_DIR) { + if (options->flags & VIR_STORAGE_POOL_SOURCE_DIR) { if ((ret->source.dir = virXPathString(conn, "string(/pool/source/dir/@path)", ctxt)) == NULL) { virStorageReportError(conn, VIR_ERR_XML_ERROR, "%s", _("missing storage pool source path")); goto cleanup; } } - if (options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_NAME) { + if (options->flags & VIR_STORAGE_POOL_SOURCE_NAME) { ret->source.name = virXPathString(conn, "string(/pool/source/name)", ctxt); if (ret->source.name == NULL) { @@ -471,17 +650,17 @@ static int virStoragePoolSourceFormat(virConnectPtr conn, virBufferPtr buf, - virStorageBackendPoolOptionsPtr options, + virStoragePoolOptionsPtr options, virStoragePoolSourcePtr src) { int i, j; virBufferAddLit(buf," <source>\n"); - if ((options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_HOST) && + if ((options->flags & VIR_STORAGE_POOL_SOURCE_HOST) && src->host.name) virBufferVSprintf(buf," <host name='%s'/>\n", src->host.name); - if ((options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE) && + if ((options->flags & VIR_STORAGE_POOL_SOURCE_DEVICE) && src->ndevice) { for (i = 0 ; i < src->ndevice ; i++) { if (src->devices[i].nfreeExtent) { @@ -499,13 +678,13 @@ src->devices[i].path); } } - if ((options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_DIR) && + if ((options->flags & VIR_STORAGE_POOL_SOURCE_DIR) && src->dir) virBufferVSprintf(buf," <dir path='%s'/>\n", src->dir); - if ((options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_ADAPTER) && + if ((options->flags & VIR_STORAGE_POOL_SOURCE_ADAPTER) && src->adapter) virBufferVSprintf(buf," <adapter name='%s'/>\n", src->adapter); - if ((options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_NAME) && + if ((options->flags & VIR_STORAGE_POOL_SOURCE_NAME) && src->name) virBufferVSprintf(buf," <name>%s</name>\n", src->name); @@ -534,16 +713,16 @@ char * virStoragePoolDefFormat(virConnectPtr conn, virStoragePoolDefPtr def) { - virStorageBackendPoolOptionsPtr options; + virStoragePoolOptionsPtr options; virBuffer buf = VIR_BUFFER_INITIALIZER; const char *type; char uuid[VIR_UUID_STRING_BUFLEN]; - options = virStorageBackendPoolOptionsForType(def->type); + options = virStoragePoolOptionsForPoolType(def->type); if (options == NULL) return NULL; - type = virStorageBackendToString(def->type); + type = virStoragePoolTypeToString(def->type); if (!type) { virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", _("unexpected pool type")); @@ -725,12 +904,12 @@ xmlXPathContextPtr ctxt, xmlNodePtr root) { virStorageVolDefPtr ret; - virStorageBackendVolOptionsPtr options; + virStorageVolOptionsPtr options; char *allocation = NULL; char *capacity = NULL; char *unit = NULL; - options = virStorageBackendVolOptionsForType(pool->type); + options = virStorageVolOptionsForPoolType(pool->type); if (options == NULL) return NULL; @@ -870,11 +1049,11 @@ virStorageVolDefFormat(virConnectPtr conn, virStoragePoolDefPtr pool, virStorageVolDefPtr def) { - virStorageBackendVolOptionsPtr options; + virStorageVolOptionsPtr options; virBuffer buf = VIR_BUFFER_INITIALIZER; char *tmp; - options = virStorageBackendVolOptionsForType(pool->type); + options = virStorageVolOptionsForPoolType(pool->type); if (options == NULL) return NULL; @@ -1283,16 +1462,16 @@ char *virStoragePoolSourceListFormat(virConnectPtr conn, virStoragePoolSourceListPtr def) { - virStorageBackendPoolOptionsPtr options; + virStoragePoolOptionsPtr options; virBuffer buf = VIR_BUFFER_INITIALIZER; const char *type; int i; - options = virStorageBackendPoolOptionsForType(def->type); + options = virStoragePoolOptionsForPoolType(def->type); if (options == NULL) return NULL; - type = virStorageBackendToString(def->type); + type = virStoragePoolTypeToString(def->type); if (!type) { virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", _("unexpected pool type")); diff -r 19c9bab70d15 src/storage_conf.h --- a/src/storage_conf.h Wed Nov 12 16:38:19 2008 +0000 +++ b/src/storage_conf.h Wed Nov 12 21:05:13 2008 +0000 @@ -24,11 +24,8 @@ #ifndef __VIR_STORAGE_CONF_H__ #define __VIR_STORAGE_CONF_H__ -#include <libxml/parser.h> -#include <libxml/tree.h> -#include <libxml/xpath.h> - #include "internal.h" +#include "util.h" /* Shared structs */ @@ -84,6 +81,7 @@ struct _virStorageVolDef { char *name; char *key; + int type; /* virStorageVolType enum */ unsigned long long allocation; unsigned long long capacity; @@ -104,14 +102,18 @@ /* Storage pools */ enum virStoragePoolType { - VIR_STORAGE_POOL_DIR = 1, /* Local directory */ + VIR_STORAGE_POOL_DIR, /* Local directory */ VIR_STORAGE_POOL_FS, /* Local filesystem */ VIR_STORAGE_POOL_NETFS, /* Networked filesystem - eg NFS, GFS, etc */ VIR_STORAGE_POOL_LOGICAL, /* Logical volume groups / volumes */ VIR_STORAGE_POOL_DISK, /* Disk partitions */ VIR_STORAGE_POOL_ISCSI, /* iSCSI targets */ VIR_STORAGE_POOL_SCSI, /* SCSI HBA */ + + VIR_STORAGE_POOL_LAST, }; + +VIR_ENUM_DECL(virStoragePool); enum virStoragePoolAuthType { @@ -259,6 +261,7 @@ unsigned int nsources; virStoragePoolSourcePtr sources; }; + static inline int virStoragePoolObjIsActive(virStoragePoolObjPtr pool) { return pool->active; @@ -322,4 +325,93 @@ char *virStoragePoolSourceListFormat(virConnectPtr conn, virStoragePoolSourceListPtr def); + + +enum virStoragePoolFormatFileSystem { + VIR_STORAGE_POOL_FS_AUTO = 0, + VIR_STORAGE_POOL_FS_EXT2, + VIR_STORAGE_POOL_FS_EXT3, + VIR_STORAGE_POOL_FS_EXT4, + VIR_STORAGE_POOL_FS_UFS, + VIR_STORAGE_POOL_FS_ISO, + VIR_STORAGE_POOL_FS_UDF, + VIR_STORAGE_POOL_FS_GFS, + VIR_STORAGE_POOL_FS_GFS2, + VIR_STORAGE_POOL_FS_VFAT, + VIR_STORAGE_POOL_FS_HFSPLUS, + VIR_STORAGE_POOL_FS_XFS, + VIR_STORAGE_POOL_FS_LAST, +}; +VIR_ENUM_DECL(virStoragePoolFormatFileSystem); + +enum virStoragePoolFormatFileSystemNet { + VIR_STORAGE_POOL_NETFS_AUTO = 0, + VIR_STORAGE_POOL_NETFS_NFS, + VIR_STORAGE_POOL_NETFS_LAST, +}; +VIR_ENUM_DECL(virStoragePoolFormatFileSystemNet); + +enum virStoragePoolFormatDisk { + VIR_STORAGE_POOL_DISK_UNKNOWN = 0, + VIR_STORAGE_POOL_DISK_DOS = 1, + VIR_STORAGE_POOL_DISK_DVH, + VIR_STORAGE_POOL_DISK_GPT, + VIR_STORAGE_POOL_DISK_MAC, + VIR_STORAGE_POOL_DISK_BSD, + VIR_STORAGE_POOL_DISK_PC98, + VIR_STORAGE_POOL_DISK_SUN, + VIR_STORAGE_POOL_DISK_LVM2, + VIR_STORAGE_POOL_DISK_LAST, +}; + +VIR_ENUM_DECL(virStoragePoolFormatDisk); + +enum virStoragePoolFormatLogical { + VIR_STORAGE_POOL_LOGICAL_UNKNOWN = 0, + VIR_STORAGE_POOL_LOGICAL_LVM2 = 1, + VIR_STORAGE_POOL_LOGICAL_LAST, +}; +VIR_ENUM_DECL(virStoragePoolFormatLogical); + + +enum virStorageVolFormatFileSystem { + VIR_STORAGE_VOL_FILE_RAW = 0, + VIR_STORAGE_VOL_FILE_DIR, + VIR_STORAGE_VOL_FILE_BOCHS, + VIR_STORAGE_VOL_FILE_CLOOP, + VIR_STORAGE_VOL_FILE_COW, + VIR_STORAGE_VOL_FILE_DMG, + VIR_STORAGE_VOL_FILE_ISO, + VIR_STORAGE_VOL_FILE_QCOW, + VIR_STORAGE_VOL_FILE_QCOW2, + VIR_STORAGE_VOL_FILE_VMDK, + VIR_STORAGE_VOL_FILE_VPC, + VIR_STORAGE_VOL_FILE_LAST, +}; +VIR_ENUM_DECL(virStorageVolFormatFileSystem); + +/* + * XXX these are basically partition types. + * + * fdisk has a bazillion partition ID types + * parted has practically none, and splits the + * info across 3 different attributes. + * + * So this is a semi-generic set + */ +enum virStorageVolFormatDisk { + VIR_STORAGE_VOL_DISK_NONE = 0, + VIR_STORAGE_VOL_DISK_LINUX, + VIR_STORAGE_VOL_DISK_FAT16, + VIR_STORAGE_VOL_DISK_FAT32, + VIR_STORAGE_VOL_DISK_LINUX_SWAP, + VIR_STORAGE_VOL_DISK_LINUX_LVM, + VIR_STORAGE_VOL_DISK_LINUX_RAID, + VIR_STORAGE_VOL_DISK_EXTENDED, + VIR_STORAGE_VOL_DISK_LAST, +}; +VIR_ENUM_DECL(virStorageVolFormatDisk); + + + #endif /* __VIR_STORAGE_CONF_H__ */ diff -r 19c9bab70d15 src/storage_driver.c --- a/src/storage_driver.c Wed Nov 12 16:38:19 2008 +0000 +++ b/src/storage_driver.c Wed Nov 12 21:05:13 2008 +0000 @@ -403,7 +403,7 @@ int backend_type; virStorageBackendPtr backend; - backend_type = virStorageBackendFromString(type); + backend_type = virStoragePoolTypeFromString(type); if (backend_type < 0) return NULL; @@ -968,33 +968,22 @@ for (i = 0 ; i < driver->pools.count ; i++) { if (virStoragePoolObjIsActive(driver->pools.objs[i])) { virStorageVolDefPtr vol; - virStorageBackendPoolOptionsPtr options; + const char *stable_path; - options = virStorageBackendPoolOptionsForType(driver->pools.objs[i]->def->type); - if (options == NULL) - continue; + stable_path = virStorageBackendStablePath(conn, + driver->pools.objs[i], + path); + /* + * virStorageBackendStablePath already does + * virStorageReportError if it fails; we just need to keep + * propagating the return code + */ + if (stable_path == NULL) + return NULL; - if (options->flags & VIR_STORAGE_BACKEND_POOL_STABLE_PATH) { - const char *stable_path; - - stable_path = virStorageBackendStablePath(conn, - driver->pools.objs[i], - path); - /* - * virStorageBackendStablePath already does - * virStorageReportError if it fails; we just need to keep - * propagating the return code - */ - if (stable_path == NULL) - return NULL; - - vol = virStorageVolDefFindByPath(driver->pools.objs[i], - stable_path); - VIR_FREE(stable_path); - } - else - vol = virStorageVolDefFindByPath(driver->pools.objs[i], path); - + vol = virStorageVolDefFindByPath(driver->pools.objs[i], + stable_path); + VIR_FREE(stable_path); if (vol) return virGetStorageVol(conn, @@ -1170,7 +1159,7 @@ return -1; memset(info, 0, sizeof(*info)); - info->type = backend->volType; + info->type = vol->type; info->capacity = vol->capacity; info->allocation = vol->allocation; -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Thu, Nov 13, 2008 at 05:23:05PM +0000, Daniel P. Berrange wrote:
My previous patch for refactoring the storage backends broke the test driver's storage capabilities. The problem was that it made the backends private to the storage driver, but part of them was in fact needed by the XML parsers. This patch pulls a bunch of code out of the storage_backenmd file, and individual drivers and puts it straight into storage_conf.c/h for generic use by the parser. The storage backends are not totally private to the storage driver, and the test driver's storage impl still works
Okay, this really looks like only stuff moved around ... with a bit of renaming too, ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

This patch changes the way hypervisor URIs are probed when NULL is passed to the virConnectOpen() method. Previously we had an explicit probe method called in each driver. This does not work when we move some drivers out of libvirt.so and into libvirtd daemon. So I've refactored the way this works so that we simply pass a NULL uri into the individual driver open methods. If they see a NULL uri, they will make an attempt to open, and return a VIR_DRV_OPEN_DECLINED code if its not suitable. This also works for the remote driver, probing supported URI inside the daemon. Quite alot of code churn but the end result should be functionally the same Daniel diff -r d97fa69e255b proxy/libvirt_proxy.c --- a/proxy/libvirt_proxy.c Wed Nov 12 21:05:13 2008 +0000 +++ b/proxy/libvirt_proxy.c Wed Nov 12 21:59:20 2008 +0000 @@ -82,7 +82,7 @@ priv->xshandle = NULL; priv->proxy = -1; - ret = xenHypervisorOpen(conn, NULL, NULL, 0); + ret = xenHypervisorOpen(conn, NULL, 0); if (ret < 0) { fprintf(stderr, "Failed to open Xen hypervisor\n"); return(-1); @@ -98,7 +98,7 @@ fprintf(stderr, "Failed to connect to Xen daemon\n"); return(-1); } - ret = xenStoreOpen(conn, NULL, NULL, VIR_CONNECT_RO); + ret = xenStoreOpen(conn, NULL, VIR_CONNECT_RO); if (ret < 0) { fprintf(stderr, "Failed to open XenStore connection"); return (-1); diff -r d97fa69e255b qemud/remote.c --- a/qemud/remote.c Wed Nov 12 21:05:13 2008 +0000 +++ b/qemud/remote.c Wed Nov 12 21:59:20 2008 +0000 @@ -547,6 +547,23 @@ if (hostname == NULL) return -1; ret->hostname = hostname; + return 0; +} + +static int +remoteDispatchGetUri (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, + remote_message_header *req, + void *args ATTRIBUTE_UNUSED, + remote_get_uri_ret *ret) +{ + char *uri; + CHECK_CONN(client); + + uri = virConnectGetURI (client->conn); + if (uri == NULL) return -1; + + ret->uri = uri; return 0; } diff -r d97fa69e255b qemud/remote_dispatch_localvars.h --- a/qemud/remote_dispatch_localvars.h Wed Nov 12 21:05:13 2008 +0000 +++ b/qemud/remote_dispatch_localvars.h Wed Nov 12 21:59:20 2008 +0000 @@ -138,6 +138,7 @@ 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_get_uri_ret lv_remote_get_uri_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; diff -r d97fa69e255b qemud/remote_dispatch_proc_switch.h --- a/qemud/remote_dispatch_proc_switch.h Wed Nov 12 21:05:13 2008 +0000 +++ b/qemud/remote_dispatch_proc_switch.h Wed Nov 12 21:59:20 2008 +0000 @@ -388,6 +388,12 @@ ret_filter = (xdrproc_t) xdr_remote_get_type_ret; ret = (char *) &lv_remote_get_type_ret; memset (&lv_remote_get_type_ret, 0, sizeof lv_remote_get_type_ret); + break; +case REMOTE_PROC_GET_URI: + fn = (dispatch_fn) remoteDispatchGetUri; + ret_filter = (xdrproc_t) xdr_remote_get_uri_ret; + ret = (char *) &lv_remote_get_uri_ret; + memset (&lv_remote_get_uri_ret, 0, sizeof lv_remote_get_uri_ret); break; case REMOTE_PROC_GET_VERSION: fn = (dispatch_fn) remoteDispatchGetVersion; diff -r d97fa69e255b qemud/remote_dispatch_prototypes.h --- a/qemud/remote_dispatch_prototypes.h Wed Nov 12 21:05:13 2008 +0000 +++ b/qemud/remote_dispatch_prototypes.h Wed Nov 12 21:59:20 2008 +0000 @@ -55,6 +55,7 @@ static int remoteDispatchGetHostname (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_get_hostname_ret *ret); static int remoteDispatchGetMaxVcpus (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_get_max_vcpus_args *args, remote_get_max_vcpus_ret *ret); static int remoteDispatchGetType (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_get_type_ret *ret); +static int remoteDispatchGetUri (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_get_uri_ret *ret); static int remoteDispatchGetVersion (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_get_version_ret *ret); static int remoteDispatchListDefinedDomains (struct qemud_server *server, 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_server *server, struct qemud_client *client, remote_message_header *req, remote_list_defined_networks_args *args, remote_list_defined_networks_ret *ret); diff -r d97fa69e255b qemud/remote_protocol.c --- a/qemud/remote_protocol.c Wed Nov 12 21:05:13 2008 +0000 +++ b/qemud/remote_protocol.c Wed Nov 12 21:59:20 2008 +0000 @@ -271,6 +271,15 @@ { if (!xdr_remote_nonnull_string (xdrs, &objp->hostname)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_get_uri_ret (XDR *xdrs, remote_get_uri_ret *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->uri)) return FALSE; return TRUE; } diff -r d97fa69e255b qemud/remote_protocol.h --- a/qemud/remote_protocol.h Wed Nov 12 21:05:13 2008 +0000 +++ b/qemud/remote_protocol.h Wed Nov 12 21:59:20 2008 +0000 @@ -153,6 +153,11 @@ remote_nonnull_string hostname; }; typedef struct remote_get_hostname_ret remote_get_hostname_ret; + +struct remote_get_uri_ret { + remote_nonnull_string uri; +}; +typedef struct remote_get_uri_ret remote_get_uri_ret; struct remote_get_max_vcpus_args { remote_string type; @@ -1208,6 +1213,7 @@ REMOTE_PROC_DOMAIN_EVENTS_REGISTER = 105, REMOTE_PROC_DOMAIN_EVENTS_DEREGISTER = 106, REMOTE_PROC_DOMAIN_EVENT = 107, + REMOTE_PROC_GET_URI = 108, }; typedef enum remote_procedure remote_procedure; @@ -1260,6 +1266,7 @@ extern bool_t xdr_remote_get_type_ret (XDR *, remote_get_type_ret*); extern bool_t xdr_remote_get_version_ret (XDR *, remote_get_version_ret*); extern bool_t xdr_remote_get_hostname_ret (XDR *, remote_get_hostname_ret*); +extern bool_t xdr_remote_get_uri_ret (XDR *, remote_get_uri_ret*); extern bool_t xdr_remote_get_max_vcpus_args (XDR *, remote_get_max_vcpus_args*); extern bool_t xdr_remote_get_max_vcpus_ret (XDR *, remote_get_max_vcpus_ret*); extern bool_t xdr_remote_node_get_info_ret (XDR *, remote_node_get_info_ret*); @@ -1444,6 +1451,7 @@ extern bool_t xdr_remote_get_type_ret (); extern bool_t xdr_remote_get_version_ret (); extern bool_t xdr_remote_get_hostname_ret (); +extern bool_t xdr_remote_get_uri_ret (); extern bool_t xdr_remote_get_max_vcpus_args (); extern bool_t xdr_remote_get_max_vcpus_ret (); extern bool_t xdr_remote_node_get_info_ret (); diff -r d97fa69e255b qemud/remote_protocol.x --- a/qemud/remote_protocol.x Wed Nov 12 21:05:13 2008 +0000 +++ b/qemud/remote_protocol.x Wed Nov 12 21:59:20 2008 +0000 @@ -243,6 +243,10 @@ struct remote_get_hostname_ret { remote_nonnull_string hostname; +}; + +struct remote_get_uri_ret { + remote_nonnull_string uri; }; struct remote_get_max_vcpus_args { @@ -1103,13 +1107,12 @@ REMOTE_PROC_NODE_GET_CELLS_FREE_MEMORY = 101, REMOTE_PROC_NODE_GET_FREE_MEMORY = 102, - REMOTE_PROC_DOMAIN_BLOCK_PEEK = 103, REMOTE_PROC_DOMAIN_MEMORY_PEEK = 104, - REMOTE_PROC_DOMAIN_EVENTS_REGISTER = 105, REMOTE_PROC_DOMAIN_EVENTS_DEREGISTER = 106, - REMOTE_PROC_DOMAIN_EVENT = 107 + REMOTE_PROC_DOMAIN_EVENT = 107, + REMOTE_PROC_GET_URI = 108 }; /* Custom RPC structure. */ diff -r d97fa69e255b src/datatypes.c --- a/src/datatypes.c Wed Nov 12 21:05:13 2008 +0000 +++ b/src/datatypes.c Wed Nov 12 21:59:20 2008 +0000 @@ -174,7 +174,7 @@ */ static void virReleaseConnect(virConnectPtr conn) { - DEBUG("release connection %p %s", conn, conn->name); + DEBUG("release connection %p", conn); if (conn->domains != NULL) virHashFree(conn->domains, (virHashDeallocator) virDomainFreeName); if (conn->networks != NULL) @@ -188,7 +188,7 @@ if (virLastErr.conn == conn) virLastErr.conn = NULL; - VIR_FREE(conn->name); + xmlFreeURI(conn->uri); pthread_mutex_unlock(&conn->lock); pthread_mutex_destroy(&conn->lock); @@ -213,7 +213,7 @@ return(-1); } pthread_mutex_lock(&conn->lock); - DEBUG("unref connection %p %s %d", conn, conn->name, conn->refs); + DEBUG("unref connection %p %d", conn, conn->refs); conn->refs--; refs = conn->refs; if (refs == 0) { @@ -322,7 +322,7 @@ VIR_FREE(domain->name); VIR_FREE(domain); - DEBUG("unref connection %p %s %d", conn, conn->name, conn->refs); + DEBUG("unref connection %p %d", conn, conn->refs); conn->refs--; if (conn->refs == 0) { virReleaseConnect(conn); @@ -458,7 +458,7 @@ VIR_FREE(network->name); VIR_FREE(network); - DEBUG("unref connection %p %s %d", conn, conn->name, conn->refs); + DEBUG("unref connection %p %d", conn, conn->refs); conn->refs--; if (conn->refs == 0) { virReleaseConnect(conn); @@ -591,7 +591,7 @@ VIR_FREE(pool->name); VIR_FREE(pool); - DEBUG("unref connection %p %s %d", conn, conn->name, conn->refs); + DEBUG("unref connection %p %d", conn, conn->refs); conn->refs--; if (conn->refs == 0) { virReleaseConnect(conn); @@ -729,7 +729,7 @@ VIR_FREE(vol->pool); VIR_FREE(vol); - DEBUG("unref connection %p %s %d", conn, conn->name, conn->refs); + DEBUG("unref connection %p %d", conn, conn->refs); conn->refs--; if (conn->refs == 0) { virReleaseConnect(conn); diff -r d97fa69e255b src/datatypes.h --- a/src/datatypes.h Wed Nov 12 21:05:13 2008 +0000 +++ b/src/datatypes.h Wed Nov 12 21:59:20 2008 +0000 @@ -87,7 +87,7 @@ struct _virConnect { unsigned int magic; /* specific value to check */ int flags; /* a set of connection flags */ - char *name; /* connection URI */ + xmlURIPtr uri; /* connection URI */ /* The underlying hypervisor driver and network driver. */ virDriverPtr driver; diff -r d97fa69e255b src/driver.h --- a/src/driver.h Wed Nov 12 21:05:13 2008 +0000 +++ b/src/driver.h Wed Nov 12 21:59:20 2008 +0000 @@ -63,11 +63,8 @@ #define VIR_DRV_SUPPORTS_FEATURE(drv,conn,feature) \ ((drv)->supports_feature ? (drv)->supports_feature((conn),(feature)) : 0) -typedef const char * - (*virDrvProbe) (void); typedef virDrvOpenStatus (*virDrvOpen) (virConnectPtr conn, - xmlURIPtr uri, virConnectAuthPtr auth, int flags); typedef int @@ -302,7 +299,6 @@ int no; /* the number virDrvNo */ const char * name; /* the name of the driver */ unsigned long ver; /* the version of the backend */ - virDrvProbe probe; virDrvOpen open; virDrvClose close; virDrvDrvSupportsFeature supports_feature; diff -r d97fa69e255b src/libvirt.c --- a/src/libvirt.c Wed Nov 12 21:05:13 2008 +0000 +++ b/src/libvirt.c Wed Nov 12 21:59:20 2008 +0000 @@ -685,8 +685,11 @@ int flags) { int i, res; - virConnectPtr ret = NULL; - xmlURIPtr uri; + virConnectPtr ret; + + ret = virGetConnect(); + if (ret == NULL) + return NULL; /* * If no URI is passed, then check for an environment string if not @@ -699,74 +702,43 @@ DEBUG("Using LIBVIRT_DEFAULT_URI %s", defname); name = defname; } else { - const char *use = NULL; - const char *latest; - int probes = 0; - for (i = 0; i < virDriverTabCount; i++) { - if ((virDriverTab[i]->probe != NULL) && - ((latest = virDriverTab[i]->probe()) != NULL)) { - probes++; - - DEBUG("Probed %s", latest); - /* - * if running a xen kernel, give it priority over - * QEmu emulation - */ - if (STREQ(latest, "xen:///")) - use = latest; - else if (use == NULL) - use = latest; - } - } - if (use == NULL) { - name = "xen:///"; - DEBUG("Could not probe any hypervisor defaulting to %s", - name); - } else { - name = use; - DEBUG("Using %s as default URI, %d hypervisor found", - use, probes); - } - } - } - - /* Convert xen -> xen:/// for back compat */ - if (STRCASEEQ(name, "xen")) - name = "xen:///"; - - /* Convert xen:// -> xen:/// because xmlParseURI cannot parse the - * former. This allows URIs such as xen://localhost to work. - */ - if (STREQ (name, "xen://")) - name = "xen:///"; - - ret = virGetConnect(); - if (ret == NULL) - return NULL; - - uri = xmlParseURI (name); - if (!uri) { - virLibConnError (ret, VIR_ERR_INVALID_ARG, - _("could not parse connection URI")); - goto failed; - } - - DEBUG("name \"%s\" to URI components:\n" - " scheme %s\n" - " opaque %s\n" - " authority %s\n" - " server %s\n" - " user %s\n" - " port %d\n" - " path %s\n", - name, - uri->scheme, uri->opaque, uri->authority, uri->server, - uri->user, uri->port, uri->path); - - ret->name = strdup (name); - if (!ret->name) { - virLibConnError (ret, VIR_ERR_NO_MEMORY, _("allocating conn->name")); - goto failed; + name = NULL; + } + } + + if (name) { + /* Convert xen -> xen:/// for back compat */ + if (STRCASEEQ(name, "xen")) + name = "xen:///"; + + /* Convert xen:// -> xen:/// because xmlParseURI cannot parse the + * former. This allows URIs such as xen://localhost to work. + */ + if (STREQ (name, "xen://")) + name = "xen:///"; + + ret->uri = xmlParseURI (name); + if (!ret->uri) { + virLibConnError (ret, VIR_ERR_INVALID_ARG, + _("could not parse connection URI")); + goto failed; + } + + DEBUG("name \"%s\" to URI components:\n" + " scheme %s\n" + " opaque %s\n" + " authority %s\n" + " server %s\n" + " user %s\n" + " port %d\n" + " path %s\n", + name, + ret->uri->scheme, ret->uri->opaque, + ret->uri->authority, ret->uri->server, + ret->uri->user, ret->uri->port, + ret->uri->path); + } else { + DEBUG0("no name, allowing driver auto-select"); } /* Cleansing flags */ @@ -775,7 +747,7 @@ for (i = 0; i < virDriverTabCount; i++) { DEBUG("trying driver %d (%s) ...", i, virDriverTab[i]->name); - res = virDriverTab[i]->open (ret, uri, auth, flags); + res = virDriverTab[i]->open (ret, auth, flags); DEBUG("driver %d %s returned %s", i, virDriverTab[i]->name, res == VIR_DRV_OPEN_SUCCESS ? "SUCCESS" : @@ -795,7 +767,7 @@ } for (i = 0; i < virNetworkDriverTabCount; i++) { - res = virNetworkDriverTab[i]->open (ret, uri, auth, flags); + res = virNetworkDriverTab[i]->open (ret, auth, flags); DEBUG("network driver %d %s returned %s", i, virNetworkDriverTab[i]->name, res == VIR_DRV_OPEN_SUCCESS ? "SUCCESS" : @@ -816,7 +788,7 @@ /* Secondary driver for storage. Optional */ for (i = 0; i < virStorageDriverTabCount; i++) { - res = virStorageDriverTab[i]->open (ret, uri, auth, flags); + res = virStorageDriverTab[i]->open (ret, auth, flags); #ifdef ENABLE_DEBUG DEBUG("storage driver %d %s returned %s", i, virStorageDriverTab[i]->name, @@ -836,13 +808,10 @@ } } - xmlFreeURI (uri); - return ret; failed: if (ret->driver) ret->driver->close (ret); - if (uri) xmlFreeURI(uri); /* If no global error was set, copy any error set in the connection object we're about to dispose of */ @@ -1103,7 +1072,7 @@ if (conn->driver->getURI) return conn->driver->getURI (conn); - name = strdup (conn->name); + name = (char *)xmlSaveUri(conn->uri); if (!name) { virLibConnError (conn, VIR_ERR_NO_MEMORY, __FUNCTION__); return NULL; diff -r d97fa69e255b src/lxc_driver.c --- a/src/lxc_driver.c Wed Nov 12 21:05:13 2008 +0000 +++ b/src/lxc_driver.c Wed Nov 12 21:59:20 2008 +0000 @@ -55,36 +55,34 @@ /* Functions */ -static const char *lxcProbe(void) +static int lxcProbe(void) { - if (lxcContainerAvailable(0) < 0) - return NULL; + if (getuid() != 0 || + lxcContainerAvailable(0) < 0) + return 0; - return("lxc:///"); + return 1; } static virDrvOpenStatus lxcOpen(virConnectPtr conn, - xmlURIPtr uri, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) { - uid_t uid = getuid(); - - /* Check that the user is root */ - if (0 != uid) { + if (!lxcProbe()) goto declineConnection; - } if (lxc_driver == NULL) goto declineConnection; /* Verify uri was specified */ - if ((NULL == uri) || (NULL == uri->scheme)) { - goto declineConnection; - } - - /* Check that the uri scheme is lxc */ - if (STRNEQ(uri->scheme, "lxc")) { + if (conn->uri == NULL) { + conn->uri = xmlParseURI("lxc:///"); + if (!conn->uri) { + lxcError(conn, NULL, VIR_ERR_NO_MEMORY, NULL); + return VIR_DRV_OPEN_ERROR; + } + } else if (conn->uri->scheme == NULL || + STRNEQ(conn->uri->scheme, "lxc")) { goto declineConnection; } @@ -1226,7 +1224,6 @@ VIR_DRV_LXC, /* the number virDrvNo */ "LXC", /* the name of the driver */ LIBVIR_VERSION_NUMBER, /* the version of the backend */ - lxcProbe, /* probe */ lxcOpen, /* open */ lxcClose, /* close */ NULL, /* supports_feature */ diff -r d97fa69e255b src/network_driver.c --- a/src/network_driver.c Wed Nov 12 21:05:13 2008 +0000 +++ b/src/network_driver.c Wed Nov 12 21:59:20 2008 +0000 @@ -836,7 +836,6 @@ } static virDrvOpenStatus networkOpenNetwork(virConnectPtr conn, - xmlURIPtr uri ATTRIBUTE_UNUSED, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) { if (!driverState) diff -r d97fa69e255b src/openvz_driver.c --- a/src/openvz_driver.c Wed Nov 12 21:05:13 2008 +0000 +++ b/src/openvz_driver.c Wed Nov 12 21:59:20 2008 +0000 @@ -861,35 +861,33 @@ return 0; } -static const char *openvzProbe(void) +static int openvzProbe(void) { -#ifdef __linux__ - if ((geteuid() == 0) && (virFileExists("/proc/vz"))) - return("openvz:///system"); -#endif - return(NULL); + if (geteuid() == 0 && + virFileExists("/proc/vz")) + return 1; + + return 0; } static virDrvOpenStatus openvzOpen(virConnectPtr conn, - xmlURIPtr uri, - virConnectAuthPtr auth ATTRIBUTE_UNUSED, - int flags ATTRIBUTE_UNUSED) + virConnectAuthPtr auth ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED) { struct openvz_driver *driver; - /*Just check if the user is root. Nothing really to open for OpenVZ */ - if (geteuid()) { // OpenVZ tools can only be used by r00t + if (!openvzProbe()) return VIR_DRV_OPEN_DECLINED; - } else { - if (uri == NULL || - uri->scheme == NULL || - uri->path == NULL || - STRNEQ (uri->scheme, "openvz") || - STRNEQ (uri->path, "/system")) - return VIR_DRV_OPEN_DECLINED; - } - /* See if we are running an OpenVZ enabled kernel */ - if(access("/proc/vz/veinfo", F_OK) == -1 || - access("/proc/user_beancounters", F_OK) == -1) { + + if (conn->uri == NULL) { + conn->uri = xmlParseURI("openvz:///system"); + if (conn->uri == NULL) { + openvzError(conn, VIR_ERR_NO_DOMAIN, NULL); + return VIR_DRV_OPEN_ERROR; + } + } else if (conn->uri->scheme == NULL || + conn->uri->path == NULL || + STRNEQ (conn->uri->scheme, "openvz") || + STRNEQ (conn->uri->path, "/system")) { return VIR_DRV_OPEN_DECLINED; } @@ -1086,7 +1084,6 @@ VIR_DRV_OPENVZ, "OPENVZ", LIBVIR_VERSION_NUMBER, - openvzProbe, /* probe */ openvzOpen, /* open */ openvzClose, /* close */ NULL, /* supports_feature */ diff -r d97fa69e255b src/proxy_internal.c --- a/src/proxy_internal.c Wed Nov 12 21:05:13 2008 +0000 +++ b/src/proxy_internal.c Wed Nov 12 21:59:20 2008 +0000 @@ -36,7 +36,7 @@ static int debug = 0; static int xenProxyClose(virConnectPtr conn); -static int xenProxyOpen(virConnectPtr conn, xmlURIPtr uri, virConnectAuthPtr auth, int flags); +static int xenProxyOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags); static int xenProxyGetVersion(virConnectPtr conn, unsigned long *hvVer); static int xenProxyNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info); static char *xenProxyGetCapabilities(virConnectPtr conn); @@ -480,7 +480,6 @@ */ int xenProxyOpen(virConnectPtr conn, - xmlURIPtr uri ATTRIBUTE_UNUSED, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags) { diff -r d97fa69e255b src/qemu_driver.c --- a/src/qemu_driver.c Wed Nov 12 21:05:13 2008 +0000 +++ b/src/qemu_driver.c Wed Nov 12 21:59:20 2008 +0000 @@ -1150,22 +1150,17 @@ * Probe for the availability of the qemu driver, assume the * presence of QEmu emulation if the binaries are installed */ -static const char *qemudProbe(void) +static int qemudProbe(void) { if ((virFileExists("/usr/bin/qemu")) || (virFileExists("/usr/bin/qemu-kvm")) || - (virFileExists("/usr/bin/xenner"))) { - if (getuid() == 0) { - return("qemu:///system"); - } else { - return("qemu:///session"); - } - } - return(NULL); + (virFileExists("/usr/bin/xenner"))) + return 1; + + return 0; } static virDrvOpenStatus qemudOpen(virConnectPtr conn, - xmlURIPtr uri, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) { uid_t uid = getuid(); @@ -1173,18 +1168,28 @@ if (qemu_driver == NULL) goto decline; - if (uri == NULL || uri->scheme == NULL || uri->path == NULL) + if (!qemudProbe()) goto decline; - if (STRNEQ (uri->scheme, "qemu")) + if (conn->uri == NULL) { + conn->uri = xmlParseURI(uid ? "qemu:///session" : "qemu:///system"); + if (!conn->uri) { + qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY,NULL); + return VIR_DRV_OPEN_ERROR; + } + } else if (conn->uri->scheme == NULL || + conn->uri->path == NULL) + goto decline; + + if (STRNEQ (conn->uri->scheme, "qemu")) goto decline; if (uid != 0) { - if (STRNEQ (uri->path, "/session")) + if (STRNEQ (conn->uri->path, "/session")) goto decline; } else { /* root */ - if (STRNEQ (uri->path, "/system") && - STRNEQ (uri->path, "/session")) + if (STRNEQ (conn->uri->path, "/system") && + STRNEQ (conn->uri->path, "/session")) goto decline; } @@ -3358,7 +3363,6 @@ VIR_DRV_QEMU, "QEMU", LIBVIR_VERSION_NUMBER, - qemudProbe, /* probe */ qemudOpen, /* open */ qemudClose, /* close */ NULL, /* supports_feature */ diff -r d97fa69e255b src/remote_internal.c --- a/src/remote_internal.c Wed Nov 12 21:05:13 2008 +0000 +++ b/src/remote_internal.c Wed Nov 12 21:59:20 2008 +0000 @@ -273,46 +273,51 @@ VIR_DRV_OPEN_REMOTE_AUTOSTART = (1 << 3), }; +/* What transport? */ +enum { + trans_tls, + trans_unix, + trans_ssh, + trans_ext, + trans_tcp, +} transport; + + static int doRemoteOpen (virConnectPtr conn, struct private_data *priv, - xmlURIPtr uri, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags) { - if (!uri || !uri->scheme) - return VIR_DRV_OPEN_DECLINED; /* Decline - not a URL. */ - - char *transport_str = get_transport_from_scheme (uri->scheme); - - /* What transport? */ - enum { - trans_tls, - trans_unix, - trans_ssh, - trans_ext, - trans_tcp, - } transport; - - if (!transport_str || STRCASEEQ (transport_str, "tls")) - transport = trans_tls; - else if (STRCASEEQ (transport_str, "unix")) - transport = trans_unix; - else if (STRCASEEQ (transport_str, "ssh")) - transport = trans_ssh; - else if (STRCASEEQ (transport_str, "ext")) - transport = trans_ext; - else if (STRCASEEQ (transport_str, "tcp")) - transport = trans_tcp; - else { - error (conn, VIR_ERR_INVALID_ARG, - _("remote_open: transport in URL not recognised " - "(should be tls|unix|ssh|ext|tcp)")); - return VIR_DRV_OPEN_ERROR; - } - - if (!uri->server && !transport_str) { - if (flags & VIR_DRV_OPEN_REMOTE_UNIX) + char *transport_str = NULL; + + if (conn->uri) { + if (!conn->uri->scheme) + return VIR_DRV_OPEN_DECLINED; + + transport_str = get_transport_from_scheme (conn->uri->scheme); + + if (!transport_str || STRCASEEQ (transport_str, "tls")) + transport = trans_tls; + else if (STRCASEEQ (transport_str, "unix")) + transport = trans_unix; + else if (STRCASEEQ (transport_str, "ssh")) + transport = trans_ssh; + else if (STRCASEEQ (transport_str, "ext")) + transport = trans_ext; + else if (STRCASEEQ (transport_str, "tcp")) + transport = trans_tcp; + else { + error (conn, VIR_ERR_INVALID_ARG, + _("remote_open: transport in URL not recognised " + "(should be tls|unix|ssh|ext|tcp)")); + return VIR_DRV_OPEN_ERROR; + } + } + + if (!transport_str) { + if ((!conn->uri || !conn->uri->server) && + (flags & VIR_DRV_OPEN_REMOTE_UNIX)) transport = trans_unix; else return VIR_DRV_OPEN_DECLINED; /* Decline - not a remote URL. */ @@ -330,8 +335,8 @@ int retcode = VIR_DRV_OPEN_ERROR; /* Remote server defaults to "localhost" if not specified. */ - if (uri->port != 0) { - if (asprintf (&port, "%d", uri->port) == -1) goto out_of_memory; + if (conn->uri && conn->uri->port != 0) { + if (asprintf (&port, "%d", conn->uri->port) == -1) goto out_of_memory; } else if (transport == trans_tls) { port = strdup (LIBVIRTD_TLS_PORT); if (!port) goto out_of_memory; @@ -345,11 +350,12 @@ port = NULL; /* Port not used for unix, ext. */ - priv->hostname = strdup (uri->server ? uri->server : "localhost"); + priv->hostname = strdup (conn->uri && conn->uri->server ? + conn->uri->server : "localhost"); if (!priv->hostname) goto out_of_memory; - if (uri->user) { - username = strdup (uri->user); + if (conn->uri && conn->uri->user) { + username = strdup (conn->uri->user); if (!username) goto out_of_memory; } @@ -363,67 +369,93 @@ struct qparam *var; int i; char *query; + + if (conn->uri) { #ifdef HAVE_XMLURI_QUERY_RAW - query = uri->query_raw; + query = conn->uri->query_raw; #else - query = uri->query; -#endif - vars = qparam_query_parse (query); - if (vars == NULL) goto failed; - - for (i = 0; i < vars->n; i++) { - var = &vars->p[i]; - if (STRCASEEQ (var->name, "name")) { - name = strdup (var->value); - if (!name) goto out_of_memory; - var->ignore = 1; - } else if (STRCASEEQ (var->name, "command")) { - command = strdup (var->value); - if (!command) goto out_of_memory; - var->ignore = 1; - } else if (STRCASEEQ (var->name, "socket")) { - sockname = strdup (var->value); - if (!sockname) goto out_of_memory; - var->ignore = 1; - } else if (STRCASEEQ (var->name, "auth")) { - authtype = strdup (var->value); - if (!authtype) goto out_of_memory; - var->ignore = 1; - } else if (STRCASEEQ (var->name, "netcat")) { - netcat = strdup (var->value); - if (!netcat) goto out_of_memory; - var->ignore = 1; - } else if (STRCASEEQ (var->name, "no_verify")) { - no_verify = atoi (var->value); - var->ignore = 1; - } else if (STRCASEEQ (var->name, "no_tty")) { - no_tty = atoi (var->value); - var->ignore = 1; - } else if (STRCASEEQ (var->name, "debug")) { - if (var->value && - STRCASEEQ (var->value, "stdout")) - priv->debugLog = stdout; - else - priv->debugLog = stderr; - } else - DEBUG("passing through variable '%s' ('%s') to remote end", - var->name, var->value); - } - + query = conn->uri->query; +#endif + vars = qparam_query_parse (query); + if (vars == NULL) goto failed; + + for (i = 0; i < vars->n; i++) { + var = &vars->p[i]; + if (STRCASEEQ (var->name, "name")) { + name = strdup (var->value); + if (!name) goto out_of_memory; + var->ignore = 1; + } else if (STRCASEEQ (var->name, "command")) { + command = strdup (var->value); + if (!command) goto out_of_memory; + var->ignore = 1; + } else if (STRCASEEQ (var->name, "socket")) { + sockname = strdup (var->value); + if (!sockname) goto out_of_memory; + var->ignore = 1; + } else if (STRCASEEQ (var->name, "auth")) { + authtype = strdup (var->value); + if (!authtype) goto out_of_memory; + var->ignore = 1; + } else if (STRCASEEQ (var->name, "netcat")) { + netcat = strdup (var->value); + if (!netcat) goto out_of_memory; + var->ignore = 1; + } else if (STRCASEEQ (var->name, "no_verify")) { + no_verify = atoi (var->value); + var->ignore = 1; + } else if (STRCASEEQ (var->name, "no_tty")) { + no_tty = atoi (var->value); + var->ignore = 1; + } else if (STRCASEEQ (var->name, "debug")) { + if (var->value && + STRCASEEQ (var->value, "stdout")) + priv->debugLog = stdout; + else + priv->debugLog = stderr; + } else + DEBUG("passing through variable '%s' ('%s') to remote end", + var->name, var->value); + } + + /* Construct the original name. */ + if (!name) { + xmlURI tmpuri = { + .scheme = conn->uri->scheme, #ifdef HAVE_XMLURI_QUERY_RAW - xmlFree (uri->query_raw); + .query_raw = qparam_get_query (vars), #else - xmlFree (uri->query); -#endif - -#ifdef HAVE_XMLURI_QUERY_RAW - uri->query_raw = -#else - uri->query = -#endif - qparam_get_query (vars); - - free_qparam_set (vars); + .query = qparam_get_query (vars), +#endif + .path = conn->uri->path, + .fragment = conn->uri->fragment, + }; + + /* Evil, blank out transport scheme temporarily */ + if (transport_str) { + assert (transport_str[-1] == '+'); + transport_str[-1] = '\0'; + } + + name = (char *) xmlSaveUri (&tmpuri); + + /* Restore transport scheme */ + if (transport_str) + transport_str[-1] = '+'; + } + + free_qparam_set (vars); + } else { + /* Probe URI server side */ + name = strdup(""); + } + + if (!name) { + error(conn, VIR_ERR_NO_MEMORY, NULL); + goto failed; + } + + DEBUG("proceeding with name = %s", name); /* For ext transport, command is required. */ if (transport == trans_ext && !command) { @@ -431,28 +463,6 @@ _("remote_open: for 'ext' transport, command is required")); goto failed; } - - /* Construct the original name. */ - if (!name) { - /* Remove the transport (if any) from the scheme. */ - if (transport_str) { - assert (transport_str[-1] == '+'); - transport_str[-1] = '\0'; - } - /* Remove the username, server name and port number. */ - xmlFree (uri->user); - uri->user = 0; - - xmlFree (uri->server); - uri->server = 0; - - uri->port = 0; - - name = (char *) xmlSaveUri (uri); - } - - assert (name); - DEBUG("proceeding with name = %s", name); /* Connect to the remote service. */ switch (transport) { @@ -702,6 +712,38 @@ (xdrproc_t) xdr_void, (char *) NULL) == -1) goto failed; + /* Now try and find out what URI the daemon used */ + if (conn->uri == NULL) { + remote_get_uri_ret uriret; + int urierr; + + memset (&uriret, 0, sizeof uriret); + urierr = call (conn, priv, + REMOTE_CALL_IN_OPEN | REMOTE_CALL_QUIET_MISSING_RPC, + REMOTE_PROC_GET_URI, + (xdrproc_t) xdr_void, (char *) NULL, + (xdrproc_t) xdr_remote_get_uri_ret, (char *) &uriret); + if (urierr == -2) { + /* Should not really happen, since we only probe local libvirtd's, + & the library should always match the daemon. Only case is post + RPM upgrade where an old daemon instance is still running with + new client. Too bad. It is not worth the hassle to fix this */ + error (conn, VIR_ERR_INTERNAL_ERROR, _("unable to auto-detect URI")); + goto failed; + } + if (urierr == -1) { + goto failed; + } + + DEBUG("Auto-probed URI is %s", uriret.uri); + conn->uri = xmlParseURI(uriret.uri); + VIR_FREE(uriret.uri); + if (!conn->uri) { + error (conn, VIR_ERR_NO_MEMORY, NULL); + goto failed; + } + } + if(VIR_ALLOC(priv->callbackList)<0) { error(conn, VIR_ERR_INVALID_ARG, _("Error allocating callbacks list")); goto failed; @@ -788,7 +830,6 @@ static int remoteOpen (virConnectPtr conn, - xmlURIPtr uri, virConnectAuthPtr auth, int flags) { @@ -806,40 +847,54 @@ if (flags & VIR_CONNECT_RO) rflags |= VIR_DRV_OPEN_REMOTE_RO; -#if WITH_QEMU - if (uri && - uri->scheme && STREQ (uri->scheme, "qemu") && - (!uri->server || STREQ (uri->server, "")) && - uri->path) { - if (STREQ (uri->path, "/system")) { - rflags |= VIR_DRV_OPEN_REMOTE_UNIX; - } else if (STREQ (uri->path, "/session")) { - rflags |= VIR_DRV_OPEN_REMOTE_UNIX; - if (getuid() > 0) { - rflags |= VIR_DRV_OPEN_REMOTE_USER; - rflags |= VIR_DRV_OPEN_REMOTE_AUTOSTART; - } - } - } -#endif -#if WITH_XEN - if (uri && - uri->scheme && STREQ (uri->scheme, "xen") && - (!uri->server || STREQ (uri->server, "")) && - (!uri->path || STREQ(uri->path, "/"))) { + /* + * If no servername is given, and no +XXX + * transport is listed, then force to a + * local UNIX socket connection + */ + if (conn->uri && + !conn->uri->server && + !strchr(conn->uri->scheme, '+')) { + DEBUG0("Auto-remote UNIX socket"); rflags |= VIR_DRV_OPEN_REMOTE_UNIX; } -#endif -#if WITH_LXC - if (uri && - uri->scheme && STREQ (uri->scheme, "lxc")) { + + /* + * If no servername is given, and no +XXX + * transport is listed, or transport is unix, + * and path is /session, and uid is unprivileged + * then auto-spawn a daemon. + */ + if (conn->uri && + !conn->uri->server && + conn->uri->path && + ((strchr(conn->uri->scheme, '+') == 0)|| + (strstr(conn->uri->scheme, "+unix") != NULL)) && + STREQ(conn->uri->path, "/session") && + getuid() > 0) { + DEBUG0("Auto-spawn user daemon instance"); + rflags |= VIR_DRV_OPEN_REMOTE_USER; + rflags |= VIR_DRV_OPEN_REMOTE_AUTOSTART; + } + + /* + * If URI is NULL, then do a UNIX connection + * possibly auto-spawning unprivileged server + * and probe remote server for URI + */ + if (!conn->uri) { + DEBUG0("Auto-probe remote URI"); rflags |= VIR_DRV_OPEN_REMOTE_UNIX; - } -#endif + if (getuid() > 0) { + DEBUG0("Auto-spawn user daemon instance"); + rflags |= VIR_DRV_OPEN_REMOTE_USER; + rflags |= VIR_DRV_OPEN_REMOTE_AUTOSTART; + } + } priv->magic = DEAD; priv->sock = -1; - ret = doRemoteOpen(conn, priv, uri, auth, rflags); + ret = doRemoteOpen(conn, priv, auth, rflags); if (ret != VIR_DRV_OPEN_SUCCESS) { conn->privateData = NULL; VIR_FREE(priv); @@ -2486,7 +2541,6 @@ static int remoteNetworkOpen (virConnectPtr conn, - xmlURIPtr uri, virConnectAuthPtr auth, int flags) { @@ -2520,7 +2574,7 @@ priv->magic = DEAD; priv->sock = -1; - ret = doRemoteOpen(conn, priv, uri, auth, rflags); + ret = doRemoteOpen(conn, priv, auth, rflags); if (ret != VIR_DRV_OPEN_SUCCESS) { conn->networkPrivateData = NULL; VIR_FREE(priv); @@ -2887,7 +2941,6 @@ static int remoteStorageOpen (virConnectPtr conn, - xmlURIPtr uri, virConnectAuthPtr auth, int flags) { @@ -2926,7 +2979,7 @@ priv->magic = DEAD; priv->sock = -1; - ret = doRemoteOpen(conn, priv, uri, auth, rflags); + ret = doRemoteOpen(conn, priv, auth, rflags); if (ret != VIR_DRV_OPEN_SUCCESS) { conn->storagePrivateData = NULL; VIR_FREE(priv); @@ -4935,7 +4988,6 @@ .no = VIR_DRV_REMOTE, .name = "remote", .ver = REMOTE_PROTOCOL_VERSION, - .probe = NULL, .open = remoteOpen, .close = remoteClose, .supports_feature = remoteSupportsFeature, diff -r d97fa69e255b src/storage_driver.c --- a/src/storage_driver.c Wed Nov 12 21:05:13 2008 +0000 +++ b/src/storage_driver.c Wed Nov 12 21:59:20 2008 +0000 @@ -294,7 +294,6 @@ static virDrvOpenStatus storageOpen(virConnectPtr conn, - xmlURIPtr uri ATTRIBUTE_UNUSED, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) { if (!driverState) diff -r d97fa69e255b src/test.c --- a/src/test.c Wed Nov 12 21:05:13 2008 +0000 +++ b/src/test.c Wed Nov 12 21:59:20 2008 +0000 @@ -635,39 +635,38 @@ static int testOpen(virConnectPtr conn, - xmlURIPtr uri, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) { int ret; - if (!uri) + if (!conn->uri) return VIR_DRV_OPEN_DECLINED; - if (!uri->scheme || STRNEQ(uri->scheme, "test")) + if (!conn->uri->scheme || STRNEQ(conn->uri->scheme, "test")) return VIR_DRV_OPEN_DECLINED; /* Remote driver should handle these. */ - if (uri->server) + if (conn->uri->server) return VIR_DRV_OPEN_DECLINED; - if (uri->server) + if (conn->uri->server) return VIR_DRV_OPEN_DECLINED; /* From this point on, the connection is for us. */ - if (!uri->path - || uri->path[0] == '\0' - || (uri->path[0] == '/' && uri->path[1] == '\0')) { + if (!conn->uri->path + || conn->uri->path[0] == '\0' + || (conn->uri->path[0] == '/' && conn->uri->path[1] == '\0')) { testError (NULL, VIR_ERR_INVALID_ARG, "%s", _("testOpen: supply a path or use test:///default")); return VIR_DRV_OPEN_ERROR; } - if (STREQ(uri->path, "/default")) + if (STREQ(conn->uri->path, "/default")) ret = testOpenDefault(conn); else ret = testOpenFromFile(conn, - uri->path); + conn->uri->path); return (ret); } @@ -711,19 +710,6 @@ return NULL; } return str; -} - -static char * testGetURI (virConnectPtr conn) -{ - char *uri; - GET_CONNECTION(conn); - - if (asprintf (&uri, "test://%s", privconn->path) == -1) { - testError (conn, VIR_ERR_SYSTEM_ERROR, "%s", - strerror (errno)); - return NULL; - } - return uri; } static int testGetMaxVCPUs(virConnectPtr conn ATTRIBUTE_UNUSED, @@ -1398,7 +1384,6 @@ } static virDrvOpenStatus testOpenNetwork(virConnectPtr conn, - xmlURIPtr uri ATTRIBUTE_UNUSED, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) { if (STRNEQ(conn->driver->name, "Test")) @@ -1631,7 +1616,6 @@ } static virDrvOpenStatus testStorageOpen(virConnectPtr conn, - xmlURIPtr uri ATTRIBUTE_UNUSED, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) { if (STRNEQ(conn->driver->name, "Test")) @@ -2211,14 +2195,13 @@ VIR_DRV_TEST, "Test", LIBVIR_VERSION_NUMBER, - NULL, /* probe */ testOpen, /* open */ testClose, /* close */ NULL, /* supports_feature */ NULL, /* type */ testGetVersion, /* version */ testGetHostname, /* hostname */ - testGetURI, /* URI */ + NULL, /* URI */ testGetMaxVCPUs, /* getMaxVcpus */ testNodeGetInfo, /* nodeGetInfo */ testGetCapabilities, /* getCapabilities */ diff -r d97fa69e255b src/xen_internal.c --- a/src/xen_internal.c Wed Nov 12 21:05:13 2008 +0000 +++ b/src/xen_internal.c Wed Nov 12 21:59:20 2008 +0000 @@ -2033,7 +2033,6 @@ */ int xenHypervisorOpen(virConnectPtr conn, - xmlURIPtr uri ATTRIBUTE_UNUSED, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) { diff -r d97fa69e255b src/xen_internal.h --- a/src/xen_internal.h Wed Nov 12 21:05:13 2008 +0000 +++ b/src/xen_internal.h Wed Nov 12 21:59:20 2008 +0000 @@ -33,7 +33,6 @@ xenHypervisorDomainGetOSType (virDomainPtr dom); int xenHypervisorOpen (virConnectPtr conn, - xmlURIPtr uri, virConnectAuthPtr auth, int flags); int xenHypervisorClose (virConnectPtr conn); diff -r d97fa69e255b src/xen_unified.c --- a/src/xen_unified.c Wed Nov 12 21:05:13 2008 +0000 +++ b/src/xen_unified.c Wed Nov 12 21:59:20 2008 +0000 @@ -200,34 +200,45 @@ * in the low level drivers directly. */ -static const char * +static int xenUnifiedProbe (void) { #ifdef __linux__ if (virFileExists("/proc/xen")) - return("xen:///"); + return 1; #endif #ifdef __sun__ FILE *fh; if (fh = fopen("/dev/xen/domcaps", "r")) { fclose(fh); - return("xen:///"); + return 1; } #endif - return(NULL); + return 0; } static int -xenUnifiedOpen (virConnectPtr conn, xmlURIPtr uri, virConnectAuthPtr auth, int flags) +xenUnifiedOpen (virConnectPtr conn, virConnectAuthPtr auth, int flags) { int i, ret = VIR_DRV_OPEN_DECLINED; xenUnifiedPrivatePtr priv; + if (conn->uri == NULL) { + if (!xenUnifiedProbe()) + return VIR_DRV_OPEN_DECLINED; + + conn->uri = xmlParseURI("xen:///"); + if (!conn->uri) { + xenUnifiedError (NULL, VIR_ERR_NO_MEMORY, NULL); + return VIR_DRV_OPEN_ERROR; + } + } + /* Refuse any scheme which isn't "xen://" or "http://". */ - if (uri->scheme && - STRCASENEQ(uri->scheme, "xen") && - STRCASENEQ(uri->scheme, "http")) + if (conn->uri->scheme && + STRCASENEQ(conn->uri->scheme, "xen") && + STRCASENEQ(conn->uri->scheme, "http")) return VIR_DRV_OPEN_DECLINED; /* xmlParseURI will parse a naked string like "foo" as a URI with @@ -235,11 +246,11 @@ * allow full pathnames (eg. ///var/lib/xen/xend-socket). Decline * anything else. */ - if (!uri->scheme && (!uri->path || uri->path[0] != '/')) + if (!conn->uri->scheme && (!conn->uri->path || conn->uri->path[0] != '/')) return VIR_DRV_OPEN_DECLINED; /* Refuse any xen:// URI with a server specified - allow remote to do it */ - if (uri->scheme && STRCASEEQ(uri->scheme, "xen") && uri->server) + if (conn->uri->scheme && STRCASEEQ(conn->uri->scheme, "xen") && conn->uri->server) return VIR_DRV_OPEN_DECLINED; /* Allocate per-connection private data. */ @@ -261,7 +272,7 @@ /* Hypervisor is only run as root & required to succeed */ if (getuid() == 0) { DEBUG0("Trying hypervisor sub-driver"); - if (drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->open(conn, uri, auth, flags) == + if (drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->open(conn, auth, flags) == VIR_DRV_OPEN_SUCCESS) { DEBUG0("Activated hypervisor sub-driver"); priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET] = 1; @@ -272,7 +283,7 @@ * If it fails as non-root, then the proxy driver may take over */ DEBUG0("Trying XenD sub-driver"); - if (drivers[XEN_UNIFIED_XEND_OFFSET]->open(conn, uri, auth, flags) == + if (drivers[XEN_UNIFIED_XEND_OFFSET]->open(conn, auth, flags) == VIR_DRV_OPEN_SUCCESS) { DEBUG0("Activated XenD sub-driver"); priv->opened[XEN_UNIFIED_XEND_OFFSET] = 1; @@ -281,14 +292,14 @@ * succeed if root, optional otherwise */ if (priv->xendConfigVersion <= 2) { DEBUG0("Trying XM sub-driver"); - if (drivers[XEN_UNIFIED_XM_OFFSET]->open(conn, uri, auth, flags) == + if (drivers[XEN_UNIFIED_XM_OFFSET]->open(conn, auth, flags) == VIR_DRV_OPEN_SUCCESS) { DEBUG0("Activated XM sub-driver"); priv->opened[XEN_UNIFIED_XM_OFFSET] = 1; } } DEBUG0("Trying XS sub-driver"); - if (drivers[XEN_UNIFIED_XS_OFFSET]->open(conn, uri, auth, flags) == + if (drivers[XEN_UNIFIED_XS_OFFSET]->open(conn, auth, flags) == VIR_DRV_OPEN_SUCCESS) { DEBUG0("Activated XS sub-driver"); priv->opened[XEN_UNIFIED_XS_OFFSET] = 1; @@ -302,7 +313,7 @@ } else { #if WITH_PROXY DEBUG0("Trying proxy sub-driver"); - if (drivers[XEN_UNIFIED_PROXY_OFFSET]->open(conn, uri, auth, flags) == + if (drivers[XEN_UNIFIED_PROXY_OFFSET]->open(conn, auth, flags) == VIR_DRV_OPEN_SUCCESS) { DEBUG0("Activated proxy sub-driver"); priv->opened[XEN_UNIFIED_PROXY_OFFSET] = 1; @@ -1292,7 +1303,6 @@ .no = VIR_DRV_XEN_UNIFIED, .name = "Xen", .ver = HV_VERSION, - .probe = xenUnifiedProbe, .open = xenUnifiedOpen, .close = xenUnifiedClose, .supports_feature = xenUnifiedSupportsFeature, diff -r d97fa69e255b src/xend_internal.c --- a/src/xend_internal.c Wed Nov 12 21:05:13 2008 +0000 +++ b/src/xend_internal.c Wed Nov 12 21:59:20 2008 +0000 @@ -2706,7 +2706,6 @@ */ int xenDaemonOpen(virConnectPtr conn, - xmlURIPtr uri, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) { @@ -2715,13 +2714,13 @@ /* Switch on the scheme, which we expect to be NULL (file), * "http" or "xen". */ - if (uri->scheme == NULL) { + if (conn->uri->scheme == NULL) { /* It should be a file access */ - if (uri->path == NULL) { + if (conn->uri->path == NULL) { virXendError(NULL, VIR_ERR_NO_CONNECT, __FUNCTION__); goto failed; } - ret = xenDaemonOpen_unix(conn, uri->path); + ret = xenDaemonOpen_unix(conn, conn->uri->path); if (ret < 0) goto failed; @@ -2729,7 +2728,7 @@ if (ret == -1) goto failed; } - else if (STRCASEEQ (uri->scheme, "xen")) { + else if (STRCASEEQ (conn->uri->scheme, "xen")) { /* * try first to open the unix socket */ @@ -2750,8 +2749,8 @@ ret = xend_detect_config_version(conn); if (ret == -1) goto failed; - } else if (STRCASEEQ (uri->scheme, "http")) { - ret = xenDaemonOpen_tcp(conn, uri->server, uri->port); + } else if (STRCASEEQ (conn->uri->scheme, "http")) { + ret = xenDaemonOpen_tcp(conn, conn->uri->server, conn->uri->port); if (ret < 0) goto failed; ret = xend_detect_config_version(conn); diff -r d97fa69e255b src/xend_internal.h --- a/src/xend_internal.h Wed Nov 12 21:05:13 2008 +0000 +++ b/src/xend_internal.h Wed Nov 12 21:59:20 2008 +0000 @@ -129,7 +129,7 @@ /* refactored ones */ -int xenDaemonOpen(virConnectPtr conn, xmlURIPtr uri, virConnectAuthPtr auth, int flags); +int xenDaemonOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags); int xenDaemonClose(virConnectPtr conn); int xenDaemonGetVersion(virConnectPtr conn, unsigned long *hvVer); int xenDaemonNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info); diff -r d97fa69e255b src/xm_internal.c --- a/src/xm_internal.c Wed Nov 12 21:05:13 2008 +0000 +++ b/src/xm_internal.c Wed Nov 12 21:59:20 2008 +0000 @@ -529,7 +529,6 @@ */ int xenXMOpen (virConnectPtr conn ATTRIBUTE_UNUSED, - xmlURIPtr uri ATTRIBUTE_UNUSED, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) { diff -r d97fa69e255b src/xm_internal.h --- a/src/xm_internal.h Wed Nov 12 21:05:13 2008 +0000 +++ b/src/xm_internal.h Wed Nov 12 21:59:20 2008 +0000 @@ -32,7 +32,7 @@ extern struct xenUnifiedDriver xenXMDriver; int xenXMInit (void); -int xenXMOpen(virConnectPtr conn, xmlURIPtr uri, virConnectAuthPtr auth, int flags); +int xenXMOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags); int xenXMClose(virConnectPtr conn); const char *xenXMGetType(virConnectPtr conn); int xenXMDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info); diff -r d97fa69e255b src/xs_internal.c --- a/src/xs_internal.c Wed Nov 12 21:05:13 2008 +0000 +++ b/src/xs_internal.c Wed Nov 12 21:59:20 2008 +0000 @@ -276,7 +276,6 @@ */ int xenStoreOpen(virConnectPtr conn, - xmlURIPtr uri ATTRIBUTE_UNUSED, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) { diff -r d97fa69e255b src/xs_internal.h --- a/src/xs_internal.h Wed Nov 12 21:05:13 2008 +0000 +++ b/src/xs_internal.h Wed Nov 12 21:59:20 2008 +0000 @@ -17,7 +17,6 @@ int xenStoreInit (void); int xenStoreOpen (virConnectPtr conn, - xmlURIPtr uri, virConnectAuthPtr auth, int flags); int xenStoreClose (virConnectPtr conn); -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Thu, Nov 13, 2008 at 05:25:53PM +0000, Daniel P. Berrange wrote:
This patch changes the way hypervisor URIs are probed when NULL is passed to the virConnectOpen() method. Previously we had an explicit probe method called in each driver. This does not work when we move some drivers out of libvirt.so and into libvirtd daemon. So I've refactored the way this works so that we simply pass a NULL uri into the individual driver open methods. If they see a NULL uri, they will make an attempt to open, and return a VIR_DRV_OPEN_DECLINED code if its not suitable. This also works for the remote driver, probing supported URI inside the daemon. Quite alot of code churn but the end result should be functionally the same
Okay, makes sense, [...]
+++ b/src/datatypes.c Wed Nov 12 21:59:20 2008 +0000 @@ -174,7 +174,7 @@ */ static void virReleaseConnect(virConnectPtr conn) { - DEBUG("release connection %p %s", conn, conn->name); + DEBUG("release connection %p", conn);
maybe conn->name should have been kept to help with debug, each time conn->uri was set it should be easy to keep name too. not a blocker, just a suggestion...
if (conn->domains != NULL) virHashFree(conn->domains, (virHashDeallocator) virDomainFreeName); if (conn->networks != NULL) @@ -188,7 +188,7 @@ if (virLastErr.conn == conn) virLastErr.conn = NULL;
- VIR_FREE(conn->name); + xmlFreeURI(conn->uri);
pthread_mutex_unlock(&conn->lock); pthread_mutex_destroy(&conn->lock); @@ -213,7 +213,7 @@ return(-1); } pthread_mutex_lock(&conn->lock); - DEBUG("unref connection %p %s %d", conn, conn->name, conn->refs); + DEBUG("unref connection %p %d", conn, conn->refs); conn->refs--; refs = conn->refs; if (refs == 0) { @@ -322,7 +322,7 @@ VIR_FREE(domain->name); VIR_FREE(domain);
- DEBUG("unref connection %p %s %d", conn, conn->name, conn->refs); + DEBUG("unref connection %p %d", conn, conn->refs); conn->refs--; if (conn->refs == 0) { virReleaseConnect(conn); @@ -458,7 +458,7 @@ VIR_FREE(network->name); VIR_FREE(network);
- DEBUG("unref connection %p %s %d", conn, conn->name, conn->refs); + DEBUG("unref connection %p %d", conn, conn->refs); conn->refs--; if (conn->refs == 0) { virReleaseConnect(conn); @@ -591,7 +591,7 @@ VIR_FREE(pool->name); VIR_FREE(pool);
- DEBUG("unref connection %p %s %d", conn, conn->name, conn->refs); + DEBUG("unref connection %p %d", conn, conn->refs); conn->refs--; if (conn->refs == 0) { virReleaseConnect(conn); @@ -729,7 +729,7 @@ VIR_FREE(vol->pool); VIR_FREE(vol);
- DEBUG("unref connection %p %s %d", conn, conn->name, conn->refs); + DEBUG("unref connection %p %d", conn, conn->refs); conn->refs--; if (conn->refs == 0) { virReleaseConnect(conn); diff -r d97fa69e255b src/datatypes.h --- a/src/datatypes.h Wed Nov 12 21:05:13 2008 +0000 +++ b/src/datatypes.h Wed Nov 12 21:59:20 2008 +0000 @@ -87,7 +87,7 @@ struct _virConnect { unsigned int magic; /* specific value to check */ int flags; /* a set of connection flags */ - char *name; /* connection URI */ + xmlURIPtr uri; /* connection URI */
/* The underlying hypervisor driver and network driver. */ virDriverPtr driver; diff -r d97fa69e255b src/driver.h --- a/src/driver.h Wed Nov 12 21:05:13 2008 +0000 +++ b/src/driver.h Wed Nov 12 21:59:20 2008 +0000 @@ -63,11 +63,8 @@ #define VIR_DRV_SUPPORTS_FEATURE(drv,conn,feature) \ ((drv)->supports_feature ? (drv)->supports_feature((conn),(feature)) : 0)
-typedef const char * - (*virDrvProbe) (void); typedef virDrvOpenStatus (*virDrvOpen) (virConnectPtr conn, - xmlURIPtr uri, virConnectAuthPtr auth, int flags); typedef int @@ -302,7 +299,6 @@ int no; /* the number virDrvNo */ const char * name; /* the name of the driver */ unsigned long ver; /* the version of the backend */ - virDrvProbe probe; virDrvOpen open; virDrvClose close; virDrvDrvSupportsFeature supports_feature; diff -r d97fa69e255b src/libvirt.c --- a/src/libvirt.c Wed Nov 12 21:05:13 2008 +0000 +++ b/src/libvirt.c Wed Nov 12 21:59:20 2008 +0000 @@ -685,8 +685,11 @@ int flags) { int i, res; - virConnectPtr ret = NULL; - xmlURIPtr uri; + virConnectPtr ret; + + ret = virGetConnect(); + if (ret == NULL) + return NULL;
/* * If no URI is passed, then check for an environment string if not @@ -699,74 +702,43 @@ DEBUG("Using LIBVIRT_DEFAULT_URI %s", defname); name = defname; } else { - const char *use = NULL; - const char *latest; - int probes = 0; - for (i = 0; i < virDriverTabCount; i++) { - if ((virDriverTab[i]->probe != NULL) && - ((latest = virDriverTab[i]->probe()) != NULL)) { - probes++; - - DEBUG("Probed %s", latest); - /* - * if running a xen kernel, give it priority over - * QEmu emulation - */ - if (STREQ(latest, "xen:///")) - use = latest; - else if (use == NULL) - use = latest; - } - } - if (use == NULL) { - name = "xen:///"; - DEBUG("Could not probe any hypervisor defaulting to %s", - name); - } else { - name = use; - DEBUG("Using %s as default URI, %d hypervisor found", - use, probes); - } - } - } - - /* Convert xen -> xen:/// for back compat */ - if (STRCASEEQ(name, "xen")) - name = "xen:///"; - - /* Convert xen:// -> xen:/// because xmlParseURI cannot parse the - * former. This allows URIs such as xen://localhost to work. - */ - if (STREQ (name, "xen://")) - name = "xen:///"; - - ret = virGetConnect(); - if (ret == NULL) - return NULL; - - uri = xmlParseURI (name); - if (!uri) { - virLibConnError (ret, VIR_ERR_INVALID_ARG, - _("could not parse connection URI")); - goto failed; - } - - DEBUG("name \"%s\" to URI components:\n" - " scheme %s\n" - " opaque %s\n" - " authority %s\n" - " server %s\n" - " user %s\n" - " port %d\n" - " path %s\n", - name, - uri->scheme, uri->opaque, uri->authority, uri->server, - uri->user, uri->port, uri->path); - - ret->name = strdup (name); - if (!ret->name) { - virLibConnError (ret, VIR_ERR_NO_MEMORY, _("allocating conn->name")); - goto failed; + name = NULL; + } + } + + if (name) { + /* Convert xen -> xen:/// for back compat */ + if (STRCASEEQ(name, "xen")) + name = "xen:///"; + + /* Convert xen:// -> xen:/// because xmlParseURI cannot parse the + * former. This allows URIs such as xen://localhost to work. + */ + if (STREQ (name, "xen://")) + name = "xen:///"; + + ret->uri = xmlParseURI (name); + if (!ret->uri) { + virLibConnError (ret, VIR_ERR_INVALID_ARG, + _("could not parse connection URI")); + goto failed; + } + + DEBUG("name \"%s\" to URI components:\n" + " scheme %s\n" + " opaque %s\n" + " authority %s\n" + " server %s\n" + " user %s\n" + " port %d\n" + " path %s\n", + name, + ret->uri->scheme, ret->uri->opaque, + ret->uri->authority, ret->uri->server, + ret->uri->user, ret->uri->port, + ret->uri->path);
Hum... that could crash on some OSes, many of those strings might get NULL, actually opaque will be NULL if you have path. .... Okay, the remote extension and the auto-spawn of a user daemon for testing makes it a more complex than expected fix, but I don't see any simpler way. Only testing will tell us if something is missing compatibility wise, so let's push it and wait for feedback ! +1 Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Fri, Nov 14, 2008 at 11:26:49AM +0100, Daniel Veillard wrote:
On Thu, Nov 13, 2008 at 05:25:53PM +0000, Daniel P. Berrange wrote:
This patch changes the way hypervisor URIs are probed when NULL is passed to the virConnectOpen() method. Previously we had an explicit probe method called in each driver. This does not work when we move some drivers out of libvirt.so and into libvirtd daemon. So I've refactored the way this works so that we simply pass a NULL uri into the individual driver open methods. If they see a NULL uri, they will make an attempt to open, and return a VIR_DRV_OPEN_DECLINED code if its not suitable. This also works for the remote driver, probing supported URI inside the daemon. Quite alot of code churn but the end result should be functionally the same
Okay, makes sense,
[...]
+++ b/src/datatypes.c Wed Nov 12 21:59:20 2008 +0000 @@ -174,7 +174,7 @@ */ static void virReleaseConnect(virConnectPtr conn) { - DEBUG("release connection %p %s", conn, conn->name); + DEBUG("release connection %p", conn);
maybe conn->name should have been kept to help with debug, each time conn->uri was set it should be easy to keep name too. not a blocker, just a suggestion...
The reason I remove it, was because once we store the xmlUriPtr there was not actually any functional code which used the 'name' field. All the drivers' open methods will now potentially have to set 'uri', so I felt it easier to just remove 'name', and not have possibility of one driver forgetting to also change 'name' when changing the 'uri'.
+ if (name) { + /* Convert xen -> xen:/// for back compat */ + if (STRCASEEQ(name, "xen")) + name = "xen:///"; + + /* Convert xen:// -> xen:/// because xmlParseURI cannot parse the + * former. This allows URIs such as xen://localhost to work. + */ + if (STREQ (name, "xen://")) + name = "xen:///"; + + ret->uri = xmlParseURI (name); + if (!ret->uri) { + virLibConnError (ret, VIR_ERR_INVALID_ARG, + _("could not parse connection URI")); + goto failed; + } + + DEBUG("name \"%s\" to URI components:\n" + " scheme %s\n" + " opaque %s\n" + " authority %s\n" + " server %s\n" + " user %s\n" + " port %d\n" + " path %s\n", + name, + ret->uri->scheme, ret->uri->opaque, + ret->uri->authority, ret->uri->server, + ret->uri->user, ret->uri->port, + ret->uri->path);
Hum... that could crash on some OSes, many of those strings might get NULL, actually opaque will be NULL if you have path.
Hmm, doesn't printf just turn NULL into the string '(null)' ? We kind of rely on that not crashing, more or less everywhere in libvirt.c for the DEBUG macros. Some of these are false positives, but the vast majority have potential for the %s argument to be NULL, since they're accepting input directly from the public API. $ grep DEBUG src/libvirt.c | grep '%s' DEBUG ("registering %s as driver %d", DEBUG("libVir=%p, type=%s, typeVer=%p", libVer, type, typeVer); DEBUG("Using LIBVIRT_DEFAULT_URI %s", defname); DEBUG("Probed %s", latest); DEBUG("Could not probe any hypervisor defaulting to %s", DEBUG("Using %s as default URI, %d hypervisor found", DEBUG("name \"%s\" to URI components:\n" DEBUG("trying driver %d (%s) ...", DEBUG("driver %d %s returned %s", DEBUG("network driver %d %s returned %s", DEBUG("storage driver %d %s returned %s", DEBUG("name=%s", name); DEBUG("name=%s", name); DEBUG("name=%s, auth=%p, flags=%d", name, auth, flags); DEBUG("conn=%p, type=%s", conn, type); DEBUG("conn=%p, xmlDesc=%s, flags=%d", conn, xmlDesc, flags); DEBUG("conn=%p, uuid=%s", conn, uuid); DEBUG("conn=%p, uuidstr=%s", conn, uuidstr); DEBUG("conn=%p, name=%s", conn, name); DEBUG("domain=%p, to=%s", domain, to); DEBUG("conn=%p, from=%s", conn, from); DEBUG("domain=%p, to=%s, flags=%d", domain, to, flags); DEBUG("domain=%p, dconn=%p, flags=%lu, dname=%s, uri=%s, bandwidth=%lu", DEBUG("dconn=%p, cookie=%p, cookielen=%p, uri_in=%s, uri_out=%p, flags=%lu, dname=%s, bandwidth=%lu", dconn, cookie, cookielen, uri_in, uri_out, flags, dname, bandwidth); DEBUG("domain=%p, cookie=%p, cookielen=%d, uri=%s, flags=%lu, dname=%s, bandwidth=%lu", domain, cookie, cookielen, uri, flags, dname, bandwidth); DEBUG("dconn=%p, dname=%s, cookie=%p, cookielen=%d, uri=%s, flags=%lu", dconn, dname, cookie, cookielen, uri, flags); DEBUG("domain=%p, path=%s, stats=%p, size=%zi", dom, path, stats, size); DEBUG("domain=%p, path=%s, stats=%p, size=%zi", dom, path, stats, size); DEBUG("domain=%p, path=%s, offset=%lld, size=%zi, buffer=%p", DEBUG("conn=%p, xml=%s", conn, xml); DEBUG("domain=%p, xml=%s", domain, xml); DEBUG("domain=%p, xml=%s", domain, xml); DEBUG("conn=%p, name=%s", conn, name); DEBUG("conn=%p, uuid=%s", conn, uuid); DEBUG("conn=%p, uuidstr=%s", conn, uuidstr); DEBUG("conn=%p, xmlDesc=%s", conn, xmlDesc); DEBUG("conn=%p, xml=%s", conn, xml); DEBUG("conn=%p, name=%s", conn, name); DEBUG("conn=%p, uuid=%s", conn, uuid); DEBUG("conn=%p, uuidstr=%s", conn, uuidstr); DEBUG("conn=%p, xmlDesc=%s", conn, xmlDesc); DEBUG("conn=%p, xml=%s", conn, xml); DEBUG("pool=%p, name=%s", pool, name); DEBUG("conn=%p, key=%s", conn, key); DEBUG("conn=%p, path=%s", conn, path);
Okay, the remote extension and the auto-spawn of a user daemon for testing makes it a more complex than expected fix, but I don't see any simpler way. Only testing will tell us if something is missing compatibility wise, so let's push it and wait for feedback !
The auto-spawn & daemon stuff is the bit I tested most carefully in this patch, so hopefully no bad surprises there... Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Fri, Nov 14, 2008 at 11:35:16AM +0000, Daniel P. Berrange wrote:
On Fri, Nov 14, 2008 at 11:26:49AM +0100, Daniel Veillard wrote:
On Thu, Nov 13, 2008 at 05:25:53PM +0000, Daniel P. Berrange wrote:
This patch changes the way hypervisor URIs are probed when NULL is passed to the virConnectOpen() method. Previously we had an explicit probe method called in each driver. This does not work when we move some drivers out of libvirt.so and into libvirtd daemon. So I've refactored the way this works so that we simply pass a NULL uri into the individual driver open methods. If they see a NULL uri, they will make an attempt to open, and return a VIR_DRV_OPEN_DECLINED code if its not suitable. This also works for the remote driver, probing supported URI inside the daemon. Quite alot of code churn but the end result should be functionally the same
Okay, makes sense,
[...]
+++ b/src/datatypes.c Wed Nov 12 21:59:20 2008 +0000 @@ -174,7 +174,7 @@ */ static void virReleaseConnect(virConnectPtr conn) { - DEBUG("release connection %p %s", conn, conn->name); + DEBUG("release connection %p", conn);
maybe conn->name should have been kept to help with debug, each time conn->uri was set it should be easy to keep name too. not a blocker, just a suggestion...
The reason I remove it, was because once we store the xmlUriPtr there was not actually any functional code which used the 'name' field. All the drivers' open methods will now potentially have to set 'uri', so I felt it easier to just remove 'name', and not have possibility of one driver forgetting to also change 'name' when changing the 'uri'.
okay
+ if (name) { + /* Convert xen -> xen:/// for back compat */ + if (STRCASEEQ(name, "xen")) + name = "xen:///"; + + /* Convert xen:// -> xen:/// because xmlParseURI cannot parse the + * former. This allows URIs such as xen://localhost to work. + */ + if (STREQ (name, "xen://")) + name = "xen:///"; + + ret->uri = xmlParseURI (name); + if (!ret->uri) { + virLibConnError (ret, VIR_ERR_INVALID_ARG, + _("could not parse connection URI")); + goto failed; + } + + DEBUG("name \"%s\" to URI components:\n" + " scheme %s\n" + " opaque %s\n" + " authority %s\n" + " server %s\n" + " user %s\n" + " port %d\n" + " path %s\n", + name, + ret->uri->scheme, ret->uri->opaque, + ret->uri->authority, ret->uri->server, + ret->uri->user, ret->uri->port, + ret->uri->path);
Hum... that could crash on some OSes, many of those strings might get NULL, actually opaque will be NULL if you have path.
Hmm, doesn't printf just turn NULL into the string '(null)' ? We kind
Linux one yes, others no :-)
of rely on that not crashing, more or less everywhere in libvirt.c for the DEBUG macros. Some of these are false positives, but the vast majority have potential for the %s argument to be NULL, since they're accepting input directly from the public API.
$ grep DEBUG src/libvirt.c | grep '%s' DEBUG ("registering %s as driver %d", DEBUG("libVir=%p, type=%s, typeVer=%p", libVer, type, typeVer); DEBUG("Using LIBVIRT_DEFAULT_URI %s", defname); DEBUG("Probed %s", latest); DEBUG("Could not probe any hypervisor defaulting to %s", DEBUG("Using %s as default URI, %d hypervisor found", DEBUG("name \"%s\" to URI components:\n" DEBUG("trying driver %d (%s) ...", DEBUG("driver %d %s returned %s", DEBUG("network driver %d %s returned %s", DEBUG("storage driver %d %s returned %s", DEBUG("name=%s", name); DEBUG("name=%s", name); DEBUG("name=%s, auth=%p, flags=%d", name, auth, flags); DEBUG("conn=%p, type=%s", conn, type); DEBUG("conn=%p, xmlDesc=%s, flags=%d", conn, xmlDesc, flags); DEBUG("conn=%p, uuid=%s", conn, uuid); DEBUG("conn=%p, uuidstr=%s", conn, uuidstr); DEBUG("conn=%p, name=%s", conn, name); DEBUG("domain=%p, to=%s", domain, to); DEBUG("conn=%p, from=%s", conn, from); DEBUG("domain=%p, to=%s, flags=%d", domain, to, flags); DEBUG("domain=%p, dconn=%p, flags=%lu, dname=%s, uri=%s, bandwidth=%lu", DEBUG("dconn=%p, cookie=%p, cookielen=%p, uri_in=%s, uri_out=%p, flags=%lu, dname=%s, bandwidth=%lu", dconn, cookie, cookielen, uri_in, uri_out, flags, dname, bandwidth); DEBUG("domain=%p, cookie=%p, cookielen=%d, uri=%s, flags=%lu, dname=%s, bandwidth=%lu", domain, cookie, cookielen, uri, flags, dname, bandwidth); DEBUG("dconn=%p, dname=%s, cookie=%p, cookielen=%d, uri=%s, flags=%lu", dconn, dname, cookie, cookielen, uri, flags); DEBUG("domain=%p, path=%s, stats=%p, size=%zi", dom, path, stats, size); DEBUG("domain=%p, path=%s, stats=%p, size=%zi", dom, path, stats, size); DEBUG("domain=%p, path=%s, offset=%lld, size=%zi, buffer=%p", DEBUG("conn=%p, xml=%s", conn, xml); DEBUG("domain=%p, xml=%s", domain, xml); DEBUG("domain=%p, xml=%s", domain, xml); DEBUG("conn=%p, name=%s", conn, name); DEBUG("conn=%p, uuid=%s", conn, uuid); DEBUG("conn=%p, uuidstr=%s", conn, uuidstr); DEBUG("conn=%p, xmlDesc=%s", conn, xmlDesc); DEBUG("conn=%p, xml=%s", conn, xml); DEBUG("conn=%p, name=%s", conn, name); DEBUG("conn=%p, uuid=%s", conn, uuid); DEBUG("conn=%p, uuidstr=%s", conn, uuidstr); DEBUG("conn=%p, xmlDesc=%s", conn, xmlDesc); DEBUG("conn=%p, xml=%s", conn, xml); DEBUG("pool=%p, name=%s", pool, name); DEBUG("conn=%p, key=%s", conn, key); DEBUG("conn=%p, path=%s", conn, path);
Let's keep as-is that can be handled separately
Okay, the remote extension and the auto-spawn of a user daemon for testing makes it a more complex than expected fix, but I don't see any simpler way. Only testing will tell us if something is missing compatibility wise, so let's push it and wait for feedback !
The auto-spawn & daemon stuff is the bit I tested most carefully in this patch, so hopefully no bad surprises there...
Okidoc :-) Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

This patch changes the module biuld so that stateful drivers like QEMU and LXC are directly linked into the libvirtd daemon, and not part of the libvirt.so file. It also does this for network and storage drivers. We need to export a few more symbols for this to work, and libvirtd has to explicitly initialize these drivers. Thanks to the previous patch changing the probe method, automatic driver probing still works. Daniel diff -r c21e0cdc2637 qemud/Makefile.am --- a/qemud/Makefile.am Fri Nov 07 12:51:10 2008 +0000 +++ b/qemud/Makefile.am Fri Nov 07 12:51:13 2008 +0000 @@ -88,7 +88,25 @@ $(POLKIT_LIBS) libvirtd_DEPENDENCIES = ../src/libvirt.la -libvirtd_LDADD = ../src/libvirt.la ../gnulib/lib/libgnu.la +libvirtd_LDADD = \ + ../gnulib/lib/libgnu.la \ + ../src/libvirt.la + +if WITH_QEMU +libvirtd_LDADD += ../src/libvirt_driver_qemu.la +endif + +if WITH_LXC +libvirtd_LDADD += ../src/libvirt_driver_lxc.la +endif + +if WITH_STORAGE_DIR +libvirtd_LDADD += ../src/libvirt_driver_storage.la +endif + +if WITH_NETWORK +libvirtd_LDADD += ../src/libvirt_driver_network.la +endif if HAVE_POLKIT policydir = $(datadir)/PolicyKit/policy diff -r c21e0cdc2637 qemud/qemud.c --- a/qemud/qemud.c Fri Nov 07 12:51:10 2008 +0000 +++ b/qemud/qemud.c Fri Nov 07 12:51:13 2008 +0000 @@ -60,6 +60,20 @@ #ifdef HAVE_AVAHI #include "mdns.h" #endif + +#ifdef WITH_QEMU +#include "qemu_driver.h" +#endif +#ifdef WITH_LXC +#include "lxc_driver.h" +#endif +#ifdef WITH_NETWORK +#include "network_driver.h" +#endif +#ifdef WITH_STORAGE_DIR +#include "storage_driver.h" +#endif + static int godaemon = 0; /* -d: Be a daemon */ static int verbose = 0; /* -v: Verbose mode */ @@ -727,6 +741,21 @@ } server->sigread = sigread; + + virInitialize(); + +#ifdef WITH_QEMU + qemudRegister(); +#endif +#ifdef WITH_LXC + lxcRegister(); +#endif +#ifdef WITH_NETWORK + networkRegister(); +#endif +#ifdef WITH_STORAGE_DIR + storageRegister(); +#endif virEventRegisterImpl(virEventAddHandleImpl, virEventUpdateHandleImpl, diff -r c21e0cdc2637 src/Makefile.am --- a/src/Makefile.am Fri Nov 07 12:51:10 2008 +0000 +++ b/src/Makefile.am Fri Nov 07 12:51:13 2008 +0000 @@ -196,7 +196,8 @@ if WITH_QEMU noinst_LTLIBRARIES += libvirt_driver_qemu.la -libvirt_la_LIBADD += libvirt_driver_qemu.la +# Stateful, so linked to daemon instead +#libvirt_la_LIBADD += libvirt_driver_qemu.la libvirt_driver_qemu_la_CFLAGS = $(NUMACTL_CFLAGS) libvirt_driver_qemu_la_LDFLAGS = $(NUMACTL_LIBS) libvirt_driver_qemu_la_SOURCES = $(QEMU_DRIVER_SOURCES) @@ -204,14 +205,16 @@ if WITH_LXC noinst_LTLIBRARIES += libvirt_driver_lxc.la -libvirt_la_LIBADD += libvirt_driver_lxc.la +# Stateful, so linked to daemon instead +#libvirt_la_LIBADD += libvirt_driver_lxc.la libvirt_driver_lxc_la_SOURCES = $(LXC_DRIVER_SOURCES) endif if WITH_NETWORK noinst_LTLIBRARIES += libvirt_driver_network.la -libvirt_la_LIBADD += libvirt_driver_network.la +# Stateful, so linked to daemon instead +#libvirt_la_LIBADD += libvirt_driver_network.la libvirt_driver_network_la_SOURCES = $(NETWORK_DRIVER_SOURCES) endif @@ -219,7 +222,8 @@ libvirt_driver_storage_la_SOURCES = if WITH_STORAGE_DIR noinst_LTLIBRARIES += libvirt_driver_storage.la -libvirt_la_LIBADD += libvirt_driver_storage.la +# Stateful, so linked to daemon instead +#libvirt_la_LIBADD += libvirt_driver_storage.la libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_SOURCES) libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_FS_SOURCES) endif @@ -261,6 +265,7 @@ $(COVERAGE_CFLAGS:-f%=-Wc,-f%) \ @CYGWIN_EXTRA_LDFLAGS@ @MINGW_EXTRA_LDFLAGS@ libvirt_la_CFLAGS = $(COVERAGE_CFLAGS) -DIN_LIBVIRT +libvirt_la_DEPENDENCIES = $(libvirt_la_LIBADD) $(srcdir)/libvirt_sym.version # Create an automake "convenience library" version of libvirt_la, # just for testing, since the test harness requires access to internal diff -r c21e0cdc2637 src/libvirt.c --- a/src/libvirt.c Fri Nov 07 12:51:10 2008 +0000 +++ b/src/libvirt.c Fri Nov 07 12:51:13 2008 +0000 @@ -50,18 +50,8 @@ #ifdef WITH_REMOTE #include "remote_internal.h" #endif -#ifdef WITH_QEMU -#include "qemu_driver.h" -#endif #ifdef WITH_OPENVZ #include "openvz_driver.h" -#endif -#ifdef WITH_LXC -#include "lxc_driver.h" -#endif -#include "storage_driver.h" -#ifdef WITH_NETWORK -#include "network_driver.h" #endif /* @@ -286,20 +276,8 @@ #ifdef WITH_XEN if (xenUnifiedRegister () == -1) return -1; #endif -#ifdef WITH_QEMU - if (qemudRegister() == -1) return -1; -#endif #ifdef WITH_OPENVZ if (openvzRegister() == -1) return -1; -#endif -#ifdef WITH_LXC - if (lxcRegister() == -1) return -1; -#endif -#ifdef WITH_NETWORK - if (networkRegister() == -1) return -1; -#endif -#ifdef WITH_STORAGE_DIR - if (storageRegister() == -1) return -1; #endif #ifdef WITH_REMOTE if (remoteRegister () == -1) return -1; diff -r c21e0cdc2637 src/libvirt_sym.version.in --- a/src/libvirt_sym.version.in Fri Nov 07 12:51:10 2008 +0000 +++ b/src/libvirt_sym.version.in Fri Nov 07 12:51:13 2008 +0000 @@ -257,6 +257,19 @@ LIBVIRT_PRIVATE_@VERSION@ { global: + /* bridge.h */ + brAddBridge; + brAddInterface; + brAddTap; + brDeleteBridge; + brInit; + brSetEnableSTP; + brSetForwardDelay; + brSetInetAddress; + brSetInetNetmask; + brSetInterfaceUp; + brShutdown; + /* buf.h */ virBufferVSprintf; @@ -264,6 +277,18 @@ virBufferAddChar; virBufferContentAndReset; virBufferError; + + + /* caps.h */ + virCapabilitiesAddGuest; + virCapabilitiesAddGuestDomain; + virCapabilitiesAddGuestFeature; + virCapabilitiesAddHostNUMACell; + virCapabilitiesDefaultGuestEmulator; + virCapabilitiesFormatXML; + virCapabilitiesFree; + virCapabilitiesNew; + virCapabilitiesSetMacPrefix; /* conf.h */ @@ -284,7 +309,62 @@ virGetStorageVol; + /* domain_conf.h */ + virDiskNameToBusDeviceIndex; + virDiskNameToIndex; + virDomainAssignDef; + virDomainConfigFile; + virDomainDefDefaultEmulator; + virDomainDefFormat; + virDomainDefFree; + virDomainDefParseFile; + virDomainDefParseString; + virDomainDeleteConfig; + virDomainDeviceDefParse; + virDomainDiskBusTypeToString; + virDomainDiskDeviceTypeToString; + virDomainDiskQSort; + virDomainEventCallbackListAdd; + virDomainEventCallbackListFree; + virDomainEventCallbackListRemove; + virDomainFindByID; + virDomainFindByName; + virDomainFindByUUID; + virDomainLoadAllConfigs; + virDomainObjListFree; + virDomainRemoveInactive; + virDomainSaveConfig; + virDomainSoundModelTypeToString; + virDomainVirtTypeToString; + + + /* iptables.h */ + iptablesAddForwardAllowCross; + iptablesAddForwardAllowIn; + iptablesAddForwardAllowOut; + iptablesAddForwardAllowRelatedIn; + iptablesAddForwardMasquerade; + iptablesAddForwardRejectIn; + iptablesAddForwardRejectOut; + iptablesAddTcpInput; + iptablesAddUdpInput; + iptablesContextFree; + iptablesContextNew; + iptablesReloadRules; + iptablesRemoveForwardAllowCross; + iptablesRemoveForwardAllowIn; + iptablesRemoveForwardAllowOut; + iptablesRemoveForwardAllowRelatedIn; + iptablesRemoveForwardMasquerade; + iptablesRemoveForwardRejectIn; + iptablesRemoveForwardRejectOut; + iptablesRemoveTcpInput; + iptablesRemoveUdpInput; + iptablesSaveRules; + + /* libvirt_internal.h */ + debugFlag; virStateInitialize; virStateCleanup; virStateReload; @@ -294,6 +374,10 @@ virDomainMigratePrepare; virDomainMigratePerform; virDomainMigrateFinish; + virRegisterDriver; + virRegisterNetworkDriver; + virRegisterStateDriver; + virRegisterStorageDriver; /* memory.h */ @@ -303,13 +387,97 @@ virFree; + /* network_conf.h */ + virNetworkAssignDef; + virNetworkDefFormat; + virNetworkDefFree; + virNetworkDefParseString; + virNetworkDeleteConfig; + virNetworkFindByName; + virNetworkFindByUUID; + virNetworkLoadAllConfigs; + virNetworkObjListFree; + virNetworkRemoveInactive; + virNetworkSaveConfig; + + + /* nodeinfo.h */ + virNodeInfoPopulate; + + + /* stats_linux.h */ + linuxDomainInterfaceStats; + + + /* storage_backend.h */ + virStorageBackendForType; + virStorageBackendFromString; + virStorageBackendPartTableTypeFromString; + virStorageBackendPartTableTypeToString; + virStorageBackendRegister; + virStorageBackendRunProgNul; + virStorageBackendRunProgRegex; + virStorageBackendStablePath; + virStorageBackendUpdateVolInfo; + virStorageBackendUpdateVolInfoFD; + + + /* storage_conf.h */ + virStoragePoolDefFormat; + virStoragePoolDefFree; + virStoragePoolDefParse; + virStoragePoolLoadAllConfigs; + virStoragePoolObjAssignDef; + virStoragePoolObjClearVols; + virStoragePoolObjDeleteDef; + virStoragePoolObjFindByName; + virStoragePoolObjFindByUUID; + virStoragePoolObjListFree; + virStoragePoolObjRemove; + virStoragePoolObjSaveDef; + virStoragePoolSourceFree; + virStoragePoolSourceListFormat; + virStorageVolDefFindByKey; + virStorageVolDefFindByName; + virStorageVolDefFindByPath; + virStorageVolDefFormat; + virStorageVolDefFree; + virStorageVolDefParse; + + /* util.h */ virFileReadAll; virStrToLong_i; + virStrToLong_ll; virStrToLong_ull; saferead; safewrite; virMacAddrCompare; + virEnumFromString; + virEnumToString; + virEventAddHandle; + virEventRemoveHandle; + virExec; + virFileDeletePid; + virFileExists; + virFileHasSuffix; + virFileMakePath; + virFileOpenTty; + virFileReadLimFD; + virFileReadPid; + virRun; + + + /* uuid.h */ + virUUIDFormat; + + + /* virterror_internal.h */ + virReportErrorHelper; + + + /* xml.h */ + virXPathString; /* Finally everything else is totally private */ diff -r c21e0cdc2637 tests/Makefile.am --- a/tests/Makefile.am Fri Nov 07 12:51:10 2008 +0000 +++ b/tests/Makefile.am Fri Nov 07 12:51:13 2008 +0000 @@ -108,12 +108,12 @@ qemuxml2argvtest_SOURCES = \ qemuxml2argvtest.c testutilsqemu.c testutilsqemu.h \ testutils.c testutils.h -qemuxml2argvtest_LDADD = $(LDADDS) +qemuxml2argvtest_LDADD = ../src/libvirt_driver_qemu.la $(LDADDS) qemuxml2xmltest_SOURCES = \ qemuxml2xmltest.c testutilsqemu.c testutilsqemu.h \ testutils.c testutils.h -qemuxml2xmltest_LDADD = $(LDADDS) +qemuxml2xmltest_LDADD = ../src/libvirt_driver_qemu.la $(LDADDS) virshtest_SOURCES = \ virshtest.c \ -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Thu, Nov 13, 2008 at 05:27:48PM +0000, Daniel P. Berrange wrote:
This patch changes the module biuld so that stateful drivers like QEMU and LXC are directly linked into the libvirtd daemon, and not part of the libvirt.so file. It also does this for network and storage drivers. We need to export a few more symbols for this to work, and libvirtd has to explicitly initialize these drivers. Thanks to the previous patch changing the probe method, automatic driver probing still works.
Okay, the whole point of the exercise ! +1 at some point libvirt package might be splitted between a libvirt and libvirt-daemon to reflect the dichotomy, but there is no hurry ! Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

This patch is a small incremental change to optionally allow us to build every driver as a dlopen()able module. This is disabled by default for now. I'm not sure whether this is hugely usefl or not, but it was easy enough to do, so here's the patch. Daniel diff -r ecc8ae6295bc configure.in --- a/configure.in Wed Nov 12 21:59:22 2008 +0000 +++ b/configure.in Thu Nov 13 17:13:02 2008 +0000 @@ -1059,6 +1059,38 @@ AC_CHECK_TOOL([WINDRES], [windres], [no]) AM_CONDITIONAL([WITH_WIN_ICON], [test "$WINDRES" != "no"]) + + +dnl Driver-Modules library +AC_ARG_WITH([driver-modules], + [ --with-driver-modules build drivers as loadable modules], + [], + [with_driver_modules=no]) + +DRIVER_MODULES_CFLAGS= +DRIVER_MODULES_LIBS= +if test "x$with_driver_modules" = "xyes" ; then + old_cflags="$CFLAGS" + old_libs="$LIBS" + fail=0 + AC_CHECK_HEADER([dlfcn.h],[],[fail=1]) + AC_CHECK_LIB([dl], [dlopen],[],[fail=1]) + test $fail = 1 && + AC_MSG_ERROR([You must have dlfcn.h / dlopen() support to build driver modules]) + + CFLAGS="$old_cflags" + LIBS="$old_libs" +fi +if test "$with_driver_modules" = "yes"; then + DRIVER_MODULES_CFLAGS="-export-dynamic" + DRIVER_MODULES_LIBS="-ldl" + AC_DEFINE_UNQUOTED([WITH_DRIVER_MODULES], 1, [whether to build drivers as modules]) +fi +AM_CONDITIONAL([WITH_DRIVER_MODULES], [test "$with_driver_modules" != "no"]) +AC_SUBST([DRIVER_MODULES_CFLAGS]) +AC_SUBST([DRIVER_MODULES_LIBS]) + + # Set LV_LIBTOOL_OBJDIR to "." or $lt_cv_objdir, depending on whether # we're building shared libraries. This is the name of the directory # in which .o files will be created. @@ -1114,6 +1146,14 @@ AC_MSG_NOTICE([ iSCSI: $with_storage_iscsi]) AC_MSG_NOTICE([ Disk: $with_storage_disk]) AC_MSG_NOTICE([]) +AC_MSG_NOTICE([Driver Loadable Modules]) +AC_MSG_NOTICE([]) +if test "$with_driver_modules" != "no" ; then +AC_MSG_NOTICE([ dlopen: $DRIVER_MODULES_CFLAGS $DRIVER_MODULES_LIBS]) +else +AC_MSG_NOTICE([ dlopen: no]) +fi +AC_MSG_NOTICE([]) AC_MSG_NOTICE([Libraries]) AC_MSG_NOTICE([]) AC_MSG_NOTICE([ libxml: $LIBXML_CFLAGS $LIBXML_LIBS]) diff -r ecc8ae6295bc qemud/Makefile.am --- a/qemud/Makefile.am Wed Nov 12 21:59:22 2008 +0000 +++ b/qemud/Makefile.am Thu Nov 13 17:13:02 2008 +0000 @@ -92,6 +92,7 @@ ../gnulib/lib/libgnu.la \ ../src/libvirt.la +if ! WITH_DRIVER_MODULES if WITH_QEMU libvirtd_LDADD += ../src/libvirt_driver_qemu.la endif @@ -106,6 +107,7 @@ if WITH_NETWORK libvirtd_LDADD += ../src/libvirt_driver_network.la +endif endif if HAVE_POLKIT diff -r ecc8ae6295bc qemud/qemud.c --- a/qemud/qemud.c Wed Nov 12 21:59:22 2008 +0000 +++ b/qemud/qemud.c Thu Nov 13 17:13:02 2008 +0000 @@ -61,6 +61,9 @@ #include "mdns.h" #endif +#ifdef WITH_DRIVER_MODULES +#include "driver.h" +#else #ifdef WITH_QEMU #include "qemu_driver.h" #endif @@ -72,6 +75,7 @@ #endif #ifdef WITH_STORAGE_DIR #include "storage_driver.h" +#endif #endif @@ -744,8 +748,19 @@ virInitialize(); +#ifdef WITH_DRIVER_MODULES + /* We don't care if any of these fail, because the whole point + * is to allow users to only install modules they want to use. + * If they try to use a open a connection for a module that + * is not loaded they'll get a suitable error at that point + */ + virDriverLoadModule("qemu"); + virDriverLoadModule("lxc"); + virDriverLoadModule("network"); + virDriverLoadModule("storage"); +#else #ifdef WITH_QEMU - qemudRegister(); + qemuRegister(); #endif #ifdef WITH_LXC lxcRegister(); @@ -755,6 +770,7 @@ #endif #ifdef WITH_STORAGE_DIR storageRegister(); +#endif #endif virEventRegisterImpl(virEventAddHandleImpl, diff -r ecc8ae6295bc src/Makefile.am --- a/src/Makefile.am Wed Nov 12 21:59:22 2008 +0000 +++ b/src/Makefile.am Thu Nov 13 17:13:02 2008 +0000 @@ -6,7 +6,10 @@ -I@top_srcdir@/include \ -I@top_srcdir@/qemud \ $(LIBXML_CFLAGS) \ + $(XEN_CFLAGS) \ $(SELINUX_CFLAGS) \ + $(DRIVER_MODULE_CFLAGS) \ + -DLIBDIR=\""$(libdir)"\" \ -DBINDIR=\""$(libexecdir)"\" \ -DSBINDIR=\""$(sbindir)"\" \ -DSYSCONF_DIR="\"$(sysconfdir)\"" \ @@ -30,6 +33,10 @@ lib_LTLIBRARIES = libvirt.la +moddir = $(libdir)/libvirt/drivers +mod_LTLIBRARIES = + + # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ @@ -49,7 +56,7 @@ # Internal generic driver infrastructure DRIVER_SOURCES = \ - driver.h \ + driver.c driver.h \ internal.h \ datatypes.c datatypes.h \ domain_event.c domain_event.h \ @@ -163,67 +170,120 @@ $(STORAGE_CONF_SOURCES) if WITH_TEST +if WITH_DRIVER_MODULES +mod_LTLIBRARIES += libvirt_driver_test.la +else noinst_LTLIBRARIES += libvirt_driver_test.la libvirt_la_LIBADD += libvirt_driver_test.la +endif libvirt_driver_test_la_SOURCES = $(TEST_DRIVER_SOURCES) endif if WITH_REMOTE +if WITH_DRIVER_MODULES +mod_LTLIBRARIES += libvirt_driver_remote.la +else noinst_LTLIBRARIES += libvirt_driver_remote.la libvirt_la_LIBADD += libvirt_driver_remote.la +endif libvirt_driver_remote_la_CFLAGS = \ $(GNUTLS_CFLAGS) \ $(SASL_CFLAGS) libvirt_driver_remote_la_LDFLAGS = \ $(GNUTLS_LIBS) \ $(SASL_LIBS) +if WITH_DRIVER_MODULES +libvirt_driver_remote_la_LDFLAGS += -module -avoid-version +endif libvirt_driver_remote_la_SOURCES = $(REMOTE_DRIVER_SOURCES) endif if WITH_XEN +if WITH_DRIVER_MODULES +mod_LTLIBRARIES += libvirt_driver_xen.la +else noinst_LTLIBRARIES += libvirt_driver_xen.la libvirt_la_LIBADD += libvirt_driver_xen.la +endif libvirt_driver_xen_la_CFLAGS = $(XEN_CFLAGS) libvirt_driver_xen_la_LDFLAGS = $(XEN_LIBS) +if WITH_DRIVER_MODULES +libvirt_driver_xen_la_LDFLAGS += -module -avoid-version +endif libvirt_driver_xen_la_SOURCES = $(XEN_DRIVER_SOURCES) endif if WITH_OPENVZ +if WITH_DRIVER_MODULES +mod_LTLIBRARIES += libvirt_driver_openvz.la +else noinst_LTLIBRARIES += libvirt_driver_openvz.la libvirt_la_LIBADD += libvirt_driver_openvz.la +endif +if WITH_DRIVER_MODULES +libvirt_driver_openvz_la_LDFLAGS = -module -avoid-version +endif libvirt_driver_openvz_la_SOURCES = $(OPENVZ_DRIVER_SOURCES) endif if WITH_QEMU +if WITH_DRIVER_MODULES +mod_LTLIBRARIES += libvirt_driver_qemu.la +else noinst_LTLIBRARIES += libvirt_driver_qemu.la # Stateful, so linked to daemon instead #libvirt_la_LIBADD += libvirt_driver_qemu.la +endif libvirt_driver_qemu_la_CFLAGS = $(NUMACTL_CFLAGS) libvirt_driver_qemu_la_LDFLAGS = $(NUMACTL_LIBS) +if WITH_DRIVER_MODULES +libvirt_driver_qemu_la_LDFLAGS += -module -avoid-version +endif libvirt_driver_qemu_la_SOURCES = $(QEMU_DRIVER_SOURCES) endif if WITH_LXC +if WITH_DRIVER_MODULES +mod_LTLIBRARIES += libvirt_driver_lxc.la +else noinst_LTLIBRARIES += libvirt_driver_lxc.la # Stateful, so linked to daemon instead #libvirt_la_LIBADD += libvirt_driver_lxc.la +endif +if WITH_DRIVER_MODULES +libvirt_driver_lxc_la_LDFLAGS = -module -avoid-version +endif libvirt_driver_lxc_la_SOURCES = $(LXC_DRIVER_SOURCES) endif if WITH_NETWORK +if WITH_DRIVER_MODULES +mod_LTLIBRARIES += libvirt_driver_network.la +else noinst_LTLIBRARIES += libvirt_driver_network.la # Stateful, so linked to daemon instead #libvirt_la_LIBADD += libvirt_driver_network.la +endif +if WITH_DRIVER_MODULES +libvirt_driver_network_la_LDFLAGS = -module -avoid-version +endif libvirt_driver_network_la_SOURCES = $(NETWORK_DRIVER_SOURCES) endif # Needed to keep automake quiet about conditionals libvirt_driver_storage_la_SOURCES = if WITH_STORAGE_DIR +if WITH_DRIVER_MODULES +mod_LTLIBRARIES += libvirt_driver_storage.la +else noinst_LTLIBRARIES += libvirt_driver_storage.la # Stateful, so linked to daemon instead #libvirt_la_LIBADD += libvirt_driver_storage.la +endif +if WITH_DRIVER_MODULES +libvirt_driver_storage_la_LDFLAGS = -module -avoid-version +endif libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_SOURCES) libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_FS_SOURCES) endif @@ -258,7 +318,8 @@ # Empty source list - it merely links a bunch of convenience libs together libvirt_la_SOURCES = -libvirt_la_LIBADD += $(LIBXML_LIBS) $(SELINUX_LIBS) \ +libvirt_la_LIBADD += $(LIBXML_LIBS) $(XEN_LIBS) $(SELINUX_LIBS) \ + $(DRIVER_MODULE_LIBS) \ @CYGWIN_EXTRA_LIBADD@ ../gnulib/lib/libgnu.la libvirt_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libvirt_sym.version \ -version-info @LIBVIRT_VERSION_INFO@ \ diff -r ecc8ae6295bc src/driver.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/driver.c Thu Nov 13 17:13:02 2008 +0000 @@ -0,0 +1,97 @@ +/* + * driver.c: Helpers for loading drivers + * + * Copyright (C) 2006-2008 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + +#include <config.h> + +#include <unistd.h> + +#include "driver.h" +#include "memory.h" +#include "logging.h" + +#define DEFAULT_DRIVER_DIR LIBDIR "/libvirt/drivers" + +#ifdef WITH_DRIVER_MODULES + +/* XXX re-implment this for other OS, or use libtools helper lib ? */ + +#include <dlfcn.h> + +void * +virDriverLoadModule(const char *name) +{ + const char *moddir = getenv("LIBVIRT_DRIVER_DIR"); + char *modfile = NULL, *regfunc = NULL; + void *handle = NULL; + int (*regsym)(void); + + if (moddir == NULL) + moddir = DEFAULT_DRIVER_DIR; + + DEBUG("Module load %s", name); + + if (asprintf(&modfile, "%s/libvirt_driver_%s.so", moddir, name) < 0) + return NULL; + + if (access(modfile, R_OK) < 0) { + DEBUG("Moodule %s not accessible", modfile); + goto cleanup; + } + + handle = dlopen(modfile, RTLD_NOW | RTLD_LOCAL); + if (!handle) { + DEBUG("failed to load module %s %s", modfile, dlerror()); + goto cleanup; + } + + if (asprintf(®func, "%sRegister", name) < 0) { + regfunc = NULL; + goto cleanup; + } + + regsym = dlsym(handle, regfunc); + if (!regsym) { + DEBUG("Missing module registration symbol %s", regfunc); + goto cleanup; + } + + if ((*regsym)() < 0) { + DEBUG("Failed module registration %s", regfunc); + goto cleanup; + } + + VIR_FREE(modfile); + VIR_FREE(regfunc); + return handle; + +cleanup: + VIR_FREE(modfile); + VIR_FREE(regfunc); + if (handle) + dlclose(handle); + return NULL; +} + + +/* XXX unload modules, but we can't until we can unregister libvirt drivers */ + +#endif diff -r ecc8ae6295bc src/driver.h --- a/src/driver.h Wed Nov 12 21:59:22 2008 +0000 +++ b/src/driver.h Thu Nov 13 17:13:02 2008 +0000 @@ -8,6 +8,7 @@ #include <libxml/uri.h> +#include "internal.h" /* * List of registered drivers numbers */ @@ -614,5 +615,6 @@ #ifdef WITH_LIBVIRTD int virRegisterStateDriver(virStateDriverPtr); #endif +void *virDriverLoadModule(const char *name); #endif /* __VIR_DRIVER_H__ */ diff -r ecc8ae6295bc src/libvirt.c --- a/src/libvirt.c Wed Nov 12 21:59:22 2008 +0000 +++ b/src/libvirt.c Thu Nov 13 17:13:02 2008 +0000 @@ -41,6 +41,7 @@ #include "util.h" #include "memory.h" +#ifndef WITH_DRIVER_MODULES #ifdef WITH_TEST #include "test.h" #endif @@ -52,6 +53,7 @@ #endif #ifdef WITH_OPENVZ #include "openvz_driver.h" +#endif #endif /* @@ -270,11 +272,22 @@ * Note that the order is important: the first ones have a higher * priority when calling virConnectOpen. */ +#ifdef WITH_DRIVER_MODULES + /* We don't care if any of these fail, because the whole point + * is to allow users to only install modules they want to use. + * If they try to use a open a connection for a module that + * is not loaded they'll get a suitable error at that point + */ + virDriverLoadModule("test"); + virDriverLoadModule("xen"); + virDriverLoadModule("openvz"); + virDriverLoadModule("remote"); +#else #ifdef WITH_TEST if (testRegister() == -1) return -1; #endif #ifdef WITH_XEN - if (xenUnifiedRegister () == -1) return -1; + if (xenRegister () == -1) return -1; #endif #ifdef WITH_OPENVZ if (openvzRegister() == -1) return -1; @@ -282,6 +295,7 @@ #ifdef WITH_REMOTE if (remoteRegister () == -1) return -1; #endif +#endif return(0); } @@ -458,6 +472,9 @@ return(-1); } + DEBUG ("registering %s as network driver %d", + driver->name, virNetworkDriverTabCount); + virNetworkDriverTab[virNetworkDriverTabCount] = driver; return virNetworkDriverTabCount++; } @@ -485,6 +502,9 @@ virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); return(-1); } + + DEBUG ("registering %s as storage driver %d", + driver->name, virStorageDriverTabCount); virStorageDriverTab[virStorageDriverTabCount] = driver; return virStorageDriverTabCount++; diff -r ecc8ae6295bc src/libvirt_sym.version.in --- a/src/libvirt_sym.version.in Wed Nov 12 21:59:22 2008 +0000 +++ b/src/libvirt_sym.version.in Thu Nov 13 17:13:02 2008 +0000 @@ -283,8 +283,12 @@ virCapabilitiesAddGuest; virCapabilitiesAddGuestDomain; virCapabilitiesAddGuestFeature; + virCapabilitiesAddHostMigrateTransport; virCapabilitiesAddHostNUMACell; + virCapabilitiesAddHostFeature; + virCapabilitiesDefaultGuestArch; virCapabilitiesDefaultGuestEmulator; + virCapabilitiesDefaultGuestMachine; virCapabilitiesFormatXML; virCapabilitiesFree; virCapabilitiesNew; @@ -296,6 +300,7 @@ virConfReadFile; virConfReadMem; virConfFree; + virConfFreeValue; virConfGetValue; virConfSetValue; virConfWriteFile; @@ -307,6 +312,7 @@ virGetNetwork; virGetStoragePool; virGetStorageVol; + virUnrefDomain; /* domain_conf.h */ @@ -314,14 +320,22 @@ virDiskNameToIndex; virDomainAssignDef; virDomainConfigFile; + virDomainCpuSetFormat; + virDomainCpuSetParse; + virDomainChrDefFree; + virDomainChrTypeFromString; + virDomainChrTypeToString; virDomainDefDefaultEmulator; virDomainDefFormat; virDomainDefFree; virDomainDefParseFile; + virDomainDefParseNode; virDomainDefParseString; virDomainDeleteConfig; + virDomainDeviceDefFree; virDomainDeviceDefParse; virDomainDiskBusTypeToString; + virDomainDiskDefFree; virDomainDiskDeviceTypeToString; virDomainDiskQSort; virDomainEventCallbackListAdd; @@ -330,12 +344,53 @@ virDomainFindByID; virDomainFindByName; virDomainFindByUUID; + virDomainGraphicsTypeFromString; + virDomainGraphicsDefFree; + virDomainInputDefFree; + virDomainLifecycleTypeFromString; + virDomainLifecycleTypeToString; virDomainLoadAllConfigs; + virDomainNetDefFree; + virDomainObjFree; virDomainObjListFree; virDomainRemoveInactive; virDomainSaveConfig; + virDomainSoundDefFree; + virDomainSoundModelTypeFromString; virDomainSoundModelTypeToString; virDomainVirtTypeToString; + virDomainFSDefFree; + + + /* domain_event.h */ + virDomainEventQueueFree; + virDomainEventCallbackQueuePop; + virDomainEventCallbackQueuePush; + + + /* driver.h */ + virDriverLoadModule; + + + /* event.h */ + virEventAddHandle; + virEventAddTimeout; + virEventRemoveHandle; + virEventRemoveTimeout; + virEventUpdateHandle; + virEventUpdateTimeout; + + + /* hash.h */ + virHashAddEntry; + virHashCreate; + virHashForEach; + virHashFree; + virHashLookup; + virHashRemoveEntry; + virHashRemoveSet; + virHashSearch; + virHashSize; /* iptables.h */ @@ -391,12 +446,15 @@ virNetworkAssignDef; virNetworkDefFormat; virNetworkDefFree; + virNetworkDefParseFile; + virNetworkDefParseNode; virNetworkDefParseString; virNetworkDeleteConfig; virNetworkFindByName; virNetworkFindByUUID; virNetworkLoadAllConfigs; virNetworkObjListFree; + virNetworkDefParseNode; virNetworkRemoveInactive; virNetworkSaveConfig; @@ -405,8 +463,15 @@ virNodeInfoPopulate; + /* qparams.h */ + qparam_get_query; + qparam_query_parse; + free_qparam_set; + + /* stats_linux.h */ linuxDomainInterfaceStats; + xenLinuxDomainBlockStats; /* storage_backend.h */ @@ -423,6 +488,7 @@ /* storage_conf.h */ + virStorageBackendPoolOptionsForType; virStoragePoolDefFormat; virStoragePoolDefFree; virStoragePoolDefParse; @@ -443,6 +509,11 @@ virStorageVolDefFormat; virStorageVolDefFree; virStorageVolDefParse; + virStoragePoolFormatDiskTypeToString; + virStoragePoolFormatFileSystemTypeToString; + virStoragePoolFormatFileSystemNetTypeToString; + virStorageVolFormatFileSystemTypeToString; + virStoragePoolTypeFromString; /* util.h */ @@ -450,6 +521,7 @@ virStrToLong_i; virStrToLong_ll; virStrToLong_ull; + virFileLinkPointsTo; saferead; safewrite; virMacAddrCompare; @@ -458,6 +530,8 @@ virEventAddHandle; virEventRemoveHandle; virExec; + virFormatMacAddr; + virParseMacAddr; virFileDeletePid; virFileExists; virFileHasSuffix; @@ -465,20 +539,28 @@ virFileOpenTty; virFileReadLimFD; virFileReadPid; + virParseNumber; virRun; + virSkipSpaces; /* uuid.h */ virUUIDFormat; + virUUIDGenerate; + virUUIDParse; /* virterror_internal.h */ + virRaiseError; virReportErrorHelper; + virErrorMsg; /* xml.h */ + virXPathLong; + virXPathNodeSet; virXPathString; - + virXMLPropString; /* Finally everything else is totally private */ local: diff -r ecc8ae6295bc src/qemu_driver.c --- a/src/qemu_driver.c Wed Nov 12 21:59:22 2008 +0000 +++ b/src/qemu_driver.c Thu Nov 13 17:13:02 2008 +0000 @@ -3440,7 +3440,7 @@ .active = qemudActive, }; -int qemudRegister(void) { +int qemuRegister(void) { virRegisterDriver(&qemuDriver); virRegisterStateDriver(&qemuStateDriver); return 0; diff -r ecc8ae6295bc src/qemu_driver.h --- a/src/qemu_driver.h Wed Nov 12 21:59:22 2008 +0000 +++ b/src/qemu_driver.h Thu Nov 13 17:13:02 2008 +0000 @@ -47,6 +47,6 @@ # define KVM_CAP_NR_VCPUS 9 /* returns max vcpus per vm */ #endif -int qemudRegister(void); +int qemuRegister(void); #endif /* QEMUD_DRIVER_H */ diff -r ecc8ae6295bc src/xen_unified.c --- a/src/xen_unified.c Wed Nov 12 21:59:22 2008 +0000 +++ b/src/xen_unified.c Thu Nov 13 17:13:02 2008 +0000 @@ -1359,14 +1359,14 @@ }; /** - * xenUnifiedRegister: + * xenRegister: * * Register xen related drivers * * Returns the driver priority or -1 in case of error. */ int -xenUnifiedRegister (void) +xenRegister (void) { /* Ignore failures here. */ (void) xenHypervisorInit (); diff -r ecc8ae6295bc src/xen_unified.h --- a/src/xen_unified.h Wed Nov 12 21:59:22 2008 +0000 +++ b/src/xen_unified.h Thu Nov 13 17:13:02 2008 +0000 @@ -22,7 +22,7 @@ #include <winsock2.h> #endif -extern int xenUnifiedRegister (void); +extern int xenRegister (void); #define XEN_UNIFIED_HYPERVISOR_OFFSET 0 #define XEN_UNIFIED_PROXY_OFFSET 1 diff -r ecc8ae6295bc tests/Makefile.am --- a/tests/Makefile.am Wed Nov 12 21:59:22 2008 +0000 +++ b/tests/Makefile.am Thu Nov 13 17:13:02 2008 +0000 @@ -18,6 +18,11 @@ -DGETTEXT_PACKAGE=\"$(PACKAGE)\" \ $(COVERAGE_CFLAGS) \ $(WARN_CFLAGS) + +if WITH_DRIVER_MODULES +INCLUDES += \ + -DTEST_DRIVER_DIR=\"$(top_builddir)/src/.libs\" +endif LDADDS = \ @STATIC_BINARIES@ \ @@ -76,6 +81,7 @@ abs_srcdir=`cd '$(srcdir)'; pwd` \ PATH="$(path_add)$(PATH_SEPARATOR)$$PATH" \ SHELL="$(SHELL)" \ + LIBVIRT_DRIVER_DIR="$(abs_top_builddir)/src/.libs" \ $(VG) valgrind: @@ -93,17 +99,17 @@ xml2sexprtest_SOURCES = \ xml2sexprtest.c testutilsxen.c testutilsxen.h \ testutils.c testutils.h -xml2sexprtest_LDADD = $(LDADDS) +xml2sexprtest_LDADD = ../src/libvirt_driver_xen.la $(LDADDS) sexpr2xmltest_SOURCES = \ sexpr2xmltest.c \ testutils.c testutils.h -sexpr2xmltest_LDADD = $(LDADDS) +sexpr2xmltest_LDADD = ../src/libvirt_driver_xen.la $(LDADDS) xmconfigtest_SOURCES = \ xmconfigtest.c testutilsxen.c testutilsxen.h \ testutils.c testutils.h -xmconfigtest_LDADD = $(LDADDS) +xmconfigtest_LDADD = ../src/libvirt_driver_xen.la $(LDADDS) qemuxml2argvtest_SOURCES = \ qemuxml2argvtest.c testutilsqemu.c testutilsqemu.h \ @@ -126,7 +132,7 @@ xencapstest_SOURCES = \ xencapstest.c testutils.h testutils.c -xencapstest_LDADD = $(LDADDS) +xencapstest_LDADD = ../src/libvirt_driver_xen.la $(LDADDS) nodeinfotest_SOURCES = \ nodeinfotest.c testutils.h testutils.c diff -r ecc8ae6295bc tests/cpuset --- a/tests/cpuset Wed Nov 12 21:59:22 2008 +0000 +++ b/tests/cpuset Thu Nov 13 17:13:02 2008 +0000 @@ -21,6 +21,9 @@ virsh --version fi +test -z "$srcdir" && srcdir=`pwd` +test -z "$abs_top_srcdir" && abs_top_srcdir=`pwd`/.. + . $srcdir/test-lib.sh fail=0 @@ -40,6 +43,6 @@ error: Failed to define domain from xml-invalid EOF -compare out exp || fail=1 +compare exp out || fail=1 (exit $fail); exit $fail diff -r ecc8ae6295bc tests/read-bufsiz --- a/tests/read-bufsiz Wed Nov 12 21:59:22 2008 +0000 +++ b/tests/read-bufsiz Thu Nov 13 17:13:02 2008 +0000 @@ -21,6 +21,9 @@ virsh --version fi +test -z "$srcdir" && srcdir=`pwd` +test -z "$abs_top_srcdir" && abs_top_srcdir=`pwd`/.. + . $srcdir/test-lib.sh fail=0 @@ -37,7 +40,7 @@ virsh --connect test:///default define $in > out || fail=1 printf "Domain test defined from $in\n\n" > exp || fail=1 - compare out exp || fail=1 + compare exp out || fail=1 done (exit $fail); exit $fail diff -r ecc8ae6295bc tests/read-non-seekable --- a/tests/read-non-seekable Wed Nov 12 21:59:22 2008 +0000 +++ b/tests/read-non-seekable Thu Nov 13 17:13:02 2008 +0000 @@ -20,6 +20,9 @@ set -x virsh --version fi + +test -z "$srcdir" && srcdir=`pwd` +test -z "$abs_top_srcdir" && abs_top_srcdir=`pwd`/.. . $srcdir/test-lib.sh diff -r ecc8ae6295bc tests/testutils.c --- a/tests/testutils.c Wed Nov 12 21:59:22 2008 +0000 +++ b/tests/testutils.c Thu Nov 13 17:13:02 2008 +0000 @@ -151,6 +151,9 @@ int stderrfd = -1; const char *const env[] = { "LANG=C", +#if WITH_DRIVER_MODULES + "LIBVIRT_DRIVER_DIR=" TEST_DRIVER_DIR, +#endif NULL }; diff -r ecc8ae6295bc tests/undefine --- a/tests/undefine Wed Nov 12 21:59:22 2008 +0000 +++ b/tests/undefine Thu Nov 13 17:13:02 2008 +0000 @@ -21,6 +21,9 @@ virsh --version fi +test -z "$srcdir" && srcdir=`pwd` +test -z "$abs_top_srcdir" && abs_top_srcdir=`pwd`/.. + . $srcdir/test-lib.sh fail=0 @@ -32,7 +35,7 @@ libvir: Test error : internal error Domain 'test' is still running error: Failed to undefine domain test EOF -compare out exp || fail=1 +compare exp out || fail=1 # A different diagnostic when specifying a domain ID virsh -q -c test:///default undefine 1 > out 2>&1 @@ -41,7 +44,7 @@ error: a running domain like 1 cannot be undefined; to undefine, first shutdown then undefine using its name or UUID EOF -compare out exp || fail=1 +compare exp out || fail=1 # Succeed, now: first shut down, then undefine, both via name. virsh -q -c test:///default 'shutdown test; undefine test' > out 2>&1 @@ -50,6 +53,6 @@ Domain test is being shutdown Domain test has been undefined EOF -compare out exp || fail=1 +compare exp out || fail=1 (exit $fail); exit $fail diff -r ecc8ae6295bc tests/vcpupin --- a/tests/vcpupin Wed Nov 12 21:59:22 2008 +0000 +++ b/tests/vcpupin Thu Nov 13 17:13:02 2008 +0000 @@ -21,6 +21,9 @@ virsh --version fi +test -z "$srcdir" && srcdir=`pwd` +test -z "$abs_top_srcdir" && abs_top_srcdir=`pwd`/.. + . $srcdir/test-lib.sh fail=0 @@ -32,7 +35,7 @@ error: vcpupin: Invalid or missing vCPU number. EOF -compare out exp || fail=1 +compare exp out || fail=1 # An out-of-range vCPU number deserves a diagnostic, too. virsh --connect test:///default vcpupin test 100 0,1 > out 2>&1 @@ -41,6 +44,6 @@ error: vcpupin: Invalid vCPU number. EOF -compare out exp || fail=1 +compare exp out || fail=1 (exit $fail); exit $fail diff -r ecc8ae6295bc tests/xmconfigtest.c --- a/tests/xmconfigtest.c Wed Nov 12 21:59:22 2008 +0000 +++ b/tests/xmconfigtest.c Thu Nov 13 17:13:02 2008 +0000 @@ -55,13 +55,11 @@ int ret = -1; virConnectPtr conn; int wrote = MAX_FILE; - void *old_priv = NULL; struct _xenUnifiedPrivate priv; virDomainDefPtr def = NULL; - conn = virConnectOpenReadOnly("test:///default"); + conn = virGetConnect(); if (!conn) goto fail; - old_priv = conn->privateData; if (virtTestLoadFile(xml, &xmlPtr, MAX_FILE) < 0) goto fail; @@ -95,10 +93,7 @@ if (conf) virConfFree(conf); virDomainDefFree(def); - if (conn) { - conn->privateData = old_priv; - virConnectClose(conn); - } + VIR_FREE(conn); return ret; } @@ -113,13 +108,11 @@ virConfPtr conf = NULL; int ret = -1; virConnectPtr conn; - void *old_priv; struct _xenUnifiedPrivate priv; virDomainDefPtr def = NULL; - conn = virConnectOpenReadOnly("test:///default"); + conn = virGetConnect(); if (!conn) goto fail; - old_priv = conn->privateData; if (virtTestLoadFile(xml, &xmlPtr, MAX_FILE) < 0) goto fail; @@ -153,10 +146,7 @@ virConfFree(conf); VIR_FREE(gotxml); virDomainDefFree(def); - if (conn) { - conn->privateData = old_priv; - virConnectClose(conn); - } + VIR_FREE(conn); return ret; } -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Thu, Nov 13, 2008 at 05:29:15PM +0000, Daniel P. Berrange wrote:
This patch is a small incremental change to optionally allow us to build every driver as a dlopen()able module. This is disabled by default for now. I'm not sure whether this is hugely usefl or not, but it was easy enough to do, so here's the patch.
Good, I note there is also some renaming of entry points... I'm just a bit surprized it affects tests too ...
+++ b/tests/xmconfigtest.c Thu Nov 13 17:13:02 2008 +0000 [...] virDomainDefFree(def); - if (conn) { - conn->privateData = old_priv; - virConnectClose(conn); - } + VIR_FREE(conn); [...] - if (conn) { - conn->privateData = old_priv; - virConnectClose(conn); - } + VIR_FREE(conn);
hum, that's a bit surprizing, we are not closing the connection to free the data structure anymore ... I assume there is a good reason but that's obscure. +1 Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Fri, Nov 14, 2008 at 01:05:18PM +0100, Daniel Veillard wrote:
On Thu, Nov 13, 2008 at 05:29:15PM +0000, Daniel P. Berrange wrote:
This patch is a small incremental change to optionally allow us to build every driver as a dlopen()able module. This is disabled by default for now. I'm not sure whether this is hugely usefl or not, but it was easy enough to do, so here's the patch.
Good, I note there is also some renaming of entry points...
I'm just a bit surprized it affects tests too ...
+++ b/tests/xmconfigtest.c Thu Nov 13 17:13:02 2008 +0000 [...] virDomainDefFree(def); - if (conn) { - conn->privateData = old_priv; - virConnectClose(conn); - } + VIR_FREE(conn); [...] - if (conn) { - conn->privateData = old_priv; - virConnectClose(conn); - } + VIR_FREE(conn);
hum, that's a bit surprizing, we are not closing the connection to free the data structure anymore ... I assume there is a good reason but that's obscure.
Previously we were seriously abusing the virConnectPtr struct by getting an instance with test:///default URI, and then munging the private Data to point to XM's struct. I stopped opening a connection, and just have a struct directly initialized with the test data, so there's no need to explicitly close it - its a little clearer if you look further up the test case, rather than just this bit of diff context. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

This patch is the public API parts of the node device enumeration code. No changes since David's last submission of this, except for some Makefile tweaks Daniel diff -r 78738f80cf4c include/libvirt/libvirt.h --- a/include/libvirt/libvirt.h Wed Nov 12 21:05:32 2008 +0000 +++ b/include/libvirt/libvirt.h Wed Nov 12 21:11:46 2008 +0000 @@ -995,6 +995,74 @@ unsigned int flags); /* + * Host device enumeration + */ + +/** + * virNodeDevice: + * + * A virNodeDevice contains a node (host) device details. + */ + +typedef struct _virNodeDevice virNodeDevice; + +/** + * virNodeDevicePtr: + * + * A virNodeDevicePtr is a pointer to a virNodeDevice structure. Get + * one via virNodeDeviceLookupByKey, virNodeDeviceLookupByName, or + * virNodeDeviceCreate. Be sure to Call virNodeDeviceFree when done + * using a virNodeDevicePtr obtained from any of the above functions to + * avoid leaking memory. + */ + +typedef virNodeDevice *virNodeDevicePtr; + + +int virNodeNumOfDevices (virConnectPtr conn, + unsigned int flags); + +int virNodeListDevices (virConnectPtr conn, + char **const names, + int maxnames, + unsigned int flags); + +int virNodeNumOfDevicesByCap (virConnectPtr conn, + const char *cap, + unsigned int flags); + +int virNodeListDevicesByCap (virConnectPtr conn, + const char *cap, + char **const names, + int maxnames, + unsigned int flags); + +virNodeDevicePtr virNodeDeviceLookupByName (virConnectPtr conn, + const char *name); + +const char * virNodeDeviceGetName (virNodeDevicePtr dev); + +const char * virNodeDeviceGetParent (virNodeDevicePtr dev); + +int virNodeDeviceNumOfCaps (virNodeDevicePtr dev); + +int virNodeDeviceListCaps (virNodeDevicePtr dev, + char **const names, + int maxnames); + +char * virNodeDeviceGetXMLDesc (virNodeDevicePtr dev, + unsigned int flags); + +virNodeDevicePtr virNodeDeviceCreate (virConnectPtr conn, + const char *xml, + unsigned int flags); + +int virNodeDeviceDestroy (virNodeDevicePtr dev, + unsigned int flags); + +int virNodeDeviceFree (virNodeDevicePtr dev); + +/* * Domain Event Notification */ diff -r 78738f80cf4c include/libvirt/libvirt.h.in --- a/include/libvirt/libvirt.h.in Wed Nov 12 21:05:32 2008 +0000 +++ b/include/libvirt/libvirt.h.in Wed Nov 12 21:11:46 2008 +0000 @@ -995,6 +995,74 @@ unsigned int flags); /* + * Host device enumeration + */ + +/** + * virNodeDevice: + * + * A virNodeDevice contains a node (host) device details. + */ + +typedef struct _virNodeDevice virNodeDevice; + +/** + * virNodeDevicePtr: + * + * A virNodeDevicePtr is a pointer to a virNodeDevice structure. Get + * one via virNodeDeviceLookupByKey, virNodeDeviceLookupByName, or + * virNodeDeviceCreate. Be sure to Call virNodeDeviceFree when done + * using a virNodeDevicePtr obtained from any of the above functions to + * avoid leaking memory. + */ + +typedef virNodeDevice *virNodeDevicePtr; + + +int virNodeNumOfDevices (virConnectPtr conn, + unsigned int flags); + +int virNodeListDevices (virConnectPtr conn, + char **const names, + int maxnames, + unsigned int flags); + +int virNodeNumOfDevicesByCap (virConnectPtr conn, + const char *cap, + unsigned int flags); + +int virNodeListDevicesByCap (virConnectPtr conn, + const char *cap, + char **const names, + int maxnames, + unsigned int flags); + +virNodeDevicePtr virNodeDeviceLookupByName (virConnectPtr conn, + const char *name); + +const char * virNodeDeviceGetName (virNodeDevicePtr dev); + +const char * virNodeDeviceGetParent (virNodeDevicePtr dev); + +int virNodeDeviceNumOfCaps (virNodeDevicePtr dev); + +int virNodeDeviceListCaps (virNodeDevicePtr dev, + char **const names, + int maxnames); + +char * virNodeDeviceGetXMLDesc (virNodeDevicePtr dev, + unsigned int flags); + +virNodeDevicePtr virNodeDeviceCreate (virConnectPtr conn, + const char *xml, + unsigned int flags); + +int virNodeDeviceDestroy (virNodeDevicePtr dev, + unsigned int flags); + +int virNodeDeviceFree (virNodeDevicePtr dev); + +/* * Domain Event Notification */ diff -r 78738f80cf4c include/libvirt/virterror.h --- a/include/libvirt/virterror.h Wed Nov 12 21:05:32 2008 +0000 +++ b/include/libvirt/virterror.h Wed Nov 12 21:11:46 2008 +0000 @@ -58,6 +58,7 @@ VIR_FROM_STORAGE, /* Error from storage driver */ VIR_FROM_NETWORK, /* Error from network config */ VIR_FROM_DOMAIN, /* Error from domain config */ + VIR_FROM_DEVMONITOR,/* Error from node device monitor */ } virErrorDomain; @@ -148,6 +149,9 @@ 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 */ + VIR_WAR_NO_NODE, /* failed to start node driver */ + VIR_ERR_INVALID_NODE_DEVICE,/* invalid node device object */ + VIR_ERR_NO_NODE_DEVICE,/* node device not found */ } virErrorNumber; /** diff -r 78738f80cf4c src/datatypes.c --- a/src/datatypes.c Wed Nov 12 21:05:32 2008 +0000 +++ b/src/datatypes.c Wed Nov 12 21:11:46 2008 +0000 @@ -140,6 +140,9 @@ ret->storageVols = virHashCreate(20); if (ret->storageVols == NULL) goto failed; + ret->nodeDevices = virHashCreate(256); + if (ret->nodeDevices == NULL) + goto failed; pthread_mutex_init(&ret->lock, NULL); @@ -156,6 +159,8 @@ virHashFree(ret->storagePools, (virHashDeallocator) virStoragePoolFreeName); if (ret->storageVols != NULL) virHashFree(ret->storageVols, (virHashDeallocator) virStorageVolFreeName); + if (ret->nodeDevices != NULL) + virHashFree(ret->nodeDevices, (virHashDeallocator) virNodeDeviceFree); pthread_mutex_destroy(&ret->lock); VIR_FREE(ret); @@ -183,6 +188,8 @@ virHashFree(conn->storagePools, (virHashDeallocator) virStoragePoolFreeName); if (conn->storageVols != NULL) virHashFree(conn->storageVols, (virHashDeallocator) virStorageVolFreeName); + if (conn->nodeDevices != NULL) + virHashFree(conn->nodeDevices, (virHashDeallocator) virNodeDeviceFree); virResetError(&conn->err); if (virLastErr.conn == conn) @@ -771,3 +778,126 @@ pthread_mutex_unlock(&vol->conn->lock); return (refs); } + + +/** + * virGetNodeDevice: + * @conn: the hypervisor connection + * @name: device name (unique on node) + * + * Lookup if the device 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 + * virFreeNodeDevice() is needed to not leak data. + * + * Returns a pointer to the node device, or NULL in case of failure + */ +virNodeDevicePtr +virGetNodeDevice(virConnectPtr conn, const char *name) +{ + virNodeDevicePtr ret = NULL; + + if ((!VIR_IS_CONNECT(conn)) || (name == NULL)) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(NULL); + } + pthread_mutex_lock(&conn->lock); + + ret = (virNodeDevicePtr) virHashLookup(conn->nodeDevices, name); + if (ret == NULL) { + if (VIR_ALLOC(ret) < 0) { + virLibConnError(conn, VIR_ERR_NO_MEMORY, _("allocating node dev")); + goto error; + } + ret->magic = VIR_NODE_DEVICE_MAGIC; + ret->conn = conn; + ret->name = strdup(name); + if (ret->name == NULL) { + virLibConnError(conn, VIR_ERR_NO_MEMORY, _("copying node dev name")); + goto error; + } + + if (virHashAddEntry(conn->nodeDevices, name, ret) < 0) { + virLibConnError(conn, VIR_ERR_INTERNAL_ERROR, + _("failed to add node dev to conn hash table")); + goto error; + } + conn->refs++; + } + ret->refs++; + pthread_mutex_unlock(&conn->lock); + return(ret); + +error: + pthread_mutex_unlock(&conn->lock); + if (ret != NULL) { + VIR_FREE(ret->name); + VIR_FREE(ret); + } + return(NULL); +} + + +/** + * virReleaseNodeDevice: + * @dev: the dev to release + * + * Unconditionally release all memory associated with a dev. + * The conn.lock mutex must be held prior to calling this, and will + * be released prior to this returning. The dev obj must not + * be used once this method returns. + * + * It will also unreference the associated connection object, + * which may also be released if its ref count hits zero. + */ +static void +virReleaseNodeDevice(virNodeDevicePtr dev) { + virConnectPtr conn = dev->conn; + DEBUG("release dev %p %s", dev, dev->name); + + if (virHashRemoveEntry(conn->nodeDevices, dev->name, NULL) < 0) + virLibConnError(conn, VIR_ERR_INTERNAL_ERROR, + _("dev missing from connection hash table")); + + dev->magic = -1; + VIR_FREE(dev->name); + VIR_FREE(dev); + + DEBUG("unref connection %p %d", conn, conn->refs); + conn->refs--; + if (conn->refs == 0) { + virReleaseConnect(conn); + /* Already unlocked mutex */ + return; + } + + pthread_mutex_unlock(&conn->lock); +} + + +/** + * virUnrefNodeDevice: + * @dev: the dev to unreference + * + * Unreference the dev. If the use count drops to zero, the structure is + * actually freed. + * + * Returns the reference count or -1 in case of failure. + */ +int +virUnrefNodeDevice(virNodeDevicePtr dev) { + int refs; + + pthread_mutex_lock(&dev->conn->lock); + DEBUG("unref dev %p %s %d", dev, dev->name, dev->refs); + dev->refs--; + refs = dev->refs; + if (refs == 0) { + virReleaseNodeDevice(dev); + /* Already unlocked mutex */ + return (0); + } + + pthread_mutex_unlock(&dev->conn->lock); + return (refs); +} diff -r 78738f80cf4c src/datatypes.h --- a/src/datatypes.h Wed Nov 12 21:05:32 2008 +0000 +++ b/src/datatypes.h Wed Nov 12 21:11:46 2008 +0000 @@ -78,6 +78,16 @@ #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_CONNECT((obj)->conn)) +/** + * VIR_NODE_DEVICE_MAGIC: + * + * magic value used to protect the API when pointers to storage vol structures + * are passed down by the users. + */ +#define VIR_NODE_DEVICE_MAGIC 0xDEAD5679 +#define VIR_IS_NODE_DEVICE(obj) ((obj) && (obj)->magic==VIR_NODE_DEVICE_MAGIC) +#define VIR_IS_CONNECTED_NODE_DEVICE(obj) (VIR_IS_NODE_DEVICE(obj) && VIR_IS_CONNECT((obj)->conn)) + /** * _virConnect: @@ -93,6 +103,7 @@ virDriverPtr driver; virNetworkDriverPtr networkDriver; virStorageDriverPtr storageDriver; + virDeviceMonitorPtr deviceMonitor; /* Private data pointer which can be used by driver and * network driver as they wish. @@ -101,6 +112,7 @@ void * privateData; void * networkPrivateData; void * storagePrivateData; + void * devMonPrivateData; /* Per-connection error. */ virError err; /* the last error */ @@ -118,6 +130,7 @@ virHashTablePtr networks; /* hash table for known domains */ virHashTablePtr storagePools;/* hash table for known storage pools */ virHashTablePtr storageVols;/* hash table for known storage vols */ + virHashTablePtr nodeDevices; /* hash table for known node devices */ int refs; /* reference count */ }; @@ -176,6 +189,19 @@ char key[PATH_MAX]; /* unique key for storage vol */ }; +/** + * _virNodeDevice: + * + * Internal structure associated with a node device + */ +struct _virNodeDevice { + unsigned int magic; /* specific value to check */ + int refs; /* reference count */ + virConnectPtr conn; /* pointer back to the connection */ + char *name; /* device name (unique on node) */ +}; + + /************************************************************************ * * * API for domain/connections (de)allocations and lookups * @@ -203,4 +229,8 @@ const char *key); int virUnrefStorageVol(virStorageVolPtr vol); +virNodeDevicePtr virGetNodeDevice(virConnectPtr conn, + const char *name); +int virUnrefNodeDevice(virNodeDevicePtr dev); + #endif diff -r 78738f80cf4c src/driver.h --- a/src/driver.h Wed Nov 12 21:05:32 2008 +0000 +++ b/src/driver.h Wed Nov 12 21:11:46 2008 +0000 @@ -604,6 +604,73 @@ }; #endif + +typedef struct _virDeviceMonitor virDeviceMonitor; +typedef virDeviceMonitor *virDeviceMonitorPtr; + +typedef int (*virDevMonNumOfDevices)(virConnectPtr conn, + unsigned int flags); + +typedef int (*virDevMonListDevices)(virConnectPtr conn, + char **const names, + int maxnames, + unsigned int flags); + +typedef int (*virDevMonNumOfDevicesByCap)(virConnectPtr conn, + const char *cap, + unsigned int flags); + +typedef int (*virDevMonListDevicesByCap)(virConnectPtr conn, + const char *cap, + char **const names, + int maxnames, + unsigned int flags); + +typedef virNodeDevicePtr (*virDevMonDeviceLookupByName)(virConnectPtr conn, + const char *name); + +typedef char * (*virDevMonDeviceDumpXML)(virNodeDevicePtr dev, + unsigned int flags); + +typedef char * (*virDevMonDeviceGetParent)(virNodeDevicePtr dev); + +typedef int (*virDevMonDeviceNumOfCaps)(virNodeDevicePtr dev); + +typedef int (*virDevMonDeviceListCaps)(virNodeDevicePtr dev, + char **const names, + int maxnames); + +typedef virNodeDevicePtr (*virDevMonDeviceCreate)(virConnectPtr conn, + const char *xml, + unsigned int flags); + +typedef int (*virDevMonDeviceDestroy)(virNodeDevicePtr dev, + unsigned int flags); + +/** + * _virDeviceMonitor: + * + * Structure associated with monitoring the devices + * on a virtualized node. + * + */ +struct _virDeviceMonitor { + const char * name; /* the name of the driver */ + virDrvOpen open; + virDrvClose close; + virDevMonNumOfDevices numOfDevices; + virDevMonListDevices listDevices; + virDevMonNumOfDevicesByCap numOfDevicesByCap; + virDevMonListDevicesByCap listDevicesByCap; + virDevMonDeviceLookupByName deviceLookupByName; + virDevMonDeviceDumpXML deviceDumpXML; + virDevMonDeviceGetParent deviceGetParent; + virDevMonDeviceNumOfCaps deviceNumOfCaps; + virDevMonDeviceListCaps deviceListCaps; + virDevMonDeviceCreate deviceCreate; + virDevMonDeviceDestroy deviceDestroy; +}; + /* * Registration * TODO: also need ways to (des)activate a given driver @@ -612,6 +679,7 @@ int virRegisterDriver(virDriverPtr); int virRegisterNetworkDriver(virNetworkDriverPtr); int virRegisterStorageDriver(virStorageDriverPtr); +int virRegisterDeviceMonitor(virDeviceMonitorPtr); #ifdef WITH_LIBVIRTD int virRegisterStateDriver(virStateDriverPtr); #endif diff -r 78738f80cf4c src/libvirt.c --- a/src/libvirt.c Wed Nov 12 21:05:32 2008 +0000 +++ b/src/libvirt.c Wed Nov 12 21:11:46 2008 +0000 @@ -70,6 +70,8 @@ static int virNetworkDriverTabCount = 0; static virStorageDriverPtr virStorageDriverTab[MAX_DRIVERS]; static int virStorageDriverTabCount = 0; +static virDeviceMonitorPtr virDeviceMonitorTab[MAX_DRIVERS]; +static int virDeviceMonitorTabCount = 0; #ifdef WITH_LIBVIRTD static virStateDriverPtr virStateDriverTab[MAX_DRIVERS]; static int virStateDriverTabCount = 0; @@ -449,6 +451,32 @@ } /** + * virLibNodeDeviceError: + * @dev: the device if available + * @error: the error number + * @info: extra information string + * + * Handle an error at the node device level + */ +static void +virLibNodeDeviceError(virNodeDevicePtr dev, 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_NODE_DEVICE) + conn = dev->conn; + + virRaiseError(conn, NULL, NULL, VIR_FROM_DEVMONITOR, error, VIR_ERR_ERROR, + errmsg, info, NULL, 0, 0, errmsg, info); +} + +/** * virRegisterNetworkDriver: * @driver: pointer to a network driver block * @@ -508,6 +536,34 @@ virStorageDriverTab[virStorageDriverTabCount] = driver; return virStorageDriverTabCount++; +} + +/** + * virRegisterDeviceMonitor: + * @driver: pointer to a device monitor block + * + * Register a device monitor + * + * Returns the driver priority or -1 in case of error. + */ +int +virRegisterDeviceMonitor(virDeviceMonitorPtr driver) +{ + if (virInitialize() < 0) + return -1; + + if (driver == NULL) { + virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(-1); + } + + if (virDeviceMonitorTabCount >= MAX_DRIVERS) { + virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(-1); + } + + virDeviceMonitorTab[virDeviceMonitorTabCount] = driver; + return virDeviceMonitorTabCount++; } /** @@ -806,6 +862,33 @@ } } + /* Node driver (optional) */ + for (i = 0; i < virDeviceMonitorTabCount; i++) { + res = virDeviceMonitorTab[i]->open (ret, auth, flags); + DEBUG("node driver %d %s returned %s", + i, virDeviceMonitorTab[i]->name, + res == VIR_DRV_OPEN_SUCCESS ? "SUCCESS" : + (res == VIR_DRV_OPEN_DECLINED ? "DECLINED" : + (res == VIR_DRV_OPEN_ERROR ? "ERROR" : "unknown status"))); + if (res == VIR_DRV_OPEN_ERROR) { + if (STREQ(virDeviceMonitorTab[i]->name, "remote")) { + virLibConnWarning (NULL, VIR_WAR_NO_NODE, + "Is the libvirtd daemon running ?"); + } else { + char *msg; + if (asprintf(&msg, "Is the %s daemon running?", + virDeviceMonitorTab[i]->name) > 0) { + virLibConnWarning (NULL, VIR_WAR_NO_NODE, msg); + VIR_FREE(msg); + } + } + break; + } else if (res == VIR_DRV_OPEN_SUCCESS) { + ret->deviceMonitor = virDeviceMonitorTab[i]; + break; + } + } + return ret; failed: @@ -923,6 +1006,8 @@ conn->networkDriver->close (conn); if (conn->storageDriver) conn->storageDriver->close (conn); + if (conn->deviceMonitor) + conn->deviceMonitor->close (conn); conn->driver->close (conn); if (virUnrefConnect(conn) < 0) @@ -5263,6 +5348,383 @@ + +/** + * virNodeNumOfDevices: + * @conn: pointer to the hypervisor connection + * @flags: flags (unused, pass 0) + * + * Provides the number of node devices. + * + * Returns the number of node devices or -1 in case of error + */ +int +virNodeNumOfDevices(virConnectPtr conn, unsigned int flags) +{ + DEBUG("conn=%p, flags=%d", conn, flags); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (-1); + } + if (flags != 0) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + if (conn->deviceMonitor && conn->deviceMonitor->numOfDevices) + return conn->deviceMonitor->numOfDevices (conn, flags); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + + +/** + * virNodeListDevices: + * @conn: pointer to the hypervisor connection + * @names: array to collect the list of node device names + * @maxnames: size of @names + * @flags: flags (unused, pass 0) + * + * Collect the list of node devices, and store their names in @names + * + * Returns the number of node devices found or -1 in case of error + */ +int +virNodeListDevices(virConnectPtr conn, char **const names, int maxnames, + unsigned int flags) +{ + DEBUG("conn=%p, names=%p, maxnames=%d, flags=%d", + conn, names, maxnames, flags); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (-1); + } + if ((flags != 0) || (names == NULL) || (maxnames < 0)) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + if (conn->deviceMonitor && conn->deviceMonitor->listDevices) + return conn->deviceMonitor->listDevices (conn, names, maxnames, flags); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + +/** + * virNodeNumOfDevicesByCap: + * @conn: pointer to the hypervisor connection + * @cap: capability name + * @flags: flags (unused, pass 0) + * + * Provides the number of node devices with the given capability. + * + * Returns the number of node devices with the capability or -1 in case of error + */ +int +virNodeNumOfDevicesByCap(virConnectPtr conn, const char *cap, + unsigned int flags) +{ + DEBUG("conn=%p, cap=%p, flags=%d", conn, cap, flags); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (-1); + } + + if ((flags != 0) || (cap == NULL)) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + if (conn->deviceMonitor && conn->deviceMonitor->numOfDevicesByCap) + return conn->deviceMonitor->numOfDevicesByCap (conn, cap, flags); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + + +/** + * virNodeListDevicesByCap: + * @conn: pointer to the hypervisor connection + * @cap: capability name + * @names: array to collect the list of node device names + * @maxnames: size of @names + * @flags: flags (unused, pass 0) + * + * Collect the list of node devices with the given capability, and store + * their names in @names + * + * Returns the number of node devices found with the capability or -1 in case of error + */ +int +virNodeListDevicesByCap(virConnectPtr conn, const char *cap, + char **const names, int maxnames, + unsigned int flags) +{ + DEBUG("conn=%p, cap=%p, names=%p, maxnames=%d, flags=%d", + conn, cap, names, maxnames, flags); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (-1); + } + + if ((flags != 0) || (names == NULL) || (maxnames < 0) || (cap == NULL)) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + if (conn->deviceMonitor && conn->deviceMonitor->listDevicesByCap) + return conn->deviceMonitor->listDevicesByCap (conn, cap, names, maxnames, flags); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + + +/** + * virNodeDeviceLookupByName: + * @conn: pointer to the hypervisor connection + * @name: unique device name + * + * Lookup a node device by its name. + * + * Returns a virNodeDevicePtr if found, NULL otherwise. + */ +virNodeDevicePtr virNodeDeviceLookupByName(virConnectPtr conn, const char *name) +{ + DEBUG("conn=%p, name=%p", 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->deviceMonitor && conn->deviceMonitor->deviceLookupByName) + return conn->deviceMonitor->deviceLookupByName (conn, name); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; +} + + +/** + * virNodeDeviceCreate: + * @conn: pointer to the hypervisor connection + * @xml: XML description for new device + * @flags: flags (unused, pass 0) + * + * Creates a new node device, as described by the XML. + * [Need to describe what kinds of devices can be created this way] + * + * Returns a pointer to the new device, or NULL for error. + */ +virNodeDevicePtr virNodeDeviceCreate(virConnectPtr conn, const char *xml, + unsigned int flags) +{ + DEBUG("conn=%p, xml=%p, flags=%d", conn, xml, flags); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return NULL; + } + + if ((flags != 0) || (xml == NULL)) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return NULL; + } + + if (conn->deviceMonitor && conn->deviceMonitor->deviceCreate) + return conn->deviceMonitor->deviceCreate (conn, xml, flags); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; +} + +/** + * virNodeDeviceGetXMLDesc: + * @dev: pointer to the node device + * @flags: flags for XML generation (unused, pass 0) + * + * Fetch an XML document describing all aspects of + * the device. + * + * Return the XML document, or NULL on error + */ +char *virNodeDeviceGetXMLDesc(virNodeDevicePtr dev, unsigned int flags) +{ + DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL); + + if (!VIR_IS_CONNECTED_NODE_DEVICE(dev)) { + virLibNodeDeviceError(NULL, VIR_ERR_INVALID_NODE_DEVICE, __FUNCTION__); + return NULL; + } + + if (dev->conn->deviceMonitor && dev->conn->deviceMonitor->deviceDumpXML) + return dev->conn->deviceMonitor->deviceDumpXML (dev, flags); + + virLibConnError (dev->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; +} + + +/** + * virNodeDeviceDestroy: + * @dev: pointer to the created device + * @flags: flags (unused, pass 0) + * + * Removes a device created by virNodeDeviceCreate. + * + * Returns 0 for success, <0 for failure. + */ +int virNodeDeviceDestroy(virNodeDevicePtr dev, unsigned int flags) +{ + DEBUG("dev=%p, conn=%p, flags=%d", dev, dev ? dev->conn : NULL, flags); + + if (!VIR_IS_CONNECTED_NODE_DEVICE(dev)) { + virLibNodeDeviceError(NULL, VIR_ERR_INVALID_NODE_DEVICE, __FUNCTION__); + return (-1); + } + + if (flags != 0) { + virLibConnError(dev->conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return -1; + } + + if (dev->conn->deviceMonitor && dev->conn->deviceMonitor->deviceDestroy) + return dev->conn->deviceMonitor->deviceDestroy (dev, flags); + + virLibConnError (dev->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + + +/** + * virNodeDeviceGetName: + * @dev: the device + * + * Returns the device name. + */ +const char *virNodeDeviceGetName(virNodeDevicePtr dev) +{ + DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL); + + if (!VIR_IS_CONNECTED_NODE_DEVICE(dev)) { + virLibNodeDeviceError(NULL, VIR_ERR_INVALID_NODE_DEVICE, __FUNCTION__); + return NULL; + } + + return dev->name; +} + +/** + * virNodeDeviceGetParent: + * @dev: the device + * + * Returns the name of the device's parent, or NULL if the + * device has no parent. + */ +const char *virNodeDeviceGetParent(virNodeDevicePtr dev) +{ + DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL); + + if (!VIR_IS_CONNECTED_NODE_DEVICE(dev)) { + virLibNodeDeviceError(NULL, VIR_ERR_INVALID_NODE_DEVICE, __FUNCTION__); + return NULL; + } + + if (dev->conn->deviceMonitor && dev->conn->deviceMonitor->deviceGetParent) + return dev->conn->deviceMonitor->deviceGetParent (dev); + + virLibConnError (dev->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; +} + +/** + * virNodeDeviceNumOfCaps: + * @dev: the device + * + * Returns the number of capabilities supported by the device. + */ +int virNodeDeviceNumOfCaps(virNodeDevicePtr dev) +{ + DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL); + + if (!VIR_IS_CONNECTED_NODE_DEVICE(dev)) { + virLibNodeDeviceError(NULL, VIR_ERR_INVALID_NODE_DEVICE, __FUNCTION__); + return -1; + } + + if (dev->conn->deviceMonitor && dev->conn->deviceMonitor->deviceNumOfCaps) + return dev->conn->deviceMonitor->deviceNumOfCaps (dev); + + virLibConnError (dev->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + +/** + * virNodeDeviceListCaps: + * @dev: the device + * @names: array to collect the list of capability names + * @maxnames: size of @names + * + * Lists the names of the capabilities supported by the device. + * + * Returns the number of capability names listed in @names. + */ +int virNodeDeviceListCaps(virNodeDevicePtr dev, + char **const names, + int maxnames) +{ + DEBUG("dev=%p, conn=%p, names=%p, maxnames=%d", + dev, dev ? dev->conn : NULL, names, maxnames); + + if (!VIR_IS_CONNECTED_NODE_DEVICE(dev)) { + virLibNodeDeviceError(NULL, VIR_ERR_INVALID_NODE_DEVICE, __FUNCTION__); + return -1; + } + + if (dev->conn->deviceMonitor && dev->conn->deviceMonitor->deviceListCaps) + return dev->conn->deviceMonitor->deviceListCaps (dev, names, maxnames); + + virLibConnError (dev->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + + +/** + * virNodeDeviceFree: + * @dev: pointer to the node device + * + * Drops a reference to the node device, freeing it if + * this was the last reference. + * + * Returns the 0 for success, -1 for error. + */ +int virNodeDeviceFree(virNodeDevicePtr dev) +{ + DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL); + + if (!VIR_IS_CONNECTED_NODE_DEVICE(dev)) { + virLibNodeDeviceError(NULL, VIR_ERR_INVALID_NODE_DEVICE, __FUNCTION__); + return (-1); + } + if (virUnrefNodeDevice(dev) < 0) + return (-1); + return(0); +} + + /* * Domain Event Notification */ diff -r 78738f80cf4c src/libvirt_sym.version.in --- a/src/libvirt_sym.version.in Wed Nov 12 21:05:32 2008 +0000 +++ b/src/libvirt_sym.version.in Wed Nov 12 21:11:46 2008 +0000 @@ -232,6 +232,21 @@ virEventRegisterImpl; virConnectDomainEventRegister; virConnectDomainEventDeregister; + + virNodeNumOfDevices; + virNodeListDevices; + virNodeNumOfDevicesByCap; + virNodeListDevicesByCap; + virNodeDeviceLookupByName; + virNodeDeviceFree; + virNodeDeviceGetXMLDesc; + virNodeDeviceCreate; + virNodeDeviceDestroy; + virNodeDeviceGetName; + virNodeDeviceGetParent; + virNodeDeviceNumOfCaps; + virNodeDeviceListCaps; + } LIBVIRT_0.4.5; /* .... define new API here using predicted next version number .... */ diff -r 78738f80cf4c src/virterror.c --- a/src/virterror.c Wed Nov 12 21:05:32 2008 +0000 +++ b/src/virterror.c Wed Nov 12 21:11:46 2008 +0000 @@ -309,6 +309,9 @@ break; case VIR_FROM_DOMAIN: dom = "Domain Config "; + break; + case VIR_FROM_DEVMONITOR: + dom = "Device Monitor "; break; } @@ -719,6 +722,24 @@ else errmsg = _("Failed to find a storage driver: %s"); break; + case VIR_WAR_NO_NODE: + if (info == NULL) + errmsg = _("Failed to find a node driver"); + else + errmsg = _("Failed to find a node driver: %s"); + break; + case VIR_ERR_INVALID_NODE_DEVICE: + if (info == NULL) + errmsg = _("invalid node device pointer"); + else + errmsg = _("invalid node device pointer in %s"); + break; + case VIR_ERR_NO_NODE_DEVICE: + if (info == NULL) + errmsg = _("Node device not found"); + else + errmsg = _("Node device not found: %s"); + break; } return (errmsg); } -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Thu, Nov 13, 2008 at 05:30:29PM +0000, Daniel P. Berrange wrote:
This patch is the public API parts of the node device enumeration code. No changes since David's last submission of this, except for some Makefile tweaks
okidoc, reviewed many times already, +1 Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Hi, This is my first time looking at this, so sorry if I bring up stuff which has already been discussed at length. On the whole, this all looks pretty great ... On Thu, 2008-11-13 at 17:30 +0000, Daniel P. Berrange wrote:
This patch is the public API parts of the node device enumeration code. No changes since David's last submission of this, except for some Makefile tweaks
Daniel
diff -r 78738f80cf4c include/libvirt/libvirt.h --- a/include/libvirt/libvirt.h Wed Nov 12 21:05:32 2008 +0000 +++ b/include/libvirt/libvirt.h Wed Nov 12 21:11:46 2008 +0000 @@ -995,6 +995,74 @@ unsigned int flags);
/* + * Host device enumeration + */ + +/** + * virNodeDevice: + * + * A virNodeDevice contains a node (host) device details. + */ + +typedef struct _virNodeDevice virNodeDevice; + +/** + * virNodeDevicePtr: + * + * A virNodeDevicePtr is a pointer to a virNodeDevice structure. Get + * one via virNodeDeviceLookupByKey, virNodeDeviceLookupByName, or + * virNodeDeviceCreate. Be sure to Call virNodeDeviceFree when done + * using a virNodeDevicePtr obtained from any of the above functions to + * avoid leaking memory. + */ + +typedef virNodeDevice *virNodeDevicePtr; + + +int virNodeNumOfDevices (virConnectPtr conn, + unsigned int flags); + +int virNodeListDevices (virConnectPtr conn, + char **const names, + int maxnames, + unsigned int flags); + +int virNodeNumOfDevicesByCap (virConnectPtr conn, + const char *cap, + unsigned int flags); + +int virNodeListDevicesByCap (virConnectPtr conn, + const char *cap, + char **const names, + int maxnames, + unsigned int flags);
How about combining these two sets of functions and if the capability type isn't supplied list all devices?
+ +virNodeDevicePtr virNodeDeviceLookupByName (virConnectPtr conn, + const char *name); + +const char * virNodeDeviceGetName (virNodeDevicePtr dev); +
How stable are these names? e.g. should we say that no-one should rely on the format of the name and that the name of a given device could change across node reboots? Even if HAL guarantees the name to be stable (does it?), if you switch between HAL and DevKit it could change, right?
+const char * virNodeDeviceGetParent (virNodeDevicePtr dev);
A GetParent() but no ListChildren() seems a little strange ... Some of the hierarchy seems a little strange to me, e.g. # ./virsh node-list-devices --cap net ... net_00_13_20_f7_4a_06 # ./virsh node-device-dumpxml net_00_13_20_f7_4a_06 <device> <name>net_00_13_20_f7_4a_06</name> <parent>pci_8086_10de</parent> <capability type='net'> <interface>eth0</interface> <address>00:13:20:f7:4a:06</address> <capability type='80203'> <mac_address>001320f74a06</address> </capability> </capability> </device> # ./virsh node-device-dumpxml pci_8086_10de <device> <name>pci_8086_10de</name> <parent>computer</parent> <capability type='pci'> <domain>0</domain> <bus>0</bus> <slot>25</slot> <function>0</function> <product id='4318'>82567LM-3 Gigabit Network Connection</product> <vendor id='32902'>Intel Corporation</vendor> </capability> </device> I see that all this naturally flows from the way hal does things, but the pci device isn't a parent of the network device in any real sense ... I guess I would expect to just see one device with both the 'net' and 'pci' capabilities.
+int virNodeDeviceNumOfCaps (virNodeDevicePtr dev); + +int virNodeDeviceListCaps (virNodeDevicePtr dev, + char **const names, + int maxnames);
I think it would make more sense to me if there was a fixed set of capability types and for them to be an enum in the API rather than strings ...
+char * virNodeDeviceGetXMLDesc (virNodeDevicePtr dev, + unsigned int flags); + +virNodeDevicePtr virNodeDeviceCreate (virConnectPtr conn, + const char *xml, + unsigned int flags);
Very strange, and we don't implement it? What's the idea with this? Perhaps leave it out until we do implement it?
+int virNodeDeviceDestroy (virNodeDevicePtr dev, + unsigned int flags);
Ditto.
diff -r 78738f80cf4c include/libvirt/virterror.h --- a/include/libvirt/virterror.h Wed Nov 12 21:05:32 2008 +0000 +++ b/include/libvirt/virterror.h Wed Nov 12 21:11:46 2008 +0000 @@ -58,6 +58,7 @@ VIR_FROM_STORAGE, /* Error from storage driver */ VIR_FROM_NETWORK, /* Error from network config */ VIR_FROM_DOMAIN, /* Error from domain config */ + VIR_FROM_DEVMONITOR,/* Error from node device monitor */
This is the only time any mention of a "device monitor" is made in the public API, so it's a bit odd. Perhaps VIR_FROM_NODE ?
diff -r 78738f80cf4c src/libvirt.c --- a/src/libvirt.c Wed Nov 12 21:05:32 2008 +0000 +++ b/src/libvirt.c Wed Nov 12 21:11:46 2008 +0000 ... +/** + * virNodeDeviceGetXMLDesc: + * @dev: pointer to the node device + * @flags: flags for XML generation (unused, pass 0) + * + * Fetch an XML document describing all aspects of + * the device. + * + * Return the XML document, or NULL on error + */ +char *virNodeDeviceGetXMLDesc(virNodeDevicePtr dev, unsigned int flags) +{ + DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL); + + if (!VIR_IS_CONNECTED_NODE_DEVICE(dev)) { + virLibNodeDeviceError(NULL, VIR_ERR_INVALID_NODE_DEVICE, __FUNCTION__); + return NULL; + } + + if (dev->conn->deviceMonitor && dev->conn->deviceMonitor->deviceDumpXML) + return dev->conn->deviceMonitor->deviceDumpXML (dev, flags); + + virLibConnError (dev->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; +}
Missing check for flags == 0
+/** + * virNodeDeviceListCaps: + * @dev: the device + * @names: array to collect the list of capability names + * @maxnames: size of @names + * + * Lists the names of the capabilities supported by the device. + * + * Returns the number of capability names listed in @names. + */ +int virNodeDeviceListCaps(virNodeDevicePtr dev, + char **const names, + int maxnames) +{ + DEBUG("dev=%p, conn=%p, names=%p, maxnames=%d", + dev, dev ? dev->conn : NULL, names, maxnames); + + if (!VIR_IS_CONNECTED_NODE_DEVICE(dev)) { + virLibNodeDeviceError(NULL, VIR_ERR_INVALID_NODE_DEVICE, __FUNCTION__); + return -1; + } + + if (dev->conn->deviceMonitor && dev->conn->deviceMonitor->deviceListCaps) + return dev->conn->deviceMonitor->deviceListCaps (dev, names, maxnames); + + virLibConnError (dev->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +}
No checking of names/maxnames Cheers, Mark.

On Fri, Nov 14, 2008 at 12:46:09PM +0000, Mark McLoughlin wrote:
On Thu, 2008-11-13 at 17:30 +0000, Daniel P. Berrange wrote:
This patch is the public API parts of the node device enumeration code. No changes since David's last submission of this, except for some Makefile tweaks
+ +int virNodeNumOfDevices (virConnectPtr conn, + unsigned int flags); + +int virNodeListDevices (virConnectPtr conn, + char **const names, + int maxnames, + unsigned int flags); + +int virNodeNumOfDevicesByCap (virConnectPtr conn, + const char *cap, + unsigned int flags); + +int virNodeListDevicesByCap (virConnectPtr conn, + const char *cap, + char **const names, + int maxnames, + unsigned int flags);
How about combining these two sets of functions and if the capability type isn't supplied list all devices?
Yes, we could just remove the ByCap APIs, and add the 'const char *cap' arg to the first two APIs, allowing NULL.
+ +virNodeDevicePtr virNodeDeviceLookupByName (virConnectPtr conn, + const char *name); + +const char * virNodeDeviceGetName (virNodeDevicePtr dev); +
How stable are these names? e.g. should we say that no-one should rely on the format of the name and that the name of a given device could change across node reboots? Even if HAL guarantees the name to be stable (does it?), if you switch between HAL and DevKit it could change, right?
I don't think HAL explicitly guarentees it, it merely happens to have been stable AFAICT. The naming is definitely completely different between HAL and DevKit. This is probably my biggest worry with the impl so far - some app using it will need to have a stable identifier for a device and we won't be providing it. We could invent our own stable naming scheme for devices - the scheme would vary per capability - eg for PCI devices we can use the bus, function, slot identifiers. USB is hard to guarentee though - if a device is plugged in & unpluged & plugged in again it won't get the same address, and there's no real other identifier we can rely on for this.
+const char * virNodeDeviceGetParent (virNodeDevicePtr dev);
A GetParent() but no ListChildren() seems a little strange ...
Some of the hierarchy seems a little strange to me, e.g.
# ./virsh node-list-devices --cap net ... net_00_13_20_f7_4a_06 # ./virsh node-device-dumpxml net_00_13_20_f7_4a_06 <device> <name>net_00_13_20_f7_4a_06</name> <parent>pci_8086_10de</parent> <capability type='net'> <interface>eth0</interface> <address>00:13:20:f7:4a:06</address> <capability type='80203'> <mac_address>001320f74a06</address> </capability> </capability> </device> # ./virsh node-device-dumpxml pci_8086_10de <device> <name>pci_8086_10de</name> <parent>computer</parent> <capability type='pci'> <domain>0</domain> <bus>0</bus> <slot>25</slot> <function>0</function> <product id='4318'>82567LM-3 Gigabit Network Connection</product> <vendor id='32902'>Intel Corporation</vendor> </capability> </device>
I see that all this naturally flows from the way hal does things, but the pci device isn't a parent of the network device in any real sense ... I guess I would expect to just see one device with both the 'net' and 'pci' capabilities.
So that's basically removing all explicit tracking of 'logical' devices (NICs, disk, etc) and only ever representing 'physical' devices (PCI, USB devices). The problem I can see is that one physical device can result in many logical devices - even multiple instances of the same capability - particularly multi-function USB devices can result in a large number of sub-devices for audio, video, etc. Or a SCSI host adapter can have a single PCI device, but result in multiple host adapters in the OS view. Separating the physical from logical devices gives us the opportunity to define more stable names for devices with certain capabilities. eg, for a USB network card, its hard to invent a stable name at the level of the USB device, but for the logical NIC you can easily invent a name based off the MAC address.
+int virNodeDeviceNumOfCaps (virNodeDevicePtr dev); + +int virNodeDeviceListCaps (virNodeDevicePtr dev, + char **const names, + int maxnames);
I think it would make more sense to me if there was a fixed set of capability types and for them to be an enum in the API rather than strings ...
+char * virNodeDeviceGetXMLDesc (virNodeDevicePtr dev, + unsigned int flags); + +virNodeDevicePtr virNodeDeviceCreate (virConnectPtr conn, + const char *xml, + unsigned int flags);
Very strange, and we don't implement it? What's the idea with this? Perhaps leave it out until we do implement it?
This is for SCSI FiberChannel adapters with NPIV support. They let you create many virtual HBAs on the fly, which appear in /sys/class/scsi_host on Linux alongside so called 'real' HBAs. You're right though, we can simply leave this out until we actually implement NPIV support. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Fri, 2008-11-14 at 13:28 +0000, Daniel P. Berrange wrote:
On Fri, Nov 14, 2008 at 12:46:09PM +0000, Mark McLoughlin wrote:
On Thu, 2008-11-13 at 17:30 +0000, Daniel P. Berrange wrote:
This patch is the public API parts of the node device enumeration code. No changes since David's last submission of this, except for some Makefile tweaks
+ +int virNodeNumOfDevices (virConnectPtr conn, + unsigned int flags); + +int virNodeListDevices (virConnectPtr conn, + char **const names, + int maxnames, + unsigned int flags); + +int virNodeNumOfDevicesByCap (virConnectPtr conn, + const char *cap, + unsigned int flags); + +int virNodeListDevicesByCap (virConnectPtr conn, + const char *cap, + char **const names, + int maxnames, + unsigned int flags);
How about combining these two sets of functions and if the capability type isn't supplied list all devices?
Yes, we could just remove the ByCap APIs, and add the 'const char *cap' arg to the first two APIs, allowing NULL.
I like this idea as well.
+ +virNodeDevicePtr virNodeDeviceLookupByName (virConnectPtr conn, + const char *name); + +const char * virNodeDeviceGetName (virNodeDevicePtr dev); +
How stable are these names? e.g. should we say that no-one should rely on the format of the name and that the name of a given device could change across node reboots? Even if HAL guarantees the name to be stable (does it?), if you switch between HAL and DevKit it could change, right?
I don't think HAL explicitly guarentees it, it merely happens to have been stable AFAICT. The naming is definitely completely different between HAL and DevKit.
This is probably my biggest worry with the impl so far - some app using it will need to have a stable identifier for a device and we won't be providing it.
We could invent our own stable naming scheme for devices - the scheme would vary per capability - eg for PCI devices we can use the bus, function, slot identifiers. USB is hard to guarentee though - if a device is plugged in & unpluged & plugged in again it won't get the same address, and there's no real other identifier we can rely on for this.
Yep. But I think HAL is already trying to specify "stable names" wherever possible. E.g., PCI devs aren't named by position on bus, but by vendor-id/product-id, so that a PCI impl supporting hotplug will give the same name for the card if it's taken out and reinserted (well, more or less ...). Perhaps we could just identify where we think HAL gets it wrong, and implement our own naming scheme for those devices (assuming we can come up with one we like better), and using the HAL names for the rest??
I see that all this naturally flows from the way hal does things, but the pci device isn't a parent of the network device in any real sense ... I guess I would expect to just see one device with both the 'net' and 'pci' capabilities.
So that's basically removing all explicit tracking of 'logical' devices (NICs, disk, etc) and only ever representing 'physical' devices (PCI, USB devices). The problem I can see is that one physical device can result in many logical devices - even multiple instances of the same capability - particularly multi-function USB devices can result in a large number of sub-devices for audio, video, etc.
Or a SCSI host adapter can have a single PCI device, but result in multiple host adapters in the OS view.
Separating the physical from logical devices gives us the opportunity to define more stable names for devices with certain capabilities. eg, for a USB network card, its hard to invent a stable name at the level of the USB device, but for the logical NIC you can easily invent a name based off the MAC address.
Agreed. I think this extra level of heirarchy is useful, though I originally found it confusing.
+int virNodeDeviceNumOfCaps (virNodeDevicePtr dev); + +int virNodeDeviceListCaps (virNodeDevicePtr dev, + char **const names, + int maxnames);
I think it would make more sense to me if there was a fixed set of capability types and for them to be an enum in the API rather than strings ...
I have no objection to this. Dave

On Fri, Nov 14, 2008 at 01:57:26PM -0500, David Lively wrote:
On Fri, 2008-11-14 at 13:28 +0000, Daniel P. Berrange wrote:
On Fri, Nov 14, 2008 at 12:46:09PM +0000, Mark McLoughlin wrote:
On Thu, 2008-11-13 at 17:30 +0000, Daniel P. Berrange wrote:
This patch is the public API parts of the node device enumeration code. No changes since David's last submission of this, except for some Makefile tweaks
+ +int virNodeNumOfDevices (virConnectPtr conn, + unsigned int flags); + +int virNodeListDevices (virConnectPtr conn, + char **const names, + int maxnames, + unsigned int flags); + +int virNodeNumOfDevicesByCap (virConnectPtr conn, + const char *cap, + unsigned int flags); + +int virNodeListDevicesByCap (virConnectPtr conn, + const char *cap, + char **const names, + int maxnames, + unsigned int flags);
How about combining these two sets of functions and if the capability type isn't supplied list all devices?
Yes, we could just remove the ByCap APIs, and add the 'const char *cap' arg to the first two APIs, allowing NULL.
I like this idea as well.
Okay, then let's do this ! Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Fri, 2008-11-14 at 13:28 +0000, Daniel P. Berrange wrote:
On Fri, Nov 14, 2008 at 12:46:09PM +0000, Mark McLoughlin wrote:
On Thu, 2008-11-13 at 17:30 +0000, Daniel P. Berrange wrote:
+ +virNodeDevicePtr virNodeDeviceLookupByName (virConnectPtr conn, + const char *name); + +const char * virNodeDeviceGetName (virNodeDevicePtr dev); +
How stable are these names? e.g. should we say that no-one should rely on the format of the name and that the name of a given device could change across node reboots? Even if HAL guarantees the name to be stable (does it?), if you switch between HAL and DevKit it could change, right?
I don't think HAL explicitly guarentees it, it merely happens to have been stable AFAICT. The naming is definitely completely different between HAL and DevKit.
This is probably my biggest worry with the impl so far - some app using it will need to have a stable identifier for a device and we won't be providing it.
I don't have a good understanding of what this API will be used for, aside from device passthrough. I wouldn't be surprised if we decide that it makes sense to allow using higher level names for passthrough, rather than e.g. PCI IDs - i.e. passthrough "device with mac address X" rather than vendor:device or bus:dev.func. In that case, you need the names to be stable, but you don't necessarily need them to have a predictable enough structure that people can construct a name themselves.
We could invent our own stable naming scheme for devices - the scheme would vary per capability - eg for PCI devices we can use the bus, function, slot identifiers. USB is hard to guarentee though - if a device is plugged in & unpluged & plugged in again it won't get the same address, and there's no real other identifier we can rely on for this.
I think the key thing in the short term is that we make it clear that device names are completely unstable identifiers with no structure or meaning that can be relied upon. I'd almost be tempted to append a few bytes of randomness to the names for now ...
Separating the physical from logical devices gives us the opportunity to define more stable names for devices with certain capabilities. eg, for a USB network card, its hard to invent a stable name at the level of the USB device, but for the logical NIC you can easily invent a name based off the MAC address.
Another way would be to have multiple names for each device, by aggregating the "PCI device" and "network device" capabilities into a single object. The only really advantage to that would be that given a less specialized name for a device, you could easily iterate over the more specialized names. But if we need that we could add virNodeDeviceListChildren() I guess. IOW, the current scheme will probably work out just fine ... Cheers, Mark.

This is the basic internal driver support code for the node device APIs. The actual registration of the drivers was pushed to a later patch to allow this to compile on its own & thus be fully bisectable. Daniel diff -r 6812c3044043 src/Makefile.am --- a/src/Makefile.am Wed Nov 12 21:11:46 2008 +0000 +++ b/src/Makefile.am Wed Nov 12 21:11:51 2008 +0000 @@ -132,6 +132,10 @@ storage_driver.h storage_driver.c \ storage_backend.h storage_backend.c +# Network driver generic impl APIs +NODE_DEVICE_CONF_SOURCES = \ + node_device_conf.c node_device_conf.h + STORAGE_DRIVER_FS_SOURCES = \ storage_backend_fs.h storage_backend_fs.c @@ -167,7 +171,8 @@ $(DRIVER_SOURCES) \ $(DOMAIN_CONF_SOURCES) \ $(NETWORK_CONF_SOURCES) \ - $(STORAGE_CONF_SOURCES) + $(STORAGE_CONF_SOURCES) \ + $(NODE_DEVICE_CONF_SOURCES) if WITH_TEST if WITH_DRIVER_MODULES diff -r 6812c3044043 src/node_device_conf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/node_device_conf.c Wed Nov 12 21:11:51 2008 +0000 @@ -0,0 +1,425 @@ +/* + * node_device_conf.c: config handling for node devices + * + * Copyright (C) 2008 Virtual Iron Software, Inc. + * Copyright (C) 2008 David F. Lively + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: David F. Lively <dlively@virtualiron.com> + */ + +#include <config.h> + +#include <unistd.h> +#include <errno.h> + +#include "virterror_internal.h" +#include "memory.h" + +#include "node_device_conf.h" +#include "memory.h" +#include "xml.h" +#include "util.h" +#include "buf.h" +#include "uuid.h" + + +VIR_ENUM_IMPL(virNodeDevCap, VIR_NODE_DEV_CAP_LAST, + "system", + "pci", + "usb_device", + "usb", + "net", + "block", + "scsi_host", + "scsi", + "storage"); + +VIR_ENUM_IMPL(virNodeDevNetCap, VIR_NODE_DEV_CAP_NET_LAST, + "80203", + "80211"); + + +#define virNodeDeviceLog(msg...) fprintf(stderr, msg) + +virNodeDeviceObjPtr virNodeDeviceFindByName(const virNodeDeviceObjListPtr devs, + const char *name) +{ + unsigned int i; + + for (i = 0; i < devs->count; i++) + if (STREQ(devs->objs[i]->def->name, name)) + return devs->objs[i]; + + return NULL; +} + + +void virNodeDeviceDefFree(virNodeDeviceDefPtr def) +{ + virNodeDevCapsDefPtr caps; + + if (!def) + return; + + VIR_FREE(def->name); + VIR_FREE(def->parent); + + caps = def->caps; + while (caps) { + virNodeDevCapsDefPtr next = caps->next; + virNodeDevCapsDefFree(caps); + caps = next; + } + + VIR_FREE(def); +} + +void virNodeDeviceObjFree(virNodeDeviceObjPtr dev) +{ + if (!dev) + return; + + virNodeDeviceDefFree(dev->def); + if (dev->privateFree) + (*dev->privateFree)(dev->privateData); + + VIR_FREE(dev); +} + +void virNodeDeviceObjListFree(virNodeDeviceObjListPtr devs) +{ + unsigned int i; + for (i = 0 ; i < devs->count ; i++) + virNodeDeviceObjFree(devs->objs[i]); + VIR_FREE(devs->objs); + devs->count = 0; +} + +virNodeDeviceObjPtr virNodeDeviceAssignDef(virConnectPtr conn, + virNodeDeviceObjListPtr devs, + const virNodeDeviceDefPtr def) +{ + virNodeDeviceObjPtr device; + + if ((device = virNodeDeviceFindByName(devs, def->name))) { + virNodeDeviceDefFree(device->def); + device->def = def; + return device; + } + + if (VIR_ALLOC(device) < 0) { + virNodeDeviceReportError(conn, VIR_ERR_NO_MEMORY, NULL); + return NULL; + } + + device->def = def; + + if (VIR_REALLOC_N(devs->objs, devs->count+1) < 0) { + device->def = NULL; + virNodeDeviceObjFree(device); + virNodeDeviceReportError(conn, VIR_ERR_NO_MEMORY, NULL); + return NULL; + } + devs->objs[devs->count++] = device; + + return device; + +} + +void virNodeDeviceObjRemove(virNodeDeviceObjListPtr devs, + const virNodeDeviceObjPtr dev) +{ + unsigned int i; + + for (i = 0; i < devs->count; i++) { + if (devs->objs[i] == dev) { + virNodeDeviceObjFree(devs->objs[i]); + + if (i < (devs->count - 1)) + memmove(devs->objs + i, devs->objs + i + 1, + sizeof(*(devs->objs)) * (devs->count - (i + 1))); + + if (VIR_REALLOC_N(devs->objs, devs->count - 1) < 0) { + ; /* Failure to reduce memory allocation isn't fatal */ + } + devs->count--; + + break; + } + } +} + +char *virNodeDeviceDefFormat(virConnectPtr conn, + const virNodeDeviceDefPtr def) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + virNodeDevCapsDefPtr caps = def->caps; + char *tmp; + + virBufferAddLit(&buf, "<device>\n"); + virBufferEscapeString(&buf, " <name>%s</name>\n", def->name); + + if (def->parent) + virBufferEscapeString(&buf, " <parent>%s</parent>\n", def->parent); + + for (caps = def->caps; caps; caps = caps->next) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + union _virNodeDevCapData *data = &caps->data; + + virBufferVSprintf(&buf, " <capability type='%s'>\n", + virNodeDevCapTypeToString(caps->type)); + switch (caps->type) { + case VIR_NODE_DEV_CAP_SYSTEM: + if (data->system.product_name) + virBufferEscapeString(&buf, " <product>%s</product>\n", + data->system.product_name); + virBufferAddLit(&buf, " <hardware>\n"); + if (data->system.hardware.vendor_name) + virBufferEscapeString(&buf, " <vendor>%s</vendor>\n", + data->system.hardware.vendor_name); + if (data->system.hardware.version) + virBufferEscapeString(&buf, " <version>%s</version>\n", + data->system.hardware.version); + if (data->system.hardware.serial) + virBufferEscapeString(&buf, " <serial>%s</serial>\n", + data->system.hardware.serial); + virUUIDFormat(data->system.hardware.uuid, uuidstr); + virBufferVSprintf(&buf, " <uuid>%s</uuid>\n", uuidstr); + virBufferAddLit(&buf, " </hardware>\n"); + virBufferAddLit(&buf, " <firmware>\n"); + if (data->system.firmware.vendor_name) + virBufferEscapeString(&buf, " <vendor>%s</vendor>\n", + data->system.firmware.vendor_name); + if (data->system.firmware.version) + virBufferEscapeString(&buf, " <version>%s</version>\n", + data->system.firmware.version); + if (data->system.firmware.release_date) + virBufferEscapeString(&buf, + " <release_date>%s</release_date>\n", + data->system.firmware.release_date); + virBufferAddLit(&buf, " </firmware>\n"); + break; + case VIR_NODE_DEV_CAP_PCI_DEV: + virBufferVSprintf(&buf, " <domain>%d</domain>\n", + data->pci_dev.domain); + virBufferVSprintf(&buf, " <bus>%d</bus>\n", data->pci_dev.bus); + virBufferVSprintf(&buf, " <slot>%d</slot>\n", + data->pci_dev.slot); + virBufferVSprintf(&buf, " <function>%d</function>\n", + data->pci_dev.function); + virBufferVSprintf(&buf, " <product id='%d'", + data->pci_dev.product); + if (data->pci_dev.product_name) + virBufferEscapeString(&buf, ">%s</product>\n", + data->pci_dev.product_name); + else + virBufferAddLit(&buf, " />\n"); + virBufferVSprintf(&buf, " <vendor id='%d'", + data->pci_dev.vendor); + if (data->pci_dev.vendor_name) + virBufferEscapeString(&buf, ">%s</vendor>\n", + data->pci_dev.vendor_name); + else + virBufferAddLit(&buf, " />\n"); + break; + case VIR_NODE_DEV_CAP_USB_DEV: + virBufferVSprintf(&buf, " <bus>%d</bus>\n", data->usb_dev.bus); + virBufferVSprintf(&buf, " <device>%d</device>\n", + data->usb_dev.device); + virBufferVSprintf(&buf, " <product id='%d'", + data->usb_dev.product); + if (data->usb_dev.product_name) + virBufferEscapeString(&buf, ">%s</product>\n", + data->usb_dev.product_name); + else + virBufferAddLit(&buf, " />\n"); + virBufferVSprintf(&buf, " <vendor id='%d'", + data->usb_dev.vendor); + if (data->usb_dev.vendor_name) + virBufferEscapeString(&buf, ">%s</vendor>\n", + data->usb_dev.vendor_name); + else + virBufferAddLit(&buf, " />\n"); + break; + case VIR_NODE_DEV_CAP_USB_INTERFACE: + virBufferVSprintf(&buf, " <number>%d</number>\n", + data->usb_if.number); + virBufferVSprintf(&buf, " <class>%d</class>\n", + data->usb_if._class); + virBufferVSprintf(&buf, " <subclass>%d</subclass>\n", + data->usb_if.subclass); + virBufferVSprintf(&buf, " <protocol>%d</protocol>\n", + data->usb_if.protocol); + if (data->usb_if.description) + virBufferVSprintf(&buf, " <description>%s</description>\n", + data->usb_if.description); + break; + case VIR_NODE_DEV_CAP_NET: + virBufferVSprintf(&buf, " <interface>%s</interface>\n", + data->net.interface); + if (data->net.address) + virBufferVSprintf(&buf, " <address>%s</address>\n", + data->net.address); + if (data->net.subtype != VIR_NODE_DEV_CAP_NET_LAST) { + const char *subtyp = + virNodeDevNetCapTypeToString(data->net.subtype); + virBufferVSprintf(&buf, " <capability type='%s'>\n", subtyp); + switch (data->net.subtype) { + case VIR_NODE_DEV_CAP_NET_80203: + virBufferVSprintf(&buf, + " <mac_address>%012llx</address>\n", + data->net.data.ieee80203.mac_address); + break; + case VIR_NODE_DEV_CAP_NET_80211: + virBufferVSprintf(&buf, + " <mac_address>%012llx</address>\n", + data->net.data.ieee80211.mac_address); + break; + case VIR_NODE_DEV_CAP_NET_LAST: + /* Keep dumb compiler happy */ + break; + } + virBufferAddLit(&buf, " </capability>\n"); + } + break; + case VIR_NODE_DEV_CAP_BLOCK: + virBufferVSprintf(&buf, " <device>%s</device>\n", + data->block.device); + break; + case VIR_NODE_DEV_CAP_SCSI_HOST: + virBufferVSprintf(&buf, " <host>%d</host>\n", + data->scsi_host.host); + break; + case VIR_NODE_DEV_CAP_SCSI: + virBufferVSprintf(&buf, " <host>%d</host>\n", data->scsi.host); + virBufferVSprintf(&buf, " <bus>%d</bus>\n", data->scsi.bus); + virBufferVSprintf(&buf, " <target>%d</target>\n", + data->scsi.target); + virBufferVSprintf(&buf, " <lun>%d</lun>\n", data->scsi.lun); + if (data->scsi.type) + virBufferVSprintf(&buf, " <type>%s</type>\n", + data->scsi.type); + break; + case VIR_NODE_DEV_CAP_STORAGE: + if (data->storage.bus) + virBufferVSprintf(&buf, " <bus>%s</bus>\n", + data->storage.bus); + if (data->storage.drive_type) + virBufferVSprintf(&buf, " <drive_type>%s</drive_type>\n", + data->storage.drive_type); + if (data->storage.originating_device) + virBufferVSprintf(&buf, + " <originating_device>%s" + "</originating_device>\n", + data->storage.originating_device); + if (data->storage.model) + virBufferVSprintf(&buf, " <model>%s</model>\n", + data->storage.model); + if (data->storage.vendor) + virBufferVSprintf(&buf, " <vendor>%s</vendor>\n", + data->storage.vendor); + if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_REMOVABLE) { + int avl = data->storage.flags & + VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE; + virBufferAddLit(&buf, " <capability type='removable'>\n"); + virBufferVSprintf(&buf, + " <media_available>%d" + "</media_available>\n", avl ? 1 : 0); + virBufferVSprintf(&buf, " <media_size>%llu</media_size>\n", + data->storage.removable_media_size); + virBufferAddLit(&buf, " </capability>\n"); + } else { + virBufferVSprintf(&buf, " <size>%llu</size>\n", + data->storage.size); + } + if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE) + virBufferAddLit(&buf, + " <capability type='hotpluggable' />\n"); + break; + case VIR_NODE_DEV_CAP_LAST: + /* ignore special LAST value */ + break; + } + + virBufferAddLit(&buf, " </capability>\n"); + } + + virBufferAddLit(&buf, "</device>\n"); + + if (virBufferError(&buf)) + goto no_memory; + + return virBufferContentAndReset(&buf); + + no_memory: + virNodeDeviceReportError(conn, VIR_ERR_NO_MEMORY, NULL); + tmp = virBufferContentAndReset(&buf); + VIR_FREE(tmp); + return NULL; +} + +void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps) +{ + union _virNodeDevCapData *data = &caps->data; + + switch (caps->type) { + case VIR_NODE_DEV_CAP_SYSTEM: + VIR_FREE(data->system.product_name); + VIR_FREE(data->system.hardware.vendor_name); + VIR_FREE(data->system.hardware.version); + VIR_FREE(data->system.hardware.serial); + VIR_FREE(data->system.firmware.vendor_name); + VIR_FREE(data->system.firmware.version); + VIR_FREE(data->system.firmware.release_date); + break; + case VIR_NODE_DEV_CAP_PCI_DEV: + VIR_FREE(data->pci_dev.product_name); + VIR_FREE(data->pci_dev.vendor_name); + break; + case VIR_NODE_DEV_CAP_USB_DEV: + VIR_FREE(data->usb_dev.product_name); + VIR_FREE(data->usb_dev.vendor_name); + break; + case VIR_NODE_DEV_CAP_USB_INTERFACE: + VIR_FREE(data->usb_if.description); + break; + case VIR_NODE_DEV_CAP_NET: + VIR_FREE(data->net.interface); + VIR_FREE(data->net.address); + break; + case VIR_NODE_DEV_CAP_BLOCK: + VIR_FREE(data->block.device); + break; + case VIR_NODE_DEV_CAP_SCSI_HOST: + break; + case VIR_NODE_DEV_CAP_SCSI: + VIR_FREE(data->scsi.type); + break; + case VIR_NODE_DEV_CAP_STORAGE: + VIR_FREE(data->storage.bus); + VIR_FREE(data->storage.drive_type); + VIR_FREE(data->storage.model); + VIR_FREE(data->storage.vendor); + break; + case VIR_NODE_DEV_CAP_LAST: + /* This case is here to shutup the compiler */ + break; + } + + VIR_FREE(caps); +} + diff -r 6812c3044043 src/node_device_conf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/node_device_conf.h Wed Nov 12 21:11:51 2008 +0000 @@ -0,0 +1,204 @@ +/* + * node_device_conf.h: config handling for node devices + * + * Copyright (C) 2008 Virtual Iron Software, Inc. + * Copyright (C) 2008 David F. Lively + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: David F. Lively <dlively@virtualiron.com> + */ + +#ifndef __VIR_NODE_DEVICE_CONF_H__ +#define __VIR_NODE_DEVICE_CONF_H__ + +#include "internal.h" +#include "util.h" + +enum virNodeDevCapType { + /* Keep in sync with VIR_ENUM_IMPL in node_device_conf.c */ + VIR_NODE_DEV_CAP_SYSTEM, /* System capability */ + VIR_NODE_DEV_CAP_PCI_DEV, /* PCI device */ + VIR_NODE_DEV_CAP_USB_DEV, /* USB device */ + VIR_NODE_DEV_CAP_USB_INTERFACE, /* USB interface */ + VIR_NODE_DEV_CAP_NET, /* Network device */ + VIR_NODE_DEV_CAP_BLOCK, /* Block device */ + VIR_NODE_DEV_CAP_SCSI_HOST, /* SCSI Host Bus Adapter */ + VIR_NODE_DEV_CAP_SCSI, /* SCSI device */ + VIR_NODE_DEV_CAP_STORAGE, /* Storage device */ + VIR_NODE_DEV_CAP_LAST +}; + +enum virNodeDevNetCapType { + /* Keep in sync with VIR_ENUM_IMPL in node_device_conf.c */ + VIR_NODE_DEV_CAP_NET_80203, /* 802.03 network device */ + VIR_NODE_DEV_CAP_NET_80211, /* 802.11 network device */ + VIR_NODE_DEV_CAP_NET_LAST +}; + +VIR_ENUM_DECL(virNodeDevCap); +VIR_ENUM_DECL(virNodeDevNetCap); + +enum virNodeDevStorageCapFlags { + VIR_NODE_DEV_CAP_STORAGE_REMOVABLE = (1 << 0), + VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE = (1 << 1), + VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE = (1 << 2), +}; + +typedef struct _virNodeDevCapsDef virNodeDevCapsDef; +typedef virNodeDevCapsDef *virNodeDevCapsDefPtr; +struct _virNodeDevCapsDef { + enum virNodeDevCapType type; + union _virNodeDevCapData { + struct { + char *product_name; + struct { + char *vendor_name; + char *version; + char *serial; + unsigned char uuid[VIR_UUID_BUFLEN]; + } hardware; + struct { + char *vendor_name; + char *version; + char *release_date; + } firmware; + } system; + struct { + unsigned domain; + unsigned bus; + unsigned slot; + unsigned function; + unsigned product; + unsigned vendor; + char *product_name; + char *vendor_name; + } pci_dev; + struct { + unsigned bus; + unsigned device; + unsigned product; + unsigned vendor; + char *product_name; + char *vendor_name; + } usb_dev; + struct { + unsigned number; + unsigned _class; /* "class" is reserved in C */ + unsigned subclass; + unsigned protocol; + char *description; + } usb_if; + struct { + char *address; + char *interface; + enum virNodeDevNetCapType subtype; /* LAST -> no subtype */ + union { + struct { + unsigned long long mac_address; + } ieee80203; + struct { + unsigned long long mac_address; + } ieee80211; + } data; + } net; + struct { + char *device; + } block; + struct { + unsigned host; + } scsi_host; + struct { + unsigned host; + unsigned bus; + unsigned target; + unsigned lun; + char *type; + } scsi; + struct { + unsigned long long size; + unsigned long long removable_media_size; + char *bus; + char *drive_type; + char *originating_device; + char *model; + char *vendor; + unsigned flags; /* virNodeDevStorageCapFlags bits */ + } storage; + } data; + virNodeDevCapsDefPtr next; /* next capability */ +}; + + +typedef struct _virNodeDeviceDef virNodeDeviceDef; +typedef virNodeDeviceDef *virNodeDeviceDefPtr; +struct _virNodeDeviceDef { + char *name; /* device name (unique on node) */ + char *parent; /* optional parent device name */ + virNodeDevCapsDefPtr caps; /* optional device capabilities */ +}; + + +typedef struct _virNodeDeviceObj virNodeDeviceObj; +typedef virNodeDeviceObj *virNodeDeviceObjPtr; +struct _virNodeDeviceObj { + virNodeDeviceDefPtr def; /* device definition */ + void *privateData; /* driver-specific private data */ + void (*privateFree)(void *data); /* destructor for private data */ + +}; + +typedef struct _virNodeDeviceObjList virNodeDeviceObjList; +typedef virNodeDeviceObjList *virNodeDeviceObjListPtr; +struct _virNodeDeviceObjList { + unsigned int count; + virNodeDeviceObjPtr *objs; +}; + +typedef struct _virDeviceMonitorState virDeviceMonitorState; +typedef virDeviceMonitorState *virDeviceMonitorStatePtr; +struct _virDeviceMonitorState { + virNodeDeviceObjList devs; /* currently-known devices */ + void *privateData; /* driver-specific private data */ +}; + +#define virNodeDeviceReportError(conn, code, fmt...) \ + virReportErrorHelper(conn, VIR_FROM_DEVMONITOR, code, __FILE__, \ + __FUNCTION__, __LINE__, fmt) + +virNodeDeviceObjPtr virNodeDeviceFindByName(const virNodeDeviceObjListPtr devs, + const char *name); + +virNodeDeviceObjPtr virNodeDeviceAssignDef(virConnectPtr conn, + virNodeDeviceObjListPtr devs, + const virNodeDeviceDefPtr def); + +void virNodeDeviceObjRemove(virNodeDeviceObjListPtr devs, + const virNodeDeviceObjPtr dev); + +char *virNodeDeviceDefFormat(virConnectPtr conn, + const virNodeDeviceDefPtr def); + +// TODO: virNodeDeviceDefParseString/File/Node for virNodeDeviceCreate + +void virNodeDeviceDefFree(virNodeDeviceDefPtr def); + +void virNodeDeviceObjFree(virNodeDeviceObjPtr dev); + +void virNodeDeviceObjListFree(virNodeDeviceObjListPtr devs); + +void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps); + +#endif /* __VIR_NODE_DEVICE_CONF_H__ */ -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Thu, Nov 13, 2008 at 05:31:31PM +0000, Daniel P. Berrange wrote:
This is the basic internal driver support code for the node device APIs. The actual registration of the drivers was pushed to a later patch to allow this to compile on its own & thus be fully bisectable.
that was largely reviewed too, +1 Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Thu, 2008-11-13 at 17:31 +0000, Daniel P. Berrange wrote:
This is the basic internal driver support code for the node device APIs. The actual registration of the drivers was pushed to a later patch to allow this to compile on its own & thus be fully bisectable.
Daniel
diff -r 6812c3044043 src/Makefile.am --- a/src/Makefile.am Wed Nov 12 21:11:46 2008 +0000 +++ b/src/Makefile.am Wed Nov 12 21:11:51 2008 +0000 @@ -132,6 +132,10 @@ storage_driver.h storage_driver.c \ storage_backend.h storage_backend.c
+# Network driver generic impl APIs
Typo
+NODE_DEVICE_CONF_SOURCES = \ + node_device_conf.c node_device_conf.h + ... diff -r 6812c3044043 src/node_device_conf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/node_device_conf.c Wed Nov 12 21:11:51 2008 +0000 ... +char *virNodeDeviceDefFormat(virConnectPtr conn, + const virNodeDeviceDefPtr def) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + virNodeDevCapsDefPtr caps = def->caps; + char *tmp; + + virBufferAddLit(&buf, "<device>\n"); + virBufferEscapeString(&buf, " <name>%s</name>\n", def->name); + + if (def->parent) + virBufferEscapeString(&buf, " <parent>%s</parent>\n", def->parent); + + for (caps = def->caps; caps; caps = caps->next) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + union _virNodeDevCapData *data = &caps->data; + + virBufferVSprintf(&buf, " <capability type='%s'>\n", + virNodeDevCapTypeToString(caps->type)); + switch (caps->type) { ... + case VIR_NODE_DEV_CAP_NET: + virBufferVSprintf(&buf, " <interface>%s</interface>\n", + data->net.interface); + if (data->net.address) + virBufferVSprintf(&buf, " <address>%s</address>\n", + data->net.address); + if (data->net.subtype != VIR_NODE_DEV_CAP_NET_LAST) { + const char *subtyp = + virNodeDevNetCapTypeToString(data->net.subtype); + virBufferVSprintf(&buf, " <capability type='%s'>\n", subtyp); + switch (data->net.subtype) { + case VIR_NODE_DEV_CAP_NET_80203: + virBufferVSprintf(&buf, + " <mac_address>%012llx</address>\n", + data->net.data.ieee80203.mac_address); + break; + case VIR_NODE_DEV_CAP_NET_80211: + virBufferVSprintf(&buf, + " <mac_address>%012llx</address>\n", + data->net.data.ieee80211.mac_address); + break; + case VIR_NODE_DEV_CAP_NET_LAST: + /* Keep dumb compiler happy */ + break; + } + virBufferAddLit(&buf, " </capability>\n");
This all seems a bit odd. We've listed the mac address once already, so why do it again in a hex format? And I wouldn't think of "802.3 vs 802.11" as a network device capability, but more like it's "type" - they're mutually exclusive, right? Also, we have: <device> ... <capability type='net'> ... <capability type='80203'> <mac_address>001320f74a06</address> </capability> </capability> </device> i.e. two different capability semantics?
+ } + break; + case VIR_NODE_DEV_CAP_BLOCK: + virBufferVSprintf(&buf, " <device>%s</device>\n", + data->block.device);
Two nested <device> nodes: <device> ... <capability type='block'> <device>/dev/sda1</device> </capability> </device> How about <path> or <device_path> ?
+ break; + case VIR_NODE_DEV_CAP_SCSI_HOST: + virBufferVSprintf(&buf, " <host>%d</host>\n", + data->scsi_host.host); + break; + case VIR_NODE_DEV_CAP_SCSI: + virBufferVSprintf(&buf, " <host>%d</host>\n", data->scsi.host); + virBufferVSprintf(&buf, " <bus>%d</bus>\n", data->scsi.bus); + virBufferVSprintf(&buf, " <target>%d</target>\n", + data->scsi.target); + virBufferVSprintf(&buf, " <lun>%d</lun>\n", data->scsi.lun); + if (data->scsi.type) + virBufferVSprintf(&buf, " <type>%s</type>\n", + data->scsi.type); + break; + case VIR_NODE_DEV_CAP_STORAGE: + if (data->storage.bus) + virBufferVSprintf(&buf, " <bus>%s</bus>\n", + data->storage.bus); + if (data->storage.drive_type) + virBufferVSprintf(&buf, " <drive_type>%s</drive_type>\n", + data->storage.drive_type); + if (data->storage.originating_device) + virBufferVSprintf(&buf, + " <originating_device>%s" + "</originating_device>\n", + data->storage.originating_device);
This originating_device thing sounds strange, and I don't think we implement it yet. Leave it out for now?
+ if (data->storage.model) + virBufferVSprintf(&buf, " <model>%s</model>\n", + data->storage.model); + if (data->storage.vendor) + virBufferVSprintf(&buf, " <vendor>%s</vendor>\n", + data->storage.vendor); + if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_REMOVABLE) { + int avl = data->storage.flags & + VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE; + virBufferAddLit(&buf, " <capability type='removable'>\n"); + virBufferVSprintf(&buf, + " <media_available>%d" + "</media_available>\n", avl ? 1 : 0); + virBufferVSprintf(&buf, " <media_size>%llu</media_size>\n", + data->storage.removable_media_size); + virBufferAddLit(&buf, " </capability>\n"); + } else { + virBufferVSprintf(&buf, " <size>%llu</size>\n", + data->storage.size); + } + if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE) + virBufferAddLit(&buf, + " <capability type='hotpluggable' />\n");
Again, the nested capabilities doesn't seem right. How about just: <removable media_available="1"/> <hotpluggable/>
+ break; + case VIR_NODE_DEV_CAP_LAST: + /* ignore special LAST value */ + break; + } + + virBufferAddLit(&buf, " </capability>\n"); + } + + virBufferAddLit(&buf, "</device>\n"); + + if (virBufferError(&buf)) + goto no_memory; + + return virBufferContentAndReset(&buf); + + no_memory: + virNodeDeviceReportError(conn, VIR_ERR_NO_MEMORY, NULL); + tmp = virBufferContentAndReset(&buf); + VIR_FREE(tmp); + return NULL; +} + +void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps) +{ + union _virNodeDevCapData *data = &caps->data; + + switch (caps->type) { + case VIR_NODE_DEV_CAP_SYSTEM: + VIR_FREE(data->system.product_name); + VIR_FREE(data->system.hardware.vendor_name); + VIR_FREE(data->system.hardware.version); + VIR_FREE(data->system.hardware.serial); + VIR_FREE(data->system.firmware.vendor_name); + VIR_FREE(data->system.firmware.version); + VIR_FREE(data->system.firmware.release_date); + break; + case VIR_NODE_DEV_CAP_PCI_DEV: + VIR_FREE(data->pci_dev.product_name); + VIR_FREE(data->pci_dev.vendor_name); + break; + case VIR_NODE_DEV_CAP_USB_DEV: + VIR_FREE(data->usb_dev.product_name); + VIR_FREE(data->usb_dev.vendor_name); + break; + case VIR_NODE_DEV_CAP_USB_INTERFACE: + VIR_FREE(data->usb_if.description); + break; + case VIR_NODE_DEV_CAP_NET: + VIR_FREE(data->net.interface); + VIR_FREE(data->net.address); + break; + case VIR_NODE_DEV_CAP_BLOCK: + VIR_FREE(data->block.device); + break; + case VIR_NODE_DEV_CAP_SCSI_HOST: + break; + case VIR_NODE_DEV_CAP_SCSI: + VIR_FREE(data->scsi.type); + break; + case VIR_NODE_DEV_CAP_STORAGE: + VIR_FREE(data->storage.bus); + VIR_FREE(data->storage.drive_type); + VIR_FREE(data->storage.model); + VIR_FREE(data->storage.vendor);
originating_device not freed.
+ break; + case VIR_NODE_DEV_CAP_LAST: + /* This case is here to shutup the compiler */ + break; + } + + VIR_FREE(caps); +} + diff -r 6812c3044043 src/node_device_conf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/node_device_conf.h Wed Nov 12 21:11:51 2008 +0000 ... +char *virNodeDeviceDefFormat(virConnectPtr conn, + const virNodeDeviceDefPtr def); + +// TODO: virNodeDeviceDefParseString/File/Node for virNodeDeviceCreate
Kinda superflous comment - if we implement DeviceCreate(), the need for those functions will be obvious. Cheers, Mark.

On Fri, 2008-11-14 at 13:20 +0000, Mark McLoughlin wrote:
On Thu, 2008-11-13 at 17:31 +0000, Daniel P. Berrange wrote:
+ virBufferVSprintf(&buf, " <capability type='%s'>\n", + virNodeDevCapTypeToString(caps->type)); + switch (caps->type) {
...
+ case VIR_NODE_DEV_CAP_NET: + virBufferVSprintf(&buf, " <interface>%s</interface>\n", + data->net.interface); + if (data->net.address) + virBufferVSprintf(&buf, " <address>%s</address>\n", + data->net.address); + if (data->net.subtype != VIR_NODE_DEV_CAP_NET_LAST) { + const char *subtyp = + virNodeDevNetCapTypeToString(data->net.subtype); + virBufferVSprintf(&buf, " <capability type='%s'>\n", subtyp); + switch (data->net.subtype) { + case VIR_NODE_DEV_CAP_NET_80203: + virBufferVSprintf(&buf, + " <mac_address>%012llx</address>\n", + data->net.data.ieee80203.mac_address); + break; + case VIR_NODE_DEV_CAP_NET_80211: + virBufferVSprintf(&buf, + " <mac_address>%012llx</address>\n", + data->net.data.ieee80211.mac_address); + break; + case VIR_NODE_DEV_CAP_NET_LAST: + /* Keep dumb compiler happy */ + break; + } + virBufferAddLit(&buf, " </capability>\n");
This all seems a bit odd.
We've listed the mac address once already, so why do it again in a hex format?
Agreed. It's basically just reflecting the HAL attributes. But I have to admit I find a lot of HAL rather non-intuitive ... I have no particular attachment to any of this node device description XML. I really liked Daniel's suggestion that this be based on a subset of HAL, and have tried to do that as much as possible. I don't really care what it's based on, but it sure would be nice to avoid inventing yet another XML device representation (hence the attraction to HAL). But the more I've gotten to know HAL, the less I've liked the idea. I'm not aware of an alternative that doesn't involve inventing our own. Perhaps there's something suitable in CIM?? I'm a CIM-dummy, so I have no idea ... This is related to the device naming issue as well. I share all of Dan B's concerns here ...
And I wouldn't think of "802.3 vs 802.11" as a network device capability, but more like it's "type" - they're mutually exclusive, right?
Also, we have:
<device> ... <capability type='net'> ... <capability type='80203'> <mac_address>001320f74a06</address> </capability> </capability> </device>
i.e. two different capability semantics?
Again, just reflecting HAL. But I agree it seems bizarre.
+ } + break; + case VIR_NODE_DEV_CAP_BLOCK: + virBufferVSprintf(&buf, " <device>%s</device>\n", + data->block.device);
Two nested <device> nodes:
<device> ... <capability type='block'> <device>/dev/sda1</device> </capability> </device>
How about <path> or <device_path> ?
This one doesn't bother me so much, though granted the two <device> tags are talking about completely different things (clear to me from the context, but perhaps violating some proper XML design rules?).
+ if (data->storage.originating_device) + virBufferVSprintf(&buf, + " <originating_device>%s" + "</originating_device>\n", + data->storage.originating_device);
This originating_device thing sounds strange, and I don't think we implement it yet. Leave it out for now?
Fine with me. I don't know what it is -- just sounded generally useful. If it's not widely implemented, we probably shouldn't bother supporting it.
+ if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_REMOVABLE) { + int avl = data->storage.flags & + VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE; + virBufferAddLit(&buf, " <capability type='removable'>\n"); + virBufferVSprintf(&buf, + " <media_available>%d" + "</media_available>\n", avl ? 1 : 0); + virBufferVSprintf(&buf, " <media_size>%llu</media_size>\n", + data->storage.removable_media_size); + virBufferAddLit(&buf, " </capability>\n"); + } else { + virBufferVSprintf(&buf, " <size>%llu</size>\n", + data->storage.size); + } + if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE) + virBufferAddLit(&buf, + " <capability type='hotpluggable' />\n");
Again, the nested capabilities doesn't seem right.
How about just:
<removable media_available="1"/> <hotpluggable/>
Again, just mimicking HAL's properties: removable.media_available, removable.media_size.
+ case VIR_NODE_DEV_CAP_STORAGE: + VIR_FREE(data->storage.bus); + VIR_FREE(data->storage.drive_type); + VIR_FREE(data->storage.model); + VIR_FREE(data->storage.vendor);
originating_device not freed.
Good catch. Thanks! Dave

On Fri, Nov 14, 2008 at 01:20:22PM +0000, Mark McLoughlin wrote: > On Thu, 2008-11-13 at 17:31 +0000, Daniel P. Berrange wrote: > > This is the basic internal driver support code for the node device APIs. > > The actual registration of the drivers was pushed to a later patch to > > allow this to compile on its own & thus be fully bisectable. > > + case VIR_NODE_DEV_CAP_NET: > > + virBufferVSprintf(&buf, " <interface>%s</interface>\n", > > + data->net.interface); > > + if (data->net.address) > > + virBufferVSprintf(&buf, " <address>%s</address>\n", > > + data->net.address); > > + if (data->net.subtype != VIR_NODE_DEV_CAP_NET_LAST) { > > + const char *subtyp = > > + virNodeDevNetCapTypeToString(data->net.subtype); > > + virBufferVSprintf(&buf, " <capability type='%s'>\n", subtyp); > > + switch (data->net.subtype) { > > + case VIR_NODE_DEV_CAP_NET_80203: > > + virBufferVSprintf(&buf, > > + " <mac_address>%012llx</address>\n", > > + data->net.data.ieee80203.mac_address); > > + break; > > + case VIR_NODE_DEV_CAP_NET_80211: > > + virBufferVSprintf(&buf, > > + " <mac_address>%012llx</address>\n", > > + data->net.data.ieee80211.mac_address); > > + break; > > + case VIR_NODE_DEV_CAP_NET_LAST: > > + /* Keep dumb compiler happy */ > > + break; > > + } > > + virBufferAddLit(&buf, " </capability>\n"); > > This all seems a bit odd. > > We've listed the mac address once already, so why do it again in a hex format? I'd removed the 2nd hexformat one. > And I wouldn't think of "802.3 vs 802.11" as a network device > capability, but more like it's "type" - they're mutually exclusive, right? > Also, we have: > > <device> > ... > <capability type='net'> > ... > <capability type='80203'> > <mac_address>001320f74a06</address> > </capability> > </capability> > </device> > > i.e. two different capability semantics? The reason for the nested capabilities is that they're supposed to represent refinements of the main capability. While the current wifi vs ethernet refinements are mutually exclusive, I think its worth having the option of multiple refinements in the future. > > + } > > + break; > > + case VIR_NODE_DEV_CAP_BLOCK: > > + virBufferVSprintf(&buf, " <device>%s</device>\n", > > + data->block.device); > > Two nested <device> nodes: > > <device> > ... > <capability type='block'> > <device>/dev/sda1</device> > </capability> > </device> > > How about <path> or <device_path> ? This one has gone away with the merge of 'block' into 'storage' > > + if (data->storage.originating_device) > > + virBufferVSprintf(&buf, > > + " <originating_device>%s" > > + "</originating_device>\n", > > + data->storage.originating_device); > > This originating_device thing sounds strange, and I don't think we > implement it yet. Leave it out for now? Yep, removed it > > > + if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE) > > + virBufferAddLit(&buf, > > + " <capability type='hotpluggable' />\n"); > > Again, the nested capabilities doesn't seem right. This was the same rationale as the nested capability info for network devices - one or more refinements of the master capability. > > + case VIR_NODE_DEV_CAP_STORAGE: > > + VIR_FREE(data->storage.bus); > > + VIR_FREE(data->storage.drive_type); > > + VIR_FREE(data->storage.model); > > + VIR_FREE(data->storage.vendor); > > originating_device not freed. It is gone completely now > > diff -r 6812c3044043 src/node_device_conf.h > > --- /dev/null Thu Jan 01 00:00:00 1970 +0000 > > +++ b/src/node_device_conf.h Wed Nov 12 21:11:51 2008 +0000 > ... > > +char *virNodeDeviceDefFormat(virConnectPtr conn, > > + const virNodeDeviceDefPtr def); > > + > > +// TODO: virNodeDeviceDefParseString/File/Node for virNodeDeviceCreate > > Kinda superflous comment - if we implement DeviceCreate(), the need for > those functions will be obvious. Forgot to remove this TODO, but will do so. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

This is the main implementation of the local device enumation driver. The main change since David's patch is that we hav a single nodedevRegister() API call, instead of initializing HAL/DevKit separtely. This was needed to make the dlopen() support easier to implement. Functionally the end result is the same. Daniel diff -r acac4fc31665 configure.in --- a/configure.in Thu Nov 13 17:06:39 2008 +0000 +++ b/configure.in Thu Nov 13 17:10:30 2008 +0000 @@ -1098,6 +1098,108 @@ LV_LIBTOOL_OBJDIR=${lt_cv_objdir-.} AC_SUBST([LV_LIBTOOL_OBJDIR]) +dnl HAL or DeviceKit library for host device enumeration +HAL_REQUIRED=0.0 +HAL_CFLAGS= +HAL_LIBS= +AC_ARG_WITH([hal], + [ --with-hal use HAL for host device enumeration], + [], + [with_hal=check]) + +if test "$with_libvirtd" = "no" ; then + with_hal=no +fi +if test "x$with_hal" = "xyes" -o "x$with_hal" = "xcheck"; then + PKG_CHECK_MODULES(HAL, hal >= $HAL_REQUIRED, + [with_hal=yes], [ + if test "x$with_hal" = "xcheck" ; then + with_hal=no + else + AC_MSG_ERROR( + [You must install hal-devel >= $HAL_REQUIRED to compile libvirt]) + fi + ]) + if test "x$with_hal" = "xyes" ; then + AC_DEFINE_UNQUOTED([HAVE_HAL], 1, + [use HAL for host device enumeration]) + + old_CFLAGS=$CFLAGS + old_LDFLAGS=$LDFLAGS + CFLAGS="$CFLAGS $HAL_CFLAGS" + LDFLAGS="$LDFLAGS $HAL_LIBS" + AC_CHECK_FUNCS([libhal_get_all_devices],,[with_hal=no]) + CFLAGS="$old_CFLAGS" + LDFLAGS="$old_LDFLAGS" + fi +fi +AM_CONDITIONAL([HAVE_HAL], [test "x$with_hal" = "xyes"]) +AC_SUBST([HAL_CFLAGS]) +AC_SUBST([HAL_LIBS]) + +DEVKIT_REQUIRED=0.0 +DEVKIT_CFLAGS= +DEVKIT_LIBS= +AC_ARG_WITH([devkit], + [ --with-devkit use DeviceKit for host device enumeration], + [], + [with_devkit=check]) + +if test "$with_libvirtd" = "no" ; then + with_devkit=no +fi + +dnl Extra check needed while devkit pkg-config info missing glib2 dependency +PKG_CHECK_MODULES(GLIB2, glib-2.0 >= 0.0,,[ + if test "x$with_devkit" = "xcheck"; then + with_devkit=no + elif test "x$with_devkit" = "xyes"; then + AC_MSG_ERROR([required package DeviceKit requires package glib-2.0]) + fi]) + +if test "x$with_devkit" = "xyes" -o "x$with_devkit" = "xcheck"; then + PKG_CHECK_MODULES(DEVKIT, devkit-gobject >= $DEVKIT_REQUIRED, + [with_devkit=yes], [ + if test "x$with_devkit" = "xcheck" ; then + with_devkit=no + else + AC_MSG_ERROR( + [You must install DeviceKit-devel >= $DEVKIT_REQUIRED to compile libvirt]) + fi + ]) + if test "x$with_devkit" = "xyes" ; then + AC_DEFINE_UNQUOTED([HAVE_DEVKIT], 1, + [use DeviceKit for host device enumeration]) + + dnl Add glib2 flags explicitly while devkit pkg-config info missing glib2 dependency + DEVKIT_CFLAGS="$GLIB2_CFLAGS $DEVKIT_CFLAGS" + DEVKIT_LIBS="$GLIB2_LIBS $DEVKIT_LIBS" + + dnl Add more flags apparently required for devkit to work properly + DEVKIT_CFLAGS="$DEVKIT_CFLAGS -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT" + + old_CFLAGS=$CFLAGS + old_LDFLAGS=$LDFLAGS + CFLAGS="$CFLAGS $DEVKIT_CFLAGS" + LDFLAGS="$LDFLAGS $DEVKIT_LIBS" + AC_CHECK_FUNCS([devkit_client_connect],,[with_devkit=no]) + CFLAGS="$old_CFLAGS" + LDFLAGS="$old_LDFLAGS" + fi +fi +AM_CONDITIONAL([HAVE_DEVKIT], [test "x$with_devkit" = "xyes"]) +AC_SUBST([DEVKIT_CFLAGS]) +AC_SUBST([DEVKIT_LIBS]) + +with_nodedev=no; +if test "$with_devkit" = "yes" -o "$with_hal" = "yes"; +then + with_nodedev=yes + AC_DEFINE_UNQUOTED([WITH_NODE_DEVICES], 1, [with node device driver]) +fi +AM_CONDITIONAL([WITH_NODE_DEVICES], [test "$with_nodedev" = "yes"]) + + # very annoying rm -f COPYING cp COPYING.LIB COPYING @@ -1188,6 +1290,16 @@ else AC_MSG_NOTICE([ xen: no]) fi +if test "$with_hal" = "yes" ; then +AC_MSG_NOTICE([ hal: $HAL_CFLAGS $HAL_LIBS]) +else +AC_MSG_NOTICE([ hal: no]) +fi +if test "$with_devkit" = "yes" ; then +AC_MSG_NOTICE([ devkit: $DEVKIT_CFLAGS $DEVKIT_LIBS]) +else +AC_MSG_NOTICE([ devkit: no]) +fi AC_MSG_NOTICE([]) AC_MSG_NOTICE([Test suite]) AC_MSG_NOTICE([]) diff -r acac4fc31665 po/POTFILES.in --- a/po/POTFILES.in Thu Nov 13 17:06:39 2008 +0000 +++ b/po/POTFILES.in Thu Nov 13 17:10:30 2008 +0000 @@ -13,6 +13,7 @@ src/lxc_driver.c src/network_conf.c src/network_driver.c +src/node_device.c src/openvz_conf.c src/openvz_driver.c src/proxy_internal.c diff -r acac4fc31665 qemud/Makefile.am --- a/qemud/Makefile.am Thu Nov 13 17:06:39 2008 +0000 +++ b/qemud/Makefile.am Thu Nov 13 17:10:30 2008 +0000 @@ -108,6 +108,10 @@ if WITH_NETWORK libvirtd_LDADD += ../src/libvirt_driver_network.la endif + +if WITH_NODE_DEVICES +libvirtd_LDADD += ../src/libvirt_driver_nodedev.la +endif endif if HAVE_POLKIT diff -r acac4fc31665 qemud/qemud.c --- a/qemud/qemud.c Thu Nov 13 17:06:39 2008 +0000 +++ b/qemud/qemud.c Thu Nov 13 17:10:30 2008 +0000 @@ -75,6 +75,9 @@ #endif #ifdef WITH_STORAGE_DIR #include "storage_driver.h" +#endif +#ifdef WITH_NODE_DEVICES +#include "node_device.h" #endif #endif @@ -758,6 +761,7 @@ virDriverLoadModule("lxc"); virDriverLoadModule("network"); virDriverLoadModule("storage"); + virDriverLoadModule("nodedev"); #else #ifdef WITH_QEMU qemuRegister(); @@ -770,6 +774,9 @@ #endif #ifdef WITH_STORAGE_DIR storageRegister(); +#endif +#if defined(HAVE_HAL) || defined(HAVE_DEVKIT) + nodedevRegister(); #endif #endif diff -r acac4fc31665 src/Makefile.am --- a/src/Makefile.am Thu Nov 13 17:06:39 2008 +0000 +++ b/src/Makefile.am Thu Nov 13 17:10:30 2008 +0000 @@ -152,6 +152,14 @@ STORAGE_HELPER_DISK_SOURCES = \ parthelper.c + +NODE_DEVICE_DRIVER_SOURCES = \ + node_device.c node_device.h + +NODE_DEVICE_DRIVER_HAL_SOURCES = \ + node_device_hal.c +NODE_DEVICE_DRIVER_DEVKIT_SOURCES = \ + node_device_devkit.c ######################### @@ -305,6 +313,36 @@ libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_DISK_SOURCES) endif +if WITH_NODE_DEVICES +# Needed to keep automake quiet about conditionals +if WITH_DRIVER_MODULES +mod_LTLIBRARIES += libvirt_driver_nodedev.la +else +noinst_LTLIBRARIES += libvirt_driver_nodedev.la +# Stateful, so linked to daemon instead +#libvirt_la_LIBADD += libvirt_driver_nodedev.la +endif +libvirt_driver_nodedev_la_SOURCES = $(NODE_DEVICE_DRIVER_SOURCES) + +libvirt_driver_nodedev_la_CFLAGS = +libvirt_driver_nodedev_la_LDFLAGS = +if HAVE_HAL +libvirt_driver_nodedev_la_SOURCES += $(NODE_DEVICE_DRIVER_HAL_SOURCES) +libvirt_driver_nodedev_la_CFLAGS += $(HAL_CFLAGS) +libvirt_driver_nodedev_la_LDFLAGS += $(HAL_LIBS) +endif +if HAVE_DEVKIT +libvirt_driver_nodedev_la_SOURCES += $(NODE_DEVICE_DRIVER_DEVKIT_SOURCES) +libvirt_driver_nodedev_la_CFLAGS += $(DEVKIT_CFLAGS) +libvirt_driver_nodedev_la_LDFLAGS += $(DEVKIT_LIBS) +endif + +if WITH_DRIVER_MODULES +libvirt_driver_nodedev_la_LDFLAGS += -module -avoid-version +endif +endif + + # Add all conditional sources just in case... EXTRA_DIST += \ $(TEST_DRIVER_SOURCES) \ @@ -318,7 +356,10 @@ $(STORAGE_DRIVER_FS_SOURCES) \ $(STORAGE_DRIVER_LVM_SOURCES) \ $(STORAGE_DRIVER_ISCSI_SOURCES) \ - $(STORAGE_DRIVER_DISK_SOURCES) + $(STORAGE_DRIVER_DISK_SOURCES) \ + $(NODE_DEVICE_DRIVER_SOURCES) \ + $(NODE_DEVICE_DRIVER_HAL_SOURCES) \ + $(NODE_DEVICE_DRIVER_DEVKIT_SOURCES) # Empty source list - it merely links a bunch of convenience libs together diff -r acac4fc31665 src/libvirt_sym.version.in --- a/src/libvirt_sym.version.in Thu Nov 13 17:06:39 2008 +0000 +++ b/src/libvirt_sym.version.in Thu Nov 13 17:10:30 2008 +0000 @@ -327,6 +327,7 @@ virGetNetwork; virGetStoragePool; virGetStorageVol; + virGetNodeDevice; virUnrefDomain; @@ -447,6 +448,7 @@ virRegisterNetworkDriver; virRegisterStateDriver; virRegisterStorageDriver; + virRegisterDeviceMonitor; /* memory.h */ @@ -475,6 +477,16 @@ /* nodeinfo.h */ virNodeInfoPopulate; + + + /* node_device_conf.h */ + virNodeDeviceObjRemove; + virNodeDevCapTypeToString; + virNodeDeviceFindByName; + virNodeDeviceObjListFree; + virNodeDeviceDefFree; + virNodeDevCapsDefFree; + virNodeDeviceDefFormat; /* qparams.h */ @@ -535,6 +547,7 @@ virStrToLong_i; virStrToLong_ll; virStrToLong_ull; + virStrToLong_ui; virFileLinkPointsTo; saferead; safewrite; @@ -553,6 +566,7 @@ virFileOpenTty; virFileReadLimFD; virFileReadPid; + virFileLinkPointsTo; virParseNumber; virRun; virSkipSpaces; diff -r acac4fc31665 src/node_device.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/node_device.c Thu Nov 13 17:10:30 2008 +0000 @@ -0,0 +1,241 @@ +/* + * node_device.c: node device enumeration + * + * Copyright (C) 2008 Virtual Iron Software, Inc. + * Copyright (C) 2008 David F. Lively + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: David F. Lively <dlively@virtualiron.com> + */ + +#include <config.h> + +#include <unistd.h> +#include <errno.h> + +#include "virterror_internal.h" +#include "datatypes.h" +#include "memory.h" + +#include "node_device_conf.h" +#include "node_device.h" + +static int dev_has_cap(const virNodeDeviceObjPtr dev, const char *cap) +{ + virNodeDevCapsDefPtr caps = dev->def->caps; + while (caps) { + if (STREQ(cap, virNodeDevCapTypeToString(caps->type))) + return 1; + caps = caps->next; + } + return 0; +} + + +static int nodeNumOfDevices(virConnectPtr conn, + unsigned int flags ATTRIBUTE_UNUSED) +{ + virDeviceMonitorStatePtr driver = conn->devMonPrivateData; + return driver->devs.count; +} + +static int +nodeListDevices(virConnectPtr conn, char **const names, int maxnames, + unsigned int flags ATTRIBUTE_UNUSED) +{ + virDeviceMonitorStatePtr driver = conn->devMonPrivateData; + int ndevs = 0; + unsigned int i; + + for (i = 0; i < driver->devs.count && ndevs < maxnames; i++) + if ((names[ndevs++] = strdup(driver->devs.objs[i]->def->name)) == NULL) + goto failure; + + return ndevs; + + failure: + --ndevs; + while (--ndevs >= 0) + VIR_FREE(names[ndevs]); + return -1; +} + + +static int nodeNumOfDevicesByCap(virConnectPtr conn, + const char *cap, + unsigned int flags ATTRIBUTE_UNUSED) +{ + virDeviceMonitorStatePtr driver = conn->devMonPrivateData; + int ndevs = 0; + unsigned int i; + + for (i = 0; i < driver->devs.count; i++) + if (dev_has_cap(driver->devs.objs[i], cap)) + ++ndevs; + + return ndevs; +} + +static int nodeListDevicesByCap(virConnectPtr conn, + const char *cap, + char **const names, + int maxnames, + unsigned int flags ATTRIBUTE_UNUSED) +{ + virDeviceMonitorStatePtr driver = conn->devMonPrivateData; + int ndevs = 0; + unsigned int i; + + for (i = 0; i < driver->devs.count && ndevs < maxnames; i++) + if (dev_has_cap(driver->devs.objs[i], cap)) + if ((names[ndevs++] = strdup(driver->devs.objs[i]->def->name)) == NULL) + goto failure; + + return ndevs; + + failure: + --ndevs; + while (--ndevs >= 0) + VIR_FREE(names[ndevs]); + return -1; +} + +static virNodeDevicePtr nodeDeviceLookupByName(virConnectPtr conn, + const char *name) +{ + virDeviceMonitorStatePtr driver = conn->devMonPrivateData; + virNodeDeviceObjPtr obj = virNodeDeviceFindByName(&driver->devs, name); + + if (!obj) { + virNodeDeviceReportError(conn, VIR_ERR_INVALID_NODE_DEVICE, + "%s", _("no node device with matching name")); + return NULL; + } + + return virGetNodeDevice(conn, name); + +} + +static char *nodeDeviceDumpXML(virNodeDevicePtr dev, + unsigned int flags ATTRIBUTE_UNUSED) +{ + virDeviceMonitorStatePtr driver = dev->conn->devMonPrivateData; + virNodeDeviceObjPtr obj = virNodeDeviceFindByName(&driver->devs, dev->name); + + if (!obj) { + virNodeDeviceReportError(dev->conn, VIR_ERR_INVALID_NODE_DEVICE, + "%s", _("no node device with matching name")); + return NULL; + } + + return virNodeDeviceDefFormat(dev->conn, obj->def); +} + + +static char *nodeDeviceGetParent(virNodeDevicePtr dev) +{ + virDeviceMonitorStatePtr driver = dev->conn->devMonPrivateData; + virNodeDeviceObjPtr obj = virNodeDeviceFindByName(&driver->devs, dev->name); + + if (!obj) { + virNodeDeviceReportError(dev->conn, VIR_ERR_INVALID_NODE_DEVICE, + "%s", _("no node device with matching name")); + return NULL; + } + + return obj->def->parent; +} + + +static int nodeDeviceNumOfCaps(virNodeDevicePtr dev) +{ + virDeviceMonitorStatePtr driver = dev->conn->devMonPrivateData; + virNodeDeviceObjPtr obj = virNodeDeviceFindByName(&driver->devs, dev->name); + virNodeDevCapsDefPtr caps; + int ncaps = 0; + + if (!obj) { + virNodeDeviceReportError(dev->conn, VIR_ERR_INVALID_NODE_DEVICE, + "%s", _("no node device with matching name")); + return -1; + } + + for (caps = obj->def->caps; caps; caps = caps->next) + ++ncaps; + + return ncaps; +} + + +static int +nodeDeviceListCaps(virNodeDevicePtr dev, char **const names, int maxnames) +{ + virDeviceMonitorStatePtr driver = dev->conn->devMonPrivateData; + virNodeDeviceObjPtr obj = virNodeDeviceFindByName(&driver->devs, dev->name); + virNodeDevCapsDefPtr caps; + int ncaps = 0; + + if (!obj) { + virNodeDeviceReportError(dev->conn, VIR_ERR_INVALID_NODE_DEVICE, + "%s", _("no node device with matching name")); + return -1; + } + + for (caps = obj->def->caps; caps && ncaps < maxnames; caps = caps->next) { + names[ncaps] = strdup(virNodeDevCapTypeToString(caps->type)); + if (names[ncaps++] == NULL) + goto failure; + } + + return ncaps; + + failure: + --ncaps; + while (--ncaps >= 0) + VIR_FREE(names[ncaps]); + return -1; +} + + +void registerCommonNodeFuncs(virDeviceMonitorPtr driver) +{ + driver->numOfDevices = nodeNumOfDevices; + driver->listDevices = nodeListDevices; + driver->numOfDevicesByCap = nodeNumOfDevicesByCap; + driver->listDevicesByCap = nodeListDevicesByCap; + driver->deviceLookupByName = nodeDeviceLookupByName; + driver->deviceDumpXML = nodeDeviceDumpXML; + driver->deviceGetParent = nodeDeviceGetParent; + driver->deviceNumOfCaps = nodeDeviceNumOfCaps; + driver->deviceListCaps = nodeDeviceListCaps; +} + + +int nodedevRegister(void) { +#if defined(HAVE_HAL) && defined(HAVE_DEVKIT) + /* Register only one of these two - they conflict */ + if (halNodeRegister() == -1) + return devkitNodeRegister(); + return 0; +#else +#ifdef HAVE_HAL + return halNodeRegister(); +#endif +#ifdef HAVE_DEVKIT + return devkitNodeRegister(); +#endif +#endif +} diff -r acac4fc31665 src/node_device.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/node_device.h Thu Nov 13 17:10:30 2008 +0000 @@ -0,0 +1,41 @@ +/* + * node_device.h: node device enumeration + * + * Copyright (C) 2008 Virtual Iron Software, Inc. + * Copyright (C) 2008 David F. Lively + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: David F. Lively <dlively@virtualiron.com> + */ + +#ifndef __VIR_NODE_DEVICE_H__ +#define __VIR_NODE_DEVICE_H__ + +#include "internal.h" +#include "driver.h" + +#ifdef HAVE_HAL +int halNodeRegister(void); +#endif +#ifdef HAVE_DEVKIT +int devkitNodeRegister(void); +#endif + +void registerCommonNodeFuncs(virDeviceMonitorPtr mon); + +int nodedevRegister(void); + +#endif /* __VIR_NODE_DEVICE_H__ */ diff -r acac4fc31665 src/node_device_devkit.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/node_device_devkit.c Thu Nov 13 17:10:30 2008 +0000 @@ -0,0 +1,445 @@ +/* + * node_device_devkit.c: node device enumeration - DeviceKit-based implementation + * + * Copyright (C) 2008 Virtual Iron Software, Inc. + * Copyright (C) 2008 David F. Lively + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: David F. Lively <dlively@virtualiron.com> + */ + +#include <config.h> +#include <devkit-gobject.h> + +#include "node_device_conf.h" +#include "virterror_internal.h" +#include "driver.h" +#include "datatypes.h" +#include "event.h" +#include "memory.h" +#include "uuid.h" + +#include "node_device.h" + +/* + * Host device enumeration (DeviceKit implementation) + */ + +static virDeviceMonitorStatePtr driverState; + +#define DEBUG(fmt,...) VIR_DEBUG(__FILE__, fmt, __VA_ARGS__) +#define DEBUG0(msg) VIR_DEBUG(__FILE__, "%s", msg) + +#define CONN_DRV_STATE(conn) \ + ((virDeviceMonitorStatePtr)((conn)->devMonPrivateData)) +#define DRV_STATE_DKCLIENT(ds) ((DevkitClient *)((ds)->privateData)) +#define CONN_DKCLIENT(conn) DRV_STATE_DKCLIENT(CONN_DRV_STATE(conn)) + +#define NODE_DEV_DKDEV(obj) ((DevkitDevice *)((obj)->privateData) + +static int get_str_prop(DevkitDevice *dkdev, const char *prop, char **val_p) +{ + char *val = devkit_device_dup_property_as_str(dkdev, prop); + + if (val) { + if (*val) { + *val_p = val; + return 0; + } else { + /* Treat empty strings as NULL values */ + VIR_FREE(val); + } + } + + return -1; +} + +#if 0 +static int get_int_prop(DevkitDevice *dkdev, const char *prop, int *val_p) +{ + if (! devkit_device_has_property(dkdev, prop)) + return -1; + *val_p = devkit_device_get_property_as_int(dkdev, prop); + return 0; +} + +static int get_uint64_prop(DevkitDevice *dkdev, const char *prop, + unsigned long long *val_p) +{ + if (! devkit_device_has_property(dkdev, prop)) + return -1; + *val_p = devkit_device_get_property_as_uint64(dkdev, prop); + return 0; +} +#endif + +static int gather_pci_cap(DevkitDevice *dkdev, + union _virNodeDevCapData *d) +{ + const char *sysfs_path = devkit_device_get_native_path(dkdev); + + if (sysfs_path != NULL) { + char *p = strrchr(sysfs_path, '/'); + if (p) { + (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.domain); + (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.bus); + (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.slot); + (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.function); + } + } + return 0; +} + + +static int gather_usb_cap(DevkitDevice *dkdev, + union _virNodeDevCapData *d) +{ + (void)get_str_prop(dkdev, "ID_VENDOR", &d->usb_dev.vendor_name); + (void)get_str_prop(dkdev, "ID_MODEL", &d->usb_dev.product_name); + return 0; +} + + +static int gather_net_cap(DevkitDevice *dkdev, + union _virNodeDevCapData *d) +{ + const char *sysfs_path = devkit_device_get_native_path(dkdev); + const char *interface; + + if (sysfs_path == NULL) + return -1; + interface = strrchr(sysfs_path, '/'); + if (!interface && *interface && *(++interface)) + return -1; + if ((d->net.interface = strdup(interface)) == NULL) + return -1; + + d->net.subtype = VIR_NODE_DEV_CAP_NET_LAST; + + return 0; +} + + +static int gather_block_cap(DevkitDevice *dkdev, + union _virNodeDevCapData *d) +{ + const char *device = devkit_device_get_device_file(dkdev); + + if (device && ((d->block.device = strdup(device)) == NULL)) + return -1; + + return 0; +} + + +struct _caps_tbl_entry { + const char *cap_name; + enum virNodeDevCapType type; + int (*gather_fn)(DevkitDevice *dkdev, + union _virNodeDevCapData *data); +}; + +typedef struct _caps_tbl_entry caps_tbl_entry; + +static caps_tbl_entry caps_tbl[] = { + { "pci", VIR_NODE_DEV_CAP_PCI_DEV, gather_pci_cap }, + { "usb", VIR_NODE_DEV_CAP_USB_DEV, gather_usb_cap }, + { "net", VIR_NODE_DEV_CAP_NET, gather_net_cap }, + { "block", VIR_NODE_DEV_CAP_BLOCK, gather_block_cap }, + // TODO: more caps! +}; + + +/* qsort/bsearch string comparator */ +static int cmpstringp(const void *p1, const void *p2) +{ + /* from man 3 qsort */ + return strcmp(* (char * const *) p1, * (char * const *) p2); +} + + +static int gather_capability(DevkitDevice *dkdev, + const char *cap_name, + virNodeDevCapsDefPtr *caps_p) +{ + size_t caps_tbl_len = sizeof(caps_tbl) / sizeof(caps_tbl[0]); + caps_tbl_entry *entry; + + entry = bsearch(&cap_name, caps_tbl, caps_tbl_len, + sizeof(caps_tbl[0]), cmpstringp); + + if (entry) { + virNodeDevCapsDefPtr caps; + if (VIR_ALLOC(caps) < 0) + return ENOMEM; + caps->type = entry->type; + if (entry->gather_fn) { + int rv = (*entry->gather_fn)(dkdev, &caps->data); + if (rv != 0) { + virNodeDevCapsDefFree(caps); + return rv; + } + } + caps->next = *caps_p; + *caps_p = caps; + } + + return 0; +} + + +static int gather_capabilities(DevkitDevice *dkdev, + virNodeDevCapsDefPtr *caps_p) +{ + const char *subsys = devkit_device_get_subsystem(dkdev); + const char *bus_name = devkit_device_get_property(dkdev, "ID_BUS"); + virNodeDevCapsDefPtr caps = NULL; + int rv; + + if (subsys) { + rv = gather_capability(dkdev, subsys, &caps); + if (rv != 0) goto failure; + } + + if (bus_name && (subsys == NULL || !STREQ(bus_name, subsys))) { + rv = gather_capability(dkdev, bus_name, &caps); + if (rv != 0) goto failure; + } + + *caps_p = caps; + return 0; + + failure: + while (caps) { + virNodeDevCapsDefPtr next = caps->next; + virNodeDevCapsDefFree(caps); + caps = next; + } + return rv; +} + +static void dev_create(void *_dkdev, void *_dkclient ATTRIBUTE_UNUSED) +{ + DevkitDevice *dkdev = _dkdev; + const char *sysfs_path = devkit_device_get_native_path(dkdev); + virNodeDeviceObjPtr dev = NULL; + const char *name; + int rv; + + if (sysfs_path == NULL) + /* Currently using basename(sysfs_path) as device name (key) */ + return; + + name = strrchr(sysfs_path, '/'); + if (name == NULL) + name = sysfs_path; + else + ++name; + + if (VIR_ALLOC(dev) < 0 || VIR_ALLOC(dev->def) < 0) + goto failure; + + dev->privateData = dkdev; + + if ((dev->def->name = strdup(name)) == NULL) + goto failure; + + // TODO: Find device parent, if any + + rv = gather_capabilities(dkdev, &dev->def->caps); + if (rv != 0) goto failure; + + if (VIR_REALLOC_N(driverState->devs.objs, driverState->devs.count + 1) < 0) + goto failure; + + driverState->devs.objs[driverState->devs.count++] = dev; + + return; + + failure: + DEBUG("FAILED TO ADD dev %s", name); + if (dev) + virNodeDeviceDefFree(dev->def); + VIR_FREE(dev); +} + + +static int devkitDeviceMonitorStartup(void) +{ + size_t caps_tbl_len = sizeof(caps_tbl) / sizeof(caps_tbl[0]); + DevkitClient *devkit_client = NULL; + GError *err = NULL; + GList *devs; + int i; + + /* Ensure caps_tbl is sorted by capability name */ + qsort(caps_tbl, caps_tbl_len, sizeof(caps_tbl[0]), cmpstringp); + + if (VIR_ALLOC(driverState) < 0) + return -1; + + // TODO: Is it really ok to call this multiple times?? + // Is there something analogous to call on close? + g_type_init(); + + /* Get new devkit_client and connect to daemon */ + devkit_client = devkit_client_new(NULL); + if (devkit_client == NULL) { + DEBUG0("devkit_client_new returned NULL"); + goto failure; + } + if (!devkit_client_connect(devkit_client, &err)) { + DEBUG0("devkit_client_connect failed"); + goto failure; + } + + /* Populate with known devices. + * + * This really should be: + devs = devkit_client_enumerate_by_subsystem(devkit_client, NULL, &err); + if (err) { + DEBUG0("devkit_client_enumerate_by_subsystem failed"); + devs = NULL; + goto failure; + } + g_list_foreach(devs, dev_create, devkit_client); + * but devkit_client_enumerate_by_subsystem currently fails when the second + * arg is null (contrary to the API documentation). So the following code + * (from Dan B) works around this by listing devices per handled subsystem. + */ + + for (i = 0 ; i < ARRAY_CARDINALITY(caps_tbl) ; i++) { + const char *caps[] = { caps_tbl[i].cap_name, NULL }; + devs = devkit_client_enumerate_by_subsystem(devkit_client, + caps, + &err); + if (err) { + DEBUG0("devkit_client_enumerate_by_subsystem failed"); + devs = NULL; + goto failure; + } + g_list_foreach(devs, dev_create, devkit_client); + } + + driverState->privateData = devkit_client; + + // TODO: Register to get DeviceKit events on device changes and + // coordinate updates with queries and other operations. + + return 0; + + failure: + if (err) { + DEBUG("\terror[%d]: %s", err->code, err->message); + g_error_free(err); + } + if (devs) { + g_list_foreach(devs, (GFunc)g_object_unref, NULL); + g_list_free(devs); + } + if (devkit_client) + g_object_unref(devkit_client); + VIR_FREE(driverState); + + return -1; +} + + +static int devkitDeviceMonitorShutdown(void) +{ + if (driverState) { + DevkitClient *devkit_client = DRV_STATE_DKCLIENT(driverState); + virNodeDeviceObjListFree(&driverState->devs); + if (devkit_client) + g_object_unref(devkit_client); + VIR_FREE(driverState); + return 0; + } + return -1; +} + + +static int devkitDeviceMonitorReload(void) +{ + (void)devkitDeviceMonitorShutdown(); + return devkitDeviceMonitorStartup(); +} + + +static int devkitDeviceMonitorActive(void) +{ + /* Always ready to deal with a shutdown */ + return 0; +} + + +static virDrvOpenStatus +devkitNodeDrvOpen(virConnectPtr conn, + virConnectAuthPtr auth ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED) +{ + if (driverState == NULL) + return VIR_DRV_OPEN_DECLINED; + + conn->devMonPrivateData = driverState; + + return VIR_DRV_OPEN_SUCCESS; +} + +static int devkitNodeDrvClose(virConnectPtr conn ATTRIBUTE_UNUSED) +{ + conn->devMonPrivateData = NULL; + return 0; +} + + +static virNodeDevicePtr +devkitNodeDeviceCreate(virConnectPtr conn ATTRIBUTE_UNUSED, + const char *xml ATTRIBUTE_UNUSED, + unsigned int flags ATTRIBUTE_UNUSED) +{ + return NULL; +} + +static int devkitNodeDeviceDestroy(virNodeDevicePtr dev ATTRIBUTE_UNUSED, + unsigned int flags ATTRIBUTE_UNUSED) +{ + return -1; +} + +static virDeviceMonitor devkitDeviceMonitor = { + .name = "devkitDeviceMonitor", + .open = devkitNodeDrvOpen, + .close = devkitNodeDrvClose, + .deviceCreate = devkitNodeDeviceCreate, + .deviceDestroy = devkitNodeDeviceDestroy, +}; + + +static virStateDriver devkitStateDriver = { + .initialize = devkitDeviceMonitorStartup, + .cleanup = devkitDeviceMonitorShutdown, + .reload = devkitDeviceMonitorReload, + .active = devkitDeviceMonitorActive, +}; + +int devkitNodeRegister(void) +{ + registerCommonNodeFuncs(&devkitDeviceMonitor); + if (virRegisterDeviceMonitor(&devkitDeviceMonitor) < 0) + return -1; + return virRegisterStateDriver(&devkitStateDriver); +} diff -r acac4fc31665 src/node_device_hal.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/node_device_hal.c Thu Nov 13 17:10:30 2008 +0000 @@ -0,0 +1,772 @@ +/* + * node_device_hal.c: node device enumeration - HAL-based implementation + * + * Copyright (C) 2008 Virtual Iron Software, Inc. + * Copyright (C) 2008 David F. Lively + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: David F. Lively <dlively@virtualiron.com> + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <config.h> +#include <libhal.h> + +#include "node_device_conf.h" +#include "virterror_internal.h" +#include "driver.h" +#include "datatypes.h" +#include "event.h" +#include "memory.h" +#include "uuid.h" +#include "logging.h" +#include "node_device.h" + +/* + * Host device enumeration (HAL implementation) + */ + +static virDeviceMonitorStatePtr driverState; + +#define CONN_DRV_STATE(conn) \ + ((virDeviceMonitorStatePtr)((conn)->devMonPrivateData)) +#define DRV_STATE_HAL_CTX(ds) ((LibHalContext *)((ds)->privateData)) +#define CONN_HAL_CTX(conn) DRV_STATE_HAL_CTX(CONN_DRV_STATE(conn)) + +#define NODE_DEV_UDI(obj) ((const char *)((obj)->privateData) + + +static const char *hal_name(const char *udi) +{ + const char *name = strrchr(udi, '/'); + if (name) + return name+1; + return udi; +} + + +static int get_str_prop(LibHalContext *ctxt, const char *udi, + const char *prop, char **val_p) +{ + char *val = libhal_device_get_property_string(ctxt, udi, prop, NULL); + + if (val) { + if (*val) { + *val_p = val; + return 0; + } else { + /* Treat empty strings as NULL values */ + VIR_FREE(val); + } + } + + return -1; +} + +static int get_int_prop(LibHalContext *ctxt, const char *udi, + const char *prop, int *val_p) +{ + DBusError err; + int val; + int rv; + + dbus_error_init(&err); + val = libhal_device_get_property_int(ctxt, udi, prop, &err); + rv = dbus_error_is_set(&err); + dbus_error_free(&err); + if (rv == 0) + *val_p = val; + + return rv; +} + +static int get_bool_prop(LibHalContext *ctxt, const char *udi, + const char *prop, int *val_p) +{ + DBusError err; + int val; + int rv; + + dbus_error_init(&err); + val = libhal_device_get_property_bool(ctxt, udi, prop, &err); + rv = dbus_error_is_set(&err); + dbus_error_free(&err); + if (rv == 0) + *val_p = val; + + return rv; +} + +static int get_uint64_prop(LibHalContext *ctxt, const char *udi, + const char *prop, unsigned long long *val_p) +{ + DBusError err; + unsigned long long val; + int rv; + + dbus_error_init(&err); + val = libhal_device_get_property_uint64(ctxt, udi, prop, &err); + rv = dbus_error_is_set(&err); + dbus_error_free(&err); + if (rv == 0) + *val_p = val; + + return rv; +} + +static int gather_pci_cap(LibHalContext *ctx, const char *udi, + union _virNodeDevCapData *d) +{ + char *sysfs_path; + + if (get_str_prop(ctx, udi, "pci.linux.sysfs_path", &sysfs_path) == 0) { + char *p = strrchr(sysfs_path, '/'); + if (p) { + (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.domain); + (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.bus); + (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.slot); + (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.function); + } + VIR_FREE(sysfs_path); + } + (void)get_int_prop(ctx, udi, "pci.vendor_id", (int *)&d->pci_dev.vendor); + if (get_str_prop(ctx, udi, "pci.vendor", &d->pci_dev.vendor_name) != 0) + (void)get_str_prop(ctx, udi, "info.vendor", &d->pci_dev.vendor_name); + (void)get_int_prop(ctx, udi, "pci.product_id", (int *)&d->pci_dev.product); + if (get_str_prop(ctx, udi, "pci.product", &d->pci_dev.product_name) != 0) + (void)get_str_prop(ctx, udi, "info.product", &d->pci_dev.product_name); + return 0; +} + + +static int gather_usb_cap(LibHalContext *ctx, const char *udi, + union _virNodeDevCapData *d) +{ + (void)get_int_prop(ctx, udi, "usb.interface.number", + (int *)&d->usb_if.number); + (void)get_int_prop(ctx, udi, "usb.interface.class", + (int *)&d->usb_if._class); + (void)get_int_prop(ctx, udi, "usb.interface.subclass", + (int *)&d->usb_if.subclass); + (void)get_int_prop(ctx, udi, "usb.interface.protocol", + (int *)&d->usb_if.protocol); + (void)get_str_prop(ctx, udi, "usb.interface.description", + &d->usb_if.description); + return 0; +} + + +static int gather_usb_device_cap(LibHalContext *ctx, const char *udi, + union _virNodeDevCapData *d) +{ + (void)get_int_prop(ctx, udi, "usb_device.bus_number", + (int *)&d->usb_dev.bus); + (void)get_int_prop(ctx, udi, "usb_device.linux.device_number", + (int *)&d->usb_dev.device); + (void)get_int_prop(ctx, udi, "usb_device.vendor_id", + (int *)&d->usb_dev.vendor); + if (get_str_prop(ctx, udi, "usb_device.vendor", + &d->usb_dev.vendor_name) != 0) + (void)get_str_prop(ctx, udi, "info.vendor", &d->usb_dev.vendor_name); + (void)get_int_prop(ctx, udi, "usb_device.product_id", + (int *)&d->usb_dev.product); + if (get_str_prop(ctx, udi, "usb_device.product", + &d->usb_dev.product_name) != 0) + (void)get_str_prop(ctx, udi, "info.product", &d->usb_dev.product_name); + return 0; +} + + +static int gather_net_cap(LibHalContext *ctx, const char *udi, + union _virNodeDevCapData *d) +{ + (void)get_str_prop(ctx, udi, "net.interface", &d->net.interface); + (void)get_str_prop(ctx, udi, "net.address", &d->net.address); + if (get_uint64_prop(ctx, udi, "net.80203.mac_address", + &d->net.data.ieee80203.mac_address) == 0) + d->net.subtype = VIR_NODE_DEV_CAP_NET_80203; + else if (get_uint64_prop(ctx, udi, "net.80211.mac_address", + &d->net.data.ieee80211.mac_address) == 0) + d->net.subtype = VIR_NODE_DEV_CAP_NET_80211; + else + d->net.subtype = VIR_NODE_DEV_CAP_NET_LAST; + + return 0; +} + + +static int gather_block_cap(LibHalContext *ctx, const char *udi, + union _virNodeDevCapData *d) +{ + (void)get_str_prop(ctx, udi, "block.device", &d->block.device); + return 0; +} + + +static int gather_scsi_host_cap(LibHalContext *ctx, const char *udi, + union _virNodeDevCapData *d) +{ + (void)get_int_prop(ctx, udi, "scsi_host.host", (int *)&d->scsi_host.host); + return 0; +} + + +static int gather_scsi_cap(LibHalContext *ctx, const char *udi, + union _virNodeDevCapData *d) +{ + (void)get_int_prop(ctx, udi, "scsi.host", (int *)&d->scsi.host); + (void)get_int_prop(ctx, udi, "scsi.bus", (int *)&d->scsi.bus); + (void)get_int_prop(ctx, udi, "scsi.target", (int *)&d->scsi.target); + (void)get_int_prop(ctx, udi, "scsi.lun", (int *)&d->scsi.lun); + (void)get_str_prop(ctx, udi, "scsi.type", &d->scsi.type); + return 0; +} + + +static int gather_storage_cap(LibHalContext *ctx, const char *udi, + union _virNodeDevCapData *d) +{ + int val; + (void)get_str_prop(ctx, udi, "storage.bus", &d->storage.bus); + (void)get_str_prop(ctx, udi, "storage.drive_type", &d->storage.drive_type); + (void)get_str_prop(ctx, udi, "storage.model", &d->storage.model); + (void)get_str_prop(ctx, udi, "storage.vendor", &d->storage.vendor); + if (get_bool_prop(ctx, udi, "storage.removable", &val) == 0 && val) { + d->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_REMOVABLE; + if (get_bool_prop(ctx, udi, + "storage.removable.media_available", &val) && val) { + d->storage.flags |= + VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE; + (void)get_uint64_prop(ctx, udi, "storage.removable.media_size", + &d->storage.removable_media_size); + } + } else { + (void)get_uint64_prop(ctx, udi, "storage.size", &d->storage.size); + } + if (get_bool_prop(ctx, udi, "storage.hotpluggable", &val) == 0 && val) + d->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE; + return 0; +} + + +static int gather_system_cap(LibHalContext *ctx, const char *udi, + union _virNodeDevCapData *d) +{ + char *uuidstr; + + (void)get_str_prop(ctx, udi, "system.product", &d->system.product_name); + (void)get_str_prop(ctx, udi, "system.hardware.vendor", + &d->system.hardware.vendor_name); + (void)get_str_prop(ctx, udi, "system.hardware.version", + &d->system.hardware.version); + (void)get_str_prop(ctx, udi, "system.hardware.serial", + &d->system.hardware.serial); + if (get_str_prop(ctx, udi, "system.hardware.uuid", &uuidstr) == 0) { + (void)virUUIDParse(uuidstr, d->system.hardware.uuid); + VIR_FREE(uuidstr); + } + (void)get_str_prop(ctx, udi, "system.firmware.vendor", + &d->system.firmware.vendor_name); + (void)get_str_prop(ctx, udi, "system.firmware.version", + &d->system.firmware.version); + (void)get_str_prop(ctx, udi, "system.firmware.release_date", + &d->system.firmware.release_date); + return 0; +} + + +struct _caps_tbl_entry { + const char *cap_name; + enum virNodeDevCapType type; + int (*gather_fn)(LibHalContext *ctx, + const char *udi, + union _virNodeDevCapData *data); +}; + +typedef struct _caps_tbl_entry caps_tbl_entry; + +static caps_tbl_entry caps_tbl[] = { + { "system", VIR_NODE_DEV_CAP_SYSTEM, gather_system_cap }, + { "pci", VIR_NODE_DEV_CAP_PCI_DEV, gather_pci_cap }, + { "usb", VIR_NODE_DEV_CAP_USB_INTERFACE, gather_usb_cap }, + { "usb_device", VIR_NODE_DEV_CAP_USB_DEV, gather_usb_device_cap }, + { "net", VIR_NODE_DEV_CAP_NET, gather_net_cap }, + { "block", VIR_NODE_DEV_CAP_BLOCK, gather_block_cap }, + { "scsi_host", VIR_NODE_DEV_CAP_SCSI_HOST, gather_scsi_host_cap }, + { "scsi", VIR_NODE_DEV_CAP_SCSI, gather_scsi_cap }, + { "storage", VIR_NODE_DEV_CAP_STORAGE, gather_storage_cap }, +}; + + +/* qsort/bsearch string comparator */ +static int cmpstringp(const void *p1, const void *p2) +{ + /* from man 3 qsort */ + return strcmp(* (char * const *) p1, * (char * const *) p2); +} + + +static int gather_capability(LibHalContext *ctx, const char *udi, + const char *cap_name, + virNodeDevCapsDefPtr *caps_p) +{ + caps_tbl_entry *entry; + + entry = bsearch(&cap_name, caps_tbl, ARRAY_CARDINALITY(caps_tbl), + sizeof(caps_tbl[0]), cmpstringp); + + if (entry) { + virNodeDevCapsDefPtr caps; + if (VIR_ALLOC(caps) < 0) + return ENOMEM; + caps->type = entry->type; + if (entry->gather_fn) { + int rv = (*entry->gather_fn)(ctx, udi, &caps->data); + if (rv != 0) { + virNodeDevCapsDefFree(caps); + return rv; + } + } + caps->next = *caps_p; + *caps_p = caps; + } + + return 0; +} + + +static int gather_capabilities(LibHalContext *ctx, const char *udi, + virNodeDevCapsDefPtr *caps_p) +{ + char *bus_name = NULL; + virNodeDevCapsDefPtr caps = NULL; + char **hal_cap_names; + int rv, i; + + if (STREQ(udi, "/org/freedesktop/Hal/devices/computer")) { + rv = gather_capability(ctx, udi, "system", &caps); + if (rv != 0) + goto failure; + } + + if (get_str_prop(ctx, udi, "info.subsystem", &bus_name) == 0) { + rv = gather_capability(ctx, udi, bus_name, &caps); + if (rv != 0) + goto failure; + } + + hal_cap_names = libhal_device_get_property_strlist(ctx, udi, + "info.capabilities", + NULL); + if (hal_cap_names) { + for (i = 0; hal_cap_names[i]; i++) { + if (! (bus_name && STREQ(hal_cap_names[i], bus_name))) { + rv = gather_capability(ctx, udi, hal_cap_names[i], &caps); + if (rv != 0) + goto failure; + } + } + for (i = 0; hal_cap_names[i]; i++) + VIR_FREE(hal_cap_names[i]); + VIR_FREE(hal_cap_names); + } + VIR_FREE(bus_name); + + *caps_p = caps; + return 0; + + failure: + VIR_FREE(bus_name); + if (hal_cap_names) { + for (i = 0; hal_cap_names[i]; i++) + VIR_FREE(hal_cap_names[i]); + VIR_FREE(hal_cap_names); + } + while (caps) { + virNodeDevCapsDefPtr next = caps->next; + virNodeDevCapsDefFree(caps); + caps = next; + } + return rv; +} + +static void free_udi(void *udi) +{ + VIR_FREE(udi); +} + +static void dev_create(char *udi) +{ + LibHalContext *ctx = DRV_STATE_HAL_CTX(driverState); + char *parent_key = NULL; + virNodeDeviceObjPtr dev; + const char *name = hal_name(udi); + int rv; + + if (VIR_ALLOC(dev) < 0 || VIR_ALLOC(dev->def) < 0) + goto failure; + + dev->privateData = udi; + dev->privateFree = free_udi; + + if ((dev->def->name = strdup(name)) == NULL) + goto failure; + + if (get_str_prop(ctx, udi, "info.parent", &parent_key) == 0) { + dev->def->parent = strdup(hal_name(parent_key)); + VIR_FREE(parent_key); + if (dev->def->parent == NULL) + goto failure; + } + + rv = gather_capabilities(ctx, udi, &dev->def->caps); + if (rv != 0) goto failure; + + if (VIR_REALLOC_N(driverState->devs.objs, driverState->devs.count + 1) < 0) + goto failure; + + driverState->devs.objs[driverState->devs.count++] = dev; + + return; + + failure: + DEBUG("FAILED TO ADD dev %s", name); + if (dev) + virNodeDeviceDefFree(dev->def); + VIR_FREE(dev); + VIR_FREE(udi); +} + + +static void device_added(LibHalContext *ctx ATTRIBUTE_UNUSED, + const char *udi) +{ + DEBUG0(hal_name(udi)); + dev_create(strdup(udi)); +} + + +static void device_removed(LibHalContext *ctx ATTRIBUTE_UNUSED, + const char *udi) +{ + const char *name = hal_name(udi); + virNodeDeviceObjPtr dev = virNodeDeviceFindByName(&driverState->devs,name); + DEBUG0(name); + if (dev) + virNodeDeviceObjRemove(&driverState->devs, dev); + else + DEBUG("no device named %s", name); +} + + +static void device_cap_added(LibHalContext *ctx, + const char *udi, const char *cap) +{ + const char *name = hal_name(udi); + virNodeDeviceObjPtr dev = virNodeDeviceFindByName(&driverState->devs,name); + DEBUG("%s %s", cap, name); + if (dev) + (void)gather_capability(ctx, udi, cap, &dev->def->caps); + else + DEBUG("no device named %s", name); +} + + +static void device_cap_lost(LibHalContext *ctx ATTRIBUTE_UNUSED, + const char *udi, + const char *cap) +{ + const char *name = hal_name(udi); + virNodeDeviceObjPtr dev = virNodeDeviceFindByName(&driverState->devs,name); + DEBUG("%s %s", cap, name); + if (dev) { + /* Simply "rediscover" device -- incrementally handling changes + * to sub-capabilities (like net.80203) is nasty ... so avoid it. + */ + virNodeDeviceObjRemove(&driverState->devs, dev); + dev_create(strdup(udi)); + } else + DEBUG("no device named %s", name); +} + + +static void device_prop_modified(LibHalContext *ctx ATTRIBUTE_UNUSED, + const char *udi, + const char *key, + dbus_bool_t is_removed ATTRIBUTE_UNUSED, + dbus_bool_t is_added ATTRIBUTE_UNUSED) +{ + const char *name = hal_name(udi); + virNodeDeviceObjPtr dev = virNodeDeviceFindByName(&driverState->devs,name); + DEBUG("%s %s", key, name); + if (dev) { + /* Simply "rediscover" device -- incrementally handling changes + * to properties (which are mapped into caps in very capability- + * specific ways) is nasty ... so avoid it. + */ + virNodeDeviceObjRemove(&driverState->devs, dev); + dev_create(strdup(udi)); + } else + DEBUG("no device named %s", name); +} + + +static void dbus_watch_callback(int fd ATTRIBUTE_UNUSED, + int events, void *opaque) +{ + DBusWatch *watch = opaque; + LibHalContext *hal_ctx = DRV_STATE_HAL_CTX(driverState); + DBusConnection *dbus_conn = libhal_ctx_get_dbus_connection(hal_ctx); + int dbus_flags = 0; + + if (events & VIR_EVENT_HANDLE_READABLE) + dbus_flags |= DBUS_WATCH_READABLE; + if (events & VIR_EVENT_HANDLE_WRITABLE) + dbus_flags |= DBUS_WATCH_WRITABLE; + if (events & VIR_EVENT_HANDLE_ERROR) + dbus_flags |= DBUS_WATCH_ERROR; + if (events & VIR_EVENT_HANDLE_HANGUP) + dbus_flags |= DBUS_WATCH_HANGUP; + + (void)dbus_watch_handle(watch, dbus_flags); + + while (dbus_connection_dispatch(dbus_conn) == DBUS_DISPATCH_DATA_REMAINS) + /* keep dispatching while data remains */; +} + + +static int xlate_dbus_watch_flags(int dbus_flags) +{ + unsigned int flags = 0; + if (dbus_flags & DBUS_WATCH_READABLE) + flags |= VIR_EVENT_HANDLE_READABLE; + if (dbus_flags & DBUS_WATCH_WRITABLE) + flags |= VIR_EVENT_HANDLE_WRITABLE; + if (dbus_flags & DBUS_WATCH_ERROR) + flags |= VIR_EVENT_HANDLE_ERROR; + if (dbus_flags & DBUS_WATCH_HANGUP) + flags |= VIR_EVENT_HANDLE_HANGUP; + return flags; +} + + +static dbus_bool_t add_dbus_watch(DBusWatch *watch, + void *data ATTRIBUTE_UNUSED) +{ + int flags = 0; + + if (dbus_watch_get_enabled(watch)) + flags = xlate_dbus_watch_flags(dbus_watch_get_flags(watch)); + + return virEventAddHandle(dbus_watch_get_unix_fd(watch), flags, + dbus_watch_callback, watch) == 0; +} + + +static void remove_dbus_watch(DBusWatch *watch, + void *data ATTRIBUTE_UNUSED) +{ + (void)virEventRemoveHandle(dbus_watch_get_unix_fd(watch)); +} + + +static void toggle_dbus_watch(DBusWatch *watch, + void *data ATTRIBUTE_UNUSED) +{ + int flags = 0; + + if (dbus_watch_get_enabled(watch)) + flags = xlate_dbus_watch_flags(dbus_watch_get_flags(watch)); + + (void)virEventUpdateHandle(dbus_watch_get_unix_fd(watch), flags); +} + + +static int halDeviceMonitorStartup(void) +{ + LibHalContext *hal_ctx = NULL; + DBusConnection *dbus_conn = NULL; + DBusError err; + char **udi = NULL; + int num_devs, i; + + /* Ensure caps_tbl is sorted by capability name */ + qsort(caps_tbl, ARRAY_CARDINALITY(caps_tbl), sizeof(caps_tbl[0]), + cmpstringp); + + if (VIR_ALLOC(driverState) < 0) + return -1; + + /* Allocate and initialize a new HAL context */ + dbus_error_init(&err); + hal_ctx = libhal_ctx_new(); + if (hal_ctx == NULL) { + fprintf(stderr, "%s: libhal_ctx_new returned NULL\n", __FUNCTION__); + goto failure; + } + dbus_conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); + if (dbus_conn == NULL) { + fprintf(stderr, "%s: dbus_bus_get failed\n", __FUNCTION__); + goto failure; + } + if (!libhal_ctx_set_dbus_connection(hal_ctx, dbus_conn)) { + fprintf(stderr, "%s: libhal_ctx_set_dbus_connection failed\n", + __FUNCTION__); + goto failure; + } + if (!libhal_ctx_init(hal_ctx, &err)) { + fprintf(stderr, "%s: libhal_ctx_init failed\n", __FUNCTION__); + goto failure; + } + + /* Register dbus watch callbacks */ + if (!dbus_connection_set_watch_functions(dbus_conn, + add_dbus_watch, + remove_dbus_watch, + toggle_dbus_watch, + NULL, NULL)) { + fprintf(stderr, "%s: dbus_connection_set_watch_functions failed\n", + __FUNCTION__); + goto failure; + } + + /* Register HAL event callbacks */ + if (!libhal_ctx_set_device_added(hal_ctx, device_added) || + !libhal_ctx_set_device_removed(hal_ctx, device_removed) || + !libhal_ctx_set_device_new_capability(hal_ctx, device_cap_added) || + !libhal_ctx_set_device_lost_capability(hal_ctx, device_cap_lost) || + !libhal_ctx_set_device_property_modified(hal_ctx, device_prop_modified)) { + fprintf(stderr, "%s: setting up HAL callbacks failed\n", __FUNCTION__); + goto failure; + } + + /* Populate with known devices */ + driverState->privateData = hal_ctx; + udi = libhal_get_all_devices(hal_ctx, &num_devs, &err); + if (udi == NULL) { + fprintf(stderr, "%s: libhal_get_all_devices failed\n", __FUNCTION__); + goto failure; + } + for (i = 0; i < num_devs; i++) + dev_create(udi[i]); + free(udi); + + return 0; + + failure: + if (dbus_error_is_set(&err)) { + fprintf(stderr, "\t%s: %s\n", err.name, err.message); + dbus_error_free(&err); + } + virNodeDeviceObjListFree(&driverState->devs); + if (hal_ctx) + (void)libhal_ctx_free(hal_ctx); + if (udi) { + for (i = 0; i < num_devs; i++) + free(udi[i]); + free(udi); + } + VIR_FREE(driverState); + + return -1; +} + + +static int halDeviceMonitorShutdown(void) +{ + if (driverState) { + LibHalContext *hal_ctx = DRV_STATE_HAL_CTX(driverState); + virNodeDeviceObjListFree(&driverState->devs); + (void)libhal_ctx_shutdown(hal_ctx, NULL); + (void)libhal_ctx_free(hal_ctx); + VIR_FREE(driverState); + return 0; + } + return -1; +} + + +static int halDeviceMonitorReload(void) +{ + (void)halDeviceMonitorShutdown(); + return halDeviceMonitorStartup(); +} + + +static int halDeviceMonitorActive(void) +{ + /* Always ready to deal with a shutdown */ + return 0; +} + + +static virDrvOpenStatus halNodeDrvOpen(virConnectPtr conn, + virConnectAuthPtr auth ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED) +{ + if (driverState == NULL) + return VIR_DRV_OPEN_DECLINED; + + conn->devMonPrivateData = driverState; + + return VIR_DRV_OPEN_SUCCESS; +} + +static int halNodeDrvClose(virConnectPtr conn ATTRIBUTE_UNUSED) +{ + conn->devMonPrivateData = NULL; + return 0; +} + + +static virNodeDevicePtr halNodeDeviceCreate(virConnectPtr conn ATTRIBUTE_UNUSED, + const char *xml ATTRIBUTE_UNUSED, + unsigned int flags ATTRIBUTE_UNUSED) +{ + return NULL; +} + +static int halNodeDeviceDestroy(virNodeDevicePtr dev ATTRIBUTE_UNUSED, + unsigned int flags ATTRIBUTE_UNUSED) +{ + return -1; +} + +static virDeviceMonitor halDeviceMonitor = { + .name = "halDeviceMonitor", + .open = halNodeDrvOpen, + .close = halNodeDrvClose, + .deviceCreate = halNodeDeviceCreate, + .deviceDestroy = halNodeDeviceDestroy, +}; + + +static virStateDriver halStateDriver = { + .initialize = halDeviceMonitorStartup, + .cleanup = halDeviceMonitorShutdown, + .reload = halDeviceMonitorReload, + .active = halDeviceMonitorActive, +}; + +int halNodeRegister(void) +{ + registerCommonNodeFuncs(&halDeviceMonitor); + if (virRegisterDeviceMonitor(&halDeviceMonitor) < 0) + return -1; + return virRegisterStateDriver(&halStateDriver); +} -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Thu, Nov 13, 2008 at 05:33:20PM +0000, Daniel P. Berrange wrote:
This is the main implementation of the local device enumation driver. The main change since David's patch is that we hav a single nodedevRegister() API call, instead of initializing HAL/DevKit separtely. This was needed to make the dlopen() support easier to implement. Functionally the end result is the same.
again, largely reviewed already, +1 Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Thu, 2008-11-13 at 17:33 +0000, Daniel P. Berrange wrote:
This is the main implementation of the local device enumation driver. The main change since David's patch is that we hav a single nodedevRegister() API call, instead of initializing HAL/DevKit separtely. This was needed to make the dlopen() support easier to implement. Functionally the end result is the same.
The DeviceKit implementation seems to be much more of a work-in-progress than the HAL implementation - maybe disable it by default in configure? (i.e. with_devkit=no instead of with_devkit=check)
diff -r acac4fc31665 src/node_device.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/node_device.c Thu Nov 13 17:10:30 2008 +0000 ... +static int nodeListDevicesByCap(virConnectPtr conn, + const char *cap, + char **const names, + int maxnames, + unsigned int flags ATTRIBUTE_UNUSED) +{ + virDeviceMonitorStatePtr driver = conn->devMonPrivateData; + int ndevs = 0; + unsigned int i; + + for (i = 0; i < driver->devs.count && ndevs < maxnames; i++) + if (dev_has_cap(driver->devs.objs[i], cap)) + if ((names[ndevs++] = strdup(driver->devs.objs[i]->def->name)) == NULL) + goto failure;
Over 80 columns here and would be easier to read if split up
+ + return ndevs; + + failure: + --ndevs; + while (--ndevs >= 0) + VIR_FREE(names[ndevs]); + return -1; +} + ... diff -r acac4fc31665 src/node_device_devkit.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/node_device_devkit.c Thu Nov 13 17:10:30 2008 +0000 ... +static int gather_net_cap(DevkitDevice *dkdev, + union _virNodeDevCapData *d) +{ + const char *sysfs_path = devkit_device_get_native_path(dkdev); + const char *interface; + + if (sysfs_path == NULL) + return -1; + interface = strrchr(sysfs_path, '/'); + if (!interface && *interface && *(++interface)) + return -1;
Was this meant to be: if (!interface || !*interface || !*(++interface))
+ if ((d->net.interface = strdup(interface)) == NULL) + return -1; + + d->net.subtype = VIR_NODE_DEV_CAP_NET_LAST; + + return 0; +} + + ... +static void dev_create(void *_dkdev, void *_dkclient ATTRIBUTE_UNUSED) +{ + DevkitDevice *dkdev = _dkdev; + const char *sysfs_path = devkit_device_get_native_path(dkdev); + virNodeDeviceObjPtr dev = NULL; + const char *name; + int rv; + + if (sysfs_path == NULL) + /* Currently using basename(sysfs_path) as device name (key) */ + return; + + name = strrchr(sysfs_path, '/'); + if (name == NULL) + name = sysfs_path; + else + ++name; + + if (VIR_ALLOC(dev) < 0 || VIR_ALLOC(dev->def) < 0) + goto failure; + + dev->privateData = dkdev;
You need need a privateFree() hook here to do g_object_unref(), I think
+ + if ((dev->def->name = strdup(name)) == NULL) + goto failure; + + // TODO: Find device parent, if any + + rv = gather_capabilities(dkdev, &dev->def->caps); + if (rv != 0) goto failure; + + if (VIR_REALLOC_N(driverState->devs.objs, driverState->devs.count + 1) < 0) + goto failure; + + driverState->devs.objs[driverState->devs.count++] = dev;
Add a virNodeDeviceObjAdd() function for this?
+ + return; + + failure: + DEBUG("FAILED TO ADD dev %s", name); + if (dev) + virNodeDeviceDefFree(dev->def); + VIR_FREE(dev); +} + + +static int devkitDeviceMonitorStartup(void) +{ + size_t caps_tbl_len = sizeof(caps_tbl) / sizeof(caps_tbl[0]); + DevkitClient *devkit_client = NULL; + GError *err = NULL; + GList *devs; + int i; + + /* Ensure caps_tbl is sorted by capability name */ + qsort(caps_tbl, caps_tbl_len, sizeof(caps_tbl[0]), cmpstringp); + + if (VIR_ALLOC(driverState) < 0) + return -1; + + // TODO: Is it really ok to call this multiple times?? + // Is there something analogous to call on close? + g_type_init();
Yep, it's fine to call multiple times and there's no shutdown version.
+ + /* Get new devkit_client and connect to daemon */ + devkit_client = devkit_client_new(NULL); + if (devkit_client == NULL) { + DEBUG0("devkit_client_new returned NULL"); + goto failure; + } + if (!devkit_client_connect(devkit_client, &err)) { + DEBUG0("devkit_client_connect failed"); + goto failure; + } + + /* Populate with known devices. + * + * This really should be: + devs = devkit_client_enumerate_by_subsystem(devkit_client, NULL, &err); + if (err) { + DEBUG0("devkit_client_enumerate_by_subsystem failed"); + devs = NULL; + goto failure; + } + g_list_foreach(devs, dev_create, devkit_client); + * but devkit_client_enumerate_by_subsystem currently fails when the second + * arg is null (contrary to the API documentation). So the following code + * (from Dan B) works around this by listing devices per handled subsystem. + */ + + for (i = 0 ; i < ARRAY_CARDINALITY(caps_tbl) ; i++) { + const char *caps[] = { caps_tbl[i].cap_name, NULL }; + devs = devkit_client_enumerate_by_subsystem(devkit_client, + caps, + &err); + if (err) { + DEBUG0("devkit_client_enumerate_by_subsystem failed"); + devs = NULL; + goto failure; + } + g_list_foreach(devs, dev_create, devkit_client);
Need a g_list_free() here right?
+ } + + driverState->privateData = devkit_client; + + // TODO: Register to get DeviceKit events on device changes and + // coordinate updates with queries and other operations.
That's a pretty big missing feature - if both HAL and DevKit were available on a system, we'd still want HAL until this is fixed, right?
+ + return 0; + + failure: + if (err) { + DEBUG("\terror[%d]: %s", err->code, err->message); + g_error_free(err); + } + if (devs) { + g_list_foreach(devs, (GFunc)g_object_unref, NULL); + g_list_free(devs); + } + if (devkit_client) + g_object_unref(devkit_client); + VIR_FREE(driverState); + + return -1; +} ... diff -r acac4fc31665 src/node_device_hal.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/node_device_hal.c Thu Nov 13 17:10:30 2008 +0000 ... +static int gather_pci_cap(LibHalContext *ctx, const char *udi, + union _virNodeDevCapData *d) +{ + char *sysfs_path; + + if (get_str_prop(ctx, udi, "pci.linux.sysfs_path", &sysfs_path) == 0) { + char *p = strrchr(sysfs_path, '/'); + if (p) { + (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.domain); + (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.bus); + (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.slot); + (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.function); + } + VIR_FREE(sysfs_path); + } + (void)get_int_prop(ctx, udi, "pci.vendor_id", (int *)&d->pci_dev.vendor); + if (get_str_prop(ctx, udi, "pci.vendor", &d->pci_dev.vendor_name) != 0) + (void)get_str_prop(ctx, udi, "info.vendor", &d->pci_dev.vendor_name); + (void)get_int_prop(ctx, udi, "pci.product_id", (int *)&d->pci_dev.product); + if (get_str_prop(ctx, udi, "pci.product", &d->pci_dev.product_name) != 0) + (void)get_str_prop(ctx, udi, "info.product", &d->pci_dev.product_name);
By the way - vendor and product IDs are normally quoted in hex, not decimal - e.g. I'd know my NIC is 8086:10de, not 32902:4318 I guess most other integer values in libvirt XML are decimal, but might be worth adding a hex format for this?
+ return 0; +} ... +static void device_cap_lost(LibHalContext *ctx ATTRIBUTE_UNUSED, + const char *udi, + const char *cap) +{ + const char *name = hal_name(udi); + virNodeDeviceObjPtr dev = virNodeDeviceFindByName(&driverState->devs,name); + DEBUG("%s %s", cap, name); + if (dev) { + /* Simply "rediscover" device -- incrementally handling changes + * to sub-capabilities (like net.80203) is nasty ... so avoid it. + */ + virNodeDeviceObjRemove(&driverState->devs, dev); + dev_create(strdup(udi)); + } else + DEBUG("no device named %s", name); +} + + +static void device_prop_modified(LibHalContext *ctx ATTRIBUTE_UNUSED, + const char *udi, + const char *key, + dbus_bool_t is_removed ATTRIBUTE_UNUSED, + dbus_bool_t is_added ATTRIBUTE_UNUSED) +{ + const char *name = hal_name(udi); + virNodeDeviceObjPtr dev = virNodeDeviceFindByName(&driverState->devs,name); + DEBUG("%s %s", key, name); + if (dev) { + /* Simply "rediscover" device -- incrementally handling changes + * to properties (which are mapped into caps in very capability- + * specific ways) is nasty ... so avoid it. + */ + virNodeDeviceObjRemove(&driverState->devs, dev); + dev_create(strdup(udi)); + } else + DEBUG("no device named %s", name); +}
Could use the same callback for both of these (with a cast), or simplify them to: static void device_prop_modified(LibHalContext *ctx ATTRIBUTE_UNUSED, const char *udi, const char *key, dbus_bool_t is_removed ATTRIBUTE_UNUSED, dbus_bool_t is_added ATTRIBUTE_UNUSED) { DEBUG("%s %s", key, name); /* Simply "rediscover" device -- incrementally handling changes * to properties (which are mapped into caps in very capability- * specific ways) is nasty ... so avoid it. */ device_removed(ctx, udi); device_added(ctx, udi); } Cheers, Mark.

On Fri, 2008-11-14 at 13:41 +0000, Mark McLoughlin wrote:
The DeviceKit implementation seems to be much more of a work-in-progress than the HAL implementation - maybe disable it by default in configure? (i.e. with_devkit=no instead of with_devkit=check)
That's a good idea. I don't think the devkit impl can go forward until devkit itself starts moving forward. (Hmmm ... I (now) see the devkit mailing list has started getting some traffic. Apparently they've just released v2. Perhaps it's time for another look, though I can't sign up for that right now.)
+ interface = strrchr(sysfs_path, '/'); + if (!interface && *interface && *(++interface)) + return -1;
Was this meant to be:
if (!interface || !*interface || !*(++interface))
Yes. Or the equivalent (! (interface && *interface && *(++interface)).
+static void dev_create(void *_dkdev, void *_dkclient ATTRIBUTE_UNUSED) +{ ... + + dev->privateData = dkdev;
You need need a privateFree() hook here to do g_object_unref(), I think
Yes. Good catch, again.
+ for (i = 0 ; i < ARRAY_CARDINALITY(caps_tbl) ; i++) { + const char *caps[] = { caps_tbl[i].cap_name, NULL }; + devs = devkit_client_enumerate_by_subsystem(devkit_client, + caps, + &err); + if (err) { + DEBUG0("devkit_client_enumerate_by_subsystem failed"); + devs = NULL; + goto failure; + } + g_list_foreach(devs, dev_create, devkit_client);
Need a g_list_free() here right?
Yes ...
+ } + + driverState->privateData = devkit_client; + + // TODO: Register to get DeviceKit events on device changes and + // coordinate updates with queries and other operations.
That's a pretty big missing feature - if both HAL and DevKit were available on a system, we'd still want HAL until this is fixed, right?
Absolutely. I think this supports your request that this be disabled by default.
+ (void)get_int_prop(ctx, udi, "pci.vendor_id", (int *)&d->pci_dev.vendor); + if (get_str_prop(ctx, udi, "pci.vendor", &d->pci_dev.vendor_name) != 0) + (void)get_str_prop(ctx, udi, "info.vendor", &d->pci_dev.vendor_name); + (void)get_int_prop(ctx, udi, "pci.product_id", (int *)&d->pci_dev.product); + if (get_str_prop(ctx, udi, "pci.product", &d->pci_dev.product_name) != 0) + (void)get_str_prop(ctx, udi, "info.product", &d->pci_dev.product_name);
By the way - vendor and product IDs are normally quoted in hex, not decimal - e.g. I'd know my NIC is 8086:10de, not 32902:4318
I guess most other integer values in libvirt XML are decimal, but might be worth adding a hex format for this?
I'd prefer hex for vid/pid as well; I just stuck with decimal since the rest of libvirt does. If this does get changed to output hex, I'd only request that we prefix hex numbers with "0x" so people don't have to remember which attrs are dumped in hex and which in decimal.
+static void device_prop_modified(LibHalContext *ctx ATTRIBUTE_UNUSED, + const char *udi, + const char *key, + dbus_bool_t is_removed ATTRIBUTE_UNUSED, + dbus_bool_t is_added ATTRIBUTE_UNUSED) +{ + const char *name = hal_name(udi); + virNodeDeviceObjPtr dev = virNodeDeviceFindByName(&driverState->devs,name); + DEBUG("%s %s", key, name); + if (dev) { + /* Simply "rediscover" device -- incrementally handling changes + * to properties (which are mapped into caps in very capability- + * specific ways) is nasty ... so avoid it. + */ + virNodeDeviceObjRemove(&driverState->devs, dev); + dev_create(strdup(udi)); + } else + DEBUG("no device named %s", name); +}
Could use the same callback for both of these (with a cast), or simplify them to:
static void device_prop_modified(LibHalContext *ctx ATTRIBUTE_UNUSED, const char *udi, const char *key, dbus_bool_t is_removed ATTRIBUTE_UNUSED, dbus_bool_t is_added ATTRIBUTE_UNUSED) { DEBUG("%s %s", key, name);
/* Simply "rediscover" device -- incrementally handling changes * to properties (which are mapped into caps in very capability- * specific ways) is nasty ... so avoid it. */ device_removed(ctx, udi); device_added(ctx, udi); }
Yep, that's a good idea. Thanks for the careful review, Dave

On Fri, Nov 14, 2008 at 02:57:09PM -0500, David Lively wrote:
+ (void)get_int_prop(ctx, udi, "pci.vendor_id", (int *)&d->pci_dev.vendor); + if (get_str_prop(ctx, udi, "pci.vendor", &d->pci_dev.vendor_name) != 0) + (void)get_str_prop(ctx, udi, "info.vendor", &d->pci_dev.vendor_name); + (void)get_int_prop(ctx, udi, "pci.product_id", (int *)&d->pci_dev.product); + if (get_str_prop(ctx, udi, "pci.product", &d->pci_dev.product_name) != 0) + (void)get_str_prop(ctx, udi, "info.product", &d->pci_dev.product_name);
By the way - vendor and product IDs are normally quoted in hex, not decimal - e.g. I'd know my NIC is 8086:10de, not 32902:4318
I guess most other integer values in libvirt XML are decimal, but might be worth adding a hex format for this?
I'd prefer hex for vid/pid as well; I just stuck with decimal since the rest of libvirt does. If this does get changed to output hex, I'd only request that we prefix hex numbers with "0x" so people don't have to remember which attrs are dumped in hex and which in decimal.
I've included the 0x prefix & padded to 4 digits minimum. Looks much nicer now :-) Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

This patch adds support for the node device APIs in the remote driver and daemon. This is basically just a re-diff to take account of earlier changes to the remote_protocol.x file Daniel diff -r 4b43fb269efe qemud/remote.c --- a/qemud/remote.c Wed Nov 12 21:12:02 2008 +0000 +++ b/qemud/remote.c Wed Nov 12 21:57:50 2008 +0000 @@ -67,6 +67,7 @@ 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); +static void make_nonnull_node_device (remote_nonnull_node_device *dev_dst, virNodeDevicePtr dev_src); #include "remote_dispatch_prototypes.h" @@ -3658,6 +3659,303 @@ } +/*************************************************************** + * NODE INFO APIS + **************************************************************/ + +static int +remoteDispatchNodeNumOfDevices (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, + remote_message_header *req, + remote_node_num_of_devices_args *args, + remote_node_num_of_devices_ret *ret) +{ + CHECK_CONN(client); + + ret->num = virNodeNumOfDevices (client->conn, args->flags); + if (ret->num == -1) return -1; + + return 0; +} + + +static int +remoteDispatchNodeListDevices (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, + remote_message_header *req, + remote_node_list_devices_args *args, + remote_node_list_devices_ret *ret) +{ + CHECK_CONN(client); + + if (args->maxnames > REMOTE_NODE_DEVICE_NAME_LIST_MAX) { + remoteDispatchError (client, req, + "%s", _("maxnames > REMOTE_NODE_DEVICE_NAME_LIST_MAX")); + return -2; + } + + /* Allocate return buffer. */ + if (VIR_ALLOC_N(ret->names.names_val, args->maxnames) < 0) { + remoteDispatchSendError(client, req, VIR_ERR_NO_MEMORY, NULL); + return -2; + } + + ret->names.names_len = + virNodeListDevices (client->conn, + ret->names.names_val, args->maxnames, args->flags); + if (ret->names.names_len == -1) { + VIR_FREE(ret->names.names_val); + return -1; + } + + return 0; +} + + +static int +remoteDispatchNodeNumOfDevicesByCap (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, + remote_message_header *req, + remote_node_num_of_devices_by_cap_args *args, + remote_node_num_of_devices_by_cap_ret *ret) +{ + CHECK_CONN(client); + + ret->num = virNodeNumOfDevicesByCap (client->conn, args->cap, args->flags); + if (ret->num == -1) return -1; + + return 0; +} + + +static int +remoteDispatchNodeListDevicesByCap (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, + remote_message_header *req, + remote_node_list_devices_by_cap_args *args, + remote_node_list_devices_by_cap_ret *ret) +{ + CHECK_CONN(client); + + if (args->maxnames > REMOTE_NODE_DEVICE_NAME_LIST_MAX) { + remoteDispatchError (client, req, + "%s", _("maxnames > REMOTE_NODE_DEVICE_NAME_LIST_MAX")); + return -2; + } + + /* Allocate return buffer. */ + if (VIR_ALLOC_N(ret->names.names_val, args->maxnames) < 0) { + remoteDispatchSendError(client, req, VIR_ERR_NO_MEMORY, NULL); + return -2; + } + + ret->names.names_len = + virNodeListDevicesByCap (client->conn, args->cap, + ret->names.names_val, args->maxnames, + args->flags); + if (ret->names.names_len == -1) { + VIR_FREE(ret->names.names_val); + return -1; + } + + return 0; +} + + +static int +remoteDispatchNodeDeviceLookupByName (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, + remote_message_header *req, + remote_node_device_lookup_by_name_args *args, + remote_node_device_lookup_by_name_ret *ret) +{ + virNodeDevicePtr dev; + + CHECK_CONN(client); + + dev = virNodeDeviceLookupByName (client->conn, args->name); + if (dev == NULL) return -1; + + make_nonnull_node_device (&ret->dev, dev); + virNodeDeviceFree(dev); + return 0; +} + + +static int +remoteDispatchNodeDeviceDumpXml (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, + remote_message_header *req, + remote_node_device_dump_xml_args *args, + remote_node_device_dump_xml_ret *ret) +{ + virNodeDevicePtr dev; + CHECK_CONN(client); + + dev = virNodeDeviceLookupByName(client->conn, args->name); + if (dev == NULL) { + remoteDispatchError (client, req, "%s", _("node_device not found")); + return -2; + } + + /* remoteDispatchClientRequest will free this. */ + ret->xml = virNodeDeviceGetXMLDesc (dev, args->flags); + if (!ret->xml) { + virNodeDeviceFree(dev); + return -1; + } + virNodeDeviceFree(dev); + return 0; +} + + +static int +remoteDispatchNodeDeviceGetParent (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, + remote_message_header *req, + remote_node_device_get_parent_args *args, + remote_node_device_get_parent_ret *ret) +{ + virNodeDevicePtr dev; + const char *parent; + CHECK_CONN(client); + + dev = virNodeDeviceLookupByName(client->conn, args->name); + if (dev == NULL) { + remoteDispatchError (client, req, "%s", _("node_device not found")); + return -2; + } + + parent = virNodeDeviceGetParent(dev); + + if (parent == NULL) { + ret->parent = NULL; + } else { + /* remoteDispatchClientRequest will free this. */ + char **parent_p; + if (VIR_ALLOC(parent_p) < 0) { + remoteDispatchSendError(client, req, VIR_ERR_NO_MEMORY, NULL); + return -2; + } + *parent_p = strdup(parent); + if (*parent_p == NULL) { + remoteDispatchSendError(client, req, VIR_ERR_NO_MEMORY, NULL); + return -2; + } + ret->parent = parent_p; + } + + virNodeDeviceFree(dev); + return 0; +} + + +static int +remoteDispatchNodeDeviceNumOfCaps (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, + remote_message_header *req, + remote_node_device_num_of_caps_args *args, + remote_node_device_num_of_caps_ret *ret) +{ + virNodeDevicePtr dev; + CHECK_CONN(client); + + dev = virNodeDeviceLookupByName(client->conn, args->name); + if (dev == NULL) { + remoteDispatchError (client, req, "%s", _("node_device not found")); + return -2; + } + + ret->num = virNodeDeviceNumOfCaps(dev); + + virNodeDeviceFree(dev); + return 0; +} + + +static int +remoteDispatchNodeDeviceListCaps (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, + remote_message_header *req, + remote_node_device_list_caps_args *args, + remote_node_device_list_caps_ret *ret) +{ + virNodeDevicePtr dev; + CHECK_CONN(client); + + dev = virNodeDeviceLookupByName(client->conn, args->name); + if (dev == NULL) { + remoteDispatchError (client, req, "%s", _("node_device not found")); + return -2; + } + + if (args->maxnames > REMOTE_NODE_DEVICE_NAME_LIST_MAX) { + remoteDispatchError (client, req, + "%s", _("maxnames > REMOTE_NODE_DEVICE_NAME_LIST_MAX")); + return -2; + } + + /* Allocate return buffer. */ + if (VIR_ALLOC_N(ret->names.names_val, args->maxnames) < 0) { + remoteDispatchSendError(client, req, VIR_ERR_NO_MEMORY, NULL); + return -2; + } + + ret->names.names_len = + virNodeDeviceListCaps (dev, ret->names.names_val, + args->maxnames); + if (ret->names.names_len == -1) { + VIR_FREE(ret->names.names_val); + return -1; + } + + return 0; +} + + +static int +remoteDispatchNodeDeviceCreate (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, + remote_message_header *req, + remote_node_device_create_args *args, + remote_node_device_create_ret *ret) +{ + virNodeDevicePtr dev; + + CHECK_CONN(client); + + dev = virNodeDeviceCreate (client->conn, args->xml, args->flags); + if (dev == NULL) return -1; + + make_nonnull_node_device (&ret->dev, dev); + virNodeDeviceFree(dev); + return 0; +} + + +static int +remoteDispatchNodeDeviceDestroy (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, + remote_message_header *req, + remote_node_device_destroy_args *args, + void *ret ATTRIBUTE_UNUSED) +{ + virNodeDevicePtr dev; + CHECK_CONN(client); + + dev = virNodeDeviceLookupByName(client->conn, args->name); + if (dev == NULL) { + remoteDispatchError (client, req, "%s", _("node_device not found")); + return -2; + } + + if (virNodeDeviceDestroy (dev, args->flags) < 0) { + virNodeDeviceFree(dev); + return -1; + } + virNodeDeviceFree(dev); + return 0; +} /************************** * Async Events **************************/ @@ -3781,6 +4079,7 @@ client->bufferLength = len; client->bufferOffset = 0; } + /*----- Helpers. -----*/ /* get_nonnull_domain and get_nonnull_network turn an on-wire @@ -3851,3 +4150,9 @@ vol_dst->name = strdup (vol_src->name); vol_dst->key = strdup (vol_src->key); } + +static void +make_nonnull_node_device (remote_nonnull_node_device *dev_dst, virNodeDevicePtr dev_src) +{ + dev_dst->name = strdup(dev_src->name); +} diff -r 4b43fb269efe qemud/remote_dispatch_localvars.h --- a/qemud/remote_dispatch_localvars.h Wed Nov 12 21:12:02 2008 +0000 +++ b/qemud/remote_dispatch_localvars.h Wed Nov 12 21:57:50 2008 +0000 @@ -7,6 +7,8 @@ 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_events_deregister_ret lv_remote_domain_events_deregister_ret; +remote_node_device_get_parent_args lv_remote_node_device_get_parent_args; +remote_node_device_get_parent_ret lv_remote_node_device_get_parent_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; @@ -34,7 +36,11 @@ remote_list_defined_networks_ret lv_remote_list_defined_networks_ret; remote_network_create_xml_args lv_remote_network_create_xml_args; remote_network_create_xml_ret lv_remote_network_create_xml_ret; +remote_node_device_list_caps_args lv_remote_node_device_list_caps_args; +remote_node_device_list_caps_ret lv_remote_node_device_list_caps_ret; remote_open_args lv_remote_open_args; +remote_node_device_create_args lv_remote_node_device_create_args; +remote_node_device_create_ret lv_remote_node_device_create_ret; remote_storage_pool_refresh_args lv_remote_storage_pool_refresh_args; remote_storage_vol_lookup_by_path_args lv_remote_storage_vol_lookup_by_path_args; remote_storage_vol_lookup_by_path_ret lv_remote_storage_vol_lookup_by_path_ret; @@ -42,6 +48,8 @@ remote_list_domains_ret lv_remote_list_domains_ret; remote_network_define_xml_args lv_remote_network_define_xml_args; remote_network_define_xml_ret lv_remote_network_define_xml_ret; +remote_node_list_devices_by_cap_args lv_remote_node_list_devices_by_cap_args; +remote_node_list_devices_by_cap_ret lv_remote_node_list_devices_by_cap_ret; remote_get_type_ret lv_remote_get_type_ret; remote_domain_block_peek_args lv_remote_domain_block_peek_args; remote_domain_block_peek_ret lv_remote_domain_block_peek_ret; @@ -67,6 +75,8 @@ remote_storage_pool_lookup_by_volume_ret lv_remote_storage_pool_lookup_by_volume_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_node_device_num_of_caps_args lv_remote_node_device_num_of_caps_args; +remote_node_device_num_of_caps_ret lv_remote_node_device_num_of_caps_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; @@ -80,8 +90,12 @@ 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; remote_domain_destroy_args lv_remote_domain_destroy_args; +remote_node_num_of_devices_by_cap_args lv_remote_node_num_of_devices_by_cap_args; +remote_node_num_of_devices_by_cap_ret lv_remote_node_num_of_devices_by_cap_ret; remote_find_storage_pool_sources_args lv_remote_find_storage_pool_sources_args; remote_find_storage_pool_sources_ret lv_remote_find_storage_pool_sources_ret; +remote_node_num_of_devices_args lv_remote_node_num_of_devices_args; +remote_node_num_of_devices_ret lv_remote_node_num_of_devices_ret; remote_auth_sasl_step_args lv_remote_auth_sasl_step_args; remote_auth_sasl_step_ret lv_remote_auth_sasl_step_ret; remote_domain_migrate_finish_args lv_remote_domain_migrate_finish_args; @@ -91,11 +105,17 @@ 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_node_get_info_ret lv_remote_node_get_info_ret; +remote_node_device_dump_xml_args lv_remote_node_device_dump_xml_args; +remote_node_device_dump_xml_ret lv_remote_node_device_dump_xml_ret; +remote_node_device_lookup_by_name_args lv_remote_node_device_lookup_by_name_args; +remote_node_device_lookup_by_name_ret lv_remote_node_device_lookup_by_name_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; remote_domain_memory_peek_args lv_remote_domain_memory_peek_args; remote_domain_memory_peek_ret lv_remote_domain_memory_peek_ret; remote_num_of_defined_domains_ret lv_remote_num_of_defined_domains_ret; +remote_node_list_devices_args lv_remote_node_list_devices_args; +remote_node_list_devices_ret lv_remote_node_list_devices_ret; remote_domain_block_stats_args lv_remote_domain_block_stats_args; remote_domain_block_stats_ret lv_remote_domain_block_stats_ret; remote_domain_detach_device_args lv_remote_domain_detach_device_args; @@ -162,6 +182,7 @@ 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_node_device_destroy_args lv_remote_node_device_destroy_args; remote_get_max_vcpus_args lv_remote_get_max_vcpus_args; remote_get_max_vcpus_ret lv_remote_get_max_vcpus_ret; remote_domain_migrate_perform_args lv_remote_domain_migrate_perform_args; diff -r 4b43fb269efe qemud/remote_dispatch_proc_switch.h --- a/qemud/remote_dispatch_proc_switch.h Wed Nov 12 21:12:02 2008 +0000 +++ b/qemud/remote_dispatch_proc_switch.h Wed Nov 12 21:57:50 2008 +0000 @@ -542,6 +542,66 @@ args = (char *) &lv_remote_network_undefine_args; memset (&lv_remote_network_undefine_args, 0, sizeof lv_remote_network_undefine_args); break; +case REMOTE_PROC_NODE_DEVICE_CREATE: + fn = (dispatch_fn) remoteDispatchNodeDeviceCreate; + args_filter = (xdrproc_t) xdr_remote_node_device_create_args; + args = (char *) &lv_remote_node_device_create_args; + memset (&lv_remote_node_device_create_args, 0, sizeof lv_remote_node_device_create_args); + ret_filter = (xdrproc_t) xdr_remote_node_device_create_ret; + ret = (char *) &lv_remote_node_device_create_ret; + memset (&lv_remote_node_device_create_ret, 0, sizeof lv_remote_node_device_create_ret); + break; +case REMOTE_PROC_NODE_DEVICE_DESTROY: + fn = (dispatch_fn) remoteDispatchNodeDeviceDestroy; + args_filter = (xdrproc_t) xdr_remote_node_device_destroy_args; + args = (char *) &lv_remote_node_device_destroy_args; + memset (&lv_remote_node_device_destroy_args, 0, sizeof lv_remote_node_device_destroy_args); + break; +case REMOTE_PROC_NODE_DEVICE_DUMP_XML: + fn = (dispatch_fn) remoteDispatchNodeDeviceDumpXml; + args_filter = (xdrproc_t) xdr_remote_node_device_dump_xml_args; + args = (char *) &lv_remote_node_device_dump_xml_args; + memset (&lv_remote_node_device_dump_xml_args, 0, sizeof lv_remote_node_device_dump_xml_args); + ret_filter = (xdrproc_t) xdr_remote_node_device_dump_xml_ret; + ret = (char *) &lv_remote_node_device_dump_xml_ret; + memset (&lv_remote_node_device_dump_xml_ret, 0, sizeof lv_remote_node_device_dump_xml_ret); + break; +case REMOTE_PROC_NODE_DEVICE_GET_PARENT: + fn = (dispatch_fn) remoteDispatchNodeDeviceGetParent; + args_filter = (xdrproc_t) xdr_remote_node_device_get_parent_args; + args = (char *) &lv_remote_node_device_get_parent_args; + memset (&lv_remote_node_device_get_parent_args, 0, sizeof lv_remote_node_device_get_parent_args); + ret_filter = (xdrproc_t) xdr_remote_node_device_get_parent_ret; + ret = (char *) &lv_remote_node_device_get_parent_ret; + memset (&lv_remote_node_device_get_parent_ret, 0, sizeof lv_remote_node_device_get_parent_ret); + break; +case REMOTE_PROC_NODE_DEVICE_LIST_CAPS: + fn = (dispatch_fn) remoteDispatchNodeDeviceListCaps; + args_filter = (xdrproc_t) xdr_remote_node_device_list_caps_args; + args = (char *) &lv_remote_node_device_list_caps_args; + memset (&lv_remote_node_device_list_caps_args, 0, sizeof lv_remote_node_device_list_caps_args); + ret_filter = (xdrproc_t) xdr_remote_node_device_list_caps_ret; + ret = (char *) &lv_remote_node_device_list_caps_ret; + memset (&lv_remote_node_device_list_caps_ret, 0, sizeof lv_remote_node_device_list_caps_ret); + break; +case REMOTE_PROC_NODE_DEVICE_LOOKUP_BY_NAME: + fn = (dispatch_fn) remoteDispatchNodeDeviceLookupByName; + args_filter = (xdrproc_t) xdr_remote_node_device_lookup_by_name_args; + args = (char *) &lv_remote_node_device_lookup_by_name_args; + memset (&lv_remote_node_device_lookup_by_name_args, 0, sizeof lv_remote_node_device_lookup_by_name_args); + ret_filter = (xdrproc_t) xdr_remote_node_device_lookup_by_name_ret; + ret = (char *) &lv_remote_node_device_lookup_by_name_ret; + memset (&lv_remote_node_device_lookup_by_name_ret, 0, sizeof lv_remote_node_device_lookup_by_name_ret); + break; +case REMOTE_PROC_NODE_DEVICE_NUM_OF_CAPS: + fn = (dispatch_fn) remoteDispatchNodeDeviceNumOfCaps; + args_filter = (xdrproc_t) xdr_remote_node_device_num_of_caps_args; + args = (char *) &lv_remote_node_device_num_of_caps_args; + memset (&lv_remote_node_device_num_of_caps_args, 0, sizeof lv_remote_node_device_num_of_caps_args); + ret_filter = (xdrproc_t) xdr_remote_node_device_num_of_caps_ret; + ret = (char *) &lv_remote_node_device_num_of_caps_ret; + memset (&lv_remote_node_device_num_of_caps_ret, 0, sizeof lv_remote_node_device_num_of_caps_ret); + break; case REMOTE_PROC_NODE_GET_CELLS_FREE_MEMORY: fn = (dispatch_fn) remoteDispatchNodeGetCellsFreeMemory; args_filter = (xdrproc_t) xdr_remote_node_get_cells_free_memory_args; @@ -562,6 +622,42 @@ ret_filter = (xdrproc_t) xdr_remote_node_get_info_ret; ret = (char *) &lv_remote_node_get_info_ret; memset (&lv_remote_node_get_info_ret, 0, sizeof lv_remote_node_get_info_ret); + break; +case REMOTE_PROC_NODE_LIST_DEVICES: + fn = (dispatch_fn) remoteDispatchNodeListDevices; + args_filter = (xdrproc_t) xdr_remote_node_list_devices_args; + args = (char *) &lv_remote_node_list_devices_args; + memset (&lv_remote_node_list_devices_args, 0, sizeof lv_remote_node_list_devices_args); + ret_filter = (xdrproc_t) xdr_remote_node_list_devices_ret; + ret = (char *) &lv_remote_node_list_devices_ret; + memset (&lv_remote_node_list_devices_ret, 0, sizeof lv_remote_node_list_devices_ret); + break; +case REMOTE_PROC_NODE_LIST_DEVICES_BY_CAP: + fn = (dispatch_fn) remoteDispatchNodeListDevicesByCap; + args_filter = (xdrproc_t) xdr_remote_node_list_devices_by_cap_args; + args = (char *) &lv_remote_node_list_devices_by_cap_args; + memset (&lv_remote_node_list_devices_by_cap_args, 0, sizeof lv_remote_node_list_devices_by_cap_args); + ret_filter = (xdrproc_t) xdr_remote_node_list_devices_by_cap_ret; + ret = (char *) &lv_remote_node_list_devices_by_cap_ret; + memset (&lv_remote_node_list_devices_by_cap_ret, 0, sizeof lv_remote_node_list_devices_by_cap_ret); + break; +case REMOTE_PROC_NODE_NUM_OF_DEVICES: + fn = (dispatch_fn) remoteDispatchNodeNumOfDevices; + args_filter = (xdrproc_t) xdr_remote_node_num_of_devices_args; + args = (char *) &lv_remote_node_num_of_devices_args; + memset (&lv_remote_node_num_of_devices_args, 0, sizeof lv_remote_node_num_of_devices_args); + ret_filter = (xdrproc_t) xdr_remote_node_num_of_devices_ret; + ret = (char *) &lv_remote_node_num_of_devices_ret; + memset (&lv_remote_node_num_of_devices_ret, 0, sizeof lv_remote_node_num_of_devices_ret); + break; +case REMOTE_PROC_NODE_NUM_OF_DEVICES_BY_CAP: + fn = (dispatch_fn) remoteDispatchNodeNumOfDevicesByCap; + args_filter = (xdrproc_t) xdr_remote_node_num_of_devices_by_cap_args; + args = (char *) &lv_remote_node_num_of_devices_by_cap_args; + memset (&lv_remote_node_num_of_devices_by_cap_args, 0, sizeof lv_remote_node_num_of_devices_by_cap_args); + ret_filter = (xdrproc_t) xdr_remote_node_num_of_devices_by_cap_ret; + ret = (char *) &lv_remote_node_num_of_devices_by_cap_ret; + memset (&lv_remote_node_num_of_devices_by_cap_ret, 0, sizeof lv_remote_node_num_of_devices_by_cap_ret); break; case REMOTE_PROC_NUM_OF_DEFINED_DOMAINS: fn = (dispatch_fn) remoteDispatchNumOfDefinedDomains; diff -r 4b43fb269efe qemud/remote_dispatch_prototypes.h --- a/qemud/remote_dispatch_prototypes.h Wed Nov 12 21:12:02 2008 +0000 +++ b/qemud/remote_dispatch_prototypes.h Wed Nov 12 21:57:50 2008 +0000 @@ -74,9 +74,20 @@ static int remoteDispatchNetworkLookupByUuid (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_network_lookup_by_uuid_args *args, remote_network_lookup_by_uuid_ret *ret); static int remoteDispatchNetworkSetAutostart (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_network_set_autostart_args *args, void *ret); static int remoteDispatchNetworkUndefine (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_network_undefine_args *args, void *ret); +static int remoteDispatchNodeDeviceCreate (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_node_device_create_args *args, remote_node_device_create_ret *ret); +static int remoteDispatchNodeDeviceDestroy (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_node_device_destroy_args *args, void *ret); +static int remoteDispatchNodeDeviceDumpXml (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_node_device_dump_xml_args *args, remote_node_device_dump_xml_ret *ret); +static int remoteDispatchNodeDeviceGetParent (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_node_device_get_parent_args *args, remote_node_device_get_parent_ret *ret); +static int remoteDispatchNodeDeviceListCaps (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_node_device_list_caps_args *args, remote_node_device_list_caps_ret *ret); +static int remoteDispatchNodeDeviceLookupByName (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_node_device_lookup_by_name_args *args, remote_node_device_lookup_by_name_ret *ret); +static int remoteDispatchNodeDeviceNumOfCaps (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_node_device_num_of_caps_args *args, remote_node_device_num_of_caps_ret *ret); static int remoteDispatchNodeGetCellsFreeMemory (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_node_get_cells_free_memory_args *args, remote_node_get_cells_free_memory_ret *ret); static int remoteDispatchNodeGetFreeMemory (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_node_get_free_memory_ret *ret); static int remoteDispatchNodeGetInfo (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_node_get_info_ret *ret); +static int remoteDispatchNodeListDevices (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_node_list_devices_args *args, remote_node_list_devices_ret *ret); +static int remoteDispatchNodeListDevicesByCap (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_node_list_devices_by_cap_args *args, remote_node_list_devices_by_cap_ret *ret); +static int remoteDispatchNodeNumOfDevices (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_node_num_of_devices_args *args, remote_node_num_of_devices_ret *ret); +static int remoteDispatchNodeNumOfDevicesByCap (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_node_num_of_devices_by_cap_args *args, remote_node_num_of_devices_by_cap_ret *ret); static int remoteDispatchNumOfDefinedDomains (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_num_of_defined_domains_ret *ret); static int remoteDispatchNumOfDefinedNetworks (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_num_of_defined_networks_ret *ret); static int remoteDispatchNumOfDefinedStoragePools (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_num_of_defined_storage_pools_ret *ret); diff -r 4b43fb269efe qemud/remote_protocol.c --- a/qemud/remote_protocol.c Wed Nov 12 21:12:02 2008 +0000 +++ b/qemud/remote_protocol.c Wed Nov 12 21:57:50 2008 +0000 @@ -84,6 +84,15 @@ } bool_t +xdr_remote_nonnull_node_device (XDR *xdrs, remote_nonnull_node_device *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->name)) + return FALSE; + return TRUE; +} + +bool_t xdr_remote_domain (XDR *xdrs, remote_domain *objp) { @@ -115,6 +124,15 @@ { if (!xdr_pointer (xdrs, (char **)objp, sizeof (remote_nonnull_storage_vol), (xdrproc_t) xdr_remote_nonnull_storage_vol)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_node_device (XDR *xdrs, remote_node_device *objp) +{ + + if (!xdr_pointer (xdrs, (char **)objp, sizeof (remote_nonnull_node_device), (xdrproc_t) xdr_remote_nonnull_node_device)) return FALSE; return TRUE; } @@ -1952,6 +1970,217 @@ } bool_t +xdr_remote_node_num_of_devices_args (XDR *xdrs, remote_node_num_of_devices_args *objp) +{ + + if (!xdr_u_int (xdrs, &objp->flags)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_node_num_of_devices_ret (XDR *xdrs, remote_node_num_of_devices_ret *objp) +{ + + if (!xdr_int (xdrs, &objp->num)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_node_list_devices_args (XDR *xdrs, remote_node_list_devices_args *objp) +{ + + if (!xdr_int (xdrs, &objp->maxnames)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->flags)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_node_list_devices_ret (XDR *xdrs, remote_node_list_devices_ret *objp) +{ + char **objp_cpp0 = (char **) (void *) &objp->names.names_val; + + if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->names.names_len, REMOTE_NODE_DEVICE_NAME_LIST_MAX, + sizeof (remote_nonnull_string), (xdrproc_t) xdr_remote_nonnull_string)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_node_num_of_devices_by_cap_args (XDR *xdrs, remote_node_num_of_devices_by_cap_args *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->cap)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->flags)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_node_num_of_devices_by_cap_ret (XDR *xdrs, remote_node_num_of_devices_by_cap_ret *objp) +{ + + if (!xdr_int (xdrs, &objp->num)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_node_list_devices_by_cap_args (XDR *xdrs, remote_node_list_devices_by_cap_args *objp) +{ + + if (!xdr_int (xdrs, &objp->maxnames)) + return FALSE; + if (!xdr_remote_nonnull_string (xdrs, &objp->cap)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->flags)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_node_list_devices_by_cap_ret (XDR *xdrs, remote_node_list_devices_by_cap_ret *objp) +{ + char **objp_cpp0 = (char **) (void *) &objp->names.names_val; + + if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->names.names_len, REMOTE_NODE_DEVICE_NAME_LIST_MAX, + sizeof (remote_nonnull_string), (xdrproc_t) xdr_remote_nonnull_string)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_node_device_lookup_by_name_args (XDR *xdrs, remote_node_device_lookup_by_name_args *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->name)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_node_device_lookup_by_name_ret (XDR *xdrs, remote_node_device_lookup_by_name_ret *objp) +{ + + if (!xdr_remote_nonnull_node_device (xdrs, &objp->dev)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_node_device_dump_xml_args (XDR *xdrs, remote_node_device_dump_xml_args *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->name)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->flags)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_node_device_dump_xml_ret (XDR *xdrs, remote_node_device_dump_xml_ret *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->xml)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_node_device_get_parent_args (XDR *xdrs, remote_node_device_get_parent_args *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->name)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_node_device_get_parent_ret (XDR *xdrs, remote_node_device_get_parent_ret *objp) +{ + + if (!xdr_remote_string (xdrs, &objp->parent)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_node_device_num_of_caps_args (XDR *xdrs, remote_node_device_num_of_caps_args *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->name)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_node_device_num_of_caps_ret (XDR *xdrs, remote_node_device_num_of_caps_ret *objp) +{ + + if (!xdr_int (xdrs, &objp->num)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_node_device_list_caps_args (XDR *xdrs, remote_node_device_list_caps_args *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->name)) + return FALSE; + if (!xdr_int (xdrs, &objp->maxnames)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_node_device_list_caps_ret (XDR *xdrs, remote_node_device_list_caps_ret *objp) +{ + char **objp_cpp0 = (char **) (void *) &objp->names.names_val; + + if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->names.names_len, REMOTE_NODE_DEVICE_CAPS_LIST_MAX, + sizeof (remote_nonnull_string), (xdrproc_t) xdr_remote_nonnull_string)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_node_device_create_args (XDR *xdrs, remote_node_device_create_args *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->xml)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->flags)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_node_device_create_ret (XDR *xdrs, remote_node_device_create_ret *objp) +{ + + if (!xdr_remote_nonnull_node_device (xdrs, &objp->dev)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_node_device_destroy_args (XDR *xdrs, remote_node_device_destroy_args *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->name)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->flags)) + return FALSE; + return TRUE; +} + +bool_t xdr_remote_domain_events_register_ret (XDR *xdrs, remote_domain_events_register_ret *objp) { diff -r 4b43fb269efe qemud/remote_protocol.h --- a/qemud/remote_protocol.h Wed Nov 12 21:12:02 2008 +0000 +++ b/qemud/remote_protocol.h Wed Nov 12 21:57:50 2008 +0000 @@ -31,6 +31,8 @@ #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_NODE_DEVICE_NAME_LIST_MAX 16384 +#define REMOTE_NODE_DEVICE_CAPS_LIST_MAX 16384 #define REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX 16 #define REMOTE_NODE_MAX_CELLS 1024 #define REMOTE_AUTH_SASL_DATA_MAX 65536 @@ -66,6 +68,11 @@ }; typedef struct remote_nonnull_storage_vol remote_nonnull_storage_vol; +struct remote_nonnull_node_device { + remote_nonnull_string name; +}; +typedef struct remote_nonnull_node_device remote_nonnull_node_device; + typedef remote_nonnull_domain *remote_domain; typedef remote_nonnull_network *remote_network; @@ -73,6 +80,8 @@ typedef remote_nonnull_storage_pool *remote_storage_pool; typedef remote_nonnull_storage_vol *remote_storage_vol; + +typedef remote_nonnull_node_device *remote_node_device; struct remote_error { int code; @@ -1087,6 +1096,128 @@ }; typedef struct remote_storage_vol_get_path_ret remote_storage_vol_get_path_ret; +struct remote_node_num_of_devices_args { + u_int flags; +}; +typedef struct remote_node_num_of_devices_args remote_node_num_of_devices_args; + +struct remote_node_num_of_devices_ret { + int num; +}; +typedef struct remote_node_num_of_devices_ret remote_node_num_of_devices_ret; + +struct remote_node_list_devices_args { + int maxnames; + u_int flags; +}; +typedef struct remote_node_list_devices_args remote_node_list_devices_args; + +struct remote_node_list_devices_ret { + struct { + u_int names_len; + remote_nonnull_string *names_val; + } names; +}; +typedef struct remote_node_list_devices_ret remote_node_list_devices_ret; + +struct remote_node_num_of_devices_by_cap_args { + remote_nonnull_string cap; + u_int flags; +}; +typedef struct remote_node_num_of_devices_by_cap_args remote_node_num_of_devices_by_cap_args; + +struct remote_node_num_of_devices_by_cap_ret { + int num; +}; +typedef struct remote_node_num_of_devices_by_cap_ret remote_node_num_of_devices_by_cap_ret; + +struct remote_node_list_devices_by_cap_args { + int maxnames; + remote_nonnull_string cap; + u_int flags; +}; +typedef struct remote_node_list_devices_by_cap_args remote_node_list_devices_by_cap_args; + +struct remote_node_list_devices_by_cap_ret { + struct { + u_int names_len; + remote_nonnull_string *names_val; + } names; +}; +typedef struct remote_node_list_devices_by_cap_ret remote_node_list_devices_by_cap_ret; + +struct remote_node_device_lookup_by_name_args { + remote_nonnull_string name; +}; +typedef struct remote_node_device_lookup_by_name_args remote_node_device_lookup_by_name_args; + +struct remote_node_device_lookup_by_name_ret { + remote_nonnull_node_device dev; +}; +typedef struct remote_node_device_lookup_by_name_ret remote_node_device_lookup_by_name_ret; + +struct remote_node_device_dump_xml_args { + remote_nonnull_string name; + u_int flags; +}; +typedef struct remote_node_device_dump_xml_args remote_node_device_dump_xml_args; + +struct remote_node_device_dump_xml_ret { + remote_nonnull_string xml; +}; +typedef struct remote_node_device_dump_xml_ret remote_node_device_dump_xml_ret; + +struct remote_node_device_get_parent_args { + remote_nonnull_string name; +}; +typedef struct remote_node_device_get_parent_args remote_node_device_get_parent_args; + +struct remote_node_device_get_parent_ret { + remote_string parent; +}; +typedef struct remote_node_device_get_parent_ret remote_node_device_get_parent_ret; + +struct remote_node_device_num_of_caps_args { + remote_nonnull_string name; +}; +typedef struct remote_node_device_num_of_caps_args remote_node_device_num_of_caps_args; + +struct remote_node_device_num_of_caps_ret { + int num; +}; +typedef struct remote_node_device_num_of_caps_ret remote_node_device_num_of_caps_ret; + +struct remote_node_device_list_caps_args { + remote_nonnull_string name; + int maxnames; +}; +typedef struct remote_node_device_list_caps_args remote_node_device_list_caps_args; + +struct remote_node_device_list_caps_ret { + struct { + u_int names_len; + remote_nonnull_string *names_val; + } names; +}; +typedef struct remote_node_device_list_caps_ret remote_node_device_list_caps_ret; + +struct remote_node_device_create_args { + remote_nonnull_string xml; + u_int flags; +}; +typedef struct remote_node_device_create_args remote_node_device_create_args; + +struct remote_node_device_create_ret { + remote_nonnull_node_device dev; +}; +typedef struct remote_node_device_create_ret remote_node_device_create_ret; + +struct remote_node_device_destroy_args { + remote_nonnull_string name; + u_int flags; +}; +typedef struct remote_node_device_destroy_args remote_node_device_destroy_args; + struct remote_domain_events_register_ret { int cb_registered; }; @@ -1214,6 +1345,17 @@ REMOTE_PROC_DOMAIN_EVENTS_DEREGISTER = 106, REMOTE_PROC_DOMAIN_EVENT = 107, REMOTE_PROC_GET_URI = 108, + REMOTE_PROC_NODE_NUM_OF_DEVICES = 109, + REMOTE_PROC_NODE_LIST_DEVICES = 110, + REMOTE_PROC_NODE_NUM_OF_DEVICES_BY_CAP = 111, + REMOTE_PROC_NODE_LIST_DEVICES_BY_CAP = 112, + REMOTE_PROC_NODE_DEVICE_LOOKUP_BY_NAME = 113, + REMOTE_PROC_NODE_DEVICE_DUMP_XML = 114, + REMOTE_PROC_NODE_DEVICE_CREATE = 115, + REMOTE_PROC_NODE_DEVICE_DESTROY = 116, + REMOTE_PROC_NODE_DEVICE_GET_PARENT = 117, + REMOTE_PROC_NODE_DEVICE_NUM_OF_CAPS = 118, + REMOTE_PROC_NODE_DEVICE_LIST_CAPS = 119, }; typedef enum remote_procedure remote_procedure; @@ -1251,10 +1393,12 @@ 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_nonnull_node_device (XDR *, remote_nonnull_node_device*); 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_node_device (XDR *, remote_node_device*); extern bool_t xdr_remote_error (XDR *, remote_error*); extern bool_t xdr_remote_auth_type (XDR *, remote_auth_type*); extern bool_t xdr_remote_vcpu_info (XDR *, remote_vcpu_info*); @@ -1420,6 +1564,27 @@ 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_node_num_of_devices_args (XDR *, remote_node_num_of_devices_args*); +extern bool_t xdr_remote_node_num_of_devices_ret (XDR *, remote_node_num_of_devices_ret*); +extern bool_t xdr_remote_node_list_devices_args (XDR *, remote_node_list_devices_args*); +extern bool_t xdr_remote_node_list_devices_ret (XDR *, remote_node_list_devices_ret*); +extern bool_t xdr_remote_node_num_of_devices_by_cap_args (XDR *, remote_node_num_of_devices_by_cap_args*); +extern bool_t xdr_remote_node_num_of_devices_by_cap_ret (XDR *, remote_node_num_of_devices_by_cap_ret*); +extern bool_t xdr_remote_node_list_devices_by_cap_args (XDR *, remote_node_list_devices_by_cap_args*); +extern bool_t xdr_remote_node_list_devices_by_cap_ret (XDR *, remote_node_list_devices_by_cap_ret*); +extern bool_t xdr_remote_node_device_lookup_by_name_args (XDR *, remote_node_device_lookup_by_name_args*); +extern bool_t xdr_remote_node_device_lookup_by_name_ret (XDR *, remote_node_device_lookup_by_name_ret*); +extern bool_t xdr_remote_node_device_dump_xml_args (XDR *, remote_node_device_dump_xml_args*); +extern bool_t xdr_remote_node_device_dump_xml_ret (XDR *, remote_node_device_dump_xml_ret*); +extern bool_t xdr_remote_node_device_get_parent_args (XDR *, remote_node_device_get_parent_args*); +extern bool_t xdr_remote_node_device_get_parent_ret (XDR *, remote_node_device_get_parent_ret*); +extern bool_t xdr_remote_node_device_num_of_caps_args (XDR *, remote_node_device_num_of_caps_args*); +extern bool_t xdr_remote_node_device_num_of_caps_ret (XDR *, remote_node_device_num_of_caps_ret*); +extern bool_t xdr_remote_node_device_list_caps_args (XDR *, remote_node_device_list_caps_args*); +extern bool_t xdr_remote_node_device_list_caps_ret (XDR *, remote_node_device_list_caps_ret*); +extern bool_t xdr_remote_node_device_create_args (XDR *, remote_node_device_create_args*); +extern bool_t xdr_remote_node_device_create_ret (XDR *, remote_node_device_create_ret*); +extern bool_t xdr_remote_node_device_destroy_args (XDR *, remote_node_device_destroy_args*); extern bool_t xdr_remote_domain_events_register_ret (XDR *, remote_domain_events_register_ret*); extern bool_t xdr_remote_domain_events_deregister_ret (XDR *, remote_domain_events_deregister_ret*); extern bool_t xdr_remote_domain_event_ret (XDR *, remote_domain_event_ret*); @@ -1436,10 +1601,12 @@ 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_nonnull_node_device (); 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_node_device (); extern bool_t xdr_remote_error (); extern bool_t xdr_remote_auth_type (); extern bool_t xdr_remote_vcpu_info (); @@ -1605,6 +1772,27 @@ 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_node_num_of_devices_args (); +extern bool_t xdr_remote_node_num_of_devices_ret (); +extern bool_t xdr_remote_node_list_devices_args (); +extern bool_t xdr_remote_node_list_devices_ret (); +extern bool_t xdr_remote_node_num_of_devices_by_cap_args (); +extern bool_t xdr_remote_node_num_of_devices_by_cap_ret (); +extern bool_t xdr_remote_node_list_devices_by_cap_args (); +extern bool_t xdr_remote_node_list_devices_by_cap_ret (); +extern bool_t xdr_remote_node_device_lookup_by_name_args (); +extern bool_t xdr_remote_node_device_lookup_by_name_ret (); +extern bool_t xdr_remote_node_device_dump_xml_args (); +extern bool_t xdr_remote_node_device_dump_xml_ret (); +extern bool_t xdr_remote_node_device_get_parent_args (); +extern bool_t xdr_remote_node_device_get_parent_ret (); +extern bool_t xdr_remote_node_device_num_of_caps_args (); +extern bool_t xdr_remote_node_device_num_of_caps_ret (); +extern bool_t xdr_remote_node_device_list_caps_args (); +extern bool_t xdr_remote_node_device_list_caps_ret (); +extern bool_t xdr_remote_node_device_create_args (); +extern bool_t xdr_remote_node_device_create_ret (); +extern bool_t xdr_remote_node_device_destroy_args (); extern bool_t xdr_remote_domain_events_register_ret (); extern bool_t xdr_remote_domain_events_deregister_ret (); extern bool_t xdr_remote_domain_event_ret (); diff -r 4b43fb269efe qemud/remote_protocol.x --- a/qemud/remote_protocol.x Wed Nov 12 21:12:02 2008 +0000 +++ b/qemud/remote_protocol.x Wed Nov 12 21:57:50 2008 +0000 @@ -86,6 +86,12 @@ /* Upper limit on lists of storage vol names. */ const REMOTE_STORAGE_VOL_NAME_LIST_MAX = 1024; +/* Upper limit on lists of node device names. */ +const REMOTE_NODE_DEVICE_NAME_LIST_MAX = 16384; + +/* Upper limit on lists of node device capabilities. */ +const REMOTE_NODE_DEVICE_CAPS_LIST_MAX = 16384; + /* Upper limit on list of scheduler parameters. */ const REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX = 16; @@ -139,11 +145,17 @@ remote_nonnull_string key; }; +/* A node device which may not be NULL. */ +struct remote_nonnull_node_device { + remote_nonnull_string name; +}; + /* 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; +typedef remote_nonnull_node_device *remote_node_device; /* Error message. See <virterror.h> for explanation of fields. */ @@ -969,6 +981,100 @@ remote_nonnull_string name; }; +/* Node driver calls: */ + +struct remote_node_num_of_devices_args { + unsigned flags; +}; + +struct remote_node_num_of_devices_ret { + int num; +}; + +struct remote_node_list_devices_args { + int maxnames; + unsigned flags; +}; + +struct remote_node_list_devices_ret { + remote_nonnull_string names<REMOTE_NODE_DEVICE_NAME_LIST_MAX>; +}; + +struct remote_node_num_of_devices_by_cap_args { + remote_nonnull_string cap; + unsigned flags; +}; + +struct remote_node_num_of_devices_by_cap_ret { + int num; +}; + +struct remote_node_list_devices_by_cap_args { + int maxnames; + remote_nonnull_string cap; + unsigned flags; +}; + +struct remote_node_list_devices_by_cap_ret { + remote_nonnull_string names<REMOTE_NODE_DEVICE_NAME_LIST_MAX>; +}; + +struct remote_node_device_lookup_by_name_args { + remote_nonnull_string name; +}; + +struct remote_node_device_lookup_by_name_ret { + remote_nonnull_node_device dev; +}; + +struct remote_node_device_dump_xml_args { + remote_nonnull_string name; + unsigned flags; +}; + +struct remote_node_device_dump_xml_ret { + remote_nonnull_string xml; +}; + +struct remote_node_device_get_parent_args { + remote_nonnull_string name; +}; + +struct remote_node_device_get_parent_ret { + remote_string parent; +}; + +struct remote_node_device_num_of_caps_args { + remote_nonnull_string name; +}; + +struct remote_node_device_num_of_caps_ret { + int num; +}; + +struct remote_node_device_list_caps_args { + remote_nonnull_string name; + int maxnames; +}; + +struct remote_node_device_list_caps_ret { + remote_nonnull_string names<REMOTE_NODE_DEVICE_CAPS_LIST_MAX>; +}; + +struct remote_node_device_create_args { + remote_nonnull_string xml; + unsigned flags; +}; + +struct remote_node_device_create_ret { + remote_nonnull_node_device dev; +}; + +struct remote_node_device_destroy_args { + remote_nonnull_string name; + unsigned flags; +}; + /** * Events Register/Deregister: * It would seem rpcgen does not like both args, and ret @@ -1112,7 +1218,19 @@ REMOTE_PROC_DOMAIN_EVENTS_REGISTER = 105, REMOTE_PROC_DOMAIN_EVENTS_DEREGISTER = 106, REMOTE_PROC_DOMAIN_EVENT = 107, - REMOTE_PROC_GET_URI = 108 + REMOTE_PROC_GET_URI = 108, + REMOTE_PROC_NODE_NUM_OF_DEVICES = 109, + REMOTE_PROC_NODE_LIST_DEVICES = 110, + + REMOTE_PROC_NODE_NUM_OF_DEVICES_BY_CAP = 111, + REMOTE_PROC_NODE_LIST_DEVICES_BY_CAP = 112, + REMOTE_PROC_NODE_DEVICE_LOOKUP_BY_NAME = 113, + REMOTE_PROC_NODE_DEVICE_DUMP_XML = 114, + REMOTE_PROC_NODE_DEVICE_CREATE = 115, + REMOTE_PROC_NODE_DEVICE_DESTROY = 116, + REMOTE_PROC_NODE_DEVICE_GET_PARENT = 117, + REMOTE_PROC_NODE_DEVICE_NUM_OF_CAPS = 118, + REMOTE_PROC_NODE_DEVICE_LIST_CAPS = 119 }; /* Custom RPC structure. */ diff -r 4b43fb269efe src/remote_internal.c --- a/src/remote_internal.c Wed Nov 12 21:12:02 2008 +0000 +++ b/src/remote_internal.c Wed Nov 12 21:57:51 2008 +0000 @@ -142,6 +142,14 @@ return (retcode); \ } +#define GET_DEVMON_PRIVATE(conn,retcode) \ + struct private_data *priv = (struct private_data *) (conn)->devMonPrivateData; \ + if (!priv || priv->magic != MAGIC) { \ + error (conn, VIR_ERR_INVALID_ARG, \ + _("tried to use a closed or uninitialised handle")); \ + return (retcode); \ + } + enum { REMOTE_CALL_IN_OPEN = 1, @@ -171,6 +179,7 @@ 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 virNodeDevicePtr get_nonnull_node_device (virConnectPtr conn, remote_nonnull_node_device dev); 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); @@ -3696,6 +3705,331 @@ /*----------------------------------------------------------------------*/ +static virDrvOpenStatus +remoteDevMonOpen(virConnectPtr conn, + virConnectAuthPtr auth ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED) +{ + if (conn && + conn->driver && + STREQ (conn->driver->name, "remote")) { + /* 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->devMonPrivateData = conn->privateData; + return VIR_DRV_OPEN_SUCCESS; + } + + /* Decline open. Will fallback to appropriate local node driver. */ + return VIR_DRV_OPEN_DECLINED; +} + +static int remoteDevMonClose(virConnectPtr conn) +{ + int ret = 0; + GET_DEVMON_PRIVATE (conn, -1); + if (priv->localUses) { + priv->localUses--; + if (!priv->localUses) { + ret = doRemoteClose(conn, priv); + VIR_FREE(priv); + conn->devMonPrivateData = NULL; + } + } + return ret; +} + +static int remoteNodeNumOfDevices(virConnectPtr conn, + unsigned int flags) +{ + remote_node_num_of_devices_args args; + remote_node_num_of_devices_ret ret; + GET_STORAGE_PRIVATE (conn, -1); + + args.flags = flags; + + memset (&ret, 0, sizeof ret); + if (call (conn, priv, 0, REMOTE_PROC_NODE_NUM_OF_DEVICES, + (xdrproc_t) xdr_remote_node_num_of_devices_args, (char *) &args, + (xdrproc_t) xdr_remote_node_num_of_devices_ret, (char *) &ret) == -1) + return -1; + + return ret.num; +} + + +static int remoteNodeListDevices(virConnectPtr conn, + char **const names, + int maxnames, + unsigned int flags) +{ + int i; + remote_node_list_devices_args args; + remote_node_list_devices_ret ret; + GET_STORAGE_PRIVATE (conn, -1); + + if (maxnames > REMOTE_NODE_DEVICE_NAME_LIST_MAX) { + error (conn, VIR_ERR_RPC, _("too many device names requested")); + return -1; + } + args.maxnames = maxnames; + args.flags = flags; + + memset (&ret, 0, sizeof ret); + if (call (conn, priv, 0, REMOTE_PROC_NODE_LIST_DEVICES, + (xdrproc_t) xdr_remote_node_list_devices_args, (char *) &args, + (xdrproc_t) xdr_remote_node_list_devices_ret, (char *) &ret) == -1) + return -1; + + if (ret.names.names_len > maxnames) { + error (conn, VIR_ERR_RPC, _("too many device names received")); + xdr_free ((xdrproc_t) xdr_remote_node_list_devices_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_node_list_devices_ret, (char *) &ret); + + return ret.names.names_len; +} + + +static int remoteNodeNumOfDevicesByCap(virConnectPtr conn, + const char *cap, + unsigned int flags) +{ + remote_node_num_of_devices_by_cap_args args; + remote_node_num_of_devices_by_cap_ret ret; + GET_STORAGE_PRIVATE (conn, -1); + + args.cap = (char *)cap; + args.flags = flags; + + memset (&ret, 0, sizeof ret); + if (call (conn, priv, 0, REMOTE_PROC_NODE_NUM_OF_DEVICES_BY_CAP, + (xdrproc_t) xdr_remote_node_num_of_devices_by_cap_args, (char *) &args, + (xdrproc_t) xdr_remote_node_num_of_devices_by_cap_ret, (char *) &ret) == -1) + return -1; + + return ret.num; +} + +static int remoteNodeListDevicesByCap(virConnectPtr conn, + const char *cap, + char **const names, + int maxnames, + unsigned int flags) +{ + int i; + remote_node_list_devices_by_cap_args args; + remote_node_list_devices_by_cap_ret ret; + GET_STORAGE_PRIVATE (conn, -1); + + if (maxnames > REMOTE_NODE_DEVICE_NAME_LIST_MAX) { + error (conn, VIR_ERR_RPC, _("too many device names requested")); + return -1; + } + args.maxnames = maxnames; + args.cap = (char *)cap; + args.flags = flags; + + memset (&ret, 0, sizeof ret); + if (call (conn, priv, 0, REMOTE_PROC_NODE_LIST_DEVICES_BY_CAP, + (xdrproc_t) xdr_remote_node_list_devices_by_cap_args, (char *) &args, + (xdrproc_t) xdr_remote_node_list_devices_by_cap_ret, (char *) &ret) == -1) + return -1; + + if (ret.names.names_len > maxnames) { + error (conn, VIR_ERR_RPC, _("too many device names received")); + xdr_free ((xdrproc_t) xdr_remote_node_list_devices_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_node_list_devices_by_cap_ret, (char *) &ret); + + return ret.names.names_len; +} + +static virNodeDevicePtr remoteNodeDeviceLookupByName(virConnectPtr conn, + const char *name) +{ + remote_node_device_lookup_by_name_args args; + remote_node_device_lookup_by_name_ret ret; + virNodeDevicePtr dev; + GET_STORAGE_PRIVATE (conn, NULL); + + args.name = (char *)name; + + memset (&ret, 0, sizeof ret); + if (call (conn, priv, 0, REMOTE_PROC_NODE_DEVICE_LOOKUP_BY_NAME, + (xdrproc_t) xdr_remote_node_device_lookup_by_name_args, (char *) &args, + (xdrproc_t) xdr_remote_node_device_lookup_by_name_ret, (char *) &ret) == -1) + return NULL; + + dev = get_nonnull_node_device(conn, ret.dev); + + xdr_free ((xdrproc_t) xdr_remote_node_device_lookup_by_name_ret, (char *) &ret); + + return dev; +} + +static char *remoteNodeDeviceDumpXML(virNodeDevicePtr dev, + unsigned int flags) +{ + remote_node_device_dump_xml_args args; + remote_node_device_dump_xml_ret ret; + GET_STORAGE_PRIVATE (dev->conn, NULL); + + args.name = dev->name; + args.flags = flags; + + memset (&ret, 0, sizeof ret); + if (call (dev->conn, priv, 0, REMOTE_PROC_NODE_DEVICE_DUMP_XML, + (xdrproc_t) xdr_remote_node_device_dump_xml_args, (char *) &args, + (xdrproc_t) xdr_remote_node_device_dump_xml_ret, (char *) &ret) == -1) + return NULL; + + /* Caller frees. */ + return ret.xml; +} + +static char *remoteNodeDeviceGetParent(virNodeDevicePtr dev) +{ + remote_node_device_get_parent_args args; + remote_node_device_get_parent_ret ret; + GET_STORAGE_PRIVATE (dev->conn, NULL); + + args.name = dev->name; + + memset (&ret, 0, sizeof ret); + if (call (dev->conn, priv, 0, REMOTE_PROC_NODE_DEVICE_GET_PARENT, + (xdrproc_t) xdr_remote_node_device_get_parent_args, (char *) &args, + (xdrproc_t) xdr_remote_node_device_get_parent_ret, (char *) &ret) == -1) + return NULL; + + /* Caller frees. */ + return ret.parent ? *ret.parent : NULL; +} + +static int remoteNodeDeviceNumOfCaps(virNodeDevicePtr dev) +{ + remote_node_device_num_of_caps_args args; + remote_node_device_num_of_caps_ret ret; + GET_STORAGE_PRIVATE (dev->conn, -1); + + args.name = dev->name; + + memset (&ret, 0, sizeof ret); + if (call (dev->conn, priv, 0, REMOTE_PROC_NODE_DEVICE_NUM_OF_CAPS, + (xdrproc_t) xdr_remote_node_device_num_of_caps_args, (char *) &args, + (xdrproc_t) xdr_remote_node_device_num_of_caps_ret, (char *) &ret) == -1) + return -1; + + return ret.num; +} + +static int remoteNodeDeviceListCaps(virNodeDevicePtr dev, + char **const names, + int maxnames) +{ + int i; + remote_node_device_list_caps_args args; + remote_node_device_list_caps_ret ret; + GET_STORAGE_PRIVATE (dev->conn, -1); + + if (maxnames > REMOTE_NODE_DEVICE_CAPS_LIST_MAX) { + error (dev->conn, VIR_ERR_RPC, _("too many capability names requested")); + return -1; + } + args.maxnames = maxnames; + args.name = dev->name; + + memset (&ret, 0, sizeof ret); + if (call (dev->conn, priv, 0, REMOTE_PROC_NODE_DEVICE_LIST_CAPS, + (xdrproc_t) xdr_remote_node_device_list_caps_args, (char *) &args, + (xdrproc_t) xdr_remote_node_device_list_caps_ret, (char *) &ret) == -1) + return -1; + + if (ret.names.names_len > maxnames) { + error (dev->conn, VIR_ERR_RPC, _("too many capability names received")); + xdr_free ((xdrproc_t) xdr_remote_node_device_list_caps_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_node_device_list_caps_ret, (char *) &ret); + + return ret.names.names_len; +} + +static virNodeDevicePtr remoteNodeDeviceCreate(virConnectPtr conn, + const char *xml, + unsigned int flags) +{ + remote_node_device_create_args args; + remote_node_device_create_ret ret; + virNodeDevicePtr dev; + GET_STORAGE_PRIVATE (conn, NULL); + + args.xml = (char *)xml; + args.flags = flags; + + memset (&ret, 0, sizeof ret); + if (call (conn, priv, 0, REMOTE_PROC_NODE_DEVICE_CREATE, + (xdrproc_t) xdr_remote_node_device_create_args, (char *) &args, + (xdrproc_t) xdr_remote_node_device_create_ret, (char *) &ret) == -1) + return NULL; + + dev = get_nonnull_node_device(conn, ret.dev); + + xdr_free ((xdrproc_t) xdr_remote_node_device_create_ret, (char *) &ret); + + return dev; +} + +static int remoteNodeDeviceDestroy(virNodeDevicePtr dev, + unsigned int flags) +{ + remote_node_device_destroy_args args; + GET_STORAGE_PRIVATE (dev->conn, -1); + + args.name = dev->name; + args.flags = flags; + + if (call (dev->conn, priv, 0, REMOTE_PROC_NODE_DEVICE_DESTROY, + (xdrproc_t) xdr_remote_node_device_destroy_args, (char *) &args, + (xdrproc_t) xdr_void, (char *) NULL) == -1) + return -1; + + return 0; +} + + +/*----------------------------------------------------------------------*/ + static int remoteAuthenticate (virConnectPtr conn, struct private_data *priv, int in_open, virConnectAuthPtr auth @@ -4949,6 +5283,12 @@ get_nonnull_storage_vol (virConnectPtr conn, remote_nonnull_storage_vol vol) { return virGetStorageVol (conn, vol.pool, vol.name, vol.key); +} + +static virNodeDevicePtr +get_nonnull_node_device (virConnectPtr conn, remote_nonnull_node_device dev) +{ + return virGetNodeDevice(conn, dev.name); } /* Make remote_nonnull_domain and remote_nonnull_network. */ @@ -5104,6 +5444,24 @@ .volGetPath = remoteStorageVolGetPath, }; +static virDeviceMonitor dev_monitor = { + .name = "remote", + .open = remoteDevMonOpen, + .close = remoteDevMonClose, + .numOfDevices = remoteNodeNumOfDevices, + .listDevices = remoteNodeListDevices, + .numOfDevicesByCap = remoteNodeNumOfDevicesByCap, + .listDevicesByCap = remoteNodeListDevicesByCap, + .deviceLookupByName = remoteNodeDeviceLookupByName, + .deviceDumpXML = remoteNodeDeviceDumpXML, + .deviceCreate = remoteNodeDeviceCreate, + .deviceDestroy = remoteNodeDeviceDestroy, + .deviceGetParent = remoteNodeDeviceGetParent, + .deviceNumOfCaps = remoteNodeDeviceNumOfCaps, + .deviceListCaps = remoteNodeDeviceListCaps, +}; + + #ifdef WITH_LIBVIRTD static virStateDriver state_driver = { .initialize = remoteStartup, @@ -5123,6 +5481,7 @@ if (virRegisterDriver (&driver) == -1) return -1; if (virRegisterNetworkDriver (&network_driver) == -1) return -1; if (virRegisterStorageDriver (&storage_driver) == -1) return -1; + if (virRegisterDeviceMonitor (&dev_monitor) == -1) return -1; #ifdef WITH_LIBVIRTD if (virRegisterStateDriver (&state_driver) == -1) return -1; #endif -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Thu, Nov 13, 2008 at 05:34:10PM +0000, Daniel P. Berrange wrote:
This patch adds support for the node device APIs in the remote driver and daemon. This is basically just a re-diff to take account of earlier changes to the remote_protocol.x file
+1 then Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

This patch adds two node virsh commands for the node device enumeration APIs. The only change here is to change the command names to have a shorter prefix, nodedev-list and nodedev-dumpxml Daniel diff -r 0136f215fc06 src/virsh.c --- a/src/virsh.c Thu Nov 13 13:06:59 2008 +0000 +++ b/src/virsh.c Thu Nov 13 13:07:59 2008 +0000 @@ -4410,6 +4410,96 @@ vshPrint(ctl, _("Running hypervisor: %s %d.%d.%d\n"), hvType, major, minor, rel); } + return TRUE; +} + +/* + * "nodedev-list" command + */ +static const vshCmdInfo info_node_list_devices[] = { + {"syntax", "nodedev-list [--cap <capability>]"}, + {"help", gettext_noop("enumerate devices on this host")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_node_list_devices[] = { + {"cap", VSH_OT_STRING, VSH_OFLAG_NONE, gettext_noop("capability name")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdNodeListDevices (vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + char *cap; + char **devices; + int found, num_devices, i; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + cap = vshCommandOptString(cmd, "cap", &found); + if (!found) + cap = NULL; + + num_devices = cap ? virNodeNumOfDevicesByCap(ctl->conn, cap, 0) : + virNodeNumOfDevices(ctl->conn, 0); + if (num_devices < 0) { + vshError(ctl, FALSE, "%s", _("Failed to count node devices")); + return FALSE; + } else if (num_devices == 0) { + return TRUE; + } + + devices = vshMalloc(ctl, sizeof(char *) * num_devices); + num_devices = cap ? + virNodeListDevicesByCap(ctl->conn, cap, devices, num_devices, 0) : + virNodeListDevices(ctl->conn, devices, num_devices, 0); + if (num_devices < 0) { + vshError(ctl, FALSE, "%s", _("Failed to list node devices")); + free(devices); + return FALSE; + } + for (i = 0; i < num_devices; i++) { + vshPrint(ctl, "%s\n", devices[i]); + free(devices[i]); + } + free(devices); + return TRUE; +} + +/* + * "nodedev-dumpxml" command + */ +static const vshCmdInfo info_node_device_dumpxml[] = { + {"syntax", "nodedev-dumpxml <device>"}, + {"help", gettext_noop("node device details in XML")}, + {"desc", gettext_noop("Output the node device details as an XML dump to stdout.")}, + {NULL, NULL} +}; + + +static const vshCmdOptDef opts_node_device_dumpxml[] = { + {"device", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("device key")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdNodeDeviceDumpXML (vshControl *ctl, const vshCmd *cmd) +{ + const char *name; + virNodeDevicePtr device; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + if (!(name = vshCommandOptString(cmd, "device", NULL))) + return FALSE; + if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) { + vshError(ctl, FALSE, "%s '%s'", _("Could not find matching device"), name); + return FALSE; + } + + vshPrint(ctl, "%s\n", virNodeDeviceGetXMLDesc(device, 0)); + virNodeDeviceFree(device); return TRUE; } @@ -5565,6 +5655,9 @@ {"net-uuid", cmdNetworkUuid, opts_network_uuid, info_network_uuid}, {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo}, + {"node-list-devices", cmdNodeListDevices, opts_node_list_devices, info_node_list_devices}, + {"node-device-dumpxml", cmdNodeDeviceDumpXML, opts_node_device_dumpxml, info_node_device_dumpxml}, + {"pool-autostart", cmdPoolAutostart, opts_pool_autostart, info_pool_autostart}, {"pool-build", cmdPoolBuild, opts_pool_build, info_pool_build}, {"pool-create", cmdPoolCreate, opts_pool_create, info_pool_create}, -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Thu, Nov 13, 2008 at 05:35:09PM +0000, Daniel P. Berrange wrote:
This patch adds two node virsh commands for the node device enumeration APIs. The only change here is to change the command names to have a shorter prefix, nodedev-list and nodedev-dumpxml
okay then +1 Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Thu, 2008-11-13 at 17:35 +0000, Daniel P. Berrange wrote:
This patch adds two node virsh commands for the node device enumeration APIs. The only change here is to change the command names to have a shorter prefix, nodedev-list and nodedev-dumpxml
Daniel
diff -r 0136f215fc06 src/virsh.c --- a/src/virsh.c Thu Nov 13 13:06:59 2008 +0000 +++ b/src/virsh.c Thu Nov 13 13:07:59 2008 +0000 @@ -4410,6 +4410,96 @@ vshPrint(ctl, _("Running hypervisor: %s %d.%d.%d\n"), hvType, major, minor, rel); } + return TRUE; +} + +/* + * "nodedev-list" command + */ +static const vshCmdInfo info_node_list_devices[] = { + {"syntax", "nodedev-list [--cap <capability>]"},
How about: + {"syntax", "nodedev-list [--cap net|block|storage|scsi|scsi_host|pci|usb]"}, so people easily know what capabilities are valid?
+ {"help", gettext_noop("enumerate devices on this host")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_node_list_devices[] = { + {"cap", VSH_OT_STRING, VSH_OFLAG_NONE, gettext_noop("capability name")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdNodeListDevices (vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + char *cap; + char **devices; + int found, num_devices, i; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + cap = vshCommandOptString(cmd, "cap", &found); + if (!found) + cap = NULL; + + num_devices = cap ? virNodeNumOfDevicesByCap(ctl->conn, cap, 0) : + virNodeNumOfDevices(ctl->conn, 0); + if (num_devices < 0) { + vshError(ctl, FALSE, "%s", _("Failed to count node devices")); + return FALSE; + } else if (num_devices == 0) { + return TRUE; + } + + devices = vshMalloc(ctl, sizeof(char *) * num_devices); + num_devices = cap ? + virNodeListDevicesByCap(ctl->conn, cap, devices, num_devices, 0) : + virNodeListDevices(ctl->conn, devices, num_devices, 0); + if (num_devices < 0) { + vshError(ctl, FALSE, "%s", _("Failed to list node devices")); + free(devices); + return FALSE; + } + for (i = 0; i < num_devices; i++) { + vshPrint(ctl, "%s\n", devices[i]);
Just printing the name makes the output seem a bit sparse - but I guess the names are fairly descriptive.
@@ -5565,6 +5655,9 @@ {"net-uuid", cmdNetworkUuid, opts_network_uuid, info_network_uuid}, {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo},
+ {"node-list-devices", cmdNodeListDevices, opts_node_list_devices, info_node_list_devices}, + {"node-device-dumpxml", cmdNodeDeviceDumpXML, opts_node_device_dumpxml, info_node_device_dumpxml}, +
You never actually renamed them to nodedev-list and nodedev-dumpxml By the way, trying dumpxml on a non-existent name is a bit noisy: # virsh node-device-dumpxml foo libvir: Device Monitor error : invalid node device pointer in no node device with matching name error: Could not find matching device 'foo' Cheers, Mark.

"Daniel P. Berrange" <berrange@redhat.com> wrote:
This patch adds two node virsh commands for the node device enumeration APIs. The only change here is to change the command names to have a shorter prefix, nodedev-list and nodedev-dumpxml
Daniel
diff -r 0136f215fc06 src/virsh.c ... + vshPrint(ctl, "%s\n", virNodeDeviceGetXMLDesc(device, 0));
For non-glibc, you can't print that if it's NULL. Also, shouldn't the returned XML be freed?

This is the python bindings for node devices. No change from David's last patches. Daniel diff -r b2546652397b python/generator.py --- a/python/generator.py Fri Nov 07 18:44:05 2008 +0000 +++ b/python/generator.py Fri Nov 07 18:44:21 2008 +0000 @@ -260,6 +260,11 @@ 'const virConnectPtr': ('O', "virConnect", "virConnectPtr", "virConnectPtr"), 'virConnect *': ('O', "virConnect", "virConnectPtr", "virConnectPtr"), 'const virConnect *': ('O', "virConnect", "virConnectPtr", "virConnectPtr"), + + 'virNodeDevicePtr': ('O', "virNodeDevice", "virNodeDevicePtr", "virNodeDevicePtr"), + 'const virNodeDevicePtr': ('O', "virNodeDevice", "virNodeDevicePtr", "virNodeDevicePtr"), + 'virNodeDevice *': ('O', "virNodeDevice", "virNodeDevicePtr", "virNodeDevicePtr"), + 'const virNodeDevice *': ('O', "virNodeDevice", "virNodeDevicePtr", "virNodeDevicePtr"), } py_return_types = { @@ -318,6 +323,9 @@ 'virDomainBlockPeek', 'virDomainMemoryPeek', 'virEventRegisterImpl', + 'virNodeListDevicesByCap', + 'virNodeListDevices', + 'virNodeDeviceListCaps', ) @@ -601,6 +609,8 @@ "virStoragePool *": ("._o", "virStoragePool(self, _obj=%s)", "virStoragePool"), "virStorageVolPtr": ("._o", "virStorageVol(self, _obj=%s)", "virStorageVol"), "virStorageVol *": ("._o", "virStorageVol(self, _obj=%s)", "virStorageVol"), + "virNodeDevicePtr": ("._o", "virNodeDevice(self, _obj=%s)", "virNodeDevice"), + "virNodeDevice *": ("._o", "virNodeDevice(self, _obj=%s)", "virNodeDevice"), "virConnectPtr": ("._o", "virConnect(_obj=%s)", "virConnect"), "virConnect *": ("._o", "virConnect(_obj=%s)", "virConnect"), } @@ -608,7 +618,8 @@ converter_type = { } -primary_classes = ["virDomain", "virNetwork", "virStoragePool", "virStorageVol", "virConnect"] +primary_classes = ["virDomain", "virNetwork", "virStoragePool", "virStorageVol", + "virConnect", "virNodeDevice" ] classes_ancestor = { } @@ -617,6 +628,7 @@ "virNetwork": "virNetworkFree", "virStoragePool": "virStoragePoolFree", "virStorageVol": "virStorageVolFree", + "virNodeDevice" : "virNodeDeviceFree" } functions_noexcept = { @@ -626,6 +638,8 @@ 'virStoragePoolGetName': True, 'virStorageVolGetName': True, 'virStorageVolGetkey': True, + 'virNodeDeviceGetName': True, + 'virNodeDeviceGetParent': True, } reference_keepers = { @@ -706,6 +720,13 @@ elif name[0:13] == "virStorageVol": func = name[13:] func = string.lower(func[0:1]) + func[1:] + elif name[0:13] == "virNodeDevice": + if name[13:16] == "Get": + func = string.lower(name[16]) + name[17:] + elif name[13:19] == "Lookup" or name[13:] == "Create": + func = string.lower(name[3]) + name[4:] + else: + func = string.lower(name[13]) + name[14:] elif name[0:7] == "virNode": func = name[7:] func = string.lower(func[0:1]) + func[1:] @@ -958,7 +979,7 @@ else: txt.write("Class %s()\n" % (classname)) classes.write("class %s:\n" % (classname)) - if classname in [ "virDomain", "virNetwork", "virStoragePool", "virStorageVol" ]: + if classname in [ "virDomain", "virNetwork", "virStoragePool", "virStorageVol", "virNodeDevice" ]: classes.write(" def __init__(self, conn, _obj=None):\n") else: classes.write(" def __init__(self, _obj=None):\n") @@ -966,7 +987,7 @@ list = reference_keepers[classname] for ref in list: classes.write(" self.%s = None\n" % ref[1]) - if classname in [ "virDomain", "virNetwork" ]: + if classname in [ "virDomain", "virNetwork", "virNodeDevice" ]: classes.write(" self._conn = conn\n") elif classname in [ "virStorageVol", "virStoragePool" ]: classes.write(" self._conn = conn\n" + \ diff -r b2546652397b python/libvir.c --- a/python/libvir.c Fri Nov 07 18:44:05 2008 +0000 +++ b/python/libvir.c Fri Nov 07 18:44:21 2008 +0000 @@ -1465,6 +1465,132 @@ py_retval = libvirt_virStoragePoolPtrWrap((virStoragePoolPtr) c_retval); return(py_retval); } + +static PyObject * +libvirt_virNodeListDevices(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) { + PyObject *py_retval; + char **names = NULL; + int c_retval, i; + virConnectPtr conn; + PyObject *pyobj_conn; + unsigned int flags; + + + if (!PyArg_ParseTuple(args, (char *)"Oi:virNodeListDevices", &pyobj_conn, &flags)) + return(NULL); + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + c_retval = virNodeNumOfDevices(conn, flags); + if (c_retval < 0) + return VIR_PY_NONE; + + if (c_retval) { + names = malloc(sizeof(*names) * c_retval); + if (!names) + return VIR_PY_NONE; + c_retval = virNodeListDevices(conn, names, c_retval, flags); + if (c_retval < 0) { + free(names); + return VIR_PY_NONE; + } + } + py_retval = PyList_New(c_retval); + + if (names) { + for (i = 0;i < c_retval;i++) { + PyList_SetItem(py_retval, i, libvirt_constcharPtrWrap(names[i])); + free(names[i]); + } + free(names); + } + + return(py_retval); +} + +static PyObject * +libvirt_virNodeListDevicesByCap(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) { + PyObject *py_retval; + char **names = NULL; + int c_retval, i; + virConnectPtr conn; + PyObject *pyobj_conn; + char *cap; + unsigned int flags; + + if (!PyArg_ParseTuple(args, (char *)"Ozi:virNodeListDevicesByCap", + &pyobj_conn, &cap, &flags)) + return(NULL); + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + c_retval = virNodeNumOfDevicesByCap(conn, cap, flags); + if (c_retval < 0) + return VIR_PY_NONE; + + if (c_retval) { + names = malloc(sizeof(*names) * c_retval); + if (!names) + return VIR_PY_NONE; + c_retval = virNodeListDevicesByCap(conn, cap, names, c_retval, flags); + if (c_retval < 0) { + free(names); + return VIR_PY_NONE; + } + } + py_retval = PyList_New(c_retval); + + if (names) { + for (i = 0;i < c_retval;i++) { + PyList_SetItem(py_retval, i, libvirt_constcharPtrWrap(names[i])); + free(names[i]); + } + free(names); + } + + return(py_retval); +} + +static PyObject * +libvirt_virNodeDeviceListCaps(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) { + PyObject *py_retval; + char **names = NULL; + int c_retval, i; + virNodeDevicePtr dev; + PyObject *pyobj_dev; + + if (!PyArg_ParseTuple(args, (char *)"O:virNodeDeviceListCaps", &pyobj_dev)) + return(NULL); + dev = (virNodeDevicePtr) PyvirNodeDevice_Get(pyobj_dev); + + c_retval = virNodeDeviceNumOfCaps(dev); + if (c_retval < 0) + return VIR_PY_NONE; + + if (c_retval) { + names = malloc(sizeof(*names) * c_retval); + if (!names) + return VIR_PY_NONE; + c_retval = virNodeDeviceListCaps(dev, names, c_retval); + if (c_retval < 0) { + free(names); + return VIR_PY_NONE; + } + } + py_retval = PyList_New(c_retval); + + if (names) { + for (i = 0;i < c_retval;i++) { + PyList_SetItem(py_retval, i, libvirt_constcharPtrWrap(names[i])); + free(names[i]); + } + free(names); + } + + return(py_retval); +} + /******************************************* * Helper functions to avoid importing modules @@ -1952,6 +2078,9 @@ {(char *) "virEventRegisterImpl", libvirt_virEventRegisterImpl, METH_VARARGS, NULL}, {(char *) "virEventInvokeHandleCallback", libvirt_virEventInvokeHandleCallback, METH_VARARGS, NULL}, {(char *) "virEventInvokeTimeoutCallback", libvirt_virEventInvokeTimeoutCallback, METH_VARARGS, NULL}, + {(char *) "virNodeListDevices", libvirt_virNodeListDevices, METH_VARARGS, NULL}, + {(char *) "virNodeListDevicesByCap", libvirt_virNodeListDevicesByCap, METH_VARARGS, NULL}, + {(char *) "virNodeDeviceListCaps", libvirt_virNodeDeviceListCaps, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL} }; diff -r b2546652397b python/libvirt-python-api.xml --- a/python/libvirt-python-api.xml Fri Nov 07 18:44:05 2008 +0000 +++ b/python/libvirt-python-api.xml Fri Nov 07 18:44:21 2008 +0000 @@ -160,5 +160,23 @@ <return type='int *' info='the list of information or None in case of error'/> <arg name='vol' type='virStorageVolPtr' info='a storage vol object'/> </function> + <function name='virNodeListDevices' file='python'> + <info>list the node devices</info> + <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> + <arg name='flags' type='unsigned int' info='flags (unused; pass 0)'/> + <return type='str *' info='the list of Names or None in case of error'/> + </function> + <function name='virNodeListDevicesByCap' file='python'> + <info>list the node devices with a given capability</info> + <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> + <arg name='cap' type='const unsigned char *' info='capability name'/> + <arg name='flags' type='unsigned int' info='flags (unused; pass 0)'/> + <return type='str *' info='the list of Names or None in case of error'/> + </function> + <function name='virNodeDeviceListCaps' file='python'> + <info>list the node device's capabilities</info> + <arg name='dev' type='virNodeDevicePtr' info='pointer to the node device'/> + <return type='str *' info='the list of Names or None in case of error'/> + </function> </symbols> </api> diff -r b2546652397b python/libvirt_wrap.h --- a/python/libvirt_wrap.h Fri Nov 07 18:44:05 2008 +0000 +++ b/python/libvirt_wrap.h Fri Nov 07 18:44:21 2008 +0000 @@ -65,6 +65,16 @@ virStorageVolPtr obj; } PyvirStorageVol_Object; + +#define PyvirNodeDevice_Get(v) (((v) == Py_None) ? NULL : \ + (((PyvirNodeDevice_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + virNodeDevicePtr obj; +} PyvirNodeDevice_Object; + + #define PyvirEventHandleCallback_Get(v) (((v) == Py_None) ? NULL : \ (((PyvirEventHandleCallback_Object *)(v))->obj)) @@ -89,6 +99,7 @@ void* obj; } PyvirVoidPtr_Object; + PyObject * libvirt_intWrap(int val); PyObject * libvirt_longWrap(long val); PyObject * libvirt_ulongWrap(unsigned long val); @@ -104,6 +115,8 @@ PyObject * libvirt_virEventHandleCallbackWrap(virEventHandleCallback node); PyObject * libvirt_virEventTimeoutCallbackWrap(virEventTimeoutCallback node); PyObject * libvirt_virVoidPtrWrap(void* node); +PyObject * libvirt_virNodeDevicePtrWrap(virNodeDevicePtr node); + /* Provide simple macro statement wrappers (adapted from GLib, in turn from Perl): * LIBVIRT_STMT_START { statements; } LIBVIRT_STMT_END; diff -r b2546652397b python/types.c --- a/python/types.c Fri Nov 07 18:44:05 2008 +0000 +++ b/python/types.c Fri Nov 07 18:44:21 2008 +0000 @@ -164,6 +164,21 @@ } PyObject * +libvirt_virNodeDevicePtrWrap(virNodeDevicePtr node) +{ + PyObject *ret; + + if (node == NULL) { + Py_INCREF(Py_None); + return (Py_None); + } + ret = + PyCObject_FromVoidPtrAndDesc((void *) node, (char *) "virNodeDevicePtr", + NULL); + return (ret); +} + +PyObject * libvirt_virEventHandleCallbackWrap(virEventHandleCallback node) { PyObject *ret; -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Thu, Nov 13, 2008 at 05:36:06PM +0000, Daniel P. Berrange wrote:
This is the python bindings for node devices. No change from David's last patches.
sure, +1 Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

"Daniel P. Berrange" <berrange@redhat.com> wrote:
The following series of patches are updated version of patches 7-11 of this series
http://www.redhat.com/archives/libvir-list/2008-October/msg00718.html
And integrating David Lively's node device patches ontop
Hi Dan, I built that and ran "make check" under valgrind. There were two leaks in the result, though I'm not sure the leaks are new with this patch series. Here's one of them (the other was similar): 249,136 (1,840 direct, 247,296 indirect) bytes in 115 blocks are definitely lost in loss record 6 of 7 at 0x4A05174: calloc (vg_replace_malloc.c:397) by 0x423C4A: virAlloc (memory.c:100) by 0x426E93: virHashCreate (hash.c:96) by 0x43724C: virGetConnect (datatypes.c:131) by 0x409B64: testCompareFormatXML (xmconfigtest.c:114) by 0x409D7B: testCompareHelper (xmconfigtest.c:172) by 0x40AD66: virtTestRun (testutils.c:92) by 0x409EC9: mymain (xmconfigtest.c:208) by 0x40B426: virtTestMain (testutils.c:443) Here's the fix:
From df72657ae1a6d16f1722d1517ec1a1f4ab1e302e Mon Sep 17 00:00:00 2001 From: Jim Meyering <meyering@redhat.com> Date: Fri, 14 Nov 2008 18:43:48 +0100 Subject: [PATCH] tests: don't leak connection references
* tests/xmconfigtest.c (testCompareFormatXML): Use virUnrefConnect(conn), not VIR_FREE(conn). (testCompareParseXML): Likewise. --- tests/xmconfigtest.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/xmconfigtest.c b/tests/xmconfigtest.c index 276a2e4..b88637f 100644 --- a/tests/xmconfigtest.c +++ b/tests/xmconfigtest.c @@ -93,7 +93,7 @@ static int testCompareParseXML(const char *xmcfg, const char *xml, if (conf) virConfFree(conf); virDomainDefFree(def); - VIR_FREE(conn); + virUnrefConnect(conn); return ret; } @@ -146,7 +146,7 @@ static int testCompareFormatXML(const char *xmcfg, const char *xml, virConfFree(conf); VIR_FREE(gotxml); virDomainDefFree(def); - VIR_FREE(conn); + virUnrefConnect(conn); return ret; } -- 1.6.0.4.911.gc990

On Thu, Nov 13, 2008 at 05:19:07PM +0000, Daniel P. Berrange wrote:
The following series of patches are updated version of patches 7-11 of this series
http://www.redhat.com/archives/libvir-list/2008-October/msg00718.html
And integrating David Lively's node device patches ontop
I've comitted patches 1-5 of this series so far. That's everything upto the dlopen() patch. I'll go through an make the tweaks Mark suggested for node device patches next Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
participants (5)
-
Daniel P. Berrange
-
Daniel Veillard
-
David Lively
-
Jim Meyering
-
Mark McLoughlin