From: Nick Piggin This moves all the elevator selection and crazy stuff into elevator.c. ll_rw_blk.c just has to pass a string to elevator_alloc. "noop", "cfq", etc. and falls back to default if requested one does not exist. This actually now makes driver based elevator selection possible without them having to use ifdefs for conditional compilation and extern elevator_t iosched_blah. drivers/block/elevator.c | 90 ++++++++++++++++++++++++++++++++++++++-------- drivers/block/ll_rw_blk.c | 88 ++++++++++---------------------------------- include/linux/elevator.h | 27 +------------ 3 files changed, 100 insertions(+), 105 deletions(-) diff -puN drivers/block/elevator.c~elv-init-cleanup drivers/block/elevator.c --- 25/drivers/block/elevator.c~elv-init-cleanup 2003-10-17 19:07:38.000000000 -0700 +++ 25-akpm/drivers/block/elevator.c 2003-10-17 19:07:38.000000000 -0700 @@ -37,6 +37,12 @@ #include +/* These may not exist - must check CONFIG_IOSCHED_* */ +extern elevator_t elevator_noop; +extern elevator_t iosched_deadline; +extern elevator_t iosched_as; +extern elevator_t iosched_cfq; + /* * can we safely merge with this request? */ @@ -86,6 +92,49 @@ inline int elv_try_last_merge(request_qu return ELEVATOR_NO_MERGE; } +static elevator_t *default_elevator = +#if defined(CONFIG_IOSCHED_AS) + &iosched_as; +#elif defined(CONFIG_IOSCHED_DEADLINE) + &iosched_deadline; +#elif defined(CONFIG_IOSCHED_CFQ) + &iosched_cfq; +#elif defined(CONFIG_IOSCHED_NOOP) + &elevator_noop; +#else + NULL; +#error "You must have at least 1 I/O scheduler selected" +#endif + +static elevator_t *str_to_elv(const char *str) +{ + if (!strncmp(str, "default", strlen("default"))) + return default_elevator; + +#ifdef CONFIG_IOSCHED_DEADLINE + if (!strncmp(str, iosched_deadline.elevator_name, + strlen(iosched_deadline.elevator_name))) + return &iosched_deadline; +#endif +#ifdef CONFIG_IOSCHED_AS + if (!strncmp(str, iosched_as.elevator_name, + strlen(iosched_as.elevator_name))) + return &iosched_as; +#endif +#ifdef CONFIG_IOSCHED_CFQ + if (!strncmp(str, iosched_cfq.elevator_name, + strlen(iosched_cfq.elevator_name))) + return &iosched_cfq; +#endif +#ifdef CONFIG_IOSCHED_NOOP + if (!strncmp(str, elevator_noop.elevator_name, + strlen(elevator_noop.elevator_name))) + return &elevator_noop; +#endif + + return NULL; +} + /* * general block -> elevator interface starts here */ @@ -110,14 +159,22 @@ void elevator_exit(request_queue_t *q) e->elevator_exit_fn(q, e); } -elevator_t *elevator_alloc(elevator_t *type) +elevator_t *elevator_alloc(const char *type) { - elevator_t *e = kmalloc(sizeof(*type), GFP_KERNEL); + elevator_t *e, *elv_type; + + elv_type = str_to_elv(type); + if (elv_type == NULL) { + printk(KERN_INFO "Unknown elevator %s. Using default\n", type); + elv_type = default_elevator; + } + + e = kmalloc(sizeof(*elv_type), GFP_KERNEL); if (e == NULL) goto out_err; - memcpy(e, type, sizeof(*e)); + memcpy(e, elv_type, sizeof(*e)); if (e->elevator_alloc_fn) if (e->elevator_alloc_fn(e)) @@ -355,12 +412,8 @@ static struct kobj_type default_ktype = .release = &elevator_release, }; -int elv_register_queue(struct request_queue *q) +int elv_register_queue(struct request_queue *q, elevator_t *e) { - elevator_t *e; - - e = q->elevator; - e->kobj.parent = kobject_get(&q->kobj); if (!e->kobj.parent) return -EBUSY; @@ -375,15 +428,24 @@ int elv_register_queue(struct request_qu return kobject_register(&e->kobj); } -void elv_unregister_queue(struct request_queue *q) +void elv_unregister_queue(struct request_queue *q, elevator_t *e) { - if (q) { - elevator_t *e = q->elevator; - kobject_unregister(&e->kobj); - kobject_put(&q->kobj); - } + kobject_unregister(&e->kobj); + kobject_put(&q->kobj); +} + +/* boot-time set default */ +static int __init elevator_setup(char *str) +{ + elevator_t *e = str_to_elv(str); + if (e != NULL) + default_elevator = e; + + return 1; } +__setup("elevator=", elevator_setup); + module_init(elevator_global_init); EXPORT_SYMBOL(elv_add_request); diff -puN drivers/block/ll_rw_blk.c~elv-init-cleanup drivers/block/ll_rw_blk.c --- 25/drivers/block/ll_rw_blk.c~elv-init-cleanup 2003-10-17 19:07:38.000000000 -0700 +++ 25-akpm/drivers/block/ll_rw_blk.c 2003-10-17 19:07:38.000000000 -0700 @@ -1356,52 +1356,6 @@ static int blk_init_free_list(request_qu static int __make_request(request_queue_t *, struct bio *); -static elevator_t *chosen_elevator = -#if defined(CONFIG_IOSCHED_AS) - &iosched_as; -#elif defined(CONFIG_IOSCHED_DEADLINE) - &iosched_deadline; -#elif defined(CONFIG_IOSCHED_CFQ) - &iosched_cfq; -#elif defined(CONFIG_IOSCHED_NOOP) - &elevator_noop; -#else - NULL; -#error "You must have at least 1 I/O scheduler selected" -#endif - -elevator_t *str_to_elv(const char *str) -{ -#ifdef CONFIG_IOSCHED_DEADLINE - if (!strncmp(str, "deadline", strlen("deadline"))) - return &iosched_deadline; -#endif -#ifdef CONFIG_IOSCHED_AS - if (!strncmp(str, "as", strlen("as"))) - return &iosched_as; -#endif -#ifdef CONFIG_IOSCHED_CFQ - if (!strncmp(str, "cfq", strlen("cfq"))) - return &iosched_cfq; -#endif -#ifdef CONFIG_IOSCHED_NOOP - if (!strncmp(str, "noop", strlen("noop"))) - return &elevator_noop; -#endif - - return NULL; -} - -static int __init elevator_setup(char *str) -{ - elevator_t *e = str_to_elv(str); - if (e != NULL) - chosen_elevator = e; - - return 1; -} - -__setup("elevator=", elevator_setup); request_queue_t *blk_alloc_queue(int gfp_mask) { @@ -1461,7 +1415,7 @@ request_queue_t *blk_init_queue(request_ if (blk_init_free_list(q)) goto out_init; - e = elevator_alloc(chosen_elevator); + e = elevator_alloc("default"); if (!e) goto out_elv; @@ -2855,27 +2809,27 @@ queue_var_store(unsigned long *var, cons static ssize_t queue_elevator_show(struct request_queue *q, char *page) { - return sprintf(page, "%s\n", q->elevator->elevator_name); + int ret; + unsigned long flags; + spin_lock_irqsave(q->queue_lock, flags); + ret = sprintf(page, "%s\n", q->elevator->elevator_name); + spin_unlock_irqrestore(q->queue_lock, flags); + + return ret; } static ssize_t queue_elevator_store(struct request_queue *q, const char *page, size_t count) { - elevator_t *type, *elv; + elevator_t *e, *old_elv; unsigned long flags; static DECLARE_MUTEX(switch_mutex); down(&switch_mutex); - type = str_to_elv(page); - if (type == NULL) { + e = elevator_alloc(page); + if (!e) goto out; - } - - elv = elevator_alloc(type); - if (!elv) { - goto out; - } spin_lock_irqsave(q->queue_lock, flags); @@ -2883,21 +2837,21 @@ queue_elevator_store(struct request_queu blk_set_queue_drain(q); blk_wait_free_list(q); + WARN_ON(!elv_queue_empty(q)); + /* Stop old elevator */ + old_elv = q->elevator; elevator_exit(q); - /* Unlock here should be OK. The elevator should not be entered because - * the queue is drained, and blocked... */ - spin_unlock_irqrestore(q->queue_lock, flags); - elv_unregister_queue(q); - spin_lock_irqsave(q->queue_lock, flags); - /* Start new one */ - elevator_init(q, elv); + elevator_init(q, e); printk(KERN_INFO "elevator_init %s\n", q->elevator->elevator_name); + /* Unlock here should be OK. The elevator should not be entered because + * the queue is drained, and blocked... */ spin_unlock_irqrestore(q->queue_lock, flags); - if (elv_register_queue(q)) { + elv_unregister_queue(q, old_elv); + if (elv_register_queue(q, e)) { /* * Can't do much about it now... failure should not cause the * device to stop working or future elevator selection to stop @@ -3039,7 +2993,7 @@ int blk_register_queue(struct gendisk *d return ret; if (q->elevator) { - ret = elv_register_queue(q); + ret = elv_register_queue(q, q->elevator); if (ret) { kobject_unregister(&q->kobj); return ret; @@ -3055,7 +3009,7 @@ void blk_unregister_queue(struct gendisk if (q) { if (q->elevator) - elv_unregister_queue(q); + elv_unregister_queue(q, q->elevator); kobject_unregister(&q->kobj); kobject_put(&disk->kobj); diff -puN include/linux/elevator.h~elv-init-cleanup include/linux/elevator.h --- 25/include/linux/elevator.h~elv-init-cleanup 2003-10-17 19:07:38.000000000 -0700 +++ 25-akpm/include/linux/elevator.h 2003-10-17 19:07:38.000000000 -0700 @@ -75,37 +75,16 @@ extern int elv_queue_empty(request_queue extern struct request *elv_next_request(struct request_queue *q); extern struct request *elv_former_request(request_queue_t *, struct request *); extern struct request *elv_latter_request(request_queue_t *, struct request *); -extern int elv_register_queue(request_queue_t *q); -extern void elv_unregister_queue(request_queue_t *q); +extern int elv_register_queue(request_queue_t *q, elevator_t *e); +extern void elv_unregister_queue(request_queue_t *q, elevator_t *e); extern int elv_may_queue(request_queue_t *, int); extern void elv_completed_request(request_queue_t *, struct request *); extern int elv_set_request(request_queue_t *, struct request *, int); extern void elv_put_request(request_queue_t *, struct request *); -/* - * noop I/O scheduler. always merges, always inserts new request at tail - */ -extern elevator_t elevator_noop; - -/* - * deadline i/o scheduler. uses request time outs to prevent indefinite - * starvation - */ -extern elevator_t iosched_deadline; - -/* - * anticipatory I/O scheduler - */ -extern elevator_t iosched_as; - -/* - * completely fair queueing I/O scheduler - */ -extern elevator_t iosched_cfq; - extern void elevator_init(request_queue_t *, elevator_t *); extern void elevator_exit(request_queue_t *); -extern elevator_t *elevator_alloc(elevator_t *); +extern elevator_t *elevator_alloc(const char *); extern void elevator_release(struct kobject *); extern inline int elv_rq_merge_ok(struct request *, struct bio *); extern inline int elv_try_merge(struct request *, struct bio *); _