diff --git a/ChangeLog b/ChangeLog index 236e9655f5..3ded42eda1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +Fri Nov 21 12:19:14 BST 2008 Daniel P. Berrange + + Public API for node device enumeration + * include/libvirt/libvirt.h.in, include/libvirt/virterror.h: + New public APIs for node device enumeration + * src/datatypes.c, src/datatypes.h: Internal impl of public + data types for node devices + * src/driver.h, src/libvirt.c: Stubs for node device APIs + * src/libvirt_sym.version.in: Export new node device API + symbols + * src/virterror.c: Error codes for node device drivers + Fri Nov 21 12:03:14 BST 2008 Daniel P. Berrange Optional (disabled by default) dlopen support diff --git a/include/libvirt/libvirt.h b/include/libvirt/libvirt.h index 469c870c11..729e59474e 100644 --- a/include/libvirt/libvirt.h +++ b/include/libvirt/libvirt.h @@ -994,6 +994,59 @@ virDomainPtr virDomainCreateLinux (virConnectPtr conn, const char *xmlDesc, 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, + const char *cap, + unsigned int flags); + +int virNodeListDevices (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); + +int virNodeDeviceFree (virNodeDevicePtr dev); + /* * Domain Event Notification */ diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 5bdc67710c..fc322e6b0f 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -994,6 +994,59 @@ virDomainPtr virDomainCreateLinux (virConnectPtr conn, const char *xmlDesc, 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, + const char *cap, + unsigned int flags); + +int virNodeListDevices (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); + +int virNodeDeviceFree (virNodeDevicePtr dev); + /* * Domain Event Notification */ diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index 868f1a3b32..870ebbc17d 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -59,6 +59,7 @@ typedef enum { VIR_FROM_NETWORK, /* Error from network config */ VIR_FROM_DOMAIN, /* Error from domain config */ VIR_FROM_UML, /* Error at the UML driver */ + VIR_FROM_NODEDEV, /* Error from node device monitor */ } virErrorDomain; @@ -149,6 +150,9 @@ typedef enum { 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 --git a/src/datatypes.c b/src/datatypes.c index 560154b86a..3911a2dfda 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -140,6 +140,9 @@ virGetConnect(void) { 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 @@ failed: 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 @@ virReleaseConnect(virConnectPtr conn) { 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 @@ virUnrefStorageVol(virStorageVolPtr vol) { 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 --git a/src/datatypes.h b/src/datatypes.h index f06f41f639..e61b178f3a 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -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 @@ struct _virConnect { 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 @@ struct _virConnect { void * privateData; void * networkPrivateData; void * storagePrivateData; + void * devMonPrivateData; /* Per-connection error. */ virError err; /* the last error */ @@ -118,6 +130,7 @@ struct _virConnect { 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 @@ struct _virStorageVol { 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 @@ virStorageVolPtr virGetStorageVol(virConnectPtr conn, const char *key); int virUnrefStorageVol(virStorageVolPtr vol); +virNodeDevicePtr virGetNodeDevice(virConnectPtr conn, + const char *name); +int virUnrefNodeDevice(virNodeDevicePtr dev); + #endif diff --git a/src/driver.h b/src/driver.h index 2382ac90d6..5fd3843f05 100644 --- a/src/driver.h +++ b/src/driver.h @@ -635,6 +635,54 @@ struct _virStateDriver { }; #endif + +typedef struct _virDeviceMonitor virDeviceMonitor; +typedef virDeviceMonitor *virDeviceMonitorPtr; + +typedef int (*virDevMonNumOfDevices)(virConnectPtr conn, + const char *cap, + unsigned int flags); + +typedef int (*virDevMonListDevices)(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); + +/** + * _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; + virDevMonDeviceLookupByName deviceLookupByName; + virDevMonDeviceDumpXML deviceDumpXML; + virDevMonDeviceGetParent deviceGetParent; + virDevMonDeviceNumOfCaps deviceNumOfCaps; + virDevMonDeviceListCaps deviceListCaps; +}; + /* * Registration * TODO: also need ways to (des)activate a given driver @@ -643,6 +691,7 @@ struct _virStateDriver { int virRegisterDriver(virDriverPtr); int virRegisterNetworkDriver(virNetworkDriverPtr); int virRegisterStorageDriver(virStorageDriverPtr); +int virRegisterDeviceMonitor(virDeviceMonitorPtr); #ifdef WITH_LIBVIRTD int virRegisterStateDriver(virStateDriverPtr); #endif diff --git a/src/libvirt.c b/src/libvirt.c index 31e6987450..32dc3cc2c3 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -70,6 +70,8 @@ static virNetworkDriverPtr virNetworkDriverTab[MAX_DRIVERS]; 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; @@ -448,6 +450,32 @@ virLibStorageVolError(virStorageVolPtr vol, virErrorNumber error, errmsg, info, NULL, 0, 0, errmsg, info); } +/** + * 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_NODEDEV, error, VIR_ERR_ERROR, + errmsg, info, NULL, 0, 0, errmsg, info); +} + /** * virRegisterNetworkDriver: * @driver: pointer to a network driver block @@ -510,6 +538,34 @@ virRegisterStorageDriver(virStorageDriverPtr 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++; +} + /** * virRegisterDriver: * @driver: pointer to a driver block @@ -806,6 +862,33 @@ do_open (const char *name, } } + /* 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 @@ virConnectClose(virConnectPtr conn) 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) @@ -5374,6 +5459,257 @@ virStorageVolGetPath(virStorageVolPtr vol) + +/** + * virNodeNumOfDevices: + * @conn: pointer to the hypervisor connection + * @cap: capability name + * @flags: flags (unused, pass 0) + * + * Provides the number of node devices. + * + * If the optional 'cap' argument is non-NULL, then the count + * will be restricted to devices with the specified capability + * + * Returns the number of node devices or -1 in case of error + */ +int +virNodeNumOfDevices(virConnectPtr conn, const char *cap, unsigned int flags) +{ + DEBUG("conn=%p, cap=%s, flags=%d", conn, cap, 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, cap, flags); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + + +/** + * virNodeListDevices: + * @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, and store their names in @names + * + * If the optional 'cap' argument is non-NULL, then the count + * will be restricted to devices with the specified capability + * + * Returns the number of node devices found or -1 in case of error + */ +int +virNodeListDevices(virConnectPtr conn, + const char *cap, + char **const names, int maxnames, + unsigned int flags) +{ + DEBUG("conn=%p, cap=%s, 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)) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + if (conn->deviceMonitor && conn->deviceMonitor->listDevices) + return conn->deviceMonitor->listDevices (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; +} + + +/** + * 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; +} + + +/** + * 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 --git a/src/libvirt_sym.version.in b/src/libvirt_sym.version.in index 943eb9ae8e..d0920f4987 100644 --- a/src/libvirt_sym.version.in +++ b/src/libvirt_sym.version.in @@ -232,6 +232,21 @@ LIBVIRT_0.5.0 { 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 --git a/src/virterror.c b/src/virterror.c index 46a7d15426..0723db88f5 100644 --- a/src/virterror.c +++ b/src/virterror.c @@ -310,6 +310,9 @@ virDefaultErrorFunc(virErrorPtr err) case VIR_FROM_DOMAIN: dom = "Domain Config "; break; + case VIR_FROM_NODEDEV: + dom = "Node Device "; + break; case VIR_FROM_UML: dom = "UML "; break; @@ -721,6 +724,24 @@ virErrorMsg(virErrorNumber error, const char *info) 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); }