Commit 5dd531a0 authored by Jens Axboe's avatar Jens Axboe

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 1abec4fd,
  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: default avatarPeter Oberparleiter <oberpar@linux.vnet.ibm.com>
Reported-by: default avatarKevin Vigor <kevin@vigor.nu>
Signed-off-by: default avatarJens Axboe <jaxboe@fusionio.com>
parent 220eb7fd
...@@ -1009,18 +1009,19 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e) ...@@ -1009,18 +1009,19 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
{ {
struct elevator_queue *old_elevator, *e; struct elevator_queue *old_elevator, *e;
void *data; void *data;
int err;
/* /*
* Allocate new elevator * Allocate new elevator
*/ */
e = elevator_alloc(q, new_e); e = elevator_alloc(q, new_e);
if (!e) if (!e)
return 0; return -ENOMEM;
data = elevator_init_queue(q, e); data = elevator_init_queue(q, e);
if (!data) { if (!data) {
kobject_put(&e->kobj); kobject_put(&e->kobj);
return 0; return -ENOMEM;
} }
/* /*
...@@ -1043,7 +1044,8 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e) ...@@ -1043,7 +1044,8 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
__elv_unregister_queue(old_elevator); __elv_unregister_queue(old_elevator);
if (elv_register_queue(q)) err = elv_register_queue(q);
if (err)
goto fail_register; goto fail_register;
/* /*
...@@ -1056,7 +1058,7 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e) ...@@ -1056,7 +1058,7 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
blk_add_trace_msg(q, "elv switch: %s", e->elevator_type->elevator_name); blk_add_trace_msg(q, "elv switch: %s", e->elevator_type->elevator_name);
return 1; return 0;
fail_register: fail_register:
/* /*
...@@ -1071,17 +1073,19 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e) ...@@ -1071,17 +1073,19 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
queue_flag_clear(QUEUE_FLAG_ELVSWITCH, q); queue_flag_clear(QUEUE_FLAG_ELVSWITCH, q);
spin_unlock_irq(q->queue_lock); spin_unlock_irq(q->queue_lock);
return 0; return err;
} }
ssize_t elv_iosched_store(struct request_queue *q, const char *name, /*
size_t count) * Switch this queue to the given IO scheduler.
*/
int elevator_change(struct request_queue *q, const char *name)
{ {
char elevator_name[ELV_NAME_MAX]; char elevator_name[ELV_NAME_MAX];
struct elevator_type *e; struct elevator_type *e;
if (!q->elevator) if (!q->elevator)
return count; return -ENXIO;
strlcpy(elevator_name, name, sizeof(elevator_name)); strlcpy(elevator_name, name, sizeof(elevator_name));
e = elevator_get(strstrip(elevator_name)); e = elevator_get(strstrip(elevator_name));
...@@ -1092,13 +1096,27 @@ ssize_t elv_iosched_store(struct request_queue *q, const char *name, ...@@ -1092,13 +1096,27 @@ ssize_t elv_iosched_store(struct request_queue *q, const char *name,
if (!strcmp(elevator_name, q->elevator->elevator_type->elevator_name)) { if (!strcmp(elevator_name, q->elevator->elevator_type->elevator_name)) {
elevator_put(e); elevator_put(e);
return count; return 0;
} }
if (!elevator_switch(q, e)) return elevator_switch(q, e);
printk(KERN_ERR "elevator: switch to %s failed\n", }
elevator_name); EXPORT_SYMBOL(elevator_change);
return count;
ssize_t elv_iosched_store(struct request_queue *q, const char *name,
size_t count)
{
int ret;
if (!q->elevator)
return count;
ret = elevator_change(q, name);
if (!ret)
return count;
printk(KERN_ERR "elevator: switch to %s failed\n", name);
return ret;
} }
ssize_t elv_iosched_show(struct request_queue *q, char *name) ssize_t elv_iosched_show(struct request_queue *q, char *name)
......
...@@ -136,6 +136,7 @@ extern ssize_t elv_iosched_store(struct request_queue *, const char *, size_t); ...@@ -136,6 +136,7 @@ extern ssize_t elv_iosched_store(struct request_queue *, const char *, size_t);
extern int elevator_init(struct request_queue *, char *); extern int elevator_init(struct request_queue *, char *);
extern void elevator_exit(struct elevator_queue *); extern void elevator_exit(struct elevator_queue *);
extern int elevator_change(struct request_queue *, const char *);
extern int elv_rq_merge_ok(struct request *, struct bio *); extern int elv_rq_merge_ok(struct request *, struct bio *);
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment