aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--block/genhd.c120
-rw-r--r--fs/partitions/check.c9
-rw-r--r--include/linux/genhd.h13
-rw-r--r--include/linux/major.h2
4 files changed, 135 insertions, 9 deletions
diff --git a/block/genhd.c b/block/genhd.c
index 430626e440f0..7bbfed05cecb 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -16,6 +16,7 @@
16#include <linux/kobj_map.h> 16#include <linux/kobj_map.h>
17#include <linux/buffer_head.h> 17#include <linux/buffer_head.h>
18#include <linux/mutex.h> 18#include <linux/mutex.h>
19#include <linux/idr.h>
19 20
20#include "blk.h" 21#include "blk.h"
21 22
@@ -24,6 +25,15 @@ static DEFINE_MUTEX(block_class_lock);
24struct kobject *block_depr; 25struct kobject *block_depr;
25#endif 26#endif
26 27
28/* for extended dynamic devt allocation, currently only one major is used */
29#define MAX_EXT_DEVT (1 << MINORBITS)
30
31/* For extended devt allocation. ext_devt_mutex prevents look up
32 * results from going away underneath its user.
33 */
34static DEFINE_MUTEX(ext_devt_mutex);
35static DEFINE_IDR(ext_devt_idr);
36
27static struct device_type disk_type; 37static struct device_type disk_type;
28 38
29/** 39/**
@@ -288,6 +298,74 @@ EXPORT_SYMBOL(unregister_blkdev);
288 298
289static struct kobj_map *bdev_map; 299static struct kobj_map *bdev_map;
290 300
301/**
302 * blk_alloc_devt - allocate a dev_t for a partition
303 * @part: partition to allocate dev_t for
304 * @gfp_mask: memory allocation flag
305 * @devt: out parameter for resulting dev_t
306 *
307 * Allocate a dev_t for block device.
308 *
309 * RETURNS:
310 * 0 on success, allocated dev_t is returned in *@devt. -errno on
311 * failure.
312 *
313 * CONTEXT:
314 * Might sleep.
315 */
316int blk_alloc_devt(struct hd_struct *part, dev_t *devt)
317{
318 struct gendisk *disk = part_to_disk(part);
319 int idx, rc;
320
321 /* in consecutive minor range? */
322 if (part->partno < disk->minors) {
323 *devt = MKDEV(disk->major, disk->first_minor + part->partno);
324 return 0;
325 }
326
327 /* allocate ext devt */
328 do {
329 if (!idr_pre_get(&ext_devt_idr, GFP_KERNEL))
330 return -ENOMEM;
331 rc = idr_get_new(&ext_devt_idr, part, &idx);
332 } while (rc == -EAGAIN);
333
334 if (rc)
335 return rc;
336
337 if (idx > MAX_EXT_DEVT) {
338 idr_remove(&ext_devt_idr, idx);
339 return -EBUSY;
340 }
341
342 *devt = MKDEV(BLOCK_EXT_MAJOR, idx);
343 return 0;
344}
345
346/**
347 * blk_free_devt - free a dev_t
348 * @devt: dev_t to free
349 *
350 * Free @devt which was allocated using blk_alloc_devt().
351 *
352 * CONTEXT:
353 * Might sleep.
354 */
355void blk_free_devt(dev_t devt)
356{
357 might_sleep();
358
359 if (devt == MKDEV(0, 0))
360 return;
361
362 if (MAJOR(devt) == BLOCK_EXT_MAJOR) {
363 mutex_lock(&ext_devt_mutex);
364 idr_remove(&ext_devt_idr, MINOR(devt));
365 mutex_unlock(&ext_devt_mutex);
366 }
367}
368
291/* 369/*
292 * Register device numbers dev..(dev+range-1) 370 * Register device numbers dev..(dev+range-1)
293 * range must be nonzero 371 * range must be nonzero
@@ -371,10 +449,27 @@ void unlink_gendisk(struct gendisk *disk)
371 */ 449 */
372struct gendisk *get_gendisk(dev_t devt, int *partno) 450struct gendisk *get_gendisk(dev_t devt, int *partno)
373{ 451{
374 struct kobject *kobj = kobj_lookup(bdev_map, devt, partno); 452 struct gendisk *disk = NULL;
375 struct device *dev = kobj_to_dev(kobj); 453
454 if (MAJOR(devt) != BLOCK_EXT_MAJOR) {
455 struct kobject *kobj;
456
457 kobj = kobj_lookup(bdev_map, devt, partno);
458 if (kobj)
459 disk = dev_to_disk(kobj_to_dev(kobj));
460 } else {
461 struct hd_struct *part;
462
463 mutex_lock(&ext_devt_mutex);
464 part = idr_find(&ext_devt_idr, MINOR(devt));
465 if (part && get_disk(part_to_disk(part))) {
466 *partno = part->partno;
467 disk = part_to_disk(part);
468 }
469 mutex_unlock(&ext_devt_mutex);
470 }
376 471
377 return kobj ? dev_to_disk(dev) : NULL; 472 return disk;
378} 473}
379 474
380/** 475/**
@@ -878,17 +973,29 @@ struct gendisk *alloc_disk(int minors)
878 973
879struct gendisk *alloc_disk_node(int minors, int node_id) 974struct gendisk *alloc_disk_node(int minors, int node_id)
880{ 975{
976 return alloc_disk_ext_node(minors, 0, node_id);
977}
978
979struct gendisk *alloc_disk_ext(int minors, int ext_minors)
980{
981 return alloc_disk_ext_node(minors, ext_minors, -1);
982}
983
984struct gendisk *alloc_disk_ext_node(int minors, int ext_minors, int node_id)
985{
881 struct gendisk *disk; 986 struct gendisk *disk;
882 987
883 disk = kmalloc_node(sizeof(struct gendisk), 988 disk = kmalloc_node(sizeof(struct gendisk),
884 GFP_KERNEL | __GFP_ZERO, node_id); 989 GFP_KERNEL | __GFP_ZERO, node_id);
885 if (disk) { 990 if (disk) {
991 int tot_minors = minors + ext_minors;
992
886 if (!init_disk_stats(disk)) { 993 if (!init_disk_stats(disk)) {
887 kfree(disk); 994 kfree(disk);
888 return NULL; 995 return NULL;
889 } 996 }
890 if (minors > 1) { 997 if (tot_minors > 1) {
891 int size = (minors - 1) * sizeof(struct hd_struct *); 998 int size = (tot_minors - 1) * sizeof(struct hd_struct *);
892 disk->__part = kmalloc_node(size, 999 disk->__part = kmalloc_node(size,
893 GFP_KERNEL | __GFP_ZERO, node_id); 1000 GFP_KERNEL | __GFP_ZERO, node_id);
894 if (!disk->__part) { 1001 if (!disk->__part) {
@@ -898,6 +1005,7 @@ struct gendisk *alloc_disk_node(int minors, int node_id)
898 } 1005 }
899 } 1006 }
900 disk->minors = minors; 1007 disk->minors = minors;
1008 disk->ext_minors = ext_minors;
901 rand_initialize_disk(disk); 1009 rand_initialize_disk(disk);
902 disk->dev.class = &block_class; 1010 disk->dev.class = &block_class;
903 disk->dev.type = &disk_type; 1011 disk->dev.type = &disk_type;
@@ -910,6 +1018,8 @@ struct gendisk *alloc_disk_node(int minors, int node_id)
910 1018
911EXPORT_SYMBOL(alloc_disk); 1019EXPORT_SYMBOL(alloc_disk);
912EXPORT_SYMBOL(alloc_disk_node); 1020EXPORT_SYMBOL(alloc_disk_node);
1021EXPORT_SYMBOL(alloc_disk_ext);
1022EXPORT_SYMBOL(alloc_disk_ext_node);
913 1023
914struct kobject *get_disk(struct gendisk *disk) 1024struct kobject *get_disk(struct gendisk *disk)
915{ 1025{
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index c442f0aadac3..0d4b7f28f13f 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -333,6 +333,7 @@ void delete_partition(struct gendisk *disk, int partno)
333 if (!part) 333 if (!part)
334 return; 334 return;
335 335
336 blk_free_devt(part_devt(part));
336 rcu_assign_pointer(disk->__part[partno-1], NULL); 337 rcu_assign_pointer(disk->__part[partno-1], NULL);
337 kobject_put(part->holder_dir); 338 kobject_put(part->holder_dir);
338 device_del(&part->dev); 339 device_del(&part->dev);
@@ -352,6 +353,7 @@ int add_partition(struct gendisk *disk, int partno,
352 sector_t start, sector_t len, int flags) 353 sector_t start, sector_t len, int flags)
353{ 354{
354 struct hd_struct *p; 355 struct hd_struct *p;
356 dev_t devt = MKDEV(0, 0);
355 int err; 357 int err;
356 358
357 if (disk->__part[partno - 1]) 359 if (disk->__part[partno - 1])
@@ -378,11 +380,15 @@ int add_partition(struct gendisk *disk, int partno,
378 "%s%d", disk->dev.bus_id, partno); 380 "%s%d", disk->dev.bus_id, partno);
379 381
380 device_initialize(&p->dev); 382 device_initialize(&p->dev);
381 p->dev.devt = MKDEV(disk->major, disk->first_minor + partno);
382 p->dev.class = &block_class; 383 p->dev.class = &block_class;
383 p->dev.type = &part_type; 384 p->dev.type = &part_type;
384 p->dev.parent = &disk->dev; 385 p->dev.parent = &disk->dev;
385 386
387 err = blk_alloc_devt(p, &devt);
388 if (err)
389 goto out_put;
390 p->dev.devt = devt;
391
386 /* delay uevent until 'holders' subdir is created */ 392 /* delay uevent until 'holders' subdir is created */
387 p->dev.uevent_suppress = 1; 393 p->dev.uevent_suppress = 1;
388 err = device_add(&p->dev); 394 err = device_add(&p->dev);
@@ -419,6 +425,7 @@ out_del:
419 device_del(&p->dev); 425 device_del(&p->dev);
420out_put: 426out_put:
421 put_device(&p->dev); 427 put_device(&p->dev);
428 blk_free_devt(devt);
422 return err; 429 return err;
423} 430}
424 431
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index ac8a901f2002..6fc532424062 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -113,13 +113,15 @@ struct hd_struct {
113#define GENHD_FL_FAIL 64 113#define GENHD_FL_FAIL 64
114 114
115struct gendisk { 115struct gendisk {
116 /* major, first_minor and minors are input parameters only, 116 /* major, first_minor, minors and ext_minors are input
117 * don't use directly. Use disk_devt() and disk_max_parts(). 117 * parameters only, don't use directly. Use disk_devt() and
118 * disk_max_parts().
118 */ 119 */
119 int major; /* major number of driver */ 120 int major; /* major number of driver */
120 int first_minor; 121 int first_minor;
121 int minors; /* maximum number of minors, =1 for 122 int minors; /* maximum number of minors, =1 for
122 * disks that can't be partitioned. */ 123 * disks that can't be partitioned. */
124 int ext_minors; /* number of extended dynamic minors */
123 125
124 char disk_name[32]; /* name of major driver */ 126 char disk_name[32]; /* name of major driver */
125 127
@@ -167,7 +169,7 @@ static inline struct gendisk *part_to_disk(struct hd_struct *part)
167 169
168static inline int disk_max_parts(struct gendisk *disk) 170static inline int disk_max_parts(struct gendisk *disk)
169{ 171{
170 return disk->minors - 1; 172 return disk->minors + disk->ext_minors - 1;
171} 173}
172 174
173static inline dev_t disk_devt(struct gendisk *disk) 175static inline dev_t disk_devt(struct gendisk *disk)
@@ -554,6 +556,8 @@ struct unixware_disklabel {
554#define ADDPART_FLAG_RAID 1 556#define ADDPART_FLAG_RAID 1
555#define ADDPART_FLAG_WHOLEDISK 2 557#define ADDPART_FLAG_WHOLEDISK 2
556 558
559extern int blk_alloc_devt(struct hd_struct *part, dev_t *devt);
560extern void blk_free_devt(dev_t devt);
557extern dev_t blk_lookup_devt(const char *name, int partno); 561extern dev_t blk_lookup_devt(const char *name, int partno);
558extern char *disk_name (struct gendisk *hd, int partno, char *buf); 562extern char *disk_name (struct gendisk *hd, int partno, char *buf);
559 563
@@ -564,6 +568,9 @@ extern void printk_all_partitions(void);
564 568
565extern struct gendisk *alloc_disk_node(int minors, int node_id); 569extern struct gendisk *alloc_disk_node(int minors, int node_id);
566extern struct gendisk *alloc_disk(int minors); 570extern struct gendisk *alloc_disk(int minors);
571extern struct gendisk *alloc_disk_ext_node(int minors, int ext_minrs,
572 int node_id);
573extern struct gendisk *alloc_disk_ext(int minors, int ext_minors);
567extern struct kobject *get_disk(struct gendisk *disk); 574extern struct kobject *get_disk(struct gendisk *disk);
568extern void put_disk(struct gendisk *disk); 575extern void put_disk(struct gendisk *disk);
569extern void blk_register_region(dev_t devt, unsigned long range, 576extern void blk_register_region(dev_t devt, unsigned long range,
diff --git a/include/linux/major.h b/include/linux/major.h
index 53d5fafd85c3..88249452b935 100644
--- a/include/linux/major.h
+++ b/include/linux/major.h
@@ -170,4 +170,6 @@
170 170
171#define VIOTAPE_MAJOR 230 171#define VIOTAPE_MAJOR 230
172 172
173#define BLOCK_EXT_MAJOR 259
174
173#endif 175#endif