summaryrefslogtreecommitdiffstats
path: root/block/bfq-iosched.c
diff options
context:
space:
mode:
authorPaolo Valente <paolo.valente@linaro.org>2017-09-21 05:04:00 -0400
committerJens Axboe <axboe@kernel.dk>2017-10-03 10:40:54 -0400
commit4baa8bb13f41307f3eb62fe91f93a1a798ebef53 (patch)
tree499e78fa5e8deb43e51b52f21d180e8021d4aad8 /block/bfq-iosched.c
parentaac8d41cd438f25bf3110fc6b98f1d16d7dbc169 (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.c50
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 */
1209static 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 */
1218static unsigned long bfq_smallest_from_now(void)
1219{
1220 return jiffies - MAX_JIFFY_OFFSET;
1221}
1222
1205static void bfq_update_bfqq_wr_on_rq_arrival(struct bfq_data *bfqd, 1223static 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 */
2904static 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 */
2913static 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.