Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/anholt...
[safe/jmp/linux-2.6] / block / cfq-iosched.c
index 0d3b70d..a55a9bd 100644 (file)
@@ -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;