[PATCH] scsi: ensure bsg device is available before announcing scsi device

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: David Zeuthen <davidz@xxxxxxxxxx>

udev should be able to examine a scsi device (e.g. retrieving VPD like
the make/model and serial number) before announcing it to the rest of
user space. Currently this is not possible because the scsi device has
no device node of its own. Instead, user space will have to use either
the bsg device or sg device but these are not available at uevent add
time since both are children of the scsi device

This patch ensures that the bsg device is created before user space is
notified of add event for the scsi device. With devtmpfs, this thus
enables udev to use the /dev/bsg/$kernel device node to examine the
scsi device.

Related udev commits:

 http://git.kernel.org/?p=linux/hotplug/udev.git;a=commitdiff;h=2938220037862b7698df091a1e5cd45f44132d73
 http://git.kernel.org/?p=linux/hotplug/udev.git;a=commitdiff;h=310f99d33595afdc1962611a913c429785f9ad40

Signed-off-by: David Zeuthen <davidz@xxxxxxxxxx>
Acked-by: Kay Sievers <kay.sievers@xxxxxxxx>
---
 block/bsg.c                       |   53 +++++++++++++++++++++++++++++++++++-
 drivers/scsi/scsi_sysfs.c         |   27 +++++++++++++-----
 drivers/scsi/scsi_transport_fc.c  |    4 +-
 drivers/scsi/scsi_transport_sas.c |    2 +-
 include/linux/bsg.h               |    6 +++-
 5 files changed, 77 insertions(+), 15 deletions(-)

diff --git a/block/bsg.c b/block/bsg.c
index 0c8b64a..7148b4c 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -993,8 +993,48 @@ void bsg_unregister_queue(struct request_queue *q)
 }
 EXPORT_SYMBOL_GPL(bsg_unregister_queue);
 
