Commit ae7eb31e authored by Yu Kuai's avatar Yu Kuai Committed by Zheng Zengkai
Browse files

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: default avatarYu Kuai <yukuai3@huawei.com>
Reviewed-by: default avatarJason Yan <yanaijie@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parent 8d1b294d
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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;
+10 −2
Original line number Diff line number Diff line
@@ -117,13 +117,21 @@ 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,
		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 ?