From: Greg Kroah-Hartman Date: Mon, 15 May 2023 12:48:07 +0000 (+0200) Subject: 4.14-stable patches X-Git-Tag: v4.14.315~29 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3a2b61355079f0fea85731f7e7159a735699f0b4;p=thirdparty%2Fkernel%2Fstable-queue.git 4.14-stable patches added patches: drbd-correctly-submit-flush-bio-on-barrier.patch perf-bench-share-some-global-variables-to-fix-build-with-gcc-10.patch serial-8250-fix-serial8250_tx_empty-race-with-dma-tx.patch tty-prevent-writing-chars-during-tcsetattr-tcsadrain-flush.patch --- diff --git a/queue-4.14/drbd-correctly-submit-flush-bio-on-barrier.patch b/queue-4.14/drbd-correctly-submit-flush-bio-on-barrier.patch new file mode 100644 index 00000000000..a4dac9a5c8e --- /dev/null +++ b/queue-4.14/drbd-correctly-submit-flush-bio-on-barrier.patch @@ -0,0 +1,49 @@ +From 3899d94e3831ee07ea6821c032dc297aec80586a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christoph=20B=C3=B6hmwalder?= + +Date: Wed, 3 May 2023 14:19:37 +0200 +Subject: drbd: correctly submit flush bio on barrier +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Christoph Böhmwalder + +commit 3899d94e3831ee07ea6821c032dc297aec80586a upstream. + +When we receive a flush command (or "barrier" in DRBD), we currently use +a REQ_OP_FLUSH with the REQ_PREFLUSH flag set. + +The correct way to submit a flush bio is by using a REQ_OP_WRITE without +any data, and set the REQ_PREFLUSH flag. + +Since commit b4a6bb3a67aa ("block: add a sanity check for non-write +flush/fua bios"), this triggers a warning in the block layer, but this +has been broken for quite some time before that. + +So use the correct set of flags to actually make the flush happen. + +Cc: Christoph Hellwig +Cc: stable@vger.kernel.org +Fixes: f9ff0da56437 ("drbd: allow parallel flushes for multi-volume resources") +Reported-by: Thomas Voegtle +Signed-off-by: Christoph Böhmwalder +Reviewed-by: Christoph Hellwig +Link: https://lore.kernel.org/r/20230503121937.17232-1-christoph.boehmwalder@linbit.com +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + drivers/block/drbd/drbd_receiver.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/block/drbd/drbd_receiver.c ++++ b/drivers/block/drbd/drbd_receiver.c +@@ -1309,7 +1309,7 @@ static void submit_one_flush(struct drbd + bio_set_dev(bio, device->ldev->backing_bdev); + bio->bi_private = octx; + bio->bi_end_io = one_flush_endio; +- bio->bi_opf = REQ_OP_FLUSH | REQ_PREFLUSH; ++ bio->bi_opf = REQ_OP_WRITE | REQ_PREFLUSH; + + device->flush_jif = jiffies; + set_bit(FLUSH_PENDING, &device->flags); diff --git a/queue-4.14/perf-bench-share-some-global-variables-to-fix-build-with-gcc-10.patch b/queue-4.14/perf-bench-share-some-global-variables-to-fix-build-with-gcc-10.patch new file mode 100644 index 00000000000..46da765f21d --- /dev/null +++ b/queue-4.14/perf-bench-share-some-global-variables-to-fix-build-with-gcc-10.patch @@ -0,0 +1,152 @@ +From 78c855835478c4b41dd02e63bf7a01b23391fd48 Mon Sep 17 00:00:00 2001 +From: Arnaldo Carvalho de Melo +Date: Mon, 30 May 2022 16:53:24 -0500 +Subject: perf bench: Share some global variables to fix build with gcc 10 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Arnaldo Carvalho de Melo + +[ Upstream commit e4d9b04b973b2dbce7b42af95ea70d07da1c936d ] + +Noticed with gcc 10 (fedora rawhide) that those variables were not being +declared as static, so end up with: + + ld: /tmp/build/perf/bench/epoll-wait.o:/git/perf/tools/perf/bench/epoll-wait.c:93: multiple definition of `end'; /tmp/build/perf/bench/futex-hash.o:/git/perf/tools/perf/bench/futex-hash.c:40: first defined here + ld: /tmp/build/perf/bench/epoll-wait.o:/git/perf/tools/perf/bench/epoll-wait.c:93: multiple definition of `start'; /tmp/build/perf/bench/futex-hash.o:/git/perf/tools/perf/bench/futex-hash.c:40: first defined here + ld: /tmp/build/perf/bench/epoll-wait.o:/git/perf/tools/perf/bench/epoll-wait.c:93: multiple definition of `runtime'; /tmp/build/perf/bench/futex-hash.o:/git/perf/tools/perf/bench/futex-hash.c:40: first defined here + ld: /tmp/build/perf/bench/epoll-ctl.o:/git/perf/tools/perf/bench/epoll-ctl.c:38: multiple definition of `end'; /tmp/build/perf/bench/futex-hash.o:/git/perf/tools/perf/bench/futex-hash.c:40: first defined here + ld: /tmp/build/perf/bench/epoll-ctl.o:/git/perf/tools/perf/bench/epoll-ctl.c:38: multiple definition of `start'; /tmp/build/perf/bench/futex-hash.o:/git/perf/tools/perf/bench/futex-hash.c:40: first defined here + ld: /tmp/build/perf/bench/epoll-ctl.o:/git/perf/tools/perf/bench/epoll-ctl.c:38: multiple definition of `runtime'; /tmp/build/perf/bench/futex-hash.o:/git/perf/tools/perf/bench/futex-hash.c:40: first defined here + make[4]: *** [/git/perf/tools/build/Makefile.build:145: /tmp/build/perf/bench/perf-in.o] Error 1 + +Prefix those with bench__ and add them to bench/bench.h, so that we can +share those on the tools needing to access those variables from signal +handlers. + +Acked-by: Thomas Gleixner +Cc: Adrian Hunter +Cc: Davidlohr Bueso +Cc: Jiri Olsa +Cc: Namhyung Kim +Link: http://lore.kernel.org/lkml/20200303155811.GD13702@kernel.org +Signed-off-by: Arnaldo Carvalho de Melo +Signed-off-by: Daniel Díaz +Signed-off-by: Greg Kroah-Hartman +--- + tools/perf/bench/bench.h | 4 ++++ + tools/perf/bench/futex-hash.c | 12 ++++++------ + tools/perf/bench/futex-lock-pi.c | 11 +++++------ + 3 files changed, 15 insertions(+), 12 deletions(-) + +--- a/tools/perf/bench/bench.h ++++ b/tools/perf/bench/bench.h +@@ -2,6 +2,10 @@ + #ifndef BENCH_H + #define BENCH_H + ++#include ++ ++extern struct timeval bench__start, bench__end, bench__runtime; ++ + /* + * The madvise transparent hugepage constants were added in glibc + * 2.13. For compatibility with older versions of glibc, define these +--- a/tools/perf/bench/futex-hash.c ++++ b/tools/perf/bench/futex-hash.c +@@ -35,7 +35,7 @@ static unsigned int nfutexes = 1024; + static bool fshared = false, done = false, silent = false; + static int futex_flag = 0; + +-struct timeval start, end, runtime; ++struct timeval bench__start, bench__end, bench__runtime; + static pthread_mutex_t thread_lock; + static unsigned int threads_starting; + static struct stats throughput_stats; +@@ -101,8 +101,8 @@ static void toggle_done(int sig __maybe_ + { + /* inform all threads that we're done for the day */ + done = true; +- gettimeofday(&end, NULL); +- timersub(&end, &start, &runtime); ++ gettimeofday(&bench__end, NULL); ++ timersub(&bench__end, &bench__start, &bench__runtime); + } + + static void print_summary(void) +@@ -112,7 +112,7 @@ static void print_summary(void) + + printf("%sAveraged %ld operations/sec (+- %.2f%%), total secs = %d\n", + !silent ? "\n" : "", avg, rel_stddev_stats(stddev, avg), +- (int) runtime.tv_sec); ++ (int)bench__runtime.tv_sec); + } + + int bench_futex_hash(int argc, const char **argv) +@@ -156,7 +156,7 @@ int bench_futex_hash(int argc, const cha + + threads_starting = nthreads; + pthread_attr_init(&thread_attr); +- gettimeofday(&start, NULL); ++ gettimeofday(&bench__start, NULL); + for (i = 0; i < nthreads; i++) { + worker[i].tid = i; + worker[i].futex = calloc(nfutexes, sizeof(*worker[i].futex)); +@@ -199,7 +199,7 @@ int bench_futex_hash(int argc, const cha + pthread_mutex_destroy(&thread_lock); + + for (i = 0; i < nthreads; i++) { +- unsigned long t = worker[i].ops/runtime.tv_sec; ++ unsigned long t = worker[i].ops / bench__runtime.tv_sec; + update_stats(&throughput_stats, t); + if (!silent) { + if (nfutexes == 1) +--- a/tools/perf/bench/futex-lock-pi.c ++++ b/tools/perf/bench/futex-lock-pi.c +@@ -34,7 +34,6 @@ static bool silent = false, multi = fals + static bool done = false, fshared = false; + static unsigned int ncpus, nthreads = 0; + static int futex_flag = 0; +-struct timeval start, end, runtime; + static pthread_mutex_t thread_lock; + static unsigned int threads_starting; + static struct stats throughput_stats; +@@ -61,7 +60,7 @@ static void print_summary(void) + + printf("%sAveraged %ld operations/sec (+- %.2f%%), total secs = %d\n", + !silent ? "\n" : "", avg, rel_stddev_stats(stddev, avg), +- (int) runtime.tv_sec); ++ (int)bench__runtime.tv_sec); + } + + static void toggle_done(int sig __maybe_unused, +@@ -70,8 +69,8 @@ static void toggle_done(int sig __maybe_ + { + /* inform all threads that we're done for the day */ + done = true; +- gettimeofday(&end, NULL); +- timersub(&end, &start, &runtime); ++ gettimeofday(&bench__end, NULL); ++ timersub(&bench__end, &bench__start, &bench__runtime); + } + + static void *workerfn(void *arg) +@@ -178,7 +177,7 @@ int bench_futex_lock_pi(int argc, const + + threads_starting = nthreads; + pthread_attr_init(&thread_attr); +- gettimeofday(&start, NULL); ++ gettimeofday(&bench__start, NULL); + + create_threads(worker, thread_attr); + pthread_attr_destroy(&thread_attr); +@@ -204,7 +203,7 @@ int bench_futex_lock_pi(int argc, const + pthread_mutex_destroy(&thread_lock); + + for (i = 0; i < nthreads; i++) { +- unsigned long t = worker[i].ops/runtime.tv_sec; ++ unsigned long t = worker[i].ops / bench__runtime.tv_sec; + + update_stats(&throughput_stats, t); + if (!silent) diff --git a/queue-4.14/serial-8250-fix-serial8250_tx_empty-race-with-dma-tx.patch b/queue-4.14/serial-8250-fix-serial8250_tx_empty-race-with-dma-tx.patch new file mode 100644 index 00000000000..f439dec3d1b --- /dev/null +++ b/queue-4.14/serial-8250-fix-serial8250_tx_empty-race-with-dma-tx.patch @@ -0,0 +1,98 @@ +From stable-owner@vger.kernel.org Thu May 11 14:33:08 2023 +From: "Ilpo Järvinen" +Date: Thu, 11 May 2023 15:32:44 +0300 +Subject: serial: 8250: Fix serial8250_tx_empty() race with DMA Tx +To: stable@vger.kernel.org +Cc: "Ilpo Järvinen" , "Greg Kroah-Hartman" +Message-ID: <20230511123244.38514-2-ilpo.jarvinen@linux.intel.com> + +From: "Ilpo Järvinen" + +There's a potential race before THRE/TEMT deasserts when DMA Tx is +starting up (or the next batch of continuous Tx is being submitted). +This can lead to misdetecting Tx empty condition. + +It is entirely normal for THRE/TEMT to be set for some time after the +DMA Tx had been setup in serial8250_tx_dma(). As Tx side is definitely +not empty at that point, it seems incorrect for serial8250_tx_empty() +claim Tx is empty. + +Fix the race by also checking in serial8250_tx_empty() whether there's +DMA Tx active. + +Note: This fix only addresses in-kernel race mainly to make using +TCSADRAIN/FLUSH robust. Userspace can still cause other races but they +seem userspace concurrency control problems. + +Fixes: 9ee4b83e51f74 ("serial: 8250: Add support for dmaengine") +Cc: stable@vger.kernel.org +Signed-off-by: Ilpo Järvinen +Link: https://lore.kernel.org/r/20230317113318.31327-3-ilpo.jarvinen@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +(cherry picked from commit 146a37e05d620cef4ad430e5d1c9c077fe6fa76f) +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/serial/8250/8250.h | 12 ++++++++++++ + drivers/tty/serial/8250/8250_port.c | 12 +++++++++--- + 2 files changed, 21 insertions(+), 3 deletions(-) + +--- a/drivers/tty/serial/8250/8250.h ++++ b/drivers/tty/serial/8250/8250.h +@@ -221,6 +221,13 @@ extern int serial8250_rx_dma(struct uart + extern void serial8250_rx_dma_flush(struct uart_8250_port *); + extern int serial8250_request_dma(struct uart_8250_port *); + extern void serial8250_release_dma(struct uart_8250_port *); ++ ++static inline bool serial8250_tx_dma_running(struct uart_8250_port *p) ++{ ++ struct uart_8250_dma *dma = p->dma; ++ ++ return dma && dma->tx_running; ++} + #else + static inline int serial8250_tx_dma(struct uart_8250_port *p) + { +@@ -236,6 +243,11 @@ static inline int serial8250_request_dma + return -1; + } + static inline void serial8250_release_dma(struct uart_8250_port *p) { } ++ ++static inline bool serial8250_tx_dma_running(struct uart_8250_port *p) ++{ ++ return false; ++} + #endif + + static inline int ns16550a_goto_highspeed(struct uart_8250_port *up) +--- a/drivers/tty/serial/8250/8250_port.c ++++ b/drivers/tty/serial/8250/8250_port.c +@@ -1968,19 +1968,25 @@ static int serial8250_tx_threshold_handl + static unsigned int serial8250_tx_empty(struct uart_port *port) + { + struct uart_8250_port *up = up_to_u8250p(port); ++ unsigned int result = 0; + unsigned long flags; + unsigned int lsr; + + serial8250_rpm_get(up); + + spin_lock_irqsave(&port->lock, flags); +- lsr = serial_port_in(port, UART_LSR); +- up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; ++ if (!serial8250_tx_dma_running(up)) { ++ lsr = serial_port_in(port, UART_LSR); ++ up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; ++ ++ if ((lsr & BOTH_EMPTY) == BOTH_EMPTY) ++ result = TIOCSER_TEMT; ++ } + spin_unlock_irqrestore(&port->lock, flags); + + serial8250_rpm_put(up); + +- return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0; ++ return result; + } + + unsigned int serial8250_do_get_mctrl(struct uart_port *port) diff --git a/queue-4.14/series b/queue-4.14/series index 596dcda0261..aa491b7dfa3 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -108,3 +108,7 @@ ext4-add-bounds-checking-in-get_max_inline_xattr_value_size.patch ext4-bail-out-of-ext4_xattr_ibody_get-fails-for-any-reason.patch ext4-remove-a-bug_on-in-ext4_mb_release_group_pa.patch ext4-fix-invalid-free-tracking-in-ext4_xattr_move_to_block.patch +perf-bench-share-some-global-variables-to-fix-build-with-gcc-10.patch +tty-prevent-writing-chars-during-tcsetattr-tcsadrain-flush.patch +serial-8250-fix-serial8250_tx_empty-race-with-dma-tx.patch +drbd-correctly-submit-flush-bio-on-barrier.patch diff --git a/queue-4.14/tty-prevent-writing-chars-during-tcsetattr-tcsadrain-flush.patch b/queue-4.14/tty-prevent-writing-chars-during-tcsetattr-tcsadrain-flush.patch new file mode 100644 index 00000000000..f5440aa9770 --- /dev/null +++ b/queue-4.14/tty-prevent-writing-chars-during-tcsetattr-tcsadrain-flush.patch @@ -0,0 +1,127 @@ +From stable-owner@vger.kernel.org Thu May 11 14:33:03 2023 +From: "Ilpo Järvinen" +Date: Thu, 11 May 2023 15:32:43 +0300 +Subject: tty: Prevent writing chars during tcsetattr TCSADRAIN/FLUSH +To: stable@vger.kernel.org +Cc: "Ilpo Järvinen" , "Greg Kroah-Hartman" +Message-ID: <20230511123244.38514-1-ilpo.jarvinen@linux.intel.com> + +From: "Ilpo Järvinen" + +If userspace races tcsetattr() with a write, the drained condition +might not be guaranteed by the kernel. There is a race window after +checking Tx is empty before tty_set_termios() takes termios_rwsem for +write. During that race window, more characters can be queued by a +racing writer. + +Any ongoing transmission might produce garbage during HW's +->set_termios() call. The intent of TCSADRAIN/FLUSH seems to be +preventing such a character corruption. If those flags are set, take +tty's write lock to stop any writer before performing the lower layer +Tx empty check and wait for the pending characters to be sent (if any). + +The initial wait for all-writers-done must be placed outside of tty's +write lock to avoid deadlock which makes it impossible to use +tty_wait_until_sent(). The write lock is retried if a racing write is +detected. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Cc: stable@vger.kernel.org +Signed-off-by: Ilpo Järvinen +Link: https://lore.kernel.org/r/20230317113318.31327-2-ilpo.jarvinen@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +(cherry picked from commit 094fb49a2d0d6827c86d2e0840873e6db0c491d2) +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/tty_io.c | 4 ++-- + drivers/tty/tty_ioctl.c | 45 +++++++++++++++++++++++++++++++++------------ + include/linux/tty.h | 2 ++ + 3 files changed, 37 insertions(+), 14 deletions(-) + +--- a/drivers/tty/tty_io.c ++++ b/drivers/tty/tty_io.c +@@ -874,13 +874,13 @@ static ssize_t tty_read(struct file *fil + return i; + } + +-static void tty_write_unlock(struct tty_struct *tty) ++void tty_write_unlock(struct tty_struct *tty) + { + mutex_unlock(&tty->atomic_write_lock); + wake_up_interruptible_poll(&tty->write_wait, POLLOUT); + } + +-static int tty_write_lock(struct tty_struct *tty, int ndelay) ++int tty_write_lock(struct tty_struct *tty, int ndelay) + { + if (!mutex_trylock(&tty->atomic_write_lock)) { + if (ndelay) +--- a/drivers/tty/tty_ioctl.c ++++ b/drivers/tty/tty_ioctl.c +@@ -396,21 +396,42 @@ static int set_termios(struct tty_struct + tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios); + tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios); + +- ld = tty_ldisc_ref(tty); ++ if (opt & (TERMIOS_FLUSH|TERMIOS_WAIT)) { ++retry_write_wait: ++ retval = wait_event_interruptible(tty->write_wait, !tty_chars_in_buffer(tty)); ++ if (retval < 0) ++ return retval; + +- if (ld != NULL) { +- if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer) +- ld->ops->flush_buffer(tty); +- tty_ldisc_deref(ld); +- } ++ if (tty_write_lock(tty, 0) < 0) ++ goto retry_write_wait; + +- if (opt & TERMIOS_WAIT) { +- tty_wait_until_sent(tty, 0); +- if (signal_pending(current)) +- return -ERESTARTSYS; +- } ++ /* Racing writer? */ ++ if (tty_chars_in_buffer(tty)) { ++ tty_write_unlock(tty); ++ goto retry_write_wait; ++ } ++ ++ ld = tty_ldisc_ref(tty); ++ if (ld != NULL) { ++ if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer) ++ ld->ops->flush_buffer(tty); ++ tty_ldisc_deref(ld); ++ } + +- tty_set_termios(tty, &tmp_termios); ++ if ((opt & TERMIOS_WAIT) && tty->ops->wait_until_sent) { ++ tty->ops->wait_until_sent(tty, 0); ++ if (signal_pending(current)) { ++ tty_write_unlock(tty); ++ return -ERESTARTSYS; ++ } ++ } ++ ++ tty_set_termios(tty, &tmp_termios); ++ ++ tty_write_unlock(tty); ++ } else { ++ tty_set_termios(tty, &tmp_termios); ++ } + + /* FIXME: Arguably if tmp_termios == tty->termios AND the + actual requested termios was not tmp_termios then we may +--- a/include/linux/tty.h ++++ b/include/linux/tty.h +@@ -479,6 +479,8 @@ extern void __stop_tty(struct tty_struct + extern void stop_tty(struct tty_struct *tty); + extern void __start_tty(struct tty_struct *tty); + extern void start_tty(struct tty_struct *tty); ++void tty_write_unlock(struct tty_struct *tty); ++int tty_write_lock(struct tty_struct *tty, int ndelay); + extern int tty_register_driver(struct tty_driver *driver); + extern int tty_unregister_driver(struct tty_driver *driver); + extern struct device *tty_register_device(struct tty_driver *driver,