aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWill Deacon2020-12-15 09:18:07 -0600
committerGiuliano Procida2020-12-30 04:20:47 -0600
commit342a4badfd6a728f35328b7755da01cba49f051d (patch)
treea38e8e6ba786318c515ee8c476bfb7f581d0a143
parent3a01ad8acc2461dc42a88cd80434c8d0ba8099a5 (diff)
downloadkernel-342a4badfd6a728f35328b7755da01cba49f051d.tar.gz
kernel-342a4badfd6a728f35328b7755da01cba49f051d.tar.xz
kernel-342a4badfd6a728f35328b7755da01cba49f051d.zip
ANDROID: usb: f_accessory: Add refcounting to global 'acc_dev'
Add refcounting to track the lifetime of the global 'acc_dev' structure, as the underlying function directories can be removed while references still exist to the dev node. Bug: 173789633 Signed-off-by: Will Deacon <willdeacon@google.com> Change-Id: I248408e890d01167706c329146d63b64a6456df6 Signed-off-by: Giuliano Procida <gprocida@google.com>
-rw-r--r--drivers/usb/gadget/function/f_accessory.c38
1 files changed, 32 insertions, 6 deletions
diff --git a/drivers/usb/gadget/function/f_accessory.c b/drivers/usb/gadget/function/f_accessory.c
index 5bc32de494c8..089e27790d29 100644
--- a/drivers/usb/gadget/function/f_accessory.c
+++ b/drivers/usb/gadget/function/f_accessory.c
@@ -28,6 +28,7 @@
28#include <linux/interrupt.h> 28#include <linux/interrupt.h>
29#include <linux/kthread.h> 29#include <linux/kthread.h>
30#include <linux/freezer.h> 30#include <linux/freezer.h>
31#include <linux/kref.h>
31 32
32#include <linux/types.h> 33#include <linux/types.h>
33#include <linux/file.h> 34#include <linux/file.h>
@@ -74,6 +75,7 @@ struct acc_dev {
74 struct usb_function function; 75 struct usb_function function;
75 struct usb_composite_dev *cdev; 76 struct usb_composite_dev *cdev;
76 spinlock_t lock; 77 spinlock_t lock;
78 struct acc_dev_ref *ref;
77 79
78 struct usb_ep *ep_in; 80 struct usb_ep *ep_in;
79 struct usb_ep *ep_out; 81 struct usb_ep *ep_out;
@@ -274,7 +276,14 @@ static struct usb_gadget_strings *acc_strings[] = {
274 NULL, 276 NULL,
275}; 277};
276 278
277static struct acc_dev *_acc_dev; 279struct acc_dev_ref {
280 struct kref kref;
281 struct acc_dev *acc_dev;
282};
283
284static struct acc_dev_ref _acc_dev_ref = {
285 .kref = KREF_INIT(0),
286};
278 287
279struct acc_instance { 288struct acc_instance {
280 struct usb_function_instance func_inst; 289 struct usb_function_instance func_inst;
@@ -283,11 +292,26 @@ struct acc_instance {
283 292
284static struct acc_dev *get_acc_dev(void) 293static struct acc_dev *get_acc_dev(void)
285{ 294{
286 return _acc_dev; 295 struct acc_dev_ref *ref = &_acc_dev_ref;
296
297 return kref_get_unless_zero(&ref->kref) ? ref->acc_dev : NULL;
298}
299
300static void __put_acc_dev(struct kref *kref)
301{
302 struct acc_dev_ref *ref = container_of(kref, struct acc_dev_ref, kref);
303 struct acc_dev *dev = ref->acc_dev;
304
305 ref->acc_dev = NULL;
306 kfree(dev);
287} 307}
288 308
289static void put_acc_dev(struct acc_dev *dev) 309static void put_acc_dev(struct acc_dev *dev)
290{ 310{
311 struct acc_dev_ref *ref = dev->ref;
312
313 WARN_ON(ref->acc_dev != dev);
314 kref_put(&ref->kref, __put_acc_dev);
291} 315}
292 316
293static inline struct acc_dev *func_to_dev(struct usb_function *f) 317static inline struct acc_dev *func_to_dev(struct usb_function *f)
@@ -1321,6 +1345,7 @@ static void acc_function_disable(struct usb_function *f)
1321 1345
1322static int acc_setup(void) 1346static int acc_setup(void)
1323{ 1347{
1348 struct acc_dev_ref *ref = &_acc_dev_ref;
1324 struct acc_dev *dev; 1349 struct acc_dev *dev;
1325 int ret; 1350 int ret;
1326 1351
@@ -1341,7 +1366,9 @@ static int acc_setup(void)
1341 INIT_WORK(&dev->getprotocol_work, acc_getprotocol_work); 1366 INIT_WORK(&dev->getprotocol_work, acc_getprotocol_work);
1342 INIT_WORK(&dev->sendstring_work, acc_sendstring_work); 1367 INIT_WORK(&dev->sendstring_work, acc_sendstring_work);
1343 1368
1344 _acc_dev = dev; 1369 dev->ref = ref;
1370 kref_init(&ref->kref);
1371 ref->acc_dev = dev;
1345 1372
1346 ret = misc_register(&acc_device); 1373 ret = misc_register(&acc_device);
1347 if (ret) 1374 if (ret)
@@ -1369,12 +1396,11 @@ EXPORT_SYMBOL_GPL(acc_disconnect);
1369 1396
1370static void acc_cleanup(void) 1397static void acc_cleanup(void)
1371{ 1398{
1372 struct acc_dev *dev = _acc_dev; 1399 struct acc_dev *dev = get_acc_dev();
1373 1400
1374 misc_deregister(&acc_device); 1401 misc_deregister(&acc_device);
1375 put_acc_dev(dev); 1402 put_acc_dev(dev);
1376 kfree(dev); 1403 put_acc_dev(dev); /* Pairs with kref_init() in acc_setup() */
1377 _acc_dev = NULL;
1378} 1404}
1379static struct acc_instance *to_acc_instance(struct config_item *item) 1405static struct acc_instance *to_acc_instance(struct config_item *item)
1380{ 1406{