lkml.org 
[lkml]   [2013]   [May]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH 19/21] aio/usb: Update cancellation for new synchonization
Date
Previous patch got rid of kiocb->ki_users; this was done by having
kiocb_cancel()/aio_complete() explicitly synchronize with each other.

The new rule is that when a driver calls aio_complete(), after
aio_complete() returns ki_cancel cannot be running and it's safe to
dispose of kiocb->priv. But, this means ki_cancel() won't be able to
call aio_complete() itself, or aio_complete() will deadlock.

So, update the driver.

Signed-off-by: Kent Overstreet <koverstreet@google.com>
Cc: Zach Brown <zab@redhat.com>
Cc: Felipe Balbi <balbi@ti.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Mark Fasheh <mfasheh@suse.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Asai Thambi S P <asamymuthupa@micron.com>
Cc: Selvan Mani <smani@micron.com>
Cc: Sam Bradshaw <sbradshaw@micron.com>
Cc: Jeff Moyer <jmoyer@redhat.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Benjamin LaHaise <bcrl@kvack.org>
---
drivers/usb/gadget/inode.c | 61 +++++++++++++++++++++-------------------------
1 file changed, 28 insertions(+), 33 deletions(-)

diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index f255ad7..69adb87 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -522,6 +522,7 @@ struct kiocb_priv {
const struct iovec *iv;
unsigned long nr_segs;
unsigned actual;
+ int status;
};

static int ep_aio_cancel(struct kiocb *iocb)
@@ -577,14 +578,26 @@ static void ep_user_copy_worker(struct work_struct *work)
struct kiocb_priv *priv = container_of(work, struct kiocb_priv, work);
struct mm_struct *mm = priv->mm;
struct kiocb *iocb = priv->iocb;
- size_t ret;

- use_mm(mm);
- ret = ep_copy_to_user(priv);
- unuse_mm(mm);
+ if (priv->iv && priv->actual) {
+ size_t ret;
+
+ use_mm(mm);
+ ret = ep_copy_to_user(priv);
+ unuse_mm(mm);
+
+ if (!priv->status)
+ priv->status = ret;
+ /*
+ * completing the iocb can drop the ctx and mm, don't touch mm
+ * after
+ */
+ }

- /* completing the iocb can drop the ctx and mm, don't touch mm after */
- aio_complete(iocb, ret, ret);
+
+ /* aio_complete() reports bytes-transferred _and_ faults */
+ aio_complete(iocb, priv->actual ? priv->actual : priv->status,
+ priv->status);

kfree(priv->buf);
kfree(priv);
@@ -596,36 +609,18 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
struct kiocb_priv *priv = iocb->private;
struct ep_data *epdata = priv->epdata;

- /* lock against disconnect (and ideally, cancel) */
- spin_lock(&epdata->dev->lock);
- priv->req = NULL;
- priv->epdata = NULL;
-
- /* if this was a write or a read returning no data then we
- * don't need to copy anything to userspace, so we can
- * complete the aio request immediately.
- */
- if (priv->iv == NULL || unlikely(req->actual == 0)) {
- kfree(req->buf);
- kfree(priv);
- iocb->private = NULL;
- /* aio_complete() reports bytes-transferred _and_ faults */
- aio_complete(iocb, req->actual ? req->actual : req->status,
- req->status);
- } else {
- /* ep_copy_to_user() won't report both; we hide some faults */
- if (unlikely(0 != req->status))
- DBG(epdata->dev, "%s fault %d len %d\n",
- ep->name, req->status, req->actual);
-
- priv->buf = req->buf;
- priv->actual = req->actual;
- schedule_work(&priv->work);
- }
- spin_unlock(&epdata->dev->lock);
+ priv->buf = req->buf;
+ priv->actual = req->actual;
+ priv->status = req->status;

usb_ep_free_request(ep, req);
put_ep(epdata);
+
+ if ((priv->iv && priv->actual) ||
+ iocb->ki_cancel == KIOCB_CANCELLING)
+ schedule_work(&priv->work);
+ else
+ ep_user_copy_worker(&priv->work);
}

static ssize_t
--
1.8.2.1


\
 
 \ /
  Last update: 2013-05-14 03:41    [W:0.244 / U:0.120 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site