linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Michal Nazarewicz <mina86@mina86.com>
To: Felipe Balbi <felipe.balbi@linux.intel.com>,
	Alan Stern <stern@rowland.harvard.edu>
Cc: "Du\, Changbin" <changbin.du@intel.com>,
	Al Viro <viro@zeniv.linux.org.uk>,
	"gregkh\@linuxfoundation.org" <gregkh@linuxfoundation.org>,
	"rui.silva\@linaro.org" <rui.silva@linaro.org>,
	"k.opasiak\@samsung.com" <k.opasiak@samsung.com>,
	"lars\@metafoo.de" <lars@metafoo.de>,
	"linux-usb\@vger.kernel.org" <linux-usb@vger.kernel.org>,
	"linux-kernel\@vger.kernel.org" <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH] usb: gadget: f_fs: report error if excess data received
Date: Mon, 16 May 2016 21:09:08 +0200	[thread overview]
Message-ID: <xa1tk2it7rcb.fsf@mina86.com> (raw)
In-Reply-To: <87bn46p2gk.fsf@linux.intel.com>

On Mon, May 16 2016, Felipe Balbi wrote:
> Michal Nazarewicz <mina86@mina86.com> writes:
>
>>> Alan Stern <stern@rowland.harvard.edu> writes:
>>>> The point is that you don't know whether the host sent more data than
>>>> expected.  All you know is that the host sent more data than the user
>>>> asked the kernel for -- but maybe the user didn't ask for all the
>>>> data that he expected.  Maybe the user wanted to retrieve the full
>>>> set of data using two read() system calls.
>>
>> On Mon, May 16 2016, Felipe Balbi wrote:
>>> right, but that just means we need to buffer the data instead of bailing
>>> out of the first read() completely.
>>
>> Correct.
>>
>> I have a ~4h bus ride ahead of me so I’ll try to implement it.  If you
>> don’t hear from me by the end of the day, there probably wasn’t enough
>> space/comfort in the bus to use a laptop.
>
> Cool, Michal. Thanks
>
> seems like a kfifo would do well here(?)

There appears to be no kfifo support for iov_iter though, so I just went
with a simple buffer.

I haven’t looked at the patch too carefully so this is an RFC rather
than an actual patch at this point.  It does compile at least.

Regardless, the more I thin about it, the more I’m under the impression
that the whole rounding up in f_fs was a mistake.  And the more I’m
leaning towards ignoring the excess data set by the host.

---------- >8 ----------------------------------------------------------
Subject: usb: gadget: f_fs: buffer data from ‘oversized’ OUT requests

f_fs rounds up read(2) requests to a multiple of a max packet size
which means that host may provide more data than user has space for.
So far, the excess data has been silently ignored.

This introduces a buffer for a tail of such requests so that they are
returned on next read instead of being ignored.

