.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
---|
1 | 2 | /* |
---|
2 | 3 | * buffered writeback throttling. loosely based on CoDel. We can't drop |
---|
3 | 4 | * packets for IO scheduling, so the logic is something like this: |
---|
.. | .. |
---|
313 | 314 | calc_wb_limits(rwb); |
---|
314 | 315 | rwb->unknown_cnt = 0; |
---|
315 | 316 | rwb_wake_all(rwb); |
---|
316 | | - rwb_trace_step(rwb, "scale up"); |
---|
| 317 | + rwb_trace_step(rwb, tracepoint_string("scale up")); |
---|
317 | 318 | } |
---|
318 | 319 | |
---|
319 | 320 | static void scale_down(struct rq_wb *rwb, bool hard_throttle) |
---|
.. | .. |
---|
322 | 323 | return; |
---|
323 | 324 | calc_wb_limits(rwb); |
---|
324 | 325 | rwb->unknown_cnt = 0; |
---|
325 | | - rwb_trace_step(rwb, "scale down"); |
---|
| 326 | + rwb_trace_step(rwb, tracepoint_string("scale down")); |
---|
326 | 327 | } |
---|
327 | 328 | |
---|
328 | 329 | static void rwb_arm_timer(struct rq_wb *rwb) |
---|
.. | .. |
---|
405 | 406 | rwb_arm_timer(rwb); |
---|
406 | 407 | } |
---|
407 | 408 | |
---|
408 | | -static void __wbt_update_limits(struct rq_wb *rwb) |
---|
| 409 | +static void wbt_update_limits(struct rq_wb *rwb) |
---|
409 | 410 | { |
---|
410 | 411 | struct rq_depth *rqd = &rwb->rq_depth; |
---|
411 | 412 | |
---|
.. | .. |
---|
416 | 417 | calc_wb_limits(rwb); |
---|
417 | 418 | |
---|
418 | 419 | rwb_wake_all(rwb); |
---|
419 | | -} |
---|
420 | | - |
---|
421 | | -void wbt_update_limits(struct request_queue *q) |
---|
422 | | -{ |
---|
423 | | - struct rq_qos *rqos = wbt_rq_qos(q); |
---|
424 | | - if (!rqos) |
---|
425 | | - return; |
---|
426 | | - __wbt_update_limits(RQWB(rqos)); |
---|
427 | 420 | } |
---|
428 | 421 | |
---|
429 | 422 | u64 wbt_get_min_lat(struct request_queue *q) |
---|
.. | .. |
---|
441 | 434 | return; |
---|
442 | 435 | RQWB(rqos)->min_lat_nsec = val; |
---|
443 | 436 | RQWB(rqos)->enable_state = WBT_STATE_ON_MANUAL; |
---|
444 | | - __wbt_update_limits(RQWB(rqos)); |
---|
| 437 | + wbt_update_limits(RQWB(rqos)); |
---|
445 | 438 | } |
---|
446 | 439 | |
---|
447 | 440 | |
---|
.. | .. |
---|
492 | 485 | } |
---|
493 | 486 | |
---|
494 | 487 | struct wbt_wait_data { |
---|
495 | | - struct wait_queue_entry wq; |
---|
496 | | - struct task_struct *task; |
---|
497 | 488 | struct rq_wb *rwb; |
---|
498 | | - struct rq_wait *rqw; |
---|
| 489 | + enum wbt_flags wb_acct; |
---|
499 | 490 | unsigned long rw; |
---|
500 | | - bool got_token; |
---|
501 | 491 | }; |
---|
502 | 492 | |
---|
503 | | -static int wbt_wake_function(struct wait_queue_entry *curr, unsigned int mode, |
---|
504 | | - int wake_flags, void *key) |
---|
| 493 | +static bool wbt_inflight_cb(struct rq_wait *rqw, void *private_data) |
---|
505 | 494 | { |
---|
506 | | - struct wbt_wait_data *data = container_of(curr, struct wbt_wait_data, |
---|
507 | | - wq); |
---|
| 495 | + struct wbt_wait_data *data = private_data; |
---|
| 496 | + return rq_wait_inc_below(rqw, get_limit(data->rwb, data->rw)); |
---|
| 497 | +} |
---|
508 | 498 | |
---|
509 | | - /* |
---|
510 | | - * If we fail to get a budget, return -1 to interrupt the wake up |
---|
511 | | - * loop in __wake_up_common. |
---|
512 | | - */ |
---|
513 | | - if (!rq_wait_inc_below(data->rqw, get_limit(data->rwb, data->rw))) |
---|
514 | | - return -1; |
---|
515 | | - |
---|
516 | | - data->got_token = true; |
---|
517 | | - list_del_init(&curr->entry); |
---|
518 | | - wake_up_process(data->task); |
---|
519 | | - return 1; |
---|
| 499 | +static void wbt_cleanup_cb(struct rq_wait *rqw, void *private_data) |
---|
| 500 | +{ |
---|
| 501 | + struct wbt_wait_data *data = private_data; |
---|
| 502 | + wbt_rqw_done(data->rwb, rqw, data->wb_acct); |
---|
520 | 503 | } |
---|
521 | 504 | |
---|
522 | 505 | /* |
---|
.. | .. |
---|
524 | 507 | * the timer to kick off queuing again. |
---|
525 | 508 | */ |
---|
526 | 509 | static void __wbt_wait(struct rq_wb *rwb, enum wbt_flags wb_acct, |
---|
527 | | - unsigned long rw, spinlock_t *lock) |
---|
528 | | - __releases(lock) |
---|
529 | | - __acquires(lock) |
---|
| 510 | + unsigned long rw) |
---|
530 | 511 | { |
---|
531 | 512 | struct rq_wait *rqw = get_rq_wait(rwb, wb_acct); |
---|
532 | 513 | struct wbt_wait_data data = { |
---|
533 | | - .wq = { |
---|
534 | | - .func = wbt_wake_function, |
---|
535 | | - .entry = LIST_HEAD_INIT(data.wq.entry), |
---|
536 | | - }, |
---|
537 | | - .task = current, |
---|
538 | 514 | .rwb = rwb, |
---|
539 | | - .rqw = rqw, |
---|
| 515 | + .wb_acct = wb_acct, |
---|
540 | 516 | .rw = rw, |
---|
541 | 517 | }; |
---|
542 | | - bool has_sleeper; |
---|
543 | 518 | |
---|
544 | | - has_sleeper = wq_has_sleeper(&rqw->wait); |
---|
545 | | - if (!has_sleeper && rq_wait_inc_below(rqw, get_limit(rwb, rw))) |
---|
546 | | - return; |
---|
547 | | - |
---|
548 | | - prepare_to_wait_exclusive(&rqw->wait, &data.wq, TASK_UNINTERRUPTIBLE); |
---|
549 | | - do { |
---|
550 | | - if (data.got_token) |
---|
551 | | - break; |
---|
552 | | - |
---|
553 | | - if (!has_sleeper && |
---|
554 | | - rq_wait_inc_below(rqw, get_limit(rwb, rw))) { |
---|
555 | | - finish_wait(&rqw->wait, &data.wq); |
---|
556 | | - |
---|
557 | | - /* |
---|
558 | | - * We raced with wbt_wake_function() getting a token, |
---|
559 | | - * which means we now have two. Put our local token |
---|
560 | | - * and wake anyone else potentially waiting for one. |
---|
561 | | - */ |
---|
562 | | - if (data.got_token) |
---|
563 | | - wbt_rqw_done(rwb, rqw, wb_acct); |
---|
564 | | - break; |
---|
565 | | - } |
---|
566 | | - |
---|
567 | | - if (lock) { |
---|
568 | | - spin_unlock_irq(lock); |
---|
569 | | - io_schedule(); |
---|
570 | | - spin_lock_irq(lock); |
---|
571 | | - } else |
---|
572 | | - io_schedule(); |
---|
573 | | - |
---|
574 | | - has_sleeper = false; |
---|
575 | | - } while (1); |
---|
576 | | - |
---|
577 | | - finish_wait(&rqw->wait, &data.wq); |
---|
| 519 | + rq_qos_wait(rqw, &data, wbt_inflight_cb, wbt_cleanup_cb); |
---|
578 | 520 | } |
---|
579 | 521 | |
---|
580 | 522 | static inline bool wbt_should_throttle(struct rq_wb *rwb, struct bio *bio) |
---|
.. | .. |
---|
587 | 529 | if ((bio->bi_opf & (REQ_SYNC | REQ_IDLE)) == |
---|
588 | 530 | (REQ_SYNC | REQ_IDLE)) |
---|
589 | 531 | return false; |
---|
590 | | - /* fallthrough */ |
---|
| 532 | + fallthrough; |
---|
591 | 533 | case REQ_OP_DISCARD: |
---|
592 | 534 | return true; |
---|
593 | 535 | default: |
---|
.. | .. |
---|
627 | 569 | * in an irq held spinlock, if it holds one when calling this function. |
---|
628 | 570 | * If we do sleep, we'll release and re-grab it. |
---|
629 | 571 | */ |
---|
630 | | -static void wbt_wait(struct rq_qos *rqos, struct bio *bio, spinlock_t *lock) |
---|
| 572 | +static void wbt_wait(struct rq_qos *rqos, struct bio *bio) |
---|
631 | 573 | { |
---|
632 | 574 | struct rq_wb *rwb = RQWB(rqos); |
---|
633 | 575 | enum wbt_flags flags; |
---|
.. | .. |
---|
639 | 581 | return; |
---|
640 | 582 | } |
---|
641 | 583 | |
---|
642 | | - __wbt_wait(rwb, flags, bio->bi_opf, lock); |
---|
| 584 | + __wbt_wait(rwb, flags, bio->bi_opf); |
---|
643 | 585 | |
---|
644 | 586 | if (!blk_stat_is_active(rwb->cb)) |
---|
645 | 587 | rwb_arm_timer(rwb); |
---|
.. | .. |
---|
651 | 593 | rq->wbt_flags |= bio_to_wbt_flags(rwb, bio); |
---|
652 | 594 | } |
---|
653 | 595 | |
---|
654 | | -void wbt_issue(struct rq_qos *rqos, struct request *rq) |
---|
| 596 | +static void wbt_issue(struct rq_qos *rqos, struct request *rq) |
---|
655 | 597 | { |
---|
656 | 598 | struct rq_wb *rwb = RQWB(rqos); |
---|
657 | 599 | |
---|
.. | .. |
---|
671 | 613 | } |
---|
672 | 614 | } |
---|
673 | 615 | |
---|
674 | | -void wbt_requeue(struct rq_qos *rqos, struct request *rq) |
---|
| 616 | +static void wbt_requeue(struct rq_qos *rqos, struct request *rq) |
---|
675 | 617 | { |
---|
676 | 618 | struct rq_wb *rwb = RQWB(rqos); |
---|
677 | 619 | if (!rwb_enabled(rwb)) |
---|
.. | .. |
---|
679 | 621 | if (rq == rwb->sync_cookie) { |
---|
680 | 622 | rwb->sync_issue = 0; |
---|
681 | 623 | rwb->sync_cookie = NULL; |
---|
682 | | - } |
---|
683 | | -} |
---|
684 | | - |
---|
685 | | -void wbt_set_queue_depth(struct request_queue *q, unsigned int depth) |
---|
686 | | -{ |
---|
687 | | - struct rq_qos *rqos = wbt_rq_qos(q); |
---|
688 | | - if (rqos) { |
---|
689 | | - RQWB(rqos)->rq_depth.queue_depth = depth; |
---|
690 | | - __wbt_update_limits(RQWB(rqos)); |
---|
691 | 624 | } |
---|
692 | 625 | } |
---|
693 | 626 | |
---|
.. | .. |
---|
716 | 649 | if (!blk_queue_registered(q)) |
---|
717 | 650 | return; |
---|
718 | 651 | |
---|
719 | | - if ((q->mq_ops && IS_ENABLED(CONFIG_BLK_WBT_MQ)) || |
---|
720 | | - (q->request_fn && IS_ENABLED(CONFIG_BLK_WBT_SQ))) |
---|
| 652 | + if (queue_is_mq(q) && IS_ENABLED(CONFIG_BLK_WBT_MQ)) |
---|
721 | 653 | wbt_init(q); |
---|
722 | 654 | } |
---|
723 | 655 | EXPORT_SYMBOL_GPL(wbt_enable_default); |
---|
.. | .. |
---|
747 | 679 | return -1; |
---|
748 | 680 | } |
---|
749 | 681 | |
---|
| 682 | +static void wbt_queue_depth_changed(struct rq_qos *rqos) |
---|
| 683 | +{ |
---|
| 684 | + RQWB(rqos)->rq_depth.queue_depth = blk_queue_depth(rqos->q); |
---|
| 685 | + wbt_update_limits(RQWB(rqos)); |
---|
| 686 | +} |
---|
| 687 | + |
---|
750 | 688 | static void wbt_exit(struct rq_qos *rqos) |
---|
751 | 689 | { |
---|
752 | 690 | struct rq_wb *rwb = RQWB(rqos); |
---|
.. | .. |
---|
774 | 712 | } |
---|
775 | 713 | EXPORT_SYMBOL_GPL(wbt_disable_default); |
---|
776 | 714 | |
---|
| 715 | +#ifdef CONFIG_BLK_DEBUG_FS |
---|
| 716 | +static int wbt_curr_win_nsec_show(void *data, struct seq_file *m) |
---|
| 717 | +{ |
---|
| 718 | + struct rq_qos *rqos = data; |
---|
| 719 | + struct rq_wb *rwb = RQWB(rqos); |
---|
| 720 | + |
---|
| 721 | + seq_printf(m, "%llu\n", rwb->cur_win_nsec); |
---|
| 722 | + return 0; |
---|
| 723 | +} |
---|
| 724 | + |
---|
| 725 | +static int wbt_enabled_show(void *data, struct seq_file *m) |
---|
| 726 | +{ |
---|
| 727 | + struct rq_qos *rqos = data; |
---|
| 728 | + struct rq_wb *rwb = RQWB(rqos); |
---|
| 729 | + |
---|
| 730 | + seq_printf(m, "%d\n", rwb->enable_state); |
---|
| 731 | + return 0; |
---|
| 732 | +} |
---|
| 733 | + |
---|
| 734 | +static int wbt_id_show(void *data, struct seq_file *m) |
---|
| 735 | +{ |
---|
| 736 | + struct rq_qos *rqos = data; |
---|
| 737 | + |
---|
| 738 | + seq_printf(m, "%u\n", rqos->id); |
---|
| 739 | + return 0; |
---|
| 740 | +} |
---|
| 741 | + |
---|
| 742 | +static int wbt_inflight_show(void *data, struct seq_file *m) |
---|
| 743 | +{ |
---|
| 744 | + struct rq_qos *rqos = data; |
---|
| 745 | + struct rq_wb *rwb = RQWB(rqos); |
---|
| 746 | + int i; |
---|
| 747 | + |
---|
| 748 | + for (i = 0; i < WBT_NUM_RWQ; i++) |
---|
| 749 | + seq_printf(m, "%d: inflight %d\n", i, |
---|
| 750 | + atomic_read(&rwb->rq_wait[i].inflight)); |
---|
| 751 | + return 0; |
---|
| 752 | +} |
---|
| 753 | + |
---|
| 754 | +static int wbt_min_lat_nsec_show(void *data, struct seq_file *m) |
---|
| 755 | +{ |
---|
| 756 | + struct rq_qos *rqos = data; |
---|
| 757 | + struct rq_wb *rwb = RQWB(rqos); |
---|
| 758 | + |
---|
| 759 | + seq_printf(m, "%lu\n", rwb->min_lat_nsec); |
---|
| 760 | + return 0; |
---|
| 761 | +} |
---|
| 762 | + |
---|
| 763 | +static int wbt_unknown_cnt_show(void *data, struct seq_file *m) |
---|
| 764 | +{ |
---|
| 765 | + struct rq_qos *rqos = data; |
---|
| 766 | + struct rq_wb *rwb = RQWB(rqos); |
---|
| 767 | + |
---|
| 768 | + seq_printf(m, "%u\n", rwb->unknown_cnt); |
---|
| 769 | + return 0; |
---|
| 770 | +} |
---|
| 771 | + |
---|
| 772 | +static int wbt_normal_show(void *data, struct seq_file *m) |
---|
| 773 | +{ |
---|
| 774 | + struct rq_qos *rqos = data; |
---|
| 775 | + struct rq_wb *rwb = RQWB(rqos); |
---|
| 776 | + |
---|
| 777 | + seq_printf(m, "%u\n", rwb->wb_normal); |
---|
| 778 | + return 0; |
---|
| 779 | +} |
---|
| 780 | + |
---|
| 781 | +static int wbt_background_show(void *data, struct seq_file *m) |
---|
| 782 | +{ |
---|
| 783 | + struct rq_qos *rqos = data; |
---|
| 784 | + struct rq_wb *rwb = RQWB(rqos); |
---|
| 785 | + |
---|
| 786 | + seq_printf(m, "%u\n", rwb->wb_background); |
---|
| 787 | + return 0; |
---|
| 788 | +} |
---|
| 789 | + |
---|
| 790 | +static const struct blk_mq_debugfs_attr wbt_debugfs_attrs[] = { |
---|
| 791 | + {"curr_win_nsec", 0400, wbt_curr_win_nsec_show}, |
---|
| 792 | + {"enabled", 0400, wbt_enabled_show}, |
---|
| 793 | + {"id", 0400, wbt_id_show}, |
---|
| 794 | + {"inflight", 0400, wbt_inflight_show}, |
---|
| 795 | + {"min_lat_nsec", 0400, wbt_min_lat_nsec_show}, |
---|
| 796 | + {"unknown_cnt", 0400, wbt_unknown_cnt_show}, |
---|
| 797 | + {"wb_normal", 0400, wbt_normal_show}, |
---|
| 798 | + {"wb_background", 0400, wbt_background_show}, |
---|
| 799 | + {}, |
---|
| 800 | +}; |
---|
| 801 | +#endif |
---|
777 | 802 | |
---|
778 | 803 | static struct rq_qos_ops wbt_rqos_ops = { |
---|
779 | 804 | .throttle = wbt_wait, |
---|
.. | .. |
---|
782 | 807 | .requeue = wbt_requeue, |
---|
783 | 808 | .done = wbt_done, |
---|
784 | 809 | .cleanup = wbt_cleanup, |
---|
| 810 | + .queue_depth_changed = wbt_queue_depth_changed, |
---|
785 | 811 | .exit = wbt_exit, |
---|
| 812 | +#ifdef CONFIG_BLK_DEBUG_FS |
---|
| 813 | + .debugfs_attrs = wbt_debugfs_attrs, |
---|
| 814 | +#endif |
---|
786 | 815 | }; |
---|
787 | 816 | |
---|
788 | 817 | int wbt_init(struct request_queue *q) |
---|
.. | .. |
---|
809 | 838 | rwb->last_comp = rwb->last_issue = jiffies; |
---|
810 | 839 | rwb->win_nsec = RWB_WINDOW_NSEC; |
---|
811 | 840 | rwb->enable_state = WBT_STATE_ON_DEFAULT; |
---|
812 | | - rwb->wc = 1; |
---|
| 841 | + rwb->wc = test_bit(QUEUE_FLAG_WC, &q->queue_flags); |
---|
813 | 842 | rwb->rq_depth.default_depth = RWB_DEF_DEPTH; |
---|
814 | | - __wbt_update_limits(rwb); |
---|
| 843 | + rwb->min_lat_nsec = wbt_default_latency_nsec(q); |
---|
| 844 | + |
---|
| 845 | + wbt_queue_depth_changed(&rwb->rqos); |
---|
815 | 846 | |
---|
816 | 847 | /* |
---|
817 | 848 | * Assign rwb and add the stats callback. |
---|
818 | 849 | */ |
---|
819 | 850 | rq_qos_add(q, &rwb->rqos); |
---|
820 | 851 | blk_stat_add_callback(q, rwb->cb); |
---|
821 | | - |
---|
822 | | - rwb->min_lat_nsec = wbt_default_latency_nsec(q); |
---|
823 | | - |
---|
824 | | - wbt_set_queue_depth(q, blk_queue_depth(q)); |
---|
825 | | - wbt_set_write_cache(q, test_bit(QUEUE_FLAG_WC, &q->queue_flags)); |
---|
826 | 852 | |
---|
827 | 853 | return 0; |
---|
828 | 854 | } |
---|