[PATCH] knfsd: nfsd4: make verify and nverify wrappers
[safe/jmp/linux-2.6] / block / cfq-iosched.c
index c6e649f..78c6b31 100644 (file)
@@ -4,7 +4,7 @@
  *  Based on ideas from a previously unfinished io
  *  scheduler (round robin per-process disk scheduling) and Andrea Arcangeli.
  *
- *  Copyright (C) 2003 Jens Axboe <axboe@suse.de>
+ *  Copyright (C) 2003 Jens Axboe <axboe@kernel.dk>
  */
 #include <linux/module.h>
 #include <linux/blkdev.h>
@@ -43,8 +43,8 @@ static int cfq_slice_idle = HZ / 125;
 #define RQ_CIC(rq)             ((struct cfq_io_context*)(rq)->elevator_private)
 #define RQ_CFQQ(rq)            ((rq)->elevator_private2)
 
-static kmem_cache_t *cfq_pool;
-static kmem_cache_t *cfq_ioc_pool;
+static struct kmem_cache *cfq_pool;
+static struct kmem_cache *cfq_ioc_pool;
 
 static DEFINE_PER_CPU(unsigned long, ioc_count);
 static struct completion *ioc_gone;
@@ -82,11 +82,6 @@ struct cfq_data {
        unsigned int busy_queues;
 
        /*
-        * non-ordered list of empty cfqq's
-        */
-       struct list_head empty_list;
-
-       /*
         * cfqq lookup hash
         */
        struct hlist_head *cfq_hash;
@@ -136,7 +131,7 @@ struct cfq_queue {
        struct hlist_node cfq_hash;
        /* hash key */
        unsigned int key;
-       /* on either rr or empty list of cfqd */
+       /* member of the rr/busy/cur/idle cfqd list */
        struct list_head cfq_list;
        /* sorted list of pending requests */
        struct rb_root sort_list;
@@ -146,6 +141,8 @@ struct cfq_queue {
        int queued[2];
        /* currently allocated requests */
        int allocated[2];
+       /* pending metadata requests */
+       int meta_pending;
        /* fifo list of requests in sort_list */
        struct list_head fifo;
 
@@ -253,6 +250,10 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2)
                return rq1;
        else if (rq_is_sync(rq2) && !rq_is_sync(rq1))
                return rq2;
+       if (rq_is_meta(rq1) && !rq_is_meta(rq2))
+               return rq1;
+       else if (rq_is_meta(rq2) && !rq_is_meta(rq1))
+               return rq2;
 
        s1 = rq1->sector;
        s2 = rq2->sector;
@@ -417,7 +418,7 @@ cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
        BUG_ON(!cfq_cfqq_on_rr(cfqq));
        cfq_clear_cfqq_on_rr(cfqq);
-       list_move(&cfqq->cfq_list, &cfqd->empty_list);
+       list_del_init(&cfqq->cfq_list);
 
        BUG_ON(!cfqd->busy_queues);
        cfqd->busy_queues--;
@@ -455,6 +456,9 @@ static void cfq_add_rq_rb(struct request *rq)
         */
        while ((__alias = elv_rb_add(&cfqq->sort_list, rq)) != NULL)
                cfq_dispatch_insert(cfqd->queue, __alias);
+
+       if (!cfq_cfqq_on_rr(cfqq))
+               cfq_add_cfqq_rr(cfqd, cfqq);
 }
 
 static inline void
@@ -515,6 +519,11 @@ static void cfq_remove_request(struct request *rq)
 
        list_del_init(&rq->queuelist);
        cfq_del_rq_rb(rq);
+
+       if (rq_is_meta(rq)) {
+               WARN_ON(!cfqq->meta_pending);
+               cfqq->meta_pending--;
+       }
 }
 
 static int
