]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - block/blk-flush.c
Merge tag 'tomoyo-pr-20210215' of git://git.osdn.net/gitroot/tomoyo/tomoyo-test1
[mirror_ubuntu-jammy-kernel.git] / block / blk-flush.c
index e32958f0b687506c3815c1105ffa3acf62b7df6b..7942ca6ed3211c684437c6875e678841888b583b 100644 (file)
@@ -69,7 +69,6 @@
 #include <linux/blkdev.h>
 #include <linux/gfp.h>
 #include <linux/blk-mq.h>
-#include <linux/lockdep.h>
 
 #include "blk.h"
 #include "blk-mq.h"
@@ -139,7 +138,7 @@ static void blk_flush_queue_rq(struct request *rq, bool add_front)
 
 static void blk_account_io_flush(struct request *rq)
 {
-       struct hd_struct *part = &rq->rq_disk->part0;
+       struct block_device *part = rq->rq_disk->part0;
 
        part_stat_lock();
        part_stat_inc(part, ios[STAT_FLUSH]);
@@ -225,13 +224,18 @@ static void flush_end_io(struct request *flush_rq, blk_status_t error)
        /* release the tag's ownership to the req cloned from */
        spin_lock_irqsave(&fq->mq_flush_lock, flags);
 
-       WRITE_ONCE(flush_rq->state, MQ_RQ_IDLE);
        if (!refcount_dec_and_test(&flush_rq->ref)) {
                fq->rq_status = error;
                spin_unlock_irqrestore(&fq->mq_flush_lock, flags);
                return;
        }
 
+       /*
+        * Flush request has to be marked as IDLE when it is really ended
+        * because its .end_io() is called from timeout code path too for
+        * avoiding use-after-free.
+        */
+       WRITE_ONCE(flush_rq->state, MQ_RQ_IDLE);
        if (fq->rq_status != BLK_STS_OK)
                error = fq->rq_status;
 
@@ -428,23 +432,18 @@ void blk_insert_flush(struct request *rq)
 /**
  * blkdev_issue_flush - queue a flush
  * @bdev:      blockdev to issue flush for
- * @gfp_mask:  memory allocation flags (for bio_alloc)
  *
  * Description:
  *    Issue a flush for the block device in question.
  */
-int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask)
+int blkdev_issue_flush(struct block_device *bdev)
 {
-       struct bio *bio;
-       int ret = 0;
+       struct bio bio;
 
-       bio = bio_alloc(gfp_mask, 0);
-       bio_set_dev(bio, bdev);
-       bio->bi_opf = REQ_OP_WRITE | REQ_PREFLUSH;
-
-       ret = submit_bio_wait(bio);
-       bio_put(bio);
-       return ret;
+       bio_init(&bio, NULL, 0);
+       bio_set_dev(&bio, bdev);
+       bio.bi_opf = REQ_OP_WRITE | REQ_PREFLUSH;
+       return submit_bio_wait(&bio);
 }
 EXPORT_SYMBOL(blkdev_issue_flush);
 
@@ -469,9 +468,6 @@ struct blk_flush_queue *blk_alloc_flush_queue(int node, int cmd_size,
        INIT_LIST_HEAD(&fq->flush_queue[1]);
        INIT_LIST_HEAD(&fq->flush_data_in_flight);
 
-       lockdep_register_key(&fq->key);
-       lockdep_set_class(&fq->mq_flush_lock, &fq->key);
-
        return fq;
 
  fail_rq:
@@ -486,7 +482,31 @@ void blk_free_flush_queue(struct blk_flush_queue *fq)
        if (!fq)
                return;
 
-       lockdep_unregister_key(&fq->key);
        kfree(fq->flush_rq);
        kfree(fq);
 }
+
+/*
+ * Allow driver to set its own lock class to fq->mq_flush_lock for
+ * avoiding lockdep complaint.
+ *
+ * flush_end_io() may be called recursively from some driver, such as
+ * nvme-loop, so lockdep may complain 'possible recursive locking' because
+ * all 'struct blk_flush_queue' instance share same mq_flush_lock lock class
+ * key. We need to assign different lock class for these driver's
+ * fq->mq_flush_lock for avoiding the lockdep warning.
+ *
+ * Use dynamically allocated lock class key for each 'blk_flush_queue'
+ * instance is over-kill, and more worse it introduces horrible boot delay
+ * issue because synchronize_rcu() is implied in lockdep_unregister_key which
+ * is called for each hctx release. SCSI probing may synchronously create and
+ * destroy lots of MQ request_queues for non-existent devices, and some robot
+ * test kernel always enable lockdep option. It is observed that more than half
+ * an hour is taken during SCSI MQ probe with per-fq lock class.
+ */
+void blk_mq_hctx_set_fq_lock_class(struct blk_mq_hw_ctx *hctx,
+               struct lock_class_key *key)
+{
+       lockdep_set_class(&hctx->fq->mq_flush_lock, key);
+}
+EXPORT_SYMBOL_GPL(blk_mq_hctx_set_fq_lock_class);