Skip to content

Commit 5cf9c91

Browse files
Christoph Hellwigaxboe
authored andcommitted
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: Christoph Hellwig <hch@lst.de> Link: https://lore.kernel.org/r/20220614074827.458955-3-hch@lst.de Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 50e34d7 commit 5cf9c91

File tree

8 files changed

+52
-29
lines changed

8 files changed

+52
-29
lines changed

block/blk-mq-debugfs.c

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -711,11 +711,6 @@ void blk_mq_debugfs_register(struct request_queue *q)
711711
}
712712
}
713713

714-
void blk_mq_debugfs_unregister(struct request_queue *q)
715-
{
716-
q->sched_debugfs_dir = NULL;
717-
}
718-
719714
static void blk_mq_debugfs_register_ctx(struct blk_mq_hw_ctx *hctx,
720715
struct blk_mq_ctx *ctx)
721716
{
@@ -746,6 +741,8 @@ void blk_mq_debugfs_register_hctx(struct request_queue *q,
746741

747742
void blk_mq_debugfs_unregister_hctx(struct blk_mq_hw_ctx *hctx)
748743
{
744+
if (!hctx->queue->debugfs_dir)
745+
return;
749746
debugfs_remove_recursive(hctx->debugfs_dir);
750747
hctx->sched_debugfs_dir = NULL;
751748
hctx->debugfs_dir = NULL;
@@ -773,6 +770,8 @@ void blk_mq_debugfs_register_sched(struct request_queue *q)
773770
{
774771
struct elevator_type *e = q->elevator->type;
775772

773+
lockdep_assert_held(&q->debugfs_mutex);
774+
776775
/*
777776
* If the parent directory has not been created yet, return, we will be
778777
* 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)
790789

791790
void blk_mq_debugfs_unregister_sched(struct request_queue *q)
792791
{
792+
lockdep_assert_held(&q->debugfs_mutex);
793+
793794
debugfs_remove_recursive(q->sched_debugfs_dir);
794795
q->sched_debugfs_dir = NULL;
795796
}
@@ -811,6 +812,10 @@ static const char *rq_qos_id_to_name(enum rq_qos_id id)
811812

812813
void blk_mq_debugfs_unregister_rqos(struct rq_qos *rqos)
813814
{
815+
lockdep_assert_held(&rqos->q->debugfs_mutex);
816+
817+
if (!rqos->q->debugfs_dir)
818+
return;
814819
debugfs_remove_recursive(rqos->debugfs_dir);
815820
rqos->debugfs_dir = NULL;
816821
}
@@ -820,6 +825,8 @@ void blk_mq_debugfs_register_rqos(struct rq_qos *rqos)
820825
struct request_queue *q = rqos->q;
821826
const char *dir_name = rq_qos_id_to_name(rqos->id);
822827

828+
lockdep_assert_held(&q->debugfs_mutex);
829+
823830
if (rqos->debugfs_dir || !rqos->ops->debugfs_attrs)
824831
return;
825832

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

836843
void blk_mq_debugfs_unregister_queue_rqos(struct request_queue *q)
837844
{
845+
lockdep_assert_held(&q->debugfs_mutex);
846+
838847
debugfs_remove_recursive(q->rqos_debugfs_dir);
839848
q->rqos_debugfs_dir = NULL;
840849
}
@@ -844,6 +853,8 @@ void blk_mq_debugfs_register_sched_hctx(struct request_queue *q,
844853
{
845854
struct elevator_type *e = q->elevator->type;
846855

856+
lockdep_assert_held(&q->debugfs_mutex);
857+
847858
/*
848859
* If the parent debugfs directory has not been created yet, return;
849860
* 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,
863874

864875
void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx)
865876
{
877+
lockdep_assert_held(&hctx->queue->debugfs_mutex);
878+
879+
if (!hctx->queue->debugfs_dir)
880+
return;
866881
debugfs_remove_recursive(hctx->sched_debugfs_dir);
867882
hctx->sched_debugfs_dir = NULL;
868883
}

block/blk-mq-debugfs.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ int __blk_mq_debugfs_rq_show(struct seq_file *m, struct request *rq);
2121
int blk_mq_debugfs_rq_show(struct seq_file *m, void *v);
2222

2323
void blk_mq_debugfs_register(struct request_queue *q);
24-
void blk_mq_debugfs_unregister(struct request_queue *q);
2524
void blk_mq_debugfs_register_hctx(struct request_queue *q,
2625
struct blk_mq_hw_ctx *hctx);
2726
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)
4241
{
4342
}
4443

45-
static inline void blk_mq_debugfs_unregister(struct request_queue *q)
46-
{
47-
}
48-
4944
static inline void blk_mq_debugfs_register_hctx(struct request_queue *q,
5045
struct blk_mq_hw_ctx *hctx)
5146
{

block/blk-mq-sched.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,9 @@ int blk_mq_init_sched(struct request_queue *q, struct elevator_type *e)
594594
if (ret)
595595
goto err_free_map_and_rqs;
596596

597+
mutex_lock(&q->debugfs_mutex);
597598
blk_mq_debugfs_register_sched(q);
599+
mutex_unlock(&q->debugfs_mutex);
598600

599601
queue_for_each_hw_ctx(q, hctx, i) {
600602
if (e->ops.init_hctx) {
@@ -607,7 +609,9 @@ int blk_mq_init_sched(struct request_queue *q, struct elevator_type *e)
607609
return ret;
608610
}
609611
}
612+
mutex_lock(&q->debugfs_mutex);
610613
blk_mq_debugfs_register_sched_hctx(q, hctx);
614+
mutex_unlock(&q->debugfs_mutex);
611615
}
612616

613617
return 0;
@@ -648,14 +652,21 @@ void blk_mq_exit_sched(struct request_queue *q, struct elevator_queue *e)
648652
unsigned int flags = 0;
649653

650654
queue_for_each_hw_ctx(q, hctx, i) {
655+
mutex_lock(&q->debugfs_mutex);
651656
blk_mq_debugfs_unregister_sched_hctx(hctx);
657+
mutex_unlock(&q->debugfs_mutex);
658+
652659
if (e->type->ops.exit_hctx && hctx->sched_data) {
653660
e->type->ops.exit_hctx(hctx, i);
654661
hctx->sched_data = NULL;
655662
}
656663
flags = hctx->flags;
657664
}
665+
666+
mutex_lock(&q->debugfs_mutex);
658667
blk_mq_debugfs_unregister_sched(q);
668+
mutex_unlock(&q->debugfs_mutex);
669+
659670
if (e->type->ops.exit_sched)
660671
e->type->ops.exit_sched(e);
661672
blk_mq_sched_tags_teardown(q, flags);

block/blk-rq-qos.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,9 @@ void rq_qos_wait(struct rq_wait *rqw, void *private_data,
294294

295295
void rq_qos_exit(struct request_queue *q)
296296
{
297+
mutex_lock(&q->debugfs_mutex);
297298
blk_mq_debugfs_unregister_queue_rqos(q);
299+
mutex_unlock(&q->debugfs_mutex);
298300

299301
while (q->rq_qos) {
300302
struct rq_qos *rqos = q->rq_qos;

block/blk-rq-qos.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,11 @@ static inline void rq_qos_add(struct request_queue *q, struct rq_qos *rqos)
104104

105105
blk_mq_unfreeze_queue(q);
106106

107-
if (rqos->ops->debugfs_attrs)
107+
if (rqos->ops->debugfs_attrs) {
108+
mutex_lock(&q->debugfs_mutex);
108109
blk_mq_debugfs_register_rqos(rqos);
110+
mutex_unlock(&q->debugfs_mutex);
111+
}
109112
}
110113

111114
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)
129132

130133
blk_mq_unfreeze_queue(q);
131134

135+
mutex_lock(&q->debugfs_mutex);
132136
blk_mq_debugfs_unregister_rqos(rqos);
137+
mutex_unlock(&q->debugfs_mutex);
133138
}
134139

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

block/blk-sysfs.c

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -779,14 +779,13 @@ static void blk_release_queue(struct kobject *kobj)
779779
if (queue_is_mq(q))
780780
blk_mq_release(q);
781781

782-
blk_trace_shutdown(q);
783782
mutex_lock(&q->debugfs_mutex);
783+
blk_trace_shutdown(q);
784784
debugfs_remove_recursive(q->debugfs_dir);
785+
q->debugfs_dir = NULL;
786+
q->sched_debugfs_dir = NULL;
785787
mutex_unlock(&q->debugfs_mutex);
786788

787-
if (queue_is_mq(q))
788-
blk_mq_debugfs_unregister(q);
789-
790789
bioset_exit(&q->bio_split);
791790

792791
if (blk_queue_has_srcu(q))
@@ -836,17 +835,16 @@ int blk_register_queue(struct gendisk *disk)
836835
goto unlock;
837836
}
838837

838+
if (queue_is_mq(q))
839+
__blk_mq_register_dev(dev, q);
840+
mutex_lock(&q->sysfs_lock);
841+
839842
mutex_lock(&q->debugfs_mutex);
840843
q->debugfs_dir = debugfs_create_dir(kobject_name(q->kobj.parent),
841844
blk_debugfs_root);
842-
mutex_unlock(&q->debugfs_mutex);
843-
844-
if (queue_is_mq(q)) {
845-
__blk_mq_register_dev(dev, q);
845+
if (queue_is_mq(q))
846846
blk_mq_debugfs_register(q);
847-
}
848-
849-
mutex_lock(&q->sysfs_lock);
847+
mutex_unlock(&q->debugfs_mutex);
850848

851849
ret = disk_register_independent_access_ranges(disk, NULL);
852850
if (ret)

include/linux/blkdev.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,6 @@ struct request_queue {
482482
#endif /* CONFIG_BLK_DEV_ZONED */
483483

484484
int node;
485-
struct mutex debugfs_mutex;
486485
#ifdef CONFIG_BLK_DEV_IO_TRACE
487486
struct blk_trace __rcu *blk_trace;
488487
#endif
@@ -526,11 +525,12 @@ struct request_queue {
526525
struct bio_set bio_split;
527526

528527
struct dentry *debugfs_dir;
529-
530-
#ifdef CONFIG_BLK_DEBUG_FS
531528
struct dentry *sched_debugfs_dir;
532529
struct dentry *rqos_debugfs_dir;
533-
#endif
530+
/*
531+
* Serializes all debugfs metadata operations using the above dentries.
532+
*/
533+
struct mutex debugfs_mutex;
534534

535535
bool mq_sysfs_init_done;
536536

kernel/trace/blktrace.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -770,14 +770,11 @@ int blk_trace_ioctl(struct block_device *bdev, unsigned cmd, char __user *arg)
770770
**/
771771
void blk_trace_shutdown(struct request_queue *q)
772772
{
773-
mutex_lock(&q->debugfs_mutex);
774773
if (rcu_dereference_protected(q->blk_trace,
775774
lockdep_is_held(&q->debugfs_mutex))) {
776775
__blk_trace_startstop(q, 0);
777776
__blk_trace_remove(q);
778777
}
779-
780-
mutex_unlock(&q->debugfs_mutex);
781778
}
782779

783780
#ifdef CONFIG_BLK_CGROUP

0 commit comments

Comments
 (0)