summaryrefslogtreecommitdiff
path: root/block/blk-rq-qos.h
diff options
context:
space:
mode:
Diffstat (limited to 'block/blk-rq-qos.h')
-rw-r--r--block/blk-rq-qos.h13
1 files changed, 8 insertions, 5 deletions
diff --git a/block/blk-rq-qos.h b/block/blk-rq-qos.h
index 1fe22000a379..b538f2c0febc 100644
--- a/block/blk-rq-qos.h
+++ b/block/blk-rq-qos.h
@@ -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)