Signed-off-by: Michal Nazarewicz <mina86@mina86.com>
---
 drivers/usb/gadget/function/f_fs.c | 63 +++++++++++++++++++++++++++++++++-----
 1 file changed, 56 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 2c314c1..7d3c51a 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -130,6 +130,12 @@ struct ffs_epfile {
 
 	struct dentry			*dentry;
 
+	/*
+	 * Buffer for holding data from partial reads which may happen since
+	 * we’re rounding user read requests to a multiple of a max packet size.
+	 */
+	struct ffs_buffer		*read_buffer;
+
 	char				name[5];
 
 	unsigned char			in;	/* P: ffs->eps_lock */
@@ -138,6 +144,12 @@ struct ffs_epfile {
 	unsigned char			_pad;
 };
 
+struct ffs_buffer {
+	size_t length;
+	char *data;
+	char storage[];
+};
+
 /*  ffs_io_data structure ***************************************************/
 
 struct ffs_io_data {
@@ -681,6 +693,24 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep,
 	schedule_work(&io_data->work);
 }
 
+static ssize_t ffs_epfile_read_buffered(struct ffs_epfile *epfile,
+					struct iov_iter *iter)
+{
+	struct ffs_buffer *buf = epfile->read_buffer;
+	ssize_t ret = 0;
+	if (buf) {
+		ret = copy_to_iter(buf->data, buf->length, iter);
+		buf->length -= ret;
+		if (buf->length) {
+			buf->data += ret;
+		} else {
+			kfree(buf);
+			epfile->read_buffer = NULL;
+		}
+	}
+	return ret;
+}
+
 static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
 {
 	struct ffs_epfile *epfile = file->private_data;
@@ -710,6 +740,18 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
 	if (halt && epfile->isoc)
 		return -EINVAL;
 
+	/*
+	 * Do we have buffered data from previous partial read?  Check that for
+	 * synchronous case only because we do not have facility to ‘wake up’
+	 * a pending asynchronous read and push buffered data to it which we
+	 * would need to make things behave consistently.
+	 */
+	if (!halt && !io_data->aio && io_data->read) {
+		ret = ffs_epfile_read_buffered(epfile, &io_data->data);
+		if (ret)
+			return ret;
+	}
+
 	/* Allocate & copy */
 	if (!halt) {
 		/*
@@ -804,17 +846,24 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
 			interrupted = ep->status < 0;
 		}
 
-		/*
-		 * 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 = interrupted ? -EINTR : ep->status;
 		if (io_data->read && ret > 0) {
+			size_t left;
 			ret = copy_to_iter(data, ret, &io_data->data);
-			if (!ret)
+			left = ep->status - ret;
+			if (!left) {
+				/* nop */
+			} else if (iov_iter_count(&io_data->data)) {
 				ret = -EFAULT;
+			} else {
+				struct ffs_buffer *buf = kmalloc(
+					sizeof(*epfile->read_buffer) + left,
+					GFP_KERNEL);
+				buf->length = left;
+				buf->data = buf->storage;
+				memcpy(buf->storage, data + ret, left);
+				epfile->read_buffer = buf;
+			}
 		}
 		goto error_mutex;
 	} else if (!(req = usb_ep_alloc_request(ep->ep, GFP_KERNEL))) {
-- 
Best regards
ミハウ “𝓶𝓲𝓷𝓪86” ナザレヴイツ
«If at first you don’t succeed, give up skydiving»

  reply	other threads:[~2016-05-16 19:09 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-05-11 10:19 [PATCH] usb: gadget: f_fs: report error if excess data received changbin.du
2016-05-11 10:59 ` Felipe Balbi
2016-05-11 12:30   ` Michal Nazarewicz
2016-05-12  4:25     ` Du, Changbin
2016-05-12  4:21   ` Du, Changbin
2016-05-12  6:52     ` Felipe Balbi
2016-05-12  7:30       ` Du, Changbin
2016-05-12  7:46         ` Felipe Balbi
2016-05-12  8:16           ` Du, Changbin
2016-05-12  9:15             ` Felipe Balbi
2016-05-12  9:22               ` Felipe Balbi
2016-05-12  9:51                 ` Du, Changbin
2016-05-12  9:39               ` Du, Changbin
2016-05-12 10:13                 ` Felipe Balbi
2016-05-12 10:14                 ` Felipe Balbi
2016-05-12 10:45                   ` Du, Changbin
2016-05-12 11:22                     ` Felipe Balbi
2016-05-13  5:52                       ` Du, Changbin
2016-05-13  6:36                         ` Felipe Balbi
2016-05-13 10:32                           ` Du, Changbin
2016-05-13 14:29                           ` Alan Stern
2016-05-14 20:39                             ` Michal Nazarewicz
2016-05-16 12:57                             ` Felipe Balbi
2016-05-16 13:08                               ` Michal Nazarewicz
2016-05-16 13:16                                 ` Felipe Balbi
2016-05-16 19:09                                   ` Michal Nazarewicz [this message]
2016-05-17  2:53                                     ` Du, Changbin
2016-05-18  9:45                                       ` Michal Nazarewicz
2016-05-18 10:15                                         ` Felipe Balbi
2016-05-18 13:39                                           ` Michal Nazarewicz
2016-05-19  2:54                                             ` Du, Changbin
2016-05-19  7:34                                               ` Michal Nazarewicz
2016-05-19  8:49                                                 ` Du, Changbin
2016-05-19  2:31                                           ` Du, Changbin
2016-05-16 16:05 ` Michal Nazarewicz
2016-05-16 16:27   ` Lars-Peter Clausen
2016-05-16 16:48     ` Michal Nazarewicz
2016-05-16 16:35   ` Krzysztof Opasiak

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=xa1tk2it7rcb.fsf@mina86.com \
    --to=mina86@mina86.com \
    --cc=changbin.du@intel.com \
    --cc=felipe.balbi@linux.intel.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=k.opasiak@samsung.com \
    --cc=lars@metafoo.de \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=rui.silva@linaro.org \
    --cc=stern@rowland.harvard.edu \
    --cc=viro@zeniv.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).