]> err.no Git - linux-2.6/blobdiff - block/cfq-iosched.c
[PATCH] EISA: handle sysfs errors
[linux-2.6] / block / cfq-iosched.c
index 6fb1613d44d7b9270d4cdc7fad00ff4d6f54c337..d3d76136f53adea6293244f7cd9a9aa07f24b4d0 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>
@@ -141,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;
 
@@ -248,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;
@@ -510,6 +516,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
@@ -1527,8 +1538,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;
 }
@@ -1539,30 +1560,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;
 }
 
 /*
@@ -1575,6 +1585,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)) {
         */
@@ -1593,7 +1606,7 @@ 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;
        }
@@ -1614,7 +1627,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)) {
                /*
@@ -1624,7 +1637,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);
        }
 }
 
@@ -1832,8 +1845,7 @@ static void cfq_kick_queue(void *data)
        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);
 }
 
@@ -2148,7 +2160,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 */