diff options
Diffstat (limited to 'block/bsg.c')
-rw-r--r-- | block/bsg.c | 69 |
1 files changed, 30 insertions, 39 deletions
diff --git a/block/bsg.c b/block/bsg.c index b571869928a8..8e4de53311e1 100644 --- a/block/bsg.c +++ b/block/bsg.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/cdev.h> | 24 | #include <linux/cdev.h> |
25 | #include <linux/percpu.h> | 25 | #include <linux/percpu.h> |
26 | #include <linux/uio.h> | 26 | #include <linux/uio.h> |
27 | #include <linux/idr.h> | ||
27 | #include <linux/bsg.h> | 28 | #include <linux/bsg.h> |
28 | 29 | ||
29 | #include <scsi/scsi.h> | 30 | #include <scsi/scsi.h> |
@@ -70,13 +71,12 @@ enum { | |||
70 | #endif | 71 | #endif |
71 | 72 | ||
72 | static DEFINE_MUTEX(bsg_mutex); | 73 | static DEFINE_MUTEX(bsg_mutex); |
73 | static int bsg_device_nr, bsg_minor_idx; | 74 | static DEFINE_IDR(bsg_minor_idr); |
74 | 75 | ||
75 | #define BSG_LIST_ARRAY_SIZE 8 | 76 | #define BSG_LIST_ARRAY_SIZE 8 |
76 | static struct hlist_head bsg_device_list[BSG_LIST_ARRAY_SIZE]; | 77 | static struct hlist_head bsg_device_list[BSG_LIST_ARRAY_SIZE]; |
77 | 78 | ||
78 | static struct class *bsg_class; | 79 | static struct class *bsg_class; |
79 | static LIST_HEAD(bsg_class_list); | ||
80 | static int bsg_major; | 80 | static int bsg_major; |
81 | 81 | ||
82 | static struct kmem_cache *bsg_cmd_cachep; | 82 | static struct kmem_cache *bsg_cmd_cachep; |
@@ -781,23 +781,18 @@ static struct bsg_device *__bsg_get_device(int minor) | |||
781 | 781 | ||
782 | static struct bsg_device *bsg_get_device(struct inode *inode, struct file *file) | 782 | static struct bsg_device *bsg_get_device(struct inode *inode, struct file *file) |
783 | { | 783 | { |
784 | struct bsg_device *bd = __bsg_get_device(iminor(inode)); | 784 | struct bsg_device *bd; |
785 | struct bsg_class_device *bcd, *__bcd; | 785 | struct bsg_class_device *bcd; |
786 | 786 | ||
787 | bd = __bsg_get_device(iminor(inode)); | ||
787 | if (bd) | 788 | if (bd) |
788 | return bd; | 789 | return bd; |
789 | 790 | ||
790 | /* | 791 | /* |
791 | * find the class device | 792 | * find the class device |
792 | */ | 793 | */ |
793 | bcd = NULL; | ||
794 | mutex_lock(&bsg_mutex); | 794 | mutex_lock(&bsg_mutex); |
795 | list_for_each_entry(__bcd, &bsg_class_list, list) { | 795 | bcd = idr_find(&bsg_minor_idr, iminor(inode)); |
796 | if (__bcd->minor == iminor(inode)) { | ||
797 | bcd = __bcd; | ||
798 | break; | ||
799 | } | ||
800 | } | ||
801 | mutex_unlock(&bsg_mutex); | 796 | mutex_unlock(&bsg_mutex); |
802 | 797 | ||
803 | if (!bcd) | 798 | if (!bcd) |
@@ -936,13 +931,12 @@ void bsg_unregister_queue(struct request_queue *q) | |||
936 | return; | 931 | return; |
937 | 932 | ||
938 | mutex_lock(&bsg_mutex); | 933 | mutex_lock(&bsg_mutex); |
934 | idr_remove(&bsg_minor_idr, bcd->minor); | ||
939 | sysfs_remove_link(&q->kobj, "bsg"); | 935 | sysfs_remove_link(&q->kobj, "bsg"); |
940 | class_device_unregister(bcd->class_dev); | 936 | class_device_unregister(bcd->class_dev); |
941 | put_device(bcd->dev); | 937 | put_device(bcd->dev); |
942 | bcd->class_dev = NULL; | 938 | bcd->class_dev = NULL; |
943 | bcd->dev = NULL; | 939 | bcd->dev = NULL; |
944 | list_del_init(&bcd->list); | ||
945 | bsg_device_nr--; | ||
946 | mutex_unlock(&bsg_mutex); | 940 | mutex_unlock(&bsg_mutex); |
947 | } | 941 | } |
948 | EXPORT_SYMBOL_GPL(bsg_unregister_queue); | 942 | EXPORT_SYMBOL_GPL(bsg_unregister_queue); |
@@ -950,9 +944,9 @@ EXPORT_SYMBOL_GPL(bsg_unregister_queue); | |||
950 | int bsg_register_queue(struct request_queue *q, struct device *gdev, | 944 | int bsg_register_queue(struct request_queue *q, struct device *gdev, |
951 | const char *name) | 945 | const char *name) |
952 | { | 946 | { |
953 | struct bsg_class_device *bcd, *__bcd; | 947 | struct bsg_class_device *bcd; |
954 | dev_t dev; | 948 | dev_t dev; |
955 | int ret = -EMFILE; | 949 | int ret, minor; |
956 | struct class_device *class_dev = NULL; | 950 | struct class_device *class_dev = NULL; |
957 | const char *devname; | 951 | const char *devname; |
958 | 952 | ||
@@ -969,28 +963,26 @@ int bsg_register_queue(struct request_queue *q, struct device *gdev, | |||
969 | 963 | ||
970 | bcd = &q->bsg_dev; | 964 | bcd = &q->bsg_dev; |
971 | memset(bcd, 0, sizeof(*bcd)); | 965 | memset(bcd, 0, sizeof(*bcd)); |
972 | INIT_LIST_HEAD(&bcd->list); | ||
973 | 966 | ||
974 | mutex_lock(&bsg_mutex); | 967 | mutex_lock(&bsg_mutex); |
975 | if (bsg_device_nr == BSG_MAX_DEVS) { | ||
976 | printk(KERN_ERR "bsg: too many bsg devices\n"); | ||
977 | goto err; | ||
978 | } | ||
979 | 968 | ||
980 | retry: | 969 | ret = idr_pre_get(&bsg_minor_idr, GFP_KERNEL); |
981 | list_for_each_entry(__bcd, &bsg_class_list, list) { | 970 | if (!ret) { |
982 | if (__bcd->minor == bsg_minor_idx) { | 971 | ret = -ENOMEM; |
983 | bsg_minor_idx++; | 972 | goto unlock; |
984 | if (bsg_minor_idx == BSG_MAX_DEVS) | ||
985 | bsg_minor_idx = 0; | ||
986 | goto retry; | ||
987 | } | ||
988 | } | 973 | } |
989 | 974 | ||
990 | bcd->minor = bsg_minor_idx++; | 975 | ret = idr_get_new(&bsg_minor_idr, bcd, &minor); |
991 | if (bsg_minor_idx == BSG_MAX_DEVS) | 976 | if (ret < 0) |
992 | bsg_minor_idx = 0; | 977 | goto unlock; |
993 | 978 | ||
979 | if (minor >= BSG_MAX_DEVS) { | ||
980 | printk(KERN_ERR "bsg: too many bsg devices\n"); | ||
981 | ret = -EINVAL; | ||
982 | goto remove_idr; | ||
983 | } | ||
984 | |||
985 | bcd->minor = minor; | ||
994 | bcd->queue = q; | 986 | bcd->queue = q; |
995 | bcd->dev = get_device(gdev); | 987 | bcd->dev = get_device(gdev); |
996 | dev = MKDEV(bsg_major, bcd->minor); | 988 | dev = MKDEV(bsg_major, bcd->minor); |
@@ -998,27 +990,26 @@ retry: | |||
998 | devname); | 990 | devname); |
999 | if (IS_ERR(class_dev)) { | 991 | if (IS_ERR(class_dev)) { |
1000 | ret = PTR_ERR(class_dev); | 992 | ret = PTR_ERR(class_dev); |
1001 | goto err_put; | 993 | goto put_dev; |
1002 | } | 994 | } |
1003 | bcd->class_dev = class_dev; | 995 | bcd->class_dev = class_dev; |
1004 | 996 | ||
1005 | if (q->kobj.sd) { | 997 | if (q->kobj.sd) { |
1006 | ret = sysfs_create_link(&q->kobj, &bcd->class_dev->kobj, "bsg"); | 998 | ret = sysfs_create_link(&q->kobj, &bcd->class_dev->kobj, "bsg"); |
1007 | if (ret) | 999 | if (ret) |
1008 | goto err_unregister; | 1000 | goto unregister_class_dev; |
1009 | } | 1001 | } |
1010 | 1002 | ||
1011 | list_add_tail(&bcd->list, &bsg_class_list); | ||
1012 | bsg_device_nr++; | ||
1013 | |||
1014 | mutex_unlock(&bsg_mutex); | 1003 | mutex_unlock(&bsg_mutex); |
1015 | return 0; | 1004 | return 0; |
1016 | 1005 | ||
1017 | err_unregister: | 1006 | unregister_class_dev: |
1018 | class_device_unregister(class_dev); | 1007 | class_device_unregister(class_dev); |
1019 | err_put: | 1008 | put_dev: |
1020 | put_device(gdev); | 1009 | put_device(gdev); |
1021 | err: | 1010 | remove_idr: |
1011 | idr_remove(&bsg_minor_idr, minor); | ||
1012 | unlock: | ||
1022 | mutex_unlock(&bsg_mutex); | 1013 | mutex_unlock(&bsg_mutex); |
1023 | return ret; | 1014 | return ret; |
1024 | } | 1015 | } |