]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.1-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 12 Oct 2023 17:40:07 +0000 (19:40 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 12 Oct 2023 17:40:07 +0000 (19:40 +0200)
added patches:
asoc-amd-yc-fix-non-functional-mic-on-lenovo-82ym.patch
ata-libata-scsi-disable-scsi-device-manage_system_start_stop.patch
hid-logitech-hidpp-fix-kernel-crash-on-receiver-usb-disconnect.patch
net-prevent-address-rewrite-in-kernel_bind.patch
quota-fix-slow-quotaoff.patch
scsi-do-not-rescan-devices-with-a-suspended-queue.patch

queue-6.1/asoc-amd-yc-fix-non-functional-mic-on-lenovo-82ym.patch [new file with mode: 0644]
queue-6.1/ata-libata-scsi-disable-scsi-device-manage_system_start_stop.patch [new file with mode: 0644]
queue-6.1/hid-logitech-hidpp-fix-kernel-crash-on-receiver-usb-disconnect.patch [new file with mode: 0644]
queue-6.1/net-prevent-address-rewrite-in-kernel_bind.patch [new file with mode: 0644]
queue-6.1/quota-fix-slow-quotaoff.patch [new file with mode: 0644]
queue-6.1/scsi-do-not-rescan-devices-with-a-suspended-queue.patch [new file with mode: 0644]
queue-6.1/series

diff --git a/queue-6.1/asoc-amd-yc-fix-non-functional-mic-on-lenovo-82ym.patch b/queue-6.1/asoc-amd-yc-fix-non-functional-mic-on-lenovo-82ym.patch
new file mode 100644 (file)
index 0000000..679f938
--- /dev/null
@@ -0,0 +1,40 @@
+From 1948fa64727685ac3f6584755212e2e738b6b051 Mon Sep 17 00:00:00 2001
+From: Sven Frotscher <sven.frotscher@gmail.com>
+Date: Thu, 28 Sep 2023 00:36:07 +0200
+Subject: ASoC: amd: yc: Fix non-functional mic on Lenovo 82YM
+
+From: Sven Frotscher <sven.frotscher@gmail.com>
+
+commit 1948fa64727685ac3f6584755212e2e738b6b051 upstream.
+
+Like the Lenovo 82TL, 82V2, 82QF and 82UG, the 82YM (Yoga 7 14ARP8)
+requires an entry in the quirk list to enable the internal microphone.
+The latter two received similar fixes in commit 1263cc0f414d
+("ASoC: amd: yc: Fix non-functional mic on Lenovo 82QF and 82UG").
+
+Fixes: c008323fe361 ("ASoC: amd: yc: Fix a non-functional mic on Lenovo 82SJ")
+Cc: stable@vger.kernel.org
+Signed-off-by: Sven Frotscher <sven.frotscher@gmail.com>
+Link: https://lore.kernel.org/r/20230927223758.18870-1-sven.frotscher@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/soc/amd/yc/acp6x-mach.c |    7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/sound/soc/amd/yc/acp6x-mach.c
++++ b/sound/soc/amd/yc/acp6x-mach.c
+@@ -238,6 +238,13 @@ static const struct dmi_system_id yc_acp
+               .driver_data = &acp6x_card,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
++                      DMI_MATCH(DMI_PRODUCT_NAME, "82YM"),
++              }
++      },
++      {
++              .driver_data = &acp6x_card,
++              .matches = {
++                      DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "82UG"),
+               }
+       },
diff --git a/queue-6.1/ata-libata-scsi-disable-scsi-device-manage_system_start_stop.patch b/queue-6.1/ata-libata-scsi-disable-scsi-device-manage_system_start_stop.patch
new file mode 100644 (file)
index 0000000..6741f6f
--- /dev/null
@@ -0,0 +1,410 @@
+From aa3998dbeb3abce63653b7f6d4542e7dcd022590 Mon Sep 17 00:00:00 2001
+From: Damien Le Moal <dlemoal@kernel.org>
+Date: Sat, 26 Aug 2023 09:43:39 +0900
+Subject: ata: libata-scsi: Disable scsi device manage_system_start_stop
+
+From: Damien Le Moal <dlemoal@kernel.org>
+
+commit aa3998dbeb3abce63653b7f6d4542e7dcd022590 upstream.
+
+The introduction of a device link to create a consumer/supplier
+relationship between the scsi device of an ATA device and the ATA port
+of that ATA device fixes the ordering of system suspend and resume
+operations. For suspend, the scsi device is suspended first and the ata
+port after it. This is fine as this allows the synchronize cache and
+START STOP UNIT commands issued by the scsi disk driver to be executed
+before the ata port is disabled.
+
+For resume operations, the ata port is resumed first, followed
+by the scsi device. This allows having the request queue of the scsi
+device to be unfrozen after the ata port resume is scheduled in EH,
+thus avoiding to see new requests prematurely issued to the ATA device.
+Since libata sets manage_system_start_stop to 1, the scsi disk resume
+operation also results in issuing a START STOP UNIT command to the
+device being resumed so that the device exits standby power mode.
+
+However, restoring the ATA device to the active power mode must be
+synchronized with libata EH processing of the port resume operation to
+avoid either 1) seeing the start stop unit command being received too
+early when the port is not yet resumed and ready to accept commands, or
+after the port resume process issues commands such as IDENTIFY to
+revalidate the device. In this last case, the risk is that the device
+revalidation fails with timeout errors as the drive is still spun down.
+
+Commit 0a8589055936 ("ata,scsi: do not issue START STOP UNIT on resume")
+disabled issuing the START STOP UNIT command to avoid issues with it.
+But this is incorrect as transitioning a device to the active power
+mode from the standby power mode set on suspend requires a media access
+command. The IDENTIFY, READ LOG and SET FEATURES commands executed in
+libata EH context triggered by the ata port resume operation may thus
+fail.
+
+Fix these synchronization issues is by handling a device power mode
+transitions for system suspend and resume directly in libata EH context,
+without relying on the scsi disk driver management triggered with the
+manage_system_start_stop flag.
+
+To do this, the following libata helper functions are introduced:
+
+1) ata_dev_power_set_standby():
+
+This function issues a STANDBY IMMEDIATE command to transitiom a device
+to the standby power mode. For HDDs, this spins down the disks. This
+function applies only to ATA and ZAC devices and does nothing otherwise.
+This function also does nothing for devices that have the
+ATA_FLAG_NO_POWEROFF_SPINDOWN or ATA_FLAG_NO_HIBERNATE_SPINDOWN flag
+set.
+
+For suspend, call ata_dev_power_set_standby() in
+ata_eh_handle_port_suspend() before the port is disabled and frozen.
+ata_eh_unload() is also modified to transition all enabled devices to
+the standby power mode when the system is shutdown or devices removed.
+
+2) ata_dev_power_set_active() and
+
+This function applies to ATA or ZAC devices and issues a VERIFY command
+for 1 sector at LBA 0 to transition the device to the active power mode.
+For HDDs, since this function will complete only once the disk spin up.
+Its execution uses the same timeouts as for reset, to give the drive
+enough time to complete spinup without triggering a command timeout.
+
+For resume, call ata_dev_power_set_active() in
+ata_eh_revalidate_and_attach() after the port has been enabled and
+before any other command is issued to the device.
+
+With these changes, the manage_system_start_stop and no_start_on_resume
+scsi device flags do not need to be set in ata_scsi_dev_config(). The
+flag manage_runtime_start_stop is still set to allow the sd driver to
+spinup/spindown a disk through the sd runtime operations.
+
+Fixes: 0a8589055936 ("ata,scsi: do not issue START STOP UNIT on resume")
+Cc: stable@vger.kernel.org
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Reviewed-by: Hannes Reinecke <hare@suse.de>
+Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/ata/libata-core.c |   90 ++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/ata/libata-eh.c   |   54 +++++++++++++++++++++++++++
+ drivers/ata/libata-scsi.c |   16 +++-----
+ drivers/ata/libata.h      |    2 +
+ include/linux/libata.h    |    7 ++-
+ 5 files changed, 157 insertions(+), 12 deletions(-)
+
+--- a/drivers/ata/libata-core.c
++++ b/drivers/ata/libata-core.c
+@@ -1944,6 +1944,96 @@ retry:
+ }
+ /**
++ *    ata_dev_power_set_standby - Set a device power mode to standby
++ *    @dev: target device
++ *
++ *    Issue a STANDBY IMMEDIATE command to set a device power mode to standby.
++ *    For an HDD device, this spins down the disks.
++ *
++ *    LOCKING:
++ *    Kernel thread context (may sleep).
++ */
++void ata_dev_power_set_standby(struct ata_device *dev)
++{
++      unsigned long ap_flags = dev->link->ap->flags;
++      struct ata_taskfile tf;
++      unsigned int err_mask;
++
++      /* Issue STANDBY IMMEDIATE command only if supported by the device */
++      if (dev->class != ATA_DEV_ATA && dev->class != ATA_DEV_ZAC)
++              return;
++
++      /*
++       * Some odd clown BIOSes issue spindown on power off (ACPI S4 or S5)
++       * causing some drives to spin up and down again. For these, do nothing
++       * if we are being called on shutdown.
++       */
++      if ((ap_flags & ATA_FLAG_NO_POWEROFF_SPINDOWN) &&
++          system_state == SYSTEM_POWER_OFF)
++              return;
++
++      if ((ap_flags & ATA_FLAG_NO_HIBERNATE_SPINDOWN) &&
++          system_entering_hibernation())
++              return;
++
++      ata_tf_init(dev, &tf);
++      tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
++      tf.protocol = ATA_PROT_NODATA;
++      tf.command = ATA_CMD_STANDBYNOW1;
++
++      ata_dev_notice(dev, "Entering standby power mode\n");
++
++      err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
++      if (err_mask)
++              ata_dev_err(dev, "STANDBY IMMEDIATE failed (err_mask=0x%x)\n",
++                          err_mask);
++}
++
++/**
++ *    ata_dev_power_set_active -  Set a device power mode to active
++ *    @dev: target device
++ *
++ *    Issue a VERIFY command to enter to ensure that the device is in the
++ *    active power mode. For a spun-down HDD (standby or idle power mode),
++ *    the VERIFY command will complete after the disk spins up.
++ *
++ *    LOCKING:
++ *    Kernel thread context (may sleep).
++ */
++void ata_dev_power_set_active(struct ata_device *dev)
++{
++      struct ata_taskfile tf;
++      unsigned int err_mask;
++
++      /*
++       * Issue READ VERIFY SECTORS command for 1 sector at lba=0 only
++       * if supported by the device.
++       */
++      if (dev->class != ATA_DEV_ATA && dev->class != ATA_DEV_ZAC)
++              return;
++
++      ata_tf_init(dev, &tf);
++      tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
++      tf.protocol = ATA_PROT_NODATA;
++      tf.command = ATA_CMD_VERIFY;
++      tf.nsect = 1;
++      if (dev->flags & ATA_DFLAG_LBA) {
++              tf.flags |= ATA_TFLAG_LBA;
++              tf.device |= ATA_LBA;
++      } else {
++              /* CHS */
++              tf.lbal = 0x1; /* sect */
++      }
++
++      ata_dev_notice(dev, "Entering active power mode\n");
++
++      err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
++      if (err_mask)
++              ata_dev_err(dev, "VERIFY failed (err_mask=0x%x)\n",
++                          err_mask);
++}
++
++/**
+  *    ata_read_log_page - read a specific log page
+  *    @dev: target device
+  *    @log: log to read
+--- a/drivers/ata/libata-eh.c
++++ b/drivers/ata/libata-eh.c
+@@ -106,6 +106,14 @@ static const unsigned int ata_eh_flush_t
+       UINT_MAX,
+ };
++static const unsigned int ata_eh_pm_timeouts[] = {
++      10000,  /* most drives spin up by 10sec */
++      10000,  /* > 99% working drives spin up before 20sec */
++      35000,  /* give > 30 secs of idleness for outlier devices */
++       5000,  /* and sweet one last chance */
++      UINT_MAX, /* > 1 min has elapsed, give up */
++};
++
+ static const unsigned int ata_eh_other_timeouts[] = {
+        5000,  /* same rationale as identify timeout */
+       10000,  /* ditto */
+@@ -147,6 +155,8 @@ ata_eh_cmd_timeout_table[ATA_EH_CMD_TIME
+         .timeouts = ata_eh_other_timeouts, },
+       { .commands = CMDS(ATA_CMD_FLUSH, ATA_CMD_FLUSH_EXT),
+         .timeouts = ata_eh_flush_timeouts },
++      { .commands = CMDS(ATA_CMD_VERIFY),
++        .timeouts = ata_eh_pm_timeouts },
+ };
+ #undef CMDS
+@@ -498,7 +508,19 @@ static void ata_eh_unload(struct ata_por
+       struct ata_device *dev;
+       unsigned long flags;
+-      /* Restore SControl IPM and SPD for the next driver and
++      /*
++       * Unless we are restarting, transition all enabled devices to
++       * standby power mode.
++       */
++      if (system_state != SYSTEM_RESTART) {
++              ata_for_each_link(link, ap, PMP_FIRST) {
++                      ata_for_each_dev(dev, link, ENABLED)
++                              ata_dev_power_set_standby(dev);
++              }
++      }
++
++      /*
++       * Restore SControl IPM and SPD for the next driver and
+        * disable attached devices.
+        */
+       ata_for_each_link(link, ap, PMP_FIRST) {
+@@ -687,6 +709,10 @@ void ata_scsi_port_error_handler(struct
+                               ehc->saved_xfer_mode[devno] = dev->xfer_mode;
+                               if (ata_ncq_enabled(dev))
+                                       ehc->saved_ncq_enabled |= 1 << devno;
++
++                              /* If we are resuming, wake up the device */
++                              if (ap->pflags & ATA_PFLAG_RESUMING)
++                                      ehc->i.dev_action[devno] |= ATA_EH_SET_ACTIVE;
+                       }
+               }
+@@ -750,6 +776,8 @@ void ata_scsi_port_error_handler(struct
+       /* clean up */
+       spin_lock_irqsave(ap->lock, flags);
++      ap->pflags &= ~ATA_PFLAG_RESUMING;
++
+       if (ap->pflags & ATA_PFLAG_LOADING)
+               ap->pflags &= ~ATA_PFLAG_LOADING;
+       else if ((ap->pflags & ATA_PFLAG_SCSI_HOTPLUG) &&
+@@ -1241,6 +1269,13 @@ void ata_eh_detach_dev(struct ata_device
+       struct ata_eh_context *ehc = &link->eh_context;
+       unsigned long flags;
++      /*
++       * If the device is still enabled, transition it to standby power mode
++       * (i.e. spin down HDDs).
++       */
++      if (ata_dev_enabled(dev))
++              ata_dev_power_set_standby(dev);
++
+       ata_dev_disable(dev);
+       spin_lock_irqsave(ap->lock, flags);
+@@ -2927,6 +2962,15 @@ static int ata_eh_revalidate_and_attach(
+               if (ehc->i.flags & ATA_EHI_DID_RESET)
+                       readid_flags |= ATA_READID_POSTRESET;
++              /*
++               * When resuming, before executing any command, make sure to
++               * transition the device to the active power mode.
++               */
++              if ((action & ATA_EH_SET_ACTIVE) && ata_dev_enabled(dev)) {
++                      ata_dev_power_set_active(dev);
++                      ata_eh_done(link, dev, ATA_EH_SET_ACTIVE);
++              }
++
+               if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) {
+                       WARN_ON(dev->class == ATA_DEV_PMP);
+@@ -3886,6 +3930,7 @@ static void ata_eh_handle_port_suspend(s
+       unsigned long flags;
+       int rc = 0;
+       struct ata_device *dev;
++      struct ata_link *link;
+       /* are we suspending? */
+       spin_lock_irqsave(ap->lock, flags);
+@@ -3898,6 +3943,12 @@ static void ata_eh_handle_port_suspend(s
+       WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED);
++      /* Set all devices attached to the port in standby mode */
++      ata_for_each_link(link, ap, HOST_FIRST) {
++              ata_for_each_dev(dev, link, ENABLED)
++                      ata_dev_power_set_standby(dev);
++      }
++
+       /*
+        * If we have a ZPODD attached, check its zero
+        * power ready status before the port is frozen.
+@@ -3980,6 +4031,7 @@ static void ata_eh_handle_port_resume(st
+       /* update the flags */
+       spin_lock_irqsave(ap->lock, flags);
+       ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED);
++      ap->pflags |= ATA_PFLAG_RESUMING;
+       spin_unlock_irqrestore(ap->lock, flags);
+ }
+ #endif /* CONFIG_PM */
+--- a/drivers/ata/libata-scsi.c
++++ b/drivers/ata/libata-scsi.c
+@@ -1081,15 +1081,13 @@ int ata_scsi_dev_config(struct scsi_devi
+               }
+       } else {
+               sdev->sector_size = ata_id_logical_sector_size(dev->id);
++
+               /*
+-               * Stop the drive on suspend but do not issue START STOP UNIT
+-               * on resume as this is not necessary and may fail: the device
+-               * will be woken up by ata_port_pm_resume() with a port reset
+-               * and device revalidation.
++               * Ask the sd driver to issue START STOP UNIT on runtime suspend
++               * and resume only. For system level suspend/resume, devices
++               * power state is handled directly by libata EH.
+                */
+-              sdev->manage_system_start_stop = true;
+               sdev->manage_runtime_start_stop = true;
+-              sdev->no_start_on_resume = 1;
+       }
+       /*
+@@ -1265,7 +1263,7 @@ static unsigned int ata_scsi_start_stop_
+       }
+       if (cdb[4] & 0x1) {
+-              tf->nsect = 1;  /* 1 sector, lba=0 */
++              tf->nsect = 1;  /* 1 sector, lba=0 */
+               if (qc->dev->flags & ATA_DFLAG_LBA) {
+                       tf->flags |= ATA_TFLAG_LBA;
+@@ -1281,7 +1279,7 @@ static unsigned int ata_scsi_start_stop_
+                       tf->lbah = 0x0; /* cyl high */
+               }
+-              tf->command = ATA_CMD_VERIFY;   /* READ VERIFY */
++              tf->command = ATA_CMD_VERIFY;   /* READ VERIFY */
+       } else {
+               /* Some odd clown BIOSen issue spindown on power off (ACPI S4
+                * or S5) causing some drives to spin up and down again.
+@@ -1291,7 +1289,7 @@ static unsigned int ata_scsi_start_stop_
+                       goto skip;
+               if ((qc->ap->flags & ATA_FLAG_NO_HIBERNATE_SPINDOWN) &&
+-                   system_entering_hibernation())
++                  system_entering_hibernation())
+                       goto skip;
+               /* Issue ATA STANDBY IMMEDIATE command */
+--- a/drivers/ata/libata.h
++++ b/drivers/ata/libata.h
+@@ -62,6 +62,8 @@ extern int ata_dev_reread_id(struct ata_
+ extern int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
+                             unsigned int readid_flags);
+ extern int ata_dev_configure(struct ata_device *dev);
++extern void ata_dev_power_set_standby(struct ata_device *dev);
++extern void ata_dev_power_set_active(struct ata_device *dev);
+ extern int sata_down_spd_limit(struct ata_link *link, u32 spd_limit);
+ extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel);
+ extern unsigned int ata_dev_set_feature(struct ata_device *dev,
+--- a/include/linux/libata.h
++++ b/include/linux/libata.h
+@@ -189,6 +189,7 @@ enum {
+       ATA_PFLAG_UNLOADING     = (1 << 9), /* driver is being unloaded */
+       ATA_PFLAG_UNLOADED      = (1 << 10), /* driver is unloaded */
++      ATA_PFLAG_RESUMING      = (1 << 16),  /* port is being resumed */
+       ATA_PFLAG_SUSPENDED     = (1 << 17), /* port is suspended (power) */
+       ATA_PFLAG_PM_PENDING    = (1 << 18), /* PM operation pending */
+       ATA_PFLAG_INIT_GTM_VALID = (1 << 19), /* initial gtm data valid */
+@@ -311,8 +312,10 @@ enum {
+       ATA_EH_RESET            = ATA_EH_SOFTRESET | ATA_EH_HARDRESET,
+       ATA_EH_ENABLE_LINK      = (1 << 3),
+       ATA_EH_PARK             = (1 << 5), /* unload heads and stop I/O */
++      ATA_EH_SET_ACTIVE       = (1 << 6), /* Set a device to active power mode */
+-      ATA_EH_PERDEV_MASK      = ATA_EH_REVALIDATE | ATA_EH_PARK,
++      ATA_EH_PERDEV_MASK      = ATA_EH_REVALIDATE | ATA_EH_PARK |
++                                ATA_EH_SET_ACTIVE,
+       ATA_EH_ALL_ACTIONS      = ATA_EH_REVALIDATE | ATA_EH_RESET |
+                                 ATA_EH_ENABLE_LINK,
+@@ -350,7 +353,7 @@ enum {
+       /* This should match the actual table size of
+        * ata_eh_cmd_timeout_table in libata-eh.c.
+        */
+-      ATA_EH_CMD_TIMEOUT_TABLE_SIZE = 7,
++      ATA_EH_CMD_TIMEOUT_TABLE_SIZE = 8,
+       /* Horkage types. May be set by libata or controller on drives
+          (some horkage may be drive/controller pair dependent */
diff --git a/queue-6.1/hid-logitech-hidpp-fix-kernel-crash-on-receiver-usb-disconnect.patch b/queue-6.1/hid-logitech-hidpp-fix-kernel-crash-on-receiver-usb-disconnect.patch
new file mode 100644 (file)
index 0000000..fdb056c
--- /dev/null
@@ -0,0 +1,177 @@
+From dac501397b9d81e4782232c39f94f4307b137452 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Thu, 5 Oct 2023 20:26:38 +0200
+Subject: HID: logitech-hidpp: Fix kernel crash on receiver USB disconnect
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+commit dac501397b9d81e4782232c39f94f4307b137452 upstream.
+
+hidpp_connect_event() has *four* time-of-check vs time-of-use (TOCTOU)
+races when it races with itself.
+
+hidpp_connect_event() primarily runs from a workqueue but it also runs
+on probe() and if a "device-connected" packet is received by the hw
+when the thread running hidpp_connect_event() from probe() is waiting on
+the hw, then a second thread running hidpp_connect_event() will be
+started from the workqueue.
+
+This opens the following races (note the below code is simplified):
+
+1. Retrieving + printing the protocol (harmless race):
+
+       if (!hidpp->protocol_major) {
+               hidpp_root_get_protocol_version()
+               hidpp->protocol_major = response.rap.params[0];
+       }
+
+We can actually see this race hit in the dmesg in the abrt output
+attached to rhbz#2227968:
+
+[ 3064.624215] logitech-hidpp-device 0003:046D:4071.0049: HID++ 4.5 device connected.
+[ 3064.658184] logitech-hidpp-device 0003:046D:4071.0049: HID++ 4.5 device connected.
+
+Testing with extra logging added has shown that after this the 2 threads
+take turn grabbing the hw access mutex (send_mutex) so they ping-pong
+through all the other TOCTOU cases managing to hit all of them:
+
+2. Updating the name to the HIDPP name (harmless race):
+
+       if (hidpp->name == hdev->name) {
+               ...
+               hidpp->name = new_name;
+       }
+
+3. Initializing the power_supply class for the battery (problematic!):
+
+hidpp_initialize_battery()
+{
+        if (hidpp->battery.ps)
+                return 0;
+
+       probe_battery(); /* Blocks, threads take turns executing this */
+
+       hidpp->battery.desc.properties =
+               devm_kmemdup(dev, hidpp_battery_props, cnt, GFP_KERNEL);
+
+       hidpp->battery.ps =
+               devm_power_supply_register(&hidpp->hid_dev->dev,
+                                          &hidpp->battery.desc, cfg);
+}
+
+4. Creating delayed input_device (potentially problematic):
+
+       if (hidpp->delayed_input)
+               return;
+
+       hidpp->delayed_input = hidpp_allocate_input(hdev);
+
+The really big problem here is 3. Hitting the race leads to the following
+sequence:
+
+       hidpp->battery.desc.properties =
+               devm_kmemdup(dev, hidpp_battery_props, cnt, GFP_KERNEL);
+
+       hidpp->battery.ps =
+               devm_power_supply_register(&hidpp->hid_dev->dev,
+                                          &hidpp->battery.desc, cfg);
+
+       ...
+
+       hidpp->battery.desc.properties =
+               devm_kmemdup(dev, hidpp_battery_props, cnt, GFP_KERNEL);
+
+       hidpp->battery.ps =
+               devm_power_supply_register(&hidpp->hid_dev->dev,
+                                          &hidpp->battery.desc, cfg);
+
+So now we have registered 2 power supplies for the same battery,
+which looks a bit weird from userspace's pov but this is not even
+the really big problem.
+
+Notice how:
+
+1. This is all devm-maganaged
+2. The hidpp->battery.desc struct is shared between the 2 power supplies
+3. hidpp->battery.desc.properties points to the result from the second
+   devm_kmemdup()
+
+This causes a use after free scenario on USB disconnect of the receiver:
+1. The last registered power supply class device gets unregistered
+2. The memory from the last devm_kmemdup() call gets freed,
+   hidpp->battery.desc.properties now points to freed memory
+3. The first registered power supply class device gets unregistered,
+   this involves sending a remove uevent to userspace which invokes
+   power_supply_uevent() to fill the uevent data
+4. power_supply_uevent() uses hidpp->battery.desc.properties which
+   now points to freed memory leading to backtraces like this one:
+
+Sep 22 20:01:35 eric kernel: BUG: unable to handle page fault for address: ffffb2140e017f08
+...
+Sep 22 20:01:35 eric kernel: Workqueue: usb_hub_wq hub_event
+Sep 22 20:01:35 eric kernel: RIP: 0010:power_supply_uevent+0xee/0x1d0
+...
+Sep 22 20:01:35 eric kernel:  ? asm_exc_page_fault+0x26/0x30
+Sep 22 20:01:35 eric kernel:  ? power_supply_uevent+0xee/0x1d0
+Sep 22 20:01:35 eric kernel:  ? power_supply_uevent+0x10d/0x1d0
+Sep 22 20:01:35 eric kernel:  dev_uevent+0x10f/0x2d0
+Sep 22 20:01:35 eric kernel:  kobject_uevent_env+0x291/0x680
+Sep 22 20:01:35 eric kernel:  power_supply_unregister+0x8e/0xa0
+Sep 22 20:01:35 eric kernel:  release_nodes+0x3d/0xb0
+Sep 22 20:01:35 eric kernel:  devres_release_group+0xfc/0x130
+Sep 22 20:01:35 eric kernel:  hid_device_remove+0x56/0xa0
+Sep 22 20:01:35 eric kernel:  device_release_driver_internal+0x19f/0x200
+Sep 22 20:01:35 eric kernel:  bus_remove_device+0xc6/0x130
+Sep 22 20:01:35 eric kernel:  device_del+0x15c/0x3f0
+Sep 22 20:01:35 eric kernel:  ? __queue_work+0x1df/0x440
+Sep 22 20:01:35 eric kernel:  hid_destroy_device+0x4b/0x60
+Sep 22 20:01:35 eric kernel:  logi_dj_remove+0x9a/0x100 [hid_logitech_dj 5c91534a0ead2b65e04dd799a0437e3b99b21bc4]
+Sep 22 20:01:35 eric kernel:  hid_device_remove+0x44/0xa0
+Sep 22 20:01:35 eric kernel:  device_release_driver_internal+0x19f/0x200
+Sep 22 20:01:35 eric kernel:  bus_remove_device+0xc6/0x130
+Sep 22 20:01:35 eric kernel:  device_del+0x15c/0x3f0
+Sep 22 20:01:35 eric kernel:  ? __queue_work+0x1df/0x440
+Sep 22 20:01:35 eric kernel:  hid_destroy_device+0x4b/0x60
+Sep 22 20:01:35 eric kernel:  usbhid_disconnect+0x47/0x60 [usbhid 727dcc1c0b94e6b4418727a468398ac3bca492f3]
+Sep 22 20:01:35 eric kernel:  usb_unbind_interface+0x90/0x270
+Sep 22 20:01:35 eric kernel:  device_release_driver_internal+0x19f/0x200
+Sep 22 20:01:35 eric kernel:  bus_remove_device+0xc6/0x130
+Sep 22 20:01:35 eric kernel:  device_del+0x15c/0x3f0
+Sep 22 20:01:35 eric kernel:  ? kobject_put+0xa0/0x1d0
+Sep 22 20:01:35 eric kernel:  usb_disable_device+0xcd/0x1e0
+Sep 22 20:01:35 eric kernel:  usb_disconnect+0xde/0x2c0
+Sep 22 20:01:35 eric kernel:  usb_disconnect+0xc3/0x2c0
+Sep 22 20:01:35 eric kernel:  hub_event+0xe80/0x1c10
+
+There have been quite a few bug reports (see Link tags) about this crash.
+
+Fix all the TOCTOU issues, including the really bad power-supply related
+system crash on USB disconnect, by making probe() use the workqueue for
+running hidpp_connect_event() too, so that it can never run more then once.
+
+Link: https://bugzilla.redhat.com/show_bug.cgi?id=2227221
+Link: https://bugzilla.redhat.com/show_bug.cgi?id=2227968
+Link: https://bugzilla.redhat.com/show_bug.cgi?id=2227968
+Link: https://bugzilla.redhat.com/show_bug.cgi?id=2242189
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=217412#c58
+Cc: stable@vger.kernel.org
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://lore.kernel.org/r/20231005182638.3776-1-hdegoede@redhat.com
+Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/hid/hid-logitech-hidpp.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/hid/hid-logitech-hidpp.c
++++ b/drivers/hid/hid-logitech-hidpp.c
+@@ -4275,7 +4275,8 @@ static int hidpp_probe(struct hid_device
+                       goto hid_hw_init_fail;
+       }
+-      hidpp_connect_event(hidpp);
++      schedule_work(&hidpp->work);
++      flush_work(&hidpp->work);
+       if (will_restart) {
+               /* Reset the HID node state */
diff --git a/queue-6.1/net-prevent-address-rewrite-in-kernel_bind.patch b/queue-6.1/net-prevent-address-rewrite-in-kernel_bind.patch
new file mode 100644 (file)
index 0000000..f90b541
--- /dev/null
@@ -0,0 +1,89 @@
+From c889a99a21bf124c3db08d09df919f0eccc5ea4c Mon Sep 17 00:00:00 2001
+From: Jordan Rife <jrife@google.com>
+Date: Thu, 21 Sep 2023 18:46:42 -0500
+Subject: net: prevent address rewrite in kernel_bind()
+
+From: Jordan Rife <jrife@google.com>
+
+commit c889a99a21bf124c3db08d09df919f0eccc5ea4c upstream.
+
+Similar to the change in commit 0bdf399342c5("net: Avoid address
+overwrite in kernel_connect"), BPF hooks run on bind may rewrite the
+address passed to kernel_bind(). This change
+
+1) Makes a copy of the bind address in kernel_bind() to insulate
+   callers.
+2) Replaces direct calls to sock->ops->bind() in net with kernel_bind()
+
+Link: https://lore.kernel.org/netdev/20230912013332.2048422-1-jrife@google.com/
+Fixes: 4fbac77d2d09 ("bpf: Hooks for sys_bind")
+Cc: stable@vger.kernel.org
+Reviewed-by: Willem de Bruijn <willemb@google.com>
+Signed-off-by: Jordan Rife <jrife@google.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/netfilter/ipvs/ip_vs_sync.c |    4 ++--
+ net/rds/tcp_connect.c           |    2 +-
+ net/rds/tcp_listen.c            |    2 +-
+ net/socket.c                    |    6 +++++-
+ 4 files changed, 9 insertions(+), 5 deletions(-)
+
+--- a/net/netfilter/ipvs/ip_vs_sync.c
++++ b/net/netfilter/ipvs/ip_vs_sync.c
+@@ -1441,7 +1441,7 @@ static int bind_mcastif_addr(struct sock
+       sin.sin_addr.s_addr  = addr;
+       sin.sin_port         = 0;
+-      return sock->ops->bind(sock, (struct sockaddr*)&sin, sizeof(sin));
++      return kernel_bind(sock, (struct sockaddr *)&sin, sizeof(sin));
+ }
+ static void get_mcast_sockaddr(union ipvs_sockaddr *sa, int *salen,
+@@ -1548,7 +1548,7 @@ static int make_receive_sock(struct netn
+       get_mcast_sockaddr(&mcast_addr, &salen, &ipvs->bcfg, id);
+       sock->sk->sk_bound_dev_if = dev->ifindex;
+-      result = sock->ops->bind(sock, (struct sockaddr *)&mcast_addr, salen);
++      result = kernel_bind(sock, (struct sockaddr *)&mcast_addr, salen);
+       if (result < 0) {
+               pr_err("Error binding to the multicast addr\n");
+               goto error;
+--- a/net/rds/tcp_connect.c
++++ b/net/rds/tcp_connect.c
+@@ -145,7 +145,7 @@ int rds_tcp_conn_path_connect(struct rds
+               addrlen = sizeof(sin);
+       }
+-      ret = sock->ops->bind(sock, addr, addrlen);
++      ret = kernel_bind(sock, addr, addrlen);
+       if (ret) {
+               rdsdebug("bind failed with %d at address %pI6c\n",
+                        ret, &conn->c_laddr);
+--- a/net/rds/tcp_listen.c
++++ b/net/rds/tcp_listen.c
+@@ -304,7 +304,7 @@ struct socket *rds_tcp_listen_init(struc
+               addr_len = sizeof(*sin);
+       }
+-      ret = sock->ops->bind(sock, (struct sockaddr *)&ss, addr_len);
++      ret = kernel_bind(sock, (struct sockaddr *)&ss, addr_len);
+       if (ret < 0) {
+               rdsdebug("could not bind %s listener socket: %d\n",
+                        isv6 ? "IPv6" : "IPv4", ret);
+--- a/net/socket.c
++++ b/net/socket.c
+@@ -3454,7 +3454,11 @@ static long compat_sock_ioctl(struct fil
+ int kernel_bind(struct socket *sock, struct sockaddr *addr, int addrlen)
+ {
+-      return sock->ops->bind(sock, addr, addrlen);
++      struct sockaddr_storage address;
++
++      memcpy(&address, addr, addrlen);
++
++      return sock->ops->bind(sock, (struct sockaddr *)&address, addrlen);
+ }
+ EXPORT_SYMBOL(kernel_bind);
diff --git a/queue-6.1/quota-fix-slow-quotaoff.patch b/queue-6.1/quota-fix-slow-quotaoff.patch
new file mode 100644 (file)
index 0000000..36b1a5a
--- /dev/null
@@ -0,0 +1,208 @@
+From 869b6ea1609f655a43251bf41757aa44e5350a8f Mon Sep 17 00:00:00 2001
+From: Jan Kara <jack@suse.cz>
+Date: Wed, 4 Oct 2023 15:32:01 +0200
+Subject: quota: Fix slow quotaoff
+
+From: Jan Kara <jack@suse.cz>
+
+commit 869b6ea1609f655a43251bf41757aa44e5350a8f upstream.
+
+Eric has reported that commit dabc8b207566 ("quota: fix dqput() to
+follow the guarantees dquot_srcu should provide") heavily increases
+runtime of generic/270 xfstest for ext4 in nojournal mode. The reason
+for this is that ext4 in nojournal mode leaves dquots dirty until the last
+dqput() and thus the cleanup done in quota_release_workfn() has to write
+them all. Due to the way quota_release_workfn() is written this results
+in synchronize_srcu() call for each dirty dquot which makes the dquot
+cleanup when turning quotas off extremely slow.
+
+To be able to avoid synchronize_srcu() for each dirty dquot we need to
+rework how we track dquots to be cleaned up. Instead of keeping the last
+dquot reference while it is on releasing_dquots list, we drop it right
+away and mark the dquot with new DQ_RELEASING_B bit instead. This way we
+can we can remove dquot from releasing_dquots list when new reference to
+it is acquired and thus there's no need to call synchronize_srcu() each
+time we drop dq_list_lock.
+
+References: https://lore.kernel.org/all/ZRytn6CxFK2oECUt@debian-BULLSEYE-live-builder-AMD64
+Reported-by: Eric Whitney <enwlinux@gmail.com>
+Fixes: dabc8b207566 ("quota: fix dqput() to follow the guarantees dquot_srcu should provide")
+CC: stable@vger.kernel.org
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/quota/dquot.c         |   66 +++++++++++++++++++++++++++--------------------
+ include/linux/quota.h    |    4 ++
+ include/linux/quotaops.h |    2 -
+ 3 files changed, 43 insertions(+), 29 deletions(-)
+
+--- a/fs/quota/dquot.c
++++ b/fs/quota/dquot.c
+@@ -233,19 +233,18 @@ static void put_quota_format(struct quot
+  * All dquots are placed to the end of inuse_list when first created, and this
+  * list is used for invalidate operation, which must look at every dquot.
+  *
+- * When the last reference of a dquot will be dropped, the dquot will be
+- * added to releasing_dquots. We'd then queue work item which would call
++ * When the last reference of a dquot is dropped, the dquot is added to
++ * releasing_dquots. We'll then queue work item which will call
+  * synchronize_srcu() and after that perform the final cleanup of all the
+- * dquots on the list. Both releasing_dquots and free_dquots use the
+- * dq_free list_head in the dquot struct. When a dquot is removed from
+- * releasing_dquots, a reference count is always subtracted, and if
+- * dq_count == 0 at that point, the dquot will be added to the free_dquots.
++ * dquots on the list. Each cleaned up dquot is moved to free_dquots list.
++ * Both releasing_dquots and free_dquots use the dq_free list_head in the dquot
++ * struct.
+  *
+- * Unused dquots (dq_count == 0) are added to the free_dquots list when freed,
+- * and this list is searched whenever we need an available dquot.  Dquots are
+- * removed from the list as soon as they are used again, and
+- * dqstats.free_dquots gives the number of dquots on the list. When
+- * dquot is invalidated it's completely released from memory.
++ * Unused and cleaned up dquots are in the free_dquots list and this list is
++ * searched whenever we need an available dquot. Dquots are removed from the
++ * list as soon as they are used again and dqstats.free_dquots gives the number
++ * of dquots on the list. When dquot is invalidated it's completely released
++ * from memory.
+  *
+  * Dirty dquots are added to the dqi_dirty_list of quota_info when mark
+  * dirtied, and this list is searched when writing dirty dquots back to
+@@ -321,6 +320,7 @@ static inline void put_dquot_last(struct
+ static inline void put_releasing_dquots(struct dquot *dquot)
+ {
+       list_add_tail(&dquot->dq_free, &releasing_dquots);
++      set_bit(DQ_RELEASING_B, &dquot->dq_flags);
+ }
+ static inline void remove_free_dquot(struct dquot *dquot)
+@@ -328,8 +328,10 @@ static inline void remove_free_dquot(str
+       if (list_empty(&dquot->dq_free))
+               return;
+       list_del_init(&dquot->dq_free);
+-      if (!atomic_read(&dquot->dq_count))
++      if (!test_bit(DQ_RELEASING_B, &dquot->dq_flags))
+               dqstats_dec(DQST_FREE_DQUOTS);
++      else
++              clear_bit(DQ_RELEASING_B, &dquot->dq_flags);
+ }
+ static inline void put_inuse(struct dquot *dquot)
+@@ -581,12 +583,6 @@ restart:
+                       continue;
+               /* Wait for dquot users */
+               if (atomic_read(&dquot->dq_count)) {
+-                      /* dquot in releasing_dquots, flush and retry */
+-                      if (!list_empty(&dquot->dq_free)) {
+-                              spin_unlock(&dq_list_lock);
+-                              goto restart;
+-                      }
+-
+                       atomic_inc(&dquot->dq_count);
+                       spin_unlock(&dq_list_lock);
+                       /*
+@@ -606,6 +602,15 @@ restart:
+                       goto restart;
+               }
+               /*
++               * The last user already dropped its reference but dquot didn't
++               * get fully cleaned up yet. Restart the scan which flushes the
++               * work cleaning up released dquots.
++               */
++              if (test_bit(DQ_RELEASING_B, &dquot->dq_flags)) {
++                      spin_unlock(&dq_list_lock);
++                      goto restart;
++              }
++              /*
+                * Quota now has no users and it has been written on last
+                * dqput()
+                */
+@@ -696,6 +701,13 @@ int dquot_writeback_dquots(struct super_
+                                                dq_dirty);
+                       WARN_ON(!dquot_active(dquot));
++                      /* If the dquot is releasing we should not touch it */
++                      if (test_bit(DQ_RELEASING_B, &dquot->dq_flags)) {
++                              spin_unlock(&dq_list_lock);
++                              flush_delayed_work(&quota_release_work);
++                              spin_lock(&dq_list_lock);
++                              continue;
++                      }
+                       /* Now we have active dquot from which someone is
+                        * holding reference so we can safely just increase
+@@ -809,18 +821,18 @@ static void quota_release_workfn(struct
+       /* Exchange the list head to avoid livelock. */
+       list_replace_init(&releasing_dquots, &rls_head);
+       spin_unlock(&dq_list_lock);
++      synchronize_srcu(&dquot_srcu);
+ restart:
+-      synchronize_srcu(&dquot_srcu);
+       spin_lock(&dq_list_lock);
+       while (!list_empty(&rls_head)) {
+               dquot = list_first_entry(&rls_head, struct dquot, dq_free);
+-              /* Dquot got used again? */
+-              if (atomic_read(&dquot->dq_count) > 1) {
+-                      remove_free_dquot(dquot);
+-                      atomic_dec(&dquot->dq_count);
+-                      continue;
+-              }
++              WARN_ON_ONCE(atomic_read(&dquot->dq_count));
++              /*
++               * Note that DQ_RELEASING_B protects us from racing with
++               * invalidate_dquots() calls so we are safe to work with the
++               * dquot even after we drop dq_list_lock.
++               */
+               if (dquot_dirty(dquot)) {
+                       spin_unlock(&dq_list_lock);
+                       /* Commit dquot before releasing */
+@@ -834,7 +846,6 @@ restart:
+               }
+               /* Dquot is inactive and clean, now move it to free list */
+               remove_free_dquot(dquot);
+-              atomic_dec(&dquot->dq_count);
+               put_dquot_last(dquot);
+       }
+       spin_unlock(&dq_list_lock);
+@@ -875,6 +886,7 @@ void dqput(struct dquot *dquot)
+       BUG_ON(!list_empty(&dquot->dq_free));
+ #endif
+       put_releasing_dquots(dquot);
++      atomic_dec(&dquot->dq_count);
+       spin_unlock(&dq_list_lock);
+       queue_delayed_work(system_unbound_wq, &quota_release_work, 1);
+ }
+@@ -963,7 +975,7 @@ we_slept:
+               dqstats_inc(DQST_LOOKUPS);
+       }
+       /* Wait for dq_lock - after this we know that either dquot_release() is
+-       * already finished or it will be canceled due to dq_count > 1 test */
++       * already finished or it will be canceled due to dq_count > 0 test */
+       wait_on_dquot(dquot);
+       /* Read the dquot / allocate space in quota file */
+       if (!dquot_active(dquot)) {
+--- a/include/linux/quota.h
++++ b/include/linux/quota.h
+@@ -285,7 +285,9 @@ static inline void dqstats_dec(unsigned
+ #define DQ_FAKE_B     3       /* no limits only usage */
+ #define DQ_READ_B     4       /* dquot was read into memory */
+ #define DQ_ACTIVE_B   5       /* dquot is active (dquot_release not called) */
+-#define DQ_LASTSET_B  6       /* Following 6 bits (see QIF_) are reserved\
++#define DQ_RELEASING_B        6       /* dquot is in releasing_dquots list waiting
++                               * to be cleaned up */
++#define DQ_LASTSET_B  7       /* Following 6 bits (see QIF_) are reserved\
+                                * for the mask of entries set via SETQUOTA\
+                                * quotactl. They are set under dq_data_lock\
+                                * and the quota format handling dquot can\
+--- a/include/linux/quotaops.h
++++ b/include/linux/quotaops.h
+@@ -57,7 +57,7 @@ static inline bool dquot_is_busy(struct
+ {
+       if (test_bit(DQ_MOD_B, &dquot->dq_flags))
+               return true;
+-      if (atomic_read(&dquot->dq_count) > 1)
++      if (atomic_read(&dquot->dq_count) > 0)
+               return true;
+       return false;
+ }
diff --git a/queue-6.1/scsi-do-not-rescan-devices-with-a-suspended-queue.patch b/queue-6.1/scsi-do-not-rescan-devices-with-a-suspended-queue.patch
new file mode 100644 (file)
index 0000000..7fcd1d6
--- /dev/null
@@ -0,0 +1,52 @@
+From 626b13f015e080e434b1dee9a0c116ddbf4fb695 Mon Sep 17 00:00:00 2001
+From: Damien Le Moal <dlemoal@kernel.org>
+Date: Wed, 4 Oct 2023 17:50:49 +0900
+Subject: scsi: Do not rescan devices with a suspended queue
+
+From: Damien Le Moal <dlemoal@kernel.org>
+
+commit 626b13f015e080e434b1dee9a0c116ddbf4fb695 upstream.
+
+Commit ff48b37802e5 ("scsi: Do not attempt to rescan suspended devices")
+modified scsi_rescan_device() to avoid attempting rescanning a suspended
+device. However, the modification added a check to verify that a SCSI
+device is in the running state without checking if the device request
+queue (in the case of block device) is also running, thus allowing the
+exectuion of internal requests. Without checking the device request
+queue, commit ff48b37802e5 fix is incomplete and deadlocks on resume can
+still happen. Use blk_queue_pm_only() to check if the device request
+queue allows executing commands in addition to checking the SCSI device
+state.
+
+Reported-by: Petr Tesarik <petr@tesarici.cz>
+Fixes: ff48b37802e5 ("scsi: Do not attempt to rescan suspended devices")
+Cc: stable@vger.kernel.org
+Tested-by: Petr Tesarik <petr@tesarici.cz>
+Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/scsi_scan.c |   11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+--- a/drivers/scsi/scsi_scan.c
++++ b/drivers/scsi/scsi_scan.c
+@@ -1619,12 +1619,13 @@ int scsi_rescan_device(struct scsi_devic
+       device_lock(dev);
+       /*
+-       * Bail out if the device is not running. Otherwise, the rescan may
+-       * block waiting for commands to be executed, with us holding the
+-       * device lock. This can result in a potential deadlock in the power
+-       * management core code when system resume is on-going.
++       * Bail out if the device or its queue are not running. Otherwise,
++       * the rescan may block waiting for commands to be executed, with us
++       * holding the device lock. This can result in a potential deadlock
++       * in the power management core code when system resume is on-going.
+        */
+-      if (sdev->sdev_state != SDEV_RUNNING) {
++      if (sdev->sdev_state != SDEV_RUNNING ||
++          blk_queue_pm_only(sdev->request_queue)) {
+               ret = -EWOULDBLOCK;
+               goto unlock;
+       }
index d1b115e9ddde6aad25743f83f35f272bd5091383..4104b21f38cf2593e146808c9d4483b2bdf43b8d 100644 (file)
@@ -6,3 +6,9 @@ perf-arm-cmn-fix-the-unhandled-overflow-status-of-co.patch
 platform-x86-think-lmi-fix-reference-leak.patch
 platform-x86-hp-wmi-mark-driver-struct-with-__refdat.patch
 lib-test_meminit-fix-off-by-one-error-in-test_pages.patch
+scsi-do-not-rescan-devices-with-a-suspended-queue.patch
+hid-logitech-hidpp-fix-kernel-crash-on-receiver-usb-disconnect.patch
+quota-fix-slow-quotaoff.patch
+asoc-amd-yc-fix-non-functional-mic-on-lenovo-82ym.patch
+ata-libata-scsi-disable-scsi-device-manage_system_start_stop.patch
+net-prevent-address-rewrite-in-kernel_bind.patch