aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--block/genhd.c252
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 */
232static 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 */
284void __init printk_all_partitions(void) 233void __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 */
291static int find_start(struct device *dev, void *data) 285static 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
303static void *part_start(struct seq_file *part, loff_t *pos) 306static 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
318static int find_next(struct device *dev, void *data) 318static 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
325static 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
338static void part_stop(struct seq_file *part, void *v) 329static 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
342static int show_partition(struct seq_file *part, void *v) 339static 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
385const struct seq_operations partitions_op = { 382const 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
578static 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
590static 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
604static void diskstats_stop(struct seq_file *part, void *v)
605{
606}
607
608static int diskstats_show(struct seq_file *s, void *v) 567static 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
668const struct seq_operations diskstats_op = { 627const 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)
696EXPORT_SYMBOL_GPL(genhd_media_change_notify); 655EXPORT_SYMBOL_GPL(genhd_media_change_notify);
697#endif /* 0 */ 656#endif /* 0 */
698 657
699struct find_block { 658dev_t blk_lookup_devt(const char *name, int part)
700 const char *name;
701 int part;
702};
703
704static 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
718dev_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}
735EXPORT_SYMBOL(blk_lookup_devt); 677EXPORT_SYMBOL(blk_lookup_devt);