summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2021-01-21 10:17:25 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2021-01-21 10:34:33 -0800
commit2b3da8cf7ecafe48704f62046fce5da5d17b9e6a (patch)
tree005cbf23d91c903a62de3de7a75b0e10a261bcae
parent1443b92a1ff3a0af5f0e5a177db2d843273a2ca1 (diff)
downloadlinux-tty-splice.tar.bz2
tty: fix up iterate_tty_read() EOVERFLOW handlingtty-splice
When I converted the tty_ldisc_ops 'read()' function to take a kernel pointer, I was a bit too aggressive about the ldisc returning EOVERFLOW. Yes, we want to have EOVERFLOW override any partially read data (because the whole point is that the buffer was too small for the whole packet, and we don't want to see partial packets), but it shouldn't override a previous EFAULT. And in fact, it really is just EOVERFLOW that is special and should throw away any partially read data, not "any error". Admittedly EOVERFLOW is currently the only one that can happen for a continuation read - and if the first read iteration returns an error we won't have this issue. So this is more of a technicality, but let's just make the intent very explicit, and re-organize the error handling a bit so that this is all clearer. Reported-by: Jiri Slaby <jirislaby@kernel.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/tty/tty_io.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index d7883da7ba3d..88b4c4963461 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -861,13 +861,20 @@ static int iterate_tty_read(struct tty_ldisc *ld, struct tty_struct *tty,
if (!size)
break;
- /*
- * A ldisc read error return will override any previously copied
- * data (eg -EOVERFLOW from HDLC)
- */
if (size < 0) {
- memzero_explicit(kernel_buf, sizeof(kernel_buf));
- return size;
+ /* Did we have an earlier error (ie -EFAULT)? */
+ if (retval)
+ break;
+ retval = size;
+
+ /*
+ * -EOVERFLOW means we didn't have enough space
+ * for a whole packet, and we shouldn't return
+ * a partial result.
+ */
+ if (retval == -EOVERFLOW)
+ offset = 0;
+ break;
}
copied = copy_to_iter(kernel_buf, size, to);