+static void bsg_release_class_device(struct device *dev)
+{
+	pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
+	kfree(dev);
+}
+
+static struct device *bsg_create_class_device(struct class *class,
+					      struct device *parent,
+					      dev_t devt,
+					      const char *name)
+{
+	struct device *dev = NULL;
+	int retval = -ENODEV;
+
+	if (class == NULL || IS_ERR(class))
+		goto error;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev) {
+		retval = -ENOMEM;
+		goto error;
+	}
+
+	dev->devt = devt;
+	dev->class = class;
+	dev->parent = parent;
+	dev->release = bsg_release_class_device;
+
+	retval = kobject_set_name(&dev->kobj, name);
+	if (retval)
+		goto error;
+
+	return dev;
+
+error:
+	put_device(dev);
+	return ERR_PTR(retval);
+}
+
 int bsg_register_queue(struct request_queue *q, struct device *parent,
-		       const char *name, void (*release)(struct device *))
+		       const char *name, void (*release)(struct device *),
+		       bool suppress_add_uevent)
 {
 	struct bsg_class_device *bcd;
 	dev_t dev;
@@ -1040,11 +1080,20 @@ int bsg_register_queue(struct request_queue *q, struct device *parent,
 	bcd->release = release;
 	kref_init(&bcd->ref);
 	dev = MKDEV(bsg_major, bcd->minor);
-	class_dev = device_create(bsg_class, parent, dev, NULL, "%s", devname);
+	class_dev = bsg_create_class_device(bsg_class, parent, dev, devname);
 	if (IS_ERR(class_dev)) {
 		ret = PTR_ERR(class_dev);
 		goto put_dev;
 	}
+	if (suppress_add_uevent) {
+		dev_set_uevent_suppress(class_dev, true);
+		ret = device_register(class_dev);
+		dev_set_uevent_suppress(class_dev, false);
+	} else {
+		ret = device_register(class_dev);
+	}
+	if (ret)
+		goto put_dev;
 	bcd->class_dev = class_dev;
 
 	if (q->kobj.sd) {
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 490ce21..fd8c43f 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -862,12 +862,31 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
 	 */
 	scsi_autopm_get_device(sdev);
 
+	/* Delay add uevent for device until bsg device has been
+	 * created - this way user space can use the bsg device node
+	 * when handling the uevent
+	 */
+	dev_set_uevent_suppress(&sdev->sdev_gendev, true);
 	error = device_add(&sdev->sdev_gendev);
+	dev_set_uevent_suppress(&sdev->sdev_gendev, false);
 	if (error) {
 		sdev_printk(KERN_INFO, sdev,
 				"failed to add device: %d\n", error);
 		return error;
 	}
+
+	error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL, NULL, true);
+	if (error) {
+		/* we're treating error on bsg register as non-fatal,
+		 * so pretend nothing went wrong */
+		sdev_printk(KERN_INFO, sdev,
+			    "Failed to register bsg queue, errno=%d\n", error);
+		kobject_uevent(&sdev->sdev_gendev.kobj, KOBJ_ADD);
+	} else {
+		kobject_uevent(&sdev->sdev_gendev.kobj, KOBJ_ADD);
+		kobject_uevent(&rq->bsg_dev.class_dev->kobj, KOBJ_ADD);
+	}
+
 	device_enable_async_suspend(&sdev->sdev_dev);
 	error = device_add(&sdev->sdev_dev);
 	if (error) {
@@ -898,14 +917,6 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
 	if (error)
 		return error;
 
-	error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL, NULL);
-
-	if (error)
-		/* we're treating error on bsg register as non-fatal,
-		 * so pretend nothing went wrong */
-		sdev_printk(KERN_INFO, sdev,
-			    "Failed to register bsg queue, errno=%d\n", error);
-
 	/* add additional host specific attributes */
 	if (sdev->host->hostt->sdev_attrs) {
 		for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) {
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 998c01b..6066b9a7 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -4037,7 +4037,7 @@ fc_bsg_hostadd(struct Scsi_Host *shost, struct fc_host_attrs *fc_host)
 	blk_queue_rq_timed_out(q, fc_bsg_job_timeout);
 	blk_queue_rq_timeout(q, FC_DEFAULT_BSG_TIMEOUT);
 
-	err = bsg_register_queue(q, dev, bsg_name, NULL);
+	err = bsg_register_queue(q, dev, bsg_name, NULL, false);
 	if (err) {
 		printk(KERN_ERR "fc_host%d: bsg interface failed to "
 				"initialize - register queue\n",
@@ -4083,7 +4083,7 @@ fc_bsg_rportadd(struct Scsi_Host *shost, struct fc_rport *rport)
 	blk_queue_rq_timed_out(q, fc_bsg_job_timeout);
 	blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT);
 
-	err = bsg_register_queue(q, dev, NULL, NULL);
+	err = bsg_register_queue(q, dev, NULL, NULL, false);
 	if (err) {
 		printk(KERN_ERR "%s: bsg interface failed to "
 				"initialize - register queue\n",
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 927e99c..0da85fe 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -241,7 +241,7 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
 	if (!q)
 		return -ENOMEM;
 
-	error = bsg_register_queue(q, dev, name, release);
+	error = bsg_register_queue(q, dev, name, release, false);
 	if (error) {
 		blk_cleanup_queue(q);
 		return -ENOMEM;
diff --git a/include/linux/bsg.h b/include/linux/bsg.h
index ecb4730..999f3e9 100644
--- a/include/linux/bsg.h
+++ b/include/linux/bsg.h
@@ -75,12 +75,14 @@ struct bsg_class_device {
 
 extern int bsg_register_queue(struct request_queue *q,
 			      struct device *parent, const char *name,
-			      void (*release)(struct device *));
+			      void (*release)(struct device *),
+			      bool suppress_add_uevent);
 extern void bsg_unregister_queue(struct request_queue *);
 #else
 static inline int bsg_register_queue(struct request_queue *q,
 				     struct device *parent, const char *name,
-				     void (*release)(struct device *))
+				     void (*release)(struct device *),
+				     bool suppress_add_uevent)
 {
 	return 0;
 }
-- 
1.7.4.1


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux