diff options
-rw-r--r-- | block/blk-throttle.c | 96 |
1 files changed, 40 insertions, 56 deletions
diff --git a/block/blk-throttle.c b/block/blk-throttle.c index a29f09240c0f..32dd3e4b041d 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c | |||
@@ -102,7 +102,7 @@ struct throtl_data | |||
102 | /* Work for dispatching throttled bios */ | 102 | /* Work for dispatching throttled bios */ |
103 | struct delayed_work throtl_work; | 103 | struct delayed_work throtl_work; |
104 | 104 | ||
105 | atomic_t limits_changed; | 105 | bool limits_changed; |
106 | }; | 106 | }; |
107 | 107 | ||
108 | enum tg_state_flags { | 108 | enum tg_state_flags { |
@@ -201,6 +201,7 @@ static struct throtl_grp * throtl_find_alloc_tg(struct throtl_data *td, | |||
201 | RB_CLEAR_NODE(&tg->rb_node); | 201 | RB_CLEAR_NODE(&tg->rb_node); |
202 | bio_list_init(&tg->bio_lists[0]); | 202 | bio_list_init(&tg->bio_lists[0]); |
203 | bio_list_init(&tg->bio_lists[1]); | 203 | bio_list_init(&tg->bio_lists[1]); |
204 | td->limits_changed = false; | ||
204 | 205 | ||
205 | /* | 206 | /* |
206 | * Take the initial reference that will be released on destroy | 207 | * Take the initial reference that will be released on destroy |
@@ -737,34 +738,27 @@ static void throtl_process_limit_change(struct throtl_data *td) | |||
737 | struct throtl_grp *tg; | 738 | struct throtl_grp *tg; |
738 | struct hlist_node *pos, *n; | 739 | struct hlist_node *pos, *n; |
739 | 740 | ||
740 | if (!atomic_read(&td->limits_changed)) | 741 | if (!td->limits_changed) |
741 | return; | 742 | return; |
742 | 743 | ||
743 | throtl_log(td, "limit changed =%d", atomic_read(&td->limits_changed)); | 744 | xchg(&td->limits_changed, false); |
744 | 745 | ||
745 | /* | 746 | throtl_log(td, "limits changed"); |
746 | * Make sure updates from throtl_update_blkio_group_read_bps() group | ||
747 | * of functions to tg->limits_changed are visible. We do not | ||
748 | * want update td->limits_changed to be visible but update to | ||
749 | * tg->limits_changed not being visible yet on this cpu. Hence | ||
750 | * the read barrier. | ||
751 | */ | ||
752 | smp_rmb(); | ||
753 | 747 | ||
754 | hlist_for_each_entry_safe(tg, pos, n, &td->tg_list, tg_node) { | 748 | hlist_for_each_entry_safe(tg, pos, n, &td->tg_list, tg_node) { |
755 | if (throtl_tg_on_rr(tg) && tg->limits_changed) { | 749 | if (!tg->limits_changed) |
756 | throtl_log_tg(td, tg, "limit change rbps=%llu wbps=%llu" | 750 | continue; |
757 | " riops=%u wiops=%u", tg->bps[READ], | 751 | |
758 | tg->bps[WRITE], tg->iops[READ], | 752 | if (!xchg(&tg->limits_changed, false)) |
759 | tg->iops[WRITE]); | 753 | continue; |
754 | |||
755 | throtl_log_tg(td, tg, "limit change rbps=%llu wbps=%llu" | ||
756 | " riops=%u wiops=%u", tg->bps[READ], tg->bps[WRITE], | ||
757 | tg->iops[READ], tg->iops[WRITE]); | ||
758 | |||
759 | if (throtl_tg_on_rr(tg)) | ||
760 | tg_update_disptime(td, tg); | 760 | tg_update_disptime(td, tg); |
761 | tg->limits_changed = false; | ||
762 | } | ||
763 | } | 761 | } |
764 | |||
765 | smp_mb__before_atomic_dec(); | ||
766 | atomic_dec(&td->limits_changed); | ||
767 | smp_mb__after_atomic_dec(); | ||
768 | } | 762 | } |
769 | 763 | ||
770 | /* Dispatch throttled bios. Should be called without queue lock held. */ | 764 | /* Dispatch throttled bios. Should be called without queue lock held. */ |
@@ -898,6 +892,15 @@ void throtl_unlink_blkio_group(void *key, struct blkio_group *blkg) | |||
898 | spin_unlock_irqrestore(td->queue->queue_lock, flags); | 892 | spin_unlock_irqrestore(td->queue->queue_lock, flags); |
899 | } | 893 | } |
900 | 894 | ||
895 | static void throtl_update_blkio_group_common(struct throtl_data *td, | ||
896 | struct throtl_grp *tg) | ||
897 | { | ||
898 | xchg(&tg->limits_changed, true); | ||
899 | xchg(&td->limits_changed, true); | ||
900 | /* Schedule a work now to process the limit change */ | ||
901 | throtl_schedule_delayed_work(td, 0); | ||
902 | } | ||
903 | |||
901 | /* | 904 | /* |
902 | * For all update functions, key should be a valid pointer because these | 905 | * For all update functions, key should be a valid pointer because these |
903 | * update functions are called under blkcg_lock, that means, blkg is | 906 | * update functions are called under blkcg_lock, that means, blkg is |
@@ -911,61 +914,40 @@ static void throtl_update_blkio_group_read_bps(void *key, | |||
911 | struct blkio_group *blkg, u64 read_bps) | 914 | struct blkio_group *blkg, u64 read_bps) |
912 | { | 915 | { |
913 | struct throtl_data *td = key; | 916 | struct throtl_data *td = key; |
917 | struct throtl_grp *tg = tg_of_blkg(blkg); | ||
914 | 918 | ||
915 | tg_of_blkg(blkg)->bps[READ] = read_bps; | 919 | tg->bps[READ] = read_bps; |
916 | /* Make sure read_bps is updated before setting limits_changed */ | 920 | throtl_update_blkio_group_common(td, tg); |
917 | smp_wmb(); | ||
918 | tg_of_blkg(blkg)->limits_changed = true; | ||
919 | |||
920 | /* Make sure tg->limits_changed is updated before td->limits_changed */ | ||
921 | smp_mb__before_atomic_inc(); | ||
922 | atomic_inc(&td->limits_changed); | ||
923 | smp_mb__after_atomic_inc(); | ||
924 | |||
925 | /* Schedule a work now to process the limit change */ | ||
926 | throtl_schedule_delayed_work(td, 0); | ||
927 | } | 921 | } |
928 | 922 | ||
929 | static void throtl_update_blkio_group_write_bps(void *key, | 923 | static void throtl_update_blkio_group_write_bps(void *key, |
930 | struct blkio_group *blkg, u64 write_bps) | 924 | struct blkio_group *blkg, u64 write_bps) |
931 | { | 925 | { |
932 | struct throtl_data *td = key; | 926 | struct throtl_data *td = key; |
927 | struct throtl_grp *tg = tg_of_blkg(blkg); | ||
933 | 928 | ||
934 | tg_of_blkg(blkg)->bps[WRITE] = write_bps; | 929 | tg->bps[WRITE] = write_bps; |
935 | smp_wmb(); | 930 | throtl_update_blkio_group_common(td, tg); |
936 | tg_of_blkg(blkg)->limits_changed = true; | ||
937 | smp_mb__before_atomic_inc(); | ||
938 | atomic_inc(&td->limits_changed); | ||
939 | smp_mb__after_atomic_inc(); | ||
940 | throtl_schedule_delayed_work(td, 0); | ||
941 | } | 931 | } |
942 | 932 | ||
943 | static void throtl_update_blkio_group_read_iops(void *key, | 933 | static void throtl_update_blkio_group_read_iops(void *key, |
944 | struct blkio_group *blkg, unsigned int read_iops) | 934 | struct blkio_group *blkg, unsigned int read_iops) |
945 | { | 935 | { |
946 | struct throtl_data *td = key; | 936 | struct throtl_data *td = key; |
937 | struct throtl_grp *tg = tg_of_blkg(blkg); | ||
947 | 938 | ||
948 | tg_of_blkg(blkg)->iops[READ] = read_iops; | 939 | tg->iops[READ] = read_iops; |
949 | smp_wmb(); | 940 | throtl_update_blkio_group_common(td, tg); |
950 | tg_of_blkg(blkg)->limits_changed = true; | ||
951 | smp_mb__before_atomic_inc(); | ||
952 | atomic_inc(&td->limits_changed); | ||
953 | smp_mb__after_atomic_inc(); | ||
954 | throtl_schedule_delayed_work(td, 0); | ||
955 | } | 941 | } |
956 | 942 | ||
957 | static void throtl_update_blkio_group_write_iops(void *key, | 943 | static void throtl_update_blkio_group_write_iops(void *key, |
958 | struct blkio_group *blkg, unsigned int write_iops) | 944 | struct blkio_group *blkg, unsigned int write_iops) |
959 | { | 945 | { |
960 | struct throtl_data *td = key; | 946 | struct throtl_data *td = key; |
947 | struct throtl_grp *tg = tg_of_blkg(blkg); | ||
961 | 948 | ||
962 | tg_of_blkg(blkg)->iops[WRITE] = write_iops; | 949 | tg->iops[WRITE] = write_iops; |
963 | smp_wmb(); | 950 | throtl_update_blkio_group_common(td, tg); |
964 | tg_of_blkg(blkg)->limits_changed = true; | ||
965 | smp_mb__before_atomic_inc(); | ||
966 | atomic_inc(&td->limits_changed); | ||
967 | smp_mb__after_atomic_inc(); | ||
968 | throtl_schedule_delayed_work(td, 0); | ||
969 | } | 951 | } |
970 | 952 | ||
971 | static void throtl_shutdown_wq(struct request_queue *q) | 953 | static void throtl_shutdown_wq(struct request_queue *q) |
@@ -1012,6 +994,7 @@ int blk_throtl_bio(struct request_queue *q, struct bio **biop) | |||
1012 | */ | 994 | */ |
1013 | update_disptime = false; | 995 | update_disptime = false; |
1014 | goto queue_bio; | 996 | goto queue_bio; |
997 | |||
1015 | } | 998 | } |
1016 | 999 | ||
1017 | /* Bio is with-in rate limit of group */ | 1000 | /* Bio is with-in rate limit of group */ |
@@ -1052,7 +1035,7 @@ int blk_throtl_init(struct request_queue *q) | |||
1052 | 1035 | ||
1053 | INIT_HLIST_HEAD(&td->tg_list); | 1036 | INIT_HLIST_HEAD(&td->tg_list); |
1054 | td->tg_service_tree = THROTL_RB_ROOT; | 1037 | td->tg_service_tree = THROTL_RB_ROOT; |
1055 | atomic_set(&td->limits_changed, 0); | 1038 | td->limits_changed = false; |
1056 | 1039 | ||
1057 | /* Init root group */ | 1040 | /* Init root group */ |
1058 | tg = &td->root_tg; | 1041 | tg = &td->root_tg; |
@@ -1064,6 +1047,7 @@ int blk_throtl_init(struct request_queue *q) | |||
1064 | /* Practically unlimited BW */ | 1047 | /* Practically unlimited BW */ |
1065 | tg->bps[0] = tg->bps[1] = -1; | 1048 | tg->bps[0] = tg->bps[1] = -1; |
1066 | tg->iops[0] = tg->iops[1] = -1; | 1049 | tg->iops[0] = tg->iops[1] = -1; |
1050 | td->limits_changed = false; | ||
1067 | 1051 | ||
1068 | /* | 1052 | /* |
1069 | * Set root group reference to 2. One reference will be dropped when | 1053 | * Set root group reference to 2. One reference will be dropped when |