Merge tag 'sound-4.15-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / block / bfq-iosched.c
index a4783da90ba882f29ac1159b67dc1b24296ead5b..889a8549d97f35e36718a9a552cda1faea71e6e2 100644 (file)
 #include "blk-mq-tag.h"
 #include "blk-mq-sched.h"
 #include "bfq-iosched.h"
+#include "blk-wbt.h"
 
 #define BFQ_BFQQ_FNS(name)                                             \
 void bfq_mark_bfqq_##name(struct bfq_queue *bfqq)                      \
@@ -724,6 +725,44 @@ static void bfq_updated_next_req(struct bfq_data *bfqd,
        }
 }
 
+static unsigned int bfq_wr_duration(struct bfq_data *bfqd)
+{
+       u64 dur;
+
+       if (bfqd->bfq_wr_max_time > 0)
+               return bfqd->bfq_wr_max_time;
+
+       dur = bfqd->RT_prod;
+       do_div(dur, bfqd->peak_rate);
+
+       /*
+        * Limit duration between 3 and 13 seconds. Tests show that
+        * higher values than 13 seconds often yield the opposite of
+        * the desired result, i.e., worsen responsiveness by letting
+        * non-interactive and non-soft-real-time applications
+        * preserve weight raising for a too long time interval.
+        *
+        * On the other end, lower values than 3 seconds make it
+        * difficult for most interactive tasks to complete their jobs
+        * before weight-raising finishes.
+        */
+       if (dur > msecs_to_jiffies(13000))
+               dur = msecs_to_jiffies(13000);
+       else if (dur < msecs_to_jiffies(3000))
+               dur = msecs_to_jiffies(3000);
+
+       return dur;
+}
+
+/* switch back from soft real-time to interactive weight raising */
+static void switch_back_to_interactive_wr(struct bfq_queue *bfqq,
+                                         struct bfq_data *bfqd)
+{
+       bfqq->wr_coeff = bfqd->bfq_wr_coeff;
+       bfqq->wr_cur_max_time = bfq_wr_duration(bfqd);
+       bfqq->last_wr_start_finish = bfqq->wr_start_at_switch_to_srt;
+}
+
 static void
 bfq_bfqq_resume_state(struct bfq_queue *bfqq, struct bfq_data *bfqd,
                      struct bfq_io_cq *bic, bool bfq_already_existing)
