aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Axboe <jaxboe@fusionio.com>2010-08-23 07:52:19 -0400
committerJens Axboe <jaxboe@fusionio.com>2010-08-23 07:52:19 -0400
commit5dd531a03ad721b41911ddb32e6e0481404e7aaf (patch)
tree3d07d0aa902eb61a575bbc7cc2a57c03431e2b01
parent220eb7fd984bfc7e6b4005fdf32efe9cd8af7cf2 (diff)
block: add function call to switch the IO scheduler from a driver
Currently drivers must do an elevator_exit() + elevator_init() to switch IO schedulers. There are a few problems with this: - Since commit 1abec4fdbb142e3ccb6ce99832fae42129134a96, elevator_init() requires a zeroed out q->elevator pointer. The two existing in-kernel users don't do that. - It will only work at initialization time, since using the above two-staged construct does not properly quisce the queue. So add elevator_change() which takes care of this, and convert the elv_iosched_store() sysfs interface to use this helper as well. Reported-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com> Reported-by: Kevin Vigor <kevin@vigor.nu> Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
-rw-r--r--block/elevator.c44
-rw-r--r--include/linux/elevator.h1
2 files changed, 32 insertions, 13 deletions
diff --git a/block/elevator.c b/block/elevator.c
index ec585c9554d3..205b09a5bd9e 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -1009,18 +1009,19 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
1009{ 1009{
1010 struct elevator_queue *old_elevator, *e; 1010 struct elevator_queue *old_elevator, *e;
1011 void *data; 1011 void *data;
1012 int err;
1012 1013
1013 /* 1014 /*
1014 * Allocate new elevator 1015 * Allocate new elevator
1015 */ 1016 */
1016 e = elevator_alloc(q, new_e); 1017 e = elevator_alloc(q, new_e);
1017 if (!e) 1018 if (!e)
1018 return 0; 1019 return -ENOMEM;
1019 1020
1020 data = elevator_init_queue(q, e); 1021 data = elevator_init_queue(q, e);
1021 if (!data) { 1022 if (!data) {
1022 kobject_put(&e->kobj); 1023 kobject_put(&e->kobj);
1023 return 0; 1024 return -ENOMEM;
1024 } 1025 }
1025 1026
1026 /* 1027 /*
@@ -1043,7 +1044,8 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
1043 1044
1044 __elv_unregister_queue(old_elevator); 1045 __elv_unregister_queue(old_elevator);
1045 1046
1046 if (elv_register_queue(q)) 1047 err = elv_register_queue(q);
1048 if (err)
1047 goto fail_register; 1049 goto fail_register;
1048 1050
1049 /* 1051 /*
@@ -1056,7 +1058,7 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
1056 1058
1057 blk_add_trace_msg(q, "elv switch: %s", e->elevator_type->elevator_name); 1059 blk_add_trace_msg(q, "elv switch: %s", e->elevator_type->elevator_name);
1058 1060
1059 return 1; 1061 return 0;
1060 1062
1061fail_register: 1063fail_register:
1062 /* 1064 /*
@@ -1071,17 +1073,19 @@ fail_register:
1071 queue_flag_clear(QUEUE_FLAG_ELVSWITCH, q); 1073 queue_flag_clear(QUEUE_FLAG_ELVSWITCH, q);
1072 spin_unlock_irq(q->queue_lock); 1074 spin_unlock_irq(q->queue_lock);
1073 1075
1074 return 0; 1076 return err;
1075} 1077}
1076 1078
1077ssize_t elv_iosched_store(struct request_queue *q, const char *name, 1079/*
1078 size_t count) 1080 * Switch this queue to the given IO scheduler.
1081 */
1082int elevator_change(struct request_queue *q, const char *name)
1079{ 1083{
1080 char elevator_name[ELV_NAME_MAX]; 1084 char elevator_name[ELV_NAME_MAX];
1081 struct elevator_type *e; 1085 struct elevator_type *e;
1082 1086
1083 if (!q->elevator) 1087 if (!q->elevator)
1084 return count; 1088 return -ENXIO;
1085 1089
1086 strlcpy(elevator_name, name, sizeof(elevator_name)); 1090 strlcpy(elevator_name, name, sizeof(elevator_name));
1087 e = elevator_get(strstrip(elevator_name)); 1091 e = elevator_get(strstrip(elevator_name));
@@ -1092,13 +1096,27 @@ ssize_t elv_iosched_store(struct request_queue *q, const char *name,
1092 1096
1093 if (!strcmp(elevator_name, q->elevator->elevator_type->elevator_name)) { 1097 if (!strcmp(elevator_name, q->elevator->elevator_type->elevator_name)) {
1094 elevator_put(e); 1098 elevator_put(e);
1095 return count; 1099 return 0;
1096 } 1100 }
1097 1101
1098 if (!elevator_switch(q, e)) 1102 return elevator_switch(q, e);
1099 printk(KERN_ERR "elevator: switch to %s failed\n", 1103}
1100 elevator_name); 1104EXPORT_SYMBOL(elevator_change);
1101 return count; 1105
1106ssize_t elv_iosched_store(struct request_queue *q, const char *name,
1107 size_t count)
1108{
1109 int ret;
1110
1111 if (!q->elevator)
1112 return count;
1113
1114 ret = elevator_change(q, name);
1115 if (!ret)
1116 return count;
1117
1118 printk(KERN_ERR "elevator: switch to %s failed\n", name);
1119 return ret;
1102} 1120}
1103 1121
1104ssize_t elv_iosched_show(struct request_queue *q, char *name) 1122ssize_t elv_iosched_show(struct request_queue *q, char *name)
diff --git a/include/linux/elevator.h b/include/linux/elevator.h
index 2c958f4fce1e..926b50322a46 100644
--- a/include/linux/elevator.h
+++ b/include/linux/elevator.h
@@ -136,6 +136,7 @@ extern ssize_t elv_iosched_store(struct request_queue *, const char *, size_t);
136 136
137extern int elevator_init(struct request_queue *, char *); 137extern int elevator_init(struct request_queue *, char *);
138extern void elevator_exit(struct elevator_queue *); 138extern void elevator_exit(struct elevator_queue *);
139extern int elevator_change(struct request_queue *, const char *);
139extern int elv_rq_merge_ok(struct request *, struct bio *); 140extern int elv_rq_merge_ok(struct request *, struct bio *);
140 141
141/* 142/*