Commit ce8ee858 authored by Ming Lei's avatar Ming Lei Committed by Jens Axboe
Browse files

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: default avatarYi Zhang <yi.zhang@redhat.com>
Closes: https://lore.kernel.org/linux-block/CAHj4cs-em-4acsHabMdT=jJhXkCzjnprD-aQH1OgrZo4nTnmMw@mail.gmail.com/


Fixes: 626ff4f8 ("blk-mq: convert to serialize updating nr_requests with update_nr_hwq_lock")
Signed-off-by: default avatarMing Lei <ming.lei@redhat.com>
Tested-by: default avatarYi Zhang <yi.zhang@redhat.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent d90c470b
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -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()
	 * 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)
		goto unlock;
+11 −1
Original line number Diff line number Diff line
@@ -807,7 +807,16 @@ ssize_t elv_iosched_store(struct gendisk *disk, const char *buf,
	elv_iosched_load_module(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)) {
		ret = elevator_change(q, &ctx);
		if (!ret)
@@ -817,6 +826,7 @@ ssize_t elv_iosched_store(struct gendisk *disk, const char *buf,
	}
	up_read(&set->update_nr_hwq_lock);

out:
	if (ctx.type)
		elevator_put(ctx.type);
	return ret;