aboutsummaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2008-04-18 11:43:14 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-04-22 16:16:32 -0400
commit97f46ae45c70857e459b7f8df1fc2807e7bd90a9 (patch)
tree7e7245349c433f67be23c6a75c3936c0466b59d6 /block
parent643eb2d932c97a0583381629d632d486934cf7ee (diff)
[SCSI] bsg: add release callback support
This patch adds release callback support, which is called when a bsg device goes away. bsg_register_queue() takes a pointer to a callback function. This feature is useful for stuff like sas_host that can't use the release callback in struct device. If a caller doesn't need bsg's release callback, it can call bsg_register_queue() with NULL pointer (e.g. scsi devices can use release callback in struct device so they don't need bsg's callback). With this patch, bsg uses kref for refcounts on bsg devices instead of get/put_device in fops->open/release. bsg calls put_device and the caller's release callback (if it was registered) in kref_put's release. Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'block')
-rw-r--r--block/bsg.c43
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
702static 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
702static int bsg_put_device(struct bsg_device *bd) 713static 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);
729out: 740out:
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}
954EXPORT_SYMBOL_GPL(bsg_unregister_queue); 967EXPORT_SYMBOL_GPL(bsg_unregister_queue);
955 968
956int bsg_register_queue(struct request_queue *q, struct device *gdev, 969int 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,
1017unregister_class_dev: 1032unregister_class_dev:
1018 device_unregister(class_dev); 1033 device_unregister(class_dev);
1019put_dev: 1034put_dev:
1020 put_device(gdev); 1035 put_device(parent);
1021remove_idr: 1036remove_idr:
1022 idr_remove(&bsg_minor_idr, minor); 1037 idr_remove(&bsg_minor_idr, minor);
1023unlock: 1038unlock: