diff options
-rw-r--r-- | block/bsg.c | 43 | ||||
-rw-r--r-- | drivers/scsi/scsi_sysfs.c | 2 | ||||
-rw-r--r-- | drivers/scsi/scsi_transport_sas.c | 2 | ||||
-rw-r--r-- | include/linux/bsg.h | 14 |
4 files changed, 41 insertions, 20 deletions
diff --git a/block/bsg.c b/block/bsg.c index f51172ed27c2..23ea4fd1a66d 100644 --- a/block/bsg.c +++ b/block/bsg.c | |||
@@ -699,14 +699,26 @@ static struct bsg_device *bsg_alloc_device(void) | |||
699 | return bd; | 699 | return bd; |
700 | } | 700 | } |
701 | 701 | ||
702 | static void bsg_kref_release_function(struct kref *kref) | ||
703 | { | ||
704 | struct bsg_class_device *bcd = | ||
705 | container_of(kref, struct bsg_class_device, ref); | ||
706 | |||
707 | if (bcd->release) | ||
708 | bcd->release(bcd->parent); | ||
709 | |||
710 | put_device(bcd->parent); | ||
711 | } | ||
712 | |||
702 | static int bsg_put_device(struct bsg_device *bd) | 713 | static int bsg_put_device(struct bsg_device *bd) |
703 | { | 714 | { |
704 | int ret = 0; | 715 | int ret = 0, do_free; |
705 | struct device *dev = bd->queue->bsg_dev.dev; | 716 | struct request_queue *q = bd->queue; |
706 | 717 | ||
707 | mutex_lock(&bsg_mutex); | 718 | mutex_lock(&bsg_mutex); |
708 | 719 | ||
709 | if (!atomic_dec_and_test(&bd->ref_count)) | 720 | do_free = atomic_dec_and_test(&bd->ref_count); |
721 | if (!do_free) | ||
710 | goto out; | 722 | goto out; |
711 | 723 | ||
712 | dprintk("%s: tearing down\n", bd->name); | 724 | dprintk("%s: tearing down\n", bd->name); |
@@ -723,12 +735,13 @@ static int bsg_put_device(struct bsg_device *bd) | |||
723 | */ | 735 | */ |
724 | ret = bsg_complete_all_commands(bd); | 736 | ret = bsg_complete_all_commands(bd); |
725 | 737 | ||
726 | blk_put_queue(bd->queue); | ||
727 | hlist_del(&bd->dev_list); | 738 | hlist_del(&bd->dev_list); |
728 | kfree(bd); | 739 | kfree(bd); |
729 | out: | 740 | out: |
730 | mutex_unlock(&bsg_mutex); | 741 | mutex_unlock(&bsg_mutex); |
731 | put_device(dev); | 742 | kref_put(&q->bsg_dev.ref, bsg_kref_release_function); |
743 | if (do_free) | ||
744 | blk_put_queue(q); | ||
732 | return ret; | 745 | return ret; |
733 | } | 746 | } |
734 | 747 | ||
@@ -796,7 +809,7 @@ static struct bsg_device *bsg_get_device(struct inode *inode, struct file *file) | |||
796 | mutex_lock(&bsg_mutex); | 809 | mutex_lock(&bsg_mutex); |
797 | bcd = idr_find(&bsg_minor_idr, iminor(inode)); | 810 | bcd = idr_find(&bsg_minor_idr, iminor(inode)); |
798 | if (bcd) | 811 | if (bcd) |
799 | get_device(bcd->dev); | 812 | kref_get(&bcd->ref); |
800 | mutex_unlock(&bsg_mutex); | 813 | mutex_unlock(&bsg_mutex); |
801 | 814 | ||
802 | if (!bcd) | 815 | if (!bcd) |
@@ -808,7 +821,7 @@ static struct bsg_device *bsg_get_device(struct inode *inode, struct file *file) | |||
808 | 821 | ||
809 | bd = bsg_add_device(inode, bcd->queue, file); | 822 | bd = bsg_add_device(inode, bcd->queue, file); |
810 | if (IS_ERR(bd)) | 823 | if (IS_ERR(bd)) |
811 | put_device(bcd->dev); | 824 | kref_put(&bcd->ref, bsg_kref_release_function); |
812 | 825 | ||
813 | return bd; | 826 | return bd; |
814 | } | 827 | } |
@@ -947,14 +960,14 @@ void bsg_unregister_queue(struct request_queue *q) | |||
947 | idr_remove(&bsg_minor_idr, bcd->minor); | 960 | idr_remove(&bsg_minor_idr, bcd->minor); |
948 | sysfs_remove_link(&q->kobj, "bsg"); | 961 | sysfs_remove_link(&q->kobj, "bsg"); |
949 | device_unregister(bcd->class_dev); | 962 | device_unregister(bcd->class_dev); |
950 | put_device(bcd->dev); | ||
951 | bcd->class_dev = NULL; | 963 | bcd->class_dev = NULL; |
964 | kref_put(&bcd->ref, bsg_kref_release_function); | ||
952 | mutex_unlock(&bsg_mutex); | 965 | mutex_unlock(&bsg_mutex); |
953 | } | 966 | } |
954 | EXPORT_SYMBOL_GPL(bsg_unregister_queue); | 967 | EXPORT_SYMBOL_GPL(bsg_unregister_queue); |
955 | 968 | ||
956 | int bsg_register_queue(struct request_queue *q, struct device *gdev, | 969 | int bsg_register_queue(struct request_queue *q, struct device *parent, |
957 | const char *name) | 970 | const char *name, void (*release)(struct device *)) |
958 | { | 971 | { |
959 | struct bsg_class_device *bcd; | 972 | struct bsg_class_device *bcd; |
960 | dev_t dev; | 973 | dev_t dev; |
@@ -965,7 +978,7 @@ int bsg_register_queue(struct request_queue *q, struct device *gdev, | |||
965 | if (name) | 978 | if (name) |
966 | devname = name; | 979 | devname = name; |
967 | else | 980 | else |
968 | devname = gdev->bus_id; | 981 | devname = parent->bus_id; |
969 | 982 | ||
970 | /* | 983 | /* |
971 | * we need a proper transport to send commands, not a stacked device | 984 | * we need a proper transport to send commands, not a stacked device |
@@ -996,9 +1009,11 @@ int bsg_register_queue(struct request_queue *q, struct device *gdev, | |||
996 | 1009 | ||
997 | bcd->minor = minor; | 1010 | bcd->minor = minor; |
998 | bcd->queue = q; | 1011 | bcd->queue = q; |
999 | bcd->dev = get_device(gdev); | 1012 | bcd->parent = get_device(parent); |
1013 | bcd->release = release; | ||
1014 | kref_init(&bcd->ref); | ||
1000 | dev = MKDEV(bsg_major, bcd->minor); | 1015 | dev = MKDEV(bsg_major, bcd->minor); |
1001 | class_dev = device_create(bsg_class, gdev, dev, "%s", devname); | 1016 | class_dev = device_create(bsg_class, parent, dev, "%s", devname); |
1002 | if (IS_ERR(class_dev)) { | 1017 | if (IS_ERR(class_dev)) { |
1003 | ret = PTR_ERR(class_dev); | 1018 | ret = PTR_ERR(class_dev); |
1004 | goto put_dev; | 1019 | goto put_dev; |
@@ -1017,7 +1032,7 @@ int bsg_register_queue(struct request_queue *q, struct device *gdev, | |||
1017 | unregister_class_dev: | 1032 | unregister_class_dev: |
1018 | device_unregister(class_dev); | 1033 | device_unregister(class_dev); |
1019 | put_dev: | 1034 | put_dev: |
1020 | put_device(gdev); | 1035 | put_device(parent); |
1021 | remove_idr: | 1036 | remove_idr: |
1022 | idr_remove(&bsg_minor_idr, minor); | 1037 | idr_remove(&bsg_minor_idr, minor); |
1023 | unlock: | 1038 | unlock: |
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 198aa4571e35..049103f1d16f 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c | |||
@@ -889,7 +889,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) | |||
889 | goto out; | 889 | goto out; |
890 | } | 890 | } |
891 | 891 | ||
892 | error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL); | 892 | error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL, NULL); |
893 | 893 | ||
894 | if (error) | 894 | if (error) |
895 | sdev_printk(KERN_INFO, sdev, | 895 | sdev_printk(KERN_INFO, sdev, |
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 27ec625ab771..94ff29f7c34b 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c | |||
@@ -219,7 +219,7 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy) | |||
219 | if (!q) | 219 | if (!q) |
220 | return -ENOMEM; | 220 | return -ENOMEM; |
221 | 221 | ||
222 | error = bsg_register_queue(q, dev, name); | 222 | error = bsg_register_queue(q, dev, name, NULL); |
223 | if (error) { | 223 | if (error) { |
224 | blk_cleanup_queue(q); | 224 | blk_cleanup_queue(q); |
225 | return -ENOMEM; | 225 | return -ENOMEM; |
diff --git a/include/linux/bsg.h b/include/linux/bsg.h index e8406c55c6d3..cf0303a60611 100644 --- a/include/linux/bsg.h +++ b/include/linux/bsg.h | |||
@@ -56,19 +56,25 @@ struct sg_io_v4 { | |||
56 | #if defined(CONFIG_BLK_DEV_BSG) | 56 | #if defined(CONFIG_BLK_DEV_BSG) |
57 | struct bsg_class_device { | 57 | struct bsg_class_device { |
58 | struct device *class_dev; | 58 | struct device *class_dev; |
59 | struct device *dev; | 59 | struct device *parent; |
60 | int minor; | 60 | int minor; |
61 | struct request_queue *queue; | 61 | struct request_queue *queue; |
62 | struct kref ref; | ||
63 | void (*release)(struct device *); | ||
62 | }; | 64 | }; |
63 | 65 | ||
64 | extern int bsg_register_queue(struct request_queue *, struct device *, const char *); | 66 | extern int bsg_register_queue(struct request_queue *q, |
67 | struct device *parent, const char *name, | ||
68 | void (*release)(struct device *)); | ||
65 | extern void bsg_unregister_queue(struct request_queue *); | 69 | extern void bsg_unregister_queue(struct request_queue *); |
66 | #else | 70 | #else |
67 | static inline int bsg_register_queue(struct request_queue * rq, struct device *dev, const char *name) | 71 | static inline int bsg_register_queue(struct request_queue *q, |
72 | struct device *parent, const char *name, | ||
73 | void (*release)(struct device *)) | ||
68 | { | 74 | { |
69 | return 0; | 75 | return 0; |
70 | } | 76 | } |
71 | static inline void bsg_unregister_queue(struct request_queue *rq) | 77 | static inline void bsg_unregister_queue(struct request_queue *q) |
72 | { | 78 | { |
73 | } | 79 | } |
74 | #endif | 80 | #endif |