|
@@ -1795,3 +1795,85 @@ static void cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
|
|
cfq_rb_erase(&cfqq->rb_node, cfqq->service_tree);
|
|
cfq_rb_erase(&cfqq->rb_node, cfqq->service_tree);
|
|
cfqq->service_tree = NULL;
|
|
cfqq->service_tree = NULL;
|
|
}
|
|
}
|
|
|
|
+ if (cfqq->p_root) {
|
|
|
|
+ rb_erase(&cfqq->p_node, cfqq->p_root);
|
|
|
|
+ cfqq->p_root = NULL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ cfq_group_notify_queue_del(cfqd, cfqq->cfqg);
|
|
|
|
+ BUG_ON(!cfqd->busy_queues);
|
|
|
|
+ cfqd->busy_queues--;
|
|
|
|
+ if (cfq_cfqq_sync(cfqq))
|
|
|
|
+ cfqd->busy_sync_queues--;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * rb tree support functions
|
|
|
|
+ */
|
|
|
|
+static void cfq_del_rq_rb(struct request *rq)
|
|
|
|
+{
|
|
|
|
+ struct cfq_queue *cfqq = RQ_CFQQ(rq);
|
|
|
|
+ const int sync = rq_is_sync(rq);
|
|
|
|
+
|
|
|
|
+ BUG_ON(!cfqq->queued[sync]);
|
|
|
|
+ cfqq->queued[sync]--;
|
|
|
|
+
|
|
|
|
+ elv_rb_del(&cfqq->sort_list, rq);
|
|
|
|
+
|
|
|
|
+ if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY_ROOT(&cfqq->sort_list)) {
|
|
|
|
+ /*
|
|
|
|
+ * Queue will be deleted from service tree when we actually
|
|
|
|
+ * expire it later. Right now just remove it from prio tree
|
|
|
|
+ * as it is empty.
|
|
|
|
+ */
|
|
|
|
+ if (cfqq->p_root) {
|
|
|
|
+ rb_erase(&cfqq->p_node, cfqq->p_root);
|
|
|
|
+ cfqq->p_root = NULL;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void cfq_add_rq_rb(struct request *rq)
|
|
|
|
+{
|
|
|
|
+ struct cfq_queue *cfqq = RQ_CFQQ(rq);
|
|
|
|
+ struct cfq_data *cfqd = cfqq->cfqd;
|
|
|
|
+ struct request *prev;
|
|
|
|
+
|
|
|
|
+ cfqq->queued[rq_is_sync(rq)]++;
|
|
|
|
+
|
|
|
|
+ elv_rb_add(&cfqq->sort_list, rq);
|
|
|
|
+
|
|
|
|
+ if (!cfq_cfqq_on_rr(cfqq))
|
|
|
|
+ cfq_add_cfqq_rr(cfqd, cfqq);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * check if this request is a better next-serve candidate
|
|
|
|
+ */
|
|
|
|
+ prev = cfqq->next_rq;
|
|
|
|
+ cfqq->next_rq = cfq_choose_req(cfqd, cfqq->next_rq, rq, cfqd->last_position);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * adjust priority tree position, if ->next_rq changes
|
|
|
|
+ */
|
|
|
|
+ if (prev != cfqq->next_rq)
|
|
|
|
+ cfq_prio_tree_add(cfqd, cfqq);
|
|
|
|
+
|
|
|
|
+ BUG_ON(!cfqq->next_rq);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void cfq_reposition_rq_rb(struct cfq_queue *cfqq, struct request *rq)
|
|
|
|
+{
|
|
|
|
+ elv_rb_del(&cfqq->sort_list, rq);
|
|
|
|
+ cfqq->queued[rq_is_sync(rq)]--;
|
|
|
|
+ cfqg_stats_update_io_remove(RQ_CFQG(rq), rq->cmd_flags);
|
|
|
|
+ cfq_add_rq_rb(rq);
|
|
|
|
+ cfqg_stats_update_io_add(RQ_CFQG(rq), cfqq->cfqd->serving_group,
|
|
|
|
+ rq->cmd_flags);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static struct request *
|
|
|
|
+cfq_find_rq_fmerge(struct cfq_data *cfqd, struct bio *bio)
|
|
|
|
+{
|
|
|
|
+ struct task_struct *tsk = current;
|
|
|
|
+ struct cfq_io_cq *cic;
|
|
|
|
+ struct cfq_queue *cfqq;
|