]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ata: sata_dwc_460ex: fix infinite loop in NCQ tag completion bit-scanning
authorRosen Penev <rosenp@gmail.com>
Sun, 12 Jul 2026 21:37:28 +0000 (14:37 -0700)
committerDamien Le Moal <dlemoal@kernel.org>
Mon, 13 Jul 2026 05:32:11 +0000 (14:32 +0900)
The hand-rolled bit-scanning loop in the NCQ completion path has an
infinite loop bug.  When tag_mask has only high bits set (e.g.
0x80000000), the inner while loop left-shifts tag_mask until it
overflows to 0.  At that point !(0 & 1) is always true and 0 <<= 1
stays 0, causing an infinite loop in hardirq context with a spinlock
held.

Replace the open-coded bit-scanning with __ffs() which correctly
finds the least significant set bit and is bounded by the width of
the argument.

Fixes: 62936009f35a ("[libata] Add 460EX on-chip SATA driver, sata_dwc_460ex")
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
drivers/ata/sata_dwc_460ex.c

index bc543a40896316974518238ca20ff6598b076f6b..8e3fc713891afc927fb08e12128c29da35e8ce89 100644 (file)
@@ -607,14 +607,9 @@ DRVSTILLBUSY:
        status = ap->ops->sff_check_status(ap);
        dev_dbg(ap->dev, "%s ATA status register=0x%x\n", __func__, status);
 
-       tag = 0;
        while (tag_mask) {
-               while (!(tag_mask & 0x00000001)) {
-                       tag++;
-                       tag_mask <<= 1;
-               }
-
-               tag_mask &= (~0x00000001);
+               tag = __ffs(tag_mask);
+               tag_mask &= ~(1U << tag);
                qc = ata_qc_from_tag(ap, tag);
                if (unlikely(!qc)) {
                        dev_err(ap->dev, "failed to get qc");