diff options
author | Paolo Valente <paolo.valente@linaro.org> | 2017-09-21 05:04:00 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2017-10-03 10:40:54 -0400 |
commit | 4baa8bb13f41307f3eb62fe91f93a1a798ebef53 (patch) | |
tree | 499e78fa5e8deb43e51b52f21d180e8021d4aad8 /block/bfq-iosched.c | |
parent | aac8d41cd438f25bf3110fc6b98f1d16d7dbc169 (diff) |
block, bfq: fix wrong init of saved start time for weight raising
This commit fixes a bug that causes bfq to fail to guarantee a high
responsiveness on some drives, if there is heavy random read+write I/O
in the background. More precisely, such a failure allowed this bug to
be found [1], but the bug may well cause other yet unreported
anomalies.
BFQ raises the weight of the bfq_queues associated with soft real-time
applications, to privilege the I/O, and thus reduce latency, for these
applications. This mechanism is named soft-real-time weight raising in
BFQ. A soft real-time period may happen to be nested into an
interactive weight raising period, i.e., it may happen that, when a
bfq_queue switches to a soft real-time weight-raised state, the
bfq_queue is already being weight-raised because deemed interactive
too. In this case, BFQ saves in a special variable
wr_start_at_switch_to_srt, the time instant when the interactive
weight-raising period started for the bfq_queue, i.e., the time
instant when BFQ started to deem the bfq_queue interactive. This value
is then used to check whether the interactive weight-raising period
would still be in progress when the soft real-time weight-raising
period ends. If so, interactive weight raising is restored for the
bfq_queue. This restore is useful, in particular, because it prevents
bfq_queues from losing their interactive weight raising prematurely,
as a consequence of spurious, short-lived soft real-time
weight-raising periods caused by wrong detections as soft real-time.
If, instead, a bfq_queue switches to soft-real-time weight raising
while it *is not* already in an interactive weight-raising period,
then the variable wr_start_at_switch_to_srt has no meaning during the
following soft real-time weight-raising period. Unfortunately the
handling of this case is wrong in BFQ: not only the variable is not
flagged somehow as meaningless, but it is also set to the time when
the switch to soft real-time weight-raising occurs. This may cause an
interactive weight-raising period to be considered mistakenly as still
in progress, and thus a spurious interactive weight-raising period to
start for the bfq_queue, at the end of the soft-real-time
weight-raising period. In particular the spurious interactive
weight-raising period will be considered as still in progress, if the
soft-real-time weight-raising period does not last very long. The
bfq_queue will then be wrongly privileged and, if I/O bound, will
unjustly steal bandwidth to truly interactive or soft real-time
bfq_queues, harming responsiveness and low latency.
This commit fixes this issue by just setting wr_start_at_switch_to_srt
to minus infinity (farthest past time instant according to jiffies
macros): when the soft-real-time weight-raising period ends, certainly
no interactive weight-raising period will be considered as still in
progress.
[1] Background I/O Type: Random - Background I/O mix: Reads and writes
- Application to start: LibreOffice Writer in
http://www.phoronix.com/scan.php?page=news_item&px=Linux-4.13-IO-Laptop
Signed-off-by: Paolo Valente <paolo.valente@linaro.org>
Signed-off-by: Angelo Ruocco <angeloruocco90@gmail.com>
Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name>
Tested-by: Lee Tibbert <lee.tibbert@gmail.com>
Tested-by: Mirko Montanari <mirkomontanari91@gmail.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'block/bfq-iosched.c')
-rw-r--r-- | block/bfq-iosched.c | 50 |
1 files changed, 31 insertions, 19 deletions
diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c index a4783da90ba8..c25955c25e03 100644 --- a/block/bfq-iosched.c +++ b/block/bfq-iosched.c | |||
@@ -1202,6 +1202,24 @@ static unsigned int bfq_wr_duration(struct bfq_data *bfqd) | |||
1202 | return dur; | 1202 | return dur; |
1203 | } | 1203 | } |
1204 | 1204 | ||
1205 | /* | ||
1206 | * Return the farthest future time instant according to jiffies | ||
1207 | * macros. | ||
1208 | */ | ||
1209 | static unsigned long bfq_greatest_from_now(void) | ||
1210 | { | ||
1211 | return jiffies + MAX_JIFFY_OFFSET; | ||
1212 | } | ||
1213 | |||
1214 | /* | ||
1215 | * Return the farthest past time instant according to jiffies | ||
1216 | * macros. | ||
1217 | */ | ||
1218 | static unsigned long bfq_smallest_from_now(void) | ||
1219 | { | ||
1220 | return jiffies - MAX_JIFFY_OFFSET; | ||
1221 | } | ||
1222 | |||
1205 | static void bfq_update_bfqq_wr_on_rq_arrival(struct bfq_data *bfqd, | 1223 | static void bfq_update_bfqq_wr_on_rq_arrival(struct bfq_data *bfqd, |
1206 | struct bfq_queue *bfqq, | 1224 | struct bfq_queue *bfqq, |
1207 | unsigned int old_wr_coeff, | 1225 | unsigned int old_wr_coeff, |
@@ -1216,7 +1234,19 @@ static void bfq_update_bfqq_wr_on_rq_arrival(struct bfq_data *bfqd, | |||
1216 | bfqq->wr_coeff = bfqd->bfq_wr_coeff; | 1234 | bfqq->wr_coeff = bfqd->bfq_wr_coeff; |
1217 | bfqq->wr_cur_max_time = bfq_wr_duration(bfqd); | 1235 | bfqq->wr_cur_max_time = bfq_wr_duration(bfqd); |
1218 | } else { | 1236 | } else { |
1219 | bfqq->wr_start_at_switch_to_srt = jiffies; | 1237 | /* |
1238 | * No interactive weight raising in progress | ||
1239 | * here: assign minus infinity to | ||
1240 | * wr_start_at_switch_to_srt, to make sure | ||
1241 | * that, at the end of the soft-real-time | ||
1242 | * weight raising periods that is starting | ||
1243 | * now, no interactive weight-raising period | ||
1244 | * may be wrongly considered as still in | ||
1245 | * progress (and thus actually started by | ||
1246 | * mistake). | ||
1247 | */ | ||
1248 | bfqq->wr_start_at_switch_to_srt = | ||
1249 | bfq_smallest_from_now(); | ||
1220 | bfqq->wr_coeff = bfqd->bfq_wr_coeff * | 1250 | bfqq->wr_coeff = bfqd->bfq_wr_coeff * |
1221 | BFQ_SOFTRT_WEIGHT_FACTOR; | 1251 | BFQ_SOFTRT_WEIGHT_FACTOR; |
1222 | bfqq->wr_cur_max_time = | 1252 | bfqq->wr_cur_max_time = |
@@ -2897,24 +2927,6 @@ static unsigned long bfq_bfqq_softrt_next_start(struct bfq_data *bfqd, | |||
2897 | jiffies + nsecs_to_jiffies(bfqq->bfqd->bfq_slice_idle) + 4); | 2927 | jiffies + nsecs_to_jiffies(bfqq->bfqd->bfq_slice_idle) + 4); |
2898 | } | 2928 | } |
2899 | 2929 | ||
2900 | /* | ||
2901 | * Return the farthest future time instant according to jiffies | ||
2902 | * macros. | ||
2903 | */ | ||
2904 | static unsigned long bfq_greatest_from_now(void) | ||
2905 | { | ||
2906 | return jiffies + MAX_JIFFY_OFFSET; | ||
2907 | } | ||
2908 | |||
2909 | /* | ||
2910 | * Return the farthest past time instant according to jiffies | ||
2911 | * macros. | ||
2912 | */ | ||
2913 | static unsigned long bfq_smallest_from_now(void) | ||
2914 | { | ||
2915 | return jiffies - MAX_JIFFY_OFFSET; | ||
2916 | } | ||
2917 | |||
2918 | /** | 2930 | /** |
2919 | * bfq_bfqq_expire - expire a queue. | 2931 | * bfq_bfqq_expire - expire a queue. |
2920 | * @bfqd: device owning the queue. | 2932 | * @bfqd: device owning the queue. |