aboutsummaryrefslogtreecommitdiffstats
path: root/block/genhd.c
diff options
context:
space:
mode:
Diffstat (limited to 'block/genhd.c')
-rw-r--r--block/genhd.c217
1 files changed, 131 insertions, 86 deletions
diff --git a/block/genhd.c b/block/genhd.c
index b922d4801c87..c13cc77291af 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -183,16 +183,19 @@ static int exact_lock(dev_t devt, void *data)
183void add_disk(struct gendisk *disk) 183void add_disk(struct gendisk *disk)
184{ 184{
185 struct backing_dev_info *bdi; 185 struct backing_dev_info *bdi;
186 int retval;
186 187
187 disk->flags |= GENHD_FL_UP; 188 disk->flags |= GENHD_FL_UP;
188 blk_register_region(MKDEV(disk->major, disk->first_minor), 189 blk_register_region(MKDEV(disk->major, disk->first_minor),
189 disk->minors, NULL, exact_match, exact_lock, disk); 190 disk->minors, NULL, exact_match, exact_lock, disk);
190 register_disk(disk); 191 register_disk(disk);
191 blk_register_queue(disk); 192 blk_register_queue(disk);
193 blk_register_filter(disk);
192 194
193 bdi = &disk->queue->backing_dev_info; 195 bdi = &disk->queue->backing_dev_info;
194 bdi_register_dev(bdi, MKDEV(disk->major, disk->first_minor)); 196 bdi_register_dev(bdi, MKDEV(disk->major, disk->first_minor));
195 sysfs_create_link(&disk->dev.kobj, &bdi->dev->kobj, "bdi"); 197 retval = sysfs_create_link(&disk->dev.kobj, &bdi->dev->kobj, "bdi");
198 WARN_ON(retval);
196} 199}
197 200
198EXPORT_SYMBOL(add_disk); 201EXPORT_SYMBOL(add_disk);
@@ -200,6 +203,7 @@ EXPORT_SYMBOL(del_gendisk); /* in partitions/check.c */
200 203
201void unlink_gendisk(struct gendisk *disk) 204void unlink_gendisk(struct gendisk *disk)
202{ 205{
206 blk_unregister_filter(disk);
203 sysfs_remove_link(&disk->dev.kobj, "bdi"); 207 sysfs_remove_link(&disk->dev.kobj, "bdi");
204 bdi_unregister(&disk->queue->backing_dev_info); 208 bdi_unregister(&disk->queue->backing_dev_info);
205 blk_unregister_queue(disk); 209 blk_unregister_queue(disk);
@@ -223,89 +227,111 @@ struct gendisk *get_gendisk(dev_t devt, int *part)
223} 227}
224 228
225/* 229/*
226 * print a full list of all partitions - intended for places where the root 230 * print a partitions - intended for places where the root filesystem can't be
227 * filesystem can't be mounted and thus to give the victim some idea of what 231 * mounted and thus to give the victim some idea of what went wrong
228 * went wrong
229 */ 232 */
230void __init printk_all_partitions(void) 233static int printk_partition(struct device *dev, void *data)
231{ 234{
232 struct device *dev;
233 struct gendisk *sgp; 235 struct gendisk *sgp;
234 char buf[BDEVNAME_SIZE]; 236 char buf[BDEVNAME_SIZE];
235 int n; 237 int n;
236 238
237 mutex_lock(&block_class_lock); 239 if (dev->type != &disk_type)
238 /* For each block device... */ 240 goto exit;
239 list_for_each_entry(dev, &block_class.devices, node) {
240 if (dev->type != &disk_type)
241 continue;
242 sgp = dev_to_disk(dev);
243 /*
244 * Don't show empty devices or things that have been surpressed
245 */
246 if (get_capacity(sgp) == 0 ||
247 (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO))
248 continue;
249 241
250 /* 242 sgp = dev_to_disk(dev);
251 * Note, unlike /proc/partitions, I am showing the numbers in 243 /*
252 * hex - the same format as the root= option takes. 244 * Don't show empty devices or things that have been surpressed
253 */ 245 */
254 printk("%02x%02x %10llu %s", 246 if (get_capacity(sgp) == 0 ||
255 sgp->major, sgp->first_minor, 247 (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO))
256 (unsigned long long)get_capacity(sgp) >> 1, 248 goto exit;
257 disk_name(sgp, 0, buf)); 249
258 if (sgp->driverfs_dev != NULL && 250 /*
259 sgp->driverfs_dev->driver != NULL) 251 * Note, unlike /proc/partitions, I am showing the numbers in
260 printk(" driver: %s\n", 252 * hex - the same format as the root= option takes.
261 sgp->driverfs_dev->driver->name); 253 */
262 else 254 printk("%02x%02x %10llu %s",
263 printk(" (driver?)\n"); 255 sgp->major, sgp->first_minor,
264 256 (unsigned long long)get_capacity(sgp) >> 1,
265 /* now show the partitions */ 257 disk_name(sgp, 0, buf));
266 for (n = 0; n < sgp->minors - 1; ++n) { 258 if (sgp->driverfs_dev != NULL &&
267 if (sgp->part[n] == NULL) 259 sgp->driverfs_dev->driver != NULL)
268 continue; 260 printk(" driver: %s\n",
269 if (sgp->part[n]->nr_sects == 0) 261 sgp->driverfs_dev->driver->name);
270 continue; 262 else
271 printk(" %02x%02x %10llu %s\n", 263 printk(" (driver?)\n");
272 sgp->major, n + 1 + sgp->first_minor, 264
273 (unsigned long long)sgp->part[n]->nr_sects >> 1, 265 /* now show the partitions */
274 disk_name(sgp, n + 1, buf)); 266 for (n = 0; n < sgp->minors - 1; ++n) {
275 } 267 if (sgp->part[n] == NULL)
268 goto exit;
269 if (sgp->part[n]->nr_sects == 0)
270 goto exit;
271 printk(" %02x%02x %10llu %s\n",
272 sgp->major, n + 1 + sgp->first_minor,
273 (unsigned long long)sgp->part[n]->nr_sects >> 1,
274 disk_name(sgp, n + 1, buf));
276 } 275 }
276exit:
277 return 0;
278}
277 279
280/*
281 * print a full list of all partitions - intended for places where the root
282 * filesystem can't be mounted and thus to give the victim some idea of what
283 * went wrong
284 */
285void __init printk_all_partitions(void)
286{
287 mutex_lock(&block_class_lock);
288 class_for_each_device(&block_class, NULL, NULL, printk_partition);
278 mutex_unlock(&block_class_lock); 289 mutex_unlock(&block_class_lock);
279} 290}
280 291
281#ifdef CONFIG_PROC_FS 292#ifdef CONFIG_PROC_FS
282/* iterator */ 293/* iterator */
294static int find_start(struct device *dev, void *data)
295{
296 loff_t k = *(loff_t *)data;
297
298 if (dev->type != &disk_type)
299 return 0;
300 if (!k--)
301 return 1;
302 return 0;
303}
304
283static void *part_start(struct seq_file *part, loff_t *pos) 305static void *part_start(struct seq_file *part, loff_t *pos)
284{ 306{
285 loff_t k = *pos;
286 struct device *dev; 307 struct device *dev;
308 loff_t n = *pos;
309
310 if (!n)
311 seq_puts(part, "major minor #blocks name\n\n");
287 312
288 mutex_lock(&block_class_lock); 313 mutex_lock(&block_class_lock);
289 list_for_each_entry(dev, &block_class.devices, node) { 314 dev = class_find_device(&block_class, NULL, (void *)pos, find_start);
290 if (dev->type != &disk_type) 315 if (dev)
291 continue; 316 return dev_to_disk(dev);
292 if (!k--)
293 return dev_to_disk(dev);
294 }
295 return NULL; 317 return NULL;
296} 318}
297 319
320static int find_next(struct device *dev, void *data)
321{
322 if (dev->type == &disk_type)
323 return 1;
324 return 0;
325}
326
298static void *part_next(struct seq_file *part, void *v, loff_t *pos) 327static void *part_next(struct seq_file *part, void *v, loff_t *pos)
299{ 328{
300 struct gendisk *gp = v; 329 struct gendisk *gp = v;
301 struct device *dev; 330 struct device *dev;
302 ++*pos; 331 ++*pos;
303 list_for_each_entry(dev, &gp->dev.node, node) { 332 dev = class_find_device(&block_class, &gp->dev, NULL, find_next);
304 if (&dev->node == &block_class.devices) 333 if (dev)
305 return NULL; 334 return dev_to_disk(dev);
306 if (dev->type == &disk_type)
307 return dev_to_disk(dev);
308 }
309 return NULL; 335 return NULL;
310} 336}
311 337
@@ -320,9 +346,6 @@ static int show_partition(struct seq_file *part, void *v)
320 int n; 346 int n;
321 char buf[BDEVNAME_SIZE]; 347 char buf[BDEVNAME_SIZE];
322 348
323 if (&sgp->dev.node == block_class.devices.next)
324 seq_puts(part, "major minor #blocks name\n\n");
325
326 /* Don't show non-partitionable removeable devices or empty devices */ 349 /* Don't show non-partitionable removeable devices or empty devices */
327 if (!get_capacity(sgp) || 350 if (!get_capacity(sgp) ||
328 (sgp->minors == 1 && (sgp->flags & GENHD_FL_REMOVABLE))) 351 (sgp->minors == 1 && (sgp->flags & GENHD_FL_REMOVABLE)))
@@ -368,7 +391,10 @@ static struct kobject *base_probe(dev_t devt, int *part, void *data)
368 391
369static int __init genhd_device_init(void) 392static int __init genhd_device_init(void)
370{ 393{
371 int error = class_register(&block_class); 394 int error;
395
396 block_class.dev_kobj = sysfs_dev_block_kobj;
397 error = class_register(&block_class);
372 if (unlikely(error)) 398 if (unlikely(error))
373 return error; 399 return error;
374 bdev_map = kobj_map_init(base_probe, &block_class_lock); 400 bdev_map = kobj_map_init(base_probe, &block_class_lock);
@@ -400,6 +426,14 @@ static ssize_t disk_removable_show(struct device *dev,
400 (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0)); 426 (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0));
401} 427}
402 428
429static ssize_t disk_ro_show(struct device *dev,
430 struct device_attribute *attr, char *buf)
431{
432 struct gendisk *disk = dev_to_disk(dev);
433
434 return sprintf(buf, "%d\n", disk->policy ? 1 : 0);
435}
436
403static ssize_t disk_size_show(struct device *dev, 437static ssize_t disk_size_show(struct device *dev,
404 struct device_attribute *attr, char *buf) 438 struct device_attribute *attr, char *buf)
405{ 439{
@@ -472,6 +506,7 @@ static ssize_t disk_fail_store(struct device *dev,
472 506
473static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL); 507static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL);
474static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL); 508static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL);
509static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL);
475static DEVICE_ATTR(size, S_IRUGO, disk_size_show, NULL); 510static DEVICE_ATTR(size, S_IRUGO, disk_size_show, NULL);
476static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL); 511static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL);
477static DEVICE_ATTR(stat, S_IRUGO, disk_stat_show, NULL); 512static DEVICE_ATTR(stat, S_IRUGO, disk_stat_show, NULL);
@@ -483,6 +518,7 @@ static struct device_attribute dev_attr_fail =
483static struct attribute *disk_attrs[] = { 518static struct attribute *disk_attrs[] = {
484 &dev_attr_range.attr, 519 &dev_attr_range.attr,
485 &dev_attr_removable.attr, 520 &dev_attr_removable.attr,
521 &dev_attr_ro.attr,
486 &dev_attr_size.attr, 522 &dev_attr_size.attr,
487 &dev_attr_capability.attr, 523 &dev_attr_capability.attr,
488 &dev_attr_stat.attr, 524 &dev_attr_stat.attr,
@@ -520,6 +556,7 @@ static struct device_type disk_type = {
520 .release = disk_release, 556 .release = disk_release,
521}; 557};
522 558
559#ifdef CONFIG_PROC_FS
523/* 560/*
524 * aggregate disk stat collector. Uses the same stats that the sysfs 561 * aggregate disk stat collector. Uses the same stats that the sysfs
525 * entries do, above, but makes them available through one seq_file. 562 * entries do, above, but makes them available through one seq_file.
@@ -530,16 +567,12 @@ static struct device_type disk_type = {
530 567
531static void *diskstats_start(struct seq_file *part, loff_t *pos) 568static void *diskstats_start(struct seq_file *part, loff_t *pos)
532{ 569{
533 loff_t k = *pos;
534 struct device *dev; 570 struct device *dev;
535 571
536 mutex_lock(&block_class_lock); 572 mutex_lock(&block_class_lock);
537 list_for_each_entry(dev, &block_class.devices, node) { 573 dev = class_find_device(&block_class, NULL, (void *)pos, find_start);
538 if (dev->type != &disk_type) 574 if (dev)
539 continue; 575 return dev_to_disk(dev);
540 if (!k--)
541 return dev_to_disk(dev);
542 }
543 return NULL; 576 return NULL;
544} 577}
545 578
@@ -549,12 +582,9 @@ static void *diskstats_next(struct seq_file *part, void *v, loff_t *pos)
549 struct device *dev; 582 struct device *dev;
550 583
551 ++*pos; 584 ++*pos;
552 list_for_each_entry(dev, &gp->dev.node, node) { 585 dev = class_find_device(&block_class, &gp->dev, NULL, find_next);
553 if (&dev->node == &block_class.devices) 586 if (dev)
554 return NULL; 587 return dev_to_disk(dev);
555 if (dev->type == &disk_type)
556 return dev_to_disk(dev);
557 }
558 return NULL; 588 return NULL;
559} 589}
560 590
@@ -629,6 +659,7 @@ const struct seq_operations diskstats_op = {
629 .stop = diskstats_stop, 659 .stop = diskstats_stop,
630 .show = diskstats_show 660 .show = diskstats_show
631}; 661};
662#endif /* CONFIG_PROC_FS */
632 663
633static void media_change_notify_thread(struct work_struct *work) 664static void media_change_notify_thread(struct work_struct *work)
634{ 665{
@@ -653,24 +684,38 @@ void genhd_media_change_notify(struct gendisk *disk)
653EXPORT_SYMBOL_GPL(genhd_media_change_notify); 684EXPORT_SYMBOL_GPL(genhd_media_change_notify);
654#endif /* 0 */ 685#endif /* 0 */
655 686
687struct find_block {
688 const char *name;
689 int part;
690};
691
692static int match_id(struct device *dev, void *data)
693{
694 struct find_block *find = data;
695
696 if (dev->type != &disk_type)
697 return 0;
698 if (strcmp(dev->bus_id, find->name) == 0) {
699 struct gendisk *disk = dev_to_disk(dev);
700 if (find->part < disk->minors)
701 return 1;
702 }
703 return 0;
704}
705
656dev_t blk_lookup_devt(const char *name, int part) 706dev_t blk_lookup_devt(const char *name, int part)
657{ 707{
658 struct device *dev; 708 struct device *dev;
659 dev_t devt = MKDEV(0, 0); 709 dev_t devt = MKDEV(0, 0);
710 struct find_block find;
660 711
661 mutex_lock(&block_class_lock); 712 mutex_lock(&block_class_lock);
662 list_for_each_entry(dev, &block_class.devices, node) { 713 find.name = name;
663 if (dev->type != &disk_type) 714 find.part = part;
664 continue; 715 dev = class_find_device(&block_class, NULL, (void *)&find, match_id);
665 if (strcmp(dev->bus_id, name) == 0) { 716 if (dev)
666 struct gendisk *disk = dev_to_disk(dev); 717 devt = MKDEV(MAJOR(dev->devt),
667 718 MINOR(dev->devt) + part);
668 if (part < disk->minors)
669 devt = MKDEV(MAJOR(dev->devt),
670 MINOR(dev->devt) + part);
671 break;
672 }
673 }
674 mutex_unlock(&block_class_lock); 719 mutex_unlock(&block_class_lock);
675 720
676 return devt; 721 return devt;