|
@@ -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;
|
|
|
}
|
|
|
|