]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 5 Mar 2021 08:53:07 +0000 (09:53 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 5 Mar 2021 08:53:07 +0000 (09:53 +0100)
added patches:
tty-clean-up-legacy-leftovers-from-n_tty-line-discipline.patch
tty-fix-up-hung_up_tty_read-conversion.patch
tty-fix-up-iterate_tty_read-eoverflow-handling.patch
tty-teach-n_tty-line-discipline-about-the-new-cookie-continuations.patch
tty-teach-the-n_tty-icanon-case-about-the-new-cookie-continuations-too.patch

queue-5.10/series
queue-5.10/tty-clean-up-legacy-leftovers-from-n_tty-line-discipline.patch [new file with mode: 0644]
queue-5.10/tty-fix-up-hung_up_tty_read-conversion.patch [new file with mode: 0644]
queue-5.10/tty-fix-up-iterate_tty_read-eoverflow-handling.patch [new file with mode: 0644]
queue-5.10/tty-teach-n_tty-line-discipline-about-the-new-cookie-continuations.patch [new file with mode: 0644]
queue-5.10/tty-teach-the-n_tty-icanon-case-about-the-new-cookie-continuations-too.patch [new file with mode: 0644]

index dcb00b5132271be2553b6cfb5991ff593baf2d5a..2e164f96f3a68a531f830bb13ffcec5337b18f07 100644 (file)
@@ -91,3 +91,8 @@ remoteproc-mediatek-fix-kernel-test-robot-warning.patch
 swap-fix-swapfile-read-write-offset.patch
 powerpc-sstep-check-instruction-validity-against-isa-version-before-emulation.patch
 powerpc-sstep-fix-incorrect-return-from-analyze_instr.patch
+tty-fix-up-iterate_tty_read-eoverflow-handling.patch
+tty-fix-up-hung_up_tty_read-conversion.patch
+tty-clean-up-legacy-leftovers-from-n_tty-line-discipline.patch
+tty-teach-n_tty-line-discipline-about-the-new-cookie-continuations.patch
+tty-teach-the-n_tty-icanon-case-about-the-new-cookie-continuations-too.patch
diff --git a/queue-5.10/tty-clean-up-legacy-leftovers-from-n_tty-line-discipline.patch b/queue-5.10/tty-clean-up-legacy-leftovers-from-n_tty-line-discipline.patch
new file mode 100644 (file)
index 0000000..30211fb
--- /dev/null
@@ -0,0 +1,113 @@
+From 64a69892afadd6fffaeadc65427bb7601161139d Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Tue, 19 Jan 2021 13:46:28 -0800
+Subject: tty: clean up legacy leftovers from n_tty line discipline
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+commit 64a69892afadd6fffaeadc65427bb7601161139d upstream.
+
+Back when the line disciplines did their own direct user accesses, they
+had to deal with the data copy possibly failing in the middle.
+
+Now that the user copy is done by the tty_io.c code, that failure case
+no longer exists.
+
+Remove the left-over error handling code that cannot trigger.
+
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/n_tty.c |   29 +++++++++--------------------
+ 1 file changed, 9 insertions(+), 20 deletions(-)
+
+--- a/drivers/tty/n_tty.c
++++ b/drivers/tty/n_tty.c
+@@ -1955,19 +1955,17 @@ static inline int input_available_p(stru
+  *            read_tail published
+  */
+-static int copy_from_read_buf(struct tty_struct *tty,
++static void copy_from_read_buf(struct tty_struct *tty,
+                                     unsigned char **kbp,
+                                     size_t *nr)
+ {
+       struct n_tty_data *ldata = tty->disc_data;
+-      int retval;
+       size_t n;
+       bool is_eof;
+       size_t head = smp_load_acquire(&ldata->commit_head);
+       size_t tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1);
+-      retval = 0;
+       n = min(head - ldata->read_tail, N_TTY_BUF_SIZE - tail);
+       n = min(*nr, n);
+       if (n) {
+@@ -1984,7 +1982,6 @@ static int copy_from_read_buf(struct tty
+               *kbp += n;
+               *nr -= n;
+       }
+-      return retval;
+ }
+ /**
+@@ -2010,9 +2007,9 @@ static int copy_from_read_buf(struct tty
+  *            read_tail published
+  */
+-static int canon_copy_from_read_buf(struct tty_struct *tty,
+-                                  unsigned char **kbp,
+-                                  size_t *nr)
++static void canon_copy_from_read_buf(struct tty_struct *tty,
++                                   unsigned char **kbp,
++                                   size_t *nr)
+ {
+       struct n_tty_data *ldata = tty->disc_data;
+       size_t n, size, more, c;
+@@ -2022,7 +2019,7 @@ static int canon_copy_from_read_buf(stru
+       /* N.B. avoid overrun if nr == 0 */
+       if (!*nr)
+-              return 0;
++              return;
+       n = min(*nr + 1, smp_load_acquire(&ldata->canon_head) - ldata->read_tail);
+@@ -2069,7 +2066,6 @@ static int canon_copy_from_read_buf(stru
+                       ldata->push = 0;
+               tty_audit_push();
+       }
+-      return 0;
+ }
+ /**
+@@ -2219,24 +2215,17 @@ static ssize_t n_tty_read(struct tty_str
+               }
+               if (ldata->icanon && !L_EXTPROC(tty)) {
+-                      retval = canon_copy_from_read_buf(tty, &kb, &nr);
+-                      if (retval)
+-                              break;
++                      canon_copy_from_read_buf(tty, &kb, &nr);
+               } else {
+-                      int uncopied;
+-
+                       /* Deal with packet mode. */
+                       if (packet && kb == kbuf) {
+                               *kb++ = TIOCPKT_DATA;
+                               nr--;
+                       }
+-                      uncopied = copy_from_read_buf(tty, &kb, &nr);
+-                      uncopied += copy_from_read_buf(tty, &kb, &nr);
+-                      if (uncopied) {
+-                              retval = -EFAULT;
+-                              break;
+-                      }
++                      /* See comment above copy_from_read_buf() why twice */
++                      copy_from_read_buf(tty, &kb, &nr);
++                      copy_from_read_buf(tty, &kb, &nr);
+               }
+               n_tty_check_unthrottle(tty);
diff --git a/queue-5.10/tty-fix-up-hung_up_tty_read-conversion.patch b/queue-5.10/tty-fix-up-hung_up_tty_read-conversion.patch
new file mode 100644 (file)
index 0000000..4dde0fa
--- /dev/null
@@ -0,0 +1,58 @@
+From ddc5fda7456178e2cbc87675b370920d98360daf Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Thu, 21 Jan 2021 10:08:15 -0800
+Subject: tty: fix up hung_up_tty_read() conversion
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+commit ddc5fda7456178e2cbc87675b370920d98360daf upstream.
+
+In commit "tty: implement read_iter", I left the read_iter conversion of
+the hung up tty case alone, because I incorrectly thought it didn't
+matter.
+
+Jiri showed me the errors of my ways, and pointed out the problems with
+that incomplete conversion.  Fix it all up.
+
+Reported-by: Jiri Slaby <jirislaby@kernel.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Reviewed-by: Jiri Slaby <jirislaby@kernel.org>
+Link: https://lore.kernel.org/r/CAHk-=wh+-rGsa=xruEWdg_fJViFG8rN9bpLrfLz=_yBYh2tBhA@mail.gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/tty_io.c |    9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+--- a/drivers/tty/tty_io.c
++++ b/drivers/tty/tty_io.c
+@@ -429,8 +429,7 @@ struct tty_driver *tty_find_polling_driv
+ EXPORT_SYMBOL_GPL(tty_find_polling_driver);
+ #endif
+-static ssize_t hung_up_tty_read(struct file *file, char __user *buf,
+-                              size_t count, loff_t *ppos)
++static ssize_t hung_up_tty_read(struct kiocb *iocb, struct iov_iter *to)
+ {
+       return 0;
+ }
+@@ -502,7 +501,7 @@ static const struct file_operations cons
+ static const struct file_operations hung_up_tty_fops = {
+       .llseek         = no_llseek,
+-      .read           = hung_up_tty_read,
++      .read_iter      = hung_up_tty_read,
+       .write_iter     = hung_up_tty_write,
+       .poll           = hung_up_tty_poll,
+       .unlocked_ioctl = hung_up_tty_ioctl,
+@@ -929,8 +928,10 @@ static ssize_t tty_read(struct kiocb *io
+       /* We want to wait for the line discipline to sort out in this
+          situation */
+       ld = tty_ldisc_ref_wait(tty);
++      if (!ld)
++              return hung_up_tty_read(iocb, to);
+       i = -EIO;
+-      if (ld && ld->ops->read)
++      if (ld->ops->read)
+               i = iterate_tty_read(ld, tty, file, to);
+       tty_ldisc_deref(ld);
diff --git a/queue-5.10/tty-fix-up-iterate_tty_read-eoverflow-handling.patch b/queue-5.10/tty-fix-up-iterate_tty_read-eoverflow-handling.patch
new file mode 100644 (file)
index 0000000..6886577
--- /dev/null
@@ -0,0 +1,64 @@
+From e71a8d5cf4b4f274740e31b601216071e2a11afa Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Thu, 21 Jan 2021 10:17:25 -0800
+Subject: tty: fix up iterate_tty_read() EOVERFLOW handling
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+commit e71a8d5cf4b4f274740e31b601216071e2a11afa upstream.
+
+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>
+Reviewed-by: Jiri Slaby <jirislaby@kernel.org>
+Link: https://lore.kernel.org/r/CAHk-=wh+-rGsa=xruEWdg_fJViFG8rN9bpLrfLz=_yBYh2tBhA@mail.gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/tty_io.c |   19 +++++++++++++------
+ 1 file changed, 13 insertions(+), 6 deletions(-)
+
+--- a/drivers/tty/tty_io.c
++++ b/drivers/tty/tty_io.c
+@@ -860,13 +860,20 @@ static int iterate_tty_read(struct tty_l
+               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);
diff --git a/queue-5.10/tty-teach-n_tty-line-discipline-about-the-new-cookie-continuations.patch b/queue-5.10/tty-teach-n_tty-line-discipline-about-the-new-cookie-continuations.patch
new file mode 100644 (file)
index 0000000..4150aa4
--- /dev/null
@@ -0,0 +1,139 @@
+From 15ea8ae8e03fdb845ed3ff5d9f11dd5f4f60252c Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Tue, 19 Jan 2021 18:14:20 -0800
+Subject: tty: teach n_tty line discipline about the new "cookie continuations"
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+commit 15ea8ae8e03fdb845ed3ff5d9f11dd5f4f60252c upstream.
+
+With the conversion to do the tty ldisc read operations in small chunks,
+the n_tty line discipline became noticeably slower for throughput
+oriented loads, because rather than read things in up to 2kB chunks, it
+would return at most 64 bytes per read() system call.
+
+The cost is mainly all in the "do system calls over and over", not
+really in the new "copy to an extra kernel buffer".
+
+This can be fixed by teaching the n_tty line discipline about the
+"cookie continuation" model, which the chunking code supports because
+things like hdlc need to be able to handle packets up to 64kB in size.
+
+Doing that doesn't just get us back to the old performace, but to much
+better performance: my stupid "copy 10MB of data over a pty" test
+program is now almost twice as fast as it used to be (going down from
+0.1s to 0.054s).
+
+This is entirely because it now creates maximal chunks (which happens to
+be "one byte less than one page" due to how we do the circular tty
+buffers).
+
+NOTE! This case only handles the simpler non-icanon case, which is the
+one where people may care about throughput.  I'm going to do the icanon
+case later too, because while performance isn't a major issue for that,
+there may be programs that think they'll always get a full line and
+don't like the 64-byte chunking for that reason.
+
+Such programs are arguably buggy (signals etc can cause random partial
+results from tty reads anyway), and good programs will handle such
+partial reads, but expecting everybody to write "good programs" has
+never been a winning policy for the kernel..
+
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/n_tty.c |   52 ++++++++++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 42 insertions(+), 10 deletions(-)
+
+--- a/drivers/tty/n_tty.c
++++ b/drivers/tty/n_tty.c
+@@ -1943,19 +1943,17 @@ static inline int input_available_p(stru
+  *    Helper function to speed up n_tty_read.  It is only called when
+  *    ICANON is off; it copies characters straight from the tty queue.
+  *
+- *    It can be profitably called twice; once to drain the space from
+- *    the tail pointer to the (physical) end of the buffer, and once
+- *    to drain the space from the (physical) beginning of the buffer
+- *    to head pointer.
+- *
+  *    Called under the ldata->atomic_read_lock sem
+  *
++ *    Returns true if it successfully copied data, but there is still
++ *    more data to be had.
++ *
+  *    n_tty_read()/consumer path:
+  *            caller holds non-exclusive termios_rwsem
+  *            read_tail published
+  */
+-static void copy_from_read_buf(struct tty_struct *tty,
++static bool copy_from_read_buf(struct tty_struct *tty,
+                                     unsigned char **kbp,
+                                     size_t *nr)
+@@ -1978,10 +1976,14 @@ static void copy_from_read_buf(struct tt
+               /* Turn single EOF into zero-length read */
+               if (L_EXTPROC(tty) && ldata->icanon && is_eof &&
+                   (head == ldata->read_tail))
+-                      n = 0;
++                      return false;
+               *kbp += n;
+               *nr -= n;
++
++              /* If we have more to copy, let the caller know */
++              return head != ldata->read_tail;
+       }
++      return false;
+ }
+ /**
+@@ -2129,6 +2131,25 @@ static ssize_t n_tty_read(struct tty_str
+       int packet;
+       size_t tail;
++      /*
++       * Is this a continuation of a read started earler?
++       *
++       * If so, we still hold the atomic_read_lock and the
++       * termios_rwsem, and can just continue to copy data.
++       */
++      if (*cookie) {
++              if (copy_from_read_buf(tty, &kb, &nr))
++                      return kb - kbuf;
++
++              /* No more data - release locks and stop retries */
++              n_tty_kick_worker(tty);
++              n_tty_check_unthrottle(tty);
++              up_read(&tty->termios_rwsem);
++              mutex_unlock(&ldata->atomic_read_lock);
++              *cookie = NULL;
++              return kb - kbuf;
++      }
++
+       c = job_control(tty, file);
+       if (c < 0)
+               return c;
+@@ -2223,9 +2244,20 @@ static ssize_t n_tty_read(struct tty_str
+                               nr--;
+                       }
+-                      /* See comment above copy_from_read_buf() why twice */
+-                      copy_from_read_buf(tty, &kb, &nr);
+-                      copy_from_read_buf(tty, &kb, &nr);
++                      /*
++                       * Copy data, and if there is more to be had
++                       * and we have nothing more to wait for, then
++                       * let's mark us for retries.
++                       *
++                       * NOTE! We return here with both the termios_sem
++                       * and atomic_read_lock still held, the retries
++                       * will release them when done.
++                       */
++                      if (copy_from_read_buf(tty, &kb, &nr) && kb - kbuf >= minimum) {
++                              remove_wait_queue(&tty->read_wait, &wait);
++                              *cookie = cookie;
++                              return kb - kbuf;
++                      }
+               }
+               n_tty_check_unthrottle(tty);
diff --git a/queue-5.10/tty-teach-the-n_tty-icanon-case-about-the-new-cookie-continuations-too.patch b/queue-5.10/tty-teach-the-n_tty-icanon-case-about-the-new-cookie-continuations-too.patch
new file mode 100644 (file)
index 0000000..ca00e0a
--- /dev/null
@@ -0,0 +1,106 @@
+From d7fe75cbc23c7d225eee2ef04def239b6603dce7 Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Wed, 20 Jan 2021 15:43:38 -0800
+Subject: tty: teach the n_tty ICANON case about the new "cookie continuations" too
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+commit d7fe75cbc23c7d225eee2ef04def239b6603dce7 upstream.
+
+The ICANON case is a bit messy, since it has to look for the line
+ending, and has special code to then suppress line ending characters if
+they match the __DISABLED_CHAR.  So it actually looks up the line ending
+even past the point where it knows it won't copy it to the result
+buffer.
+
+That said, apart from all those odd legacy N_TTY ICANON cases, the
+actual "should we continue copying" logic isn't really all that
+complicated or different from the non-canon case.  In fact, the lack of
+"wait for at least N characters" arguably makes the repeat case slightly
+simpler.  It really just boils down to "there's more of the line to be
+copied".
+
+So add the necessarily trivial logic, and now the N_TTY case will give
+long result lines even when in canon mode.
+
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/n_tty.c |   26 +++++++++++++++++++-------
+ 1 file changed, 19 insertions(+), 7 deletions(-)
+
+--- a/drivers/tty/n_tty.c
++++ b/drivers/tty/n_tty.c
+@@ -2009,21 +2009,22 @@ static bool copy_from_read_buf(struct tt
+  *            read_tail published
+  */
+-static void canon_copy_from_read_buf(struct tty_struct *tty,
++static bool canon_copy_from_read_buf(struct tty_struct *tty,
+                                    unsigned char **kbp,
+                                    size_t *nr)
+ {
+       struct n_tty_data *ldata = tty->disc_data;
+       size_t n, size, more, c;
+       size_t eol;
+-      size_t tail;
++      size_t tail, canon_head;
+       int found = 0;
+       /* N.B. avoid overrun if nr == 0 */
+       if (!*nr)
+-              return;
++              return false;
+-      n = min(*nr + 1, smp_load_acquire(&ldata->canon_head) - ldata->read_tail);
++      canon_head = smp_load_acquire(&ldata->canon_head);
++      n = min(*nr + 1, canon_head - ldata->read_tail);
+       tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1);
+       size = min_t(size_t, tail + n, N_TTY_BUF_SIZE);
+@@ -2067,7 +2068,11 @@ static void canon_copy_from_read_buf(str
+               else
+                       ldata->push = 0;
+               tty_audit_push();
++              return false;
+       }
++
++      /* No EOL found - do a continuation retry if there is more data */
++      return ldata->read_tail != canon_head;
+ }
+ /**
+@@ -2138,8 +2143,13 @@ static ssize_t n_tty_read(struct tty_str
+        * termios_rwsem, and can just continue to copy data.
+        */
+       if (*cookie) {
+-              if (copy_from_read_buf(tty, &kb, &nr))
+-                      return kb - kbuf;
++              if (ldata->icanon && !L_EXTPROC(tty)) {
++                      if (canon_copy_from_read_buf(tty, &kb, &nr))
++                              return kb - kbuf;
++              } else {
++                      if (copy_from_read_buf(tty, &kb, &nr))
++                              return kb - kbuf;
++              }
+               /* No more data - release locks and stop retries */
+               n_tty_kick_worker(tty);
+@@ -2236,7 +2246,8 @@ static ssize_t n_tty_read(struct tty_str
+               }
+               if (ldata->icanon && !L_EXTPROC(tty)) {
+-                      canon_copy_from_read_buf(tty, &kb, &nr);
++                      if (canon_copy_from_read_buf(tty, &kb, &nr))
++                              goto more_to_be_read;
+               } else {
+                       /* Deal with packet mode. */
+                       if (packet && kb == kbuf) {
+@@ -2254,6 +2265,7 @@ static ssize_t n_tty_read(struct tty_str
+                        * will release them when done.
+                        */
+                       if (copy_from_read_buf(tty, &kb, &nr) && kb - kbuf >= minimum) {
++more_to_be_read:
+                               remove_wait_queue(&tty->read_wait, &wait);
+                               *cookie = cookie;
+                               return kb - kbuf;