]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 4.4
authorSasha Levin <sashal@kernel.org>
Thu, 31 Dec 2020 04:14:51 +0000 (23:14 -0500)
committerSasha Levin <sashal@kernel.org>
Thu, 31 Dec 2020 04:14:51 +0000 (23:14 -0500)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-4.4/s390-dasd-fix-hanging-device-offline-processing.patch [new file with mode: 0644]
queue-4.4/s390-smp-perform-initial-cpu-reset-also-for-smt-sibl.patch [new file with mode: 0644]
queue-4.4/s390-smp-use-smp_get_base_cpu-helper-function.patch [new file with mode: 0644]
queue-4.4/series
queue-4.4/usb-serial-digi_acceleport-fix-write-wakeup-deadlock.patch [new file with mode: 0644]

diff --git a/queue-4.4/s390-dasd-fix-hanging-device-offline-processing.patch b/queue-4.4/s390-dasd-fix-hanging-device-offline-processing.patch
new file mode 100644 (file)
index 0000000..49de84a
--- /dev/null
@@ -0,0 +1,62 @@
+From 8ddf4d22cac7e4804ac1a7c11f4877a307944546 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 17 Dec 2020 16:59:04 +0100
+Subject: s390/dasd: fix hanging device offline processing
+
+From: Stefan Haberland <sth@linux.ibm.com>
+
+[ Upstream commit 658a337a606f48b7ebe451591f7681d383fa115e ]
+
+For an LCU update a read unit address configuration IO is required.
+This is started using sleep_on(), which has early exit paths in case the
+device is not usable for IO. For example when it is in offline processing.
+
+In those cases the LCU update should fail and not be retried.
+Therefore lcu_update_work checks if EOPNOTSUPP is returned or not.
+
+Commit 41995342b40c ("s390/dasd: fix endless loop after read unit address configuration")
+accidentally removed the EOPNOTSUPP return code from
+read_unit_address_configuration(), which in turn might lead to an endless
+loop of the LCU update in offline processing.
+
+Fix by returning EOPNOTSUPP again if the device is not able to perform the
+request.
+
+Fixes: 41995342b40c ("s390/dasd: fix endless loop after read unit address configuration")
+Cc: stable@vger.kernel.org #5.3
+Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
+Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/s390/block/dasd_alias.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c
+index 89b708135000c..03543c0a2dd0f 100644
+--- a/drivers/s390/block/dasd_alias.c
++++ b/drivers/s390/block/dasd_alias.c
+@@ -475,11 +475,19 @@ static int read_unit_address_configuration(struct dasd_device *device,
+       spin_unlock_irqrestore(&lcu->lock, flags);
+       rc = dasd_sleep_on(cqr);
+-      if (rc && !suborder_not_supported(cqr)) {
++      if (!rc)
++              goto out;
++
++      if (suborder_not_supported(cqr)) {
++              /* suborder not supported or device unusable for IO */
++              rc = -EOPNOTSUPP;
++      } else {
++              /* IO failed but should be retried */
+               spin_lock_irqsave(&lcu->lock, flags);
+               lcu->flags |= NEED_UAC_UPDATE;
+               spin_unlock_irqrestore(&lcu->lock, flags);
+       }
++out:
+       dasd_kfree_request(cqr, cqr->memdev);
+       return rc;
+ }
+-- 
+2.27.0
+
diff --git a/queue-4.4/s390-smp-perform-initial-cpu-reset-also-for-smt-sibl.patch b/queue-4.4/s390-smp-perform-initial-cpu-reset-also-for-smt-sibl.patch
new file mode 100644 (file)
index 0000000..1327f99
--- /dev/null
@@ -0,0 +1,59 @@
+From ed8b681de2733104b61dda3d7d8a69166d405ee6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 8 Dec 2020 07:35:21 +0100
+Subject: s390/smp: perform initial CPU reset also for SMT siblings
+
+From: Sven Schnelle <svens@linux.ibm.com>
+
+[ Upstream commit b5e438ebd7e808d1d2435159ac4742e01a94b8da ]
+
+Not resetting the SMT siblings might leave them in unpredictable
+state. One of the observed problems was that the CPU timer wasn't
+reset and therefore large system time values where accounted during
+CPU bringup.
+
+Cc: <stable@kernel.org> # 4.0
+Fixes: 10ad34bc76dfb ("s390: add SMT support")
+Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
+Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
+Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/s390/kernel/smp.c | 18 +++---------------
+ 1 file changed, 3 insertions(+), 15 deletions(-)
+
+diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
+index c941bd500765a..526927621369b 100644
+--- a/arch/s390/kernel/smp.c
++++ b/arch/s390/kernel/smp.c
+@@ -843,24 +843,12 @@ static void smp_start_secondary(void *cpuvoid)
+ /* Upping and downing of CPUs */
+ int __cpu_up(unsigned int cpu, struct task_struct *tidle)
+ {
+-      struct pcpu *pcpu;
+-      int base, i, rc;
++      struct pcpu *pcpu = pcpu_devices + cpu;
++      int rc;
+-      pcpu = pcpu_devices + cpu;
+       if (pcpu->state != CPU_STATE_CONFIGURED)
+               return -EIO;
+-      base = smp_get_base_cpu(cpu);
+-      for (i = 0; i <= smp_cpu_mtid; i++) {
+-              if (base + i < nr_cpu_ids)
+-                      if (cpu_online(base + i))
+-                              break;
+-      }
+-      /*
+-       * If this is the first CPU of the core to get online
+-       * do an initial CPU reset.
+-       */
+-      if (i > smp_cpu_mtid &&
+-          pcpu_sigp_retry(pcpu_devices + base, SIGP_INITIAL_CPU_RESET, 0) !=
++      if (pcpu_sigp_retry(pcpu, SIGP_INITIAL_CPU_RESET, 0) !=
+           SIGP_CC_ORDER_CODE_ACCEPTED)
+               return -EIO;
+-- 
+2.27.0
+
diff --git a/queue-4.4/s390-smp-use-smp_get_base_cpu-helper-function.patch b/queue-4.4/s390-smp-use-smp_get_base_cpu-helper-function.patch
new file mode 100644 (file)
index 0000000..2f99202
--- /dev/null
@@ -0,0 +1,41 @@
+From dbcde903799671b0c171e0450733faaf11dc66ad Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 5 Dec 2016 21:18:58 +0100
+Subject: s390/smp: use smp_get_base_cpu() helper function
+
+From: Heiko Carstens <heiko.carstens@de.ibm.com>
+
+[ Upstream commit 5423145f8c4e885c640d12adc35c421127ed015f ]
+
+Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/s390/kernel/smp.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
+index f113fcd781d87..c941bd500765a 100644
+--- a/arch/s390/kernel/smp.c
++++ b/arch/s390/kernel/smp.c
+@@ -849,7 +849,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle)
+       pcpu = pcpu_devices + cpu;
+       if (pcpu->state != CPU_STATE_CONFIGURED)
+               return -EIO;
+-      base = cpu - (cpu % (smp_cpu_mtid + 1));
++      base = smp_get_base_cpu(cpu);
+       for (i = 0; i <= smp_cpu_mtid; i++) {
+               if (base + i < nr_cpu_ids)
+                       if (cpu_online(base + i))
+@@ -1018,7 +1018,7 @@ static ssize_t cpu_configure_store(struct device *dev,
+       rc = -EBUSY;
+       /* disallow configuration changes of online cpus and cpu 0 */
+       cpu = dev->id;
+-      cpu -= cpu % (smp_cpu_mtid + 1);
++      cpu = smp_get_base_cpu(cpu);
+       if (cpu == 0)
+               goto out;
+       for (i = 0; i <= smp_cpu_mtid; i++)
+-- 
+2.27.0
+
index a6d38d7d48981d43f3f5193f0b9e8e0c312db902..d3c99afd7c79d91b5735715462e2baa7ef26f519 100644 (file)
@@ -4,3 +4,7 @@ alsa-usb-audio-fix-sync-ep-altsetting-sanity-check.patch
 alsa-hda-realtek-support-dell-headset-mode-for-alc3271.patch
 alsa-hda-fix-a-wrong-fixup-for-alc289-on-dell-machines.patch
 alsa-hda-realtek-dell-headphone-has-noise-on-unmute-for-alc236.patch
+s390-smp-use-smp_get_base_cpu-helper-function.patch
+s390-smp-perform-initial-cpu-reset-also-for-smt-sibl.patch
+s390-dasd-fix-hanging-device-offline-processing.patch
+usb-serial-digi_acceleport-fix-write-wakeup-deadlock.patch
diff --git a/queue-4.4/usb-serial-digi_acceleport-fix-write-wakeup-deadlock.patch b/queue-4.4/usb-serial-digi_acceleport-fix-write-wakeup-deadlock.patch
new file mode 100644 (file)
index 0000000..6ef9d03
--- /dev/null
@@ -0,0 +1,160 @@
+From 0403535f41a8ea7e98d76c506e9425d357c670c3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 26 Oct 2020 11:43:06 +0100
+Subject: USB: serial: digi_acceleport: fix write-wakeup deadlocks
+
+From: Johan Hovold <johan@kernel.org>
+
+[ Upstream commit 5098e77962e7c8947f87bd8c5869c83e000a522a ]
+
+The driver must not call tty_wakeup() while holding its private lock as
+line disciplines are allowed to call back into write() from
+write_wakeup(), leading to a deadlock.
+
+Also remove the unneeded work struct that was used to defer wakeup in
+order to work around a possible race in ancient times (see comment about
+n_tty write_chan() in commit 14b54e39b412 ("USB: serial: remove
+changelogs and old todo entries")).
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Cc: stable@vger.kernel.org
+Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/serial/digi_acceleport.c | 45 ++++++++--------------------
+ 1 file changed, 13 insertions(+), 32 deletions(-)
+
+diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
+index be93b9ff2d989..b630048c49883 100644
+--- a/drivers/usb/serial/digi_acceleport.c
++++ b/drivers/usb/serial/digi_acceleport.c
+@@ -23,7 +23,6 @@
+ #include <linux/tty_flip.h>
+ #include <linux/module.h>
+ #include <linux/spinlock.h>
+-#include <linux/workqueue.h>
+ #include <linux/uaccess.h>
+ #include <linux/usb.h>
+ #include <linux/wait.h>
+@@ -201,14 +200,12 @@ struct digi_port {
+       int dp_throttle_restart;
+       wait_queue_head_t dp_flush_wait;
+       wait_queue_head_t dp_close_wait;        /* wait queue for close */
+-      struct work_struct dp_wakeup_work;
+       struct usb_serial_port *dp_port;
+ };
+ /* Local Function Declarations */
+-static void digi_wakeup_write_lock(struct work_struct *work);
+ static int digi_write_oob_command(struct usb_serial_port *port,
+       unsigned char *buf, int count, int interruptible);
+ static int digi_write_inb_command(struct usb_serial_port *port,
+@@ -355,26 +352,6 @@ __releases(lock)
+       return timeout;
+ }
+-
+-/*
+- *  Digi Wakeup Write
+- *
+- *  Wake up port, line discipline, and tty processes sleeping
+- *  on writes.
+- */
+-
+-static void digi_wakeup_write_lock(struct work_struct *work)
+-{
+-      struct digi_port *priv =
+-                      container_of(work, struct digi_port, dp_wakeup_work);
+-      struct usb_serial_port *port = priv->dp_port;
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&priv->dp_port_lock, flags);
+-      tty_port_tty_wakeup(&port->port);
+-      spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+-}
+-
+ /*
+  *  Digi Write OOB Command
+  *
+@@ -986,6 +963,7 @@ static void digi_write_bulk_callback(struct urb *urb)
+       struct digi_serial *serial_priv;
+       int ret = 0;
+       int status = urb->status;
++      bool wakeup;
+       /* port and serial sanity check */
+       if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) {
+@@ -1012,6 +990,7 @@ static void digi_write_bulk_callback(struct urb *urb)
+       }
+       /* try to send any buffered data on this port */
++      wakeup = true;
+       spin_lock(&priv->dp_port_lock);
+       priv->dp_write_urb_in_use = 0;
+       if (priv->dp_out_buf_len > 0) {
+@@ -1027,19 +1006,18 @@ static void digi_write_bulk_callback(struct urb *urb)
+               if (ret == 0) {
+                       priv->dp_write_urb_in_use = 1;
+                       priv->dp_out_buf_len = 0;
++                      wakeup = false;
+               }
+       }
+-      /* wake up processes sleeping on writes immediately */
+-      tty_port_tty_wakeup(&port->port);
+-      /* also queue up a wakeup at scheduler time, in case we */
+-      /* lost the race in write_chan(). */
+-      schedule_work(&priv->dp_wakeup_work);
+-
+       spin_unlock(&priv->dp_port_lock);
++
+       if (ret && ret != -EPERM)
+               dev_err_console(port,
+                       "%s: usb_submit_urb failed, ret=%d, port=%d\n",
+                       __func__, ret, priv->dp_port_num);
++
++      if (wakeup)
++              tty_port_tty_wakeup(&port->port);
+ }
+ static int digi_write_room(struct tty_struct *tty)
+@@ -1239,7 +1217,6 @@ static int digi_port_init(struct usb_serial_port *port, unsigned port_num)
+       init_waitqueue_head(&priv->dp_transmit_idle_wait);
+       init_waitqueue_head(&priv->dp_flush_wait);
+       init_waitqueue_head(&priv->dp_close_wait);
+-      INIT_WORK(&priv->dp_wakeup_work, digi_wakeup_write_lock);
+       priv->dp_port = port;
+       init_waitqueue_head(&port->write_wait);
+@@ -1525,13 +1502,14 @@ static int digi_read_oob_callback(struct urb *urb)
+                       rts = tty->termios.c_cflag & CRTSCTS;
+               
+               if (tty && opcode == DIGI_CMD_READ_INPUT_SIGNALS) {
++                      bool wakeup = false;
++
+                       spin_lock(&priv->dp_port_lock);
+                       /* convert from digi flags to termiox flags */
+                       if (val & DIGI_READ_INPUT_SIGNALS_CTS) {
+                               priv->dp_modem_signals |= TIOCM_CTS;
+-                              /* port must be open to use tty struct */
+                               if (rts)
+-                                      tty_port_tty_wakeup(&port->port);
++                                      wakeup = true;
+                       } else {
+                               priv->dp_modem_signals &= ~TIOCM_CTS;
+                               /* port must be open to use tty struct */
+@@ -1550,6 +1528,9 @@ static int digi_read_oob_callback(struct urb *urb)
+                               priv->dp_modem_signals &= ~TIOCM_CD;
+                       spin_unlock(&priv->dp_port_lock);
++
++                      if (wakeup)
++                              tty_port_tty_wakeup(&port->port);
+               } else if (opcode == DIGI_CMD_TRANSMIT_IDLE) {
+                       spin_lock(&priv->dp_port_lock);
+                       priv->dp_transmit_idle = 1;
+-- 
+2.27.0
+