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 1abec4fdbb,
  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>
This commit is contained in:
Jens Axboe 2010-08-23 13:52:19 +02:00
Родитель 220eb7fd98
Коммит 5dd531a03a
2 изменённых файлов: 32 добавлений и 13 удалений

Просмотреть файл

@ -1009,18 +1009,19 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
{
struct elevator_queue *old_elevator, *e;
void *data;
int err;
/*
* Allocate new elevator
*/
e = elevator_alloc(q, new_e);
if (!e)
return 0;
return -ENOMEM;
data = elevator_init_queue(q, e);
if (!data) {
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)
__elv_unregister_queue(old_elevator);
if (elv_register_queue(q))
err = elv_register_queue(q);
if (err)
goto fail_register;
/*
@ -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);
return 1;
return 0;
fail_register:
/*
@ -1071,17 +1073,19 @@ fail_register:
queue_flag_clear(QUEUE_FLAG_ELVSWITCH, q);
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];
struct elevator_type *e;
if (!q->elevator)
return count;
return -ENXIO;
strlcpy(elevator_name, name, sizeof(elevator_name));
e = elevator_get(strstrip(elevator_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)) {
elevator_put(e);
return count;
return 0;
}
if (!elevator_switch(q, e))
printk(KERN_ERR "elevator: switch to %s failed\n",
elevator_name);
return count;
return elevator_switch(q, e);
}
EXPORT_SYMBOL(elevator_change);
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)

Просмотреть файл

@ -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 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 *);
/*