Linux USB
 help / color / mirror / Atom feed
* [PATCH 0/3] usb: gadget: f_fs: cancellation and mm fixes
@ 2026-09-01 12:09 Ingo Rohloff
  2026-09-01 12:09 ` [PATCH 1/3] usb: gadget: f_fs: simplify error handling using goto Ingo Rohloff
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Ingo Rohloff @ 2026-09-01 12:09 UTC (permalink / raw)
  To: gregkh; +Cc: viro, nkapron, me, michael.bommarito, linux-usb, Ingo Rohloff

This 3 part patch series does some mini refactoring and
fixes two previous commits.

Ingo Rohloff (3):
  usb: gadget: f_fs: simplify error handling using goto
  usb: gadget: f_fs: register cancellation handler only after request
    queueing
  usb: gadget: f_fs: Fix mmgrab()/mmdrop() balance.

 drivers/usb/gadget/function/f_fs.c | 132 +++++++++++++++--------------
 1 file changed, 68 insertions(+), 64 deletions(-)

--
2.55.0

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/3] usb: gadget: f_fs: simplify error handling using goto
  2026-09-01 12:09 [PATCH 0/3] usb: gadget: f_fs: cancellation and mm fixes Ingo Rohloff
@ 2026-09-01 12:09 ` Ingo Rohloff
  2026-11-06 23:13   ` Neill Kapron
  2026-09-01 12:09 ` [PATCH 2/3] usb: gadget: f_fs: register cancellation handler only after request queueing Ingo Rohloff
  2026-09-01 12:09 ` [PATCH 3/3] usb: gadget: f_fs: Fix mmgrab()/mmdrop() balance Ingo Rohloff
  2 siblings, 1 reply; 10+ messages in thread
From: Ingo Rohloff @ 2026-09-01 12:09 UTC (permalink / raw)
  To: gregkh; +Cc: viro, nkapron, me, michael.bommarito, linux-usb, Ingo Rohloff

Refactor conditional checks to use direct error returns/gotos instead of a
long if/else chain. This makes failure paths more obvious.

At the end of the function AIO request handling is done.

Signed-off-by: Ingo Rohloff <ingo.rohloff@lauterbach.com>
---
 drivers/usb/gadget/function/f_fs.c | 80 ++++++++++++++++++------------
 1 file changed, 47 insertions(+), 33 deletions(-)

diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 43962e05eacf..76fba3085664 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -1104,11 +1104,17 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
 	if (epfile->ep != ep) {
 		/* In the meantime, endpoint got disabled or changed. */
 		ret = -ESHUTDOWN;
-	} else if (halt) {
+		goto error_lock;
+	}
+
+	if (halt) {
 		ret = usb_ep_set_halt(ep->ep);
 		if (!ret)
 			ret = -EBADMSG;
-	} else if (data_len == -EINVAL) {
+		goto error_lock;
+	}
+
+	if (data_len == -EINVAL) {
 		/*
 		 * Sanity Check: even though data_len can't be used
 		 * uninitialized at the time I write this comment, some
@@ -1122,7 +1128,10 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
 		 */
 		WARN(1, "%s: data_len == -EINVAL\n", __func__);
 		ret = -EINVAL;
-	} else if (!io_data->aio) {
+		goto error_lock;
+	}
+
+	if (!io_data->aio) {
 		bool interrupted = false;
 
 		req = ep->req;
@@ -1176,44 +1185,49 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
 		else
 			ret = io_data->status;
 		goto error_mutex;
-	} else if (!(req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC))) {
+	}
+
+	// It's an AIO request
+	req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC);
+	if (!req) {
 		ret = -ENOMEM;
-	} else {
-		if (io_data->use_sg) {
-			req->buf = NULL;
-			req->sg	= io_data->sgt.sgl;
-			req->num_sgs = io_data->sgt.nents;
-		} else {
-			req->buf = data;
-			req->num_sgs = 0;
-		}
+		goto error_lock;
+	}
 
-		req->zero = !io_data->read ? epfile->zlp_enabled : 0;
-		req->length = data_len;
+	if (io_data->use_sg) {
+		req->buf = NULL;
+		req->sg = io_data->sgt.sgl;
+		req->num_sgs = io_data->sgt.nents;
+	} else {
+		req->buf = data;
+		req->num_sgs = 0;
+	}
 
-		io_data->buf = data;
-		io_data->ep = ep->ep;
-		io_data->req = req;
-		io_data->ffs = epfile->ffs;
+	req->zero = !io_data->read ? epfile->zlp_enabled : 0;
+	req->length = data_len;
 
-		req->context  = io_data;
-		req->complete = ffs_epfile_async_io_complete;
+	io_data->buf = data;
+	io_data->ep = ep->ep;
+	io_data->req = req;
+	io_data->ffs = epfile->ffs;
 
-		ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
-		if (ret) {
-			io_data->req = NULL;
-			usb_ep_free_request(ep->ep, req);
-			goto error_lock;
-		}
+	req->context  = io_data;
+	req->complete = ffs_epfile_async_io_complete;
 
-		ret = -EIOCBQUEUED;
-		/*
-		 * Do not kfree the buffer in this function.  It will be freed
-		 * by ffs_user_copy_worker.
-		 */
-		data = NULL;
+	ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
+	if (ret) {
+		io_data->req = NULL;
+		usb_ep_free_request(ep->ep, req);
+		goto error_lock;
 	}
 
+	ret = -EIOCBQUEUED;
+	/*
+	 * Do not kfree the buffer in this function.  It will be freed
+	 * by ffs_user_copy_worker.
+	 */
+	data = NULL;
+
 error_lock:
 	spin_unlock_irq(&epfile->ffs->eps_lock);
 error_mutex:
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/3] usb: gadget: f_fs: register cancellation handler only after request queueing
  2026-09-01 12:09 [PATCH 0/3] usb: gadget: f_fs: cancellation and mm fixes Ingo Rohloff
  2026-09-01 12:09 ` [PATCH 1/3] usb: gadget: f_fs: simplify error handling using goto Ingo Rohloff
