aboutsummaryrefslogtreecommitdiffstats
path: root/block/bsg.c
diff options
context:
space:
mode:
Diffstat (limited to 'block/bsg.c')
-rw-r--r--block/bsg.c78
1 files changed, 30 insertions, 48 deletions
diff --git a/block/bsg.c b/block/bsg.c
index 3b2f05258a92..d60eee549405 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -9,13 +9,6 @@
9 * archive for more details. 9 * archive for more details.
10 * 10 *
11 */ 11 */
12/*
13 * TODO
14 * - Should this get merged, block/scsi_ioctl.c will be migrated into
15 * this file. To keep maintenance down, it's easier to have them
16 * seperated right now.
17 *
18 */
19#include <linux/module.h> 12#include <linux/module.h>
20#include <linux/init.h> 13#include <linux/init.h>
21#include <linux/file.h> 14#include <linux/file.h>
@@ -24,6 +17,7 @@
24#include <linux/cdev.h> 17#include <linux/cdev.h>
25#include <linux/percpu.h> 18#include <linux/percpu.h>
26#include <linux/uio.h> 19#include <linux/uio.h>
20#include <linux/idr.h>
27#include <linux/bsg.h> 21#include <linux/bsg.h>
28 22
29#include <scsi/scsi.h> 23#include <scsi/scsi.h>
@@ -70,13 +64,12 @@ enum {
70#endif 64#endif
71 65
72static DEFINE_MUTEX(bsg_mutex); 66static DEFINE_MUTEX(bsg_mutex);
73static int bsg_device_nr, bsg_minor_idx; 67static DEFINE_IDR(bsg_minor_idr);
74 68
75#define BSG_LIST_ARRAY_SIZE 8 69#define BSG_LIST_ARRAY_SIZE 8
76static struct hlist_head bsg_device_list[BSG_LIST_ARRAY_SIZE]; 70static struct hlist_head bsg_device_list[BSG_LIST_ARRAY_SIZE];
77 71
78static struct class *bsg_class; 72static struct class *bsg_class;
79static LIST_HEAD(bsg_class_list);
80static int bsg_major; 73static int bsg_major;
81 74
82static struct kmem_cache *bsg_cmd_cachep; 75static struct kmem_cache *bsg_cmd_cachep;
@@ -92,7 +85,6 @@ struct bsg_command {
92 struct bio *bidi_bio; 85 struct bio *bidi_bio;
93 int err; 86 int err;
94 struct sg_io_v4 hdr; 87 struct sg_io_v4 hdr;
95 struct sg_io_v4 __user *uhdr;
96 char sense[SCSI_SENSE_BUFFERSIZE]; 88 char sense[SCSI_SENSE_BUFFERSIZE];
97}; 89};
98 90
@@ -620,7 +612,6 @@ static int __bsg_write(struct bsg_device *bd, const char __user *buf,
620 break; 612 break;
621 } 613 }
622 614
623 bc->uhdr = (struct sg_io_v4 __user *) buf;
624 if (copy_from_user(&bc->hdr, buf, sizeof(bc->hdr))) { 615 if (copy_from_user(&bc->hdr, buf, sizeof(bc->hdr))) {
625 ret = -EFAULT; 616 ret = -EFAULT;
626 break; 617 break;
@@ -781,23 +772,18 @@ static struct bsg_device *__bsg_get_device(int minor)
781 772
782static struct bsg_device *bsg_get_device(struct inode *inode, struct file *file) 773static struct bsg_device *bsg_get_device(struct inode *inode, struct file *file)
783{ 774{
784 struct bsg_device *bd = __bsg_get_device(iminor(inode)); 775 struct bsg_device *bd;
785 struct bsg_class_device *bcd, *__bcd; 776 struct bsg_class_device *bcd;
786 777
778 bd = __bsg_get_device(iminor(inode));
787 if (bd) 779 if (bd)
788 return bd; 780 return bd;
789 781
790 /* 782 /*
791 * find the class device 783 * find the class device
792 */ 784 */
793 bcd = NULL;
794 mutex_lock(&bsg_mutex); 785 mutex_lock(&bsg_mutex);
795 list_for_each_entry(__bcd, &bsg_class_list, list) { 786 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); 787 mutex_unlock(&bsg_mutex);
802 788
803 if (!bcd) 789 if (!bcd)
@@ -936,13 +922,12 @@ void bsg_unregister_queue(struct request_queue *q)
936 return; 922 return;
937 923
938 mutex_lock(&bsg_mutex); 924 mutex_lock(&bsg_mutex);
925 idr_remove(&bsg_minor_idr, bcd->minor);
939 sysfs_remove_link(&q->kobj, "bsg"); 926 sysfs_remove_link(&q->kobj, "bsg");
940 class_device_unregister(bcd->class_dev); 927 class_device_unregister(bcd->class_dev);
941 put_device(bcd->dev); 928 put_device(bcd->dev);
942 bcd->class_dev = NULL; 929 bcd->class_dev = NULL;
943 bcd->dev = NULL; 930 bcd->dev = NULL;
944 list_del_init(&bcd->list);
945 bsg_device_nr--;
946 mutex_unlock(&bsg_mutex); 931 mutex_unlock(&bsg_mutex);
947} 932}
948EXPORT_SYMBOL_GPL(bsg_unregister_queue); 933EXPORT_SYMBOL_GPL(bsg_unregister_queue);
@@ -950,9 +935,9 @@ EXPORT_SYMBOL_GPL(bsg_unregister_queue);
950int bsg_register_queue(struct request_queue *q, struct device *gdev, 935int bsg_register_queue(struct request_queue *q, struct device *gdev,
951 const char *name) 936 const char *name)
952{ 937{
953 struct bsg_class_device *bcd, *__bcd; 938 struct bsg_class_device *bcd;
954 dev_t dev; 939 dev_t dev;
955 int ret = -EMFILE; 940 int ret, minor;
956 struct class_device *class_dev = NULL; 941 struct class_device *class_dev = NULL;
957 const char *devname; 942 const char *devname;
958 943
@@ -969,28 +954,26 @@ int bsg_register_queue(struct request_queue *q, struct device *gdev,
969 954
970 bcd = &q->bsg_dev; 955 bcd = &q->bsg_dev;
971 memset(bcd, 0, sizeof(*bcd)); 956 memset(bcd, 0, sizeof(*bcd));
972 INIT_LIST_HEAD(&bcd->list);
973 957
974 mutex_lock(&bsg_mutex); 958 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 959
980retry: 960 ret = idr_pre_get(&bsg_minor_idr, GFP_KERNEL);
981 list_for_each_entry(__bcd, &bsg_class_list, list) { 961 if (!ret) {
982 if (__bcd->minor == bsg_minor_idx) { 962 ret = -ENOMEM;
983 bsg_minor_idx++; 963 goto unlock;
984 if (bsg_minor_idx == BSG_MAX_DEVS)
985 bsg_minor_idx = 0;
986 goto retry;
987 }
988 } 964 }
989 965
990 bcd->minor = bsg_minor_idx++; 966 ret = idr_get_new(&bsg_minor_idr, bcd, &minor);
991 if (bsg_minor_idx == BSG_MAX_DEVS) 967 if (ret < 0)
992 bsg_minor_idx = 0; 968 goto unlock;
993 969
970 if (minor >= BSG_MAX_DEVS) {
971 printk(KERN_ERR "bsg: too many bsg devices\n");
972 ret = -EINVAL;
973 goto remove_idr;
974 }
975
976 bcd->minor = minor;
994 bcd->queue = q; 977 bcd->queue = q;
995 bcd->dev = get_device(gdev); 978 bcd->dev = get_device(gdev);
996 dev = MKDEV(bsg_major, bcd->minor); 979 dev = MKDEV(bsg_major, bcd->minor);
@@ -998,27 +981,26 @@ retry:
998 devname); 981 devname);
999 if (IS_ERR(class_dev)) { 982 if (IS_ERR(class_dev)) {
1000 ret = PTR_ERR(class_dev); 983 ret = PTR_ERR(class_dev);
1001 goto err_put; 984 goto put_dev;
1002 } 985 }
1003 bcd->class_dev = class_dev; 986 bcd->class_dev = class_dev;
1004 987
1005 if (q->kobj.sd) { 988 if (q->kobj.sd) {
1006 ret = sysfs_create_link(&q->kobj, &bcd->class_dev->kobj, "bsg"); 989 ret = sysfs_create_link(&q->kobj, &bcd->class_dev->kobj, "bsg");
1007 if (ret) 990 if (ret)
1008 goto err_unregister; 991 goto unregister_class_dev;
1009 } 992 }
1010 993
1011 list_add_tail(&bcd->list, &bsg_class_list);
1012 bsg_device_nr++;
1013
1014 mutex_unlock(&bsg_mutex); 994 mutex_unlock(&bsg_mutex);
1015 return 0; 995 return 0;
1016 996
1017err_unregister: 997unregister_class_dev:
1018 class_device_unregister(class_dev); 998 class_device_unregister(class_dev);
1019err_put: 999put_dev:
1020 put_device(gdev); 1000 put_device(gdev);
1021err: 1001remove_idr:
1002 idr_remove(&bsg_minor_idr, minor);
1003unlock:
1022 mutex_unlock(&bsg_mutex); 1004 mutex_unlock(&bsg_mutex);
1023 return ret; 1005 return ret;
1024} 1006}