]> err.no Git - linux-2.6/blobdiff - block/cfq-iosched.c
Pull bugzilla-5764 into release branch
[linux-2.6] / block / cfq-iosched.c
index 93ba54605eda98c9c62657e3e461526c34a31a61..052b17487625f0edf905feb1beadaec7c8e5fa96 100644 (file)
@@ -133,6 +133,7 @@ struct cfq_data {
        mempool_t *crq_pool;
 
        int rq_in_driver;
+       int hw_tag;
 
        /*
         * schedule slice state info
@@ -500,10 +501,13 @@ static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted)
 
        /*
         * if queue was preempted, just add to front to be fair. busy_rr
-        * isn't sorted.
+        * isn't sorted, but insert at the back for fairness.
         */
        if (preempted || list == &cfqd->busy_rr) {
-               list_add(&cfqq->cfq_list, list);
+               if (preempted)
+                       list = list->prev;
+
+               list_add_tail(&cfqq->cfq_list, list);
                return;
        }
 
@@ -664,6 +668,15 @@ static void cfq_activate_request(request_queue_t *q, struct request *rq)
        struct cfq_data *cfqd = q->elevator->elevator_data;
 
        cfqd->rq_in_driver++;
+
+       /*
+        * If the depth is larger 1, it really could be queueing. But lets
+        * make the mark a little higher - idling could still be good for
+        * low queueing, and a low queueing number could also just indicate
+        * a SCSI mid layer like behaviour where limit+1 is often seen.
+        */
+       if (!cfqd->hw_tag && cfqd->rq_in_driver > 4)
+               cfqd->hw_tag = 1;
 }
 
 static void cfq_deactivate_request(request_queue_t *q, struct request *rq)
@@ -1310,17 +1323,12 @@ cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
        struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_mask);
 
        if (cic) {
-               RB_CLEAR(&cic->rb_node);
-               cic->key = NULL;
-               cic->cfqq[ASYNC] = NULL;
-               cic->cfqq[SYNC] = NULL;
+               memset(cic, 0, sizeof(*cic));
+               RB_CLEAR_COLOR(&cic->rb_node);
                cic->last_end_request = jiffies;
-               cic->ttime_total = 0;
-               cic->ttime_samples = 0;
-               cic->ttime_mean = 0;
+               INIT_LIST_HEAD(&cic->queue_list);
                cic->dtor = cfq_free_io_context;
                cic->exit = cfq_exit_io_context;
-               INIT_LIST_HEAD(&cic->queue_list);
                atomic_inc(&ioc_count);
        }
 
@@ -1465,7 +1473,8 @@ retry:
                 * set ->slice_left to allow preemption for a new process
                 */
                cfqq->slice_left = 2 * cfqd->cfq_slice_idle;
-               cfq_mark_cfqq_idle_window(cfqq);
+               if (!cfqd->hw_tag)
+                       cfq_mark_cfqq_idle_window(cfqq);
                cfq_mark_cfqq_prio_changed(cfqq);
                cfq_init_prio_data(cfqq);
        }
@@ -1656,7 +1665,7 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
 {
        int enable_idle = cfq_cfqq_idle_window(cfqq);
 
-       if (!cic->ioc->task || !cfqd->cfq_slice_idle)
+       if (!cic->ioc->task || !cfqd->cfq_slice_idle || cfqd->hw_tag)
                enable_idle = 0;
        else if (sample_valid(cic->ttime_samples)) {
                if (cic->ttime_mean > cfqd->cfq_slice_idle)
@@ -2182,10 +2191,9 @@ static void cfq_idle_class_timer(unsigned long data)
         * race with a non-idle queue, reset timer
         */
        end = cfqd->last_end_request + CFQ_IDLE_GRACE;
-       if (!time_after_eq(jiffies, end)) {
-               cfqd->idle_class_timer.expires = end;
-               add_timer(&cfqd->idle_class_timer);
-       } else
+       if (!time_after_eq(jiffies, end))
+               mod_timer(&cfqd->idle_class_timer, end);
+       else
                cfq_schedule_dispatch(cfqd);
 
        spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
@@ -2238,14 +2246,14 @@ static void cfq_exit_queue(elevator_t *e)
        kfree(cfqd);
 }
 
-static int cfq_init_queue(request_queue_t *q, elevator_t *e)
+static void *cfq_init_queue(request_queue_t *q, elevator_t *e)
 {
        struct cfq_data *cfqd;
        int i;
 
        cfqd = kmalloc(sizeof(*cfqd), GFP_KERNEL);
        if (!cfqd)
-               return -ENOMEM;
+               return NULL;
 
        memset(cfqd, 0, sizeof(*cfqd));
 
@@ -2275,8 +2283,6 @@ static int cfq_init_queue(request_queue_t *q, elevator_t *e)
        for (i = 0; i < CFQ_QHASH_ENTRIES; i++)
                INIT_HLIST_HEAD(&cfqd->cfq_hash[i]);
 
-       e->elevator_data = cfqd;
-
        cfqd->queue = q;
 
        cfqd->max_queued = q->nr_requests / 4;
@@ -2303,14 +2309,14 @@ static int cfq_init_queue(request_queue_t *q, elevator_t *e)
        cfqd->cfq_slice_async_rq = cfq_slice_async_rq;
        cfqd->cfq_slice_idle = cfq_slice_idle;
 
-       return 0;
+       return cfqd;
 out_crqpool:
        kfree(cfqd->cfq_hash);
 out_cfqhash:
        kfree(cfqd->crq_hash);
 out_crqhash:
        kfree(cfqd);
-       return -ENOMEM;
+       return NULL;
 }
 
 static void cfq_slab_kill(void)