usb: f_fs: refactor ffs_epfile_io
Eliminate one of the return paths by using a ‘goto error_mutex’ and
rearrange some if-bodies which results in reduction of the indention level
and thus hopefully makes the function easier to read and reason about.
Signed-off-by: Michal Nazarewicz <mina86@mina86.com>
Signed-off-by: Felipe Balbi <balbi@kernel.org>
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index c4e6395..63fe693 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -684,6 +684,7 @@
static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
{
struct ffs_epfile *epfile = file->private_data;
+ struct usb_request *req;
struct ffs_ep *ep;
char *data = NULL;
ssize_t ret, data_len = -EINVAL;
@@ -713,7 +714,8 @@
if (!halt) {
/*
* if we _do_ wait above, the epfile->ffs->gadget might be NULL
- * before the waiting completes, so do not assign to 'gadget' earlier
+ * before the waiting completes, so do not assign to 'gadget'
+ * earlier
*/
struct usb_gadget *gadget = epfile->ffs->gadget;
size_t copied;
@@ -755,17 +757,12 @@
if (epfile->ep != ep) {
/* In the meantime, endpoint got disabled or changed. */
ret = -ESHUTDOWN;
- goto error_lock;
} else if (halt) {
/* Halt */
if (likely(epfile->ep == ep) && !WARN_ON(!ep->ep))
usb_ep_set_halt(ep->ep);
- spin_unlock_irq(&epfile->ffs->eps_lock);
ret = -EBADMSG;
- } else {
- /* Fire the request */
- struct usb_request *req;
-
+ } else if (unlikely(data_len == -EINVAL)) {
/*
* Sanity Check: even though data_len can't be used
* uninitialized at the time I write this comment, some
@@ -777,82 +774,74 @@
* For such reason, we're adding this redundant sanity check
* here.
*/
- if (unlikely(data_len == -EINVAL)) {
- WARN(1, "%s: data_len == -EINVAL\n", __func__);
- ret = -EINVAL;
+ WARN(1, "%s: data_len == -EINVAL\n", __func__);
+ ret = -EINVAL;
+ } else if (!io_data->aio) {
+ DECLARE_COMPLETION_ONSTACK(done);
+
+ req = ep->req;
+ req->buf = data;
+ req->length = data_len;
+
+ req->context = &done;
+ req->complete = ffs_epfile_io_complete;
+
+ ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
+ if (unlikely(ret < 0))
+ goto error_lock;
+
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+
+ if (unlikely(wait_for_completion_interruptible(&done))) {
+ ret = -EINTR;
+ usb_ep_dequeue(ep->ep, req);
+ goto error_mutex;
+ }
+
+ /*
+ * XXX We may end up silently droping data here. Since data_len
+ * (i.e. req->length) may be bigger than len (after being
+ * rounded up to maxpacketsize), we may end up with more data
+ * then user space has space for.
+ */
+ ret = ep->status;
+ if (io_data->read && ret > 0) {
+ ret = copy_to_iter(data, ret, &io_data->data);
+ if (!ret)
+ ret = -EFAULT;
+ }
+ goto error_mutex;
+ } else if (!(req = usb_ep_alloc_request(ep->ep, GFP_KERNEL))) {
+ ret = -ENOMEM;
+ } else {
+ req->buf = data;
+ req->length = data_len;
+
+ io_data->buf = data;
+ io_data->ep = ep->ep;
+ io_data->req = req;
+ io_data->ffs = epfile->ffs;
+
+ req->context = io_data;
+ req->complete = ffs_epfile_async_io_complete;
+
+ ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
+ if (unlikely(ret)) {
+ usb_ep_free_request(ep->ep, req);
goto error_lock;
}
- if (io_data->aio) {
- req = usb_ep_alloc_request(ep->ep, GFP_KERNEL);
- if (unlikely(!req)) {
- ret = -ENOMEM;
- goto error_lock;
- }
-
- req->buf = data;
- req->length = data_len;
-
- io_data->buf = data;
- io_data->ep = ep->ep;
- io_data->req = req;
- io_data->ffs = epfile->ffs;
-
- req->context = io_data;
- req->complete = ffs_epfile_async_io_complete;
-
- ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
- if (unlikely(ret)) {
- usb_ep_free_request(ep->ep, req);
- goto error_lock;
- }
- ret = -EIOCBQUEUED;
-
- spin_unlock_irq(&epfile->ffs->eps_lock);
- } else {
- DECLARE_COMPLETION_ONSTACK(done);
-
- req = ep->req;
- req->buf = data;
- req->length = data_len;
-
- req->context = &done;
- req->complete = ffs_epfile_io_complete;
-
- ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
-
- spin_unlock_irq(&epfile->ffs->eps_lock);
-
- if (unlikely(ret < 0)) {
- /* nop */
- } else if (unlikely(
- wait_for_completion_interruptible(&done))) {
- ret = -EINTR;
- usb_ep_dequeue(ep->ep, req);
- } else {
- /*
- * XXX We may end up silently droping data
- * here. Since data_len (i.e. req->length) may
- * be bigger than len (after being rounded up
- * to maxpacketsize), we may end up with more
- * data then user space has space for.
- */
- ret = ep->status;
- if (io_data->read && ret > 0) {
- ret = copy_to_iter(data, ret, &io_data->data);
- if (!ret)
- ret = -EFAULT;
- }
- }
- kfree(data);
- }
+ ret = -EIOCBQUEUED;
+ /*
+ * Do not kfree the buffer in this function. It will be freed
+ * by ffs_user_copy_worker.
+ */
+ data = NULL;
}
- mutex_unlock(&epfile->mutex);
- return ret;
-
error_lock:
spin_unlock_irq(&epfile->ffs->eps_lock);
+error_mutex:
mutex_unlock(&epfile->mutex);
error:
kfree(data);