Commit 345c03a0 authored by Harshad Shirwadkar's avatar Harshad Shirwadkar Committed by Greg Kroah-Hartman

blk-wbt: fix performance regression in wbt scale_up/scale_down

commit b84477d3 upstream.

scale_up wakes up waiters after scaling up. But after scaling max, it
should not wake up more waiters as waiters will not have anything to
do. This patch fixes this by making scale_up (and also scale_down)
return when threshold is reached.

This bug causes increased fdatasync latency when fdatasync and dd
conv=sync are performed in parallel on 4.19 compared to 4.14. This
bug was introduced during refactoring of blk-wbt code.

Fixes: a7905043 ("blk-rq-qos: refactor out common elements of blk-wbt")
Cc: stable@vger.kernel.org
Cc: Josef Bacik <jbacik@fb.com>
Signed-off-by: default avatarHarshad Shirwadkar <harshadshirwadkar@gmail.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d855a5f2
...@@ -148,24 +148,27 @@ bool rq_depth_calc_max_depth(struct rq_depth *rqd) ...@@ -148,24 +148,27 @@ bool rq_depth_calc_max_depth(struct rq_depth *rqd)
return ret; return ret;
} }
void rq_depth_scale_up(struct rq_depth *rqd) /* Returns true on success and false if scaling up wasn't possible */
bool rq_depth_scale_up(struct rq_depth *rqd)
{ {
/* /*
* Hit max in previous round, stop here * Hit max in previous round, stop here
*/ */
if (rqd->scaled_max) if (rqd->scaled_max)
return; return false;
rqd->scale_step--; rqd->scale_step--;
rqd->scaled_max = rq_depth_calc_max_depth(rqd); rqd->scaled_max = rq_depth_calc_max_depth(rqd);
return true;
} }
/* /*
* Scale rwb down. If 'hard_throttle' is set, do it quicker, since we * Scale rwb down. If 'hard_throttle' is set, do it quicker, since we
* had a latency violation. * had a latency violation. Returns true on success and returns false if
* scaling down wasn't possible.
*/ */
void rq_depth_scale_down(struct rq_depth *rqd, bool hard_throttle) bool rq_depth_scale_down(struct rq_depth *rqd, bool hard_throttle)
{ {
/* /*
* Stop scaling down when we've hit the limit. This also prevents * Stop scaling down when we've hit the limit. This also prevents
...@@ -173,7 +176,7 @@ void rq_depth_scale_down(struct rq_depth *rqd, bool hard_throttle) ...@@ -173,7 +176,7 @@ void rq_depth_scale_down(struct rq_depth *rqd, bool hard_throttle)
* keep up. * keep up.
*/ */
if (rqd->max_depth == 1) if (rqd->max_depth == 1)
return; return false;
if (rqd->scale_step < 0 && hard_throttle) if (rqd->scale_step < 0 && hard_throttle)
rqd->scale_step = 0; rqd->scale_step = 0;
...@@ -182,6 +185,7 @@ void rq_depth_scale_down(struct rq_depth *rqd, bool hard_throttle) ...@@ -182,6 +185,7 @@ void rq_depth_scale_down(struct rq_depth *rqd, bool hard_throttle)
rqd->scaled_max = false; rqd->scaled_max = false;
rq_depth_calc_max_depth(rqd); rq_depth_calc_max_depth(rqd);
return true;
} }
void rq_qos_exit(struct request_queue *q) void rq_qos_exit(struct request_queue *q)
......
...@@ -94,8 +94,8 @@ static inline void rq_qos_del(struct request_queue *q, struct rq_qos *rqos) ...@@ -94,8 +94,8 @@ static inline void rq_qos_del(struct request_queue *q, struct rq_qos *rqos)
} }
bool rq_wait_inc_below(struct rq_wait *rq_wait, unsigned int limit); bool rq_wait_inc_below(struct rq_wait *rq_wait, unsigned int limit);
void rq_depth_scale_up(struct rq_depth *rqd); bool rq_depth_scale_up(struct rq_depth *rqd);
void rq_depth_scale_down(struct rq_depth *rqd, bool hard_throttle); bool rq_depth_scale_down(struct rq_depth *rqd, bool hard_throttle);
bool rq_depth_calc_max_depth(struct rq_depth *rqd); bool rq_depth_calc_max_depth(struct rq_depth *rqd);
void rq_qos_cleanup(struct request_queue *, struct bio *); void rq_qos_cleanup(struct request_queue *, struct bio *);
......
...@@ -307,7 +307,8 @@ static void calc_wb_limits(struct rq_wb *rwb) ...@@ -307,7 +307,8 @@ static void calc_wb_limits(struct rq_wb *rwb)
static void scale_up(struct rq_wb *rwb) static void scale_up(struct rq_wb *rwb)
{ {
rq_depth_scale_up(&rwb->rq_depth); if (!rq_depth_scale_up(&rwb->rq_depth))
return;
calc_wb_limits(rwb); calc_wb_limits(rwb);
rwb->unknown_cnt = 0; rwb->unknown_cnt = 0;
rwb_wake_all(rwb); rwb_wake_all(rwb);
...@@ -316,7 +317,8 @@ static void scale_up(struct rq_wb *rwb) ...@@ -316,7 +317,8 @@ static void scale_up(struct rq_wb *rwb)
static void scale_down(struct rq_wb *rwb, bool hard_throttle) static void scale_down(struct rq_wb *rwb, bool hard_throttle)
{ {
rq_depth_scale_down(&rwb->rq_depth, hard_throttle); if (!rq_depth_scale_down(&rwb->rq_depth, hard_throttle))
return;
calc_wb_limits(rwb); calc_wb_limits(rwb);
rwb->unknown_cnt = 0; rwb->unknown_cnt = 0;
rwb_trace_step(rwb, "scale down"); rwb_trace_step(rwb, "scale down");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment