aboutsummaryrefslogtreecommitdiffstats
path: root/block/bsg.c
diff options
context:
space:
mode:
Diffstat (limited to 'block/bsg.c')
-rw-r--r--block/bsg.c69
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
72static DEFINE_MUTEX(bsg_mutex); 73static DEFINE_MUTEX(bsg_mutex);
73static int bsg_device_nr, bsg_minor_idx; 74static DEFINE_IDR(bsg_minor_idr);
74 75
75#define BSG_LIST_ARRAY_SIZE 8 76#define BSG_LIST_ARRAY_SIZE 8
76static struct hlist_head bsg_device_list[BSG_LIST_ARRAY_SIZE]; 77static struct hlist_head bsg_device_list[BSG_LIST_ARRAY_SIZE];
77 78
78static struct class *bsg_class; 79static struct class *bsg_class;
79static LIST_HEAD(bsg_class_list);
80static int bsg_major; 80static int bsg_major;
81 81
82static struct kmem_cache *bsg_cmd_cachep; 82static struct kmem_cache *bsg_cmd_cachep;
@@ -781,23 +781,18 @@ static struct bsg_device *__bsg_get_device(int minor)
781 781
782static struct bsg_device *bsg_get_device(struct inode *inode, struct file *file) 782static 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}
948EXPORT_SYMBOL_GPL(bsg_unregister_queue); 942EXPORT_SYMBOL_GPL(bsg_unregister_queue);
@@ -950,9 +944,9 @@ EXPORT_SYMBOL_GPL(bsg_unregister_queue);
950int bsg_register_queue(struct request_queue *q, struct device *gdev, 944int 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
980retry: 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
1017err_unregister: 1006unregister_class_dev:
1018 class_device_unregister(class_dev); 1007 class_device_unregister(class_dev);
1019err_put: 1008put_dev:
1020 put_device(gdev); 1009 put_device(gdev);
1021err: 1010remove_idr:
1011 idr_remove(&bsg_minor_idr, minor);
1012unlock:
1022 mutex_unlock(&bsg_mutex); 1013 mutex_unlock(&bsg_mutex);
1023 return ret; 1014 return ret;
1024} 1015}