aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--block/elevator.c90
1 files changed, 45 insertions, 45 deletions
diff --git a/block/elevator.c b/block/elevator.c
index f016855a46b0..f8c08e1bff2b 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -121,11 +121,10 @@ static struct elevator_type *elevator_get(const char *name)
121 return e; 121 return e;
122} 122}
123 123
124static int elevator_init_queue(struct request_queue *q, 124static int elevator_init_queue(struct request_queue *q)
125 struct elevator_queue *eq)
126{ 125{
127 eq->elevator_data = eq->type->ops.elevator_init_fn(q); 126 q->elevator->elevator_data = q->elevator->type->ops.elevator_init_fn(q);
128 if (eq->elevator_data) 127 if (q->elevator->elevator_data)
129 return 0; 128 return 0;
130 return -ENOMEM; 129 return -ENOMEM;
131} 130}
@@ -188,7 +187,6 @@ static void elevator_release(struct kobject *kobj)
188int elevator_init(struct request_queue *q, char *name) 187int elevator_init(struct request_queue *q, char *name)
189{ 188{
190 struct elevator_type *e = NULL; 189 struct elevator_type *e = NULL;
191 struct elevator_queue *eq;
192 int err; 190 int err;
193 191
194 if (unlikely(q->elevator)) 192 if (unlikely(q->elevator))
@@ -222,17 +220,16 @@ int elevator_init(struct request_queue *q, char *name)
222 } 220 }
223 } 221 }
224 222
225 eq = elevator_alloc(q, e); 223 q->elevator = elevator_alloc(q, e);
226 if (!eq) 224 if (!q->elevator)
227 return -ENOMEM; 225 return -ENOMEM;
228 226
229 err = elevator_init_queue(q, eq); 227 err = elevator_init_queue(q);
230 if (err) { 228 if (err) {
231 kobject_put(&eq->kobj); 229 kobject_put(&q->elevator->kobj);
232 return err; 230 return err;
233 } 231 }
234 232
235 q->elevator = eq;
236 return 0; 233 return 0;
237} 234}
238EXPORT_SYMBOL(elevator_init); 235EXPORT_SYMBOL(elevator_init);
@@ -801,8 +798,9 @@ static struct kobj_type elv_ktype = {
801 .release = elevator_release, 798 .release = elevator_release,
802}; 799};
803 800
804int __elv_register_queue(struct request_queue *q, struct elevator_queue *e) 801int elv_register_queue(struct request_queue *q)
805{ 802{
803 struct elevator_queue *e = q->elevator;
806 int error; 804 int error;
807 805
808 error = kobject_add(&e->kobj, &q->kobj, "%s", "iosched"); 806 error = kobject_add(&e->kobj, &q->kobj, "%s", "iosched");
@@ -820,11 +818,6 @@ int __elv_register_queue(struct request_queue *q, struct elevator_queue *e)
820 } 818 }
821 return error; 819 return error;
822} 820}
823
824int elv_register_queue(struct request_queue *q)
825{
826 return __elv_register_queue(q, q->elevator);
827}
828EXPORT_SYMBOL(elv_register_queue); 821EXPORT_SYMBOL(elv_register_queue);
829 822
830void elv_unregister_queue(struct request_queue *q) 823void elv_unregister_queue(struct request_queue *q)
@@ -907,51 +900,58 @@ EXPORT_SYMBOL_GPL(elv_unregister);
907 */ 900 */
908static int elevator_switch(struct request_queue *q, struct elevator_type *new_e) 901static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
909{ 902{
910 struct elevator_queue *old_elevator, *e; 903 struct elevator_queue *old = q->elevator;
904 bool registered = old->registered;
911 int err; 905 int err;
912 906
913 /* allocate new elevator */ 907 /*
914 e = elevator_alloc(q, new_e); 908 * Turn on BYPASS and drain all requests w/ elevator private data.
915 if (!e) 909 * Block layer doesn't call into a quiesced elevator - all requests
916 return -ENOMEM; 910 * are directly put on the dispatch list without elevator data
917 911 * using INSERT_BACK. All requests have SOFTBARRIER set and no
918 err = elevator_init_queue(q, e); 912 * merge happens either.
919 if (err) { 913 */
920 kobject_put(&e->kobj);
921 return err;
922 }
923
924 /* turn on BYPASS and drain all requests w/ elevator private data */
925 elv_quiesce_start(q); 914 elv_quiesce_start(q);
926 915
927 /* unregister old queue, register new one and kill old elevator */ 916 /* unregister and clear all auxiliary data of the old elevator */
928 if (q->elevator->registered) { 917 if (registered)
929 elv_unregister_queue(q); 918 elv_unregister_queue(q);
930 err = __elv_register_queue(q, e);
931 if (err)
932 goto fail_register;
933 }
934 919
935 /* done, clear io_cq's, switch elevators and turn off BYPASS */
936 spin_lock_irq(q->queue_lock); 920 spin_lock_irq(q->queue_lock);
937 ioc_clear_queue(q); 921 ioc_clear_queue(q);
938 old_elevator = q->elevator;
939 q->elevator = e;
940 spin_unlock_irq(q->queue_lock); 922 spin_unlock_irq(q->queue_lock);
941 923
942 elevator_exit(old_elevator); 924 /* allocate, init and register new elevator */
925 err = -ENOMEM;
926 q->elevator = elevator_alloc(q, new_e);
927 if (!q->elevator)
928 goto fail_init;
929
930 err = elevator_init_queue(q);
931 if (err) {
932 kobject_put(&q->elevator->kobj);
933 goto fail_init;
934 }
935
936 if (registered) {
937 err = elv_register_queue(q);
938 if (err)
939 goto fail_register;
940 }
941
942 /* done, kill the old one and finish */
943 elevator_exit(old);
943 elv_quiesce_end(q); 944 elv_quiesce_end(q);
944 945
945 blk_add_trace_msg(q, "elv switch: %s", e->type->elevator_name); 946 blk_add_trace_msg(q, "elv switch: %s", new_e->elevator_name);
946 947
947 return 0; 948 return 0;
948 949
949fail_register: 950fail_register:
950 /* 951 elevator_exit(q->elevator);
951 * switch failed, exit the new io scheduler and reattach the old 952fail_init:
952 * one again (along with re-adding the sysfs dir) 953 /* switch failed, restore and re-register old elevator */
953 */ 954 q->elevator = old;
954 elevator_exit(e);
955 elv_register_queue(q); 955 elv_register_queue(q);
956 elv_quiesce_end(q); 956 elv_quiesce_end(q);
957 957