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

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
Loading
Loading
Loading
Loading
+31 −13
Original line number Diff line number Diff line
@@ -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;
	}

	return elevator_switch(q, e);
}
EXPORT_SYMBOL(elevator_change);

	if (!elevator_switch(q, e))
		printk(KERN_ERR "elevator: switch to %s failed\n",
							elevator_name);
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)
+1 −0
Original line number Diff line number Diff line
@@ -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 *);

/*