Re: [PATCH v2 1/3] vmbus: add support for dynamic device id's

2016-11-10 Thread Greg KH
On Mon, Oct 17, 2016 at 12:29:59PM -0700, Stephen Hemminger wrote:
> From: Stephen Hemminger 
> 
> This patch adds sysfs interface to dynamically bind new UUID values
> to existing VMBus device. This is useful for generic UIO driver to
> act similar to uio_pci_generic.
> 
> Signed-off-by: Stephen Hemminger 
> ---
> v2 - allow device driver to have empty id table, and fix bugs
> 
>  drivers/hv/vmbus_drv.c | 174 
> ++---
>  include/linux/hyperv.h |   6 ++
>  2 files changed, 172 insertions(+), 8 deletions(-)

Can I get an ack from the hyperv maintainers before accepting this?

thanks,

greg k-h


[PATCH v2 1/3] vmbus: add support for dynamic device id's

2016-10-17 Thread Stephen Hemminger
From: Stephen Hemminger 

This patch adds sysfs interface to dynamically bind new UUID values
to existing VMBus device. This is useful for generic UIO driver to
act similar to uio_pci_generic.

Signed-off-by: Stephen Hemminger 
---
v2 - allow device driver to have empty id table, and fix bugs

 drivers/hv/vmbus_drv.c | 174 ++---
 include/linux/hyperv.h |   6 ++
 2 files changed, 172 insertions(+), 8 deletions(-)

diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index a259e18..d8d34bf 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -45,6 +45,11 @@
 #include 
 #include "hyperv_vmbus.h"
 
+struct vmbus_dynid {
+   struct list_head node;
+   struct hv_vmbus_device_id id;
+};
+
 static struct acpi_device  *hv_acpi_dev;
 
 static struct completion probe_event;
@@ -500,7 +505,7 @@ static ssize_t device_show(struct device *dev,
 static DEVICE_ATTR_RO(device);
 
 /* Set up per device attributes in /sys/bus/vmbus/devices/ */
-static struct attribute *vmbus_attrs[] = {
+static struct attribute *vmbus_dev_attrs[] = {
&dev_attr_id.attr,
&dev_attr_state.attr,
&dev_attr_monitor_id.attr,
@@ -528,7 +533,7 @@ static struct attribute *vmbus_attrs[] = {
&dev_attr_device.attr,
NULL,
 };
-ATTRIBUTE_GROUPS(vmbus);
+ATTRIBUTE_GROUPS(vmbus_dev);
 
 /*
  * vmbus_uevent - add uevent for our device
@@ -565,10 +570,29 @@ static inline bool is_null_guid(const uuid_le *guid)
  * Return a matching hv_vmbus_device_id pointer.
  * If there is no match, return NULL.
  */
-static const struct hv_vmbus_device_id *hv_vmbus_get_id(
-   const struct hv_vmbus_device_id *id,
+static const struct hv_vmbus_device_id *hv_vmbus_get_id(struct hv_driver *drv,
const uuid_le *guid)
 {
+   const struct hv_vmbus_device_id *id = NULL;
+   struct vmbus_dynid *dynid;
+
+   /* Look at the dynamic ids first, before the static ones */
+   spin_lock(&drv->dynids.lock);
+   list_for_each_entry(dynid, &drv->dynids.list, node) {
+   if (!uuid_le_cmp(dynid->id.guid, *guid)) {
+   id = &dynid->id;
+   break;
+   }
+   }
+   spin_unlock(&drv->dynids.lock);
+
+   if (id)
+   return id;
+
+   id = drv->id_table;
+   if (id == NULL)
+   return NULL; /* empty device table */
+
for (; !is_null_guid(&id->guid); id++)
if (!uuid_le_cmp(id->guid, *guid))
return id;
@@ -576,6 +600,134 @@ static const struct hv_vmbus_device_id *hv_vmbus_get_id(
return NULL;
 }
 
+/* vmbus_add_dynid - add a new device ID to this driver and re-probe devices */
+static int vmbus_add_dynid(struct hv_driver *drv, uuid_le *guid)
+{
+   struct vmbus_dynid *dynid;
+
+   dynid = kzalloc(sizeof(*dynid), GFP_KERNEL);
+   if (!dynid)
+   return -ENOMEM;
+
+   dynid->id.guid = *guid;
+
+   spin_lock(&drv->dynids.lock);
+   list_add_tail(&dynid->node, &drv->dynids.list);
+   spin_unlock(&drv->dynids.lock);
+
+   return driver_attach(&drv->driver);
+}
+
+static void vmbus_free_dynids(struct hv_driver *drv)
+{
+   struct vmbus_dynid *dynid, *n;
+
+   spin_lock(&drv->dynids.lock);
+   list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
+   list_del(&dynid->node);
+   kfree(dynid);
+   }
+   spin_unlock(&drv->dynids.lock);
+}
+
+/* Parse string of form: 1b4e28ba-2fa1-11d2-883f-b9a761bde3f */
+static int get_uuid_le(const char *str, uuid_le *uu)
+{
+   unsigned int b[16];
+   int i;
+
+   if (strlen(str) < 37)
+   return -1;
+
+   for (i = 0; i < 36; i++) {
+   switch (i) {
+   case 8: case 13: case 18: case 23:
+   if (str[i] != '-')
+   return -1;
+   break;
+   default:
+   if (!isxdigit(str[i]))
+   return -1;
+   }
+   }
+
+   /* unparse little endian output byte order */
+   if (sscanf(str,
+  "%2x%2x%2x%2x-%2x%2x-%2x%2x-%2x%2x-%2x%2x%2x%2x%2x%2x",
+  &b[3], &b[2], &b[1], &b[0],
+  &b[5], &b[4], &b[7], &b[6], &b[8], &b[9],
+  &b[10], &b[11], &b[12], &b[13], &b[14], &b[15]) != 16)
+   return -1;
+
+   for (i = 0; i < 16; i++)
+   uu->b[i] = b[i];
+   return 0;
+}
+
+/*
+ * store_new_id - sysfs frontend to vmbus_add_dynid()
+ *
+ * Allow GUIDs to be added to an existing driver via sysfs.
+ */
+static ssize_t store_new_id(struct device_driver *driver, const char *buf,
+   size_t count)
+{
+   struct hv_driver *drv = drv_to_hv_drv(driver);
+   uuid_le guid = NULL_UUID_LE;
+   ssize_t retval;
+
+   if (get_uu