diff options
author | Tejun Heo <tj@kernel.org> | 2013-05-14 16:52:38 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2013-05-14 16:52:38 -0400 |
commit | 2e48a530a3a7daebd0cc17866304a36d39b611de (patch) | |
tree | 6fc47a1a5b74966ff19f5287dc58fbcf3a541ee6 /block | |
parent | 6bc9c2b464fb89eab705da87aa4284171d942369 (diff) |
blk-throttle: make throtl_pending_timer_fn() ready for hierarchy
throtl_pending_timer_fn() currently assumes that the parent_sq is the
top level one and the bio's dispatched are ready to be issued;
however, this assumption will be wrong with proper hierarchy support.
This patch makes the following changes to make
throtl_pending_timer_fn() ready for hiearchy.
* If the parent_sq isn't the top-level one, update the parent
throtl_grp's dispatch time and schedule the next dispatch as
necessary. If the parent's dispatch time is now, repeat the
function for the parent throtl_grp.
* If the parent_sq is the top-level one, kick issue work_item as
before.
* The debug message printed by throtl_log() now prints out the
service_queue's nr_queued[] instead of the total nr_queued as the
latter becomes uninteresting and misleading with hierarchical
dispatch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Vivek Goyal <vgoyal@redhat.com>
Diffstat (limited to 'block')
-rw-r--r-- | block/blk-throttle.c | 40 |
1 files changed, 33 insertions, 7 deletions
diff --git a/block/blk-throttle.c b/block/blk-throttle.c index 04202617fda5..bc65077f6e43 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c | |||
@@ -952,23 +952,33 @@ static int throtl_select_dispatch(struct throtl_service_queue *parent_sq) | |||
952 | * This timer is armed when a child throtl_grp with active bio's become | 952 | * This timer is armed when a child throtl_grp with active bio's become |
953 | * pending and queued on the service_queue's pending_tree and expires when | 953 | * pending and queued on the service_queue's pending_tree and expires when |
954 | * the first child throtl_grp should be dispatched. This function | 954 | * the first child throtl_grp should be dispatched. This function |
955 | * dispatches bio's from the children throtl_grps and kicks | 955 | * dispatches bio's from the children throtl_grps to the parent |
956 | * throtl_data->dispatch_work if there are bio's ready to be issued. | 956 | * service_queue. |
957 | * | ||
958 | * If the parent's parent is another throtl_grp, dispatching is propagated | ||
959 | * by either arming its pending_timer or repeating dispatch directly. If | ||
960 | * the top-level service_tree is reached, throtl_data->dispatch_work is | ||
961 | * kicked so that the ready bio's are issued. | ||
957 | */ | 962 | */ |
958 | static void throtl_pending_timer_fn(unsigned long arg) | 963 | static void throtl_pending_timer_fn(unsigned long arg) |
959 | { | 964 | { |
960 | struct throtl_service_queue *sq = (void *)arg; | 965 | struct throtl_service_queue *sq = (void *)arg; |
966 | struct throtl_grp *tg = sq_to_tg(sq); | ||
961 | struct throtl_data *td = sq_to_td(sq); | 967 | struct throtl_data *td = sq_to_td(sq); |
962 | struct request_queue *q = td->queue; | 968 | struct request_queue *q = td->queue; |
963 | bool dispatched = false; | 969 | struct throtl_service_queue *parent_sq; |
970 | bool dispatched; | ||
964 | int ret; | 971 | int ret; |
965 | 972 | ||
966 | spin_lock_irq(q->queue_lock); | 973 | spin_lock_irq(q->queue_lock); |
974 | again: | ||
975 | parent_sq = sq->parent_sq; | ||
976 | dispatched = false; | ||
967 | 977 | ||
968 | while (true) { | 978 | while (true) { |
969 | throtl_log(sq, "dispatch nr_queued=%u read=%u write=%u", | 979 | throtl_log(sq, "dispatch nr_queued=%u read=%u write=%u", |
970 | td->nr_queued[READ] + td->nr_queued[WRITE], | 980 | sq->nr_queued[READ] + sq->nr_queued[WRITE], |
971 | td->nr_queued[READ], td->nr_queued[WRITE]); | 981 | sq->nr_queued[READ], sq->nr_queued[WRITE]); |
972 | 982 | ||
973 | ret = throtl_select_dispatch(sq); | 983 | ret = throtl_select_dispatch(sq); |
974 | if (ret) { | 984 | if (ret) { |
@@ -985,9 +995,25 @@ static void throtl_pending_timer_fn(unsigned long arg) | |||
985 | spin_lock_irq(q->queue_lock); | 995 | spin_lock_irq(q->queue_lock); |
986 | } | 996 | } |
987 | 997 | ||
988 | if (dispatched) | 998 | if (!dispatched) |
989 | queue_work(kthrotld_workqueue, &td->dispatch_work); | 999 | goto out_unlock; |
990 | 1000 | ||
1001 | if (parent_sq) { | ||
1002 | /* @parent_sq is another throl_grp, propagate dispatch */ | ||
1003 | if (tg->flags & THROTL_TG_WAS_EMPTY) { | ||
1004 | tg_update_disptime(tg); | ||
1005 | if (!throtl_schedule_next_dispatch(parent_sq, false)) { | ||
1006 | /* window is already open, repeat dispatching */ | ||
1007 | sq = parent_sq; | ||
1008 | tg = sq_to_tg(sq); | ||
1009 | goto again; | ||
1010 | } | ||
1011 | } | ||
1012 | } else { | ||
1013 | /* reached the top-level, queue issueing */ | ||
1014 | queue_work(kthrotld_workqueue, &td->dispatch_work); | ||
1015 | } | ||
1016 | out_unlock: | ||
991 | spin_unlock_irq(q->queue_lock); | 1017 | spin_unlock_irq(q->queue_lock); |
992 | } | 1018 | } |
993 | 1019 | ||