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:
Родитель
220eb7fd98
Коммит
5dd531a03a
|
@ -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 *);
|
||||
|
||||
/*
|
||||
|
|
Загрузка…
Ссылка в новой задаче