Commit 87c4252a authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

[PATCH] USB: file-storage gadget: Add reference count for children

This patch (as601) adds a proper reference count to the file-storage
gadget's main data structure, to keep track of references held by child
devices (LUNs in this case).  Before this, the driver would wait for
each child to be released before unbinding.

While there's nothing really wrong with that (you can't create a hang by
doing "rmmod g_file_storage </sys/.../lun0/ro" since the open file will
prevent rmmod from running), the code might as well follow the standard
procedures.  Besides, this shrinks the size of the structure by a few
words...  :-)
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent c9a50cc9
...@@ -224,6 +224,7 @@ ...@@ -224,6 +224,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/limits.h> #include <linux/limits.h>
#include <linux/list.h> #include <linux/list.h>
...@@ -631,6 +632,9 @@ struct fsg_dev { ...@@ -631,6 +632,9 @@ struct fsg_dev {
/* filesem protects: backing files in use */ /* filesem protects: backing files in use */
struct rw_semaphore filesem; struct rw_semaphore filesem;
/* reference counting: wait until all LUNs are released */
struct kref ref;
struct usb_ep *ep0; // Handy copy of gadget->ep0 struct usb_ep *ep0; // Handy copy of gadget->ep0
struct usb_request *ep0req; // For control responses struct usb_request *ep0req; // For control responses
volatile unsigned int ep0_req_tag; volatile unsigned int ep0_req_tag;
...@@ -694,7 +698,6 @@ struct fsg_dev { ...@@ -694,7 +698,6 @@ struct fsg_dev {
unsigned int nluns; unsigned int nluns;
struct lun *luns; struct lun *luns;
struct lun *curlun; struct lun *curlun;
struct completion lun_released;
}; };
typedef void (*fsg_routine_t)(struct fsg_dev *); typedef void (*fsg_routine_t)(struct fsg_dev *);
...@@ -3642,11 +3645,19 @@ static DEVICE_ATTR(file, 0444, show_file, NULL); ...@@ -3642,11 +3645,19 @@ static DEVICE_ATTR(file, 0444, show_file, NULL);
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static void fsg_release(struct kref *ref)
{
struct fsg_dev *fsg = container_of(ref, struct fsg_dev, ref);
kfree(fsg->luns);
kfree(fsg);
}
static void lun_release(struct device *dev) static void lun_release(struct device *dev)
{ {
struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
complete(&fsg->lun_released); kref_put(&fsg->ref, fsg_release);
} }
static void fsg_unbind(struct usb_gadget *gadget) static void fsg_unbind(struct usb_gadget *gadget)
...@@ -3660,14 +3671,12 @@ static void fsg_unbind(struct usb_gadget *gadget) ...@@ -3660,14 +3671,12 @@ static void fsg_unbind(struct usb_gadget *gadget)
clear_bit(REGISTERED, &fsg->atomic_bitflags); clear_bit(REGISTERED, &fsg->atomic_bitflags);
/* Unregister the sysfs attribute files and the LUNs */ /* Unregister the sysfs attribute files and the LUNs */
init_completion(&fsg->lun_released);
for (i = 0; i < fsg->nluns; ++i) { for (i = 0; i < fsg->nluns; ++i) {
curlun = &fsg->luns[i]; curlun = &fsg->luns[i];
if (curlun->registered) { if (curlun->registered) {
device_remove_file(&curlun->dev, &dev_attr_ro); device_remove_file(&curlun->dev, &dev_attr_ro);
device_remove_file(&curlun->dev, &dev_attr_file); device_remove_file(&curlun->dev, &dev_attr_file);
device_unregister(&curlun->dev); device_unregister(&curlun->dev);
wait_for_completion(&fsg->lun_released);
curlun->registered = 0; curlun->registered = 0;
} }
} }
...@@ -3846,6 +3855,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) ...@@ -3846,6 +3855,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
curlun->dev.release = lun_release; curlun->dev.release = lun_release;
device_create_file(&curlun->dev, &dev_attr_ro); device_create_file(&curlun->dev, &dev_attr_ro);
device_create_file(&curlun->dev, &dev_attr_file); device_create_file(&curlun->dev, &dev_attr_file);
kref_get(&fsg->ref);
} }
if (file[i] && *file[i]) { if (file[i] && *file[i]) {
...@@ -4061,6 +4071,7 @@ static int __init fsg_alloc(void) ...@@ -4061,6 +4071,7 @@ static int __init fsg_alloc(void)
return -ENOMEM; return -ENOMEM;
spin_lock_init(&fsg->lock); spin_lock_init(&fsg->lock);
init_rwsem(&fsg->filesem); init_rwsem(&fsg->filesem);
kref_init(&fsg->ref);
init_waitqueue_head(&fsg->thread_wqh); init_waitqueue_head(&fsg->thread_wqh);
init_completion(&fsg->thread_notifier); init_completion(&fsg->thread_notifier);
...@@ -4069,13 +4080,6 @@ static int __init fsg_alloc(void) ...@@ -4069,13 +4080,6 @@ static int __init fsg_alloc(void)
} }
static void fsg_free(struct fsg_dev *fsg)
{
kfree(fsg->luns);
kfree(fsg);
}
static int __init fsg_init(void) static int __init fsg_init(void)
{ {
int rc; int rc;
...@@ -4085,7 +4089,7 @@ static int __init fsg_init(void) ...@@ -4085,7 +4089,7 @@ static int __init fsg_init(void)
return rc; return rc;
fsg = the_fsg; fsg = the_fsg;
if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0) if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0)
fsg_free(fsg); kref_put(&fsg->ref, fsg_release);
return rc; return rc;
} }
module_init(fsg_init); module_init(fsg_init);
...@@ -4103,6 +4107,6 @@ static void __exit fsg_cleanup(void) ...@@ -4103,6 +4107,6 @@ static void __exit fsg_cleanup(void)
wait_for_completion(&fsg->thread_notifier); wait_for_completion(&fsg->thread_notifier);
close_all_backing_files(fsg); close_all_backing_files(fsg);
fsg_free(fsg); kref_put(&fsg->ref, fsg_release);
} }
module_exit(fsg_cleanup); module_exit(fsg_cleanup);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment