|
@@ -154,6 +154,8 @@ struct cfq_queue {
|
|
|
unsigned long rb_key;
|
|
|
/* prio tree member */
|
|
|
struct rb_node p_node;
|
|
|
+ /* prio tree root we belong to, if any */
|
|
|
+ struct rb_root *p_root;
|
|
|
/* sorted list of pending requests */
|
|
|
struct rb_root sort_list;
|
|
|
/* if fifo isn't expired, next request to serve */
|
|
@@ -558,10 +560,10 @@ static void cfq_service_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq,
|
|
|
}
|
|
|
|
|
|
static struct cfq_queue *
|
|
|
-cfq_prio_tree_lookup(struct cfq_data *cfqd, int ioprio, sector_t sector,
|
|
|
- struct rb_node **ret_parent, struct rb_node ***rb_link)
|
|
|
+cfq_prio_tree_lookup(struct cfq_data *cfqd, struct rb_root *root,
|
|
|
+ sector_t sector, struct rb_node **ret_parent,
|
|
|
+ struct rb_node ***rb_link)
|
|
|
{
|
|
|
- struct rb_root *root = &cfqd->prio_trees[ioprio];
|
|
|
struct rb_node **p, *parent;
|
|
|
struct cfq_queue *cfqq = NULL;
|
|
|
|
|
@@ -584,34 +586,38 @@ cfq_prio_tree_lookup(struct cfq_data *cfqd, int ioprio, sector_t sector,
|
|
|
else
|
|
|
break;
|
|
|
p = n;
|
|
|
+ cfqq = NULL;
|
|
|
}
|
|
|
|
|
|
*ret_parent = parent;
|
|
|
if (rb_link)
|
|
|
*rb_link = p;
|
|
|
- return NULL;
|
|
|
+ return cfqq;
|
|
|
}
|
|
|
|
|
|
static void cfq_prio_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq)
|
|
|
{
|
|
|
- struct rb_root *root = &cfqd->prio_trees[cfqq->ioprio];
|
|
|
struct rb_node **p, *parent;
|
|
|
struct cfq_queue *__cfqq;
|
|
|
|
|
|
- if (!RB_EMPTY_NODE(&cfqq->p_node))
|
|
|
- rb_erase_init(&cfqq->p_node, root);
|
|
|
+ if (cfqq->p_root) {
|
|
|
+ rb_erase(&cfqq->p_node, cfqq->p_root);
|
|
|
+ cfqq->p_root = NULL;
|
|
|
+ }
|
|
|
|
|
|
if (cfq_class_idle(cfqq))
|
|
|
return;
|
|
|
if (!cfqq->next_rq)
|
|
|
return;
|
|
|
|
|
|
- __cfqq = cfq_prio_tree_lookup(cfqd, cfqq->ioprio, cfqq->next_rq->sector,
|
|
|
+ cfqq->p_root = &cfqd->prio_trees[cfqq->org_ioprio];
|
|
|
+ __cfqq = cfq_prio_tree_lookup(cfqd, cfqq->p_root, cfqq->next_rq->sector,
|
|
|
&parent, &p);
|
|
|
- BUG_ON(__cfqq);
|
|
|
-
|
|
|
- rb_link_node(&cfqq->p_node, parent, p);
|
|
|
- rb_insert_color(&cfqq->p_node, root);
|
|
|
+ if (!__cfqq) {
|
|
|
+ rb_link_node(&cfqq->p_node, parent, p);
|
|
|
+ rb_insert_color(&cfqq->p_node, cfqq->p_root);
|
|
|
+ } else
|
|
|
+ cfqq->p_root = NULL;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -656,8 +662,10 @@ static void cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
|
|
|
|
|
|
if (!RB_EMPTY_NODE(&cfqq->rb_node))
|
|
|
cfq_rb_erase(&cfqq->rb_node, &cfqd->service_tree);
|
|
|
- if (!RB_EMPTY_NODE(&cfqq->p_node))
|
|
|
- rb_erase_init(&cfqq->p_node, &cfqd->prio_trees[cfqq->ioprio]);
|
|
|
+ if (cfqq->p_root) {
|
|
|
+ rb_erase(&cfqq->p_node, cfqq->p_root);
|
|
|
+ cfqq->p_root = NULL;
|
|
|
+ }
|
|
|
|
|
|
BUG_ON(!cfqd->busy_queues);
|
|
|
cfqd->busy_queues--;
|
|
@@ -947,20 +955,24 @@ static inline sector_t cfq_dist_from_last(struct cfq_data *cfqd,
|
|
|
return cfqd->last_position - rq->sector;
|
|
|
}
|
|
|
|
|
|
+#define CIC_SEEK_THR 8 * 1024
|
|
|
+#define CIC_SEEKY(cic) ((cic)->seek_mean > CIC_SEEK_THR)
|
|
|
+
|
|
|
static inline int cfq_rq_close(struct cfq_data *cfqd, struct request *rq)
|
|
|
{
|
|
|
struct cfq_io_context *cic = cfqd->active_cic;
|
|
|
+ sector_t sdist = cic->seek_mean;
|
|
|
|
|
|
if (!sample_valid(cic->seek_samples))
|
|
|
- return 0;
|
|
|
+ sdist = CIC_SEEK_THR;
|
|
|
|
|
|
- return cfq_dist_from_last(cfqd, rq) <= cic->seek_mean;
|
|
|
+ return cfq_dist_from_last(cfqd, rq) <= sdist;
|
|
|
}
|
|
|
|
|
|
static struct cfq_queue *cfqq_close(struct cfq_data *cfqd,
|
|
|
struct cfq_queue *cur_cfqq)
|
|
|
{
|
|
|
- struct rb_root *root = &cfqd->prio_trees[cur_cfqq->ioprio];
|
|
|
+ struct rb_root *root = &cfqd->prio_trees[cur_cfqq->org_ioprio];
|
|
|
struct rb_node *parent, *node;
|
|
|
struct cfq_queue *__cfqq;
|
|
|
sector_t sector = cfqd->last_position;
|
|
@@ -972,8 +984,7 @@ static struct cfq_queue *cfqq_close(struct cfq_data *cfqd,
|
|
|
* First, if we find a request starting at the end of the last
|
|
|
* request, choose it.
|
|
|
*/
|
|
|
- __cfqq = cfq_prio_tree_lookup(cfqd, cur_cfqq->ioprio,
|
|
|
- sector, &parent, NULL);
|
|
|
+ __cfqq = cfq_prio_tree_lookup(cfqd, root, sector, &parent, NULL);
|
|
|
if (__cfqq)
|
|
|
return __cfqq;
|
|
|
|
|
@@ -1039,9 +1050,6 @@ static struct cfq_queue *cfq_close_cooperator(struct cfq_data *cfqd,
|
|
|
return cfqq;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-#define CIC_SEEKY(cic) ((cic)->seek_mean > (8 * 1024))
|
|
|
-
|
|
|
static void cfq_arm_slice_timer(struct cfq_data *cfqd)
|
|
|
{
|
|
|
struct cfq_queue *cfqq = cfqd->active_queue;
|
|
@@ -1908,7 +1916,9 @@ cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic,
|
|
|
sector_t sdist;
|
|
|
u64 total;
|
|
|
|
|
|
- if (cic->last_request_pos < rq->sector)
|
|
|
+ if (!cic->last_request_pos)
|
|
|
+ sdist = 0;
|
|
|
+ else if (cic->last_request_pos < rq->sector)
|
|
|
sdist = rq->sector - cic->last_request_pos;
|
|
|
else
|
|
|
sdist = cic->last_request_pos - rq->sector;
|
|
@@ -2443,12 +2453,22 @@ static void cfq_exit_queue(struct elevator_queue *e)
|
|
|
static void *cfq_init_queue(struct request_queue *q)
|
|
|
{
|
|
|
struct cfq_data *cfqd;
|
|
|
+ int i;
|
|
|
|
|
|
cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL | __GFP_ZERO, q->node);
|
|
|
if (!cfqd)
|
|
|
return NULL;
|
|
|
|
|
|
cfqd->service_tree = CFQ_RB_ROOT;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Not strictly needed (since RB_ROOT just clears the node and we
|
|
|
+ * zeroed cfqd on alloc), but better be safe in case someone decides
|
|
|
+ * to add magic to the rb code
|
|
|
+ */
|
|
|
+ for (i = 0; i < CFQ_PRIO_LISTS; i++)
|
|
|
+ cfqd->prio_trees[i] = RB_ROOT;
|
|
|
+
|
|
|
INIT_LIST_HEAD(&cfqd->cic_list);
|
|
|
|
|
|
cfqd->queue = q;
|