root/block/blk-mq-sched.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. blk_mq_sched_free_hctx_data
  2. blk_mq_sched_assign_ioc
  3. blk_mq_sched_mark_restart_hctx
  4. blk_mq_sched_restart
  5. blk_mq_do_dispatch_sched
  6. blk_mq_next_ctx
  7. blk_mq_do_dispatch_ctx
  8. blk_mq_sched_dispatch_requests
  9. blk_mq_sched_try_merge
  10. blk_mq_bio_list_merge
  11. blk_mq_attempt_merge
  12. __blk_mq_sched_bio_merge
  13. blk_mq_sched_try_insert_merge
  14. blk_mq_sched_request_inserted
  15. blk_mq_sched_bypass_insert
  16. blk_mq_sched_insert_request
  17. blk_mq_sched_insert_requests
  18. blk_mq_sched_free_tags
  19. blk_mq_sched_alloc_tags
  20. blk_mq_sched_tags_teardown
  21. blk_mq_init_sched
  22. blk_mq_sched_free_requests
  23. blk_mq_exit_sched

   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 void blk_mq_sched_free_hctx_data(struct request_queue *q,
  21                                  void (*exit)(struct blk_mq_hw_ctx *))
  22 {
  23         struct blk_mq_hw_ctx *hctx;
  24         int i;
  25 
  26         queue_for_each_hw_ctx(q, hctx, i) {
  27                 if (exit && hctx->sched_data)
  28                         exit(hctx);
  29                 kfree(hctx->sched_data);
  30                 hctx->sched_data = NULL;
  31         }
  32 }
  33 EXPORT_SYMBOL_GPL(blk_mq_sched_free_hctx_data);
  34 
  35 void blk_mq_sched_assign_ioc(struct request *rq)
  36 {
  37         struct request_queue *q = rq->q;
  38         struct io_context *ioc;
  39         struct io_cq *icq;
  40 
  41         /*
  42          * May not have an IO context if it's a passthrough request
  43          */
  44         ioc = current->io_context;
  45         if (!ioc)
  46                 return;
  47 
  48         spin_lock_irq(&q->queue_lock);
  49         icq = ioc_lookup_icq(ioc, q);
  50         spin_unlock_irq(&q->queue_lock);
  51 
  52         if (!icq) {
  53                 icq = ioc_create_icq(ioc, q, GFP_ATOMIC);
  54                 if (!icq)
  55                         return;
  56         }
  57         get_io_context(icq->ioc);
  58         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 void blk_mq_sched_mark_restart_hctx(struct blk_mq_hw_ctx *hctx)
  66 {
  67         if (test_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state))
  68                 return;
  69 
  70         set_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state);
  71 }
  72 EXPORT_SYMBOL_GPL(blk_mq_sched_mark_restart_hctx);
  73 
  74 void blk_mq_sched_restart(struct blk_mq_hw_ctx *hctx)
  75 {
  76         if (!test_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state))
  77                 return;
  78         clear_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state);
  79 
  80         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 static void blk_mq_do_dispatch_sched(struct blk_mq_hw_ctx *hctx)
  89 {
  90         struct request_queue *q = hctx->queue;
  91         struct elevator_queue *e = q->elevator;
  92         LIST_HEAD(rq_list);
  93 
  94         do {
  95                 struct request *rq;
  96 
  97                 if (e->type->ops.has_work && !e->type->ops.has_work(hctx))
  98                         break;
  99 
 100                 if (!blk_mq_get_dispatch_budget(hctx))
 101                         break;
 102 
 103                 rq = e->type->ops.dispatch_request(hctx);
 104                 if (!rq) {
 105                         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                 list_add(&rq->queuelist, &rq_list);
 115         } while (blk_mq_dispatch_rq_list(q, &rq_list, true));
 116 }
 117 
 118 static struct blk_mq_ctx *blk_mq_next_ctx(struct blk_mq_hw_ctx *hctx,
 119                                           struct blk_mq_ctx *ctx)
 120 {
 121         unsigned short idx = ctx->index_hw[hctx->type];
 122 
 123         if (++idx == hctx->nr_ctx)
 124                 idx = 0;
 125 
 126         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 static void blk_mq_do_dispatch_ctx(struct blk_mq_hw_ctx *hctx)
 135 {
 136         struct request_queue *q = hctx->queue;
 137         LIST_HEAD(rq_list);
 138         struct blk_mq_ctx *ctx = READ_ONCE(hctx->dispatch_from);
 139 
 140         do {
 141                 struct request *rq;
 142 
 143                 if (!sbitmap_any_bit_set(&hctx->ctx_map))
 144                         break;
 145 
 146                 if (!blk_mq_get_dispatch_budget(hctx))
 147                         break;
 148 
 149                 rq = blk_mq_dequeue_from_ctx(hctx, ctx);
 150                 if (!rq) {
 151                         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                 list_add(&rq->queuelist, &rq_list);
 161 
 162                 /* round robin for fair dispatch */
 163                 ctx = blk_mq_next_ctx(hctx, rq->mq_ctx);
 164 
 165         } while (blk_mq_dispatch_rq_list(q, &rq_list, true));
 166 
 167         WRITE_ONCE(hctx->dispatch_from, ctx);
 168 }
 169 
 170 void blk_mq_sched_dispatch_requests(struct blk_mq_hw_ctx *hctx)
 171 {
 172         struct request_queue *q = hctx->queue;
 173         struct elevator_queue *e = q->elevator;
 174         const bool has_sched_dispatch = e && e->type->ops.dispatch_request;
 175         LIST_HEAD(rq_list);
 176 
 177         /* RCU or SRCU read lock is needed before checking quiesced flag */
 178         if (unlikely(blk_mq_hctx_stopped(hctx) || blk_queue_quiesced(q)))
 179                 return;
 180 
 181         hctx->run++;
 182 
 183         /*
 184          * If we have previous entries on our dispatch list, grab them first for
 185          * more fair dispatch.
 186          */
 187         if (!list_empty_careful(&hctx->dispatch)) {
 188                 spin_lock(&hctx->lock);
 189                 if (!list_empty(&hctx->dispatch))
 190                         list_splice_init(&hctx->dispatch, &rq_list);
 191                 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         if (!list_empty(&rq_list)) {
 208                 blk_mq_sched_mark_restart_hctx(hctx);
 209                 if (blk_mq_dispatch_rq_list(q, &rq_list, false)) {
 210                         if (has_sched_dispatch)
 211                                 blk_mq_do_dispatch_sched(hctx);
 212                         else
 213                                 blk_mq_do_dispatch_ctx(hctx);
 214                 }
 215         } else if (has_sched_dispatch) {
 216                 blk_mq_do_dispatch_sched(hctx);
 217         } else if (hctx->dispatch_busy) {
 218                 /* dequeue request one by one from sw queue if queue is busy */
 219                 blk_mq_do_dispatch_ctx(hctx);
 220         } else {
 221                 blk_mq_flush_busy_ctxs(hctx, &rq_list);
 222                 blk_mq_dispatch_rq_list(q, &rq_list, false);
 223         }
 224 }
 225 
 226 bool blk_mq_sched_try_merge(struct request_queue *q, struct bio *bio,
 227                 unsigned int nr_segs, struct request **merged_request)
 228 {
 229         struct request *rq;
 230 
 231         switch (elv_merge(q, &rq, bio)) {
 232         case ELEVATOR_BACK_MERGE:
 233                 if (!blk_mq_sched_allow_merge(q, rq, bio))
 234                         return false;
 235                 if (!bio_attempt_back_merge(rq, bio, nr_segs))
 236                         return false;
 237                 *merged_request = attempt_back_merge(q, rq);
 238                 if (!*merged_request)
 239                         elv_merged_request(q, rq, ELEVATOR_BACK_MERGE);
 240                 return true;
 241         case ELEVATOR_FRONT_MERGE:
 242                 if (!blk_mq_sched_allow_merge(q, rq, bio))
 243                         return false;
 244                 if (!bio_attempt_front_merge(rq, bio, nr_segs))
 245                         return false;
 246                 *merged_request = attempt_front_merge(q, rq);
 247                 if (!*merged_request)
 248                         elv_merged_request(q, rq, ELEVATOR_FRONT_MERGE);
 249                 return true;
 250         case ELEVATOR_DISCARD_MERGE:
 251                 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 bool blk_mq_bio_list_merge(struct request_queue *q, struct list_head *list,
 263                            struct bio *bio, unsigned int nr_segs)
 264 {
 265         struct request *rq;
 266         int checked = 8;
 267 
 268         list_for_each_entry_reverse(rq, list, queuelist) {
 269                 bool merged = false;
 270 
 271                 if (!checked--)
 272                         break;
 273 
 274                 if (!blk_rq_merge_ok(rq, bio))
 275                         continue;
 276 
 277                 switch (blk_try_merge(rq, bio)) {
 278                 case ELEVATOR_BACK_MERGE:
 279                         if (blk_mq_sched_allow_merge(q, rq, bio))
 280                                 merged = bio_attempt_back_merge(rq, bio,
 281                                                 nr_segs);
 282                         break;
 283                 case ELEVATOR_FRONT_MERGE:
 284                         if (blk_mq_sched_allow_merge(q, rq, bio))
 285                                 merged = bio_attempt_front_merge(rq, bio,
 286                                                 nr_segs);
 287                         break;
 288                 case ELEVATOR_DISCARD_MERGE:
 289                         merged = bio_attempt_discard_merge(q, rq, bio);
 290                         break;
 291                 default:
 292                         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 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         enum hctx_type type = hctx->type;
 313 
 314         lockdep_assert_held(&ctx->lock);
 315 
 316         if (blk_mq_bio_list_merge(q, &ctx->rq_lists[type], bio, nr_segs)) {
 317                 ctx->rq_merged++;
 318                 return true;
 319         }
 320 
 321         return false;
 322 }
 323 
 324 bool __blk_mq_sched_bio_merge(struct request_queue *q, struct bio *bio,
 325                 unsigned int nr_segs)
 326 {
 327         struct elevator_queue *e = q->elevator;
 328         struct blk_mq_ctx *ctx = blk_mq_get_ctx(q);
 329         struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(q, bio->bi_opf, ctx);
 330         bool ret = false;
 331         enum hctx_type type;
 332 
 333         if (e && e->type->ops.bio_merge)
 334                 return e->type->ops.bio_merge(hctx, bio, nr_segs);
 335 
 336         type = hctx->type;
 337         if ((hctx->flags & BLK_MQ_F_SHOULD_MERGE) &&
 338                         !list_empty_careful(&ctx->rq_lists[type])) {
 339                 /* default per sw-queue merge */
 340                 spin_lock(&ctx->lock);
 341                 ret = blk_mq_attempt_merge(q, hctx, ctx, bio, nr_segs);
 342                 spin_unlock(&ctx->lock);
 343         }
 344 
 345         return ret;
 346 }
 347 
 348 bool blk_mq_sched_try_insert_merge(struct request_queue *q, struct request *rq)
 349 {
 350         return rq_mergeable(rq) && elv_attempt_insert_merge(q, rq);
 351 }
 352 EXPORT_SYMBOL_GPL(blk_mq_sched_try_insert_merge);
 353 
 354 void blk_mq_sched_request_inserted(struct request *rq)
 355 {
 356         trace_block_rq_insert(rq->q, rq);
 357 }
 358 EXPORT_SYMBOL_GPL(blk_mq_sched_request_inserted);
 359 
 360 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         if ((rq->rq_flags & RQF_FLUSH_SEQ) || blk_rq_is_passthrough(rq))
 376                 return true;
 377 
 378         if (has_sched)
 379                 rq->rq_flags |= RQF_SORTED;
 380 
 381         return false;
 382 }
 383 
 384 void blk_mq_sched_insert_request(struct request *rq, bool at_head,
 385                                  bool run_queue, bool async)
 386 {
 387         struct request_queue *q = rq->q;
 388         struct elevator_queue *e = q->elevator;
 389         struct blk_mq_ctx *ctx = rq->mq_ctx;
 390         struct blk_mq_hw_ctx *hctx = rq->mq_hctx;
 391 
 392         /* flush rq in flush machinery need to be dispatched directly */
 393         if (!(rq->rq_flags & RQF_FLUSH_SEQ) && op_is_flush(rq->cmd_flags)) {
 394                 blk_insert_flush(rq);
 395                 goto run;
 396         }
 397 
 398         WARN_ON(e && (rq->tag != -1));
 399 
 400         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                 at_head = (rq->rq_flags & RQF_FLUSH_SEQ) ? true : at_head;
 423                 blk_mq_request_bypass_insert(rq, at_head, false);
 424                 goto run;
 425         }
 426 
 427         if (e && e->type->ops.insert_requests) {
 428                 LIST_HEAD(list);
 429 
 430                 list_add(&rq->queuelist, &list);
 431                 e->type->ops.insert_requests(hctx, &list, at_head);
 432         } else {
 433                 spin_lock(&ctx->lock);
 434                 __blk_mq_insert_request(hctx, rq, at_head);
 435                 spin_unlock(&ctx->lock);
 436         }
 437 
 438 run:
 439         if (run_queue)
 440                 blk_mq_run_hw_queue(hctx, async);
 441 }
 442 
 443 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         struct elevator_queue *e;
 448         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         percpu_ref_get(&q->q_usage_counter);
 456 
 457         e = hctx->queue->elevator;
 458         if (e && e->type->ops.insert_requests)
 459                 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                 if (!hctx->dispatch_busy && !e && !run_queue_async) {
 467                         blk_mq_try_issue_list_directly(hctx, list);
 468                         if (list_empty(list))
 469                                 goto out;
 470                 }
 471                 blk_mq_insert_requests(hctx, ctx, list);
 472         }
 473 
 474         blk_mq_run_hw_queue(hctx, run_queue_async);
 475  out:
 476         percpu_ref_put(&q->q_usage_counter);
 477 }
 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 int blk_mq_init_sched(struct request_queue *q, struct elevator_type *e)
 524 {
 525         struct blk_mq_hw_ctx *hctx;
 526         struct elevator_queue *eq;
 527         unsigned int i;
 528         int ret;
 529 
 530         if (!e) {
 531                 q->elevator = NULL;
 532                 q->nr_requests = q->tag_set->queue_depth;
 533                 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         q->nr_requests = 2 * min_t(unsigned int, q->tag_set->queue_depth,
 542                                    BLKDEV_MAX_RQ);
 543 
 544         queue_for_each_hw_ctx(q, hctx, i) {
 545                 ret = blk_mq_sched_alloc_tags(q, hctx, i);
 546                 if (ret)
 547                         goto err;
 548         }
 549 
 550         ret = e->ops.init_sched(q, e);
 551         if (ret)
 552                 goto err;
 553 
 554         blk_mq_debugfs_register_sched(q);
 555 
 556         queue_for_each_hw_ctx(q, hctx, i) {
 557                 if (e->ops.init_hctx) {
 558                         ret = e->ops.init_hctx(hctx, i);
 559                         if (ret) {
 560                                 eq = q->elevator;
 561                                 blk_mq_sched_free_requests(q);
 562                                 blk_mq_exit_sched(q, eq);
 563                                 kobject_put(&eq->kobj);
 564                                 return ret;
 565                         }
 566                 }
 567                 blk_mq_debugfs_register_sched_hctx(q, hctx);
 568         }
 569 
 570         return 0;
 571 
 572 err:
 573         blk_mq_sched_free_requests(q);
 574         blk_mq_sched_tags_teardown(q);
 575         q->elevator = NULL;
 576         return ret;
 577 }
 578 
 579 /*
 580  * called in either blk_queue_cleanup or elevator_switch, tagset
 581  * is required for freeing requests
 582  */
 583 void blk_mq_sched_free_requests(struct request_queue *q)
 584 {
 585         struct blk_mq_hw_ctx *hctx;
 586         int i;
 587 
 588         queue_for_each_hw_ctx(q, hctx, i) {
 589                 if (hctx->sched_tags)
 590                         blk_mq_free_rqs(q->tag_set, hctx->sched_tags, i);
 591         }
 592 }
 593 
 594 void blk_mq_exit_sched(struct request_queue *q, struct elevator_queue *e)
 595 {
 596         struct blk_mq_hw_ctx *hctx;
 597         unsigned int i;
 598 
 599         queue_for_each_hw_ctx(q, hctx, i) {
 600                 blk_mq_debugfs_unregister_sched_hctx(hctx);
 601                 if (e->type->ops.exit_hctx && hctx->sched_data) {
 602                         e->type->ops.exit_hctx(hctx, i);
 603                         hctx->sched_data = NULL;
 604                 }
 605         }
 606         blk_mq_debugfs_unregister_sched(q);
 607         if (e->type->ops.exit_sched)
 608                 e->type->ops.exit_sched(e);
 609         blk_mq_sched_tags_teardown(q);
 610         q->elevator = NULL;
 611 }

/* [<][>][^][v][top][bottom][index][help] */