block: use trylock to avoid lockdep circular dependency in sysfs
Use trylock instead of blocking lock acquisition for update_nr_hwq_lock
in queue_requests_store() and elv_iosched_store() to avoid circular lock
dependency with kernfs active reference during concurrent disk deletion:
update_nr_hwq_lock -> kn->active (via del_gendisk -> kobject_del)
kn->active -> update_nr_hwq_lock (via sysfs write path)
Return -EBUSY when the lock is not immediately available.
Reported-and-tested-by: Yi Zhang <yi.zhang@redhat.com>
Closes: https://lore.kernel.org/linux-block/CAHj4cs-em-4acsHabMdT=jJhXkCzjnprD-aQH1OgrZo4nTnmMw@mail.gmail.com/
Fixes: 626ff4f8eb ("blk-mq: convert to serialize updating nr_requests with update_nr_hwq_lock")
Signed-off-by: Ming Lei <ming.lei@redhat.com>
Tested-by: Yi Zhang <yi.zhang@redhat.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
master
parent
d90c470b0e
commit
ce8ee8583e
|
|
@ -78,8 +78,14 @@ queue_requests_store(struct gendisk *disk, const char *page, size_t count)
|
||||||
/*
|
/*
|
||||||
* Serialize updating nr_requests with concurrent queue_requests_store()
|
* Serialize updating nr_requests with concurrent queue_requests_store()
|
||||||
* and switching elevator.
|
* and switching elevator.
|
||||||
|
*
|
||||||
|
* Use trylock to avoid circular lock dependency with kernfs active
|
||||||
|
* reference during concurrent disk deletion:
|
||||||
|
* update_nr_hwq_lock -> kn->active (via del_gendisk -> kobject_del)
|
||||||
|
* kn->active -> update_nr_hwq_lock (via this sysfs write path)
|
||||||
*/
|
*/
|
||||||
down_write(&set->update_nr_hwq_lock);
|
if (!down_write_trylock(&set->update_nr_hwq_lock))
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
if (nr == q->nr_requests)
|
if (nr == q->nr_requests)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
|
||||||
|
|
@ -807,7 +807,16 @@ ssize_t elv_iosched_store(struct gendisk *disk, const char *buf,
|
||||||
elv_iosched_load_module(ctx.name);
|
elv_iosched_load_module(ctx.name);
|
||||||
ctx.type = elevator_find_get(ctx.name);
|
ctx.type = elevator_find_get(ctx.name);
|
||||||
|
|
||||||
down_read(&set->update_nr_hwq_lock);
|
/*
|
||||||
|
* Use trylock to avoid circular lock dependency with kernfs active
|
||||||
|
* reference during concurrent disk deletion:
|
||||||
|
* update_nr_hwq_lock -> kn->active (via del_gendisk -> kobject_del)
|
||||||
|
* kn->active -> update_nr_hwq_lock (via this sysfs write path)
|
||||||
|
*/
|
||||||
|
if (!down_read_trylock(&set->update_nr_hwq_lock)) {
|
||||||
|
ret = -EBUSY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
if (!blk_queue_no_elv_switch(q)) {
|
if (!blk_queue_no_elv_switch(q)) {
|
||||||
ret = elevator_change(q, &ctx);
|
ret = elevator_change(q, &ctx);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
|
|
@ -817,6 +826,7 @@ ssize_t elv_iosched_store(struct gendisk *disk, const char *buf,
|
||||||
}
|
}
|
||||||
up_read(&set->update_nr_hwq_lock);
|
up_read(&set->update_nr_hwq_lock);
|
||||||
|
|
||||||
|
out:
|
||||||
if (ctx.type)
|
if (ctx.type)
|
||||||
elevator_put(ctx.type);
|
elevator_put(ctx.type);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue