From e105b8bfc769b0545b6f0f395179d1e43cbee822 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 21 Apr 2008 10:51:07 -0700 Subject: 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 Cc: Tejun Heo Acked-by: Kay Sievers Reviewed-by: SL Baur Acked-by: Kay Sievers Acked-by: Mark Lord Acked-by: H. Peter Anvin Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- block/genhd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'block/genhd.c') diff --git a/block/genhd.c b/block/genhd.c index 9074f384b097..24e3fc9095fe 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -370,7 +370,10 @@ static struct kobject *base_probe(dev_t devt, int *part, void *data) static int __init genhd_device_init(void) { - int error = class_register(&block_class); + int error; + + block_class.dev_kobj = sysfs_dev_block_kobj; + error = class_register(&block_class); if (unlikely(error)) return error; bdev_map = kobj_map_init(base_probe, &block_class_lock); -- cgit v1.2.3 From 6ffeea77ff014f1456fcd0564eac84b34e9535ca Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 22 May 2008 17:21:08 -0400 Subject: block: fix compiler warning in genhd.c Warn if something really bad happens if we can't create this link. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- block/genhd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'block/genhd.c') diff --git a/block/genhd.c b/block/genhd.c index 24e3fc9095fe..3ccf5c017565 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -183,6 +183,7 @@ static int exact_lock(dev_t devt, void *data) void add_disk(struct gendisk *disk) { struct backing_dev_info *bdi; + int retval; disk->flags |= GENHD_FL_UP; blk_register_region(MKDEV(disk->major, disk->first_minor), @@ -193,7 +194,8 @@ void add_disk(struct gendisk *disk) bdi = &disk->queue->backing_dev_info; bdi_register_dev(bdi, MKDEV(disk->major, disk->first_minor)); - sysfs_create_link(&disk->dev.kobj, &bdi->dev->kobj, "bdi"); + retval = sysfs_create_link(&disk->dev.kobj, &bdi->dev->kobj, "bdi"); + WARN_ON(retval); } EXPORT_SYMBOL(add_disk); -- cgit v1.2.3 From 5c6f35c5ece8f130cd8ec9ba0d71dc146b46a0f1 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 22 May 2008 17:21:08 -0400 Subject: block: make printk_partition use the class iterator function Use the proper class iterator function instead of mucking around in the internals of the class structures. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- block/genhd.c | 93 ++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 50 insertions(+), 43 deletions(-) (limited to 'block/genhd.c') diff --git a/block/genhd.c b/block/genhd.c index 3ccf5c017565..10b9ac46c2da 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -227,58 +227,65 @@ struct gendisk *get_gendisk(dev_t devt, int *part) } /* - * print a full list of all partitions - intended for places where the root - * filesystem can't be mounted and thus to give the victim some idea of what - * went wrong + * print a partitions - intended for places where the root filesystem can't be + * mounted and thus to give the victim some idea of what went wrong */ -void __init printk_all_partitions(void) +static int printk_partition(struct device *dev, void *data) { - struct device *dev; struct gendisk *sgp; char buf[BDEVNAME_SIZE]; int n; - mutex_lock(&block_class_lock); - /* For each block device... */ - list_for_each_entry(dev, &block_class.devices, node) { - if (dev->type != &disk_type) - continue; - sgp = dev_to_disk(dev); - /* - * Don't show empty devices or things that have been surpressed - */ - if (get_capacity(sgp) == 0 || - (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO)) - continue; + if (dev->type != &disk_type) + goto exit; - /* - * Note, unlike /proc/partitions, I am showing the numbers in - * hex - the same format as the root= option takes. - */ - printk("%02x%02x %10llu %s", - sgp->major, sgp->first_minor, - (unsigned long long)get_capacity(sgp) >> 1, - disk_name(sgp, 0, buf)); - if (sgp->driverfs_dev != NULL && - sgp->driverfs_dev->driver != NULL) - printk(" driver: %s\n", - sgp->driverfs_dev->driver->name); - else - printk(" (driver?)\n"); - - /* now show the partitions */ - for (n = 0; n < sgp->minors - 1; ++n) { - if (sgp->part[n] == NULL) - continue; - if (sgp->part[n]->nr_sects == 0) - continue; - printk(" %02x%02x %10llu %s\n", - sgp->major, n + 1 + sgp->first_minor, - (unsigned long long)sgp->part[n]->nr_sects >> 1, - disk_name(sgp, n + 1, buf)); - } + sgp = dev_to_disk(dev); + /* + * Don't show empty devices or things that have been surpressed + */ + if (get_capacity(sgp) == 0 || + (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO)) + goto exit; + + /* + * Note, unlike /proc/partitions, I am showing the numbers in + * hex - the same format as the root= option takes. + */ + printk("%02x%02x %10llu %s", + sgp->major, sgp->first_minor, + (unsigned long long)get_capacity(sgp) >> 1, + disk_name(sgp, 0, buf)); + if (sgp->driverfs_dev != NULL && + sgp->driverfs_dev->driver != NULL) + printk(" driver: %s\n", + sgp->driverfs_dev->driver->name); + else + printk(" (driver?)\n"); + + /* now show the partitions */ + for (n = 0; n < sgp->minors - 1; ++n) { + if (sgp->part[n] == NULL) + goto exit; + if (sgp->part[n]->nr_sects == 0) + goto exit; + printk(" %02x%02x %10llu %s\n", + sgp->major, n + 1 + sgp->first_minor, + (unsigned long long)sgp->part[n]->nr_sects >> 1, + disk_name(sgp, n + 1, buf)); } +exit: + return 0; +} +/* + * print a full list of all partitions - intended for places where the root + * filesystem can't be mounted and thus to give the victim some idea of what + * went wrong + */ +void __init printk_all_partitions(void) +{ + mutex_lock(&block_class_lock); + class_for_each_device(&block_class, NULL, NULL, printk_partition); mutex_unlock(&block_class_lock); } -- cgit v1.2.3 From a142be856f060ae8106512c0e81a8d6f8746ab0b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 22 May 2008 17:21:08 -0400 Subject: block: make blk_lookup_devt use the class iterator function Use the proper class iterator function instead of mucking around in the internals of the class structures. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- block/genhd.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) (limited to 'block/genhd.c') diff --git a/block/genhd.c b/block/genhd.c index 10b9ac46c2da..e8c42bfd12be 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -677,24 +677,38 @@ void genhd_media_change_notify(struct gendisk *disk) EXPORT_SYMBOL_GPL(genhd_media_change_notify); #endif /* 0 */ +struct find_block { + const char *name; + int part; +}; + +static int match_id(struct device *dev, void *data) +{ + struct find_block *find = data; + + if (dev->type != &disk_type) + return 0; + if (strcmp(dev->bus_id, find->name) == 0) { + struct gendisk *disk = dev_to_disk(dev); + if (find->part < disk->minors) + return 1; + } + return 0; +} + dev_t blk_lookup_devt(const char *name, int part) { struct device *dev; dev_t devt = MKDEV(0, 0); + struct find_block find; mutex_lock(&block_class_lock); - list_for_each_entry(dev, &block_class.devices, node) { - if (dev->type != &disk_type) - continue; - if (strcmp(dev->bus_id, name) == 0) { - struct gendisk *disk = dev_to_disk(dev); - - if (part < disk->minors) - devt = MKDEV(MAJOR(dev->devt), - MINOR(dev->devt) + part); - break; - } - } + find.name = name; + find.part = part; + dev = class_find_device(&block_class, NULL, (void *)&find, match_id); + if (dev) + devt = MKDEV(MAJOR(dev->devt), + MINOR(dev->devt) + part); mutex_unlock(&block_class_lock); return devt; -- cgit v1.2.3 From a6e2ba88774bc5870ab3d9664cb86d70415f7402 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 23 May 2008 09:44:11 -0700 Subject: block: make /proc/diskstats only build if CONFIG_PROC_FS is enabled These functions are only needed if CONFIG_PROC_FS is enabled, so save the space when it is not. This also makes it easier for a patch later in this series to work properly if CONFIG_PROC_FS is not enabled. Signed-off-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- block/genhd.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'block/genhd.c') diff --git a/block/genhd.c b/block/genhd.c index e8c42bfd12be..68a5f28007e4 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -544,6 +544,7 @@ static struct device_type disk_type = { .release = disk_release, }; +#ifdef CONFIG_PROC_FS /* * aggregate disk stat collector. Uses the same stats that the sysfs * entries do, above, but makes them available through one seq_file. @@ -653,6 +654,7 @@ const struct seq_operations diskstats_op = { .stop = diskstats_stop, .show = diskstats_show }; +#endif /* CONFIG_PROC_FS */ static void media_change_notify_thread(struct work_struct *work) { -- cgit v1.2.3 From 68c4d4a7875c59f2e4b72901ab11ba978e75bde0 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 22 May 2008 17:21:08 -0400 Subject: block: make proc files seq_start use the class_find_device() Use the proper class iterator function instead of mucking around in the internals of the class structures. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- block/genhd.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'block/genhd.c') diff --git a/block/genhd.c b/block/genhd.c index 68a5f28007e4..f03bdadc52ac 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -291,18 +291,25 @@ void __init printk_all_partitions(void) #ifdef CONFIG_PROC_FS /* iterator */ +static int find_start(struct device *dev, void *data) +{ + loff_t k = *(loff_t *)data; + + if (dev->type != &disk_type) + return 0; + if (!k--) + return 1; + return 0; +} + static void *part_start(struct seq_file *part, loff_t *pos) { - loff_t k = *pos; struct device *dev; mutex_lock(&block_class_lock); - list_for_each_entry(dev, &block_class.devices, node) { - if (dev->type != &disk_type) - continue; - if (!k--) - return dev_to_disk(dev); - } + dev = class_find_device(&block_class, NULL, (void *)pos, find_start); + if (dev) + return dev_to_disk(dev); return NULL; } @@ -555,16 +562,12 @@ static struct device_type disk_type = { static void *diskstats_start(struct seq_file *part, loff_t *pos) { - loff_t k = *pos; struct device *dev; mutex_lock(&block_class_lock); - list_for_each_entry(dev, &block_class.devices, node) { - if (dev->type != &disk_type) - continue; - if (!k--) - return dev_to_disk(dev); - } + dev = class_find_device(&block_class, NULL, (void *)pos, find_start); + if (dev) + return dev_to_disk(dev); return NULL; } -- cgit v1.2.3 From 66c64afec16a7b46212ecb2fa99998923bbeea3f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 22 May 2008 17:21:08 -0400 Subject: block: move header for /proc/partitions to seq_start The seq_start call is the better place for the header for the file, that way we don't have to be mucking in the class structure to try to figure out if this is the first partition or not. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- block/genhd.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'block/genhd.c') diff --git a/block/genhd.c b/block/genhd.c index f03bdadc52ac..70f1d7075783 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -305,6 +305,10 @@ static int find_start(struct device *dev, void *data) static void *part_start(struct seq_file *part, loff_t *pos) { struct device *dev; + loff_t n = *pos; + + if (!n) + seq_puts(part, "major minor #blocks name\n\n"); mutex_lock(&block_class_lock); dev = class_find_device(&block_class, NULL, (void *)pos, find_start); @@ -338,9 +342,6 @@ static int show_partition(struct seq_file *part, void *v) int n; char buf[BDEVNAME_SIZE]; - if (&sgp->dev.node == block_class.devices.next) - seq_puts(part, "major minor #blocks name\n\n"); - /* Don't show non-partitionable removeable devices or empty devices */ if (!get_capacity(sgp) || (sgp->minors == 1 && (sgp->flags & GENHD_FL_REMOVABLE))) -- cgit v1.2.3 From 27f302519148f311307637d4c9a6d0fd87d07e4c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 22 May 2008 17:21:08 -0400 Subject: block: make /proc/partitions and /proc/diskstats use class_find_device() Use the proper class iterator function instead of mucking around in the internals of the class structures. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- block/genhd.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'block/genhd.c') diff --git a/block/genhd.c b/block/genhd.c index 70f1d7075783..c13cc77291af 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -317,17 +317,21 @@ static void *part_start(struct seq_file *part, loff_t *pos) return NULL; } +static int find_next(struct device *dev, void *data) +{ + if (dev->type == &disk_type) + return 1; + return 0; +} + static void *part_next(struct seq_file *part, void *v, loff_t *pos) { struct gendisk *gp = v; struct device *dev; ++*pos; - list_for_each_entry(dev, &gp->dev.node, node) { - if (&dev->node == &block_class.devices) - return NULL; - if (dev->type == &disk_type) - return dev_to_disk(dev); - } + dev = class_find_device(&block_class, &gp->dev, NULL, find_next); + if (dev) + return dev_to_disk(dev); return NULL; } @@ -578,12 +582,9 @@ static void *diskstats_next(struct seq_file *part, void *v, loff_t *pos) struct device *dev; ++*pos; - list_for_each_entry(dev, &gp->dev.node, node) { - if (&dev->node == &block_class.devices) - return NULL; - if (dev->type == &disk_type) - return dev_to_disk(dev); - } + dev = class_find_device(&block_class, &gp->dev, NULL, find_next); + if (dev) + return dev_to_disk(dev); return NULL; } -- cgit v1.2.3