aboutsummaryrefslogtreecommitdiffstats
path: root/block/elevator.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2012-03-05 16:14:56 -0500
committerJens Axboe <axboe@kernel.dk>2012-03-06 15:27:21 -0500
commit5a5bafdc396b1da7570f84fb96a0f8a288970c5e (patch)
tree31ed56739ff72b8e4cb62b10b280db99bd1b6d0e /block/elevator.c
parentb95ada558c9e69c69ffd6950eb644ee8a3dba18f (diff)
elevator: clear auxiliary data earlier during elevator switch
Elevator switch tries hard to keep as much as context until new elevator is ready so that it can revert to the original state if initializing the new elevator fails for some reason. Unfortunately, with more auxiliary contexts to manage, this makes elevator init and exit paths too complex and fragile. This patch makes elevator_switch() unregister the current elevator and flush icq's before start initializing the new one. As we still keep the old elevator itself, the only difference is that we lose icq's on rare occassions of switching failure, which isn't critical at all. Note that this makes explicit elevator parameter to elevator_init_queue() and __elv_register_queue() unnecessary as they always can use the current elevator. This patch enables block cgroup cleanups. -v2: blk_add_trace_msg() prints elevator name from @new_e instead of @e->type as the local variable no longer exists. This caused build failure on CONFIG_BLK_DEV_IO_TRACE. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Vivek Goyal <vgoyal@redhat.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'block/elevator.c')
-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