blk-throttle: fix possible io stall when upgrade to max
authorJoseph Qi <qijiang.qj@alibaba-inc.com>
Sat, 30 Sep 2017 06:38:49 +0000 (14:38 +0800)
committerJens Axboe <axboe@kernel.dk>
Tue, 3 Oct 2017 21:41:55 +0000 (15:41 -0600)
There is a case which will lead to io stall. The case is described as
follows.
/test1
  |-subtest1
/test2
  |-subtest2
And subtest1 and subtest2 each has 32 queued bios already.

Now upgrade to max. In throtl_upgrade_state, it will try to dispatch
bios as follows:
1) tg=subtest1, do nothing;
2) tg=test1, transfer 32 queued bios from subtest1 to test1; no pending
left, no need to schedule next dispatch;
3) tg=subtest2, do nothing;
4) tg=test2, transfer 32 queued bios from subtest2 to test2; no pending
left, no need to schedule next dispatch;
5) tg=/, transfer 8 queued bios from test1 to /, 8 queued bios from
test2 to /, 8 queued bios from test1 to /, and 8 queued bios from test2
to /; note that test1 and test2 each still has 16 queued bios left;
6) tg=/, try to schedule next dispatch, but since disptime is now
(update in tg_update_disptime, wait=0), pending timer is not scheduled
in fact;
7) In throtl_upgrade_state it totally dispatches 32 queued bios and with
32 left. test1 and test2 each has 16 queued bios;
8) throtl_pending_timer_fn sees the left over bios, but could do
nothing, because throtl_select_dispatch returns 0, and test1/test2 has
no pending tg.

The blktrace shows the following:
8,32   0        0     2.539007641     0  m   N throtl upgrade to max
8,32   0        0     2.539072267     0  m   N throtl /test2 dispatch nr_queued=16 read=0 write=16
8,32   7        0     2.539077142     0  m   N throtl /test1 dispatch nr_queued=16 read=0 write=16

So force schedule dispatch if there are pending children.

Reviewed-by: Shaohua Li <shli@fb.com>
Signed-off-by: Joseph Qi <qijiang.qj@alibaba-inc.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/blk-throttle.c

index 0fea76aa0f3ff0093c4867f10139d331589df53a..17816a028dcbb6fb7f7fe4e068fb90f313448ebf 100644 (file)
@@ -1911,11 +1911,11 @@ static void throtl_upgrade_state(struct throtl_data *td)
 
                tg->disptime = jiffies - 1;
                throtl_select_dispatch(sq);
-               throtl_schedule_next_dispatch(sq, false);
+               throtl_schedule_next_dispatch(sq, true);
        }
        rcu_read_unlock();
        throtl_select_dispatch(&td->service_queue);
-       throtl_schedule_next_dispatch(&td->service_queue, false);
+       throtl_schedule_next_dispatch(&td->service_queue, true);
        queue_work(kthrotld_workqueue, &td->dispatch_work);
 }