]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.19-stable patches master
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 26 Feb 2026 14:52:03 +0000 (06:52 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 26 Feb 2026 14:52:03 +0000 (06:52 -0800)
added patches:
ata-libata-core-fix-cancellation-of-a-port-deferred-qc-work.patch
ata-libata-eh-correctly-handle-deferred-qc-timeouts.patch

queue-6.19/ata-libata-core-fix-cancellation-of-a-port-deferred-qc-work.patch [new file with mode: 0644]
queue-6.19/ata-libata-eh-correctly-handle-deferred-qc-timeouts.patch [new file with mode: 0644]
queue-6.19/series

diff --git a/queue-6.19/ata-libata-core-fix-cancellation-of-a-port-deferred-qc-work.patch b/queue-6.19/ata-libata-core-fix-cancellation-of-a-port-deferred-qc-work.patch
new file mode 100644 (file)
index 0000000..10faa92
--- /dev/null
@@ -0,0 +1,49 @@
+From 55db009926634b20955bd8abbee921adbc8d2cb4 Mon Sep 17 00:00:00 2001
+From: Damien Le Moal <dlemoal@kernel.org>
+Date: Fri, 20 Feb 2026 12:09:12 +0900
+Subject: ata: libata-core: fix cancellation of a port deferred qc work
+
+From: Damien Le Moal <dlemoal@kernel.org>
+
+commit 55db009926634b20955bd8abbee921adbc8d2cb4 upstream.
+
+cancel_work_sync() is a sleeping function so it cannot be called with
+the spin lock of a port being held. Move the call to this function in
+ata_port_detach() after EH completes, with the port lock released,
+together with other work cancellation calls.
+
+Fixes: 0ea84089dbf6 ("ata: libata-scsi: avoid Non-NCQ command starvation")
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Reviewed-by: Hannes Reinecke <hare@suse.de>
+Reviewed-by: Igor Pylypiv <ipylypiv@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/ata/libata-core.c |    8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+--- a/drivers/ata/libata-core.c
++++ b/drivers/ata/libata-core.c
+@@ -6233,10 +6233,6 @@ static void ata_port_detach(struct ata_p
+               }
+       }
+-      /* Make sure the deferred qc work finished. */
+-      cancel_work_sync(&ap->deferred_qc_work);
+-      WARN_ON(ap->deferred_qc);
+-
+       /* Tell EH to disable all devices */
+       ap->pflags |= ATA_PFLAG_UNLOADING;
+       ata_port_schedule_eh(ap);
+@@ -6247,9 +6243,11 @@ static void ata_port_detach(struct ata_p
+       /* wait till EH commits suicide */
+       ata_port_wait_eh(ap);
+-      /* it better be dead now */
++      /* It better be dead now and not have any remaining deferred qc. */
+       WARN_ON(!(ap->pflags & ATA_PFLAG_UNLOADED));
++      WARN_ON(ap->deferred_qc);
++      cancel_work_sync(&ap->deferred_qc_work);
+       cancel_delayed_work_sync(&ap->hotplug_task);
+       cancel_delayed_work_sync(&ap->scsi_rescan_task);
diff --git a/queue-6.19/ata-libata-eh-correctly-handle-deferred-qc-timeouts.patch b/queue-6.19/ata-libata-eh-correctly-handle-deferred-qc-timeouts.patch
new file mode 100644 (file)
index 0000000..cd89c82
--- /dev/null
@@ -0,0 +1,84 @@
+From eddb98ad9364b4e778768785d46cfab04ce52100 Mon Sep 17 00:00:00 2001
+From: Damien Le Moal <dlemoal@kernel.org>
+Date: Fri, 20 Feb 2026 13:43:00 +0900
+Subject: ata: libata-eh: correctly handle deferred qc timeouts
+
+From: Damien Le Moal <dlemoal@kernel.org>
+
+commit eddb98ad9364b4e778768785d46cfab04ce52100 upstream.
+
+A deferred qc may timeout while waiting for the device queue to drain
+to be submitted. In such case, since the qc is not active,
+ata_scsi_cmd_error_handler() ends up calling scsi_eh_finish_cmd(),
+which frees the qc. But as the port deferred_qc field still references
+this finished/freed qc, the deferred qc work may eventually attempt to
+call ata_qc_issue() against this invalid qc, leading to errors such as
+reported by UBSAN (syzbot run):
+
+UBSAN: shift-out-of-bounds in drivers/ata/libata-core.c:5166:24
+shift exponent 4210818301 is too large for 64-bit type 'long long unsigned int'
+...
+Call Trace:
+ <TASK>
+ __dump_stack lib/dump_stack.c:94 [inline]
+ dump_stack_lvl+0x100/0x190 lib/dump_stack.c:120
+ ubsan_epilogue+0xa/0x30 lib/ubsan.c:233
+ __ubsan_handle_shift_out_of_bounds+0x279/0x2a0 lib/ubsan.c:494
+ ata_qc_issue.cold+0x38/0x9f drivers/ata/libata-core.c:5166
+ ata_scsi_deferred_qc_work+0x154/0x1f0 drivers/ata/libata-scsi.c:1679
+ process_one_work+0x9d7/0x1920 kernel/workqueue.c:3275
+ process_scheduled_works kernel/workqueue.c:3358 [inline]
+ worker_thread+0x5da/0xe40 kernel/workqueue.c:3439
+ kthread+0x370/0x450 kernel/kthread.c:467
+ ret_from_fork+0x754/0xd80 arch/x86/kernel/process.c:158
+ ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
+ </TASK>
+
+Fix this by checking if the qc of a timed out SCSI command is a deferred
+one, and in such case, clear the port deferred_qc field and finish the
+SCSI command with DID_TIME_OUT.
+
+Reported-by: syzbot+1f77b8ca15336fff21ff@syzkaller.appspotmail.com
+Fixes: 0ea84089dbf6 ("ata: libata-scsi: avoid Non-NCQ command starvation")
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Reviewed-by: Hannes Reinecke <hare@suse.de>
+Reviewed-by: Igor Pylypiv <ipylypiv@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/ata/libata-eh.c |   22 +++++++++++++++++++---
+ 1 file changed, 19 insertions(+), 3 deletions(-)
+
+--- a/drivers/ata/libata-eh.c
++++ b/drivers/ata/libata-eh.c
+@@ -640,12 +640,28 @@ void ata_scsi_cmd_error_handler(struct S
+               set_host_byte(scmd, DID_OK);
+               ata_qc_for_each_raw(ap, qc, i) {
+-                      if (qc->flags & ATA_QCFLAG_ACTIVE &&
+-                          qc->scsicmd == scmd)
++                      if (qc->scsicmd != scmd)
++                              continue;
++                      if ((qc->flags & ATA_QCFLAG_ACTIVE) ||
++                          qc == ap->deferred_qc)
+                               break;
+               }
+-              if (i < ATA_MAX_QUEUE) {
++              if (qc == ap->deferred_qc) {
++                      /*
++                       * This is a deferred command that timed out while
++                       * waiting for the command queue to drain. Since the qc
++                       * is not active yet (deferred_qc is still set, so the
++                       * deferred qc work has not issued the command yet),
++                       * simply signal the timeout by finishing the SCSI
++                       * command and clear the deferred qc to prevent the
++                       * deferred qc work from issuing this qc.
++                       */
++                      WARN_ON_ONCE(qc->flags & ATA_QCFLAG_ACTIVE);
++                      ap->deferred_qc = NULL;
++                      set_host_byte(scmd, DID_TIME_OUT);
++                      scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
++              } else if (i < ATA_MAX_QUEUE) {
+                       /* the scmd has an associated qc */
+                       if (!(qc->flags & ATA_QCFLAG_EH)) {
+                               /* which hasn't failed yet, timeout */
index 51700f398b2607871c5723294dc6e140abc439ac..88614451b24c7c40820ed3c00d539cc33dfe74e1 100644 (file)
@@ -779,3 +779,5 @@ drm-exynos-vidi-fix-to-avoid-directly-dereferencing-user-pointer.patch
 drivers-hv-vmbus-use-kthread-for-vmbus-interrupts-on-preempt_rt.patch
 net-stmmac-dwmac-loongson-set-clk_csr_i-to-100-150mhz.patch
 revert-drm-amdgpu-don-t-attach-the-tlb-fence-for-si.patch
+ata-libata-eh-correctly-handle-deferred-qc-timeouts.patch
+ata-libata-core-fix-cancellation-of-a-port-deferred-qc-work.patch