sysfs: add /sys/dev/{char,block} to lookup sysfs path by major:minor
Why?: There are occasions where userspace would like to access sysfs attributes for a device but it may not know how sysfs has named the device or the path. For example what is the sysfs path for /dev/disk/by-id/ata-ST3160827AS_5MT004CK? With this change a call to stat(2) returns the major:minor then userspace can see that /sys/dev/block/8:32 links to /sys/block/sdc. What are the alternatives?: 1/ Add an ioctl to return the path: Doable, but sysfs is meant to reduce the need to proliferate ioctl interfaces into the kernel, so this seems counter productive. 2/ Use udev to create these symlinks: Also doable, but it adds a udev dependency to utilities that might be running in a limited environment like an initramfs. 3/ Do a full-tree search of sysfs. [kay.sievers@vrfy.org: fix duplicate registrations] [kay.sievers@vrfy.org: cleanup suggestions] Cc: Neil Brown <neilb@suse.de> Cc: Tejun Heo <htejun@gmail.com> Acked-by: Kay Sievers <kay.sievers@vrfy.org> Reviewed-by: SL Baur <steve@xemacs.org> Acked-by: Kay Sievers <kay.sievers@vrfy.org> Acked-by: Mark Lord <lkml@rtr.ca> Acked-by: H. Peter Anvin <hpa@zytor.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
93ded9b8fd
commit
e105b8bfc7
@@ -27,6 +27,9 @@
|
||||
|
||||
int (*platform_notify)(struct device *dev) = NULL;
|
||||
int (*platform_notify_remove)(struct device *dev) = NULL;
|
||||
static struct kobject *dev_kobj;
|
||||
struct kobject *sysfs_dev_char_kobj;
|
||||
struct kobject *sysfs_dev_block_kobj;
|
||||
|
||||
#ifdef CONFIG_BLOCK
|
||||
static inline int device_is_not_partition(struct device *dev)
|
||||
@@ -775,6 +778,54 @@ int dev_set_name(struct device *dev, const char *fmt, ...)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_set_name);
|
||||
|
||||
/**
|
||||
* device_to_dev_kobj - select a /sys/dev/ directory for the device
|
||||
* @dev: device
|
||||
*
|
||||
* By default we select char/ for new entries. Setting class->dev_obj
|
||||
* to NULL prevents an entry from being created. class->dev_kobj must
|
||||
* be set (or cleared) before any devices are registered to the class
|
||||
* otherwise device_create_sys_dev_entry() and
|
||||
* device_remove_sys_dev_entry() will disagree about the the presence
|
||||
* of the link.
|
||||
*/
|
||||
static struct kobject *device_to_dev_kobj(struct device *dev)
|
||||
{
|
||||
struct kobject *kobj;
|
||||
|
||||
if (dev->class)
|
||||
kobj = dev->class->dev_kobj;
|
||||
else
|
||||
kobj = sysfs_dev_char_kobj;
|
||||
|
||||
return kobj;
|
||||
}
|
||||
|
||||
static int device_create_sys_dev_entry(struct device *dev)
|
||||
{
|
||||
struct kobject *kobj = device_to_dev_kobj(dev);
|
||||
int error = 0;
|
||||
char devt_str[15];
|
||||
|
||||
if (kobj) {
|
||||
format_dev_t(devt_str, dev->devt);
|
||||
error = sysfs_create_link(kobj, &dev->kobj, devt_str);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static void device_remove_sys_dev_entry(struct device *dev)
|
||||
{
|
||||
struct kobject *kobj = device_to_dev_kobj(dev);
|
||||
char devt_str[15];
|
||||
|
||||
if (kobj) {
|
||||
format_dev_t(devt_str, dev->devt);
|
||||
sysfs_remove_link(kobj, devt_str);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* device_add - add device to device hierarchy.
|
||||
* @dev: device.
|
||||
@@ -829,6 +880,10 @@ int device_add(struct device *dev)
|
||||
error = device_create_file(dev, &devt_attr);
|
||||
if (error)
|
||||
goto ueventattrError;
|
||||
|
||||
error = device_create_sys_dev_entry(dev);
|
||||
if (error)
|
||||
goto devtattrError;
|
||||
}
|
||||
|
||||
error = device_add_class_symlinks(dev);
|
||||
@@ -872,6 +927,9 @@ int device_add(struct device *dev)
|
||||
AttrsError:
|
||||
device_remove_class_symlinks(dev);
|
||||
SymlinkError:
|
||||
if (MAJOR(dev->devt))
|
||||
device_remove_sys_dev_entry(dev);
|
||||
devtattrError:
|
||||
if (MAJOR(dev->devt))
|
||||
device_remove_file(dev, &devt_attr);
|
||||
ueventattrError:
|
||||
@@ -948,8 +1006,10 @@ void device_del(struct device *dev)
|
||||
device_pm_remove(dev);
|
||||
if (parent)
|
||||
klist_del(&dev->knode_parent);
|
||||
if (MAJOR(dev->devt))
|
||||
if (MAJOR(dev->devt)) {
|
||||
device_remove_sys_dev_entry(dev);
|
||||
device_remove_file(dev, &devt_attr);
|
||||
}
|
||||
if (dev->class) {
|
||||
device_remove_class_symlinks(dev);
|
||||
|
||||
@@ -1074,7 +1134,25 @@ int __init devices_init(void)
|
||||
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
|
||||
if (!devices_kset)
|
||||
return -ENOMEM;
|
||||
dev_kobj = kobject_create_and_add("dev", NULL);
|
||||
if (!dev_kobj)
|
||||
goto dev_kobj_err;
|
||||
sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
|
||||
if (!sysfs_dev_block_kobj)
|
||||
goto block_kobj_err;
|
||||
sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
|
||||
if (!sysfs_dev_char_kobj)
|
||||
goto char_kobj_err;
|
||||
|
||||
return 0;
|
||||
|
||||
char_kobj_err:
|
||||
kobject_put(sysfs_dev_block_kobj);
|
||||
block_kobj_err:
|
||||
kobject_put(dev_kobj);
|
||||
dev_kobj_err:
|
||||
kset_unregister(devices_kset);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(device_for_each_child);
|
||||
@@ -1447,4 +1525,7 @@ void device_shutdown(void)
|
||||
dev->driver->shutdown(dev);
|
||||
}
|
||||
}
|
||||
kobject_put(sysfs_dev_char_kobj);
|
||||
kobject_put(sysfs_dev_block_kobj);
|
||||
kobject_put(dev_kobj);
|
||||
}
|
||||
|
Reference in New Issue
Block a user