aboutsummaryrefslogtreecommitdiffstats
path: root/block/elevator.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2011-12-13 18:33:40 -0500
committerJens Axboe <axboe@kernel.dk>2011-12-13 18:33:40 -0500
commitf8fc877d3c1f10457d0d73d8540a0c51a1fa718a (patch)
tree036d5d57996a6b3f1dfd68fb569eea0e699f2263 /block/elevator.c
parentf2dbd76a0a994bc1d5a3d0e7c844cc373832e86c (diff)
block: reorder elevator switch sequence
Elevator switch sequence first attached the new elevator, then tried registering it (sysfs) and if that failed attached back the old elevator. However, sysfs registration doesn't require the elevator to be attached, so there is no reason to do the "detach, attach new, register, maybe re-attach old" sequence. It can just do "register, detach, attach". * elevator_init_queue() is updated to set ->elevator_data directly and return 0 / -errno. This allows elevator_exit() on an unattached elevator. * __elv_unregister_queue() which was necessary to unregister unattached q is removed in favor of __elv_register_queue() which can register unattached q. * elevator_attach() becomes a single assignment and obscures more then it helps. Dropped. This will help cleaning up io_context handling across elevator switch. This patch doesn't introduce visible behavior change. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'block/elevator.c')
-rw-r--r--block/elevator.c91
1 files changed, 37 insertions, 54 deletions
diff --git a/block/elevator.c b/block/elevator.c
index 6a343e8f8319..a16c2d1713e5 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -168,17 +168,13 @@ static struct elevator_type *elevator_get(const char *name)
168 return e; 168 return e;
169} 169}
170 170
171static void *elevator_init_queue(struct request_queue *q, 171static int elevator_init_queue(struct request_queue *q,
172 struct elevator_queue *eq) 172 struct elevator_queue *eq)
173{ 173{
174 return eq->ops->elevator_init_fn(q); 174 eq->elevator_data = eq->ops->elevator_init_fn(q);
175} 175 if (eq->elevator_data)
176 176 return 0;
177static void elevator_attach(struct request_queue *q, struct elevator_queue *eq, 177 return -ENOMEM;
178 void *data)
179{
180 q->elevator = eq;
181 eq->elevator_data = data;
182} 178}
183 179
184static char chosen_elevator[ELV_NAME_MAX]; 180static char chosen_elevator[ELV_NAME_MAX];
@@ -241,7 +237,7 @@ int elevator_init(struct request_queue *q, char *name)
241{ 237{
242 struct elevator_type *e = NULL; 238 struct elevator_type *e = NULL;
243 struct elevator_queue *eq; 239 struct elevator_queue *eq;
244 void *data; 240 int err;
245 241
246 if (unlikely(q->elevator)) 242 if (unlikely(q->elevator))
247 return 0; 243 return 0;
@@ -278,13 +274,13 @@ int elevator_init(struct request_queue *q, char *name)
278 if (!eq) 274 if (!eq)
279 return -ENOMEM; 275 return -ENOMEM;
280 276
281 data = elevator_init_queue(q, eq); 277 err = elevator_init_queue(q, eq);
282 if (!data) { 278 if (err) {
283 kobject_put(&eq->kobj); 279 kobject_put(&eq->kobj);
284 return -ENOMEM; 280 return err;
285 } 281 }
286 282
287 elevator_attach(q, eq, data); 283 q->elevator = eq;
288 return 0; 284 return 0;
289} 285}
290EXPORT_SYMBOL(elevator_init); 286EXPORT_SYMBOL(elevator_init);
@@ -856,9 +852,8 @@ static struct kobj_type elv_ktype = {
856 .release = elevator_release, 852 .release = elevator_release,
857}; 853};
858 854
859int elv_register_queue(struct request_queue *q) 855int __elv_register_queue(struct request_queue *q, struct elevator_queue *e)
860{ 856{
861 struct elevator_queue *e = q->elevator;
862 int error; 857 int error;
863 858
864 error = kobject_add(&e->kobj, &q->kobj, "%s", "iosched"); 859 error = kobject_add(&e->kobj, &q->kobj, "%s", "iosched");
@@ -876,19 +871,22 @@ int elv_register_queue(struct request_queue *q)
876 } 871 }
877 return error; 872 return error;
878} 873}
879EXPORT_SYMBOL(elv_register_queue);
880 874
881static void __elv_unregister_queue(struct elevator_queue *e) 875int elv_register_queue(struct request_queue *q)
882{ 876{
883 kobject_uevent(&e->kobj, KOBJ_REMOVE); 877 return __elv_register_queue(q, q->elevator);
884 kobject_del(&e->kobj);
885 e->registered = 0;
886} 878}
879EXPORT_SYMBOL(elv_register_queue);
887 880
888void elv_unregister_queue(struct request_queue *q) 881void elv_unregister_queue(struct request_queue *q)
889{ 882{
890 if (q) 883 if (q) {
891 __elv_unregister_queue(q->elevator); 884 struct elevator_queue *e = q->elevator;
885
886 kobject_uevent(&e->kobj, KOBJ_REMOVE);
887 kobject_del(&e->kobj);
888 e->registered = 0;
889 }
892} 890}
893EXPORT_SYMBOL(elv_unregister_queue); 891EXPORT_SYMBOL(elv_unregister_queue);
894 892
@@ -928,50 +926,36 @@ EXPORT_SYMBOL_GPL(elv_unregister);
928static int elevator_switch(struct request_queue *q, struct elevator_type *new_e) 926static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
929{ 927{
930 struct elevator_queue *old_elevator, *e; 928 struct elevator_queue *old_elevator, *e;
931 void *data;
932 int err; 929 int err;
933 930
934 /* 931 /* allocate new elevator */
935 * Allocate new elevator
936 */
937 e = elevator_alloc(q, new_e); 932 e = elevator_alloc(q, new_e);
938 if (!e) 933 if (!e)
939 return -ENOMEM; 934 return -ENOMEM;
940 935
941 data = elevator_init_queue(q, e); 936 err = elevator_init_queue(q, e);
942 if (!data) { 937 if (err) {
943 kobject_put(&e->kobj); 938 kobject_put(&e->kobj);
944 return -ENOMEM; 939 return err;
945 } 940 }
946 941
947 /* 942 /* turn on BYPASS and drain all requests w/ elevator private data */
948 * Turn on BYPASS and drain all requests w/ elevator private data
949 */
950 elv_quiesce_start(q); 943 elv_quiesce_start(q);
951 944
952 /* 945 /* unregister old queue, register new one and kill old elevator */
953 * Remember old elevator. 946 if (q->elevator->registered) {
954 */ 947 elv_unregister_queue(q);
955 old_elevator = q->elevator; 948 err = __elv_register_queue(q, e);
956
957 /*
958 * attach and start new elevator
959 */
960 spin_lock_irq(q->queue_lock);
961 elevator_attach(q, e, data);
962 spin_unlock_irq(q->queue_lock);
963
964 if (old_elevator->registered) {
965 __elv_unregister_queue(old_elevator);
966
967 err = elv_register_queue(q);
968 if (err) 949 if (err)
969 goto fail_register; 950 goto fail_register;
970 } 951 }
971 952
972 /* 953 /* done, replace the old one with new one and turn off BYPASS */
973 * finally exit old elevator and turn off BYPASS. 954 spin_lock_irq(q->queue_lock);
974 */ 955 old_elevator = q->elevator;
956 q->elevator = e;
957 spin_unlock_irq(q->queue_lock);
958
975 elevator_exit(old_elevator); 959 elevator_exit(old_elevator);
976 elv_quiesce_end(q); 960 elv_quiesce_end(q);
977 961
@@ -985,7 +969,6 @@ fail_register:
985 * one again (along with re-adding the sysfs dir) 969 * one again (along with re-adding the sysfs dir)
986 */ 970 */
987 elevator_exit(e); 971 elevator_exit(e);
988 q->elevator = old_elevator;
989 elv_register_queue(q); 972 elv_register_queue(q);
990 elv_quiesce_end(q); 973 elv_quiesce_end(q);
991 974