@@ -750,10 +789,16 @@ bfq_bfqq_resume_state(struct bfq_queue *bfqq, struct bfq_data *bfqd,
        if (bfqq->wr_coeff > 1 && (bfq_bfqq_in_large_burst(bfqq) ||
            time_is_before_jiffies(bfqq->last_wr_start_finish +
                                   bfqq->wr_cur_max_time))) {
-               bfq_log_bfqq(bfqq->bfqd, bfqq,
-                   "resume state: switching off wr");
-
-               bfqq->wr_coeff = 1;
+               if (bfqq->wr_cur_max_time == bfqd->bfq_wr_rt_max_time &&
+                   !bfq_bfqq_in_large_burst(bfqq) &&
+                   time_is_after_eq_jiffies(bfqq->wr_start_at_switch_to_srt +
+                                            bfq_wr_duration(bfqd))) {
+                       switch_back_to_interactive_wr(bfqq, bfqd);
+               } else {
+                       bfqq->wr_coeff = 1;
+                       bfq_log_bfqq(bfqq->bfqd, bfqq,
+                                    "resume state: switching off wr");
+               }
        }
 
        /* make sure weight will be updated, however we got here */
@@ -1173,33 +1218,22 @@ static bool bfq_bfqq_update_budg_for_activation(struct bfq_data *bfqd,
        return wr_or_deserves_wr;
 }
 
-static unsigned int bfq_wr_duration(struct bfq_data *bfqd)
+/*
+ * Return the farthest future time instant according to jiffies
+ * macros.
+ */
+static unsigned long bfq_greatest_from_now(void)
 {
-       u64 dur;
-
-       if (bfqd->bfq_wr_max_time > 0)
-               return bfqd->bfq_wr_max_time;
-
-       dur = bfqd->RT_prod;
-       do_div(dur, bfqd->peak_rate);
-
-       /*
-        * Limit duration between 3 and 13 seconds. Tests show that
-        * higher values than 13 seconds often yield the opposite of
-        * the desired result, i.e., worsen responsiveness by letting
-        * non-interactive and non-soft-real-time applications
-        * preserve weight raising for a too long time interval.
-        *
-        * On the other end, lower values than 3 seconds make it
-        * difficult for most interactive tasks to complete their jobs
-        * before weight-raising finishes.
-        */
-       if (dur > msecs_to_jiffies(13000))
-               dur = msecs_to_jiffies(13000);
-       else if (dur < msecs_to_jiffies(3000))
-               dur = msecs_to_jiffies(3000);
+       return jiffies + MAX_JIFFY_OFFSET;
+}
 
-       return dur;
+/*
+ * Return the farthest past time instant according to jiffies
+ * macros.
+ */
+static unsigned long bfq_smallest_from_now(void)
+{
+       return jiffies - MAX_JIFFY_OFFSET;
 }
 
 static void bfq_update_bfqq_wr_on_rq_arrival(struct bfq_data *bfqd,
@@ -1216,7 +1250,19 @@ static void bfq_update_bfqq_wr_on_rq_arrival(struct bfq_data *bfqd,
                        bfqq->wr_coeff = bfqd->bfq_wr_coeff;
                        bfqq->wr_cur_max_time = bfq_wr_duration(bfqd);
                } else {
-                       bfqq->wr_start_at_switch_to_srt = jiffies;
+                       /*
+                        * No interactive weight raising in progress
+                        * here: assign minus infinity to
+                        * wr_start_at_switch_to_srt, to make sure
+                        * that, at the end of the soft-real-time
+                        * weight raising periods that is starting
+                        * now, no interactive weight-raising period
+                        * may be wrongly considered as still in
+                        * progress (and thus actually started by
+                        * mistake).
+                        */
+                       bfqq->wr_start_at_switch_to_srt =
+                               bfq_smallest_from_now();
                        bfqq->wr_coeff = bfqd->bfq_wr_coeff *
                                BFQ_SOFTRT_WEIGHT_FACTOR;
                        bfqq->wr_cur_max_time =
@@ -2016,10 +2062,27 @@ static void bfq_bfqq_save_state(struct bfq_queue *bfqq)
        bic->saved_IO_bound = bfq_bfqq_IO_bound(bfqq);
        bic->saved_in_large_burst = bfq_bfqq_in_large_burst(bfqq);
        bic->was_in_burst_list = !hlist_unhashed(&bfqq->burst_list_node);
-       bic->saved_wr_coeff = bfqq->wr_coeff;
-       bic->saved_wr_start_at_switch_to_srt = bfqq->wr_start_at_switch_to_srt;
-       bic->saved_last_wr_start_finish = bfqq->last_wr_start_finish;
-       bic->saved_wr_cur_max_time = bfqq->wr_cur_max_time;
+       if (unlikely(bfq_bfqq_just_created(bfqq) &&
+                    !bfq_bfqq_in_large_burst(bfqq))) {
+               /*
+                * bfqq being merged right after being created: bfqq
+                * would have deserved interactive weight raising, but
+                * did not make it to be set in a weight-raised state,
+                * because of this early merge. Store directly the
+                * weight-raising state that would have been assigned
+                * to bfqq, so that to avoid that bfqq unjustly fails
+                * to enjoy weight raising if split soon.
+                */
+               bic->saved_wr_coeff = bfqq->bfqd->bfq_wr_coeff;
+               bic->saved_wr_cur_max_time = bfq_wr_duration(bfqq->bfqd);
+               bic->saved_last_wr_start_finish = jiffies;
+       } else {
+               bic->saved_wr_coeff = bfqq->wr_coeff;
+               bic->saved_wr_start_at_switch_to_srt =
+                       bfqq->wr_start_at_switch_to_srt;
+               bic->saved_last_wr_start_finish = bfqq->last_wr_start_finish;
+               bic->saved_wr_cur_max_time = bfqq->wr_cur_max_time;
+       }
 }
 
 static void
@@ -2897,24 +2960,6 @@ static unsigned long bfq_bfqq_softrt_next_start(struct bfq_data *bfqd,
                   jiffies + nsecs_to_jiffies(bfqq->bfqd->bfq_slice_idle) + 4);
 }
 
-/*
- * Return the farthest future time instant according to jiffies
- * macros.
- */
-static unsigned long bfq_greatest_from_now(void)
-{
-       return jiffies + MAX_JIFFY_OFFSET;
-}
-
-/*
- * Return the farthest past time instant according to jiffies
- * macros.
- */
-static unsigned long bfq_smallest_from_now(void)
-{
-       return jiffies - MAX_JIFFY_OFFSET;
-}
-
 /**
  * bfq_bfqq_expire - expire a queue.
  * @bfqd: device owning the queue.
@@ -3489,11 +3534,7 @@ static void bfq_update_wr_data(struct bfq_data *bfqd, struct bfq_queue *bfqq)
                                               bfq_wr_duration(bfqd)))
                                bfq_bfqq_end_wr(bfqq);
                        else {
-                               /* switch back to interactive wr */
-                               bfqq->wr_coeff = bfqd->bfq_wr_coeff;
-                               bfqq->wr_cur_max_time = bfq_wr_duration(bfqd);
-                               bfqq->last_wr_start_finish =
-                                       bfqq->wr_start_at_switch_to_srt;
+                               switch_back_to_interactive_wr(bfqq, bfqd);
                                bfqq->entity.prio_changed = 1;
                        }
                }
