提交 620d4be7 编写于 作者: D Daniel P. Berrange

Node device driver for HAL and DeviceKit (David Lively)

上级 149322c5
Fri Nov 21 12:23:14 BST 2008 Daniel P. Berrange <berrange@redhat.com>
Primary internal driver for node devices with HAL (default)
and DeviceKit (optional, unfinished) (David Lively)
* configure.in: Probe for HAL & DeviceKit libraries
* po/POTFILES.in: Add new source files
* qemud/Makefile.am: Link to node device driver
* qemud/qemud.c: Load node device driver implementation
* src/Makefile.am: Buid node device drivers
* src/libvirt_sym.version.in: Export internal symbols needed
by node device driver
* src/node_device.c, src/node_device.h: Common driver
routines
* src/node_device_hal.c: HAL specific device routines
* src/node_device_devkit.c: DeviceKit specific routines
* src/node_device_conf.h: Add dbusWatch handle field
Fri Nov 21 12:20:14 BST 2008 Daniel P. Berrange <berrange@redhat.com>
* src/Makefile.am, src/node_device_conf.c, src/node_device_conf.h:
......
......@@ -1105,6 +1105,108 @@ 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
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=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])
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
......@@ -1196,6 +1298,16 @@ AC_MSG_NOTICE([ xen: $XEN_CFLAGS $XEN_LIBS])
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([])
......
......@@ -13,6 +13,7 @@ src/lxc_controller.c
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
......
......@@ -111,6 +111,10 @@ endif
if WITH_NETWORK
libvirtd_LDADD += ../src/libvirt_driver_network.la
endif
if WITH_NODE_DEVICES
libvirtd_LDADD += ../src/libvirt_driver_nodedev.la
endif
endif
libvirtd_LDADD += ../src/libvirt.la
......
......@@ -79,6 +79,9 @@
#ifdef WITH_STORAGE_DIR
#include "storage_driver.h"
#endif
#ifdef WITH_NODE_DEVICES
#include "node_device.h"
#endif
#endif
......@@ -763,6 +766,7 @@ static struct qemud_server *qemudInitialize(int sigread) {
virDriverLoadModule("uml");
virDriverLoadModule("network");
virDriverLoadModule("storage");
virDriverLoadModule("nodedev");
#else
#ifdef WITH_QEMU
qemuRegister();
......@@ -779,6 +783,9 @@ static struct qemud_server *qemudInitialize(int sigread) {
#ifdef WITH_STORAGE_DIR
storageRegister();
#endif
#if defined(HAVE_HAL) || defined(HAVE_DEVKIT)
nodedevRegister();
#endif
#endif
virEventRegisterImpl(virEventAddHandleImpl,
......
......@@ -157,6 +157,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
#########################
#
......@@ -330,6 +338,36 @@ if WITH_STORAGE_DISK
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) \
......@@ -344,7 +382,10 @@ EXTRA_DIST += \
$(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
......
......@@ -327,6 +327,7 @@ LIBVIRT_PRIVATE_@VERSION@ {
virGetNetwork;
virGetStoragePool;
virGetStorageVol;
virGetNodeDevice;
virUnrefDomain;
......@@ -451,6 +452,7 @@ LIBVIRT_PRIVATE_@VERSION@ {
virRegisterNetworkDriver;
virRegisterStateDriver;
virRegisterStorageDriver;
virRegisterDeviceMonitor;
/* memory.h */
......@@ -481,6 +483,16 @@ LIBVIRT_PRIVATE_@VERSION@ {
virNodeInfoPopulate;
/* node_device_conf.h */
virNodeDeviceObjRemove;
virNodeDevCapTypeToString;
virNodeDeviceFindByName;
virNodeDeviceObjListFree;
virNodeDeviceDefFree;
virNodeDevCapsDefFree;
virNodeDeviceDefFormat;
/* qparams.h */
qparam_get_query;
qparam_query_parse;
......@@ -539,6 +551,7 @@ LIBVIRT_PRIVATE_@VERSION@ {
virStrToLong_i;
virStrToLong_ll;
virStrToLong_ull;
virStrToLong_ui;
virFileLinkPointsTo;
saferead;
safewrite;
......@@ -558,6 +571,7 @@ LIBVIRT_PRIVATE_@VERSION@ {
virFileOpenTty;
virFileReadLimFD;
virFileReadPid;
virFileLinkPointsTo;
virParseNumber;
virRun;
virSkipSpaces;
......
/*
* 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,
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 ((cap == NULL) ||
dev_has_cap(driver->devs.objs[i], cap))
++ndevs;
return ndevs;
}
static int
nodeListDevices(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 (cap == NULL ||
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->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
}
/*
* 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__ */
......@@ -161,6 +161,7 @@ struct _virNodeDeviceObjList {
typedef struct _virDeviceMonitorState virDeviceMonitorState;
typedef virDeviceMonitorState *virDeviceMonitorStatePtr;
struct _virDeviceMonitorState {
int dbusWatch;
virNodeDeviceObjList devs; /* currently-known devices */
void *privateData; /* driver-specific private data */
};
......
/*
* 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 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);
}
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册