@@ -1209,11 +1218,12 @@ static inline void changed_ioprio(struct cfq_io_context *cic)
 {
        struct cfq_data *cfqd = cic->key;
        struct cfq_queue *cfqq;
+       unsigned long flags;
 
        if (unlikely(!cfqd))
                return;
 
-       spin_lock(cfqd->queue->queue_lock);
+       spin_lock_irqsave(cfqd->queue->queue_lock, flags);
 
        cfqq = cic->cfqq[ASYNC];
        if (cfqq) {
@@ -1230,7 +1240,7 @@ static inline void changed_ioprio(struct cfq_io_context *cic)
        if (cfqq)
                cfq_mark_cfqq_prio_changed(cfqq);
 
-       spin_unlock(cfqd->queue->queue_lock);
+       spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
 }
 
 static void cfq_ioc_set_ioprio(struct io_context *ioc)
@@ -1356,6 +1366,7 @@ cfq_cic_link(struct cfq_data *cfqd, struct io_context *ioc,
        struct rb_node **p;
        struct rb_node *parent;
        struct cfq_io_context *__cic;
+       unsigned long flags;
        void *k;
 
        cic->ioc = ioc;
@@ -1385,9 +1396,9 @@ restart:
        rb_link_node(&cic->rb_node, parent, p);
        rb_insert_color(&cic->rb_node, &ioc->cic_root);
 
-       spin_lock_irq(cfqd->queue->queue_lock);
+       spin_lock_irqsave(cfqd->queue->queue_lock, flags);
        list_add(&cic->queue_list, &cfqd->cic_list);
-       spin_unlock_irq(cfqd->queue->queue_lock);
+       spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
 }
 
 /*
@@ -1453,8 +1464,7 @@ cfq_update_io_thinktime(struct cfq_data *cfqd, struct cfq_io_context *cic)
 }
 
 static void
-cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic,
-                      struct request *rq)
+cfq_update_io_seektime(struct cfq_io_context *cic, struct request *rq)
 {
        sector_t sdist;
        u64 total;
@@ -1532,8 +1542,18 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
         */
        if (new_cfqq->slice_left < cfqd->cfq_slice_idle)
                return 0;
+       /*
+        * if the new request is sync, but the currently running queue is
+        * not, let the sync request have priority.
+        */
        if (rq_is_sync(rq) && !cfq_cfqq_sync(cfqq))
                return 1;
+       /*
+        * So both queues are sync. Let the new request get disk time if
+        * it's a metadata request and the current queue is doing regular IO.
+        */
+       if (rq_is_meta(rq) && !cfqq->meta_pending)
+               return 1;
 
        return 0;
 }
@@ -1544,30 +1564,19 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
  */
 static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
-       struct cfq_queue *__cfqq, *next;
-
-       list_for_each_entry_safe(__cfqq, next, &cfqd->cur_rr, cfq_list)
-               cfq_resort_rr_list(__cfqq, 1);
+       cfq_slice_expired(cfqd, 1);
 
        if (!cfqq->slice_left)
                cfqq->slice_left = cfq_prio_to_slice(cfqd, cfqq) / 2;
 
-       cfqq->slice_end = cfqq->slice_left + jiffies;
-       cfq_slice_expired(cfqd, 1);
-       __cfq_set_active_queue(cfqd, cfqq);
-}
-
-/*
- * should really be a ll_rw_blk.c helper
- */
-static void cfq_start_queueing(struct cfq_data *cfqd, struct cfq_queue *cfqq)
-{
-       request_queue_t *q = cfqd->queue;
+       /*
+        * Put the new queue at the front of the of the current list,
+        * so we know that it will be selected next.
+        */
+       BUG_ON(!cfq_cfqq_on_rr(cfqq));
+       list_move(&cfqq->cfq_list, &cfqd->cur_rr);
 
-       if (!blk_queue_plugged(q))
-               q->request_fn(q);
-       else
-               __generic_unplug_device(q);
+       cfqq->slice_end = cfqq->slice_left + jiffies;
 }
 
 /*
@@ -1580,6 +1589,9 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
 {
        struct cfq_io_context *cic = RQ_CIC(rq);
 
+       if (rq_is_meta(rq))
+               cfqq->meta_pending++;
+
        /*
         * check if this request is a better next-serve candidate)) {
         */
@@ -1598,13 +1610,13 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                if (cic == cfqd->active_cic &&
                    del_timer(&cfqd->idle_slice_timer)) {
                        cfq_slice_expired(cfqd, 0);
-                       cfq_start_queueing(cfqd, cfqq);
+                       blk_start_queueing(cfqd->queue);
                }
                return;
        }
 
        cfq_update_io_thinktime(cfqd, cic);
-       cfq_update_io_seektime(cfqd, cic, rq);
+       cfq_update_io_seektime(cic, rq);
        cfq_update_idle_window(cfqd, cfqq, cic);
 
        cic->last_queue = jiffies;
@@ -1619,7 +1631,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                if (cfq_cfqq_wait_request(cfqq)) {
                        cfq_mark_cfqq_must_dispatch(cfqq);
                        del_timer(&cfqd->idle_slice_timer);
-                       cfq_start_queueing(cfqd, cfqq);
+                       blk_start_queueing(cfqd->queue);
                }
        } else if (cfq_should_preempt(cfqd, cfqq, rq)) {
                /*
@@ -1629,7 +1641,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                 */
                cfq_preempt_queue(cfqd, cfqq);
                cfq_mark_cfqq_must_dispatch(cfqq);
-               cfq_start_queueing(cfqd, cfqq);
+               blk_start_queueing(cfqd->queue);
        }
 }
 
@@ -1642,9 +1654,6 @@ static void cfq_insert_request(request_queue_t *q, struct request *rq)
 
        cfq_add_rq_rb(rq);
 
-       if (!cfq_cfqq_on_rr(cfqq))
-               cfq_add_cfqq_rr(cfqd, cfqq);
-
        list_add_tail(&rq->queuelist, &cfqq->fifo);
 
        cfq_rq_enqueued(cfqd, cfqq, rq);
@@ -1760,7 +1769,7 @@ static int cfq_may_queue(request_queue_t *q, int rw)
 /*
  * queue lock held here
  */
-static void cfq_put_request(request_queue_t *q, struct request *rq)
+static void cfq_put_request(struct request *rq)
 {
        struct cfq_queue *cfqq = RQ_CFQQ(rq);
 
@@ -1831,14 +1840,15 @@ queue_fail:
        return 1;
 }
 
-static void cfq_kick_queue(void *data)
+static void cfq_kick_queue(struct work_struct *work)
 {
-       request_queue_t *q = data;
+       struct cfq_data *cfqd =
+               container_of(work, struct cfq_data, unplug_work);
+       request_queue_t *q = cfqd->queue;
        unsigned long flags;
 
        spin_lock_irqsave(q->queue_lock, flags);
-       blk_remove_plug(q);
-       q->request_fn(q);
+       blk_start_queueing(q);
        spin_unlock_irqrestore(q->queue_lock, flags);
 }
 
@@ -1942,7 +1952,7 @@ static void cfq_exit_queue(elevator_t *e)
        kfree(cfqd);
 }
 
-static void *cfq_init_queue(request_queue_t *q, elevator_t *e)
+static void *cfq_init_queue(request_queue_t *q)
 {
        struct cfq_data *cfqd;
        int i;
@@ -1959,7 +1969,6 @@ static void *cfq_init_queue(request_queue_t *q, elevator_t *e)
        INIT_LIST_HEAD(&cfqd->busy_rr);
        INIT_LIST_HEAD(&cfqd->cur_rr);
        INIT_LIST_HEAD(&cfqd->idle_rr);
-       INIT_LIST_HEAD(&cfqd->empty_list);
        INIT_LIST_HEAD(&cfqd->cic_list);
 
        cfqd->cfq_hash = kmalloc_node(sizeof(struct hlist_head) * CFQ_QHASH_ENTRIES, GFP_KERNEL, q->node);
@@ -1979,7 +1988,7 @@ static void *cfq_init_queue(request_queue_t *q, elevator_t *e)
        cfqd->idle_class_timer.function = cfq_idle_class_timer;
        cfqd->idle_class_timer.data = (unsigned long) cfqd;
 
-       INIT_WORK(&cfqd->unplug_work, cfq_kick_queue, q);
+       INIT_WORK(&cfqd->unplug_work, cfq_kick_queue);
 
        cfqd->cfq_quantum = cfq_quantum;
        cfqd->cfq_fifo_expire[0] = cfq_fifo_expire[0];
@@ -2154,7 +2163,7 @@ static int __init cfq_init(void)
 
 static void __exit cfq_exit(void)
 {
-       DECLARE_COMPLETION(all_gone);
+       DECLARE_COMPLETION_ONSTACK(all_gone);
        elv_unregister(&iosched_cfq);
        ioc_gone = &all_gone;
        /* ioc_gone's update must be visible before reading ioc_count */