]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/block/elevator.c
Merge branch 'for-linus' of git://brick.kernel.dk/data/git/linux-2.6-block
[karo-tx-linux.git] / drivers / block / elevator.c
index 89982925f9e2230d404c78349efe2b415133d5f7..4f69d222b183fed2b3f145c98cf2e11498ea8196 100644 (file)
@@ -97,7 +97,6 @@ static struct elevator_type *elevator_find(const char *name)
        struct elevator_type *e = NULL;
        struct list_head *entry;
 
-       spin_lock_irq(&elv_list_lock);
        list_for_each(entry, &elv_list) {
                struct elevator_type *__e;
 
@@ -108,7 +107,6 @@ static struct elevator_type *elevator_find(const char *name)
                        break;
                }
        }
-       spin_unlock_irq(&elv_list_lock);
 
        return e;
 }
@@ -120,12 +118,15 @@ static void elevator_put(struct elevator_type *e)
 
 static struct elevator_type *elevator_get(const char *name)
 {
-       struct elevator_type *e = elevator_find(name);
+       struct elevator_type *e;
 
-       if (!e)
-               return NULL;
-       if (!try_module_get(e->elevator_owner))
-               return NULL;
+       spin_lock_irq(&elv_list_lock);
+
+       e = elevator_find(name);
+       if (e && !try_module_get(e->elevator_owner))
+               e = NULL;
+
+       spin_unlock_irq(&elv_list_lock);
 
        return e;
 }
@@ -153,11 +154,15 @@ static char chosen_elevator[16];
 
 static void elevator_setup_default(void)
 {
+       struct elevator_type *e;
+
        /*
         * check if default is set and exists
         */
-       if (chosen_elevator[0] && elevator_find(chosen_elevator))
+       if (chosen_elevator[0] && (e = elevator_get(chosen_elevator))) {
+               elevator_put(e);
                return;
+       }
 
 #if defined(CONFIG_IOSCHED_AS)
        strcpy(chosen_elevator, "anticipatory");
@@ -285,6 +290,13 @@ void elv_requeue_request(request_queue_t *q, struct request *rq)
                rq = rq->end_io_data;
        }
 
+       /*
+        * the request is prepped and may have some resources allocated.
+        * allowing unprepped requests to pass this one may cause resource
+        * deadlock.  turn on softbarrier.
+        */
+       rq->flags |= REQ_SOFTBARRIER;
+
        /*
         * if iosched has an explicit requeue hook, then use that. otherwise
         * just put the request at the front of the queue
@@ -381,6 +393,12 @@ struct request *elv_next_request(request_queue_t *q)
                if (ret == BLKPREP_OK) {
                        break;
                } else if (ret == BLKPREP_DEFER) {
+                       /*
+                        * the request may have been (partially) prepped.
+                        * we need to keep this request in the front to
+                        * avoid resource deadlock.  turn on softbarrier.
+                        */
+                       rq->flags |= REQ_SOFTBARRIER;
                        rq = NULL;
                        break;
                } else if (ret == BLKPREP_KILL) {
@@ -473,12 +491,13 @@ struct request *elv_former_request(request_queue_t *q, struct request *rq)
        return NULL;
 }
 
-int elv_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
+int elv_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
+                   gfp_t gfp_mask)
 {
        elevator_t *e = q->elevator;
 
        if (e->ops->elevator_set_req_fn)
-               return e->ops->elevator_set_req_fn(q, rq, gfp_mask);
+               return e->ops->elevator_set_req_fn(q, rq, bio, gfp_mask);
 
        rq->elevator_private = NULL;
        return 0;
@@ -492,12 +511,12 @@ void elv_put_request(request_queue_t *q, struct request *rq)
                e->ops->elevator_put_req_fn(q, rq);
 }
 
-int elv_may_queue(request_queue_t *q, int rw)
+int elv_may_queue(request_queue_t *q, int rw, struct bio *bio)
 {
        elevator_t *e = q->elevator;
 
        if (e->ops->elevator_may_queue_fn)
-               return e->ops->elevator_may_queue_fn(q, rw);
+               return e->ops->elevator_may_queue_fn(q, rw, bio);
 
        return ELV_MQUEUE_MAY;
 }
@@ -541,10 +560,9 @@ void elv_unregister_queue(struct request_queue *q)
 
 int elv_register(struct elevator_type *e)
 {
+       spin_lock_irq(&elv_list_lock);
        if (elevator_find(e->elevator_name))
                BUG();
-
-       spin_lock_irq(&elv_list_lock);
        list_add_tail(&e->list, &elv_list);
        spin_unlock_irq(&elv_list_lock);