aboutsummaryrefslogtreecommitdiffstats
path: root/block/blk-throttle.c
diff options
context:
space:
mode:
authorVivek Goyal <vgoyal@redhat.com>2013-05-14 16:52:38 -0400
committerTejun Heo <tj@kernel.org>2013-05-14 16:52:38 -0400
commit32ee5bc4787dfbdb280b4d81a338dcdd55918c1e (patch)
treeadb0b9bc436db10588035cfb2cc8071d588b6f01 /block/blk-throttle.c
parentc5cc2070b45333f40a3f99319b83c8caeb62ec05 (diff)
blk-throttle: Account for child group's start time in parent while bio climbs up
With the planned proper hierarchy support, a bio will climb up the tree before actually being dispatched. This makes sure bio is also subjected to parent's throttling limits, if any. It might happen that parent is idle and when bio is transferred to parent, a new slice starts fresh. But that is incorrect as parents wait time should have started when bio was queued in child group and causes IOs to be throttled more than configured as they climb the hierarchy. Given the fact that we have not written hierarchical algorithm in a way where child's and parents time slices are synchronized, we transfer the child's start time to parent if parent was idling. If parent was busy doing dispatch of other bios all this while, this is not an issue. Child's slice start time is passed to parent. Parent looks at its last expired slice start time. If child's start time is after parents old start time, that means parent had been idle and after parent went idle, child had an IO queued. So use child's start time as parent start time. If parent's start time is after child's start time, that means, when IO got queued in child group, parent was not idle. But later it dispatched some IO, its slice got trimmed and then it went idle. After a while child's request got shifted in parent group. In this case use parent's old start time as new start time as that's the duration of slice we did not use. This logic is far from perfect as if there are multiple childs then first child transferring the bio decides the start time while a bio might have queued up even earlier in other child, which is yet to be transferred up to parent. In that case we will lose time and bandwidth in parent. This patch is just an approximation to make situation somewhat better. Signed-off-by: Vivek Goyal <vgoyal@redhat.com> Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'block/blk-throttle.c')
-rw-r--r--block/blk-throttle.c33
1 files changed, 33 insertions, 0 deletions
diff --git a/block/blk-throttle.c b/block/blk-throttle.c
index 541bd0dabb9a..7477f332c8dc 100644
--- a/block/blk-throttle.c
+++ b/block/blk-throttle.c
@@ -633,6 +633,28 @@ static bool throtl_schedule_next_dispatch(struct throtl_service_queue *sq,
633 return false; 633 return false;
634} 634}
635 635
636static inline void throtl_start_new_slice_with_credit(struct throtl_grp *tg,
637 bool rw, unsigned long start)
638{
639 tg->bytes_disp[rw] = 0;
640 tg->io_disp[rw] = 0;
641
642 /*
643 * Previous slice has expired. We must have trimmed it after last
644 * bio dispatch. That means since start of last slice, we never used
645 * that bandwidth. Do try to make use of that bandwidth while giving
646 * credit.
647 */
648 if (time_after_eq(start, tg->slice_start[rw]))
649 tg->slice_start[rw] = start;
650
651 tg->slice_end[rw] = jiffies + throtl_slice;
652 throtl_log(&tg->service_queue,
653 "[%c] new slice with credit start=%lu end=%lu jiffies=%lu",
654 rw == READ ? 'R' : 'W', tg->slice_start[rw],
655 tg->slice_end[rw], jiffies);
656}
657
636static inline void throtl_start_new_slice(struct throtl_grp *tg, bool rw) 658static inline void throtl_start_new_slice(struct throtl_grp *tg, bool rw)
637{ 659{
638 tg->bytes_disp[rw] = 0; 660 tg->bytes_disp[rw] = 0;
@@ -992,6 +1014,16 @@ static void tg_update_disptime(struct throtl_grp *tg)
992 tg->flags &= ~THROTL_TG_WAS_EMPTY; 1014 tg->flags &= ~THROTL_TG_WAS_EMPTY;
993} 1015}
994 1016
1017static void start_parent_slice_with_credit(struct throtl_grp *child_tg,
1018 struct throtl_grp *parent_tg, bool rw)
1019{
1020 if (throtl_slice_used(parent_tg, rw)) {
1021 throtl_start_new_slice_with_credit(parent_tg, rw,
1022 child_tg->slice_start[rw]);
1023 }
1024
1025}
1026
995static void tg_dispatch_one_bio(struct throtl_grp *tg, bool rw) 1027static void tg_dispatch_one_bio(struct throtl_grp *tg, bool rw)
996{ 1028{
997 struct throtl_service_queue *sq = &tg->service_queue; 1029 struct throtl_service_queue *sq = &tg->service_queue;
@@ -1020,6 +1052,7 @@ static void tg_dispatch_one_bio(struct throtl_grp *tg, bool rw)
1020 */ 1052 */
1021 if (parent_tg) { 1053 if (parent_tg) {
1022 throtl_add_bio_tg(bio, &tg->qnode_on_parent[rw], parent_tg); 1054 throtl_add_bio_tg(bio, &tg->qnode_on_parent[rw], parent_tg);
1055 start_parent_slice_with_credit(tg, parent_tg, rw);
1023 } else { 1056 } else {
1024 throtl_qnode_add_bio(bio, &tg->qnode_on_parent[rw], 1057 throtl_qnode_add_bio(bio, &tg->qnode_on_parent[rw],
1025 &parent_sq->queued[rw]); 1058 &parent_sq->queued[rw]);