Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

FUJITA Tomonori and committed by
James Bottomley
97f46ae4 643eb2d9

+41 -20
+29 -14
block/bsg.c
··· 699 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 713 static int bsg_put_device(struct bsg_device *bd) 703 714 { 704 - int ret = 0; 705 - struct device *dev = bd->queue->bsg_dev.dev; 715 + int ret = 0, do_free; 716 + struct request_queue *q = bd->queue; 706 717 707 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 722 goto out; 711 723 712 724 dprintk("%s: tearing down\n", bd->name); ··· 735 723 */ 736 724 ret = bsg_complete_all_commands(bd); 737 725 738 - blk_put_queue(bd->queue); 739 726 hlist_del(&bd->dev_list); 740 727 kfree(bd); 741 728 out: 742 729 mutex_unlock(&bsg_mutex); 743 - put_device(dev); 730 + kref_put(&q->bsg_dev.ref, bsg_kref_release_function); 731 + if (do_free) 732 + blk_put_queue(q); 744 733 return ret; 745 734 } 746 735 ··· 809 796 mutex_lock(&bsg_mutex); 810 797 bcd = idr_find(&bsg_minor_idr, iminor(inode)); 811 798 if (bcd) 812 - get_device(bcd->dev); 799 + kref_get(&bcd->ref); 813 800 mutex_unlock(&bsg_mutex); 814 801 815 802 if (!bcd) ··· 821 808 822 809 bd = bsg_add_device(inode, bcd->queue, file); 823 810 if (IS_ERR(bd)) 824 - put_device(bcd->dev); 811 + kref_put(&bcd->ref, bsg_kref_release_function); 825 812 826 813 return bd; 827 814 } ··· 960 947 idr_remove(&bsg_minor_idr, bcd->minor); 961 948 sysfs_remove_link(&q->kobj, "bsg"); 962 949 device_unregister(bcd->class_dev); 963 - put_device(bcd->dev); 964 950 bcd->class_dev = NULL; 951 + kref_put(&bcd->ref, bsg_kref_release_function); 965 952 mutex_unlock(&bsg_mutex); 966 953 } 967 954 EXPORT_SYMBOL_GPL(bsg_unregister_queue); 968 955 969 - int bsg_register_queue(struct request_queue *q, struct device *gdev, 970 - const char *name) 956 + int bsg_register_queue(struct request_queue *q, struct device *parent, 957 + const char *name, void (*release)(struct device *)) 971 958 { 972 959 struct bsg_class_device *bcd; 973 960 dev_t dev; ··· 978 965 if (name) 979 966 devname = name; 980 967 else 981 - devname = gdev->bus_id; 968 + devname = parent->bus_id; 982 969 983 970 /* 984 971 * we need a proper transport to send commands, not a stacked device ··· 1009 996 1010 997 bcd->minor = minor; 1011 998 bcd->queue = q; 1012 - bcd->dev = get_device(gdev); 999 + bcd->parent = get_device(parent); 1000 + bcd->release = release; 1001 + kref_init(&bcd->ref); 1013 1002 dev = MKDEV(bsg_major, bcd->minor); 1014 - class_dev = device_create(bsg_class, gdev, dev, "%s", devname); 1003 + class_dev = device_create(bsg_class, parent, dev, "%s", devname); 1015 1004 if (IS_ERR(class_dev)) { 1016 1005 ret = PTR_ERR(class_dev); 1017 1006 goto put_dev; ··· 1032 1017 unregister_class_dev: 1033 1018 device_unregister(class_dev); 1034 1019 put_dev: 1035 - put_device(gdev); 1020 + put_device(parent); 1036 1021 remove_idr: 1037 1022 idr_remove(&bsg_minor_idr, minor); 1038 1023 unlock:
+1 -1
drivers/scsi/scsi_sysfs.c
··· 889 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 894 if (error) 895 895 sdev_printk(KERN_INFO, sdev,
+1 -1
drivers/scsi/scsi_transport_sas.c
··· 219 219 if (!q) 220 220 return -ENOMEM; 221 221 222 - error = bsg_register_queue(q, dev, name); 222 + error = bsg_register_queue(q, dev, name, NULL); 223 223 if (error) { 224 224 blk_cleanup_queue(q); 225 225 return -ENOMEM;
+10 -4
include/linux/bsg.h
··· 56 56 #if defined(CONFIG_BLK_DEV_BSG) 57 57 struct bsg_class_device { 58 58 struct device *class_dev; 59 - struct device *dev; 59 + struct device *parent; 60 60 int minor; 61 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 69 extern void bsg_unregister_queue(struct request_queue *); 66 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 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 80 #endif