diff options
Diffstat (limited to 'block/elevator.c')
-rw-r--r-- | block/elevator.c | 65 |
1 files changed, 41 insertions, 24 deletions
diff --git a/block/elevator.c b/block/elevator.c index 0d6be03d929e..a0afdd317cef 100644 --- a/block/elevator.c +++ b/block/elevator.c | |||
@@ -121,16 +121,16 @@ static struct elevator_type *elevator_get(const char *name) | |||
121 | return e; | 121 | return e; |
122 | } | 122 | } |
123 | 123 | ||
124 | static int elevator_attach(request_queue_t *q, struct elevator_queue *eq) | 124 | static void *elevator_init_queue(request_queue_t *q, struct elevator_queue *eq) |
125 | { | 125 | { |
126 | int ret = 0; | 126 | return eq->ops->elevator_init_fn(q, eq); |
127 | } | ||
127 | 128 | ||
129 | static void elevator_attach(request_queue_t *q, struct elevator_queue *eq, | ||
130 | void *data) | ||
131 | { | ||
128 | q->elevator = eq; | 132 | q->elevator = eq; |
129 | 133 | eq->elevator_data = data; | |
130 | if (eq->ops->elevator_init_fn) | ||
131 | ret = eq->ops->elevator_init_fn(q, eq); | ||
132 | |||
133 | return ret; | ||
134 | } | 134 | } |
135 | 135 | ||
136 | static char chosen_elevator[16]; | 136 | static char chosen_elevator[16]; |
@@ -181,6 +181,7 @@ int elevator_init(request_queue_t *q, char *name) | |||
181 | struct elevator_type *e = NULL; | 181 | struct elevator_type *e = NULL; |
182 | struct elevator_queue *eq; | 182 | struct elevator_queue *eq; |
183 | int ret = 0; | 183 | int ret = 0; |
184 | void *data; | ||
184 | 185 | ||
185 | INIT_LIST_HEAD(&q->queue_head); | 186 | INIT_LIST_HEAD(&q->queue_head); |
186 | q->last_merge = NULL; | 187 | q->last_merge = NULL; |
@@ -202,10 +203,13 @@ int elevator_init(request_queue_t *q, char *name) | |||
202 | if (!eq) | 203 | if (!eq) |
203 | return -ENOMEM; | 204 | return -ENOMEM; |
204 | 205 | ||
205 | ret = elevator_attach(q, eq); | 206 | data = elevator_init_queue(q, eq); |
206 | if (ret) | 207 | if (!data) { |
207 | kobject_put(&eq->kobj); | 208 | kobject_put(&eq->kobj); |
209 | return -ENOMEM; | ||
210 | } | ||
208 | 211 | ||
212 | elevator_attach(q, eq, data); | ||
209 | return ret; | 213 | return ret; |
210 | } | 214 | } |
211 | 215 | ||
@@ -333,6 +337,7 @@ void elv_insert(request_queue_t *q, struct request *rq, int where) | |||
333 | { | 337 | { |
334 | struct list_head *pos; | 338 | struct list_head *pos; |
335 | unsigned ordseq; | 339 | unsigned ordseq; |
340 | int unplug_it = 1; | ||
336 | 341 | ||
337 | blk_add_trace_rq(q, rq, BLK_TA_INSERT); | 342 | blk_add_trace_rq(q, rq, BLK_TA_INSERT); |
338 | 343 | ||
@@ -399,6 +404,11 @@ void elv_insert(request_queue_t *q, struct request *rq, int where) | |||
399 | } | 404 | } |
400 | 405 | ||
401 | list_add_tail(&rq->queuelist, pos); | 406 | list_add_tail(&rq->queuelist, pos); |
407 | /* | ||
408 | * most requeues happen because of a busy condition, don't | ||
409 | * force unplug of the queue for that case. | ||
410 | */ | ||
411 | unplug_it = 0; | ||
402 | break; | 412 | break; |
403 | 413 | ||
404 | default: | 414 | default: |
@@ -407,7 +417,7 @@ void elv_insert(request_queue_t *q, struct request *rq, int where) | |||
407 | BUG(); | 417 | BUG(); |
408 | } | 418 | } |
409 | 419 | ||
410 | if (blk_queue_plugged(q)) { | 420 | if (unplug_it && blk_queue_plugged(q)) { |
411 | int nrq = q->rq.count[READ] + q->rq.count[WRITE] | 421 | int nrq = q->rq.count[READ] + q->rq.count[WRITE] |
412 | - q->in_flight; | 422 | - q->in_flight; |
413 | 423 | ||
@@ -716,13 +726,16 @@ int elv_register_queue(struct request_queue *q) | |||
716 | return error; | 726 | return error; |
717 | } | 727 | } |
718 | 728 | ||
729 | static void __elv_unregister_queue(elevator_t *e) | ||
730 | { | ||
731 | kobject_uevent(&e->kobj, KOBJ_REMOVE); | ||
732 | kobject_del(&e->kobj); | ||
733 | } | ||
734 | |||
719 | void elv_unregister_queue(struct request_queue *q) | 735 | void elv_unregister_queue(struct request_queue *q) |
720 | { | 736 | { |
721 | if (q) { | 737 | if (q) |
722 | elevator_t *e = q->elevator; | 738 | __elv_unregister_queue(q->elevator); |
723 | kobject_uevent(&e->kobj, KOBJ_REMOVE); | ||
724 | kobject_del(&e->kobj); | ||
725 | } | ||
726 | } | 739 | } |
727 | 740 | ||
728 | int elv_register(struct elevator_type *e) | 741 | int elv_register(struct elevator_type *e) |
@@ -774,6 +787,7 @@ EXPORT_SYMBOL_GPL(elv_unregister); | |||
774 | static int elevator_switch(request_queue_t *q, struct elevator_type *new_e) | 787 | static int elevator_switch(request_queue_t *q, struct elevator_type *new_e) |
775 | { | 788 | { |
776 | elevator_t *old_elevator, *e; | 789 | elevator_t *old_elevator, *e; |
790 | void *data; | ||
777 | 791 | ||
778 | /* | 792 | /* |
779 | * Allocate new elevator | 793 | * Allocate new elevator |
@@ -782,6 +796,12 @@ static int elevator_switch(request_queue_t *q, struct elevator_type *new_e) | |||
782 | if (!e) | 796 | if (!e) |
783 | return 0; | 797 | return 0; |
784 | 798 | ||
799 | data = elevator_init_queue(q, e); | ||
800 | if (!data) { | ||
801 | kobject_put(&e->kobj); | ||
802 | return 0; | ||
803 | } | ||
804 | |||
785 | /* | 805 | /* |
786 | * Turn on BYPASS and drain all requests w/ elevator private data | 806 | * Turn on BYPASS and drain all requests w/ elevator private data |
787 | */ | 807 | */ |
@@ -800,19 +820,19 @@ static int elevator_switch(request_queue_t *q, struct elevator_type *new_e) | |||
800 | elv_drain_elevator(q); | 820 | elv_drain_elevator(q); |
801 | } | 821 | } |
802 | 822 | ||
803 | spin_unlock_irq(q->queue_lock); | ||
804 | |||
805 | /* | 823 | /* |
806 | * unregister old elevator data | 824 | * Remember old elevator. |
807 | */ | 825 | */ |
808 | elv_unregister_queue(q); | ||
809 | old_elevator = q->elevator; | 826 | old_elevator = q->elevator; |
810 | 827 | ||
811 | /* | 828 | /* |
812 | * attach and start new elevator | 829 | * attach and start new elevator |
813 | */ | 830 | */ |
814 | if (elevator_attach(q, e)) | 831 | elevator_attach(q, e, data); |
815 | goto fail; | 832 | |
833 | spin_unlock_irq(q->queue_lock); | ||
834 | |||
835 | __elv_unregister_queue(old_elevator); | ||
816 | 836 | ||
817 | if (elv_register_queue(q)) | 837 | if (elv_register_queue(q)) |
818 | goto fail_register; | 838 | goto fail_register; |
@@ -831,7 +851,6 @@ fail_register: | |||
831 | */ | 851 | */ |
832 | elevator_exit(e); | 852 | elevator_exit(e); |
833 | e = NULL; | 853 | e = NULL; |
834 | fail: | ||
835 | q->elevator = old_elevator; | 854 | q->elevator = old_elevator; |
836 | elv_register_queue(q); | 855 | elv_register_queue(q); |
837 | clear_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); | 856 | clear_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); |
@@ -895,10 +914,8 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name) | |||
895 | EXPORT_SYMBOL(elv_dispatch_sort); | 914 | EXPORT_SYMBOL(elv_dispatch_sort); |
896 | EXPORT_SYMBOL(elv_add_request); | 915 | EXPORT_SYMBOL(elv_add_request); |
897 | EXPORT_SYMBOL(__elv_add_request); | 916 | EXPORT_SYMBOL(__elv_add_request); |
898 | EXPORT_SYMBOL(elv_requeue_request); | ||
899 | EXPORT_SYMBOL(elv_next_request); | 917 | EXPORT_SYMBOL(elv_next_request); |
900 | EXPORT_SYMBOL(elv_dequeue_request); | 918 | EXPORT_SYMBOL(elv_dequeue_request); |
901 | EXPORT_SYMBOL(elv_queue_empty); | 919 | EXPORT_SYMBOL(elv_queue_empty); |
902 | EXPORT_SYMBOL(elv_completed_request); | ||
903 | EXPORT_SYMBOL(elevator_exit); | 920 | EXPORT_SYMBOL(elevator_exit); |
904 | EXPORT_SYMBOL(elevator_init); | 921 | EXPORT_SYMBOL(elevator_init); |