diff --git a/block/blk-mq-sched.c b/block/blk-mq-sched.c index a4f7c101b53b..68227240fdea 100644 --- a/block/blk-mq-sched.c +++ b/block/blk-mq-sched.c @@ -555,6 +555,7 @@ static int blk_mq_init_sched_shared_tags(struct request_queue *queue) return 0; } +/* caller must have a reference to @e, will grab another one if successful */ int blk_mq_init_sched(struct request_queue *q, struct elevator_type *e) { unsigned int flags = q->tag_set->flags; diff --git a/block/blk-mq.c b/block/blk-mq.c index 9db8814cdd02..098432d3caf1 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -4591,6 +4591,8 @@ static void blk_mq_elv_switch_back(struct list_head *head, mutex_lock(&q->sysfs_lock); elevator_switch(q, t); + /* drop the reference acquired in blk_mq_elv_switch_none */ + elevator_put(t); mutex_unlock(&q->sysfs_lock); } diff --git a/block/elevator.c b/block/elevator.c index 61d5655a3819..d26aa787e29f 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -165,6 +165,7 @@ struct elevator_queue *elevator_alloc(struct request_queue *q, if (unlikely(!eq)) return NULL; + __elevator_get(e); eq->type = e; kobject_init(&eq->kobj, &elv_ktype); mutex_init(&eq->sysfs_lock); @@ -704,8 +705,9 @@ void elevator_init_mq(struct request_queue *q) if (err) { pr_warn("\"%s\" elevator initialization failed, " "falling back to \"none\"\n", e->elevator_name); - elevator_put(e); } + + elevator_put(e); } /* @@ -737,6 +739,7 @@ int elevator_switch(struct request_queue *q, struct elevator_type *new_e) static int elevator_change(struct request_queue *q, const char *elevator_name) { struct elevator_type *e; + int ret; /* Make sure queue is not in the middle of being removed */ if (!blk_queue_registered(q)) @@ -757,8 +760,9 @@ static int elevator_change(struct request_queue *q, const char *elevator_name) e = elevator_get(q, elevator_name, true); if (!e) return -EINVAL; - - return elevator_switch(q, e); + ret = elevator_switch(q, e); + elevator_put(e); + return ret; } ssize_t elv_iosched_store(struct request_queue *q, const char *buf,