Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

block: use {alloc|free}_sched data methods

The previous patch introduced ->alloc_sched_data and
->free_sched_data methods. This patch builds upon that
by now using these methods during elevator switch and
nr_hw_queue update.

It's also ensured that scheduler-specific data is
allocated and freed through the new callbacks outside
of the ->freeze_lock and ->elevator_lock locking contexts,
thereby preventing any dependency on pcpu_alloc_mutex.

Reviewed-by: Ming Lei <ming.lei@redhat.com>
Reviewed-by: Yu Kuai <yukuai@fnnas.com>
Signed-off-by: Nilay Shroff <nilay@linux.ibm.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Nilay Shroff and committed by
Jens Axboe
0315476e 61019afd

+50 -20
+21 -6
block/blk-mq-sched.c
··· 428 428 } 429 429 430 430 void blk_mq_free_sched_res(struct elevator_resources *res, 431 + struct elevator_type *type, 431 432 struct blk_mq_tag_set *set) 432 433 { 433 434 if (res->et) { 434 435 blk_mq_free_sched_tags(res->et, set); 435 436 res->et = NULL; 437 + } 438 + if (res->data) { 439 + blk_mq_free_sched_data(type, res->data); 440 + res->data = NULL; 436 441 } 437 442 } 438 443 ··· 463 458 WARN_ON_ONCE(1); 464 459 continue; 465 460 } 466 - blk_mq_free_sched_res(&ctx->res, set); 461 + blk_mq_free_sched_res(&ctx->res, ctx->type, set); 467 462 } 468 463 } 469 464 } ··· 545 540 } 546 541 547 542 int blk_mq_alloc_sched_res(struct request_queue *q, 548 - struct elevator_resources *res, unsigned int nr_hw_queues) 543 + struct elevator_type *type, 544 + struct elevator_resources *res, 545 + unsigned int nr_hw_queues) 549 546 { 550 547 struct blk_mq_tag_set *set = q->tag_set; 551 548 ··· 555 548 blk_mq_default_nr_requests(set)); 556 549 if (!res->et) 557 550 return -ENOMEM; 551 + 552 + res->data = blk_mq_alloc_sched_data(q, type); 553 + if (IS_ERR(res->data)) { 554 + blk_mq_free_sched_tags(res->et, set); 555 + return -ENOMEM; 556 + } 558 557 559 558 return 0; 560 559 } ··· 589 576 goto out_unwind; 590 577 } 591 578 592 - ret = blk_mq_alloc_sched_res(q, &ctx->res, 593 - nr_hw_queues); 579 + ret = blk_mq_alloc_sched_res(q, q->elevator->type, 580 + &ctx->res, nr_hw_queues); 594 581 if (ret) 595 582 goto out_unwind; 596 583 } 597 584 } 598 585 return 0; 586 + 599 587 out_unwind: 600 588 list_for_each_entry_continue_reverse(q, &set->tag_list, tag_set_list) { 601 589 if (q->elevator) { 602 590 ctx = xa_load(elv_tbl, q->id); 603 591 if (ctx) 604 - blk_mq_free_sched_res(&ctx->res, set); 592 + blk_mq_free_sched_res(&ctx->res, 593 + ctx->type, set); 605 594 } 606 595 } 607 596 return ret; ··· 620 605 unsigned long i; 621 606 int ret; 622 607 623 - eq = elevator_alloc(q, e, et); 608 + eq = elevator_alloc(q, e, res); 624 609 if (!eq) 625 610 return -ENOMEM; 626 611
+4 -1
block/blk-mq-sched.h
··· 26 26 struct elevator_tags *blk_mq_alloc_sched_tags(struct blk_mq_tag_set *set, 27 27 unsigned int nr_hw_queues, unsigned int nr_requests); 28 28 int blk_mq_alloc_sched_res(struct request_queue *q, 29 - struct elevator_resources *res, unsigned int nr_hw_queues); 29 + struct elevator_type *type, 30 + struct elevator_resources *res, 31 + unsigned int nr_hw_queues); 30 32 int blk_mq_alloc_sched_res_batch(struct xarray *elv_tbl, 31 33 struct blk_mq_tag_set *set, unsigned int nr_hw_queues); 32 34 int blk_mq_alloc_sched_ctx_batch(struct xarray *elv_tbl, ··· 37 35 void blk_mq_free_sched_tags(struct elevator_tags *et, 38 36 struct blk_mq_tag_set *set); 39 37 void blk_mq_free_sched_res(struct elevator_resources *res, 38 + struct elevator_type *type, 40 39 struct blk_mq_tag_set *set); 41 40 void blk_mq_free_sched_res_batch(struct xarray *et_table, 42 41 struct blk_mq_tag_set *set);
+22 -12
block/elevator.c
··· 121 121 static const struct kobj_type elv_ktype; 122 122 123 123 struct elevator_queue *elevator_alloc(struct request_queue *q, 124 - struct elevator_type *e, struct elevator_tags *et) 124 + struct elevator_type *e, struct elevator_resources *res) 125 125 { 126 126 struct elevator_queue *eq; 127 127 ··· 134 134 kobject_init(&eq->kobj, &elv_ktype); 135 135 mutex_init(&eq->sysfs_lock); 136 136 hash_init(eq->hash); 137 - eq->et = et; 137 + eq->et = res->et; 138 + eq->elevator_data = res->data; 138 139 139 140 return eq; 140 141 } ··· 618 617 mutex_unlock(&q->elevator_lock); 619 618 blk_mq_unfreeze_queue(q, memflags); 620 619 if (e) { 621 - blk_mq_free_sched_res(&ctx->res, q->tag_set); 620 + blk_mq_free_sched_res(&ctx->res, ctx->type, q->tag_set); 622 621 kobject_put(&e->kobj); 623 622 } 624 623 } ··· 629 628 int ret = 0; 630 629 631 630 if (ctx->old) { 632 - struct elevator_resources res = {.et = ctx->old->et}; 631 + struct elevator_resources res = { 632 + .et = ctx->old->et, 633 + .data = ctx->old->elevator_data 634 + }; 633 635 bool enable_wbt = test_bit(ELEVATOR_FLAG_ENABLE_WBT_ON_EXIT, 634 636 &ctx->old->flags); 635 637 636 638 elv_unregister_queue(q, ctx->old); 637 - blk_mq_free_sched_res(&res, q->tag_set); 639 + blk_mq_free_sched_res(&res, ctx->old->type, q->tag_set); 638 640 kobject_put(&ctx->old->kobj); 639 641 if (enable_wbt) 640 642 wbt_enable_default(q->disk); ··· 662 658 lockdep_assert_held(&set->update_nr_hwq_lock); 663 659 664 660 if (strncmp(ctx->name, "none", 4)) { 665 - ret = blk_mq_alloc_sched_res(q, &ctx->res, set->nr_hw_queues); 661 + ret = blk_mq_alloc_sched_res(q, ctx->type, &ctx->res, 662 + set->nr_hw_queues); 666 663 if (ret) 667 664 return ret; 668 665 } ··· 686 681 blk_mq_unfreeze_queue(q, memflags); 687 682 if (!ret) 688 683 ret = elevator_change_done(q, ctx); 684 + 689 685 /* 690 686 * Free sched resource if it's allocated but we couldn't switch elevator. 691 687 */ 692 688 if (!ctx->new) 693 - blk_mq_free_sched_res(&ctx->res, set); 689 + blk_mq_free_sched_res(&ctx->res, ctx->type, set); 694 690 695 691 return ret; 696 692 } ··· 717 711 blk_mq_unfreeze_queue_nomemrestore(q); 718 712 if (!ret) 719 713 WARN_ON_ONCE(elevator_change_done(q, ctx)); 714 + 720 715 /* 721 716 * Free sched resource if it's allocated but we couldn't switch elevator. 722 717 */ 723 718 if (!ctx->new) 724 - blk_mq_free_sched_res(&ctx->res, set); 719 + blk_mq_free_sched_res(&ctx->res, ctx->type, set); 725 720 } 726 721 727 722 /* ··· 736 729 .no_uevent = true, 737 730 }; 738 731 int err; 739 - struct elevator_type *e; 740 732 741 733 /* now we allow to switch elevator */ 742 734 blk_queue_flag_clear(QUEUE_FLAG_NO_ELV_SWITCH, q); ··· 748 742 * have multiple queues or mq-deadline is not available, default 749 743 * to "none". 750 744 */ 751 - e = elevator_find_get(ctx.name); 752 - if (!e) 745 + ctx.type = elevator_find_get(ctx.name); 746 + if (!ctx.type) 753 747 return; 754 748 755 749 if ((q->nr_hw_queues == 1 || ··· 759 753 pr_warn("\"%s\" elevator initialization, failed %d, falling back to \"none\"\n", 760 754 ctx.name, err); 761 755 } 762 - elevator_put(e); 756 + elevator_put(ctx.type); 763 757 } 764 758 765 759 void elevator_set_none(struct request_queue *q) ··· 808 802 ctx.name = strstrip(elevator_name); 809 803 810 804 elv_iosched_load_module(ctx.name); 805 + ctx.type = elevator_find_get(ctx.name); 811 806 812 807 down_read(&set->update_nr_hwq_lock); 813 808 if (!blk_queue_no_elv_switch(q)) { ··· 819 812 ret = -ENOENT; 820 813 } 821 814 up_read(&set->update_nr_hwq_lock); 815 + 816 + if (ctx.type) 817 + elevator_put(ctx.type); 822 818 return ret; 823 819 } 824 820
+3 -1
block/elevator.h
··· 33 33 }; 34 34 35 35 struct elevator_resources { 36 + /* holds elevator data */ 37 + void *data; 36 38 /* holds elevator tags */ 37 39 struct elevator_tags *et; 38 40 }; ··· 187 185 188 186 extern bool elv_bio_merge_ok(struct request *, struct bio *); 189 187 struct elevator_queue *elevator_alloc(struct request_queue *, 190 - struct elevator_type *, struct elevator_tags *); 188 + struct elevator_type *, struct elevator_resources *); 191 189 192 190 /* 193 191 * Helper functions.