
Attached is a fully functional version of the node device udev based backend, incorporating all the feedback from earlier revisions. I broke the new capability fields out into a separate patch per Dan's suggestion, and I have also included a patch removing the DevKit backend. Dave
From e95f0c84ff50c4d8736750e93b70b901c7a246ad Mon Sep 17 00:00:00 2001 From: David Allan <dallan@redhat.com> Date: Fri, 16 Oct 2009 16:52:40 -0400 Subject: [PATCH 1/3] Add several fields to node device capabilities
--- src/conf/node_device_conf.c | 22 ++++++++++++++++++++++ src/conf/node_device_conf.h | 7 +++++++ 2 files changed, 29 insertions(+), 0 deletions(-) diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index c2c5a44..87f441d 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -248,6 +248,12 @@ char *virNodeDeviceDefFormat(virConnectPtr conn, if (data->system.product_name) virBufferEscapeString(&buf, " <product>%s</product>\n", data->system.product_name); + if (data->system.dmi_devpath) + virBufferEscapeString(&buf, " <dmi_devpath>%s</dmi_devpath>\n", + data->system.dmi_devpath); + if (data->system.description) + virBufferEscapeString(&buf, " <description>%s</description>\n", + data->system.description); virBufferAddLit(&buf, " <hardware>\n"); if (data->system.hardware.vendor_name) virBufferEscapeString(&buf, " <vendor>%s</vendor>\n", @@ -325,6 +331,9 @@ char *virNodeDeviceDefFormat(virConnectPtr conn, data->usb_if.subclass); virBufferVSprintf(&buf, " <protocol>%d</protocol>\n", data->usb_if.protocol); + if (data->usb_if.interface_name) + virBufferVSprintf(&buf, " <interface_name>%s</interface_name>\n", + data->usb_if.interface_name); if (data->usb_if.description) virBufferVSprintf(&buf, " <description>%s</description>\n", data->usb_if.description); @@ -394,10 +403,20 @@ char *virNodeDeviceDefFormat(virConnectPtr conn, "</media_available>\n", avl ? 1 : 0); virBufferVSprintf(&buf, " <media_size>%llu</media_size>\n", data->storage.removable_media_size); + virBufferVSprintf(&buf, " <logical_block_size>%llu" + "</logical_block_size>\n", + data->storage.logical_block_size); + virBufferVSprintf(&buf, " <num_blocks>%llu</num_blocks>\n", + data->storage.num_blocks); virBufferAddLit(&buf, " </capability>\n"); } else { virBufferVSprintf(&buf, " <size>%llu</size>\n", data->storage.size); + virBufferVSprintf(&buf, " <logical_block_size>%llu" + "</logical_block_size>\n", + data->storage.logical_block_size); + virBufferVSprintf(&buf, " <num_blocks>%llu</num_blocks>\n", + data->storage.num_blocks); } if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE) virBufferAddLit(&buf, @@ -1310,6 +1329,8 @@ void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps) switch (caps->type) { case VIR_NODE_DEV_CAP_SYSTEM: VIR_FREE(data->system.product_name); + VIR_FREE(data->system.dmi_devpath); + VIR_FREE(data->system.description); VIR_FREE(data->system.hardware.vendor_name); VIR_FREE(data->system.hardware.version); VIR_FREE(data->system.hardware.serial); @@ -1326,6 +1347,7 @@ void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps) VIR_FREE(data->usb_dev.vendor_name); break; case VIR_NODE_DEV_CAP_USB_INTERFACE: + VIR_FREE(data->usb_if.interface_name); VIR_FREE(data->usb_if.description); break; case VIR_NODE_DEV_CAP_NET: diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h index a7bb6c6..f70184d 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -82,6 +82,8 @@ struct _virNodeDevCapsDef { union _virNodeDevCapData { struct { char *product_name; + char *description; + char *dmi_devpath; struct { char *vendor_name; char *version; @@ -101,6 +103,7 @@ struct _virNodeDevCapsDef { unsigned function; unsigned product; unsigned vendor; + unsigned class; char *product_name; char *vendor_name; } pci_dev; @@ -117,10 +120,12 @@ struct _virNodeDevCapsDef { unsigned _class; /* "class" is reserved in C */ unsigned subclass; unsigned protocol; + char *interface_name; char *description; } usb_if; struct { char *address; + unsigned address_len; char *ifname; enum virNodeDevNetCapType subtype; /* LAST -> no subtype */ } net; @@ -139,6 +144,8 @@ struct _virNodeDevCapsDef { } scsi; struct { unsigned long long size; + unsigned long long num_blocks; + unsigned long long logical_block_size; unsigned long long removable_media_size; char *block; char *bus; -- 1.6.4.4
From d8f4ac6806a8f55e4f9fa9c4af3e0c89aa4d0074 Mon Sep 17 00:00:00 2001 From: David Allan <dallan@redhat.com> Date: Fri, 16 Oct 2009 10:09:01 -0400 Subject: [PATCH 2/3] Implement a node device backend using libudev.
Monitoring for addition and removal of devices is implemented. There is a lot of detail work in this code, so we should try to get people running it on a wide variety of hardware so we can shake out the differences in implementation between the HAL and libudev backends. I have moved the new fields in the node device capabilities to a separate patch. This version contains changes per all the feedback I've received on earlier versions. --- configure.in | 47 +- daemon/libvirtd.c | 3 +- po/POTFILES.in | 3 +- src/Makefile.am | 16 +- src/node_device/node_device_driver.c | 12 +- src/node_device/node_device_driver.h | 22 + src/node_device/node_device_hal.h | 19 - ...evice_hal_linux.c => node_device_linux_sysfs.c} | 0 src/node_device/node_device_udev.c | 1142 ++++++++++++++++++++ src/node_device/node_device_udev.h | 32 + src/util/util.c | 28 + src/util/util.h | 3 + tools/virsh.c | 10 +- 13 files changed, 1306 insertions(+), 31 deletions(-) rename src/node_device/{node_device_hal_linux.c => node_device_linux_sysfs.c} (100%) create mode 100644 src/node_device/node_device_udev.c create mode 100644 src/node_device/node_device_udev.h diff --git a/configure.in b/configure.in index 2f9db72..25ed55f 100644 --- a/configure.in +++ b/configure.in @@ -1640,7 +1640,7 @@ test "$enable_shared" = no && lt_cv_objdir=. LV_LIBTOOL_OBJDIR=${lt_cv_objdir-.} AC_SUBST([LV_LIBTOOL_OBJDIR]) -dnl HAL or DeviceKit library for host device enumeration +dnl HAL, DeviceKit, or libudev library for host device enumeration HAL_REQUIRED=0.0 HAL_CFLAGS= HAL_LIBS= @@ -1734,8 +1734,46 @@ AM_CONDITIONAL([HAVE_DEVKIT], [test "x$with_devkit" = "xyes"]) AC_SUBST([DEVKIT_CFLAGS]) AC_SUBST([DEVKIT_LIBS]) +UDEV_REQUIRED=143 +UDEV_CFLAGS= +UDEV_LIBS= +AC_ARG_WITH([udev], + [ --with-udev use libudev for host device enumeration], + [], + [with_udev=check]) + +if test "$with_libvirtd" = "no" ; then + with_udev=no +fi +if test "x$with_udev" = "xyes" -o "x$with_udev" = "xcheck"; then + PKG_CHECK_MODULES(UDEV, libudev >= $UDEV_REQUIRED, + [with_udev=yes], [ + if test "x$with_udev" = "xcheck" ; then + with_udev=no + else + AC_MSG_ERROR( + [You must install udev-devel >= $UDEV_REQUIRED to compile libvirt]) + fi + ]) + if test "x$with_udev" = "xyes" ; then + AC_DEFINE_UNQUOTED([HAVE_UDEV], 1, + [use UDEV for host device enumeration]) + + old_CFLAGS=$CFLAGS + old_LDFLAGS=$LDFLAGS + CFLAGS="$CFLAGS $UDEV_CFLAGS" + LDFLAGS="$LDFLAGS $UDEV_LIBS" + AC_CHECK_FUNCS([udev_new],,[with_udev=no]) + CFLAGS="$old_CFLAGS" + LDFLAGS="$old_LDFLAGS" + fi +fi +AM_CONDITIONAL([HAVE_UDEV], [test "x$with_udev" = "xyes"]) +AC_SUBST([UDEV_CFLAGS]) +AC_SUBST([UDEV_LIBS]) + with_nodedev=no; -if test "$with_devkit" = "yes" -o "$with_hal" = "yes"; +if test "$with_devkit" = "yes" -o "$with_hal" = "yes" -o "$with_udev" = "yes"; then with_nodedev=yes AC_DEFINE_UNQUOTED([WITH_NODE_DEVICES], 1, [with node device driver]) @@ -1900,6 +1938,11 @@ AC_MSG_NOTICE([ devkit: $DEVKIT_CFLAGS $DEVKIT_LIBS]) else AC_MSG_NOTICE([ devkit: no]) fi +if test "$with_udev" = "yes" ; then +AC_MSG_NOTICE([ udev: $UDEV_CFLAGS $UDEV_LIBS]) +else +AC_MSG_NOTICE([ udev: no]) +fi if test "$with_netcf" = "yes" ; then AC_MSG_NOTICE([ netcf: $NETCF_CFLAGS $NETCF_LIBS]) else diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index 02bd287..d8d6c00 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -833,8 +833,7 @@ static struct qemud_server *qemudInitialize(int sigread) { #ifdef WITH_STORAGE_DIR storageRegister(); #endif -#if defined(WITH_NODE_DEVICES) && \ - (defined(HAVE_HAL) || defined(HAVE_DEVKIT)) +#if defined(WITH_NODE_DEVICES) nodedevRegister(); #endif secretRegister(); diff --git a/po/POTFILES.in b/po/POTFILES.in index 1a12a39..4561e55 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -17,7 +17,8 @@ src/lxc/lxc_controller.c src/lxc/lxc_driver.c src/network/bridge_driver.c src/node_device/node_device_driver.c -src/node_device/node_device_hal_linux.c +src/node_device/node_device_linux_sysfs.c +src/node_device/node_device_udev.c src/nodeinfo.c src/opennebula/one_conf.c src/opennebula/one_driver.c diff --git a/src/Makefile.am b/src/Makefile.am index 8e27ea7..11da07b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -254,16 +254,20 @@ SECURITY_DRIVER_APPARMOR_SOURCES = \ NODE_DEVICE_DRIVER_SOURCES = \ - node_device/node_device_driver.c node_device/node_device_driver.h + node_device/node_device_driver.c \ + node_device/node_device_driver.h \ + node_device/node_device_linux_sysfs.c NODE_DEVICE_DRIVER_HAL_SOURCES = \ node_device/node_device_hal.c \ - node_device/node_device_hal.h \ - node_device/node_device_hal_linux.c + node_device/node_device_hal.h NODE_DEVICE_DRIVER_DEVKIT_SOURCES = \ node_device/node_device_devkit.c +NODE_DEVICE_DRIVER_UDEV_SOURCES = \ + node_device/node_device_udev.c + ######################### # @@ -642,6 +646,11 @@ 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 HAVE_UDEV +libvirt_driver_nodedev_la_SOURCES += $(NODE_DEVICE_DRIVER_UDEV_SOURCES) +libvirt_driver_nodedev_la_CFLAGS += $(UDEV_CFLAGS) +libvirt_driver_nodedev_la_LDFLAGS += $(UDEV_LIBS) +endif if WITH_DRIVER_MODULES libvirt_driver_nodedev_la_LDFLAGS += -module -avoid-version @@ -691,6 +700,7 @@ EXTRA_DIST += \ $(NODE_DEVICE_DRIVER_SOURCES) \ $(NODE_DEVICE_DRIVER_HAL_SOURCES) \ $(NODE_DEVICE_DRIVER_DEVKIT_SOURCES) \ + $(NODE_DEVICE_DRIVER_UDEV_SOURCES) \ $(SECURITY_DRIVER_SELINUX_SOURCES) \ $(SECURITY_DRIVER_APPARMOR_SOURCES) \ $(SECRET_DRIVER_SOURCES) \ diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index f33ff48..c139907 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -70,7 +70,10 @@ static int update_caps(virNodeDeviceObjPtr dev) } -#ifdef __linux__ +#if defined (__linux__) && defined (HAVE_HAL) +/* Under libudev changes to the driver name should be picked up as + * "change" events, so we don't call update driver name unless we're + * using the HAL backend. */ static int update_driver_name(virConnectPtr conn, virNodeDeviceObjPtr dev) { @@ -658,10 +661,10 @@ void registerCommonNodeFuncs(virDeviceMonitorPtr driver) int nodedevRegister(void) { -#if defined(HAVE_HAL) && defined(HAVE_DEVKIT) +#if defined(HAVE_HAL) && defined(HAVE_UDEV) /* Register only one of these two - they conflict */ if (halNodeRegister() == -1) - return devkitNodeRegister(); + return udevNodeRegister(); return 0; #else #ifdef HAVE_HAL @@ -670,5 +673,8 @@ int nodedevRegister(void) { #ifdef HAVE_DEVKIT return devkitNodeRegister(); #endif +#ifdef HAVE_UDEV + return udevNodeRegister(); +#endif #endif } diff --git a/src/node_device/node_device_driver.h b/src/node_device/node_device_driver.h index db01624..5be0781 100644 --- a/src/node_device/node_device_driver.h +++ b/src/node_device/node_device_driver.h @@ -45,6 +45,9 @@ int halNodeRegister(void); #ifdef HAVE_DEVKIT int devkitNodeRegister(void); #endif +#ifdef HAVE_UDEV +int udevNodeRegister(void); +#endif void nodeDeviceLock(virDeviceMonitorStatePtr driver); void nodeDeviceUnlock(virDeviceMonitorStatePtr driver); @@ -53,4 +56,23 @@ void registerCommonNodeFuncs(virDeviceMonitorPtr mon); int nodedevRegister(void); +#ifdef __linux__ + +#define check_fc_host(d) check_fc_host_linux(d) +int check_fc_host_linux(union _virNodeDevCapData *d); + +#define check_vport_capable(d) check_vport_capable_linux(d) +int check_vport_capable_linux(union _virNodeDevCapData *d); + +#define read_wwn(host, file, wwn) read_wwn_linux(host, file, wwn) +int read_wwn_linux(int host, const char *file, char **wwn); + +#else /* __linux__ */ + +#define check_fc_host(d) +#define check_vport_capable(d) +#define read_wwn(host, file, wwn) + +#endif /* __linux__ */ + #endif /* __VIR_NODE_DEVICE_H__ */ diff --git a/src/node_device/node_device_hal.h b/src/node_device/node_device_hal.h index c859fe3..8ac8a35 100644 --- a/src/node_device/node_device_hal.h +++ b/src/node_device/node_device_hal.h @@ -22,23 +22,4 @@ #ifndef __VIR_NODE_DEVICE_HAL_H__ #define __VIR_NODE_DEVICE_HAL_H__ -#ifdef __linux__ - -#define check_fc_host(d) check_fc_host_linux(d) -int check_fc_host_linux(union _virNodeDevCapData *d); - -#define check_vport_capable(d) check_vport_capable_linux(d) -int check_vport_capable_linux(union _virNodeDevCapData *d); - -#define read_wwn(host, file, wwn) read_wwn_linux(host, file, wwn) -int read_wwn_linux(int host, const char *file, char **wwn); - -#else /* __linux__ */ - -#define check_fc_host(d) -#define check_vport_capable(d) -#define read_wwn(host, file, wwn) - -#endif /* __linux__ */ - #endif /* __VIR_NODE_DEVICE_HAL_H__ */ diff --git a/src/node_device/node_device_hal_linux.c b/src/node_device/node_device_linux_sysfs.c similarity index 100% rename from src/node_device/node_device_hal_linux.c rename to src/node_device/node_device_linux_sysfs.c diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c new file mode 100644 index 0000000..10f45aa --- /dev/null +++ b/src/node_device/node_device_udev.c @@ -0,0 +1,1142 @@ +/* + * node_device_udev.c: node device enumeration - libudev implementation + * + * Copyright (C) 2009 Red Hat + * + * 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: Dave Allan <dallan@redhat.com> + */ + +#include <config.h> +#include <libudev.h> + +#include "node_device_udev.h" +#include "virterror_internal.h" +#include "node_device_conf.h" +#include "node_device_driver.h" +#include "driver.h" +#include "datatypes.h" +#include "logging.h" +#include "memory.h" +#include "uuid.h" +#include "util.h" +#include "buf.h" +#include "daemon/event.h" + +#define VIR_FROM_THIS VIR_FROM_NODEDEV + +static virDeviceMonitorStatePtr driverState = NULL; + +/* This function allocates memory from the heap for the property + * value. That memory must be later freed by some other code. */ +static int udevGetDeviceProperty(struct udev_device *udev_device, + const char *property_key, + char **property_value) +{ + const char *udev_value = NULL; + int ret = PROPERTY_FOUND; + + udev_value = udev_device_get_property_value(udev_device, property_key); + if (udev_value == NULL) { + VIR_INFO(_("udev reports device '%s' does not have property '%s'"), + udev_device_get_sysname(udev_device), property_key); + ret = PROPERTY_MISSING; + goto out; + } + + /* If this allocation is changed, the comment at the beginning + * of the function must also be changed. */ + *property_value = strdup(udev_value); + if (*property_value == NULL) { + VIR_ERROR(_("Failed to allocate memory for " + "property '%s' on device '%s'"), + property_key, udev_device_get_sysname(udev_device)); + virReportOOMError(NULL); + ret = PROPERTY_ERROR; + } + +out: + return ret; +} + + +static int udevGetStringProperty(struct udev_device *udev_device, + const char *property_key, + char **value) +{ + return udevGetDeviceProperty(udev_device, property_key, value); +} + + +static int udevGetIntProperty(struct udev_device *udev_device, + const char *property_key, + int *value, + int base) +{ + char *udev_value = NULL; + int ret = PROPERTY_FOUND; + + ret = udevGetDeviceProperty(udev_device, property_key, &udev_value); + + if (ret == PROPERTY_FOUND) { + if (virStrToLong_i(udev_value, NULL, base, value) != 0) { + ret = PROPERTY_ERROR; + } + } + + VIR_FREE(udev_value); + return ret; +} + + +static int udevGetUintProperty(struct udev_device *udev_device, + const char *property_key, + unsigned int *value, + int base) +{ + char *udev_value = NULL; + int ret = PROPERTY_FOUND; + + ret = udevGetDeviceProperty(udev_device, property_key, &udev_value); + + if (ret == PROPERTY_FOUND) { + if (virStrToLong_ui(udev_value, NULL, base, value) != 0) { + ret = PROPERTY_ERROR; + } + } + + VIR_FREE(udev_value); + return ret; +} + + +/* This function allocates memory from the heap for the attr value. + * That memory must be later freed by some other code. */ +static int udevGetStringSysfsAttr(struct udev_device *udev_device, + const char *attr_name, + char **value) +{ + const char *udev_value = NULL; + int ret = PROPERTY_FOUND; + + udev_value = udev_device_get_sysattr_value(udev_device, attr_name); + + if (udev_value != NULL) { + *value = strdup(udev_value); + if (*value == NULL) { + VIR_ERROR(_("Failed to allocate memory for " + "attribute '%s' on device '%s'"), + attr_name, udev_device_get_sysname(udev_device)); + virReportOOMError(NULL); + ret = PROPERTY_ERROR; + } + } else { + ret = PROPERTY_MISSING; + } + + return ret; +} + + +static int udevGetIntSysfsAttr(struct udev_device *udev_device, + const char *attr_name, + int *value, + int base) +{ + const char *udev_value = NULL; + int ret = PROPERTY_FOUND; + + udev_value = udev_device_get_sysattr_value(udev_device, attr_name); + + if (udev_value != NULL) { + if (virStrToLong_i(udev_value, NULL, base, value) != 0) { + ret = PROPERTY_ERROR; + } + } else { + ret = PROPERTY_MISSING; + } + + return ret; +} + + +static int udevGetUintSysfsAttr(struct udev_device *udev_device, + const char *attr_name, + unsigned int *value, + int base) +{ + const char *udev_value = NULL; + int ret = PROPERTY_FOUND; + + udev_value = udev_device_get_sysattr_value(udev_device, attr_name); + + if (udev_value != NULL) { + if (virStrToLong_ui(udev_value, NULL, base, value) != 0) { + ret = PROPERTY_ERROR; + } + } else { + ret = PROPERTY_MISSING; + } + + return ret; +} + + +static int udevGetUint64SysfsAttr(struct udev_device *udev_device, + const char *attr_name, + uint64_t *value) +{ + const char *udev_value = NULL; + int ret = PROPERTY_FOUND; + + udev_value = udev_device_get_sysattr_value(udev_device, attr_name); + + if (udev_value != NULL) { + if (virStrToLong_ull(udev_value, NULL, 0, value) != 0) { + ret = PROPERTY_ERROR; + } + } else { + ret = PROPERTY_MISSING; + } + + return ret; +} + + +static void udevLogFunction(struct udev *udev ATTRIBUTE_UNUSED, + int priority ATTRIBUTE_UNUSED, + const char *file, + int line, + const char *fn, + const char *fmt, + va_list args) +{ + VIR_ERROR_INT(file, fn, line, fmt, args); +} + + +static int udevProcessPCI(struct udev_device *device, + virNodeDeviceDefPtr def) +{ + const char *devpath = NULL; + union _virNodeDevCapData *data = &def->caps->data; + int ret = -1; + + devpath = udev_device_get_devpath(device); + + char *p = strrchr(devpath, '/'); + + if ((p == NULL) || (virStrToLong_ui(p+1, + &p, + 16, + &data->pci_dev.domain) == -1)) { + goto out; + } + + if ((p == NULL) || (virStrToLong_ui(p+1, + &p, + 16, + &data->pci_dev.bus) == -1)) { + goto out; + } + + if ((p == NULL) || (virStrToLong_ui(p+1, + &p, + 16, + &data->pci_dev.slot) == -1)) { + goto out; + } + + if ((p == NULL) || (virStrToLong_ui(p+1, + &p, + 16, + &data->pci_dev.function) == -1)) { + goto out; + } + + if (udevGetUintSysfsAttr(device, + "vendor", + &data->pci_dev.vendor, + 0) == PROPERTY_ERROR) { + goto out; + } + + if (udevGetUintSysfsAttr(device, "product", &data->pci_dev.product, 0) + == PROPERTY_ERROR) { + goto out; + } + + /* FIXME: to do the vendor name and product name, we have to + * parse /usr/share/hwdata/pci.ids. Look in hal/hald/ids.c + */ + + ret = 0; + +out: + return ret; +} + + +static int udevProcessUSBDevice(struct udev_device *device, + virNodeDeviceDefPtr def) +{ + union _virNodeDevCapData *data = &def->caps->data; + int ret = 0; + + if (udevGetUintProperty(device, + "BUSNUM", + &data->usb_dev.bus, + 0) == PROPERTY_ERROR) { + goto out; + } + + if (udevGetUintProperty(device, + "DEVNUM", + &data->usb_dev.device, + 0) == PROPERTY_ERROR) { + goto out; + } + + if (udevGetUintProperty(device, + "ID_VENDOR_ID", + &data->usb_dev.vendor, + 16) == PROPERTY_ERROR) { + goto out; + } + + if (udevGetStringProperty(device, + "ID_VENDOR", + &data->usb_dev.vendor_name) == PROPERTY_ERROR) { + goto out; + } + + if (udevGetUintProperty(device, + "ID_MODEL_ID", + &data->usb_dev.product, + 0) == PROPERTY_ERROR) { + goto out; + } + + if (udevGetStringProperty(device, + "ID_MODEL", + &data->usb_dev.product_name) == PROPERTY_ERROR) { + goto out; + } + +out: + return ret; +} + + +/* XXX Is 10 the correct base for the Number/Class/SubClass/Protocol + * conversions? */ +static int udevProcessUSBInterface(struct udev_device *device, + virNodeDeviceDefPtr def) +{ + int ret = 0; + union _virNodeDevCapData *data = &def->caps->data; + + if (udevGetStringProperty(device, + "INTERFACE", + &data->usb_if.interface_name) == PROPERTY_ERROR) { + goto out; + } + + if (udevGetUintSysfsAttr(device, + "bInterfaceNumber", + &data->usb_if.number, + 10) == PROPERTY_ERROR) { + goto out; + } + + if (udevGetUintSysfsAttr(device, + "bInterfaceClass", + &data->usb_if._class, + 10) == PROPERTY_ERROR) { + goto out; + } + + if (udevGetUintSysfsAttr(device, + "bInterfaceSubClass", + &data->usb_if.subclass, + 10) == PROPERTY_ERROR) { + goto out; + } + + if (udevGetUintSysfsAttr(device, + "bInterfaceProtocol", + &data->usb_if.protocol, + 10) == PROPERTY_ERROR) { + goto out; + } + + ret = 0; + +out: + return ret; +} + + +static int udevProcessNetworkInterface(struct udev_device *device, + virNodeDeviceDefPtr def) +{ + union _virNodeDevCapData *data = &def->caps->data; + int ret = 0; + + if (udevGetStringSysfsAttr(device, + "address", + &data->net.address) == PROPERTY_ERROR) { + goto out; + } + if (udevGetUintSysfsAttr(device, + "addr_len", + &data->net.address_len, + 0) == PROPERTY_ERROR) { + goto out; + } + +out: + return ret; +} + + +static int udevProcessSCSIHost(struct udev_device *device ATTRIBUTE_UNUSED, + virNodeDeviceDefPtr def) +{ + int ret = 0; + union _virNodeDevCapData *data = &def->caps->data; + char *filename = NULL; + + filename = basename(def->name); + + if (STRPREFIX(filename, "host")) { + /* XXX There's really no better way to get the host #? */ + ret = virStrToLong_ui(filename + strlen("host"), + NULL, + 0, + &data->scsi_host.host); + check_fc_host(&def->caps->data); + check_vport_capable(&def->caps->data); + } + + return ret; +} + + +static int udevProcessSCSIDevice(struct udev_device *device ATTRIBUTE_UNUSED, + virNodeDeviceDefPtr def) +{ + int ret = 0; + union _virNodeDevCapData *data = &def->caps->data; + char *filename = NULL, *p = NULL; + + filename = basename(def->name); + + virStrToLong_ui(filename, &p, 10, &data->scsi.host); + virStrToLong_ui(p+1, &p, 10, &data->scsi.bus); + virStrToLong_ui(p+1, &p, 10, &data->scsi.target); + virStrToLong_ui(p+1, &p, 10, &data->scsi.lun); + + return ret; +} + + +static int udevProcessDisk(struct udev_device *device, + virNodeDeviceDefPtr def) +{ + union _virNodeDevCapData *data = &def->caps->data; + int ret = 0; + + data->storage.drive_type = strdup("disk"); + if (data->storage.drive_type == NULL) { + ret = -1; + goto out; + } + + if (udevGetUint64SysfsAttr(device, + "size", + &data->storage.num_blocks) == PROPERTY_ERROR) { + goto out; + } + + if (udevGetUint64SysfsAttr(device, + "queue/logical_block_size", + &data->storage.logical_block_size) + == PROPERTY_ERROR) { + goto out; + } + + + data->storage.size = data->storage.num_blocks * + data->storage.logical_block_size; + +out: + return ret; +} + + +static int udevProcessCDROM(struct udev_device *device, + virNodeDeviceDefPtr def) +{ + union _virNodeDevCapData *data = &def->caps->data; + int tmp_int = 0, ret = 0; + + if ((udevGetIntSysfsAttr(device, "removable", &tmp_int, 0) == PROPERTY_FOUND) && + (tmp_int == 1)) { + def->caps->data.storage.flags |= VIR_NODE_DEV_CAP_STORAGE_REMOVABLE; + } + + if ((udevGetIntProperty(device, "ID_CDROM_MEDIA", &tmp_int, 0) + == PROPERTY_FOUND) && (tmp_int == 1)) { + + def->caps->data.storage.flags |= + VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE; + + if (udevGetUint64SysfsAttr(device, + "size", + &data->storage.num_blocks) == PROPERTY_ERROR) { + goto out; + } + + if (udevGetUint64SysfsAttr(device, + "queue/logical_block_size", + &data->storage.logical_block_size) == PROPERTY_ERROR) { + goto out; + } + + /* XXX This calculation is wrong for the qemu virtual cdrom + * which reports the size in 512 byte blocks, but the logical + * block size as 2048. I don't have a physical cdrom on a + * devel system to see how they behave. */ + def->caps->data.storage.removable_media_size = + def->caps->data.storage.num_blocks * + def->caps->data.storage.logical_block_size; + } + +out: + return ret; +} + + +/* This function exists to deal with the case in which a driver does + * not provide a device type in the usual place, but udev told us it's + * a storage device, and we can make a good guess at what kind of + * storage device it is from other information that is provided. */ +static int udevKludgeStorageType(virNodeDeviceDefPtr def) +{ + int ret = -1; + + if (STRPREFIX(def->caps->data.storage.block, "/dev/vd")) { + /* virtio disk */ + def->caps->data.storage.drive_type = strdup("disk"); + if (def->caps->data.storage.drive_type != NULL) { + ret = 0; + } + } + + return ret; +} + + +static void udevStripSpaces(char *s) +{ + if (s == NULL) { + return; + } + + while (virFileStripSuffix(s, " ")) { + /* do nothing */ + ; + } + + return; +} + + +static int udevProcessStorage(struct udev_device *device, + virNodeDeviceDefPtr def) +{ + union _virNodeDevCapData *data = &def->caps->data; + int ret = -1; + + data->storage.block = strdup(udev_device_get_devnode(device)); + if (udevGetStringProperty(device, + "DEVNAME", + &data->storage.block) == PROPERTY_ERROR) { + goto out; + } + if (udevGetStringProperty(device, + "ID_BUS", + &data->storage.bus) == PROPERTY_ERROR) { + goto out; + } + if (udevGetStringProperty(device, + "ID_SERIAL", + &data->storage.serial) == PROPERTY_ERROR) { + goto out; + } + if (udevGetStringSysfsAttr(device, + "device/vendor", + &data->storage.vendor) == PROPERTY_ERROR) { + goto out; + } + udevStripSpaces(def->caps->data.storage.vendor); + if (udevGetStringSysfsAttr(device, + "device/model", + &data->storage.model) == PROPERTY_ERROR) { + goto out; + } + udevStripSpaces(def->caps->data.storage.model); + /* There is no equivalent of the hotpluggable property in libudev, + * but storage is going toward a world in which hotpluggable is + * expected, so I don't see a problem with not having a property + * for it. */ + + if (udevGetStringProperty(device, + "ID_TYPE", + &data->storage.drive_type) != 0) { + /* If udev doesn't have it, perhaps we can guess it. */ + if (udevKludgeStorageType(def) != 0) { + goto out; + } + } + + /* NB: drive_type has changed from HAL; now it's "cd" instead of "cdrom" */ + if (STREQ(def->caps->data.storage.drive_type, "cd")) { + ret = udevProcessCDROM(device, def); + } else if (STREQ(def->caps->data.storage.drive_type, "disk")) { + ret = udevProcessDisk(device, def); + } else { + goto out; + } + +out: + return ret; +} + + +static int udevSetDeviceType(struct udev_device *device, + virNodeDeviceDefPtr def) +{ + union _virNodeDevCapData *data = NULL; + const char *devtype = NULL; + int ret = 0; + + if (VIR_ALLOC(def->caps) != 0) { + ret = -1; + goto out; + } + + data = &def->caps->data; + + devtype = udev_device_get_devtype(device); + + if (udevGetUintProperty(device, + "PCI_CLASS", + &data->pci_dev.class, + 0) == PROPERTY_FOUND) { + def->caps->type = VIR_NODE_DEV_CAP_PCI_DEV; + goto out; + } + + if (devtype != NULL && STREQ(devtype, "usb_device")) { + def->caps->type = VIR_NODE_DEV_CAP_USB_DEV; + goto out; + } + + if (devtype != NULL && STREQ(devtype, "usb_interface")) { + def->caps->type = VIR_NODE_DEV_CAP_USB_INTERFACE; + goto out; + } + + /* XXX Do some network interfaces set the device type property? */ + if (udevGetStringProperty(device, + "INTERFACE", + &data->net.ifname) == PROPERTY_FOUND) { + def->caps->type = VIR_NODE_DEV_CAP_NET; + goto out; + } + + if (devtype != NULL && STREQ(devtype, "scsi_host")) { + def->caps->type = VIR_NODE_DEV_CAP_SCSI_HOST; + goto out; + } + + if (devtype != NULL && STREQ(devtype, "scsi_device")) { + def->caps->type = VIR_NODE_DEV_CAP_SCSI; + goto out; + } + + if (devtype != NULL && STREQ(devtype, "disk")) { + def->caps->type = VIR_NODE_DEV_CAP_STORAGE; + goto out; + } + + ret = -1; + +out: + return ret; +} + + +static int udevGetDeviceDetails(struct udev_device *device, + virNodeDeviceDefPtr def) +{ + int ret = 0; + + switch (def->caps->type) { + case VIR_NODE_DEV_CAP_SYSTEM: + /* There's no libudev equivalent of system, so ignore it. */ + break; + case VIR_NODE_DEV_CAP_PCI_DEV: + ret = udevProcessPCI(device, def); + break; + case VIR_NODE_DEV_CAP_USB_DEV: + ret = udevProcessUSBDevice(device, def); + break; + case VIR_NODE_DEV_CAP_USB_INTERFACE: + ret = udevProcessUSBInterface(device, def); + break; + case VIR_NODE_DEV_CAP_NET: + ret = udevProcessNetworkInterface(device, def); + break; + case VIR_NODE_DEV_CAP_SCSI_HOST: + ret = udevProcessSCSIHost(device, def); + break; + case VIR_NODE_DEV_CAP_SCSI: + ret = udevProcessSCSIDevice(device, def); + break; + case VIR_NODE_DEV_CAP_STORAGE: + ret = udevProcessStorage(device, def); + break; + default: + ret = -1; + break; + } + + return ret; +} + + +static int udevRemoveOneDevice(struct udev_device *device) +{ + virNodeDeviceObjPtr dev = NULL; + const char *name = NULL; + int ret = 0; + + name = udev_device_get_syspath(device); + + dev = virNodeDeviceFindByName(&driverState->devs, name); + if (dev != NULL) { + virNodeDeviceObjRemove(&driverState->devs, dev); + } else { + ret = -1; + } + + return ret; +} + + +static int udevAddOneDevice(struct udev_device *device) +{ + virNodeDeviceDefPtr def = NULL; + struct udev_device *parent = NULL; + virNodeDeviceObjPtr dev = NULL; + const char *parent_name = NULL; + int ret = -1; + + if (VIR_ALLOC(def) != 0) { + goto out; + } + + def->name = strdup(udev_device_get_syspath(device)); + if (udevGetStringProperty(device, + "DRIVER", + &def->driver) == PROPERTY_ERROR) { + goto out; + } + + parent = udev_device_get_parent(device); + if (parent != NULL) { + parent_name = udev_device_get_syspath(parent); + if (parent_name != NULL) { + def->parent = strdup(parent_name); + } + } + + if (udevSetDeviceType(device, def) == 0) { + ret = udevGetDeviceDetails(device, def); + } + + if (ret == 0) { + dev = virNodeDeviceAssignDef(NULL, &driverState->devs, def); + dev->devicePath = strdup(udev_device_get_devpath(device)); + virNodeDeviceObjUnlock(dev); + } else { + virNodeDeviceDefFree(def); + } + +out: + return ret; +} + + +static int udevProcessDeviceListEntry(struct udev *udev, + struct udev_list_entry *list_entry) +{ + struct udev_device *device; + const char *name = NULL; + int ret = -1; + + name = udev_list_entry_get_name(list_entry); + + device = udev_device_new_from_syspath(udev, name); + if (device != NULL) { + udevAddOneDevice(device); + udev_device_unref(device); + ret = 0; + } + + return ret; +} + + +static int udevEnumerateDevices(struct udev *udev) +{ + struct udev_enumerate *udev_enumerate = NULL; + struct udev_list_entry *list_entry = NULL; + const char *name = NULL; + int ret = 0; + + udev_enumerate = udev_enumerate_new(udev); + + ret = udev_enumerate_scan_devices(udev_enumerate); + if (0 != ret) { + VIR_ERROR("udev scan devices returned %d\n", ret); + goto out; + } + + udev_list_entry_foreach(list_entry, + udev_enumerate_get_list_entry(udev_enumerate)) { + + udevProcessDeviceListEntry(udev, list_entry); + name = udev_list_entry_get_name(list_entry); + } + +out: + udev_enumerate_unref(udev_enumerate); + return ret; +} + + +static int udevDeviceMonitorShutdown(void) +{ + int ret = 0; + + struct udev_monitor *udev_monitor = NULL; + struct udev *udev = NULL; + + if (driverState) { + + nodeDeviceLock(driverState); + udev_monitor = DRV_STATE_UDEV_MONITOR(driverState); + + if (udev_monitor != NULL) { + udev = udev_monitor_get_udev(udev_monitor); + udev_monitor_unref(udev_monitor); + } + + if (udev != NULL) { + udev_unref(udev); + } + + virNodeDeviceObjListFree(&driverState->devs); + nodeDeviceUnlock(driverState); + virMutexDestroy(&driverState->lock); + VIR_FREE(driverState); + + } else { + ret = -1; + } + + return ret; +} + + +static void udevEventHandleCallback(int watch ATTRIBUTE_UNUSED, + int fd, + int events ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) +{ + struct udev_device *device = NULL; + struct udev_monitor *udev_monitor = DRV_STATE_UDEV_MONITOR(driverState); + const char *action = NULL; + + if (fd != udev_monitor_get_fd(udev_monitor)) { + goto out; + } + + device = udev_monitor_receive_device(udev_monitor); + if (device == NULL) { + goto out; + } + + action = udev_device_get_action(device); + + if (STREQ(action, "add") || STREQ(action, "change")) { + udevAddOneDevice(device); + goto out; + } + + if (STREQ(action, "remove")) { + udevRemoveOneDevice(device); + goto out; + } + +out: + return; +} + + +static int udevSetupSystemDev(void) +{ + virNodeDeviceDefPtr def = NULL; + virNodeDeviceObjPtr dev = NULL; + struct udev *udev = NULL; + struct udev_device *device = NULL; + union _virNodeDevCapData *data = NULL; + char *tmp = NULL; + int ret = -1; + + if (VIR_ALLOC(def) != 0) { + goto out; + } + + def->name = strdup("computer"); + if (def->name == NULL) { + goto out; + } + + if (VIR_ALLOC(def->caps) != 0) { + goto out; + } + + udev = udev_monitor_get_udev(DRV_STATE_UDEV_MONITOR(driverState)); + device = udev_device_new_from_syspath(udev, DMI_DEVPATH); + if (device == NULL) { + goto out; + } + + data = &def->caps->data; + + data->system.dmi_devpath = strdup(DMI_DEVPATH); + data->system.description = strdup(SYSTEM_DESCRIPTION); + + if (udevGetStringSysfsAttr(device, + "product_name", + &data->system.product_name) == PROPERTY_ERROR) { + goto out; + } + if (udevGetStringSysfsAttr(device, + "sys_vendor", + &data->system.hardware.vendor_name) + == PROPERTY_ERROR) { + goto out; + } + if (udevGetStringSysfsAttr(device, + "product_version", + &data->system.hardware.version) + == PROPERTY_ERROR) { + goto out; + } + if (udevGetStringSysfsAttr(device, + "product_serial", + &data->system.hardware.serial) + == PROPERTY_ERROR) { + goto out; + } + + if (udevGetStringSysfsAttr(device, + "product_uuid", + &tmp) == PROPERTY_ERROR) { + goto out; + } + virUUIDParse(tmp, def->caps->data.system.hardware.uuid); + VIR_FREE(tmp); + + if (udevGetStringSysfsAttr(device, + "bios_vendor", + &data->system.firmware.vendor_name) + == PROPERTY_ERROR) { + goto out; + } + if (udevGetStringSysfsAttr(device, + "bios_version", + &data->system.firmware.version) + == PROPERTY_ERROR) { + goto out; + } + if (udevGetStringSysfsAttr(device, + "bios_date", + &data->system.firmware.release_date) + == PROPERTY_ERROR) { + goto out; + } + + udev_device_unref(device); + + dev = virNodeDeviceAssignDef(NULL, &driverState->devs, def); + virNodeDeviceObjUnlock(dev); + + ret = 0; + +out: + return ret; +} + +static int udevDeviceMonitorStartup(int privileged ATTRIBUTE_UNUSED) +{ + struct udev *udev = NULL; + struct udev_monitor *udev_monitor = NULL; + int ret = 0; + + if (VIR_ALLOC(driverState) < 0) { + ret = -1; + goto out; + } + + if (virMutexInit(&driverState->lock) < 0) { + VIR_FREE(driverState); + ret = -1; + goto out; + } + + nodeDeviceLock(driverState); + + /* + * http://www.kernel.org/pub/linux/utils/kernel/hotplug/libudev/libudev-udev.ht... + * + * indicates no return value other than success, so we don't check + * its return value. + */ + udev = udev_new(); + udev_set_log_fn(udev, udevLogFunction); + + udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); + if (udev_monitor == NULL) { + ret = -1; + goto out; + } + + udev_monitor_enable_receiving(udev_monitor); + + /* udev can be retrieved from udev_monitor */ + driverState->privateData = udev_monitor; + nodeDeviceUnlock(driverState); + + /* We register the monitor with the event callback so we are + * notified by udev of device changes before we enumerate existing + * devices because libvirt will simply recreate the device if we + * try to register it twice, i.e., if the device appears between + * the time we register the callback and the time we begin + * enumeration. The alternative is to register the callback after + * we enumerate, in which case we will fail to create any devices + * that appear while the enumeration is taking place. */ + if (virEventAddHandleImpl(udev_monitor_get_fd(udev_monitor), + VIR_EVENT_HANDLE_READABLE, + udevEventHandleCallback, + NULL, NULL) == -1) { + ret = -1; + goto out; + } + + /* Create a fictional 'computer' device to root the device tree. */ + if (udevSetupSystemDev() != 0) { + ret = -1; + goto out; + } + + /* Populate with known devices */ + + if (udevEnumerateDevices(udev) != 0) { + ret = -1; + goto out; + } + +out: + if (ret == -1) { + udevDeviceMonitorShutdown(); + } + return ret; +} + + +static int udevDeviceMonitorReload(void) +{ + return 0; +} + + +static int udevDeviceMonitorActive(void) +{ + /* Always ready to deal with a shutdown */ + return 0; +} + + +static virDrvOpenStatus udevNodeDrvOpen(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 udevNodeDrvClose(virConnectPtr conn) +{ + conn->devMonPrivateData = NULL; + return 0; +} + +static virDeviceMonitor udevDeviceMonitor = { + .name = "udevDeviceMonitor", + .open = udevNodeDrvOpen, + .close = udevNodeDrvClose, +}; + +static virStateDriver udevStateDriver = { + .initialize = udevDeviceMonitorStartup, + .cleanup = udevDeviceMonitorShutdown, + .reload = udevDeviceMonitorReload, + .active = udevDeviceMonitorActive, +}; + +int udevNodeRegister(void) +{ + VIR_ERROR0("Registering udev node device backend\n"); + + registerCommonNodeFuncs(&udevDeviceMonitor); + if (virRegisterDeviceMonitor(&udevDeviceMonitor) < 0) { + return -1; + } + + return virRegisterStateDriver(&udevStateDriver); +} diff --git a/src/node_device/node_device_udev.h b/src/node_device/node_device_udev.h new file mode 100644 index 0000000..d950106 --- /dev/null +++ b/src/node_device/node_device_udev.h @@ -0,0 +1,32 @@ +/* + * node_device_udev.h: node device enumeration - libudev implementation + * + * Copyright (C) 2009 Red Hat + * + * 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: Dave Allan <dallan@redhat.com> + */ + +#include <libudev.h> +#include <stdint.h> + +#define SYSFS_DATA_SIZE 4096 +#define DRV_STATE_UDEV_MONITOR(ds) ((struct udev_monitor *)((ds)->privateData)) +#define DMI_DEVPATH "/sys/devices/virtual/dmi/id" +#define SYSTEM_DESCRIPTION "fictional device to root the node device tree" +#define PROPERTY_FOUND 0 +#define PROPERTY_MISSING 1 +#define PROPERTY_ERROR -1 diff --git a/src/util/util.c b/src/util/util.c index 98f8a14..f63bd39 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -2114,3 +2114,31 @@ void virFileWaitForDevices(virConnectPtr conn) void virFileWaitForDevices(virConnectPtr conn ATTRIBUTE_UNUSED) {} #endif #endif + +int virBuildPathInternal(char **path, ...) +{ + char *path_component = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + va_list ap; + int ret = 0; + + va_start(ap, *path); + + path_component = va_arg(ap, char *); + virBufferAdd(&buf, path_component, -1); + + while ((path_component = va_arg(ap, char *)) != NULL) + { + virBufferAddChar(&buf, '/'); + virBufferAdd(&buf, path_component, -1); + } + + va_end(ap); + + *path = virBufferContentAndReset(&buf); + if (*path == NULL) { + ret = -1; + } + + return ret; +} diff --git a/src/util/util.h b/src/util/util.h index 8679636..da410e1 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -248,4 +248,7 @@ char *virFileFindMountPoint(const char *type); void virFileWaitForDevices(virConnectPtr conn); +#define virBuildPath(path, ...) virBuildPathInternal(path, __VA_ARGS__, NULL) +int virBuildPathInternal(char **path, ...) __attribute__ ((sentinel)); + #endif /* __VIR_UTIL_H__ */ diff --git a/tools/virsh.c b/tools/virsh.c index 6b93405..19a2eb1 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -5790,9 +5790,17 @@ cmdNodeListDevices (vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) char **parents = vshMalloc(ctl, sizeof(char *) * num_devices); for (i = 0; i < num_devices; i++) { virNodeDevicePtr dev = virNodeDeviceLookupByName(ctl->conn, devices[i]); + virNodeDevicePtr parent_dev = NULL; + if (dev && STRNEQ(devices[i], "computer")) { const char *parent = virNodeDeviceGetParent(dev); - parents[i] = parent ? strdup(parent) : NULL; + parent_dev = virNodeDeviceLookupByName(ctl->conn, parent); + if (parent_dev) { + parents[i] = strdup(parent); + } else { + parents[i] = strdup("computer"); + } + virNodeDeviceFree(parent_dev); } else { parents[i] = NULL; } -- 1.6.4.4
From cc3644b71d042ff394c9540a9f364752484f63a8 Mon Sep 17 00:00:00 2001 From: David Allan <dallan@redhat.com> Date: Fri, 16 Oct 2009 14:36:07 -0400 Subject: [PATCH 3/3] Remove DevKit node device backend
--- configure.in | 61 +----- src/Makefile.am | 9 - src/node_device/node_device_devkit.c | 446 ---------------------------------- src/node_device/node_device_driver.c | 3 - src/node_device/node_device_driver.h | 3 - 5 files changed, 1 insertions(+), 521 deletions(-) delete mode 100644 src/node_device/node_device_devkit.c diff --git a/configure.in b/configure.in index 25ed55f..3d05d9b 100644 --- a/configure.in +++ b/configure.in @@ -1680,60 +1680,6 @@ 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=no]) - -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]) - UDEV_REQUIRED=143 UDEV_CFLAGS= UDEV_LIBS= @@ -1773,7 +1719,7 @@ AC_SUBST([UDEV_CFLAGS]) AC_SUBST([UDEV_LIBS]) with_nodedev=no; -if test "$with_devkit" = "yes" -o "$with_hal" = "yes" -o "$with_udev" = "yes"; +if test "$with_hal" = "yes" -o "$with_udev" = "yes"; then with_nodedev=yes AC_DEFINE_UNQUOTED([WITH_NODE_DEVICES], 1, [with node device driver]) @@ -1933,11 +1879,6 @@ 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 if test "$with_udev" = "yes" ; then AC_MSG_NOTICE([ udev: $UDEV_CFLAGS $UDEV_LIBS]) else diff --git a/src/Makefile.am b/src/Makefile.am index 11da07b..cd05c28 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -262,9 +262,6 @@ NODE_DEVICE_DRIVER_HAL_SOURCES = \ node_device/node_device_hal.c \ node_device/node_device_hal.h -NODE_DEVICE_DRIVER_DEVKIT_SOURCES = \ - node_device/node_device_devkit.c - NODE_DEVICE_DRIVER_UDEV_SOURCES = \ node_device/node_device_udev.c @@ -641,11 +638,6 @@ 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 HAVE_UDEV libvirt_driver_nodedev_la_SOURCES += $(NODE_DEVICE_DRIVER_UDEV_SOURCES) libvirt_driver_nodedev_la_CFLAGS += $(UDEV_CFLAGS) @@ -699,7 +691,6 @@ EXTRA_DIST += \ $(STORAGE_DRIVER_DISK_SOURCES) \ $(NODE_DEVICE_DRIVER_SOURCES) \ $(NODE_DEVICE_DRIVER_HAL_SOURCES) \ - $(NODE_DEVICE_DRIVER_DEVKIT_SOURCES) \ $(NODE_DEVICE_DRIVER_UDEV_SOURCES) \ $(SECURITY_DRIVER_SELINUX_SOURCES) \ $(SECURITY_DRIVER_APPARMOR_SOURCES) \ diff --git a/src/node_device/node_device_devkit.c b/src/node_device/node_device_devkit.c deleted file mode 100644 index a6c7941..0000000 --- a/src/node_device/node_device_devkit.c +++ /dev/null @@ -1,446 +0,0 @@ -/* - * 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 "logging.h" - -#include "node_device.h" - -/* - * Host device enumeration (DeviceKit implementation) - */ - -static virDeviceMonitorStatePtr driverState; - -#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 *ifname; - - if (sysfs_path == NULL) - return -1; - ifname = strrchr(sysfs_path, '/'); - if (!ifname || !*ifname || !*(++ifname)) - return -1; - if ((d->net.ifname = strdup(ifname)) == NULL) - return -1; - - d->net.subtype = VIR_NODE_DEV_CAP_NET_LAST; - - return 0; -} - - -static int gather_storage_cap(DevkitDevice *dkdev, - union _virNodeDevCapData *d) -{ - const char *device = devkit_device_get_device_file(dkdev); - - if (device && ((d->storage.block = 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_STORAGE, gather_storage_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; - virNodeDeviceDefPtr def = 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(def) < 0) - goto failure; - - if ((def->name = strdup(name)) == NULL) - goto failure; - - // TODO: Find device parent, if any - - rv = gather_capabilities(dkdev, &def->caps); - if (rv != 0) goto failure; - - nodeDeviceLock(driverState); - dev = virNodeDeviceAssignDef(NULL, - &driverState->devs, - def); - - if (!dev) { - nodeDeviceUnlock(driverState); - goto failure; - } - - dev->privateData = dkdev; - dev->privateFree = NULL; /* XXX some free func needed ? */ - virNodeDeviceObjUnlock(dev); - - nodeDeviceUnlock(driverState); - - return; - - failure: - DEBUG("FAILED TO ADD dev %s", name); - if (def) - virNodeDeviceDefFree(def); -} - - -static int devkitDeviceMonitorStartup(int privileged ATTRIBUTE_UNUSED) -{ - 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; - - if (virMutexInit(&driverState->lock) < 0) { - VIR_FREE(driverState); - return -1; - } - - 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; - - nodeDeviceLock(driverState); - devkit_client = DRV_STATE_DKCLIENT(driverState); - virNodeDeviceObjListFree(&driverState->devs); - if (devkit_client) - g_object_unref(devkit_client); - nodeDeviceUnlock(driverState); - virMutexDestroy(&driveState->lock); - VIR_FREE(driverState); - return 0; - } - return -1; -} - - -static int devkitDeviceMonitorReload(void) -{ - /* XXX This isn't thread safe because its free'ing the thing - * we're locking */ - (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 virDeviceMonitor devkitDeviceMonitor = { - .name = "devkitDeviceMonitor", - .open = devkitNodeDrvOpen, - .close = devkitNodeDrvClose, -}; - - -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 --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index c139907..cddd994 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -670,9 +670,6 @@ int nodedevRegister(void) { #ifdef HAVE_HAL return halNodeRegister(); #endif -#ifdef HAVE_DEVKIT - return devkitNodeRegister(); -#endif #ifdef HAVE_UDEV return udevNodeRegister(); #endif diff --git a/src/node_device/node_device_driver.h b/src/node_device/node_device_driver.h index 5be0781..4f0822c 100644 --- a/src/node_device/node_device_driver.h +++ b/src/node_device/node_device_driver.h @@ -42,9 +42,6 @@ #ifdef HAVE_HAL int halNodeRegister(void); #endif -#ifdef HAVE_DEVKIT -int devkitNodeRegister(void); -#endif #ifdef HAVE_UDEV int udevNodeRegister(void); #endif -- 1.6.4.4