@ 2026-09-01 12:09 ` Ingo Rohloff
  2026-11-06 22:47   ` Neill Kapron
  2026-09-01 12:09 ` [PATCH 3/3] usb: gadget: f_fs: Fix mmgrab()/mmdrop() balance Ingo Rohloff
  2 siblings, 1 reply; 10+ messages in thread
From: Ingo Rohloff @ 2026-09-01 12:09 UTC (permalink / raw)
  To: gregkh; +Cc: viro, nkapron, me, michael.bommarito, linux-usb, Ingo Rohloff

Call kiocb_set_cancel_fn() only after usb_ep_queue() completes
successfully.

This also undoes commit e78dcb1f7ec2 ("usb: gadget: f_fs: Fix
Use-After-Free in AIO error path"): The described error is avoided by
making sure the cancellation handler is only registered, if there is
something to cancel.

Registering the cancellation handler adds the kiocb to the context's
active request list (active_reqs in aio.c).  If usb_ep_queue() fails, the
request was never actually submitted to the hardware, which means the
request is not active.  The aio framework already deals with calling the
completion function ki_complete() automatically if you do not return
-EIOCBQUEUED.

Signed-off-by: Ingo Rohloff <ingo.rohloff@lauterbach.com>
---
 drivers/usb/gadget/function/f_fs.c | 50 ++++++++++++------------------
 1 file changed, 20 insertions(+), 30 deletions(-)

diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 76fba3085664..9dec09d06ca9 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -1014,8 +1014,21 @@ static struct ffs_ep *ffs_epfile_wait_ep(struct ffs_epfile *epfile, struct file
 	return ep;
 }
 
-static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
+static int ffs_aio_cancel(struct kiocb *kiocb)
 {
+	struct ffs_io_data *io_data = kiocb->private;
+	int value;
+
+	if (!io_data || !io_data->ep || !io_data->req)
+		return -EINVAL;
+
+	value = usb_ep_dequeue(io_data->ep, io_data->req);
+	return value;
+}
+
+static ssize_t ffs_epfile_io(struct kiocb *kiocb, struct ffs_io_data *io_data)
+{
+	struct file *file = kiocb->ki_filp;
 	struct ffs_epfile *epfile = file->private_data;
 	struct usb_request *req;
 	struct ffs_ep *ep;
@@ -1227,6 +1240,8 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
 	 * by ffs_user_copy_worker.
 	 */
 	data = NULL;
+	kiocb->private = io_data;
+	kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
 
 error_lock:
 	spin_unlock_irq(&epfile->ffs->eps_lock);
@@ -1266,19 +1281,6 @@ ffs_epfile_open(struct inode *inode, struct file *file)
 	return stream_open(inode, file);
 }
 
-static int ffs_aio_cancel(struct kiocb *kiocb)
-{
-	struct ffs_io_data *io_data = kiocb->private;
-	int value;
-
-	if (io_data && io_data->ep && io_data->req)
-		value = usb_ep_dequeue(io_data->ep, io_data->req);
-	else
-		value = -EINVAL;
-
-	return value;
-}
-
 static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from)
 {
 	struct ffs_io_data io_data, *p = &io_data;
@@ -1299,21 +1301,15 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from)
 	p->data = *from;
 	p->mm = current->mm;
 
-	kiocb->private = p;
-
-	if (p->aio) {
+	if (p->aio)
 		mmgrab(p->mm);
-		kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
-	}
 
-	res = ffs_epfile_io(kiocb->ki_filp, p);
+	res = ffs_epfile_io(kiocb, p);
 	if (res == -EIOCBQUEUED)
 		return res;
 	if (p->aio) {
-		kiocb->ki_complete(kiocb, res);
 		mmdrop(p->mm);
 		kfree(p);
-		return -EIOCBQUEUED;
 	} else {
 		*from = p->data;
 	}
@@ -1349,23 +1345,17 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to)
 	}
 	p->mm = current->mm;
 
-	kiocb->private = p;
-
-	if (p->aio) {
+	if (p->aio)
 		mmgrab(p->mm);
-		kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
-	}
 
-	res = ffs_epfile_io(kiocb->ki_filp, p);
+	res = ffs_epfile_io(kiocb, p);
 	if (res == -EIOCBQUEUED)
 		return res;
 
 	if (p->aio) {
-		kiocb->ki_complete(kiocb, res);
 		mmdrop(p->mm);
 		kfree(p->to_free);
 		kfree(p);
-		return -EIOCBQUEUED;
 	} else {
 		*to = p->data;
 	}
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/3] usb: gadget: f_fs: Fix mmgrab()/mmdrop() balance.
  2026-09-01 12:09 [PATCH 0/3] usb: gadget: f_fs: cancellation and mm fixes Ingo Rohloff
  2026-09-01 12:09 ` [PATCH 1/3] usb: gadget: f_fs: simplify error handling using goto Ingo Rohloff
  2026-09-01 12:09 ` [PATCH 2/3] usb: gadget: f_fs: register cancellation handler only after request queueing Ingo Rohloff
@ 2026-09-01 12:09 ` Ingo Rohloff
  2026-10-30  8:19   ` Hongyu Xie
  2026-11-06 22:53   ` Neill Kapron
  2 siblings, 2 replies; 10+ messages in thread
From: Ingo Rohloff @ 2026-09-01 12:09 UTC (permalink / raw)
  To: gregkh; +Cc: viro, nkapron, me, michael.bommarito, linux-usb, Ingo Rohloff

This fixes commit 5eb5c72c72fe ("USB: gadget: ffs: fix mm lifetime
handling").  The problem is that the previous patch calls mmgrab() for
reads and writes, but it only calls mmdrop() for reads.  So with each
completed async IO write (via an USB IN endpoint) the number of mm_count
increases.

Signed-off-by: Ingo Rohloff <ingo.rohloff@lauterbach.com>
---
 drivers/usb/gadget/function/f_fs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 9dec09d06ca9..0be989c7c23f 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -884,8 +884,8 @@ static void ffs_user_copy_worker(struct work_struct *work)
 		} else {
 			ret = -EFAULT;
 		}
-		mmdrop(io_data->mm);
 	}
+	mmdrop(io_data->mm);
 
 	io_data->kiocb->ki_complete(io_data->kiocb, ret);
 
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/3] usb: gadget: f_fs: Fix mmgrab()/mmdrop() balance.
  2026-09-01 12:09 ` [PATCH 3/3] usb: gadget: f_fs: Fix mmgrab()/mmdrop() balance Ingo Rohloff
@ 2026-10-30  8:19   ` Hongyu Xie
  2026-11-06 22:53   ` Neill Kapron
  1 sibling, 0 replies; 10+ messages in thread
From: Hongyu Xie @ 2026-10-30  8:19 UTC (permalink / raw)
  To: Ingo Rohloff; +Cc: Greg Kroah-Hartman, linux-usb, linux-kernel

Hi Ingo,

I ran into the same imbalance while carrying a backport of 5eb5c72c72fe in
a 5.10-based product tree, and your analysis matches what I see.

mmgrab() is taken in both ffs_epfile_read_iter() and ffs_epfile_write_iter()
when the request is queued for AIO, but ffs_user_copy_worker() drops the
reference only inside

	if (io_data->read && ret > 0)

so the reference is lost on every completed AIO write, and also on an AIO
read that completes with ret <= 0. Moving mmdrop() out of the block fixes
both cases, and it stays balanced with the mmgrab() in the iter functions.

The released stable trees carry the same code: 6.6.160, 6.12.111, 7.2.y and
rolling-lts (6.18.y) all still have mmdrop() inside the if. 5.10.y and
5.15.y are not affected, they still use the older kthread_use_mm() code
without mmgrab().

It would help to add

	Fixes: 5eb5c72c72fe ("USB: gadget: ffs: fix mm lifetime handling")
	Cc: stable@vger.kernel.org

so the stable trees pick it up; the change itself applies there with only
offset differences.

Reviewed-by: Hongyu Xie <xiehongyu1@kylinos.cn>

Thanks,
Hongyu

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] usb: gadget: f_fs: register cancellation handler only after request queueing
  2026-09-01 12:09 ` [PATCH 2/3] usb: gadget: f_fs: register cancellation handler only after request queueing Ingo Rohloff
