diff options
Diffstat (limited to 'block/bsg.c')
-rw-r--r-- | block/bsg.c | 49 |
1 files changed, 41 insertions, 8 deletions
diff --git a/block/bsg.c b/block/bsg.c index cd0221c61bf..4ef3cc55024 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -58,6 +58,7 @@ enum { }; #define BSG_DEFAULT_CMDS 64 +#define BSG_MAX_DEVS 32768 #undef BSG_DEBUG @@ -75,7 +76,7 @@ enum { #define BSG_MAJOR (240) static DEFINE_MUTEX(bsg_mutex); -static int bsg_device_nr; +static int bsg_device_nr, bsg_minor_idx; #define BSG_LIST_SIZE (8) #define bsg_list_idx(minor) ((minor) & (BSG_LIST_SIZE - 1)) @@ -957,14 +958,15 @@ void bsg_unregister_queue(struct request_queue *q) class_device_destroy(bsg_class, MKDEV(BSG_MAJOR, bcd->minor)); bcd->class_dev = NULL; list_del_init(&bcd->list); + bsg_device_nr--; mutex_unlock(&bsg_mutex); } int bsg_register_queue(struct request_queue *q, char *name) { - struct bsg_class_device *bcd; + struct bsg_class_device *bcd, *__bcd; dev_t dev; - int ret; + int ret = -EMFILE; struct class_device *class_dev = NULL; /* @@ -978,10 +980,27 @@ int bsg_register_queue(struct request_queue *q, char *name) INIT_LIST_HEAD(&bcd->list); mutex_lock(&bsg_mutex); - dev = MKDEV(BSG_MAJOR, bsg_device_nr); - bcd->minor = bsg_device_nr; - bsg_device_nr++; + if (bsg_device_nr == BSG_MAX_DEVS) { + printk(KERN_ERR "bsg: too many bsg devices\n"); + goto err; + } + +retry: + list_for_each_entry(__bcd, &bsg_class_list, list) { + if (__bcd->minor == bsg_minor_idx) { + bsg_minor_idx++; + if (bsg_minor_idx == BSG_MAX_DEVS) + bsg_minor_idx = 0; + goto retry; + } + } + + bcd->minor = bsg_minor_idx++; + if (bsg_minor_idx == BSG_MAX_DEVS) + bsg_minor_idx = 0; + bcd->queue = q; + dev = MKDEV(BSG_MAJOR, bcd->minor); class_dev = class_device_create(bsg_class, NULL, dev, bcd->dev, "%s", name); if (IS_ERR(class_dev)) { ret = PTR_ERR(class_dev); @@ -996,11 +1015,11 @@ int bsg_register_queue(struct request_queue *q, char *name) } list_add_tail(&bcd->list, &bsg_class_list); + bsg_device_nr++; mutex_unlock(&bsg_mutex); return 0; err: - bsg_device_nr--; if (class_dev) class_device_destroy(bsg_class, MKDEV(BSG_MAJOR, bcd->minor)); mutex_unlock(&bsg_mutex); @@ -1030,6 +1049,11 @@ static struct class_interface bsg_intf = { .remove = bsg_remove, }; +static struct cdev bsg_cdev = { + .kobj = {.name = "bsg", }, + .owner = THIS_MODULE, +}; + static int __init bsg_init(void) { int ret, i; @@ -1050,10 +1074,19 @@ static int __init bsg_init(void) return PTR_ERR(bsg_class); } - ret = register_chrdev(BSG_MAJOR, "bsg", &bsg_fops); + ret = register_chrdev_region(MKDEV(BSG_MAJOR, 0), BSG_MAX_DEVS, "bsg"); + if (ret) { + kmem_cache_destroy(bsg_cmd_cachep); + class_destroy(bsg_class); + return ret; + } + + cdev_init(&bsg_cdev, &bsg_fops); + ret = cdev_add(&bsg_cdev, MKDEV(BSG_MAJOR, 0), BSG_MAX_DEVS); if (ret) { kmem_cache_destroy(bsg_cmd_cachep); class_destroy(bsg_class); + unregister_chrdev_region(MKDEV(BSG_MAJOR, 0), BSG_MAX_DEVS); return ret; } |