Commit 5cf9c91b authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Jens Axboe
Browse files

block: serialize all debugfs operations using q->debugfs_mutex



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>
parent 50e34d78
Loading
Loading
Loading
Loading
+20 −5
Original line number Diff line number Diff line
@@ -711,11 +711,6 @@ void blk_mq_debugfs_register(struct request_queue *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)
{
@@ -746,6 +741,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;
@@ -773,6 +770,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.
@@ -790,6 +789,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;
}
@@ -811,6 +812,10 @@ static const char *rq_qos_id_to_name(enum rq_qos_id id)

void blk_mq_debugfs_unregister_rqos(struct rq_qos *rqos)
{
	lockdep_assert_held(&rqos->q->debugfs_mutex);

	if (!rqos->q->debugfs_dir)
		return;
	debugfs_remove_recursive(rqos->debugfs_dir);
	rqos->debugfs_dir = NULL;
}
@@ -820,6 +825,8 @@ void blk_mq_debugfs_register_rqos(struct rq_qos *rqos)
	struct request_queue *q = rqos->q;
	const char *dir_name = rq_qos_id_to_name(rqos->id);

	lockdep_assert_held(&q->debugfs_mutex);

	if (rqos->debugfs_dir || !rqos->ops->debugfs_attrs)
		return;

@@ -835,6 +842,8 @@ void blk_mq_debugfs_register_rqos(struct rq_qos *rqos)

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

	debugfs_remove_recursive(q->rqos_debugfs_dir);
	q->rqos_debugfs_dir = NULL;
}
@@ -844,6 +853,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
@@ -863,6 +874,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
@@ -21,7 +21,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);
@@ -42,10 +41,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
@@ -594,7 +594,9 @@ int blk_mq_init_sched(struct request_queue *q, struct elevator_type *e)
	if (ret)
		goto err_free_map_and_rqs;

	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.init_hctx) {
@@ -607,7 +609,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;
@@ -648,14 +652,21 @@ void blk_mq_exit_sched(struct request_queue *q, struct elevator_queue *e)
	unsigned int flags = 0;

	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.exit_hctx && hctx->sched_data) {
			e->type->ops.exit_hctx(hctx, i);
			hctx->sched_data = NULL;
		}
		flags = hctx->flags;
	}

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

	if (e->type->ops.exit_sched)
		e->type->ops.exit_sched(e);
	blk_mq_sched_tags_teardown(q, flags);
+2 −0
Original line number Diff line number Diff line
@@ -294,7 +294,9 @@ void rq_qos_wait(struct rq_wait *rqw, void *private_data,

void rq_qos_exit(struct request_queue *q)
{
	mutex_lock(&q->debugfs_mutex);
	blk_mq_debugfs_unregister_queue_rqos(q);
	mutex_unlock(&q->debugfs_mutex);

	while (q->rq_qos) {
		struct rq_qos *rqos = q->rq_qos;
+6 −1
Original line number Diff line number Diff line
@@ -104,8 +104,11 @@ static inline void rq_qos_add(struct request_queue *q, struct rq_qos *rqos)

	blk_mq_unfreeze_queue(q);

	if (rqos->ops->debugfs_attrs)
	if (rqos->ops->debugfs_attrs) {
		mutex_lock(&q->debugfs_mutex);
		blk_mq_debugfs_register_rqos(rqos);
		mutex_unlock(&q->debugfs_mutex);
	}
}

static inline void rq_qos_del(struct request_queue *q, struct rq_qos *rqos)
@@ -129,7 +132,9 @@ static inline void rq_qos_del(struct request_queue *q, struct rq_qos *rqos)

	blk_mq_unfreeze_queue(q);

	mutex_lock(&q->debugfs_mutex);
	blk_mq_debugfs_unregister_rqos(rqos);
	mutex_unlock(&q->debugfs_mutex);
}

typedef bool (acquire_inflight_cb_t)(struct rq_wait *rqw, void *private_data);
Loading