@@ -3685,16 +3726,37 @@ void bfq_put_queue(struct bfq_queue *bfqq)
        if (bfqq->ref)
                return;
 
-       if (bfq_bfqq_sync(bfqq))
+       if (!hlist_unhashed(&bfqq->burst_list_node)) {
+               hlist_del_init(&bfqq->burst_list_node);
                /*
-                * The fact that this queue is being destroyed does not
-                * invalidate the fact that this queue may have been
-                * activated during the current burst. As a consequence,
-                * although the queue does not exist anymore, and hence
-                * needs to be removed from the burst list if there,
-                * the burst size has not to be decremented.
+                * Decrement also burst size after the removal, if the
+                * process associated with bfqq is exiting, and thus
+                * does not contribute to the burst any longer. This
+                * decrement helps filter out false positives of large
+                * bursts, when some short-lived process (often due to
+                * the execution of commands by some service) happens
+                * to start and exit while a complex application is
+                * starting, and thus spawning several processes that
+                * do I/O (and that *must not* be treated as a large
+                * burst, see comments on bfq_handle_burst).
+                *
+                * In particular, the decrement is performed only if:
+                * 1) bfqq is not a merged queue, because, if it is,
+                * then this free of bfqq is not triggered by the exit
+                * of the process bfqq is associated with, but exactly
+                * by the fact that bfqq has just been merged.
+                * 2) burst_size is greater than 0, to handle
+                * unbalanced decrements. Unbalanced decrements may
+                * happen in te following case: bfqq is inserted into
+                * the current burst list--without incrementing
+                * bust_size--because of a split, but the current
+                * burst list is not the burst list bfqq belonged to
+                * (see comments on the case of a split in
+                * bfq_set_request).
                 */
-               hlist_del_init(&bfqq->burst_list_node);
+               if (bfqq->bic && bfqq->bfqd->burst_size > 0)
+                       bfqq->bfqd->burst_size--;
+       }
 
        kmem_cache_free(bfq_pool, bfqq);
 #ifdef CONFIG_BFQ_GROUP_IOSCHED
@@ -4127,7 +4189,6 @@ static void __bfq_insert_request(struct bfq_data *bfqd, struct request *rq)
                new_bfqq->allocated++;
                bfqq->allocated--;
                new_bfqq->ref++;
-               bfq_clear_bfqq_just_created(bfqq);
                /*
                 * If the bic associated with the process
                 * issuing this request still points to bfqq
@@ -4139,6 +4200,8 @@ static void __bfq_insert_request(struct bfq_data *bfqd, struct request *rq)
                if (bic_to_bfqq(RQ_BIC(rq), 1) == bfqq)
                        bfq_merge_bfqqs(bfqd, RQ_BIC(rq),
                                        bfqq, new_bfqq);
+
+               bfq_clear_bfqq_just_created(bfqq);
                /*
                 * rq is about to be enqueued into new_bfqq,
                 * release rq reference on bfqq
@@ -4424,6 +4487,34 @@ static struct bfq_queue *bfq_get_bfqq_handle_split(struct bfq_data *bfqd,
                else {
                        bfq_clear_bfqq_in_large_burst(bfqq);
                        if (bic->was_in_burst_list)
+                               /*
+                                * If bfqq was in the current
+                                * burst list before being
+                                * merged, then we have to add
+                                * it back. And we do not need
+                                * to increase burst_size, as
+                                * we did not decrement
+                                * burst_size when we removed
+                                * bfqq from the burst list as
+                                * a consequence of a merge
+                                * (see comments in
+                                * bfq_put_queue). In this
+                                * respect, it would be rather
+                                * costly to know whether the
+                                * current burst list is still
+                                * the same burst list from
+                                * which bfqq was removed on
+                                * the merge. To avoid this
+                                * cost, if bfqq was in a
+                                * burst list, then we add
+                                * bfqq to the current burst
+                                * list without any further
+                                * check. This can cause
+                                * inappropriate insertions,
+                                * but rarely enough to not
+                                * harm the detection of large
+                                * bursts significantly.
+                                */
                                hlist_add_head(&bfqq->burst_list_node,
                                               &bfqd->burst_list);
                }
@@ -4775,7 +4866,7 @@ static int bfq_init_queue(struct request_queue *q, struct elevator_type *e)
        bfq_init_root_group(bfqd->root_group, bfqd);
        bfq_init_entity(&bfqd->oom_bfqq.entity, bfqd->root_group);
 
-
+       wbt_disable_default(q);
        return 0;
 
 out_free: