aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZach Brown <zab@redhat.com>2013-05-07 19:18:23 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-05-07 21:38:27 -0400
commita80bf61ef36da48285850974f30700d1e8efbfc0 (patch)
treeb9166b0fda8921655003bf73127cfb784d1878ff
parent4b49bb8ad6d6e6e564017e2fad2357c3024683eb (diff)
gadget: remove only user of aio retry
This removes the only in-tree user of aio retry. This will let us remove the retry code from the aio core. Removing retry is relatively easy as the USB gadget wasn't using it to retry IOs at all. It always fully submitted the IO in the context of the initial io_submit() call. It only used the AIO retry facility to get the submitter's mm context for copying the result of a read back to user space. This is easy to implement with use_mm() and a work struct, much like kvm does with async_pf_execute() for get_user_pages(). [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Zach Brown <zab@redhat.com> Signed-off-by: Kent Overstreet <koverstreet@google.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> Acked-by: Jeff Moyer <jmoyer@redhat.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Benjamin LaHaise <bcrl@kvack.org> Cc: Theodore Ts'o <tytso@mit.edu> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/usb/gadget/inode.c38
1 files changed, 29 insertions, 9 deletions
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index dda0dc4a5567..32bcbeba119e 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -24,6 +24,7 @@
24#include <linux/sched.h> 24#include <linux/sched.h>
25#include <linux/slab.h> 25#include <linux/slab.h>
26#include <linux/poll.h> 26#include <linux/poll.h>
27#include <linux/mmu_context.h>
27 28
28#include <linux/device.h> 29#include <linux/device.h>
29#include <linux/moduleparam.h> 30#include <linux/moduleparam.h>
@@ -513,6 +514,9 @@ static long ep_ioctl(struct file *fd, unsigned code, unsigned long value)
513struct kiocb_priv { 514struct kiocb_priv {
514 struct usb_request *req; 515 struct usb_request *req;
515 struct ep_data *epdata; 516 struct ep_data *epdata;
517 struct kiocb *iocb;
518 struct mm_struct *mm;
519 struct work_struct work;
516 void *buf; 520 void *buf;
517 const struct iovec *iv; 521 const struct iovec *iv;
518 unsigned long nr_segs; 522 unsigned long nr_segs;
@@ -540,15 +544,12 @@ static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e)
540 return value; 544 return value;
541} 545}
542 546
543static ssize_t ep_aio_read_retry(struct kiocb *iocb) 547static ssize_t ep_copy_to_user(struct kiocb_priv *priv)
544{ 548{
545 struct kiocb_priv *priv = iocb->private;
546 ssize_t len, total; 549 ssize_t len, total;
547 void *to_copy; 550 void *to_copy;
548 int i; 551 int i;
549 552
550 /* we "retry" to get the right mm context for this: */
551
552 /* copy stuff into user buffers */ 553 /* copy stuff into user buffers */
553 total = priv->actual; 554 total = priv->actual;
554 len = 0; 555 len = 0;
@@ -568,9 +569,26 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb)
568 if (total == 0) 569 if (total == 0)
569 break; 570 break;
570 } 571 }
572
573 return len;
574}
575
576static void ep_user_copy_worker(struct work_struct *work)
577{
578 struct kiocb_priv *priv = container_of(work, struct kiocb_priv, work);
579 struct mm_struct *mm = priv->mm;
580 struct kiocb *iocb = priv->iocb;
581 size_t ret;
582
583 use_mm(mm);
584 ret = ep_copy_to_user(priv);
585 unuse_mm(mm);
586
587 /* completing the iocb can drop the ctx and mm, don't touch mm after */
588 aio_complete(iocb, ret, ret);
589
571 kfree(priv->buf); 590 kfree(priv->buf);
572 kfree(priv); 591 kfree(priv);
573 return len;
574} 592}
575 593
576static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) 594static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
@@ -596,14 +614,14 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
596 aio_complete(iocb, req->actual ? req->actual : req->status, 614 aio_complete(iocb, req->actual ? req->actual : req->status,
597 req->status); 615 req->status);
598 } else { 616 } else {
599 /* retry() won't report both; so we hide some faults */ 617 /* ep_copy_to_user() won't report both; we hide some faults */
600 if (unlikely(0 != req->status)) 618 if (unlikely(0 != req->status))
601 DBG(epdata->dev, "%s fault %d len %d\n", 619 DBG(epdata->dev, "%s fault %d len %d\n",
602 ep->name, req->status, req->actual); 620 ep->name, req->status, req->actual);
603 621
604 priv->buf = req->buf; 622 priv->buf = req->buf;
605 priv->actual = req->actual; 623 priv->actual = req->actual;
606 kick_iocb(iocb); 624 schedule_work(&priv->work);
607 } 625 }
608 spin_unlock(&epdata->dev->lock); 626 spin_unlock(&epdata->dev->lock);
609 627
@@ -633,8 +651,10 @@ fail:
633 return value; 651 return value;
634 } 652 }
635 iocb->private = priv; 653 iocb->private = priv;
654 priv->iocb = iocb;
636 priv->iv = iv; 655 priv->iv = iv;
637 priv->nr_segs = nr_segs; 656 priv->nr_segs = nr_segs;
657 INIT_WORK(&priv->work, ep_user_copy_worker);
638 658
639 value = get_ready_ep(iocb->ki_filp->f_flags, epdata); 659 value = get_ready_ep(iocb->ki_filp->f_flags, epdata);
640 if (unlikely(value < 0)) { 660 if (unlikely(value < 0)) {
@@ -646,6 +666,7 @@ fail:
646 get_ep(epdata); 666 get_ep(epdata);
647 priv->epdata = epdata; 667 priv->epdata = epdata;
648 priv->actual = 0; 668 priv->actual = 0;
669 priv->mm = current->mm; /* mm teardown waits for iocbs in exit_aio() */
649 670
650 /* each kiocb is coupled to one usb_request, but we can't 671 /* each kiocb is coupled to one usb_request, but we can't
651 * allocate or submit those if the host disconnected. 672 * allocate or submit those if the host disconnected.
@@ -674,7 +695,7 @@ fail:
674 kfree(priv); 695 kfree(priv);
675 put_ep(epdata); 696 put_ep(epdata);
676 } else 697 } else
677 value = (iv ? -EIOCBRETRY : -EIOCBQUEUED); 698 value = -EIOCBQUEUED;
678 return value; 699 return value;
679} 700}
680 701
@@ -692,7 +713,6 @@ ep_aio_read(struct kiocb *iocb, const struct iovec *iov,
692 if (unlikely(!buf)) 713 if (unlikely(!buf))
693 return -ENOMEM; 714 return -ENOMEM;
694 715
695 iocb->ki_retry = ep_aio_read_retry;
696 return ep_aio_rwtail(iocb, buf, iocb->ki_left, epdata, iov, nr_segs); 716 return ep_aio_rwtail(iocb, buf, iocb->ki_left, epdata, iov, nr_segs);
697} 717}
698 718