]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - block/blk-core.c
drm/shmem-helper: Remove errant put in error path
[mirror_ubuntu-jammy-kernel.git] / block / blk-core.c
index 5454db2fa263b0d87bce30058bf7052d37f2962d..13e1fca1e923f358aa1cb75d9604c3974c057602 100644 (file)
@@ -337,24 +337,19 @@ void blk_put_queue(struct request_queue *q)
 }
 EXPORT_SYMBOL(blk_put_queue);
 
-void blk_set_queue_dying(struct request_queue *q)
+void blk_queue_start_drain(struct request_queue *q)
 {
-       blk_queue_flag_set(QUEUE_FLAG_DYING, q);
-
        /*
         * When queue DYING flag is set, we need to block new req
         * entering queue, so we call blk_freeze_queue_start() to
         * prevent I/O from crossing blk_queue_enter().
         */
        blk_freeze_queue_start(q);
-
        if (queue_is_mq(q))
                blk_mq_wake_waiters(q);
-
        /* Make blk_queue_enter() reexamine the DYING flag. */
        wake_up_all(&q->mq_freeze_wq);
 }
-EXPORT_SYMBOL_GPL(blk_set_queue_dying);
 
 /**
  * blk_cleanup_queue - shutdown a request queue
@@ -373,7 +368,8 @@ void blk_cleanup_queue(struct request_queue *q)
        WARN_ON_ONCE(blk_queue_registered(q));
 
        /* mark @q DYING, no new request or merges will be allowed afterwards */
-       blk_set_queue_dying(q);
+       blk_queue_flag_set(QUEUE_FLAG_DYING, q);
+       blk_queue_start_drain(q);
 
        blk_queue_flag_set(QUEUE_FLAG_NOMERGES, q);
        blk_queue_flag_set(QUEUE_FLAG_NOXMERGES, q);
@@ -385,16 +381,16 @@ void blk_cleanup_queue(struct request_queue *q)
         */
        blk_freeze_queue(q);
 
+       /* cleanup rq qos structures for queue without disk */
        rq_qos_exit(q);
 
        blk_queue_flag_set(QUEUE_FLAG_DEAD, q);
 
-       /* for synchronous bio-based driver finish in-flight integrity i/o */
-       blk_flush_integrity();
-
        blk_sync_queue(q);
