diff options
-rw-r--r-- | drivers/usb/gadget/file_storage.c | 30 |
1 files changed, 17 insertions, 13 deletions
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index ea09aaa3cab6..f6f0b2aa1145 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c | |||
@@ -224,6 +224,7 @@ | |||
224 | #include <linux/fs.h> | 224 | #include <linux/fs.h> |
225 | #include <linux/init.h> | 225 | #include <linux/init.h> |
226 | #include <linux/kernel.h> | 226 | #include <linux/kernel.h> |
227 | #include <linux/kref.h> | ||
227 | #include <linux/kthread.h> | 228 | #include <linux/kthread.h> |
228 | #include <linux/limits.h> | 229 | #include <linux/limits.h> |
229 | #include <linux/list.h> | 230 | #include <linux/list.h> |
@@ -631,6 +632,9 @@ struct fsg_dev { | |||
631 | /* filesem protects: backing files in use */ | 632 | /* filesem protects: backing files in use */ |
632 | struct rw_semaphore filesem; | 633 | struct rw_semaphore filesem; |
633 | 634 | ||
635 | /* reference counting: wait until all LUNs are released */ | ||
636 | struct kref ref; | ||
637 | |||
634 | struct usb_ep *ep0; // Handy copy of gadget->ep0 | 638 | struct usb_ep *ep0; // Handy copy of gadget->ep0 |
635 | struct usb_request *ep0req; // For control responses | 639 | struct usb_request *ep0req; // For control responses |
636 | volatile unsigned int ep0_req_tag; | 640 | volatile unsigned int ep0_req_tag; |
@@ -694,7 +698,6 @@ struct fsg_dev { | |||
694 | unsigned int nluns; | 698 | unsigned int nluns; |
695 | struct lun *luns; | 699 | struct lun *luns; |
696 | struct lun *curlun; | 700 | struct lun *curlun; |
697 | struct completion lun_released; | ||
698 | }; | 701 | }; |
699 | 702 | ||
700 | typedef void (*fsg_routine_t)(struct fsg_dev *); | 703 | typedef void (*fsg_routine_t)(struct fsg_dev *); |
@@ -3642,11 +3645,19 @@ static DEVICE_ATTR(file, 0444, show_file, NULL); | |||
3642 | 3645 | ||
3643 | /*-------------------------------------------------------------------------*/ | 3646 | /*-------------------------------------------------------------------------*/ |
3644 | 3647 | ||
3648 | static void fsg_release(struct kref *ref) | ||
3649 | { | ||
3650 | struct fsg_dev *fsg = container_of(ref, struct fsg_dev, ref); | ||
3651 | |||
3652 | kfree(fsg->luns); | ||
3653 | kfree(fsg); | ||
3654 | } | ||
3655 | |||
3645 | static void lun_release(struct device *dev) | 3656 | static void lun_release(struct device *dev) |
3646 | { | 3657 | { |
3647 | struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); | 3658 | struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); |
3648 | 3659 | ||
3649 | complete(&fsg->lun_released); | 3660 | kref_put(&fsg->ref, fsg_release); |
3650 | } | 3661 | } |
3651 | 3662 | ||
3652 | static void fsg_unbind(struct usb_gadget *gadget) | 3663 | static void fsg_unbind(struct usb_gadget *gadget) |
@@ -3660,14 +3671,12 @@ static void fsg_unbind(struct usb_gadget *gadget) | |||
3660 | clear_bit(REGISTERED, &fsg->atomic_bitflags); | 3671 | clear_bit(REGISTERED, &fsg->atomic_bitflags); |
3661 | 3672 | ||
3662 | /* Unregister the sysfs attribute files and the LUNs */ | 3673 | /* Unregister the sysfs attribute files and the LUNs */ |
3663 | init_completion(&fsg->lun_released); | ||
3664 | for (i = 0; i < fsg->nluns; ++i) { | 3674 | for (i = 0; i < fsg->nluns; ++i) { |
3665 | curlun = &fsg->luns[i]; | 3675 | curlun = &fsg->luns[i]; |
3666 | if (curlun->registered) { | 3676 | if (curlun->registered) { |
3667 | device_remove_file(&curlun->dev, &dev_attr_ro); | 3677 | device_remove_file(&curlun->dev, &dev_attr_ro); |
3668 | device_remove_file(&curlun->dev, &dev_attr_file); | 3678 | device_remove_file(&curlun->dev, &dev_attr_file); |
3669 | device_unregister(&curlun->dev); | 3679 | device_unregister(&curlun->dev); |
3670 | wait_for_completion(&fsg->lun_released); | ||
3671 | curlun->registered = 0; | 3680 | curlun->registered = 0; |
3672 | } | 3681 | } |
3673 | } | 3682 | } |
@@ -3846,6 +3855,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) | |||
3846 | curlun->dev.release = lun_release; | 3855 | curlun->dev.release = lun_release; |
3847 | device_create_file(&curlun->dev, &dev_attr_ro); | 3856 | device_create_file(&curlun->dev, &dev_attr_ro); |
3848 | device_create_file(&curlun->dev, &dev_attr_file); | 3857 | device_create_file(&curlun->dev, &dev_attr_file); |
3858 | kref_get(&fsg->ref); | ||
3849 | } | 3859 | } |
3850 | 3860 | ||
3851 | if (file[i] && *file[i]) { | 3861 | if (file[i] && *file[i]) { |
@@ -4061,6 +4071,7 @@ static int __init fsg_alloc(void) | |||
4061 | return -ENOMEM; | 4071 | return -ENOMEM; |
4062 | spin_lock_init(&fsg->lock); | 4072 | spin_lock_init(&fsg->lock); |
4063 | init_rwsem(&fsg->filesem); | 4073 | init_rwsem(&fsg->filesem); |
4074 | kref_init(&fsg->ref); | ||
4064 | init_waitqueue_head(&fsg->thread_wqh); | 4075 | init_waitqueue_head(&fsg->thread_wqh); |
4065 | init_completion(&fsg->thread_notifier); | 4076 | init_completion(&fsg->thread_notifier); |
4066 | 4077 | ||
@@ -4069,13 +4080,6 @@ static int __init fsg_alloc(void) | |||
4069 | } | 4080 | } |
4070 | 4081 | ||
4071 | 4082 | ||
4072 | static void fsg_free(struct fsg_dev *fsg) | ||
4073 | { | ||
4074 | kfree(fsg->luns); | ||
4075 | kfree(fsg); | ||
4076 | } | ||
4077 | |||
4078 | |||
4079 | static int __init fsg_init(void) | 4083 | static int __init fsg_init(void) |
4080 | { | 4084 | { |
4081 | int rc; | 4085 | int rc; |
@@ -4085,7 +4089,7 @@ static int __init fsg_init(void) | |||
4085 | return rc; | 4089 | return rc; |
4086 | fsg = the_fsg; | 4090 | fsg = the_fsg; |
4087 | if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0) | 4091 | if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0) |
4088 | fsg_free(fsg); | 4092 | kref_put(&fsg->ref, fsg_release); |
4089 | return rc; | 4093 | return rc; |
4090 | } | 4094 | } |
4091 | module_init(fsg_init); | 4095 | module_init(fsg_init); |
@@ -4103,6 +4107,6 @@ static void __exit fsg_cleanup(void) | |||
4103 | wait_for_completion(&fsg->thread_notifier); | 4107 | wait_for_completion(&fsg->thread_notifier); |
4104 | 4108 | ||
4105 | close_all_backing_files(fsg); | 4109 | close_all_backing_files(fsg); |
4106 | fsg_free(fsg); | 4110 | kref_put(&fsg->ref, fsg_release); |
4107 | } | 4111 | } |
4108 | module_exit(fsg_cleanup); | 4112 | module_exit(fsg_cleanup); |