[dm-devel] patch to enable creating device attributes before exporting hotpl ug/uevent for device kobject
goggin, edward
egoggin at emc.com
Thu Nov 10 20:08:53 UTC 2005
In order to guarantee visibility through Sysfs of device attributes for
uevent/hotplug handlers, I've changed drivers/base/core.c:device_add
from calling kobject_register() before adding attributes to the device
kobject to instead
(1) call kobject_add(),
(2) add the device attributes to the device kobject, and
(3) call kobject_hotplug() to export the kobject ONLY AFTER the
attributes
are added to the device object.
Also, changed scsi_sysfs_add_sdev() to follow this new sequence for creating
scsi device objects.
--- ../base/linux-2.6.14-rc4/include/linux/device.h 2005-10-10
20:19:19.000000000 -0500
+++ include/linux/device.h 2005-10-24 05:48:11.000000000 -0500
@@ -330,6 +330,10 @@ extern void device_unregister(struct dev
extern void device_initialize(struct device * dev);
extern int device_add(struct device * dev);
extern void device_del(struct device * dev);
+extern int device_add_without_export(struct device * dev);
+extern void device_del_without_unexport(struct device * dev);
+extern int device_export(struct device * dev);
+extern void device_unexport(struct device * dev);
extern int device_for_each_child(struct device *, void *,
int (*fn)(struct device *, void *));
--- ../base/linux-2.6.14-rc4/drivers/base/core.c 2005-10-10
20:19:19.000000000 -0500
+++ drivers/base/core.c 2005-10-24 06:29:04.000000000 -0500
@@ -212,7 +212,7 @@ static void klist_children_put(struct kl
*
* This prepares the device for use by other layers,
* including adding it to the device hierarchy.
- * It is the first half of device_register(), if called by
+ * It is the first of 3 parts of device_register(), if called by
* that, though it can also be called separately, so one
* may use @dev's fields (e.g. the refcount).
*/
@@ -228,17 +228,20 @@ void device_initialize(struct device *de
}
/**
- * device_add - add device to device hierarchy.
+ * device_add_without_export - add device to device hierarchy.
* @dev: device.
*
- * This is part 2 of device_register(), though may be called
- * separately _iff_ device_initialize() has been called separately.
+ * This is a sub-part of device_add() which along with device_export(),
+ * should be called separately if one must associate device attributes
+ * with a device between the two calls.
*
- * This adds it to the kobject hierarchy via kobject_add(), adds it
- * to the global and sibling lists for the device, then
- * adds it to the other relevant subsystems of the driver model.
+ * This adds it to the kobject hierarchy via kobject_add() and adds it
+ * to the global and sibling lists for the device.
+ *
+ * device_export() will add it to the other relevant subsystems of
+ * the driver model.
*/
-int device_add(struct device *dev)
+int device_add_without_export(struct device *dev)
{
struct device *parent = NULL;
int error = -EINVAL;
@@ -256,33 +259,92 @@ int device_add(struct device *dev)
if (parent)
dev->kobj.parent = &parent->kobj;
- if ((error = kobject_add(&dev->kobj)))
- goto Error;
+ error = kobject_add(&dev->kobj);
+
+ if (error && parent)
+ put_device(parent);
+
+ Error:
+ put_device(dev);
+
+ return error;
+}
+
+/**
+ * device_export - export device to device hierarchy.
+ * @dev: device.
+ *
+ * This is a sub-part of device_add() which along with
+ * device_add_without_export(), should be called separately
+ * if one must associate device attributes with a device
+ * between the two calls.
+ *
+ * This adds the device to the relevant subsystems of the driver model.
+ */
+int device_export(struct device *dev)
+{
+ struct device * parent = dev->parent;
+ int error = -EINVAL;
+
+ dev = get_device(dev);
+ if (!dev || !strlen(dev->bus_id))
+ goto Done;
+
+ if (parent)
+ klist_add_tail(&dev->knode_parent, &parent->klist_children);
+
kobject_hotplug(&dev->kobj, KOBJ_ADD);
+
if ((error = device_pm_add(dev)))
goto PMError;
+
if ((error = bus_add_device(dev)))
goto BusError;
- if (parent)
- klist_add_tail(&dev->knode_parent, &parent->klist_children);
/* notify platform of device entry */
if (platform_notify)
platform_notify(dev);
+
Done:
put_device(dev);
return error;
+
BusError:
device_pm_remove(dev);
+
PMError:
+ klist_del(&dev->knode_parent);
kobject_hotplug(&dev->kobj, KOBJ_REMOVE);
- kobject_del(&dev->kobj);
- Error:
- if (parent)
- put_device(parent);
+
goto Done;
}
+/**
+ * device_add - add device to device hierarchy.
+ * @dev: device.
+ *
+ * This is part 2 of device_register(), though may be called
+ * separately _iff_ device_initialize() has been called separately.
+ *
+ * This adds it to the kobject hierarchy via kobject_add(), adds it
+ * to the global and sibling lists for the device, then
+ * adds it to the other relevant subsystems of the driver model.
+ */
+int device_add(struct device *dev)
+{
+ struct device * parent = dev->parent;
+ int error;
+
+ error = device_add_without_export(dev);
+ if (error == 0)
+ error = device_export(dev);
+ else {
+ kobject_del(&dev->kobj);
+ put_device(parent);
+ }
+
+ return error;
+}
/**
* device_register - register a device with the system.
@@ -328,22 +390,19 @@ void put_device(struct device * dev)
kobject_put(&dev->kobj);
}
-
/**
- * device_del - delete device from system.
+ * device_unexport - remove device from relevant subsystems.
* @dev: device.
*
* This is the first part of the device unregistration
- * sequence. This removes the device from the lists we control
- * from here, has it removed from the other driver model
- * subsystems it was added to in device_add(), and removes it
- * from the kobject hierarchy.
+ * sequence. This removes the device from the subsystems it
+ * was added to in device_export().
*
- * NOTE: this should be called manually _iff_ device_add() was
+ * NOTE: this should be called manually _iff_ device_export() was
* also called manually.
*/
-void device_del(struct device * dev)
+void device_unexport(struct device * dev)
{
struct device * parent = dev->parent;
@@ -358,12 +417,53 @@ void device_del(struct device * dev)
bus_remove_device(dev);
device_pm_remove(dev);
kobject_hotplug(&dev->kobj, KOBJ_REMOVE);
+}
+
+
+/**
+ * device_del_without_unexport - delete device from system.
+ * @dev: device.
+ *
+ * This is sub-part of the first part of the device unregistration
+ * sequence. This removes the device from the lists we control
+ * from here, has it removed from the other driver model
+ * subsystems it was added to in device_add(), and removes it
+ * from the kobject hierarchy.
+ *
+ * NOTE: this should be called manually _iff_ device_add() was
+ * also called manually.
+ */
+
+void device_del_without_unexport(struct device * dev)
+{
+ struct device * parent = dev->parent;
+
kobject_del(&dev->kobj);
if (parent)
put_device(parent);
}
/**
+ * device_del - delete device from system.
+ * @dev: device.
+ *
+ * This is the first part of the device unregistration
+ * sequence. This removes the device from the lists we control
+ * from here, has it removed from the other driver model
+ * subsystems it was added to in device_add(), and removes it
+ * from the kobject hierarchy.
+ *
+ * NOTE: this should be called manually _iff_ device_add() was
+ * also called manually.
+ */
+
+void device_del(struct device * dev)
+{
+ device_unexport(dev);
+ device_del_without_unexport(dev);
+}
+
+/**
* device_unregister - unregister device from system.
* @dev: device going away.
*
@@ -424,9 +524,13 @@ EXPORT_SYMBOL_GPL(device_for_each_child)
EXPORT_SYMBOL_GPL(device_initialize);
EXPORT_SYMBOL_GPL(device_add);
EXPORT_SYMBOL_GPL(device_register);
+EXPORT_SYMBOL_GPL(device_add_without_export);
+EXPORT_SYMBOL_GPL(device_export);
EXPORT_SYMBOL_GPL(device_del);
EXPORT_SYMBOL_GPL(device_unregister);
+EXPORT_SYMBOL_GPL(device_del_without_unexport);
+EXPORT_SYMBOL_GPL(device_unexport);
EXPORT_SYMBOL_GPL(get_device);
EXPORT_SYMBOL_GPL(put_device);
--- ../base/linux-2.6.14-rc4/drivers/scsi/scsi_sysfs.c 2005-10-10
20:19:19.000000000 -0500
+++ drivers/scsi/scsi_sysfs.c 2005-10-24 06:31:55.000000000 -0500
@@ -621,6 +621,20 @@ static int attr_add(struct device *dev,
return device_create_file(dev, attr);
}
+void __scsi_remove_device_without_unexport(struct scsi_device *sdev)
+{
+ if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0)
+ return;
+
+ class_device_unregister(&sdev->sdev_classdev);
+ device_del_without_unexport(&sdev->sdev_gendev);
+ scsi_device_set_state(sdev, SDEV_DEL);
+ if (sdev->host->hostt->slave_destroy)
+ sdev->host->hostt->slave_destroy(sdev);
+ transport_unregister_device(&sdev->sdev_gendev);
+ put_device(&sdev->sdev_gendev);
+}
+
/**
* scsi_sysfs_add_sdev - add scsi device to sysfs
* @sdev: scsi_device to add
@@ -635,9 +649,8 @@ int scsi_sysfs_add_sdev(struct scsi_devi
if ((error = scsi_device_set_state(sdev, SDEV_RUNNING)) != 0)
return error;
- error = device_add(&sdev->sdev_gendev);
+ error = device_add_without_export(&sdev->sdev_gendev);
if (error) {
- put_device(sdev->sdev_gendev.parent);
printk(KERN_INFO "error 1\n");
return error;
}
@@ -655,7 +668,7 @@ int scsi_sysfs_add_sdev(struct scsi_devi
error = attr_add(&sdev->sdev_gendev,
sdev->host->hostt->sdev_attrs[i]);
if (error) {
- __scsi_remove_device(sdev);
+ __scsi_remove_device_without_unexport(sdev);
goto out;
}
}
@@ -669,20 +682,27 @@ int scsi_sysfs_add_sdev(struct scsi_devi
scsi_sysfs_sdev_attrs[i]);
error = device_create_file(&sdev->sdev_gendev,
attr);
if (error) {
- __scsi_remove_device(sdev);
+ __scsi_remove_device_without_unexport(sdev);
goto out;
}
}
}
+ error = device_export(&sdev->sdev_gendev);
+ if (error) {
+ __scsi_remove_device_without_unexport(sdev);
+ goto out;
+ }
+
transport_add_device(&sdev->sdev_gendev);
+
out:
return error;
clean_device:
scsi_device_set_state(sdev, SDEV_CANCEL);
- device_del(&sdev->sdev_gendev);
+ device_del_without_unexport(&sdev->sdev_gendev);
transport_destroy_device(&sdev->sdev_gendev);
put_device(&sdev->sdev_gendev);
More information about the dm-devel
mailing list