@ 2026-11-06 22:47   ` Neill Kapron
  2026-11-09 11:31     ` Ingo Rohloff
  0 siblings, 1 reply; 10+ messages in thread
From: Neill Kapron @ 2026-11-06 22:47 UTC (permalink / raw)
  To: Ingo Rohloff; +Cc: gregkh, viro, me, michael.bommarito, linux-usb

On Tue, Sep 01, 2026 at 02:09:07PM +0200, Ingo Rohloff wrote:
> Call kiocb_set_cancel_fn() only after usb_ep_queue() completes
> successfully.
> 
> This also undoes commit e78dcb1f7ec2 ("usb: gadget: f_fs: Fix
> Use-After-Free in AIO error path"): The described error is avoided by
> making sure the cancellation handler is only registered, if there is
> something to cancel.

Hi Ingo,

Unfortunately, I don't think this is safe. The cancel handler has to be
set before the request is queued. 

Moving the registration to just before usb_ep_queue() would close the
potential race, but if the queue fails, you still have to unwind- the
kiocb is already on active_reqs, so it has to be removed before io_data
is freed. 

That ends up more complex than what we have today, so I'm going to NAK
this patch.

Thanks,
Neill


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/3] usb: gadget: f_fs: Fix mmgrab()/mmdrop() balance.
  2026-09-01 12:09 ` [PATCH 3/3] usb: gadget: f_fs: Fix mmgrab()/mmdrop() balance Ingo Rohloff
  2026-10-30  8:19   ` Hongyu Xie