-       if (queue_is_mq(q))
+       if (queue_is_mq(q)) {
+               blk_mq_cancel_work_sync(q);
                blk_mq_exit_queue(q);
+       }
 
        /*
         * In theory, request pool of sched_tags belongs to request queue.
@@ -416,6 +412,30 @@ void blk_cleanup_queue(struct request_queue *q)
 }
 EXPORT_SYMBOL(blk_cleanup_queue);
 
+static bool blk_try_enter_queue(struct request_queue *q, bool pm)
+{
+       rcu_read_lock();
+       if (!percpu_ref_tryget_live(&q->q_usage_counter))
+               goto fail;
+
+       /*
+        * The code that increments the pm_only counter must ensure that the
+        * counter is globally visible before the queue is unfrozen.
+        */
+       if (blk_queue_pm_only(q) &&
+           (!pm || queue_rpm_status(q) == RPM_SUSPENDED))
+               goto fail_put;
+
+       rcu_read_unlock();
+       return true;
+
+fail_put:
+       percpu_ref_put(&q->q_usage_counter);
+fail:
+       rcu_read_unlock();
+       return false;
+}
+
 /**
  * blk_queue_enter() - try to increase q->q_usage_counter
  * @q: request queue pointer
@@ -425,40 +445,18 @@ int blk_queue_enter(struct request_queue *q, blk_mq_req_flags_t flags)
 {
        const bool pm = flags & BLK_MQ_REQ_PM;
 
-       while (true) {
-               bool success = false;
-
-               rcu_read_lock();
-               if (percpu_ref_tryget_live(&q->q_usage_counter)) {
-                       /*
-                        * The code that increments the pm_only counter is
-                        * responsible for ensuring that that counter is
-                        * globally visible before the queue is unfrozen.
-                        */
-                       if ((pm && queue_rpm_status(q) != RPM_SUSPENDED) ||
-                           !blk_queue_pm_only(q)) {
-                               success = true;
-                       } else {
-                               percpu_ref_put(&q->q_usage_counter);
-                       }
-               }
-               rcu_read_unlock();
-
-               if (success)
-                       return 0;
-
+       while (!blk_try_enter_queue(q, pm)) {
                if (flags & BLK_MQ_REQ_NOWAIT)
-                       return -EBUSY;
+                       return -EAGAIN;
 
                /*
-                * read pair of barrier in blk_freeze_queue_start(),
-                * we need to order reading __PERCPU_REF_DEAD flag of
-                * .q_usage_counter and reading .mq_freeze_depth or
-                * queue dying flag, otherwise the following wait may
-                * never return if the two reads are reordered.
+                * read pair of barrier in blk_freeze_queue_start(), we need to
+                * order reading __PERCPU_REF_DEAD flag of .q_usage_counter and
+                * reading .mq_freeze_depth or queue dying flag, otherwise the
+                * following wait may never return if the two reads are
+                * reordered.
                 */
                smp_rmb();
-
                wait_event(q->mq_freeze_wq,
                           (!q->mq_freeze_depth &&
                            blk_pm_resume_queue(pm, q)) ||
@@ -466,23 +464,43 @@ int blk_queue_enter(struct request_queue *q, blk_mq_req_flags_t flags)
                if (blk_queue_dying(q))
                        return -ENODEV;
        }
+
+       return 0;
 }
 
 static inline int bio_queue_enter(struct bio *bio)
 {
-       struct request_queue *q = bio->bi_bdev->bd_disk->queue;
-       bool nowait = bio->bi_opf & REQ_NOWAIT;
-       int ret;
+       struct gendisk *disk = bio->bi_bdev->bd_disk;
+       struct request_queue *q = disk->queue;
 
-       ret = blk_queue_enter(q, nowait ? BLK_MQ_REQ_NOWAIT : 0);
-       if (unlikely(ret)) {
-               if (nowait && !blk_queue_dying(q))
+       while (!blk_try_enter_queue(q, false)) {
+               if (bio->bi_opf & REQ_NOWAIT) {
+                       if (test_bit(GD_DEAD, &disk->state))
+                               goto dead;
                        bio_wouldblock_error(bio);
-               else
-                       bio_io_error(bio);
+                       return -EAGAIN;
+               }
+
+               /*
+                * read pair of barrier in blk_freeze_queue_start(), we need to
+                * order reading __PERCPU_REF_DEAD flag of .q_usage_counter and
+                * reading .mq_freeze_depth or queue dying flag, otherwise the
+                * following wait may never return if the two reads are
+                * reordered.
+                */
+               smp_rmb();
+               wait_event(q->mq_freeze_wq,
+                          (!q->mq_freeze_depth &&
+                           blk_pm_resume_queue(false, q)) ||
+                          test_bit(GD_DEAD, &disk->state));
+               if (test_bit(GD_DEAD, &disk->state))
+                       goto dead;
        }
 
-       return ret;
+       return 0;
+dead:
+       bio_io_error(bio);
+       return -ENODEV;
 }
 
 void blk_queue_exit(struct request_queue *q)
@@ -869,10 +887,8 @@ static noinline_for_stack bool submit_bio_checks(struct bio *bio)
        if (unlikely(!current->io_context))
                create_task_io_context(current, GFP_ATOMIC, q->node);
 
-       if (blk_throtl_bio(bio)) {
-               blkcg_bio_issue_init(bio);
+       if (blk_throtl_bio(bio))
                return false;
-       }
 
        blk_cgroup_bio_start(bio);
        blkcg_bio_issue_init(bio);
@@ -899,11 +915,18 @@ static blk_qc_t __submit_bio(struct bio *bio)
        struct gendisk *disk = bio->bi_bdev->bd_disk;
        blk_qc_t ret = BLK_QC_T_NONE;
 
-       if (blk_crypto_bio_prep(&bio)) {
-               if (!disk->fops->submit_bio)
-                       return blk_mq_submit_bio(bio);
+       if (unlikely(bio_queue_enter(bio) != 0))
+               return BLK_QC_T_NONE;
+
+       if (!submit_bio_checks(bio) || !blk_crypto_bio_prep(&bio))
+               goto queue_exit;
+       if (disk->fops->submit_bio) {
                ret = disk->fops->submit_bio(bio);
+               goto queue_exit;
        }
+       return blk_mq_submit_bio(bio);
+
+queue_exit:
        blk_queue_exit(disk->queue);
        return ret;
 }
@@ -941,9 +964,6 @@ static blk_qc_t __submit_bio_noacct(struct bio *bio)
                struct request_queue *q = bio->bi_bdev->bd_disk->queue;
                struct bio_list lower, same;
 
-               if (unlikely(bio_queue_enter(bio) != 0))
-                       continue;
-
                /*
                 * Create a fresh bio_list for all subordinate requests.
                 */
@@ -979,23 +999,12 @@ static blk_qc_t __submit_bio_noacct(struct bio *bio)
 static blk_qc_t __submit_bio_noacct_mq(struct bio *bio)
 {
        struct bio_list bio_list[2] = { };
-       blk_qc_t ret = BLK_QC_T_NONE;
+       blk_qc_t ret;
 
        current->bio_list = bio_list;
 
        do {
-               struct gendisk *disk = bio->bi_bdev->bd_disk;
-
-               if (unlikely(bio_queue_enter(bio) != 0))
-                       continue;
-
-               if (!blk_crypto_bio_prep(&bio)) {
-                       blk_queue_exit(disk->queue);
-                       ret = BLK_QC_T_NONE;
-                       continue;
-               }
-
-               ret = blk_mq_submit_bio(bio);
+               ret = __submit_bio(bio);
        } while ((bio = bio_list_pop(&bio_list[0])));
 
        current->bio_list = NULL;
@@ -1013,9 +1022,6 @@ static blk_qc_t __submit_bio_noacct_mq(struct bio *bio)
  */
 blk_qc_t submit_bio_noacct(struct bio *bio)
 {
-       if (!submit_bio_checks(bio))
-               return BLK_QC_T_NONE;
-
        /*
         * We only want one ->submit_bio to be active at a time, else stack
         * usage with stacked devices could be a problem.  Use current->bio_list
@@ -1285,20 +1291,32 @@ void blk_account_io_start(struct request *rq)
 }
 
 static unsigned long __part_start_io_acct(struct block_device *part,
-                                         unsigned int sectors, unsigned int op)
+                                         unsigned int sectors, unsigned int op,
+                                         unsigned long start_time)
 {
        const int sgrp = op_stat_group(op);
-       unsigned long now = READ_ONCE(jiffies);
 
        part_stat_lock();
-       update_io_ticks(part, now, false);
+       update_io_ticks(part, start_time, false);
        part_stat_inc(part, ios[sgrp]);
        part_stat_add(part, sectors[sgrp], sectors);
        part_stat_local_inc(part, in_flight[op_is_write(op)]);
        part_stat_unlock();
 
-       return now;
+       return start_time;
+}
+
+/**
+ * bio_start_io_acct_time - start I/O accounting for bio based drivers
+ * @bio:       bio to start account for
+ * @start_time:        start time that should be passed back to bio_end_io_acct().
+ */
+void bio_start_io_acct_time(struct bio *bio, unsigned long start_time)
+{
+       __part_start_io_acct(bio->bi_bdev, bio_sectors(bio),
+                            bio_op(bio), start_time);
 }
+EXPORT_SYMBOL_GPL(bio_start_io_acct_time);
 
 /**
  * bio_start_io_acct - start I/O accounting for bio based drivers
@@ -1308,14 +1326,15 @@ static unsigned long __part_start_io_acct(struct block_device *part,
  */
 unsigned long bio_start_io_acct(struct bio *bio)
 {
-       return __part_start_io_acct(bio->bi_bdev, bio_sectors(bio), bio_op(bio));
+       return __part_start_io_acct(bio->bi_bdev, bio_sectors(bio),
+                                   bio_op(bio), jiffies);
 }
 EXPORT_SYMBOL_GPL(bio_start_io_acct);
 
 unsigned long disk_start_io_acct(struct gendisk *disk, unsigned int sectors,
                                 unsigned int op)
 {
-       return __part_start_io_acct(disk->part0, sectors, op);
+       return __part_start_io_acct(disk->part0, sectors, op, jiffies);
 }
 EXPORT_SYMBOL(disk_start_io_acct);