diff options
author | Tejun Heo <tj@kernel.org> | 2008-09-03 02:57:12 -0400 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2008-10-09 02:56:04 -0400 |
commit | def4e38ddda9bef20b69bfa939195c2f79da7979 (patch) | |
tree | 51535a76dee0b21857d2c64da22a0406c0dc7357 | |
parent | 2ac3cee5298a247b2774f3319b28a05f588c3f0e (diff) |
block: use class_dev_iterator instead of class_for_each_device()
Recent block_class iteration updates 5c6f35c5..27f3025 converted all
class device iteration to class_for_each_device() and
class_find_device(), which are correct but pain in the ass to use.
This pach converts them to newly introduced class_dev_iterator so that
they can use more natural control structures instead of separate
callbacks and struct to pass parameters to them.
This results in smaller and easier code.
This patch also restores the original behavior of not printing header
in /proc/partitions if there's no partition to print. This is trivial
but still user-visible behavior.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
-rw-r--r-- | block/genhd.c | 252 |
1 files changed, 97 insertions, 155 deletions
diff --git a/block/genhd.c b/block/genhd.c index 9eb8b3e212c1..8b9a9ff1a842 100644 --- a/block/genhd.c +++ b/block/genhd.c | |||
@@ -226,117 +226,114 @@ struct gendisk *get_gendisk(dev_t devt, int *part) | |||
226 | } | 226 | } |
227 | 227 | ||
228 | /* | 228 | /* |
229 | * print a partitions - intended for places where the root filesystem can't be | ||
230 | * mounted and thus to give the victim some idea of what went wrong | ||
231 | */ | ||
232 | static int printk_partition(struct device *dev, void *data) | ||
233 | { | ||
234 | struct gendisk *sgp; | ||
235 | char buf[BDEVNAME_SIZE]; | ||
236 | int n; | ||
237 | |||
238 | if (dev->type != &disk_type) | ||
239 | return 0; | ||
240 | |||
241 | sgp = dev_to_disk(dev); | ||
242 | /* | ||
243 | * Don't show empty devices or things that have been surpressed | ||
244 | */ | ||
245 | if (get_capacity(sgp) == 0 || | ||
246 | (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO)) | ||
247 | return 0; | ||
248 | |||
249 | /* | ||
250 | * Note, unlike /proc/partitions, I am showing the numbers in | ||
251 | * hex - the same format as the root= option takes. | ||
252 | */ | ||
253 | printk("%02x%02x %10llu %s", | ||
254 | sgp->major, sgp->first_minor, | ||
255 | (unsigned long long)get_capacity(sgp) >> 1, | ||
256 | disk_name(sgp, 0, buf)); | ||
257 | if (sgp->driverfs_dev != NULL && | ||
258 | sgp->driverfs_dev->driver != NULL) | ||
259 | printk(" driver: %s\n", | ||
260 | sgp->driverfs_dev->driver->name); | ||
261 | else | ||
262 | printk(" (driver?)\n"); | ||
263 | |||
264 | /* now show the partitions */ | ||
265 | for (n = 0; n < sgp->minors - 1; ++n) { | ||
266 | if (sgp->part[n] == NULL) | ||
267 | continue; | ||
268 | if (sgp->part[n]->nr_sects == 0) | ||
269 | continue; | ||
270 | printk(" %02x%02x %10llu %s\n", | ||
271 | sgp->major, n + 1 + sgp->first_minor, | ||
272 | (unsigned long long)sgp->part[n]->nr_sects >> 1, | ||
273 | disk_name(sgp, n + 1, buf)); | ||
274 | } | ||
275 | |||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | /* | ||
280 | * print a full list of all partitions - intended for places where the root | 229 | * print a full list of all partitions - intended for places where the root |
281 | * filesystem can't be mounted and thus to give the victim some idea of what | 230 | * filesystem can't be mounted and thus to give the victim some idea of what |
282 | * went wrong | 231 | * went wrong |
283 | */ | 232 | */ |
284 | void __init printk_all_partitions(void) | 233 | void __init printk_all_partitions(void) |
285 | { | 234 | { |
286 | class_for_each_device(&block_class, NULL, NULL, printk_partition); | 235 | struct class_dev_iter iter; |
236 | struct device *dev; | ||
237 | |||
238 | class_dev_iter_init(&iter, &block_class, NULL, &disk_type); | ||
239 | while ((dev = class_dev_iter_next(&iter))) { | ||
240 | struct gendisk *disk = dev_to_disk(dev); | ||
241 | char buf[BDEVNAME_SIZE]; | ||
242 | int n; | ||
243 | |||
244 | /* | ||
245 | * Don't show empty devices or things that have been | ||
246 | * surpressed | ||
247 | */ | ||
248 | if (get_capacity(disk) == 0 || | ||
249 | (disk->flags & GENHD_FL_SUPPRESS_PARTITION_INFO)) | ||
250 | continue; | ||
251 | |||
252 | /* | ||
253 | * Note, unlike /proc/partitions, I am showing the | ||
254 | * numbers in hex - the same format as the root= | ||
255 | * option takes. | ||
256 | */ | ||
257 | printk("%02x%02x %10llu %s", | ||
258 | disk->major, disk->first_minor, | ||
259 | (unsigned long long)get_capacity(disk) >> 1, | ||
260 | disk_name(disk, 0, buf)); | ||
261 | if (disk->driverfs_dev != NULL && | ||
262 | disk->driverfs_dev->driver != NULL) | ||
263 | printk(" driver: %s\n", | ||
264 | disk->driverfs_dev->driver->name); | ||
265 | else | ||
266 | printk(" (driver?)\n"); | ||
267 | |||
268 | /* now show the partitions */ | ||
269 | for (n = 0; n < disk->minors - 1; ++n) { | ||
270 | if (disk->part[n] == NULL) | ||
271 | continue; | ||
272 | if (disk->part[n]->nr_sects == 0) | ||
273 | continue; | ||
274 | printk(" %02x%02x %10llu %s\n", | ||
275 | disk->major, n + 1 + disk->first_minor, | ||
276 | (unsigned long long)disk->part[n]->nr_sects >> 1, | ||
277 | disk_name(disk, n + 1, buf)); | ||
278 | } | ||
279 | } | ||
280 | class_dev_iter_exit(&iter); | ||
287 | } | 281 | } |
288 | 282 | ||
289 | #ifdef CONFIG_PROC_FS | 283 | #ifdef CONFIG_PROC_FS |
290 | /* iterator */ | 284 | /* iterator */ |
291 | static int find_start(struct device *dev, void *data) | 285 | static void *disk_seqf_start(struct seq_file *seqf, loff_t *pos) |
292 | { | 286 | { |
293 | loff_t *k = data; | 287 | loff_t skip = *pos; |
288 | struct class_dev_iter *iter; | ||
289 | struct device *dev; | ||
294 | 290 | ||
295 | if (dev->type != &disk_type) | 291 | iter = kmalloc(GFP_KERNEL, sizeof(*iter)); |
296 | return 0; | 292 | if (!iter) |
297 | if (!*k) | 293 | return ERR_PTR(-ENOMEM); |
298 | return 1; | 294 | |
299 | (*k)--; | 295 | seqf->private = iter; |
300 | return 0; | 296 | class_dev_iter_init(iter, &block_class, NULL, &disk_type); |
297 | do { | ||
298 | dev = class_dev_iter_next(iter); | ||
299 | if (!dev) | ||
300 | return NULL; | ||
301 | } while (skip--); | ||
302 | |||
303 | return dev_to_disk(dev); | ||
301 | } | 304 | } |
302 | 305 | ||
303 | static void *part_start(struct seq_file *part, loff_t *pos) | 306 | static void *disk_seqf_next(struct seq_file *seqf, void *v, loff_t *pos) |
304 | { | 307 | { |
305 | struct device *dev; | 308 | struct device *dev; |
306 | loff_t n = *pos; | ||
307 | |||
308 | if (!n) | ||
309 | part->private = (void *)1LU; /* tell show to print header */ | ||
310 | 309 | ||
311 | dev = class_find_device(&block_class, NULL, &n, find_start); | 310 | (*pos)++; |
311 | dev = class_dev_iter_next(seqf->private); | ||
312 | if (dev) | 312 | if (dev) |
313 | return dev_to_disk(dev); | 313 | return dev_to_disk(dev); |
314 | 314 | ||
315 | return NULL; | 315 | return NULL; |
316 | } | 316 | } |
317 | 317 | ||
318 | static int find_next(struct device *dev, void *data) | 318 | static void disk_seqf_stop(struct seq_file *seqf, void *v) |
319 | { | 319 | { |
320 | if (dev->type == &disk_type) | 320 | struct class_dev_iter *iter = seqf->private; |
321 | return 1; | ||
322 | return 0; | ||
323 | } | ||
324 | 321 | ||
325 | static void *part_next(struct seq_file *part, void *v, loff_t *pos) | 322 | /* stop is called even after start failed :-( */ |
326 | { | 323 | if (iter) { |
327 | struct gendisk *gp = v; | 324 | class_dev_iter_exit(iter); |
328 | struct device *dev; | 325 | kfree(iter); |
329 | ++*pos; | ||
330 | dev = class_find_device(&block_class, &gp->dev, NULL, find_next); | ||
331 | if (dev) { | ||
332 | put_device(dev); | ||
333 | return dev_to_disk(dev); | ||
334 | } | 326 | } |
335 | return NULL; | ||
336 | } | 327 | } |
337 | 328 | ||
338 | static void part_stop(struct seq_file *part, void *v) | 329 | static void *show_partition_start(struct seq_file *seqf, loff_t *pos) |
339 | { | 330 | { |
331 | static void *p; | ||
332 | |||
333 | p = disk_seqf_start(seqf, pos); | ||
334 | if (!IS_ERR(p) && p) | ||
335 | seq_puts(seqf, "major minor #blocks name\n\n"); | ||
336 | return p; | ||
340 | } | 337 | } |
341 | 338 | ||
342 | static int show_partition(struct seq_file *part, void *v) | 339 | static int show_partition(struct seq_file *part, void *v) |
@@ -383,9 +380,9 @@ static int show_partition(struct seq_file *part, void *v) | |||
383 | } | 380 | } |
384 | 381 | ||
385 | const struct seq_operations partitions_op = { | 382 | const struct seq_operations partitions_op = { |
386 | .start = part_start, | 383 | .start = show_partition_start, |
387 | .next = part_next, | 384 | .next = disk_seqf_next, |
388 | .stop = part_stop, | 385 | .stop = disk_seqf_stop, |
389 | .show = show_partition | 386 | .show = show_partition |
390 | }; | 387 | }; |
391 | #endif | 388 | #endif |
@@ -567,44 +564,6 @@ static struct device_type disk_type = { | |||
567 | }; | 564 | }; |
568 | 565 | ||
569 | #ifdef CONFIG_PROC_FS | 566 | #ifdef CONFIG_PROC_FS |
570 | /* | ||
571 | * aggregate disk stat collector. Uses the same stats that the sysfs | ||
572 | * entries do, above, but makes them available through one seq_file. | ||
573 | * | ||
574 | * The output looks suspiciously like /proc/partitions with a bunch of | ||
575 | * extra fields. | ||
576 | */ | ||
577 | |||
578 | static void *diskstats_start(struct seq_file *part, loff_t *pos) | ||
579 | { | ||
580 | struct device *dev; | ||
581 | loff_t n = *pos; | ||
582 | |||
583 | dev = class_find_device(&block_class, NULL, &n, find_start); | ||
584 | if (dev) | ||
585 | return dev_to_disk(dev); | ||
586 | |||
587 | return NULL; | ||
588 | } | ||
589 | |||
590 | static void *diskstats_next(struct seq_file *part, void *v, loff_t *pos) | ||
591 | { | ||
592 | struct gendisk *gp = v; | ||
593 | struct device *dev; | ||
594 | |||
595 | ++*pos; | ||
596 | dev = class_find_device(&block_class, &gp->dev, NULL, find_next); | ||
597 | if (dev) { | ||
598 | put_device(dev); | ||
599 | return dev_to_disk(dev); | ||
600 | } | ||
601 | return NULL; | ||
602 | } | ||
603 | |||
604 | static void diskstats_stop(struct seq_file *part, void *v) | ||
605 | { | ||
606 | } | ||
607 | |||
608 | static int diskstats_show(struct seq_file *s, void *v) | 567 | static int diskstats_show(struct seq_file *s, void *v) |
609 | { | 568 | { |
610 | struct gendisk *gp = v; | 569 | struct gendisk *gp = v; |
@@ -666,9 +625,9 @@ static int diskstats_show(struct seq_file *s, void *v) | |||
666 | } | 625 | } |
667 | 626 | ||
668 | const struct seq_operations diskstats_op = { | 627 | const struct seq_operations diskstats_op = { |
669 | .start = diskstats_start, | 628 | .start = disk_seqf_start, |
670 | .next = diskstats_next, | 629 | .next = disk_seqf_next, |
671 | .stop = diskstats_stop, | 630 | .stop = disk_seqf_stop, |
672 | .show = diskstats_show | 631 | .show = diskstats_show |
673 | }; | 632 | }; |
674 | #endif /* CONFIG_PROC_FS */ | 633 | #endif /* CONFIG_PROC_FS */ |
@@ -696,40 +655,23 @@ void genhd_media_change_notify(struct gendisk *disk) | |||
696 | EXPORT_SYMBOL_GPL(genhd_media_change_notify); | 655 | EXPORT_SYMBOL_GPL(genhd_media_change_notify); |
697 | #endif /* 0 */ | 656 | #endif /* 0 */ |
698 | 657 | ||
699 | struct find_block { | 658 | dev_t blk_lookup_devt(const char *name, int part) |
700 | const char *name; | ||
701 | int part; | ||
702 | }; | ||
703 | |||
704 | static int match_id(struct device *dev, void *data) | ||
705 | { | 659 | { |
706 | struct find_block *find = data; | 660 | dev_t devt = MKDEV(0, 0); |
661 | struct class_dev_iter iter; | ||
662 | struct device *dev; | ||
707 | 663 | ||
708 | if (dev->type != &disk_type) | 664 | class_dev_iter_init(&iter, &block_class, NULL, &disk_type); |
709 | return 0; | 665 | while ((dev = class_dev_iter_next(&iter))) { |
710 | if (strcmp(dev->bus_id, find->name) == 0) { | ||
711 | struct gendisk *disk = dev_to_disk(dev); | 666 | struct gendisk *disk = dev_to_disk(dev); |
712 | if (find->part < disk->minors) | ||
713 | return 1; | ||
714 | } | ||
715 | return 0; | ||
716 | } | ||
717 | 667 | ||
718 | dev_t blk_lookup_devt(const char *name, int part) | 668 | if (!strcmp(dev->bus_id, name) && part < disk->minors) { |
719 | { | 669 | devt = MKDEV(MAJOR(dev->devt), |
720 | struct device *dev; | 670 | MINOR(dev->devt) + part); |
721 | dev_t devt = MKDEV(0, 0); | 671 | break; |
722 | struct find_block find; | 672 | } |
723 | |||
724 | find.name = name; | ||
725 | find.part = part; | ||
726 | dev = class_find_device(&block_class, NULL, &find, match_id); | ||
727 | if (dev) { | ||
728 | put_device(dev); | ||
729 | devt = MKDEV(MAJOR(dev->devt), | ||
730 | MINOR(dev->devt) + part); | ||
731 | } | 673 | } |
732 | 674 | class_dev_iter_exit(&iter); | |
733 | return devt; | 675 | return devt; |
734 | } | 676 | } |
735 | EXPORT_SYMBOL(blk_lookup_devt); | 677 | EXPORT_SYMBOL(blk_lookup_devt); |