]> www.infradead.org Git - users/griffoul/linux.git/commitdiff
block: validate QoS before calling __rq_qos_done_bio()
authorNilay Shroff <nilay@linux.ibm.com>
Tue, 26 Aug 2025 16:30:32 +0000 (22:00 +0530)
committerJens Axboe <axboe@kernel.dk>
Tue, 26 Aug 2025 16:34:08 +0000 (10:34 -0600)
If a bio has BIO_QOS_xxx set, it doesn't guarantee that q->rq_qos is
also present at-least for stacked block devices. For instance, in case
of NVMe when multipath is enabled, the bottom device may have QoS
enabled but top device doesn't. So always validate QoS is enabled and
q->rq_qos is present before calling __rq_qos_done_bio().

Fixes: 370ac285f23a ("block: avoid cpu_hotplug_lock depedency on freeze_lock")
Reported-by: Venkat Rao Bagalkote <venkat88@linux.ibm.com>
Closes: https://lore.kernel.org/all/3a07b752-06a4-4eee-b302-f4669feb859d@linux.ibm.com/
Signed-off-by: Nilay Shroff <nilay@linux.ibm.com>
Link: https://lore.kernel.org/r/20250826163128.1952394-1-nilay@linux.ibm.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/blk-rq-qos.h

index 1fe22000a3790ea3bcee2171d46ea5e1160001cf..b538f2c0febc2bddf4092b722d18048b3b26ccf2 100644 (file)
@@ -149,12 +149,15 @@ static inline void rq_qos_done_bio(struct bio *bio)
        q = bdev_get_queue(bio->bi_bdev);
 
        /*
-        * If a bio has BIO_QOS_xxx set, it implicitly implies that
-        * q->rq_qos is present. So, we skip re-checking q->rq_qos
-        * here as an extra optimization and directly call
-        * __rq_qos_done_bio().
+        * A BIO may carry BIO_QOS_* flags even if the associated request_queue
+        * does not have rq_qos enabled. This can happen with stacked block
+        * devices — for example, NVMe multipath, where it's possible that the
+        * bottom device has QoS enabled but the top device does not. Therefore,
+        * always verify that q->rq_qos is present and QoS is enabled before
+        * calling __rq_qos_done_bio().
         */
-       __rq_qos_done_bio(q->rq_qos, bio);
+       if (test_bit(QUEUE_FLAG_QOS_ENABLED, &q->queue_flags) && q->rq_qos)
+               __rq_qos_done_bio(q->rq_qos, bio);
 }
 
 static inline void rq_qos_throttle(struct request_queue *q, struct bio *bio)