diff options
Diffstat (limited to 'block')
-rw-r--r-- | block/bsg.c | 43 |
1 files changed, 29 insertions, 14 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: |