|
@@ -1160,6 +1160,34 @@ static struct cfq_queue *cfq_close_cooperator(struct cfq_data *cfqd,
|
|
|
return cfqq;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Determine whether we should enforce idle window for this queue.
|
|
|
+ */
|
|
|
+
|
|
|
+static bool cfq_should_idle(struct cfq_data *cfqd, struct cfq_queue *cfqq)
|
|
|
+{
|
|
|
+ enum wl_prio_t prio = cfqq_prio(cfqq);
|
|
|
+ struct cfq_rb_root *service_tree;
|
|
|
+
|
|
|
+ /* We never do for idle class queues. */
|
|
|
+ if (prio == IDLE_WORKLOAD)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /* We do for queues that were marked with idle window flag. */
|
|
|
+ if (cfq_cfqq_idle_window(cfqq))
|
|
|
+ return true;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Otherwise, we do only if they are the last ones
|
|
|
+ * in their service tree.
|
|
|
+ */
|
|
|
+ service_tree = service_tree_for(prio, cfqd);
|
|
|
+ if (service_tree->count == 0)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ return (service_tree->count == 1 && cfq_rb_first(service_tree) == cfqq);
|
|
|
+}
|
|
|
+
|
|
|
static void cfq_arm_slice_timer(struct cfq_data *cfqd)
|
|
|
{
|
|
|
struct cfq_queue *cfqq = cfqd->active_queue;
|
|
@@ -1180,7 +1208,7 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd)
|
|
|
/*
|
|
|
* idle is disabled, either manually or by past process history
|
|
|
*/
|
|
|
- if (!cfqd->cfq_slice_idle || !cfq_cfqq_idle_window(cfqq))
|
|
|
+ if (!cfqd->cfq_slice_idle || !cfq_should_idle(cfqd, cfqq))
|
|
|
return;
|
|
|
|
|
|
/*
|
|
@@ -1362,7 +1390,7 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
|
|
|
* conditions to happen (or time out) before selecting a new queue.
|
|
|
*/
|
|
|
if (timer_pending(&cfqd->idle_slice_timer) ||
|
|
|
- (cfqq->dispatched && cfq_cfqq_idle_window(cfqq))) {
|
|
|
+ (cfqq->dispatched && cfq_should_idle(cfqd, cfqq))) {
|
|
|
cfqq = NULL;
|
|
|
goto keep_queue;
|
|
|
}
|
|
@@ -1427,7 +1455,7 @@ static bool cfq_may_dispatch(struct cfq_data *cfqd, struct cfq_queue *cfqq)
|
|
|
/*
|
|
|
* Drain async requests before we start sync IO
|
|
|
*/
|
|
|
- if (cfq_cfqq_idle_window(cfqq) && cfqd->rq_in_driver[BLK_RW_ASYNC])
|
|
|
+ if (cfq_should_idle(cfqd, cfqq) && cfqd->rq_in_driver[BLK_RW_ASYNC])
|
|
|
return false;
|
|
|
|
|
|
/*
|