vserver 2.0 rc7
[linux-2.6.git] / drivers / block / elevator.c
index 35f4079..8998292 100644 (file)
@@ -92,7 +92,7 @@ inline int elv_try_last_merge(request_queue_t *q, struct bio *bio)
 }
 EXPORT_SYMBOL(elv_try_last_merge);
 
-struct elevator_type *elevator_find(const char *name)
+static struct elevator_type *elevator_find(const char *name)
 {
        struct elevator_type *e = NULL;
        struct list_head *entry;
@@ -220,11 +220,6 @@ void elevator_exit(elevator_t *e)
        kfree(e);
 }
 
-int elevator_global_init(void)
-{
-       return 0;
-}
-
 int elv_merge(request_queue_t *q, struct request **req, struct bio *bio)
 {
        elevator_t *e = q->elevator;
@@ -255,8 +250,16 @@ void elv_merge_requests(request_queue_t *q, struct request *rq,
                e->ops->elevator_merge_req_fn(q, rq, next);
 }
 
-void elv_requeue_request(request_queue_t *q, struct request *rq)
+/*
+ * For careful internal use by the block layer. Essentially the same as
+ * a requeue in that it tells the io scheduler that this request is not
+ * active in the driver or hardware anymore, but we don't want the request
+ * added back to the scheduler. Function is not exported.
+ */
+void elv_deactivate_request(request_queue_t *q, struct request *rq)
 {
+       elevator_t *e = q->elevator;
+
        /*
         * it already went through dequeue, we need to decrement the
         * in_flight count again
@@ -264,6 +267,24 @@ void elv_requeue_request(request_queue_t *q, struct request *rq)
        if (blk_account_rq(rq))
                q->in_flight--;
 
+       rq->flags &= ~REQ_STARTED;
+
+       if (e->ops->elevator_deactivate_req_fn)
+               e->ops->elevator_deactivate_req_fn(q, rq);
+}
+
+void elv_requeue_request(request_queue_t *q, struct request *rq)
+{
+       elv_deactivate_request(q, rq);
+
+       /*
+        * if this is the flush, requeue the original instead and drop the flush
+        */
+       if (rq->flags & REQ_BAR_FLUSH) {
+               clear_bit(QUEUE_FLAG_FLUSH, &q->queue_flags);
+               rq = rq->end_io_data;
+       }
+
        /*
         * if iosched has an explicit requeue hook, then use that. otherwise
         * just put the request at the front of the queue
@@ -296,7 +317,7 @@ void __elv_add_request(request_queue_t *q, struct request *rq, int where,
                        int nrq = q->rq.count[READ] + q->rq.count[WRITE]
                                  - q->in_flight;
 
-                       if (nrq == q->unplug_thresh)
+                       if (nrq >= q->unplug_thresh)
                                __generic_unplug_device(q);
                }
        } else
@@ -320,7 +341,21 @@ void elv_add_request(request_queue_t *q, struct request *rq, int where,
 
 static inline struct request *__elv_next_request(request_queue_t *q)
 {
-       return q->elevator->ops->elevator_next_req_fn(q);
+       struct request *rq = q->elevator->ops->elevator_next_req_fn(q);
+
+       /*
+        * if this is a barrier write and the device has to issue a
+        * flush sequence to support it, check how far we are
+        */
+       if (rq && blk_fs_request(rq) && blk_barrier_rq(rq)) {
+               BUG_ON(q->ordered == QUEUE_ORDERED_NONE);
+
+               if (q->ordered == QUEUE_ORDERED_FLUSH &&
+                   !blk_barrier_preflush(rq))
+                       rq = blk_start_pre_flush(q, rq);
+       }
+
+       return rq;
 }
 
 struct request *elv_next_request(request_queue_t *q)
@@ -652,8 +687,6 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name)
        return len;
 }
 
-module_init(elevator_global_init);
-
 EXPORT_SYMBOL(elv_add_request);
 EXPORT_SYMBOL(__elv_add_request);
 EXPORT_SYMBOL(elv_requeue_request);