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.

blk-wbt: fix possible deadlock to nest pcpu_alloc_mutex under q_usage_counter

If wbt is disabled by default and user configures wbt by sysfs, queue
will be frozen first and then pcpu_alloc_mutex will be held in
blk_stat_alloc_callback().

Fix this problem by allocating memory first before queue frozen.

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

authored by

Yu Kuai and committed by
Jens Axboe
41afaeed 2751b900

+63 -45
+63 -45
block/blk-wbt.c
··· 93 93 struct rq_depth rq_depth; 94 94 }; 95 95 96 - static int wbt_init(struct gendisk *disk); 96 + static int wbt_init(struct gendisk *disk, struct rq_wb *rwb); 97 97 98 98 static inline struct rq_wb *RQWB(struct rq_qos *rqos) 99 99 { ··· 698 698 } 699 699 } 700 700 701 + static int wbt_data_dir(const struct request *rq) 702 + { 703 + const enum req_op op = req_op(rq); 704 + 705 + if (op == REQ_OP_READ) 706 + return READ; 707 + else if (op_is_write(op)) 708 + return WRITE; 709 + 710 + /* don't account */ 711 + return -1; 712 + } 713 + 714 + static struct rq_wb *wbt_alloc(void) 715 + { 716 + struct rq_wb *rwb = kzalloc(sizeof(*rwb), GFP_KERNEL); 717 + 718 + if (!rwb) 719 + return NULL; 720 + 721 + rwb->cb = blk_stat_alloc_callback(wb_timer_fn, wbt_data_dir, 2, rwb); 722 + if (!rwb->cb) { 723 + kfree(rwb); 724 + return NULL; 725 + } 726 + 727 + return rwb; 728 + } 729 + 730 + static void wbt_free(struct rq_wb *rwb) 731 + { 732 + blk_stat_free_callback(rwb->cb); 733 + kfree(rwb); 734 + } 735 + 701 736 /* 702 737 * Enable wbt if defaults are configured that way 703 738 */ ··· 774 739 775 740 void wbt_init_enable_default(struct gendisk *disk) 776 741 { 777 - if (__wbt_enable_default(disk)) 778 - WARN_ON_ONCE(wbt_init(disk)); 742 + struct rq_wb *rwb; 743 + 744 + if (!__wbt_enable_default(disk)) 745 + return; 746 + 747 + rwb = wbt_alloc(); 748 + if (WARN_ON_ONCE(!rwb)) 749 + return; 750 + 751 + if (WARN_ON_ONCE(wbt_init(disk, rwb))) 752 + wbt_free(rwb); 779 753 } 780 754 781 755 static u64 wbt_default_latency_nsec(struct request_queue *q) ··· 798 754 return 2000000ULL; 799 755 } 800 756 801 - static int wbt_data_dir(const struct request *rq) 802 - { 803 - const enum req_op op = req_op(rq); 804 - 805 - if (op == REQ_OP_READ) 806 - return READ; 807 - else if (op_is_write(op)) 808 - return WRITE; 809 - 810 - /* don't account */ 811 - return -1; 812 - } 813 - 814 757 static void wbt_queue_depth_changed(struct rq_qos *rqos) 815 758 { 816 759 RQWB(rqos)->rq_depth.queue_depth = blk_queue_depth(rqos->disk->queue); ··· 809 778 struct rq_wb *rwb = RQWB(rqos); 810 779 811 780 blk_stat_remove_callback(rqos->disk->queue, rwb->cb); 812 - blk_stat_free_callback(rwb->cb); 813 - kfree(rwb); 781 + wbt_free(rwb); 814 782 } 815 783 816 784 /* ··· 933 903 #endif 934 904 }; 935 905 936 - static int wbt_init(struct gendisk *disk) 906 + static int wbt_init(struct gendisk *disk, struct rq_wb *rwb) 937 907 { 938 908 struct request_queue *q = disk->queue; 939 - struct rq_wb *rwb; 940 - int i; 941 909 int ret; 942 - 943 - rwb = kzalloc(sizeof(*rwb), GFP_KERNEL); 944 - if (!rwb) 945 - return -ENOMEM; 946 - 947 - rwb->cb = blk_stat_alloc_callback(wb_timer_fn, wbt_data_dir, 2, rwb); 948 - if (!rwb->cb) { 949 - kfree(rwb); 950 - return -ENOMEM; 951 - } 910 + int i; 952 911 953 912 for (i = 0; i < WBT_NUM_RWQ; i++) 954 913 rq_wait_init(&rwb->rq_wait[i]); ··· 957 938 ret = rq_qos_add(&rwb->rqos, disk, RQ_QOS_WBT, &wbt_rqos_ops); 958 939 mutex_unlock(&q->rq_qos_mutex); 959 940 if (ret) 960 - goto err_free; 941 + return ret; 961 942 962 943 blk_stat_add_callback(q, rwb->cb); 963 - 964 944 return 0; 965 - 966 - err_free: 967 - blk_stat_free_callback(rwb->cb); 968 - kfree(rwb); 969 - return ret; 970 - 971 945 } 972 946 973 947 int wbt_set_lat(struct gendisk *disk, s64 val) 974 948 { 975 949 struct request_queue *q = disk->queue; 950 + struct rq_qos *rqos = wbt_rq_qos(q); 951 + struct rq_wb *rwb = NULL; 976 952 unsigned int memflags; 977 - struct rq_qos *rqos; 978 953 int ret = 0; 954 + 955 + if (!rqos) { 956 + rwb = wbt_alloc(); 957 + if (!rwb) 958 + return -ENOMEM; 959 + } 979 960 980 961 /* 981 962 * Ensure that the queue is idled, in case the latency update ··· 983 964 * have IO inflight if that happens. 984 965 */ 985 966 memflags = blk_mq_freeze_queue(q); 986 - 987 - rqos = wbt_rq_qos(q); 988 967 if (!rqos) { 989 - ret = wbt_init(disk); 990 - if (ret) 968 + ret = wbt_init(disk, rwb); 969 + if (ret) { 970 + wbt_free(rwb); 991 971 goto out; 972 + } 992 973 } 993 974 994 975 if (val == -1) ··· 1008 989 blk_mq_unquiesce_queue(q); 1009 990 out: 1010 991 blk_mq_unfreeze_queue(q, memflags); 1011 - 1012 992 return ret; 1013 993 }