diff options
Diffstat (limited to 'block')
-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); |