nodedev: add <devnode> paths

Add new <devnode> top-level <device> element, that list the associated
/dev files. Distinguish the main /dev name from symlinks with a 'type'
attribute of value 'dev' or 'symlink'.

Update a test to check XML schema, and actually add it to the test list
since it was missing.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
Marc-André Lureau 2017-02-15 01:04:10 +04:00 committed by Michal Privoznik
parent 7f64435307
commit 0809508ed2
7 changed files with 123 additions and 1 deletions

View File

@ -37,6 +37,12 @@
<dd>If this element is present, it names the parent device (that
is, a controller to which this node belongs).
</dd>
<dt><code>devnode</code></dt>
<dd>This node appears for each associated <code>/dev</code>
special file. A mandatory attribute <code>type</code> specify
the kind of file path, which may be either <code>dev</code> for
the main name, or <code>link</code> for additional symlinks.
</dd>
<dt><code>capability</code></dt>
<dd>This node appears for each capability that libvirt
associates with a node. A mandatory

View File

@ -15,6 +15,22 @@
<optional>
<element name="path"><text/></element>
</optional>
<optional>
<element name="devnode">
<attribute name='type'>
<value>dev</value>
</attribute>
<text/>
</element>
</optional>
<zeroOrMore>
<element name="devnode">
<attribute name='type'>
<value>link</value>
</attribute>
<text/>
</element>
</zeroOrMore>
<optional>
<ref name="parent"/>
</optional>

View File

@ -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, "<name>%s</name>\n", def->name);
virBufferEscapeString(&buf, "<path>%s</path>\n", def->sysfs_path);
if (def->devnode)
virBufferEscapeString(&buf, "<devnode type='dev'>%s</devnode>\n",
def->devnode);
if (def->devlinks) {
for (i = 0; def->devlinks[i]; i++)
virBufferEscapeString(&buf, "<devnode type='link'>%s</devnode>\n",
def->devlinks[i]);
}
if (def->parent)
virBufferEscapeString(&buf, "<parent>%s</parent>\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);

View File

@ -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 */
};

View File

@ -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;

View File

@ -1,5 +1,9 @@
<device>
<name>storage_serial_3600c0ff000d7a2a5d463ff4902000000</name>
<devnode type='dev'>/dev/sdb</devnode>
<devnode type='link'>/dev/disk/by-id/usb-SanDisk_Ultra_Fit_4C530001051009112405-0:0</devnode>
<devnode type='link'>/dev/disk/by-path/pci-0000:00:14.0-usb-0:1:1.0-scsi-0:0:0:0</devnode>
<devnode type='link'>/dev/disk/by-uuid/661A1A460111DA18</devnode>
<parent>pci_10df_fe00_scsi_host_scsi_device_lun8</parent>
<capability type='storage'>
<block>/dev/sdj</block>

View File

@ -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");