Unverified Commit 7d696210 authored by Zxyan Zhu's avatar Zxyan Zhu Committed by Mark Brown
Browse files

regmap: debugfs: fix race condition in dummy name allocation



Use IDA instead of a simple counter for generating unique dummy names.
The previous implementation used dummy_index++ which is not atomic,
leading to potential duplicate names when multiple threads call
regmap_debugfs_init() concurrently with name="dummy".

Signed-off-by: default avatarZxyan Zhu <zxyan0222@gmail.com>
Link: https://patch.msgid.link/20260409035015.950764-1-zxyan0222@gmail.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 1ef3e1c2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -84,6 +84,7 @@ struct regmap {
	bool debugfs_disable;
	struct dentry *debugfs;
	const char *debugfs_name;
	int debugfs_dummy_id;

	unsigned int debugfs_reg_len;
	unsigned int debugfs_val_len;
+16 −5
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/list.h>
#include <linux/idr.h>

#include "internal.h"

@@ -20,7 +21,7 @@ struct regmap_debugfs_node {
	struct list_head link;
};

static unsigned int dummy_index;
static DEFINE_IDA(dummy_ida);
static struct dentry *regmap_debugfs_root;
static LIST_HEAD(regmap_debugfs_early_list);
static DEFINE_MUTEX(regmap_debugfs_early_lock);
@@ -539,6 +540,7 @@ void regmap_debugfs_init(struct regmap *map)
	struct regmap_range_node *range_node;
	const char *devname = "dummy";
	const char *name = map->name;
	int id;

	/*
	 * Userspace can initiate reads from the hardware over debugfs.
@@ -567,6 +569,7 @@ void regmap_debugfs_init(struct regmap *map)

	INIT_LIST_HEAD(&map->debugfs_off_cache);
	mutex_init(&map->cache_lock);
	map->debugfs_dummy_id = -1;

	if (map->dev)
		devname = dev_name(map->dev);
@@ -585,12 +588,16 @@ void regmap_debugfs_init(struct regmap *map)

	if (!strcmp(name, "dummy")) {
		kfree(map->debugfs_name);
		map->debugfs_name = kasprintf(GFP_KERNEL, "dummy%d",
						dummy_index);
		if (!map->debugfs_name)
		id = ida_alloc(&dummy_ida, GFP_KERNEL);
		if (id < 0)
			return;
		map->debugfs_name = kasprintf(GFP_KERNEL, "dummy%d", id);
		if (!map->debugfs_name) {
			ida_free(&dummy_ida, id);
			return;
		}
		map->debugfs_dummy_id = id;
		name = map->debugfs_name;
		dummy_index++;
	}

	map->debugfs = debugfs_create_dir(name, regmap_debugfs_root);
@@ -660,6 +667,10 @@ void regmap_debugfs_exit(struct regmap *map)
		mutex_lock(&map->cache_lock);
		regmap_debugfs_free_dump_cache(map);
		mutex_unlock(&map->cache_lock);
		if (map->debugfs_dummy_id >= 0) {
			ida_free(&dummy_ida, map->debugfs_dummy_id);
			map->debugfs_dummy_id = -1;
		}
		kfree(map->debugfs_name);
		map->debugfs_name = NULL;
	} else {