diff options
Diffstat (limited to 'block/elevator.c')
-rw-r--r-- | block/elevator.c | 91 |
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 | ||
171 | static void *elevator_init_queue(struct request_queue *q, | 171 | static 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; | |
177 | static 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 | ||
184 | static char chosen_elevator[ELV_NAME_MAX]; | 180 | static 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 | } |
290 | EXPORT_SYMBOL(elevator_init); | 286 | EXPORT_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 | ||
859 | int elv_register_queue(struct request_queue *q) | 855 | int __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 | } |
879 | EXPORT_SYMBOL(elv_register_queue); | ||
880 | 874 | ||
881 | static void __elv_unregister_queue(struct elevator_queue *e) | 875 | int 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 | } |
879 | EXPORT_SYMBOL(elv_register_queue); | ||
887 | 880 | ||
888 | void elv_unregister_queue(struct request_queue *q) | 881 | void 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 | } |
893 | EXPORT_SYMBOL(elv_unregister_queue); | 891 | EXPORT_SYMBOL(elv_unregister_queue); |
894 | 892 | ||
@@ -928,50 +926,36 @@ EXPORT_SYMBOL_GPL(elv_unregister); | |||
928 | static int elevator_switch(struct request_queue *q, struct elevator_type *new_e) | 926 | static 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 | ||