Commit 8196738e authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Yu Kuai
Browse files

block: serialize all debugfs operations using q->debugfs_mutex

mainline inclusion
from mainline-v5.19-rc4
commit 5cf9c91b
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IAGRKP
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=5cf9c91ba927119fc6606b938b1895bb2459d3bc



--------------------------------

Various places like I/O schedulers or the QOS infrastructure try to
register debugfs files on demans, which can race with creating and
removing the main queue debugfs directory.  Use the existing
debugfs_mutex to serialize all debugfs operations that rely on
q->debugfs_dir or the directories hanging off it.

To make the teardown code a little simpler declare all debugfs dentry
pointers and not just the main one uncoditionally in blkdev.h.

Move debugfs_mutex next to the dentries that it protects and document
what it is used for.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/20220614074827.458955-3-hch@lst.de


Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
Conflicts:
	block/blk-mq-debugfs.h
	block/blk-mq-debugfs.c
	block/blk-mq-sched.c
	block/blk-rq-qos.c
	block/blk-rq-qos.h
	block/blk-sysfs.c
	block/blk-io-hierarchy/debugfs.c
	block/blk-io-hierarchy/stats.c
	include/linux/blkdev.h
	kernel/trace/blktrace.c
[Context conflicts]
Signed-off-by: default avatarYu Kuai <yukuai3@huawei.com>
parent 9134f0c1
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -198,6 +198,8 @@ void blk_mq_debugfs_register_hierarchy(struct request_queue *q,
	struct blk_io_hierarchy_stats *stats =
		queue_to_wrapper(q)->io_hierarchy_stats;

	lockdep_assert_held(&q->debugfs_mutex);

	if (!blk_mq_hierarchy_registered(q, stage) ||
	    !blk_mq_debugfs_enabled(q))
		return;
@@ -211,6 +213,8 @@ void blk_mq_debugfs_unregister_hierarchy(struct request_queue *q,
	struct blk_io_hierarchy_stats *stats =
		queue_to_wrapper(q)->io_hierarchy_stats;

	lockdep_assert_held(&q->debugfs_mutex);

	if (!blk_mq_hierarchy_registered(q, stage) ||
	    !blk_mq_debugfs_enabled(q))
		return;
@@ -223,6 +227,8 @@ void blk_mq_debugfs_create_default_hierarchy_attr(struct request_queue *q)
	struct blk_io_hierarchy_stats *stats =
		queue_to_wrapper(q)->io_hierarchy_stats;

	lockdep_assert_held(&q->debugfs_mutex);

	if (!blk_mq_debugfs_enabled(q))
		return;

+8 −0
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@ void blk_mq_debugfs_register_hierarchy_stats(struct request_queue *q)
	struct blk_io_hierarchy_stats *stats;
	enum stage_group stage;

	lockdep_assert_held(&q->debugfs_mutex);

	stats = queue_to_wrapper(q)->io_hierarchy_stats;
	if (!stats || !blk_mq_debugfs_enabled(q))
		return;
@@ -203,8 +205,10 @@ void blk_mq_register_hierarchy(struct request_queue *q, enum stage_group stage)

	blk_mq_freeze_queue(q);

	mutex_lock(&q->debugfs_mutex);
	WRITE_ONCE(stats->hstage[stage], hstage);
	blk_mq_debugfs_register_hierarchy(q, stage);
	mutex_unlock(&q->debugfs_mutex);

	blk_mq_unfreeze_queue(q);
}
@@ -220,6 +224,8 @@ void blk_mq_unregister_hierarchy(struct request_queue *q,
	if (!blk_mq_hierarchy_registered(q, stage))
		return;

	mutex_lock(&q->debugfs_mutex);

	blk_mq_debugfs_unregister_hierarchy(q, stage);
	blk_io_hierarchy_iodump_exit(q, stage);

@@ -230,6 +236,8 @@ void blk_mq_unregister_hierarchy(struct request_queue *q,
	spin_unlock(&stats->hstage_lock);

	kfree(hstage);

	mutex_unlock(&q->debugfs_mutex);
}
EXPORT_SYMBOL_GPL(blk_mq_unregister_hierarchy);

+12 −5
Original line number Diff line number Diff line
@@ -862,11 +862,6 @@ void blk_mq_debugfs_register(struct request_queue *q)
	blk_mq_debugfs_register_hierarchy_stats(q);
}

void blk_mq_debugfs_unregister(struct request_queue *q)
{
	q->sched_debugfs_dir = NULL;
}

static void blk_mq_debugfs_register_ctx(struct blk_mq_hw_ctx *hctx,
					struct blk_mq_ctx *ctx)
{
@@ -900,6 +895,8 @@ void blk_mq_debugfs_register_hctx(struct request_queue *q,

void blk_mq_debugfs_unregister_hctx(struct blk_mq_hw_ctx *hctx)
{
	if (!hctx->queue->debugfs_dir)
		return;
	debugfs_remove_recursive(hctx->debugfs_dir);
	hctx->sched_debugfs_dir = NULL;
	hctx->debugfs_dir = NULL;
@@ -927,6 +924,8 @@ void blk_mq_debugfs_register_sched(struct request_queue *q)
{
	struct elevator_type *e = q->elevator->type;

	lockdep_assert_held(&q->debugfs_mutex);

	/*
	 * If the parent directory has not been created yet, return, we will be
	 * called again later on and the directory/files will be created then.
@@ -944,6 +943,8 @@ void blk_mq_debugfs_register_sched(struct request_queue *q)

void blk_mq_debugfs_unregister_sched(struct request_queue *q)
{
	lockdep_assert_held(&q->debugfs_mutex);

	debugfs_remove_recursive(q->sched_debugfs_dir);
	q->sched_debugfs_dir = NULL;
}
@@ -953,6 +954,8 @@ void blk_mq_debugfs_register_sched_hctx(struct request_queue *q,
{
	struct elevator_type *e = q->elevator->type;

	lockdep_assert_held(&q->debugfs_mutex);

	/*
	 * If the parent debugfs directory has not been created yet, return;
	 * We will be called again later on with appropriate parent debugfs
@@ -972,6 +975,10 @@ void blk_mq_debugfs_register_sched_hctx(struct request_queue *q,

void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx)
{
	lockdep_assert_held(&hctx->queue->debugfs_mutex);

	if (!hctx->queue->debugfs_dir)
		return;
	debugfs_remove_recursive(hctx->sched_debugfs_dir);
	hctx->sched_debugfs_dir = NULL;
}
+0 −5
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ int __blk_mq_debugfs_rq_show(struct seq_file *m, struct request *rq);
int blk_mq_debugfs_rq_show(struct seq_file *m, void *v);

void blk_mq_debugfs_register(struct request_queue *q);
void blk_mq_debugfs_unregister(struct request_queue *q);
void blk_mq_debugfs_register_hctx(struct request_queue *q,
				 struct blk_mq_hw_ctx *hctx);
void blk_mq_debugfs_unregister_hctx(struct blk_mq_hw_ctx *hctx);
@@ -46,10 +45,6 @@ static inline void blk_mq_debugfs_register(struct request_queue *q)
{
}

static inline void blk_mq_debugfs_unregister(struct request_queue *q)
{
}

static inline void blk_mq_debugfs_register_hctx(struct request_queue *q,
						struct blk_mq_hw_ctx *hctx)
{
+11 −0
Original line number Diff line number Diff line
@@ -609,7 +609,9 @@ int blk_mq_init_sched(struct request_queue *q, struct elevator_type *e)
	if (ret)
		goto err;

	mutex_lock(&q->debugfs_mutex);
	blk_mq_debugfs_register_sched(q);
	mutex_unlock(&q->debugfs_mutex);

	queue_for_each_hw_ctx(q, hctx, i) {
		if (e->ops.mq.init_hctx) {
@@ -621,7 +623,9 @@ int blk_mq_init_sched(struct request_queue *q, struct elevator_type *e)
				return ret;
			}
		}
		mutex_lock(&q->debugfs_mutex);
		blk_mq_debugfs_register_sched_hctx(q, hctx);
		mutex_unlock(&q->debugfs_mutex);
	}

	return 0;
@@ -638,13 +642,20 @@ void blk_mq_exit_sched(struct request_queue *q, struct elevator_queue *e)
	unsigned int i;

	queue_for_each_hw_ctx(q, hctx, i) {
		mutex_lock(&q->debugfs_mutex);
		blk_mq_debugfs_unregister_sched_hctx(hctx);
		mutex_unlock(&q->debugfs_mutex);

		if (e->type->ops.mq.exit_hctx && hctx->sched_data) {
			e->type->ops.mq.exit_hctx(hctx, i);
			hctx->sched_data = NULL;
		}
	}

	mutex_lock(&q->debugfs_mutex);
	blk_mq_debugfs_unregister_sched(q);
	mutex_unlock(&q->debugfs_mutex);

	if (e->type->ops.mq.exit_sched)
		e->type->ops.mq.exit_sched(e);
	blk_mq_sched_tags_teardown(q);
Loading