Commit f8fc877d authored by Tejun Heo's avatar Tejun Heo Committed by Jens Axboe

block: reorder elevator switch sequence

Elevator switch sequence first attached the new elevator, then tried
registering it (sysfs) and if that failed attached back the old
elevator.  However, sysfs registration doesn't require the elevator to
be attached, so there is no reason to do the "detach, attach new,
register, maybe re-attach old" sequence.  It can just do "register,
detach, attach".

* elevator_init_queue() is updated to set ->elevator_data directly and
  return 0 / -errno.  This allows elevator_exit() on an unattached
  elevator.

* __elv_unregister_queue() which was necessary to unregister
  unattached q is removed in favor of __elv_register_queue() which can
  register unattached q.

* elevator_attach() becomes a single assignment and obscures more then
  it helps.  Dropped.

This will help cleaning up io_context handling across elevator switch.

This patch doesn't introduce visible behavior change.
Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent f2dbd76a
...@@ -168,17 +168,13 @@ static struct elevator_type *elevator_get(const char *name) ...@@ -168,17 +168,13 @@ static struct elevator_type *elevator_get(const char *name)
return e; return e;
} }
static void *elevator_init_queue(struct request_queue *q, static int elevator_init_queue(struct request_queue *q,
struct elevator_queue *eq) struct elevator_queue *eq)
{ {
return eq->ops->elevator_init_fn(q); eq->elevator_data = eq->ops->elevator_init_fn(q);
} if (eq->elevator_data)
return 0;
static void elevator_attach(struct request_queue *q, struct elevator_queue *eq, return -ENOMEM;
void *data)
{
q->elevator = eq;
eq->elevator_data = data;
} }
static char chosen_elevator[ELV_NAME_MAX]; static char chosen_elevator[ELV_NAME_MAX];
...@@ -241,7 +237,7 @@ int elevator_init(struct request_queue *q, char *name) ...@@ -241,7 +237,7 @@ int elevator_init(struct request_queue *q, char *name)
{ {
struct elevator_type *e = NULL; struct elevator_type *e = NULL;
struct elevator_queue *eq; struct elevator_queue *eq;
void *data; int err;
if (unlikely(q->elevator)) if (unlikely(q->elevator))
return 0; return 0;
...@@ -278,13 +274,13 @@ int elevator_init(struct request_queue *q, char *name) ...@@ -278,13 +274,13 @@ int elevator_init(struct request_queue *q, char *name)
if (!eq) if (!eq)
return -ENOMEM; return -ENOMEM;
data = elevator_init_queue(q, eq); err = elevator_init_queue(q, eq);
if (!data) { if (err) {
kobject_put(&eq->kobj); kobject_put(&eq->kobj);
return -ENOMEM; return err;
} }
elevator_attach(q, eq, data); q->elevator = eq;
return 0; return 0;
} }
EXPORT_SYMBOL(elevator_init); EXPORT_SYMBOL(elevator_init);
...@@ -856,9 +852,8 @@ static struct kobj_type elv_ktype = { ...@@ -856,9 +852,8 @@ static struct kobj_type elv_ktype = {
.release = elevator_release, .release = elevator_release,
}; };
int elv_register_queue(struct request_queue *q) int __elv_register_queue(struct request_queue *q, struct elevator_queue *e)
{ {
struct elevator_queue *e = q->elevator;
int error; int error;
error = kobject_add(&e->kobj, &q->kobj, "%s", "iosched"); error = kobject_add(&e->kobj, &q->kobj, "%s", "iosched");
...@@ -876,19 +871,22 @@ int elv_register_queue(struct request_queue *q) ...@@ -876,19 +871,22 @@ int elv_register_queue(struct request_queue *q)
} }
return error; return error;
} }
EXPORT_SYMBOL(elv_register_queue);
static void __elv_unregister_queue(struct elevator_queue *e) int elv_register_queue(struct request_queue *q)
{ {
kobject_uevent(&e->kobj, KOBJ_REMOVE); return __elv_register_queue(q, q->elevator);
kobject_del(&e->kobj);
e->registered = 0;
} }
EXPORT_SYMBOL(elv_register_queue);
void elv_unregister_queue(struct request_queue *q) void elv_unregister_queue(struct request_queue *q)
{ {
if (q) if (q) {
__elv_unregister_queue(q->elevator); struct elevator_queue *e = q->elevator;
kobject_uevent(&e->kobj, KOBJ_REMOVE);
kobject_del(&e->kobj);
e->registered = 0;
}
} }
EXPORT_SYMBOL(elv_unregister_queue); EXPORT_SYMBOL(elv_unregister_queue);
...@@ -928,50 +926,36 @@ EXPORT_SYMBOL_GPL(elv_unregister); ...@@ -928,50 +926,36 @@ EXPORT_SYMBOL_GPL(elv_unregister);
static int elevator_switch(struct request_queue *q, struct elevator_type *new_e) 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;
int err; 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 -ENOMEM; return -ENOMEM;
data = elevator_init_queue(q, e); err = elevator_init_queue(q, e);
if (!data) { if (err) {
kobject_put(&e->kobj); kobject_put(&e->kobj);
return -ENOMEM; return err;
} }
/* /* turn on BYPASS and drain all requests w/ elevator private data */
* Turn on BYPASS and drain all requests w/ elevator private data
*/
elv_quiesce_start(q); elv_quiesce_start(q);
/* /* unregister old queue, register new one and kill old elevator */
* Remember old elevator. if (q->elevator->registered) {
*/ elv_unregister_queue(q);
old_elevator = q->elevator; err = __elv_register_queue(q, e);
/*
* attach and start new elevator
*/
spin_lock_irq(q->queue_lock);
elevator_attach(q, e, data);
spin_unlock_irq(q->queue_lock);
if (old_elevator->registered) {
__elv_unregister_queue(old_elevator);
err = elv_register_queue(q);
if (err) if (err)
goto fail_register; goto fail_register;
} }
/* /* done, replace the old one with new one and turn off BYPASS */
* finally exit old elevator and turn off BYPASS. spin_lock_irq(q->queue_lock);
*/ old_elevator = q->elevator;
q->elevator = e;
spin_unlock_irq(q->queue_lock);
elevator_exit(old_elevator); elevator_exit(old_elevator);
elv_quiesce_end(q); elv_quiesce_end(q);
...@@ -985,7 +969,6 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e) ...@@ -985,7 +969,6 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
* one again (along with re-adding the sysfs dir) * one again (along with re-adding the sysfs dir)
*/ */
elevator_exit(e); elevator_exit(e);
q->elevator = old_elevator;
elv_register_queue(q); elv_register_queue(q);
elv_quiesce_end(q); elv_quiesce_end(q);
......
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