@ 2026-11-06 22:53   ` Neill Kapron
  1 sibling, 0 replies; 10+ messages in thread
From: Neill Kapron @ 2026-11-06 22:53 UTC (permalink / raw)
  To: Ingo Rohloff; +Cc: gregkh, viro, me, michael.bommarito, linux-usb, xiehongyu1

On Tue, Sep 01, 2026 at 02:09:08PM +0200, Ingo Rohloff wrote:
> This fixes commit 5eb5c72c72fe ("USB: gadget: ffs: fix mm lifetime
> handling").  The problem is that the previous patch calls mmgrab() for
> reads and writes, but it only calls mmdrop() for reads.  So with each
> completed async IO write (via an USB IN endpoint) the number of mm_count
> increases.
> 
> Signed-off-by: Ingo Rohloff <ingo.rohloff@lauterbach.com>
> ---
>  drivers/usb/gadget/function/f_fs.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
> index 9dec09d06ca9..0be989c7c23f 100644
> --- a/drivers/usb/gadget/function/f_fs.c
> +++ b/drivers/usb/gadget/function/f_fs.c
> @@ -884,8 +884,8 @@ static void ffs_user_copy_worker(struct work_struct *work)
>  		} else {
>  			ret = -EFAULT;
>  		}
> -		mmdrop(io_data->mm);
>  	}
> +	mmdrop(io_data->mm);
>  
>  	io_data->kiocb->ki_complete(io_data->kiocb, ret);
>  
> -- 
> 2.55.0
>

Hi Ingo,

This looks correct to me, and has been reported to me separately. Can
you resend this change on its own ahead of the rest of the series and
include the Fixes: and Cc: stable tags as Hongyu already pointed out?

With that:

Reviewed-by: Neill Kapron <nkapron@google.com>

Thanks,
Neill

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/3] usb: gadget: f_fs: simplify error handling using goto
  2026-09-01 12:09 ` [PATCH 1/3] usb: gadget: f_fs: simplify error handling using goto Ingo Rohloff
@ 2026-11-06 23:13   ` Neill Kapron
  0 siblings, 0 replies; 10+ messages in thread
From: Neill Kapron @ 2026-11-06 23:13 UTC (permalink / raw)
  To: Ingo Rohloff; +Cc: gregkh, viro, me, michael.bommarito, linux-usb

On Tue, Sep 01, 2026 at 02:09:06PM +0200, Ingo Rohloff wrote:

> +	// It's an AIO request

Nit: please use /* */ style comments to match the surrounding code.

>  
> -		req->context  = io_data;
> -		req->complete = ffs_epfile_async_io_complete;
> +	io_data->buf = data;
> +	io_data->ep = ep->ep;
> +	io_data->req = req;
> +	io_data->ffs = epfile->ffs;
>  
> -		ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
> -		if (ret) {
> -			io_data->req = NULL;
> -			usb_ep_free_request(ep->ep, req);
> -			goto error_lock;
> -		}
> +	req->context  = io_data;

Nit: since we're already changing this line, can you cleanup the double
spacing?


Other that the two minor nits above, this looks reasonable. Since patch
2 shouldn't go in, can you resend this separately with the above items
addressed?

Thanks,
Neill

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] usb: gadget: f_fs: register cancellation handler only after request queueing
  2026-11-06 22:47   ` Neill Kapron
@ 2026-11-09 11:31     ` Ingo Rohloff
  2026-11-09 16:19       ` Ingo Rohloff
  0 siblings, 1 reply; 10+ messages in thread
From: Ingo Rohloff @ 2026-11-09 11:31 UTC (permalink / raw)
  To: Neill Kapron; +Cc: gregkh, viro, me, michael.bommarito, linux-usb

Hello Neill,

On Fri, 6 Nov 2026 22:47:48 +0000
Neill Kapron <nkapron@google.com> wrote:

> On Tue, Sep 01, 2026 at 02:09:07PM +0200, Ingo Rohloff wrote:
> > Call kiocb_set_cancel_fn() only after usb_ep_queue() completes
> > successfully.
> > ...
>
> Unfortunately, I don't think this is safe. The cancel handler has to be
> set before the request is queued. 

Why do you think, that the cancel handler has to be set before 
the request is queued?

I can't find any reason for this.

I will describe this in terms of an AIO write (read is the same),
referring to the current kernel (without my patch):

The request enters the kernel via
SYSCALL_DEFINE3(io_submit
...
  io_submit_one(ctx, user_iocb, false);
    __io_submit_one(ctx, &iocb, user_iocb, req, compat);   
      ...
        case IOCB_CMD_PWRITE:
          return aio_write(&req->rw, iocb, false, compat);
      aio_write
          ...
          aio_rw_done(req, file->f_op->write_iter(req, &iter));
            file->f_op->write_iter == ffs_epfile_write_iter
        ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from)
            kiocb_set_cancel_fn(...)
            ffs_epfile_io(...)
              ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);


