diff options
Diffstat (limited to 'block')
-rw-r--r-- | block/blk-throttle.c | 81 |
1 files changed, 39 insertions, 42 deletions
diff --git a/block/blk-throttle.c b/block/blk-throttle.c index ec9397f3eb0a..00cfdd05f98f 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c | |||
@@ -27,6 +27,8 @@ static struct blkcg_policy blkcg_policy_throtl; | |||
27 | static struct workqueue_struct *kthrotld_workqueue; | 27 | static struct workqueue_struct *kthrotld_workqueue; |
28 | 28 | ||
29 | struct throtl_service_queue { | 29 | struct throtl_service_queue { |
30 | struct throtl_service_queue *parent_sq; /* the parent service_queue */ | ||
31 | |||
30 | /* | 32 | /* |
31 | * Bios queued directly to this service_queue or dispatched from | 33 | * Bios queued directly to this service_queue or dispatched from |
32 | * children throtl_grp's. | 34 | * children throtl_grp's. |
@@ -197,21 +199,24 @@ alloc_stats: | |||
197 | } | 199 | } |
198 | 200 | ||
199 | /* init a service_queue, assumes the caller zeroed it */ | 201 | /* init a service_queue, assumes the caller zeroed it */ |
200 | static void throtl_service_queue_init(struct throtl_service_queue *sq) | 202 | static void throtl_service_queue_init(struct throtl_service_queue *sq, |
203 | struct throtl_service_queue *parent_sq) | ||
201 | { | 204 | { |
202 | bio_list_init(&sq->bio_lists[0]); | 205 | bio_list_init(&sq->bio_lists[0]); |
203 | bio_list_init(&sq->bio_lists[1]); | 206 | bio_list_init(&sq->bio_lists[1]); |
204 | sq->pending_tree = RB_ROOT; | 207 | sq->pending_tree = RB_ROOT; |
208 | sq->parent_sq = parent_sq; | ||
205 | } | 209 | } |
206 | 210 | ||
207 | static void throtl_pd_init(struct blkcg_gq *blkg) | 211 | static void throtl_pd_init(struct blkcg_gq *blkg) |
208 | { | 212 | { |
209 | struct throtl_grp *tg = blkg_to_tg(blkg); | 213 | struct throtl_grp *tg = blkg_to_tg(blkg); |
214 | struct throtl_data *td = blkg->q->td; | ||
210 | unsigned long flags; | 215 | unsigned long flags; |
211 | 216 | ||
212 | throtl_service_queue_init(&tg->service_queue); | 217 | throtl_service_queue_init(&tg->service_queue, &td->service_queue); |
213 | RB_CLEAR_NODE(&tg->rb_node); | 218 | RB_CLEAR_NODE(&tg->rb_node); |
214 | tg->td = blkg->q->td; | 219 | tg->td = td; |
215 | 220 | ||
216 | tg->bps[READ] = -1; | 221 | tg->bps[READ] = -1; |
217 | tg->bps[WRITE] = -1; | 222 | tg->bps[WRITE] = -1; |
@@ -339,9 +344,9 @@ static void update_min_dispatch_time(struct throtl_service_queue *parent_sq) | |||
339 | parent_sq->first_pending_disptime = tg->disptime; | 344 | parent_sq->first_pending_disptime = tg->disptime; |
340 | } | 345 | } |
341 | 346 | ||
342 | static void tg_service_queue_add(struct throtl_grp *tg, | 347 | static void tg_service_queue_add(struct throtl_grp *tg) |
343 | struct throtl_service_queue *parent_sq) | ||
344 | { | 348 | { |
349 | struct throtl_service_queue *parent_sq = tg->service_queue.parent_sq; | ||
345 | struct rb_node **node = &parent_sq->pending_tree.rb_node; | 350 | struct rb_node **node = &parent_sq->pending_tree.rb_node; |
346 | struct rb_node *parent = NULL; | 351 | struct rb_node *parent = NULL; |
347 | struct throtl_grp *__tg; | 352 | struct throtl_grp *__tg; |
@@ -367,33 +372,29 @@ static void tg_service_queue_add(struct throtl_grp *tg, | |||
367 | rb_insert_color(&tg->rb_node, &parent_sq->pending_tree); | 372 | rb_insert_color(&tg->rb_node, &parent_sq->pending_tree); |
368 | } | 373 | } |
369 | 374 | ||
370 | static void __throtl_enqueue_tg(struct throtl_grp *tg, | 375 | static void __throtl_enqueue_tg(struct throtl_grp *tg) |
371 | struct throtl_service_queue *parent_sq) | ||
372 | { | 376 | { |
373 | tg_service_queue_add(tg, parent_sq); | 377 | tg_service_queue_add(tg); |
374 | tg->flags |= THROTL_TG_PENDING; | 378 | tg->flags |= THROTL_TG_PENDING; |
375 | parent_sq->nr_pending++; | 379 | tg->service_queue.parent_sq->nr_pending++; |
376 | } | 380 | } |
377 | 381 | ||
378 | static void throtl_enqueue_tg(struct throtl_grp *tg, | 382 | static void throtl_enqueue_tg(struct throtl_grp *tg) |
379 | struct throtl_service_queue *parent_sq) | ||
380 | { | 383 | { |
381 | if (!(tg->flags & THROTL_TG_PENDING)) | 384 | if (!(tg->flags & THROTL_TG_PENDING)) |
382 | __throtl_enqueue_tg(tg, parent_sq); | 385 | __throtl_enqueue_tg(tg); |
383 | } | 386 | } |
384 | 387 | ||
385 | static void __throtl_dequeue_tg(struct throtl_grp *tg, | 388 | static void __throtl_dequeue_tg(struct throtl_grp *tg) |
386 | struct throtl_service_queue *parent_sq) | ||
387 | { | 389 | { |
388 | throtl_rb_erase(&tg->rb_node, parent_sq); | 390 | throtl_rb_erase(&tg->rb_node, tg->service_queue.parent_sq); |
389 | tg->flags &= ~THROTL_TG_PENDING; | 391 | tg->flags &= ~THROTL_TG_PENDING; |
390 | } | 392 | } |
391 | 393 | ||
392 | static void throtl_dequeue_tg(struct throtl_grp *tg, | 394 | static void throtl_dequeue_tg(struct throtl_grp *tg) |
393 | struct throtl_service_queue *parent_sq) | ||
394 | { | 395 | { |
395 | if (tg->flags & THROTL_TG_PENDING) | 396 | if (tg->flags & THROTL_TG_PENDING) |
396 | __throtl_dequeue_tg(tg, parent_sq); | 397 | __throtl_dequeue_tg(tg); |
397 | } | 398 | } |
398 | 399 | ||
399 | /* Call with queue lock held */ | 400 | /* Call with queue lock held */ |
@@ -707,8 +708,7 @@ static void throtl_charge_bio(struct throtl_grp *tg, struct bio *bio) | |||
707 | throtl_update_dispatch_stats(tg_to_blkg(tg), bio->bi_size, bio->bi_rw); | 708 | throtl_update_dispatch_stats(tg_to_blkg(tg), bio->bi_size, bio->bi_rw); |
708 | } | 709 | } |
709 | 710 | ||
710 | static void throtl_add_bio_tg(struct bio *bio, struct throtl_grp *tg, | 711 | static void throtl_add_bio_tg(struct bio *bio, struct throtl_grp *tg) |
711 | struct throtl_service_queue *parent_sq) | ||
712 | { | 712 | { |
713 | struct throtl_service_queue *sq = &tg->service_queue; | 713 | struct throtl_service_queue *sq = &tg->service_queue; |
714 | bool rw = bio_data_dir(bio); | 714 | bool rw = bio_data_dir(bio); |
@@ -727,11 +727,10 @@ static void throtl_add_bio_tg(struct bio *bio, struct throtl_grp *tg, | |||
727 | blkg_get(tg_to_blkg(tg)); | 727 | blkg_get(tg_to_blkg(tg)); |
728 | sq->nr_queued[rw]++; | 728 | sq->nr_queued[rw]++; |
729 | tg->td->nr_queued[rw]++; | 729 | tg->td->nr_queued[rw]++; |
730 | throtl_enqueue_tg(tg, parent_sq); | 730 | throtl_enqueue_tg(tg); |
731 | } | 731 | } |
732 | 732 | ||
733 | static void tg_update_disptime(struct throtl_grp *tg, | 733 | static void tg_update_disptime(struct throtl_grp *tg) |
734 | struct throtl_service_queue *parent_sq) | ||
735 | { | 734 | { |
736 | struct throtl_service_queue *sq = &tg->service_queue; | 735 | struct throtl_service_queue *sq = &tg->service_queue; |
737 | unsigned long read_wait = -1, write_wait = -1, min_wait = -1, disptime; | 736 | unsigned long read_wait = -1, write_wait = -1, min_wait = -1, disptime; |
@@ -747,16 +746,15 @@ static void tg_update_disptime(struct throtl_grp *tg, | |||
747 | disptime = jiffies + min_wait; | 746 | disptime = jiffies + min_wait; |
748 | 747 | ||
749 | /* Update dispatch time */ | 748 | /* Update dispatch time */ |
750 | throtl_dequeue_tg(tg, parent_sq); | 749 | throtl_dequeue_tg(tg); |
751 | tg->disptime = disptime; | 750 | tg->disptime = disptime; |
752 | throtl_enqueue_tg(tg, parent_sq); | 751 | throtl_enqueue_tg(tg); |
753 | 752 | ||
754 | /* see throtl_add_bio_tg() */ | 753 | /* see throtl_add_bio_tg() */ |
755 | tg->flags &= ~THROTL_TG_WAS_EMPTY; | 754 | tg->flags &= ~THROTL_TG_WAS_EMPTY; |
756 | } | 755 | } |
757 | 756 | ||
758 | static void tg_dispatch_one_bio(struct throtl_grp *tg, bool rw, | 757 | static void tg_dispatch_one_bio(struct throtl_grp *tg, bool rw) |
759 | struct throtl_service_queue *parent_sq) | ||
760 | { | 758 | { |
761 | struct throtl_service_queue *sq = &tg->service_queue; | 759 | struct throtl_service_queue *sq = &tg->service_queue; |
762 | struct bio *bio; | 760 | struct bio *bio; |
@@ -770,14 +768,13 @@ static void tg_dispatch_one_bio(struct throtl_grp *tg, bool rw, | |||
770 | tg->td->nr_queued[rw]--; | 768 | tg->td->nr_queued[rw]--; |
771 | 769 | ||
772 | throtl_charge_bio(tg, bio); | 770 | throtl_charge_bio(tg, bio); |
773 | bio_list_add(&parent_sq->bio_lists[rw], bio); | 771 | bio_list_add(&sq->parent_sq->bio_lists[rw], bio); |
774 | bio->bi_rw |= REQ_THROTTLED; | 772 | bio->bi_rw |= REQ_THROTTLED; |
775 | 773 | ||
776 | throtl_trim_slice(tg, rw); | 774 | throtl_trim_slice(tg, rw); |
777 | } | 775 | } |
778 | 776 | ||
779 | static int throtl_dispatch_tg(struct throtl_grp *tg, | 777 | static int throtl_dispatch_tg(struct throtl_grp *tg) |
780 | struct throtl_service_queue *parent_sq) | ||
781 | { | 778 | { |
782 | struct throtl_service_queue *sq = &tg->service_queue; | 779 | struct throtl_service_queue *sq = &tg->service_queue; |
783 | unsigned int nr_reads = 0, nr_writes = 0; | 780 | unsigned int nr_reads = 0, nr_writes = 0; |
@@ -790,7 +787,7 @@ static int throtl_dispatch_tg(struct throtl_grp *tg, | |||
790 | while ((bio = bio_list_peek(&sq->bio_lists[READ])) && | 787 | while ((bio = bio_list_peek(&sq->bio_lists[READ])) && |
791 | tg_may_dispatch(tg, bio, NULL)) { | 788 | tg_may_dispatch(tg, bio, NULL)) { |
792 | 789 | ||
793 | tg_dispatch_one_bio(tg, bio_data_dir(bio), parent_sq); | 790 | tg_dispatch_one_bio(tg, bio_data_dir(bio)); |
794 | nr_reads++; | 791 | nr_reads++; |
795 | 792 | ||
796 | if (nr_reads >= max_nr_reads) | 793 | if (nr_reads >= max_nr_reads) |
@@ -800,7 +797,7 @@ static int throtl_dispatch_tg(struct throtl_grp *tg, | |||
800 | while ((bio = bio_list_peek(&sq->bio_lists[WRITE])) && | 797 | while ((bio = bio_list_peek(&sq->bio_lists[WRITE])) && |
801 | tg_may_dispatch(tg, bio, NULL)) { | 798 | tg_may_dispatch(tg, bio, NULL)) { |
802 | 799 | ||
803 | tg_dispatch_one_bio(tg, bio_data_dir(bio), parent_sq); | 800 | tg_dispatch_one_bio(tg, bio_data_dir(bio)); |
804 | nr_writes++; | 801 | nr_writes++; |
805 | 802 | ||
806 | if (nr_writes >= max_nr_writes) | 803 | if (nr_writes >= max_nr_writes) |
@@ -824,12 +821,12 @@ static int throtl_select_dispatch(struct throtl_service_queue *parent_sq) | |||
824 | if (time_before(jiffies, tg->disptime)) | 821 | if (time_before(jiffies, tg->disptime)) |
825 | break; | 822 | break; |
826 | 823 | ||
827 | throtl_dequeue_tg(tg, parent_sq); | 824 | throtl_dequeue_tg(tg); |
828 | 825 | ||
829 | nr_disp += throtl_dispatch_tg(tg, parent_sq); | 826 | nr_disp += throtl_dispatch_tg(tg); |
830 | 827 | ||
831 | if (sq->nr_queued[0] || sq->nr_queued[1]) | 828 | if (sq->nr_queued[0] || sq->nr_queued[1]) |
832 | tg_update_disptime(tg, parent_sq); | 829 | tg_update_disptime(tg); |
833 | 830 | ||
834 | if (nr_disp >= throtl_quantum) | 831 | if (nr_disp >= throtl_quantum) |
835 | break; | 832 | break; |
@@ -991,7 +988,7 @@ static int tg_set_conf(struct cgroup *cgrp, struct cftype *cft, const char *buf, | |||
991 | throtl_start_new_slice(tg, 1); | 988 | throtl_start_new_slice(tg, 1); |
992 | 989 | ||
993 | if (tg->flags & THROTL_TG_PENDING) { | 990 | if (tg->flags & THROTL_TG_PENDING) { |
994 | tg_update_disptime(tg, &td->service_queue); | 991 | tg_update_disptime(tg); |
995 | throtl_schedule_next_dispatch(td); | 992 | throtl_schedule_next_dispatch(td); |
996 | } | 993 | } |
997 | 994 | ||
@@ -1142,12 +1139,12 @@ queue_bio: | |||
1142 | sq->nr_queued[READ], sq->nr_queued[WRITE]); | 1139 | sq->nr_queued[READ], sq->nr_queued[WRITE]); |
1143 | 1140 | ||
1144 | bio_associate_current(bio); | 1141 | bio_associate_current(bio); |
1145 | throtl_add_bio_tg(bio, tg, &q->td->service_queue); | 1142 | throtl_add_bio_tg(bio, tg); |
1146 | throttled = true; | 1143 | throttled = true; |
1147 | 1144 | ||
1148 | /* update @tg's dispatch time if @tg was empty before @bio */ | 1145 | /* update @tg's dispatch time if @tg was empty before @bio */ |
1149 | if (tg->flags & THROTL_TG_WAS_EMPTY) { | 1146 | if (tg->flags & THROTL_TG_WAS_EMPTY) { |
1150 | tg_update_disptime(tg, &td->service_queue); | 1147 | tg_update_disptime(tg); |
1151 | throtl_schedule_next_dispatch(td); | 1148 | throtl_schedule_next_dispatch(td); |
1152 | } | 1149 | } |
1153 | 1150 | ||
@@ -1179,12 +1176,12 @@ void blk_throtl_drain(struct request_queue *q) | |||
1179 | while ((tg = throtl_rb_first(parent_sq))) { | 1176 | while ((tg = throtl_rb_first(parent_sq))) { |
1180 | struct throtl_service_queue *sq = &tg->service_queue; | 1177 | struct throtl_service_queue *sq = &tg->service_queue; |
1181 | 1178 | ||
1182 | throtl_dequeue_tg(tg, parent_sq); | 1179 | throtl_dequeue_tg(tg); |
1183 | 1180 | ||
1184 | while ((bio = bio_list_peek(&sq->bio_lists[READ]))) | 1181 | while ((bio = bio_list_peek(&sq->bio_lists[READ]))) |
1185 | tg_dispatch_one_bio(tg, bio_data_dir(bio), parent_sq); | 1182 | tg_dispatch_one_bio(tg, bio_data_dir(bio)); |
1186 | while ((bio = bio_list_peek(&sq->bio_lists[WRITE]))) | 1183 | while ((bio = bio_list_peek(&sq->bio_lists[WRITE]))) |
1187 | tg_dispatch_one_bio(tg, bio_data_dir(bio), parent_sq); | 1184 | tg_dispatch_one_bio(tg, bio_data_dir(bio)); |
1188 | } | 1185 | } |
1189 | spin_unlock_irq(q->queue_lock); | 1186 | spin_unlock_irq(q->queue_lock); |
1190 | 1187 | ||
@@ -1205,7 +1202,7 @@ int blk_throtl_init(struct request_queue *q) | |||
1205 | return -ENOMEM; | 1202 | return -ENOMEM; |
1206 | 1203 | ||
1207 | INIT_DELAYED_WORK(&td->dispatch_work, blk_throtl_dispatch_work_fn); | 1204 | INIT_DELAYED_WORK(&td->dispatch_work, blk_throtl_dispatch_work_fn); |
1208 | throtl_service_queue_init(&td->service_queue); | 1205 | throtl_service_queue_init(&td->service_queue, NULL); |
1209 | 1206 | ||
1210 | q->td = td; | 1207 | q->td = td; |
1211 | td->queue = q; | 1208 | td->queue = q; |