提交 ae7eb31e 编写于 作者: Y Yu Kuai 提交者: Zheng Zengkai

block: fix that iostat can show huge wait time

hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I57S8D
CVE: NA

--------------------------------

There might be a problem that iostat can read less 'nsecs' than the
last time.

1) io is started after 'hd->stat_time' is set.

2) following concurrent scenario:

t1                              t2
                                blk_mq_end_request
				 time1 -> before hd->stat_time

				 blk_account_io_done
part_get_stat_info
 part_set_stat_time
  hd->stat_time = time2
  -> time1 < time2
 blk_mq_in_flight_with_stat
  blk_mq_check_inflight_with_stat
   cmpxchg64()
   -> set stat_time_ns to time2
				  cmpxchg64()
				  -> set stat_time to time1
				  duation = time1 - time2;
				  -> time1 < time2
				  part_stat_add(xx, nsecs, duation)
				  -> problematic

3) Similar concurrent scenario the other way around.

Fix the problem by don't add 'duation' if the calculation might underflow.
Signed-off-by: NYu Kuai <yukuai3@huawei.com>
Reviewed-by: NJason Yan <yanaijie@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 8d1b294d
......@@ -1304,7 +1304,8 @@ void blk_account_io_done(struct request *req, u64 now)
* This might fail if 'stat_time_ns' is updated
* in blk_mq_check_inflight_with_stat().
*/
if (likely(cmpxchg64(&rq_wrapper->stat_time_ns, stat_time, now)
if (likely(now > stat_time &&
cmpxchg64(&rq_wrapper->stat_time_ns, stat_time, now)
== stat_time)) {
u64 duation = stat_time ? now - stat_time :
now - req->start_time_ns;
......
......@@ -117,14 +117,22 @@ static bool blk_mq_check_inflight_with_stat(struct blk_mq_hw_ctx *hctx,
if (!rq->part)
return true;
/*
* If the request is started after 'part->stat_time' is set,
* don't update 'nsces' here.
*/
if (rq->part->stat_time <= rq->start_time_ns)
return true;
rq_wrapper = request_to_wrapper(rq);
stat_time = READ_ONCE(rq_wrapper->stat_time_ns);
/*
* This might fail if 'stat_time_ns' is updated in
* blk_account_io_done().
*/
if (likely(cmpxchg64(&rq_wrapper->stat_time_ns, stat_time,
rq->part->stat_time) == stat_time)) {
if (likely(rq->part->stat_time > stat_time &&
cmpxchg64(&rq_wrapper->stat_time_ns, stat_time,
rq->part->stat_time) == stat_time)) {
int sgrp = op_stat_group(req_op(rq));
u64 duation = stat_time ?
rq->part->stat_time - stat_time :
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册