I can't see why you should need to call "kiocb_set_cancel_fn(...)"
before you call "usb_ep_queue()".
In fact I think that's exactly wrong:
You should **NOT** call "kiocb_set_cancel_fn(...)",
before the request is successfully queued via "usb_ep_queue()".

Unfortunately f_fs.c seems the only place where "kiocb_set_cancel_fn()"
is used, so there is no other code to compare to.

If "usb_ep_queue()" fails, then "ffs_epfile_io()"
will **NOT** return -EIOCBQUEUED.

This in turn means the code in "aio_rw_done(...)"
will call "req->ki_complete(req, ret)", because that's
what "aio_rw_done(...)" does, if you **DO NOT** return -EIOCBQUEUED.

As far as I can tell, this is exactly what we want:
The request is completed with an error,
which indicates that the request was not queued.

Because the request is completed, why should you ever
set a cancel handler for it?
So why should you call kiocb_set_cancel_fn before the
request is queued successfully?

with best regards
  Ingo

-- 

-------------------------------------------------------------------------
Dipl.-Inform.
Ingo ROHLOFF
Senior Staff Engineer
phone +49 8102 9876-142 - ingo.rohloff@lauterbach.com

Lauterbach Engineering GmbH & Co. KG
Altlaufstrasse 40, 85635 Hoehenkirchen-Siegertsbrunn, GERMANY
www.lauterbach.com

Registered Office: Hoehenkirchen-Siegertsbrunn, Germany,
Local Court: Munich, HRA 87406, VAT ID: DE246770537, 
Managing Directors: Stephan Lauterbach, Dr. Thomas Ullmann

-------------------------------------------------------------------------

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] usb: gadget: f_fs: register cancellation handler only after request queueing
  2026-11-09 11:31     ` Ingo Rohloff
@ 2026-11-09 16:19       ` Ingo Rohloff
  0 siblings, 0 replies; 10+ messages in thread
From: Ingo Rohloff @ 2026-11-09 16:19 UTC (permalink / raw)
  To: Neill Kapron; +Cc: gregkh, viro, me, michael.bommarito, linux-usb

Hello Neill,

> On Fri, 6 Nov 2026 22:47:48 +0000
> Neill Kapron <nkapron@google.com> wrote:
> 
> > On Tue, Sep 01, 2026 at 02:09:07PM +0200, Ingo Rohloff wrote:  
> > > Call kiocb_set_cancel_fn() only after usb_ep_queue() completes
> > > successfully.
> > > ...  
> >
> > Unfortunately, I don't think this is safe. The cancel handler has to be
> > set before the request is queued.  
> ...
> You should **NOT** call "kiocb_set_cancel_fn(...)",
> before the request is successfully queued via "usb_ep_queue()".

I just had another look at the code and I am even more convinced than
before that commit  ("usb: gadget: f_fs: Fix Use-After-Free in
AIO error path") is wrong. Especially this code part

	if (res == -EIOCBQUEUED)
		return res;
	/* Comment by Ingo: Code here menans there was an error */
	if (p->aio) {
		kiocb->ki_complete(kiocb, res);
		mmdrop(p->mm);
		kfree(p);
		return -EIOCBQUEUED;
	}

Returning "-EIOCBQUEUED" when in fact nothing has been queued
(because of an error) doesn't make any sense to me.

As far as I can tell, the whole point of returning "-EIOCBQUEUED" is  to tell
aio.c that something is "in progress"; which is exactly  the opposite of
what's happening here.

Returning -EIOCBQUEUED is just a hack here, to prevent
"aio_rw_done(...)" (in aio.c) from calling "kiocb->ki_complete(...)" after 
ffs_epfile_write_iter/ffs_epfile_read_iter
has returned.

with best regards
  Ingo

On Mon, 9 Nov 2026 12:31:40 +0100
Ingo Rohloff <ingo.rohloff@lauterbach.com> wrote:

> Hello Neill,
> 
> On Fri, 6 Nov 2026 22:47:48 +0000
> Neill Kapron <nkapron@google.com> wrote:
> 
> > On Tue, Sep 01, 2026 at 02:09:07PM +0200, Ingo Rohloff wrote:  
> > > Call kiocb_set_cancel_fn() only after usb_ep_queue() completes
> > > successfully.
> > > ...  
> >
> > Unfortunately, I don't think this is safe. The cancel handler has to be
> > set before the request is queued.   
> 
> Why do you think, that the cancel handler has to be set before 
> the request is queued?
> 
> I can't find any reason for this.
> 
> I will describe this in terms of an AIO write (read is the same),
> referring to the current kernel (without my patch):
> 
> The request enters the kernel via
> SYSCALL_DEFINE3(io_submit
> ...
>   io_submit_one(ctx, user_iocb, false);
>     __io_submit_one(ctx, &iocb, user_iocb, req, compat);   
>       ...
>         case IOCB_CMD_PWRITE:
>           return aio_write(&req->rw, iocb, false, compat);
>       aio_write
>           ...
>           aio_rw_done(req, file->f_op->write_iter(req, &iter));
>             file->f_op->write_iter == ffs_epfile_write_iter
>         ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from)
>             kiocb_set_cancel_fn(...)
>             ffs_epfile_io(...)
>               ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
> 
> 
> I can't see why you should need to call "kiocb_set_cancel_fn(...)"
> before you call "usb_ep_queue()".
> In fact I think that's exactly wrong:
> You should **NOT** call "kiocb_set_cancel_fn(...)",
> before the request is successfully queued via "usb_ep_queue()".
> 
> Unfortunately f_fs.c seems the only place where "kiocb_set_cancel_fn()"
> is used, so there is no other code to compare to.
> 
> If "usb_ep_queue()" fails, then "ffs_epfile_io()"
> will **NOT** return -EIOCBQUEUED.
> 
> This in turn means the code in "aio_rw_done(...)"
> will call "req->ki_complete(req, ret)", because that's
> what "aio_rw_done(...)" does, if you **DO NOT** return -EIOCBQUEUED.
> 
> As far as I can tell, this is exactly what we want:
> The request is completed with an error,
> which indicates that the request was not queued.
> 
> Because the request is completed, why should you ever
> set a cancel handler for it?
> So why should you call kiocb_set_cancel_fn before the
> request is queued successfully?
> 
> with best regards
>   Ingo
> 



-- 

-------------------------------------------------------------------------
Dipl.-Inform.
Ingo ROHLOFF
Senior Staff Engineer
phone +49 8102 9876-142 - ingo.rohloff@lauterbach.com

Lauterbach Engineering GmbH & Co. KG
Altlaufstrasse 40, 85635 Hoehenkirchen-Siegertsbrunn, GERMANY
www.lauterbach.com

Registered Office: Hoehenkirchen-Siegertsbrunn, Germany,
Local Court: Munich, HRA 87406, VAT ID: DE246770537, 
Managing Directors: Stephan Lauterbach, Dr. Thomas Ullmann

-------------------------------------------------------------------------

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-11-09 16:19 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-01 12:09 [PATCH 0/3] usb: gadget: f_fs: cancellation and mm fixes Ingo Rohloff
2026-09-01 12:09 ` [PATCH 1/3] usb: gadget: f_fs: simplify error handling using goto Ingo Rohloff
2026-11-06 23:13   ` Neill Kapron
2026-09-01 12:09 ` [PATCH 2/3] usb: gadget: f_fs: register cancellation handler only after request queueing Ingo Rohloff
2026-11-06 22:47   ` Neill Kapron
2026-11-09 11:31     ` Ingo Rohloff
2026-11-09 16:19       ` Ingo Rohloff
2026-09-01 12:09 ` [PATCH 3/3] usb: gadget: f_fs: Fix mmgrab()/mmdrop() balance Ingo Rohloff
2026-10-30  8:19   ` Hongyu Xie
2026-11-06 22:53   ` Neill Kapron

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox