diff --git a/ChangeLog b/ChangeLog
index 4ef02d263f..842bbfefb4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,16 @@
 Thu Jun 12 13:06:42 BST 2009 Daniel P. Berrange <berrange@redhat.com>
 
-	Improve error reporting for virConnecOpen URIs
+	Include OS driver name (if any) in device XML
+	* src/node_device.c: Refresh OS driver when generating XML,
+	and include impl for Linux sysfs
+	* src/noe_device_conf.c, src/node_device_conf.h: Add field
+	for OS driver name to config
+	* src/node_device_hal.c: Record sysfs path to be used for
+	driver name fetching later.
+
+Thu Jun 12 13:06:42 BST 2009 Daniel P. Berrange <berrange@redhat.com>
+
+	Improve error reporting for virConnectOpen URIs
 	* src/lxc_driver.c, src/openvz_driver.c, src/qemu_driver.c,
 	src/uml_driver.c, src/xen_unified.c: Always return ACCEPT
 	or ERROR for URIs without hostname set, but with the driver's
diff --git a/src/node_device.c b/src/node_device.c
index cd9fb6e65f..de51bc85f4 100644
--- a/src/node_device.c
+++ b/src/node_device.c
@@ -48,6 +48,60 @@ static int dev_has_cap(const virNodeDeviceObjPtr dev, const char *cap)
     return 0;
 }
 
+#ifdef __linux__
+static int update_driver_name(virConnectPtr conn,
+                              virNodeDeviceObjPtr dev)
+{
+    char *driver_link = NULL;
+    char devpath[PATH_MAX];
+    char *p;
+    int ret = -1;
+    int n;
+
+    VIR_FREE(dev->def->driver);
+
+    if (virAsprintf(&driver_link, "%s/driver", dev->devicePath) < 0) {
+        virReportOOMError(conn);
+        goto cleanup;
+    }
+
+    /* Some devices don't have an explicit driver, so just return
+       without a name */
+    if (access(driver_link, R_OK) < 0) {
+        ret = 0;
+        goto cleanup;
+    }
+
+    if ((n = readlink(driver_link, devpath, sizeof devpath)) < 0) {
+        virReportSystemError(conn, errno,
+                             _("cannot resolve driver link %s"), driver_link);
+        goto cleanup;
+    }
+    devpath[n] = '\0';
+
+    p = strrchr(devpath, '/');
+    if (p) {
+        dev->def->driver = strdup(p+1);
+        if (!dev->def->driver) {
+            virReportOOMError(conn);
+            goto cleanup;
+        }
+    }
+    ret = 0;
+
+cleanup:
+    VIR_FREE(driver_link);
+    return ret;
+}
+#else
+/* XXX: Implement me for non-linux */
+static int update_driver_name(virConnectPtr conn ATTRIBUTE_UNUSED,
+                              virNodeDeviceObjPtr dev ATTRIBUTE_UNUSED)
+{
+    return 0;
+}
+#endif
+
 
 void nodeDeviceLock(virDeviceMonitorStatePtr driver)
 {
@@ -197,6 +251,7 @@ static char *nodeDeviceDumpXML(virNodeDevicePtr dev,
         goto cleanup;
     }
 
+    update_driver_name(dev->conn, obj);
     ret = virNodeDeviceDefFormat(dev->conn, obj->def);
 
 cleanup:
diff --git a/src/node_device_conf.c b/src/node_device_conf.c
index be198438e0..1fbf9dc891 100644
--- a/src/node_device_conf.c
+++ b/src/node_device_conf.c
@@ -106,6 +106,7 @@ void virNodeDeviceDefFree(virNodeDeviceDefPtr def)
 
     VIR_FREE(def->name);
     VIR_FREE(def->parent);
+    VIR_FREE(def->driver);
 
     caps = def->caps;
     while (caps) {
@@ -122,6 +123,7 @@ void virNodeDeviceObjFree(virNodeDeviceObjPtr dev)
     if (!dev)
         return;
 
+    VIR_FREE(dev->devicePath);
     virNodeDeviceDefFree(dev->def);
     if (dev->privateFree)
         (*dev->privateFree)(dev->privateData);
@@ -219,6 +221,11 @@ char *virNodeDeviceDefFormat(virConnectPtr conn,
 
     if (def->parent)
         virBufferEscapeString(&buf, "  <parent>%s</parent>\n", def->parent);
+    if (def->driver) {
+        virBufferAddLit(&buf, "  <driver>\n");
+        virBufferEscapeString(&buf, "    <name>%s</name>\n", def->driver);
+        virBufferAddLit(&buf, "  </driver>\n");
+    }
 
     for (caps = def->caps; caps; caps = caps->next) {
         char uuidstr[VIR_UUID_STRING_BUFLEN];
diff --git a/src/node_device_conf.h b/src/node_device_conf.h
index 522dfde484..c33cc738c2 100644
--- a/src/node_device_conf.h
+++ b/src/node_device_conf.h
@@ -156,6 +156,7 @@ typedef virNodeDeviceDef *virNodeDeviceDefPtr;
 struct _virNodeDeviceDef {
     char *name;                         /* device name (unique on node) */
     char *parent;			/* optional parent device name */
+    char *driver;                       /* optional driver name */
     virNodeDevCapsDefPtr caps;		/* optional device capabilities */
 };
 
@@ -165,6 +166,7 @@ typedef virNodeDeviceObj *virNodeDeviceObjPtr;
 struct _virNodeDeviceObj {
     virMutex lock;
 
+    char *devicePath;                   /* OS specific path to device metadat, eg sysfs */
     virNodeDeviceDefPtr def;		/* device definition */
     void *privateData;			/* driver-specific private data */
     void (*privateFree)(void *data);	/* destructor for private data */
diff --git a/src/node_device_hal.c b/src/node_device_hal.c
index b2af7a0520..ea519466c5 100644
--- a/src/node_device_hal.c
+++ b/src/node_device_hal.c
@@ -429,6 +429,7 @@ static void dev_create(const char *udi)
     const char *name = hal_name(udi);
     int rv;
     char *privData = strdup(udi);
+    char *devicePath = NULL;
 
     if (!privData)
         return;
@@ -455,15 +456,22 @@ static void dev_create(const char *udi)
     if (def->caps == NULL)
         goto cleanup;
 
+    /* Some devices don't have a path in sysfs, so ignore failure */
+    get_str_prop(ctx, udi, "linux.sysfs_path", &devicePath);
+
     dev = virNodeDeviceAssignDef(NULL,
                                  &driverState->devs,
                                  def);
 
-    if (!dev)
+    if (!dev) {
+        VIR_FREE(devicePath);
         goto failure;
+    }
 
     dev->privateData = privData;
     dev->privateFree = free_udi;
+    dev->devicePath = devicePath;
+
     virNodeDeviceObjUnlock(dev);
 
     nodeDeviceUnlock(driverState);