LCOV - code coverage report
Current view: top level - block - blk-mq-sched.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 121 248 48.8 %
Date: 2022-03-28 15:32:58 Functions: 12 17 70.6 %
Branches: 71 188 37.8 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * blk-mq scheduling framework
       4                 :            :  *
       5                 :            :  * Copyright (C) 2016 Jens Axboe
       6                 :            :  */
       7                 :            : #include <linux/kernel.h>
       8                 :            : #include <linux/module.h>
       9                 :            : #include <linux/blk-mq.h>
      10                 :            : 
      11                 :            : #include <trace/events/block.h>
      12                 :            : 
      13                 :            : #include "blk.h"
      14                 :            : #include "blk-mq.h"
      15                 :            : #include "blk-mq-debugfs.h"
      16                 :            : #include "blk-mq-sched.h"
      17                 :            : #include "blk-mq-tag.h"
      18                 :            : #include "blk-wbt.h"
      19                 :            : 
      20                 :          0 : void blk_mq_sched_free_hctx_data(struct request_queue *q,
      21                 :            :                                  void (*exit)(struct blk_mq_hw_ctx *))
      22                 :            : {
      23                 :          0 :         struct blk_mq_hw_ctx *hctx;
      24                 :          0 :         int i;
      25                 :            : 
      26         [ #  # ]:          0 :         queue_for_each_hw_ctx(q, hctx, i) {
      27   [ #  #  #  # ]:          0 :                 if (exit && hctx->sched_data)
      28                 :          0 :                         exit(hctx);
      29                 :          0 :                 kfree(hctx->sched_data);
      30                 :          0 :                 hctx->sched_data = NULL;
      31                 :            :         }
      32                 :          0 : }
      33                 :            : EXPORT_SYMBOL_GPL(blk_mq_sched_free_hctx_data);
      34                 :            : 
      35                 :          0 : void blk_mq_sched_assign_ioc(struct request *rq)
      36                 :            : {
      37                 :          0 :         struct request_queue *q = rq->q;
      38                 :          0 :         struct io_context *ioc;
      39                 :          0 :         struct io_cq *icq;
      40                 :            : 
      41                 :            :         /*
      42                 :            :          * May not have an IO context if it's a passthrough request
      43                 :            :          */
      44         [ #  # ]:          0 :         ioc = current->io_context;
      45         [ #  # ]:          0 :         if (!ioc)
      46                 :            :                 return;
      47                 :            : 
      48                 :          0 :         spin_lock_irq(&q->queue_lock);
      49                 :          0 :         icq = ioc_lookup_icq(ioc, q);
      50                 :          0 :         spin_unlock_irq(&q->queue_lock);
      51                 :            : 
      52         [ #  # ]:          0 :         if (!icq) {
      53                 :          0 :                 icq = ioc_create_icq(ioc, q, GFP_ATOMIC);
      54         [ #  # ]:          0 :                 if (!icq)
      55                 :            :                         return;
      56                 :            :         }
      57                 :          0 :         get_io_context(icq->ioc);
      58                 :          0 :         rq->elv.icq = icq;
      59                 :            : }
      60                 :            : 
      61                 :            : /*
      62                 :            :  * Mark a hardware queue as needing a restart. For shared queues, maintain
      63                 :            :  * a count of how many hardware queues are marked for restart.
      64                 :            :  */
      65                 :       5822 : void blk_mq_sched_mark_restart_hctx(struct blk_mq_hw_ctx *hctx)
      66                 :            : {
      67         [ +  + ]:       5822 :         if (test_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state))
      68                 :            :                 return;
      69                 :            : 
      70                 :       4919 :         set_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state);
      71                 :            : }
      72                 :            : EXPORT_SYMBOL_GPL(blk_mq_sched_mark_restart_hctx);
      73                 :            : 
      74                 :      32178 : void blk_mq_sched_restart(struct blk_mq_hw_ctx *hctx)
      75                 :            : {
      76         [ +  + ]:      32178 :         if (!test_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state))
      77                 :            :                 return;
      78                 :       4919 :         clear_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state);
      79                 :            : 
      80                 :       4919 :         blk_mq_run_hw_queue(hctx, true);
      81                 :            : }
      82                 :            : 
      83                 :            : /*
      84                 :            :  * Only SCSI implements .get_budget and .put_budget, and SCSI restarts
      85                 :            :  * its queue by itself in its completion handler, so we don't need to
      86                 :            :  * restart queue if .get_budget() returns BLK_STS_NO_RESOURCE.
      87                 :            :  */
      88                 :      33270 : static void blk_mq_do_dispatch_sched(struct blk_mq_hw_ctx *hctx)
      89                 :            : {
      90                 :      33270 :         struct request_queue *q = hctx->queue;
      91                 :      33270 :         struct elevator_queue *e = q->elevator;
      92                 :      33270 :         LIST_HEAD(rq_list);
      93                 :            : 
      94                 :      60193 :         do {
      95                 :      60193 :                 struct request *rq;
      96                 :            : 
      97   [ +  -  +  + ]:      60193 :                 if (e->type->ops.has_work && !e->type->ops.has_work(hctx))
      98                 :            :                         break;
      99                 :            : 
     100   [ +  -  +  + ]:      59372 :                 if (!blk_mq_get_dispatch_budget(hctx))
     101                 :            :                         break;
     102                 :            : 
     103                 :      27548 :                 rq = e->type->ops.dispatch_request(hctx);
     104         [ -  + ]:      27548 :                 if (!rq) {
     105         [ #  # ]:          0 :                         blk_mq_put_dispatch_budget(hctx);
     106                 :            :                         break;
     107                 :            :                 }
     108                 :            : 
     109                 :            :                 /*
     110                 :            :                  * Now this rq owns the budget which has to be released
     111                 :            :                  * if this rq won't be queued to driver via .queue_rq()
     112                 :            :                  * in blk_mq_dispatch_rq_list().
     113                 :            :                  */
     114                 :      27548 :                 list_add(&rq->queuelist, &rq_list);
     115         [ +  + ]:      27548 :         } while (blk_mq_dispatch_rq_list(q, &rq_list, true));
     116                 :      33270 : }
     117                 :            : 
     118                 :          0 : static struct blk_mq_ctx *blk_mq_next_ctx(struct blk_mq_hw_ctx *hctx,
     119                 :            :                                           struct blk_mq_ctx *ctx)
     120                 :            : {
     121                 :          0 :         unsigned short idx = ctx->index_hw[hctx->type];
     122                 :            : 
     123                 :          0 :         if (++idx == hctx->nr_ctx)
     124                 :          0 :                 idx = 0;
     125                 :            : 
     126                 :          0 :         return hctx->ctxs[idx];
     127                 :            : }
     128                 :            : 
     129                 :            : /*
     130                 :            :  * Only SCSI implements .get_budget and .put_budget, and SCSI restarts
     131                 :            :  * its queue by itself in its completion handler, so we don't need to
     132                 :            :  * restart queue if .get_budget() returns BLK_STS_NO_RESOURCE.
     133                 :            :  */
     134                 :       1400 : static void blk_mq_do_dispatch_ctx(struct blk_mq_hw_ctx *hctx)
     135                 :            : {
     136                 :       1400 :         struct request_queue *q = hctx->queue;
     137                 :       1400 :         LIST_HEAD(rq_list);
     138                 :       1400 :         struct blk_mq_ctx *ctx = READ_ONCE(hctx->dispatch_from);
     139                 :            : 
     140                 :       1400 :         do {
     141                 :       1400 :                 struct request *rq;
     142                 :            : 
     143         [ -  + ]:       1400 :                 if (!sbitmap_any_bit_set(&hctx->ctx_map))
     144                 :            :                         break;
     145                 :            : 
     146   [ #  #  #  # ]:          0 :                 if (!blk_mq_get_dispatch_budget(hctx))
     147                 :            :                         break;
     148                 :            : 
     149                 :          0 :                 rq = blk_mq_dequeue_from_ctx(hctx, ctx);
     150         [ #  # ]:          0 :                 if (!rq) {
     151         [ #  # ]:          0 :                         blk_mq_put_dispatch_budget(hctx);
     152                 :            :                         break;
     153                 :            :                 }
     154                 :            : 
     155                 :            :                 /*
     156                 :            :                  * Now this rq owns the budget which has to be released
     157                 :            :                  * if this rq won't be queued to driver via .queue_rq()
     158                 :            :                  * in blk_mq_dispatch_rq_list().
     159                 :            :                  */
     160         [ #  # ]:          0 :                 list_add(&rq->queuelist, &rq_list);
     161                 :            : 
     162                 :            :                 /* round robin for fair dispatch */
     163         [ #  # ]:          0 :                 ctx = blk_mq_next_ctx(hctx, rq->mq_ctx);
     164                 :            : 
     165         [ #  # ]:          0 :         } while (blk_mq_dispatch_rq_list(q, &rq_list, true));
     166                 :            : 
     167                 :       1400 :         WRITE_ONCE(hctx->dispatch_from, ctx);
     168                 :       1400 : }
     169                 :            : 
     170                 :      35340 : void blk_mq_sched_dispatch_requests(struct blk_mq_hw_ctx *hctx)
     171                 :            : {
     172                 :      35340 :         struct request_queue *q = hctx->queue;
     173                 :      35340 :         struct elevator_queue *e = q->elevator;
     174   [ +  +  -  + ]:      35340 :         const bool has_sched_dispatch = e && e->type->ops.dispatch_request;
     175                 :      35340 :         LIST_HEAD(rq_list);
     176                 :            : 
     177                 :            :         /* RCU or SRCU read lock is needed before checking quiesced flag */
     178   [ +  -  -  + ]:      35340 :         if (unlikely(blk_mq_hctx_stopped(hctx) || blk_queue_quiesced(q)))
     179                 :          0 :                 return;
     180                 :            : 
     181                 :      35340 :         hctx->run++;
     182                 :            : 
     183                 :            :         /*
     184                 :            :          * If we have previous entries on our dispatch list, grab them first for
     185                 :            :          * more fair dispatch.
     186                 :            :          */
     187         [ +  + ]:      35340 :         if (!list_empty_careful(&hctx->dispatch)) {
     188                 :       5790 :                 spin_lock(&hctx->lock);
     189         [ +  - ]:       5790 :                 if (!list_empty(&hctx->dispatch))
     190         [ +  - ]:       5790 :                         list_splice_init(&hctx->dispatch, &rq_list);
     191                 :       5790 :                 spin_unlock(&hctx->lock);
     192                 :            :         }
     193                 :            : 
     194                 :            :         /*
     195                 :            :          * Only ask the scheduler for requests, if we didn't have residual
     196                 :            :          * requests from the dispatch list. This is to avoid the case where
     197                 :            :          * we only ever dispatch a fraction of the requests available because
     198                 :            :          * of low device queue depth. Once we pull requests out of the IO
     199                 :            :          * scheduler, we can no longer merge or sort them. So it's best to
     200                 :            :          * leave them there for as long as we can. Mark the hw queue as
     201                 :            :          * needing a restart in that case.
     202                 :            :          *
     203                 :            :          * We want to dispatch from the scheduler if there was nothing
     204                 :            :          * on the dispatch list or we were able to dispatch from the
     205                 :            :          * dispatch list.
     206                 :            :          */
     207         [ +  + ]:      35340 :         if (!list_empty(&rq_list)) {
     208                 :       5790 :                 blk_mq_sched_mark_restart_hctx(hctx);
     209         [ +  + ]:       5790 :                 if (blk_mq_dispatch_rq_list(q, &rq_list, false)) {
     210         [ +  + ]:       5120 :                         if (has_sched_dispatch)
     211                 :       3720 :                                 blk_mq_do_dispatch_sched(hctx);
     212                 :            :                         else
     213                 :       1400 :                                 blk_mq_do_dispatch_ctx(hctx);
     214                 :            :                 }
     215         [ +  - ]:      29550 :         } else if (has_sched_dispatch) {
     216                 :      29550 :                 blk_mq_do_dispatch_sched(hctx);
     217         [ #  # ]:          0 :         } else if (hctx->dispatch_busy) {
     218                 :            :                 /* dequeue request one by one from sw queue if queue is busy */
     219                 :          0 :                 blk_mq_do_dispatch_ctx(hctx);
     220                 :            :         } else {
     221                 :          0 :                 blk_mq_flush_busy_ctxs(hctx, &rq_list);
     222                 :          0 :                 blk_mq_dispatch_rq_list(q, &rq_list, false);
     223                 :            :         }
     224                 :            : }
     225                 :            : 
     226                 :      27894 : bool blk_mq_sched_try_merge(struct request_queue *q, struct bio *bio,
     227                 :            :                 unsigned int nr_segs, struct request **merged_request)
     228                 :            : {
     229                 :      27894 :         struct request *rq;
     230                 :            : 
     231   [ +  -  -  + ]:      27894 :         switch (elv_merge(q, &rq, bio)) {
     232                 :         10 :         case ELEVATOR_BACK_MERGE:
     233   [ +  -  -  - ]:         10 :                 if (!blk_mq_sched_allow_merge(q, rq, bio))
     234                 :            :                         return false;
     235         [ +  - ]:         10 :                 if (!bio_attempt_back_merge(rq, bio, nr_segs))
     236                 :            :                         return false;
     237                 :         10 :                 *merged_request = attempt_back_merge(q, rq);
     238         [ +  - ]:         10 :                 if (!*merged_request)
     239                 :         10 :                         elv_merged_request(q, rq, ELEVATOR_BACK_MERGE);
     240                 :            :                 return true;
     241                 :          0 :         case ELEVATOR_FRONT_MERGE:
     242   [ #  #  #  # ]:          0 :                 if (!blk_mq_sched_allow_merge(q, rq, bio))
     243                 :            :                         return false;
     244         [ #  # ]:          0 :                 if (!bio_attempt_front_merge(rq, bio, nr_segs))
     245                 :            :                         return false;
     246                 :          0 :                 *merged_request = attempt_front_merge(q, rq);
     247         [ #  # ]:          0 :                 if (!*merged_request)
     248                 :          0 :                         elv_merged_request(q, rq, ELEVATOR_FRONT_MERGE);
     249                 :            :                 return true;
     250                 :          0 :         case ELEVATOR_DISCARD_MERGE:
     251                 :          0 :                 return bio_attempt_discard_merge(q, rq, bio);
     252                 :            :         default:
     253                 :            :                 return false;
     254                 :            :         }
     255                 :            : }
     256                 :            : EXPORT_SYMBOL_GPL(blk_mq_sched_try_merge);
     257                 :            : 
     258                 :            : /*
     259                 :            :  * Iterate list of requests and see if we can merge this bio with any
     260                 :            :  * of them.
     261                 :            :  */
     262                 :          0 : bool blk_mq_bio_list_merge(struct request_queue *q, struct list_head *list,
     263                 :            :                            struct bio *bio, unsigned int nr_segs)
     264                 :            : {
     265                 :          0 :         struct request *rq;
     266                 :          0 :         int checked = 8;
     267                 :            : 
     268         [ #  # ]:          0 :         list_for_each_entry_reverse(rq, list, queuelist) {
     269                 :          0 :                 bool merged = false;
     270                 :            : 
     271         [ #  # ]:          0 :                 if (!checked--)
     272                 :            :                         break;
     273                 :            : 
     274         [ #  # ]:          0 :                 if (!blk_rq_merge_ok(rq, bio))
     275                 :          0 :                         continue;
     276                 :            : 
     277   [ #  #  #  # ]:          0 :                 switch (blk_try_merge(rq, bio)) {
     278                 :            :                 case ELEVATOR_BACK_MERGE:
     279   [ #  #  #  # ]:          0 :                         if (blk_mq_sched_allow_merge(q, rq, bio))
     280                 :          0 :                                 merged = bio_attempt_back_merge(rq, bio,
     281                 :            :                                                 nr_segs);
     282                 :            :                         break;
     283                 :            :                 case ELEVATOR_FRONT_MERGE:
     284   [ #  #  #  # ]:          0 :                         if (blk_mq_sched_allow_merge(q, rq, bio))
     285                 :          0 :                                 merged = bio_attempt_front_merge(rq, bio,
     286                 :            :                                                 nr_segs);
     287                 :            :                         break;
     288                 :          0 :                 case ELEVATOR_DISCARD_MERGE:
     289                 :          0 :                         merged = bio_attempt_discard_merge(q, rq, bio);
     290                 :          0 :                         break;
     291                 :          0 :                 default:
     292                 :          0 :                         continue;
     293                 :            :                 }
     294                 :            : 
     295                 :            :                 return merged;
     296                 :            :         }
     297                 :            : 
     298                 :            :         return false;
     299                 :            : }
     300                 :            : EXPORT_SYMBOL_GPL(blk_mq_bio_list_merge);
     301                 :            : 
     302                 :            : /*
     303                 :            :  * Reverse check our software queue for entries that we could potentially
     304                 :            :  * merge with. Currently includes a hand-wavy stop count of 8, to not spend
     305                 :            :  * too much time checking for merges.
     306                 :            :  */
     307                 :          0 : static bool blk_mq_attempt_merge(struct request_queue *q,
     308                 :            :                                  struct blk_mq_hw_ctx *hctx,
     309                 :            :                                  struct blk_mq_ctx *ctx, struct bio *bio,
     310                 :            :                                  unsigned int nr_segs)
     311                 :            : {
     312                 :          0 :         enum hctx_type type = hctx->type;
     313                 :            : 
     314                 :          0 :         lockdep_assert_held(&ctx->lock);
     315                 :            : 
     316         [ #  # ]:          0 :         if (blk_mq_bio_list_merge(q, &ctx->rq_lists[type], bio, nr_segs)) {
     317                 :          0 :                 ctx->rq_merged++;
     318                 :          0 :                 return true;
     319                 :            :         }
     320                 :            : 
     321                 :            :         return false;
     322                 :            : }
     323                 :            : 
     324                 :      27894 : bool __blk_mq_sched_bio_merge(struct request_queue *q, struct bio *bio,
     325                 :            :                 unsigned int nr_segs)
     326                 :            : {
     327                 :      27894 :         struct elevator_queue *e = q->elevator;
     328                 :      27894 :         struct blk_mq_ctx *ctx = blk_mq_get_ctx(q);
     329         [ +  - ]:      27894 :         struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(q, bio->bi_opf, ctx);
     330                 :      27894 :         bool ret = false;
     331                 :      27894 :         enum hctx_type type;
     332                 :            : 
     333   [ +  -  +  - ]:      27894 :         if (e && e->type->ops.bio_merge)
     334                 :      27894 :                 return e->type->ops.bio_merge(hctx, bio, nr_segs);
     335                 :            : 
     336                 :          0 :         type = hctx->type;
     337         [ #  # ]:          0 :         if ((hctx->flags & BLK_MQ_F_SHOULD_MERGE) &&
     338         [ #  # ]:          0 :                         !list_empty_careful(&ctx->rq_lists[type])) {
     339                 :            :                 /* default per sw-queue merge */
     340                 :          0 :                 spin_lock(&ctx->lock);
     341                 :          0 :                 ret = blk_mq_attempt_merge(q, hctx, ctx, bio, nr_segs);
     342                 :          0 :                 spin_unlock(&ctx->lock);
     343                 :            :         }
     344                 :            : 
     345                 :            :         return ret;
     346                 :            : }
     347                 :            : 
     348                 :      27884 : bool blk_mq_sched_try_insert_merge(struct request_queue *q, struct request *rq)
     349                 :            : {
     350   [ +  -  +  + ]:      27884 :         return rq_mergeable(rq) && elv_attempt_insert_merge(q, rq);
     351                 :            : }
     352                 :            : EXPORT_SYMBOL_GPL(blk_mq_sched_try_insert_merge);
     353                 :            : 
     354                 :      27548 : void blk_mq_sched_request_inserted(struct request *rq)
     355                 :            : {
     356                 :      27548 :         trace_block_rq_insert(rq->q, rq);
     357                 :      27548 : }
     358                 :            : EXPORT_SYMBOL_GPL(blk_mq_sched_request_inserted);
     359                 :            : 
     360                 :       7995 : static bool blk_mq_sched_bypass_insert(struct blk_mq_hw_ctx *hctx,
     361                 :            :                                        bool has_sched,
     362                 :            :                                        struct request *rq)
     363                 :            : {
     364                 :            :         /*
     365                 :            :          * dispatch flush and passthrough rq directly
     366                 :            :          *
     367                 :            :          * passthrough request has to be added to hctx->dispatch directly.
     368                 :            :          * For some reason, device may be in one situation which can't
     369                 :            :          * handle FS request, so STS_RESOURCE is always returned and the
     370                 :            :          * FS request will be added to hctx->dispatch. However passthrough
     371                 :            :          * request may be required at that time for fixing the problem. If
     372                 :            :          * passthrough request is added to scheduler queue, there isn't any
     373                 :            :          * chance to dispatch it given we prioritize requests in hctx->dispatch.
     374                 :            :          */
     375         [ +  + ]:       7280 :         if ((rq->rq_flags & RQF_FLUSH_SEQ) || blk_rq_is_passthrough(rq))
     376                 :            :                 return true;
     377                 :            : 
     378         [ +  - ]:       3500 :         if (has_sched)
     379                 :       3500 :                 rq->rq_flags |= RQF_SORTED;
     380                 :            : 
     381                 :            :         return false;
     382                 :            : }
     383                 :            : 
     384                 :       7995 : void blk_mq_sched_insert_request(struct request *rq, bool at_head,
     385                 :            :                                  bool run_queue, bool async)
     386                 :            : {
     387                 :       7995 :         struct request_queue *q = rq->q;
     388                 :       7995 :         struct elevator_queue *e = q->elevator;
     389                 :       7995 :         struct blk_mq_ctx *ctx = rq->mq_ctx;
     390                 :       7995 :         struct blk_mq_hw_ctx *hctx = rq->mq_hctx;
     391                 :            : 
     392                 :            :         /* flush rq in flush machinery need to be dispatched directly */
     393   [ +  +  -  + ]:       7995 :         if (!(rq->rq_flags & RQF_FLUSH_SEQ) && op_is_flush(rq->cmd_flags)) {
     394                 :          0 :                 blk_insert_flush(rq);
     395                 :          0 :                 goto run;
     396                 :            :         }
     397                 :            : 
     398   [ +  +  +  -  :      15990 :         WARN_ON(e && (rq->tag != -1));
                   -  + ]
     399                 :            : 
     400         [ +  + ]:       7995 :         if (blk_mq_sched_bypass_insert(hctx, !!e, rq)) {
     401                 :            :                 /*
     402                 :            :                  * Firstly normal IO request is inserted to scheduler queue or
     403                 :            :                  * sw queue, meantime we add flush request to dispatch queue(
     404                 :            :                  * hctx->dispatch) directly and there is at most one in-flight
     405                 :            :                  * flush request for each hw queue, so it doesn't matter to add
     406                 :            :                  * flush request to tail or front of the dispatch queue.
     407                 :            :                  *
     408                 :            :                  * Secondly in case of NCQ, flush request belongs to non-NCQ
     409                 :            :                  * command, and queueing it will fail when there is any
     410                 :            :                  * in-flight normal IO request(NCQ command). When adding flush
     411                 :            :                  * rq to the front of hctx->dispatch, it is easier to introduce
     412                 :            :                  * extra time to flush rq's latency because of S_SCHED_RESTART
     413                 :            :                  * compared with adding to the tail of dispatch queue, then
     414                 :            :                  * chance of flush merge is increased, and less flush requests
     415                 :            :                  * will be issued to controller. It is observed that ~10% time
     416                 :            :                  * is saved in blktests block/004 on disk attached to AHCI/NCQ
     417                 :            :                  * drive when adding flush rq to the front of hctx->dispatch.
     418                 :            :                  *
     419                 :            :                  * Simply queue flush rq to the front of hctx->dispatch so that
     420                 :            :                  * intensive flush workloads can benefit in case of NCQ HW.
     421                 :            :                  */
     422   [ +  +  +  + ]:       4495 :                 at_head = (rq->rq_flags & RQF_FLUSH_SEQ) ? true : at_head;
     423                 :       4495 :                 blk_mq_request_bypass_insert(rq, at_head, false);
     424                 :       4495 :                 goto run;
     425                 :            :         }
     426                 :            : 
     427   [ +  -  +  - ]:       7000 :         if (e && e->type->ops.insert_requests) {
     428                 :       3500 :                 LIST_HEAD(list);
     429                 :            : 
     430                 :       3500 :                 list_add(&rq->queuelist, &list);
     431                 :       3500 :                 e->type->ops.insert_requests(hctx, &list, at_head);
     432                 :            :         } else {
     433                 :          0 :                 spin_lock(&ctx->lock);
     434                 :          0 :                 __blk_mq_insert_request(hctx, rq, at_head);
     435                 :          0 :                 spin_unlock(&ctx->lock);
     436                 :            :         }
     437                 :            : 
     438                 :       7995 : run:
     439         [ +  + ]:       7995 :         if (run_queue)
     440                 :       7280 :                 blk_mq_run_hw_queue(hctx, async);
     441                 :       7995 : }
     442                 :            : 
     443                 :      23956 : void blk_mq_sched_insert_requests(struct blk_mq_hw_ctx *hctx,
     444                 :            :                                   struct blk_mq_ctx *ctx,
     445                 :            :                                   struct list_head *list, bool run_queue_async)
     446                 :            : {
     447                 :      23956 :         struct elevator_queue *e;
     448                 :      23956 :         struct request_queue *q = hctx->queue;
     449                 :            : 
     450                 :            :         /*
     451                 :            :          * blk_mq_sched_insert_requests() is called from flush plug
     452                 :            :          * context only, and hold one usage counter to prevent queue
     453                 :            :          * from being released.
     454                 :            :          */
     455                 :      23956 :         percpu_ref_get(&q->q_usage_counter);
     456                 :            : 
     457                 :      23956 :         e = hctx->queue->elevator;
     458   [ +  -  +  - ]:      23956 :         if (e && e->type->ops.insert_requests)
     459                 :      23956 :                 e->type->ops.insert_requests(hctx, list, false);
     460                 :            :         else {
     461                 :            :                 /*
     462                 :            :                  * try to issue requests directly if the hw queue isn't
     463                 :            :                  * busy in case of 'none' scheduler, and this way may save
     464                 :            :                  * us one extra enqueue & dequeue to sw queue.
     465                 :            :                  */
     466   [ #  #  #  # ]:          0 :                 if (!hctx->dispatch_busy && !e && !run_queue_async) {
     467                 :          0 :                         blk_mq_try_issue_list_directly(hctx, list);
     468         [ #  # ]:          0 :                         if (list_empty(list))
     469                 :          0 :                                 goto out;
     470                 :            :                 }
     471                 :          0 :                 blk_mq_insert_requests(hctx, ctx, list);
     472                 :            :         }
     473                 :            : 
     474                 :      23956 :         blk_mq_run_hw_queue(hctx, run_queue_async);
     475                 :      23956 :  out:
     476                 :      23956 :         percpu_ref_put(&q->q_usage_counter);
     477                 :      23956 : }
     478                 :            : 
     479                 :            : static void blk_mq_sched_free_tags(struct blk_mq_tag_set *set,
     480                 :            :                                    struct blk_mq_hw_ctx *hctx,
     481                 :            :                                    unsigned int hctx_idx)
     482                 :            : {
     483                 :            :         if (hctx->sched_tags) {
     484                 :            :                 blk_mq_free_rqs(set, hctx->sched_tags, hctx_idx);
     485                 :            :                 blk_mq_free_rq_map(hctx->sched_tags);
     486                 :            :                 hctx->sched_tags = NULL;
     487                 :            :         }
     488                 :            : }
     489                 :            : 
     490                 :            : static int blk_mq_sched_alloc_tags(struct request_queue *q,
     491                 :            :                                    struct blk_mq_hw_ctx *hctx,
     492                 :            :                                    unsigned int hctx_idx)
     493                 :            : {
     494                 :            :         struct blk_mq_tag_set *set = q->tag_set;
     495                 :            :         int ret;
     496                 :            : 
     497                 :            :         hctx->sched_tags = blk_mq_alloc_rq_map(set, hctx_idx, q->nr_requests,
     498                 :            :                                                set->reserved_tags);
     499                 :            :         if (!hctx->sched_tags)
     500                 :            :                 return -ENOMEM;
     501                 :            : 
     502                 :            :         ret = blk_mq_alloc_rqs(set, hctx->sched_tags, hctx_idx, q->nr_requests);
     503                 :            :         if (ret)
     504                 :            :                 blk_mq_sched_free_tags(set, hctx, hctx_idx);
     505                 :            : 
     506                 :            :         return ret;
     507                 :            : }
     508                 :            : 
     509                 :            : /* called in queue's release handler, tagset has gone away */
     510                 :            : static void blk_mq_sched_tags_teardown(struct request_queue *q)
     511                 :            : {
     512                 :            :         struct blk_mq_hw_ctx *hctx;
     513                 :            :         int i;
     514                 :            : 
     515                 :            :         queue_for_each_hw_ctx(q, hctx, i) {
     516                 :            :                 if (hctx->sched_tags) {
     517                 :            :                         blk_mq_free_rq_map(hctx->sched_tags);
     518                 :            :                         hctx->sched_tags = NULL;
     519                 :            :                 }
     520                 :            :         }
     521                 :            : }
     522                 :            : 
     523                 :        308 : int blk_mq_init_sched(struct request_queue *q, struct elevator_type *e)
     524                 :            : {
     525                 :        308 :         struct blk_mq_hw_ctx *hctx;
     526                 :        308 :         struct elevator_queue *eq;
     527                 :        308 :         unsigned int i;
     528                 :        308 :         int ret;
     529                 :            : 
     530         [ -  + ]:        308 :         if (!e) {
     531                 :          0 :                 q->elevator = NULL;
     532                 :          0 :                 q->nr_requests = q->tag_set->queue_depth;
     533                 :          0 :                 return 0;
     534                 :            :         }
     535                 :            : 
     536                 :            :         /*
     537                 :            :          * Default to double of smaller one between hw queue_depth and 128,
     538                 :            :          * since we don't split into sync/async like the old code did.
     539                 :            :          * Additionally, this is a per-hw queue depth.
     540                 :            :          */
     541                 :        308 :         q->nr_requests = 2 * min_t(unsigned int, q->tag_set->queue_depth,
     542                 :            :                                    BLKDEV_MAX_RQ);
     543                 :            : 
     544         [ +  + ]:        616 :         queue_for_each_hw_ctx(q, hctx, i) {
     545                 :        308 :                 ret = blk_mq_sched_alloc_tags(q, hctx, i);
     546         [ -  + ]:        308 :                 if (ret)
     547                 :          0 :                         goto err;
     548                 :            :         }
     549                 :            : 
     550                 :        308 :         ret = e->ops.init_sched(q, e);
     551         [ -  + ]:        308 :         if (ret)
     552                 :          0 :                 goto err;
     553                 :            : 
     554                 :        308 :         blk_mq_debugfs_register_sched(q);
     555                 :            : 
     556         [ +  + ]:        924 :         queue_for_each_hw_ctx(q, hctx, i) {
     557         [ -  + ]:        308 :                 if (e->ops.init_hctx) {
     558                 :          0 :                         ret = e->ops.init_hctx(hctx, i);
     559         [ #  # ]:          0 :                         if (ret) {
     560                 :          0 :                                 eq = q->elevator;
     561                 :          0 :                                 blk_mq_sched_free_requests(q);
     562                 :          0 :                                 blk_mq_exit_sched(q, eq);
     563                 :          0 :                                 kobject_put(&eq->kobj);
     564                 :          0 :                                 return ret;
     565                 :            :                         }
     566                 :            :                 }
     567                 :        308 :                 blk_mq_debugfs_register_sched_hctx(q, hctx);
     568                 :            :         }
     569                 :            : 
     570                 :            :         return 0;
     571                 :            : 
     572                 :          0 : err:
     573                 :          0 :         blk_mq_sched_free_requests(q);
     574                 :          0 :         blk_mq_sched_tags_teardown(q);
     575                 :          0 :         q->elevator = NULL;
     576                 :          0 :         return ret;
     577                 :            : }
     578                 :            : 
     579                 :            : /*
     580                 :            :  * called in either blk_queue_cleanup or elevator_switch, tagset
     581                 :            :  * is required for freeing requests
     582                 :            :  */
     583                 :          0 : void blk_mq_sched_free_requests(struct request_queue *q)
     584                 :            : {
     585                 :          0 :         struct blk_mq_hw_ctx *hctx;
     586                 :          0 :         int i;
     587                 :            : 
     588         [ #  # ]:          0 :         queue_for_each_hw_ctx(q, hctx, i) {
     589         [ #  # ]:          0 :                 if (hctx->sched_tags)
     590                 :          0 :                         blk_mq_free_rqs(q->tag_set, hctx->sched_tags, i);
     591                 :            :         }
     592                 :          0 : }
     593                 :            : 
     594                 :          0 : void blk_mq_exit_sched(struct request_queue *q, struct elevator_queue *e)
     595                 :            : {
     596                 :          0 :         struct blk_mq_hw_ctx *hctx;
     597                 :          0 :         unsigned int i;
     598                 :            : 
     599         [ #  # ]:          0 :         queue_for_each_hw_ctx(q, hctx, i) {
     600                 :          0 :                 blk_mq_debugfs_unregister_sched_hctx(hctx);
     601   [ #  #  #  # ]:          0 :                 if (e->type->ops.exit_hctx && hctx->sched_data) {
     602                 :          0 :                         e->type->ops.exit_hctx(hctx, i);
     603                 :          0 :                         hctx->sched_data = NULL;
     604                 :            :                 }
     605                 :            :         }
     606                 :          0 :         blk_mq_debugfs_unregister_sched(q);
     607         [ #  # ]:          0 :         if (e->type->ops.exit_sched)
     608                 :          0 :                 e->type->ops.exit_sched(e);
     609                 :          0 :         blk_mq_sched_tags_teardown(q);
     610                 :          0 :         q->elevator = NULL;
     611                 :          0 : }

Generated by: LCOV version 1.14