diff --git a/docs/formatnode.html.in b/docs/formatnode.html.in
index f8d0e12340..ecdd1dbcb4 100644
--- a/docs/formatnode.html.in
+++ b/docs/formatnode.html.in
@@ -37,6 +37,12 @@
If this element is present, it names the parent device (that
is, a controller to which this node belongs).
+ devnode
+ This node appears for each associated /dev
+ special file. A mandatory attribute type
specify
+ the kind of file path, which may be either dev
for
+ the main name, or link
for additional symlinks.
+
capability
This node appears for each capability that libvirt
associates with a node. A mandatory
diff --git a/docs/schemas/nodedev.rng b/docs/schemas/nodedev.rng
index b100a6e16d..62e29b6cc1 100644
--- a/docs/schemas/nodedev.rng
+++ b/docs/schemas/nodedev.rng
@@ -15,6 +15,22 @@
+
+
+
+ dev
+
+
+
+
+
+
+
+ link
+
+
+
+
diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
index f37a48c404..91a76586c0 100644
--- a/src/conf/node_device_conf.c
+++ b/src/conf/node_device_conf.c
@@ -40,6 +40,10 @@
#define VIR_FROM_THIS VIR_FROM_NODEDEV
+VIR_ENUM_IMPL(virNodeDevDevnode, VIR_NODE_DEV_DEVNODE_LAST,
+ "dev",
+ "link")
+
VIR_ENUM_IMPL(virNodeDevCap, VIR_NODE_DEV_CAP_LAST,
"system",
"pci",
@@ -252,6 +256,8 @@ void virNodeDeviceDefFree(virNodeDeviceDefPtr def)
VIR_FREE(def->driver);
VIR_FREE(def->sysfs_path);
VIR_FREE(def->parent_sysfs_path);
+ VIR_FREE(def->devnode);
+ virStringListFree(def->devlinks);
caps = def->caps;
while (caps) {
@@ -387,6 +393,14 @@ char *virNodeDeviceDefFormat(const virNodeDeviceDef *def)
virBufferAdjustIndent(&buf, 2);
virBufferEscapeString(&buf, "%s\n", def->name);
virBufferEscapeString(&buf, "%s\n", def->sysfs_path);
+ if (def->devnode)
+ virBufferEscapeString(&buf, "%s\n",
+ def->devnode);
+ if (def->devlinks) {
+ for (i = 0; def->devlinks[i]; i++)
+ virBufferEscapeString(&buf, "%s\n",
+ def->devlinks[i]);
+ }
if (def->parent)
virBufferEscapeString(&buf, "%s\n", def->parent);
if (def->driver) {
@@ -1703,7 +1717,7 @@ virNodeDeviceDefParseXML(xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def;
virNodeDevCapsDefPtr *next_cap;
xmlNodePtr *nodes;
- int n;
+ int n, m;
size_t i;
if (VIR_ALLOC(def) < 0)
@@ -1722,6 +1736,44 @@ virNodeDeviceDefParseXML(xmlXPathContextPtr ctxt,
goto error;
}
+ /* Parse devnodes */
+ nodes = NULL;
+ if ((n = virXPathNodeSet("./devnode", ctxt, &nodes)) < 0)
+ goto error;
+
+ if (VIR_ALLOC_N(def->devlinks, n + 1) < 0)
+ goto error;
+
+ for (i = 0, m = 0; i < n; i++) {
+ xmlNodePtr node = nodes[i];
+ char *tmp = virXMLPropString(node, "type");
+ virNodeDevDevnodeType type;
+
+ if (!tmp) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing devnode type"));
+ goto error;
+ }
+
+ if ((type = virNodeDevDevnodeTypeFromString(tmp)) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown devnode type '%s'"), tmp);
+ VIR_FREE(tmp);
+ goto error;
+ }
+
+ switch (type) {
+ case VIR_NODE_DEV_DEVNODE_DEV:
+ def->devnode = (char*)xmlNodeGetContent(node);
+ break;
+ case VIR_NODE_DEV_DEVNODE_LINK:
+ def->devlinks[m++] = (char*)xmlNodeGetContent(node);
+ break;
+ case VIR_NODE_DEV_DEVNODE_LAST:
+ break;
+ }
+ }
+
/* Extract device parent, if any */
def->parent = virXPathString("string(./parent[1])", ctxt);
def->parent_wwnn = virXPathString("string(./parent[1]/@wwnn)", ctxt);
diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h
index 1634483339..f46e9841ae 100644
--- a/src/conf/node_device_conf.h
+++ b/src/conf/node_device_conf.h
@@ -38,6 +38,16 @@
# define CREATE_DEVICE 1
# define EXISTING_DEVICE 0
+typedef enum {
+ /* Keep in sync with VIR_ENUM_IMPL in node_device_conf.c */
+ VIR_NODE_DEV_DEVNODE_DEV,
+ VIR_NODE_DEV_DEVNODE_LINK,
+
+ VIR_NODE_DEV_DEVNODE_LAST
+} virNodeDevDevnodeType;
+
+VIR_ENUM_DECL(virNodeDevDevnode)
+
typedef enum {
/* Keep in sync with VIR_ENUM_IMPL in node_device_conf.c */
VIR_NODE_DEV_CAP_SYSTEM, /* System capability */
@@ -204,6 +214,8 @@ struct _virNodeDeviceDef {
char *parent_wwpn; /* optional parent wwpn */
char *parent_fabric_wwn; /* optional parent fabric_wwn */
char *driver; /* optional driver name */
+ char *devnode; /* /dev path */
+ char **devlinks; /* /dev links */
virNodeDevCapsDefPtr caps; /* optional device capabilities */
};
diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c
index 4b813127cb..d7658410a9 100644
--- a/src/node_device/node_device_udev.c
+++ b/src/node_device/node_device_udev.c
@@ -917,6 +917,34 @@ udevProcessSCSIGeneric(struct udev_device *dev,
return 0;
}
+static int
+udevGetDeviceNodes(struct udev_device *device,
+ virNodeDeviceDefPtr def)
+{
+ const char *devnode = NULL;
+ struct udev_list_entry *list_entry = NULL;
+ int n = 0;
+
+ devnode = udev_device_get_devnode(device);
+
+ if (VIR_STRDUP(def->devnode, devnode) < 0)
+ return -1;
+
+ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device))
+ n++;
+
+ if (VIR_ALLOC_N(def->devlinks, n + 1) < 0)
+ return -1;
+
+ n = 0;
+ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
+ if (VIR_STRDUP(def->devlinks[n++], udev_list_entry_get_name(list_entry)) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
static int
udevGetDeviceType(struct udev_device *device,
virNodeDevCapType *type)
@@ -1125,6 +1153,9 @@ static int udevAddOneDevice(struct udev_device *device)
if (udevGetDeviceType(device, &def->caps->data.type) != 0)
goto cleanup;
+ if (udevGetDeviceNodes(device, def) != 0)
+ goto cleanup;
+
if (udevGetDeviceDetails(device, def) != 0)
goto cleanup;
diff --git a/tests/nodedevschemadata/storage_serial_3600c0ff000d7a2a5d463ff4902000000.xml b/tests/nodedevschemadata/storage_serial_3600c0ff000d7a2a5d463ff4902000000.xml
index d9d61da44a..d225dca8fa 100644
--- a/tests/nodedevschemadata/storage_serial_3600c0ff000d7a2a5d463ff4902000000.xml
+++ b/tests/nodedevschemadata/storage_serial_3600c0ff000d7a2a5d463ff4902000000.xml
@@ -1,5 +1,9 @@
storage_serial_3600c0ff000d7a2a5d463ff4902000000
+ /dev/sdb
+ /dev/disk/by-id/usb-SanDisk_Ultra_Fit_4C530001051009112405-0:0
+ /dev/disk/by-path/pci-0000:00:14.0-usb-0:1:1.0-scsi-0:0:0:0
+ /dev/disk/by-uuid/661A1A460111DA18
pci_10df_fe00_scsi_host_scsi_device_lun8
/dev/sdj
diff --git a/tests/nodedevxml2xmltest.c b/tests/nodedevxml2xmltest.c
index eb32dd31d2..ec96943cb1 100644
--- a/tests/nodedevxml2xmltest.c
+++ b/tests/nodedevxml2xmltest.c
@@ -87,6 +87,7 @@ mymain(void)
DO_TEST("pci_8086_27c5_scsi_host_scsi_host");
DO_TEST("pci_8086_27c5_scsi_host");
DO_TEST("storage_serial_SATA_HTS721010G9SA00_MPCZ12Y0GNGWSE");
+ DO_TEST("storage_serial_3600c0ff000d7a2a5d463ff4902000000");
DO_TEST("usb_device_1d6b_1_0000_00_1d_0_if0");
DO_TEST("usb_device_1d6b_1_0000_00_1d_0");
DO_TEST("pci_8086_4238_pcie_wireless");