* [PATCH 0/7] regmap: cleanups for regcache and regmap init paths
@ 2026-09-30 9:46 Peng Fan (OSS)
2026-09-30 9:46 ` [PATCH 1/7] regcache: extract locked helpers to replace open-coded lock/unlock pairs Peng Fan (OSS)
` (6 more replies)
0 siblings, 7 replies; 8+ messages in thread
From: Peng Fan (OSS) @ 2026-09-30 9:46 UTC (permalink / raw)
To: Mark Brown, Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich
Cc: linux-kernel, driver-core, Peng Fan
Following up the previous regmap guard lock patchset [1].
[1] https://lore.kernel.org/all/179062150526.139547.3870545428656485907.b4-ty@b4/#r
This is the 2nd batch to do more cleanup.
This series tidies up locking, error handling, and resource management
across the regmap core and regcache.
- Extract regcache_locked_op() and regcache_locked_exit() helpers to
replace open-coded lock/unlock pairs in regcache_init() and
regcache_exit(), avoiding the cleanup.h-vs-goto concern that
prevented the earlier scoped lock guard conversion.
- Extract __regcache_sync() to deduplicate the sync dispatch logic
shared between regcache_sync() and regcache_sync_region().
- Flatten control flow in regcache_init(), regcache_lookup_reg(), and
regcache_sync_block() by using early returns, moving guards into
helpers, and merging redundant sanity checks.
- Switch regmap_register_patch() from krealloc() to krealloc_array()
for overflow-safe element-count arithmetic.
- Convert bus struct copies in regmap-i2c and regmap-spi from
kmemdup() to devm_kmemdup(), letting devres handle lifetime and
removing the free_on_exit flag from struct regmap_bus entirely.
- Simplify the early error paths in __regmap_init() by returning
directly instead of jumping to a label that does nothing but return.
- NULL map->reg_defaults after freeing in regcache_exit() to prevent
a potential double-free if regmap_reinit_cache() later fails during
cache re-initialisation.
Tested with the regmap KUnit suite (drivers/base/regmap/regmap-kunit.c)
with lockdep (PROVE_LOCKING, DEBUG_LOCK_ALLOC, DEBUG_ATOMIC_SLEEP) enabled.
Built clean with sparse (C=1).
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
Peng Fan (7):
regcache: extract locked helpers to replace open-coded lock/unlock pairs
regcache: extract __regcache_sync() to deduplicate sync dispatch
regcache: simplify control flow and reduce nesting
regmap: use krealloc_array() in regmap_register_patch()
regmap: use devm_kmemdup() for bus copies and remove free_on_exit
regmap: return errors directly before map allocation in __regmap_init()
regmap: fix potential double-free of map->reg_defaults on cache reinit
drivers/base/regmap/regcache.c | 132 +++++++++++++++++++--------------------
drivers/base/regmap/regmap-i2c.c | 3 +-
drivers/base/regmap/regmap-spi.c | 3 +-
drivers/base/regmap/regmap.c | 31 +++------
include/linux/regmap.h | 2 -
5 files changed, 77 insertions(+), 94 deletions(-)
---
base-commit: 6474fa070f2b8013b4b87350b775b8c3be6e8aac
change-id: 20260930-regmap-lock-2nd-f481885c24d6
Best regards,
--
Peng Fan <peng.fan@nxp.com>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/7] regcache: extract locked helpers to replace open-coded lock/unlock pairs
2026-09-30 9:46 [PATCH 0/7] regmap: cleanups for regcache and regmap init paths Peng Fan (OSS)
@ 2026-09-30 9:46 ` Peng Fan (OSS)
2026-09-30 9:46 ` [PATCH 2/7] regcache: extract __regcache_sync() to deduplicate sync dispatch Peng Fan (OSS)
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Peng Fan (OSS) @ 2026-09-30 9:46 UTC (permalink / raw)
To: Mark Brown, Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich
Cc: linux-kernel, driver-core, Peng Fan
From: Peng Fan <peng.fan@nxp.com>
The previous patch ("regcache: use the regmap scoped lock guard")
deliberately left regcache_init() with explicit map->lock()/unlock()
calls because the function has a goto err_* cleanup ladder and mixing
goto with cleanup helpers in the same function is discouraged by
cleanup.h.
Solve this by extracting two static helpers:
regcache_locked_op() - acquires the regmap lock via guard(regmap),
invokes an int-returning cache_ops callback
(init, populate), and returns its result.
Returns 0 when the callback is NULL.
regcache_locked_exit() - acquires the regmap lock via guard(regmap)
and invokes the void-returning exit
callback. Returns immediately when the
callback is NULL.
Because the lock scope is now entirely inside the helper functions,
it never crosses a goto target in the caller, so the cleanup.h
concern does not apply.
Convert all four remaining open-coded lock/unlock sites in
regcache_init() (init, populate, error-path exit) and the
scoped_guard in regcache_exit() to use these helpers.
No functional change.
Assisted-by: LLM
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/base/regmap/regcache.c | 57 +++++++++++++++++++++---------------------
1 file changed, 29 insertions(+), 28 deletions(-)
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 4c80db5d6f6f..ebfa27bb6f54 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -121,6 +121,28 @@ static void regcache_hw_exit(struct regmap *map)
kfree(map->reg_defaults_raw);
}
+static int regcache_locked_op(struct regmap *map,
+ int (*op)(struct regmap *map),
+ const char *action)
+{
+ if (!op)
+ return 0;
+
+ dev_dbg(map->dev, "%s %s cache\n", action, map->cache_ops->name);
+ guard(regmap)(map);
+ return op(map);
+}
+
+static void regcache_locked_exit(struct regmap *map)
+{
+ if (!map->cache_ops->exit)
+ return;
+
+ dev_dbg(map->dev, "Destroying %s cache\n", map->cache_ops->name);
+ guard(regmap)(map);
+ map->cache_ops->exit(map);
+}
+
int regcache_init(struct regmap *map, const struct regmap_config *config)
{
bool sort_defaults = false;
@@ -222,15 +244,9 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
map->max_register_is_set = true;
}
- if (map->cache_ops->init) {
- dev_dbg(map->dev, "Initializing %s cache\n",
- map->cache_ops->name);
- map->lock(map->lock_arg);
- ret = map->cache_ops->init(map);
- map->unlock(map->lock_arg);
- if (ret)
- goto err_free_reg_defaults;
- }
+ ret = regcache_locked_op(map, map->cache_ops->init, "Initializing");
+ if (ret)
+ goto err_free_reg_defaults;
/*
* Some devices such as PMICs don't have cache defaults,
@@ -243,12 +259,8 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
goto err_exit;
}
- if (map->cache_ops->populate &&
- (map->num_reg_defaults || map->reg_default_cb)) {
- dev_dbg(map->dev, "Populating %s cache\n", map->cache_ops->name);
- map->lock(map->lock_arg);
- ret = map->cache_ops->populate(map);
- map->unlock(map->lock_arg);
+ if (map->num_reg_defaults || map->reg_default_cb) {
+ ret = regcache_locked_op(map, map->cache_ops->populate, "Populating");
if (ret)
goto err_free;
}
@@ -257,12 +269,7 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
err_free:
regcache_hw_exit(map);
err_exit:
- if (map->cache_ops->exit) {
- dev_dbg(map->dev, "Destroying %s cache\n", map->cache_ops->name);
- map->lock(map->lock_arg);
- map->cache_ops->exit(map);
- map->unlock(map->lock_arg);
- }
+ regcache_locked_exit(map);
err_free_reg_defaults:
kfree(map->reg_defaults);
@@ -277,13 +284,7 @@ void regcache_exit(struct regmap *map)
BUG_ON(!map->cache_ops);
regcache_hw_exit(map);
-
- if (map->cache_ops->exit) {
- dev_dbg(map->dev, "Destroying %s cache\n",
- map->cache_ops->name);
- scoped_guard(regmap, map)
- map->cache_ops->exit(map);
- }
+ regcache_locked_exit(map);
kfree(map->reg_defaults);
}
--
2.51.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/7] regcache: extract __regcache_sync() to deduplicate sync dispatch
2026-09-30 9:46 [PATCH 0/7] regmap: cleanups for regcache and regmap init paths Peng Fan (OSS)
2026-09-30 9:46 ` [PATCH 1/7] regcache: extract locked helpers to replace open-coded lock/unlock pairs Peng Fan (OSS)
@ 2026-09-30 9:46 ` Peng Fan (OSS)
2026-09-30 9:46 ` [PATCH 3/7] regcache: simplify control flow and reduce nesting Peng Fan (OSS)
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Peng Fan (OSS) @ 2026-09-30 9:46 UTC (permalink / raw)
To: Mark Brown, Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich
Cc: linux-kernel, driver-core, Peng Fan
From: Peng Fan <peng.fan@nxp.com>
regcache_sync() and regcache_sync_region() both open-code the same
pattern: check cache_dirty, then dispatch to either cache_ops->sync()
or regcache_default_sync().
Extract this into a static __regcache_sync() helper that both callers
share. The helper checks cache_dirty and returns 0 early when the
cache is clean, dispatches to the backend sync callback when present,
and falls back to regcache_default_sync() otherwise.
In regcache_sync_region(), the cache_dirty early-exit previously
skipped setting map->async. With the helper, map->async is set to
true before the call and restored to false unconditionally afterward,
so when cache_dirty is false the flag is toggled and immediately
restored - functionally equivalent.
No functional change.
Assisted-by: LLM
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/base/regmap/regcache.c | 28 +++++++++++++++-------------
1 file changed, 15 insertions(+), 13 deletions(-)
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index ebfa27bb6f54..b486cd826b3c 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -22,6 +22,8 @@ static const struct regcache_ops *cache_types[] = {
®cache_flat_ops,
};
+static int regcache_default_sync(struct regmap *map, unsigned int min, unsigned int max);
+
static int regcache_defaults_cmp(const void *a, const void *b)
{
const struct reg_default *x = a;
@@ -143,6 +145,17 @@ static void regcache_locked_exit(struct regmap *map)
map->cache_ops->exit(map);
}
+static int __regcache_sync(struct regmap *map, unsigned int min, unsigned int max)
+{
+ if (!map->cache_dirty)
+ return 0;
+
+ if (map->cache_ops->sync)
+ return map->cache_ops->sync(map, min, max);
+
+ return regcache_default_sync(map, min, max);
+}
+
int regcache_init(struct regmap *map, const struct regmap_config *config)
{
bool sort_defaults = false;
@@ -461,11 +474,7 @@ int regcache_sync(struct regmap *map)
}
map->cache_bypass = false;
- if (map->cache_ops->sync)
- sync_ret = map->cache_ops->sync(map, 0, map->max_register);
- else
- sync_ret = regcache_default_sync(map, 0, map->max_register);
-
+ sync_ret = __regcache_sync(map, 0, map->max_register);
if (sync_ret == 0)
map->cache_dirty = false;
@@ -545,17 +554,10 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
trace_regcache_sync(map, name, "start region");
- if (!map->cache_dirty)
- goto out;
-
map->async = true;
- if (map->cache_ops->sync)
- ret = map->cache_ops->sync(map, min, max);
- else
- ret = regcache_default_sync(map, min, max);
+ ret = __regcache_sync(map, min, max);
-out:
/* Restore the bypass state */
map->cache_bypass = bypass;
map->async = false;
--
2.51.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 3/7] regcache: simplify control flow and reduce nesting
2026-09-30 9:46 [PATCH 0/7] regmap: cleanups for regcache and regmap init paths Peng Fan (OSS)
2026-09-30 9:46 ` [PATCH 1/7] regcache: extract locked helpers to replace open-coded lock/unlock pairs Peng Fan (OSS)
2026-09-30 9:46 ` [PATCH 2/7] regcache: extract __regcache_sync() to deduplicate sync dispatch Peng Fan (OSS)
@ 2026-09-30 9:46 ` Peng Fan (OSS)
2026-09-30 9:46 ` [PATCH 4/7] regmap: use krealloc_array() in regmap_register_patch() Peng Fan (OSS)
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Peng Fan (OSS) @ 2026-09-30 9:46 UTC (permalink / raw)
To: Mark Brown, Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich
Cc: linux-kernel, driver-core, Peng Fan
From: Peng Fan <peng.fan@nxp.com>
Move the count guard into regcache_hw_init() so callers don't need to
check before calling, and flatten conditional blocks that wrap a single
call by using early returns instead.
Merge the two separate reg_defaults / num_reg_defaults sanity checks
into a single expression, and drop unnecessary else-after-return in
regcache_lookup_reg() and regcache_sync_block().
No functional change.
Assisted-by: LLM
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/base/regmap/regcache.c | 50 +++++++++++++++++++-----------------------
1 file changed, 22 insertions(+), 28 deletions(-)
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index b486cd826b3c..136d6adf3120 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -58,12 +58,15 @@ static int regcache_count_cacheable_registers(struct regmap *map)
return count;
}
-static int regcache_hw_init(struct regmap *map)
+static int regcache_hw_init(struct regmap *map, int count)
{
int ret;
unsigned int reg, val;
void *tmp_buf;
+ if (!count)
+ return 0;
+
if (!map->reg_defaults_raw) {
bool cache_bypass = map->cache_bypass;
dev_dbg(map->dev, "No cache defaults, reading back from HW\n");
@@ -174,15 +177,8 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
return 0;
}
- if (config->reg_defaults && !config->num_reg_defaults) {
- dev_err(map->dev,
- "Register defaults are set without the number!\n");
- return -EINVAL;
- }
-
- if (config->num_reg_defaults && !config->reg_defaults) {
- dev_err(map->dev,
- "Register defaults number are set without the reg!\n");
+ if (!!config->reg_defaults != !!config->num_reg_defaults) {
+ dev_err(map->dev, "reg_defaults and num_reg_defaults must both be specified\n");
return -EINVAL;
}
@@ -215,9 +211,7 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
map->cache = NULL;
map->cache_ops = cache_types[i];
- if (!map->cache_ops->read ||
- !map->cache_ops->write ||
- !map->cache_ops->name)
+ if (!map->cache_ops->read || !map->cache_ops->write || !map->cache_ops->name)
return -EINVAL;
/* We still need to ensure that the reg_defaults
@@ -266,17 +260,17 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
* we cope with this by reading back the HW registers and
* crafting the cache defaults by hand.
*/
- if (count) {
- ret = regcache_hw_init(map);
- if (ret)
- goto err_exit;
- }
+ ret = regcache_hw_init(map, count);
+ if (ret)
+ goto err_exit;
+
+ if (!map->num_reg_defaults && !map->reg_default_cb)
+ return 0;
+
+ ret = regcache_locked_op(map, map->cache_ops->populate, "Populating");
+ if (ret)
+ goto err_free;
- if (map->num_reg_defaults || map->reg_default_cb) {
- ret = regcache_locked_op(map, map->cache_ops->populate, "Populating");
- if (ret)
- goto err_free;
- }
return 0;
err_free:
@@ -762,8 +756,8 @@ int regcache_lookup_reg(struct regmap *map, unsigned int reg)
if (r)
return r - map->reg_defaults;
- else
- return -ENOENT;
+
+ return -ENOENT;
}
static bool regcache_reg_present(unsigned long *cache_present, unsigned int idx)
@@ -900,7 +894,7 @@ int regcache_sync_block(struct regmap *map, void *block,
if (regmap_can_raw_write(map) && !map->use_single_write)
return regcache_sync_block_raw(map, block, cache_present,
block_base, start, end);
- else
- return regcache_sync_block_single(map, block, cache_present,
- block_base, start, end);
+
+ return regcache_sync_block_single(map, block, cache_present,
+ block_base, start, end);
}
--
2.51.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 4/7] regmap: use krealloc_array() in regmap_register_patch()
2026-09-30 9:46 [PATCH 0/7] regmap: cleanups for regcache and regmap init paths Peng Fan (OSS)
` (2 preceding siblings ...)
2026-09-30 9:46 ` [PATCH 3/7] regcache: simplify control flow and reduce nesting Peng Fan (OSS)
@ 2026-09-30 9:46 ` Peng Fan (OSS)
2026-09-30 9:46 ` [PATCH 5/7] regmap: use devm_kmemdup() for bus copies and remove free_on_exit Peng Fan (OSS)
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Peng Fan (OSS) @ 2026-09-30 9:46 UTC (permalink / raw)
To: Mark Brown, Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich
Cc: linux-kernel, driver-core, Peng Fan
From: Peng Fan <peng.fan@nxp.com>
Replace krealloc() with krealloc_array() in regmap_register_patch() to
gain the built-in overflow check on the element-count * element-size
multiplication, and switch to the early-return error style to reduce
nesting.
Assisted-by: LLM
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/base/regmap/regmap.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 0b40e1e7817c..b9830afa6d8e 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -3379,16 +3379,13 @@ int regmap_register_patch(struct regmap *map, const struct reg_sequence *regs,
num_regs))
return 0;
- p = krealloc(map->patch,
- sizeof(struct reg_sequence) * (map->patch_regs + num_regs),
- GFP_KERNEL);
- if (p) {
- memcpy(p + map->patch_regs, regs, num_regs * sizeof(*regs));
- map->patch = p;
- map->patch_regs += num_regs;
- } else {
+ p = krealloc_array(map->patch, map->patch_regs + num_regs, sizeof(*p), GFP_KERNEL);
+ if (!p)
return -ENOMEM;
- }
+
+ memcpy(p + map->patch_regs, regs, num_regs * sizeof(*regs));
+ map->patch = p;
+ map->patch_regs += num_regs;
scoped_guard(regmap, map) {
bypass = map->cache_bypass;
--
2.51.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 5/7] regmap: use devm_kmemdup() for bus copies and remove free_on_exit
2026-09-30 9:46 [PATCH 0/7] regmap: cleanups for regcache and regmap init paths Peng Fan (OSS)
` (3 preceding siblings ...)
2026-09-30 9:46 ` [PATCH 4/7] regmap: use krealloc_array() in regmap_register_patch() Peng Fan (OSS)
@ 2026-09-30 9:46 ` Peng Fan (OSS)
2026-09-30 9:47 ` [PATCH 6/7] regmap: return errors directly before map allocation in __regmap_init() Peng Fan (OSS)
2026-09-30 9:47 ` [PATCH 7/7] regmap: fix potential double-free of map->reg_defaults on cache reinit Peng Fan (OSS)
6 siblings, 0 replies; 8+ messages in thread
From: Peng Fan (OSS) @ 2026-09-30 9:46 UTC (permalink / raw)
To: Mark Brown, Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich
Cc: linux-kernel, driver-core, Peng Fan
From: Peng Fan <peng.fan@nxp.com>
regmap_get_i2c_bus() and regmap_get_spi_bus() duplicate the static bus
struct when the transfer size needs clamping. They use kmemdup()
and set the free_on_exit flag so regmap_exit() will kfree the copy.
Replace kmemdup() with devm_kmemdup() tied to the parent device, which
lets devres handle the lifetime automatically. This is safe because
devres cleanup is LIFO: the bus copy (allocated first) is freed after
the regmap devres action calls regmap_exit(), so the bus is guaranteed
alive while the regmap references it. For the non-devm regmap_init
path the driver calls regmap_exit() in its remove() callback, and
devres runs after remove() returns, so the ordering holds there as
well.
With no remaining producers of free_on_exit, remove the flag from
struct regmap_bus and drop the corresponding kfree() calls in
__regmap_init() and regmap_exit().
Assisted-by: LLM
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/base/regmap/regmap-i2c.c | 3 +--
drivers/base/regmap/regmap-spi.c | 3 +--
drivers/base/regmap/regmap.c | 4 ----
include/linux/regmap.h | 2 --
4 files changed, 2 insertions(+), 10 deletions(-)
diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c
index 51a04961faf7..813e8b407a0f 100644
--- a/drivers/base/regmap/regmap-i2c.c
+++ b/drivers/base/regmap/regmap-i2c.c
@@ -403,10 +403,9 @@ static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c,
(config->reg_bits + config->pad_bits) / BITS_PER_BYTE;
if (max_read || max_write) {
- ret_bus = kmemdup(bus, sizeof(*bus), GFP_KERNEL);
+ ret_bus = devm_kmemdup(&i2c->dev, bus, sizeof(*bus), GFP_KERNEL);
if (!ret_bus)
return ERR_PTR(-ENOMEM);
- ret_bus->free_on_exit = true;
ret_bus->max_raw_read = max_read;
ret_bus->max_raw_write = max_write;
bus = ret_bus;
diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c
index b9fec387997e..8b5a3fbcb18d 100644
--- a/drivers/base/regmap/regmap-spi.c
+++ b/drivers/base/regmap/regmap-spi.c
@@ -117,7 +117,7 @@ static const struct regmap_bus *regmap_get_spi_bus(struct spi_device *spi,
struct regmap_bus *bus;
if (max_size != SIZE_MAX) {
- bus = kmemdup(®map_spi, sizeof(*bus), GFP_KERNEL);
+ bus = devm_kmemdup(&spi->dev, ®map_spi, sizeof(*bus), GFP_KERNEL);
if (!bus)
return ERR_PTR(-ENOMEM);
@@ -126,7 +126,6 @@ static const struct regmap_bus *regmap_get_spi_bus(struct spi_device *spi,
if (max_size + reg_reserve_size > max_msg_size)
max_size -= reg_reserve_size;
- bus->free_on_exit = true;
bus->max_raw_read = max_size;
bus->max_raw_write = max_size;
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index b9830afa6d8e..bb5553ce58d1 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -1175,8 +1175,6 @@ struct regmap *__regmap_init(struct device *dev,
err_map:
kfree(map);
err:
- if (bus && bus->free_on_exit)
- kfree(bus);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(__regmap_init);
@@ -1479,8 +1477,6 @@ void regmap_exit(struct regmap *map)
mutex_destroy(&map->mutex);
kfree_const(map->name);
kfree(map->patch);
- if (map->bus && map->bus->free_on_exit)
- kfree(map->bus);
kfree(map);
}
EXPORT_SYMBOL_GPL(regmap_exit);
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index c8aebd148e08..f8334a37bd0e 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -579,7 +579,6 @@ typedef void (*regmap_hw_free_context)(void *context);
* to perform locking. This field is ignored if custom lock/unlock
* functions are used (see fields lock/unlock of
* struct regmap_config).
- * @free_on_exit: kfree this on exit of regmap
* @write: Write operation.
* @gather_write: Write operation with split register/value, return -ENOTSUPP
* if not implemented on a given device.
@@ -613,7 +612,6 @@ typedef void (*regmap_hw_free_context)(void *context);
*/
struct regmap_bus {
bool fast_io;
- bool free_on_exit;
regmap_hw_write write;
regmap_hw_gather_write gather_write;
regmap_hw_async_write async_write;
--
2.51.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 6/7] regmap: return errors directly before map allocation in __regmap_init()
2026-09-30 9:46 [PATCH 0/7] regmap: cleanups for regcache and regmap init paths Peng Fan (OSS)
` (4 preceding siblings ...)
2026-09-30 9:46 ` [PATCH 5/7] regmap: use devm_kmemdup() for bus copies and remove free_on_exit Peng Fan (OSS)
@ 2026-09-30 9:47 ` Peng Fan (OSS)
2026-09-30 9:47 ` [PATCH 7/7] regmap: fix potential double-free of map->reg_defaults on cache reinit Peng Fan (OSS)
6 siblings, 0 replies; 8+ messages in thread
From: Peng Fan (OSS) @ 2026-09-30 9:47 UTC (permalink / raw)
To: Mark Brown, Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich
Cc: linux-kernel, driver-core, Peng Fan
From: Peng Fan <peng.fan@nxp.com>
The two early error paths in __regmap_init() - a NULL config check and a
failed kzalloc - jumped to the 'err' label which only did return
ERR_PTR(ret). Since neither path has anything to clean up (the map
hasn't been allocated yet), replace the gotos with direct return
ERR_PTR() calls.
Removes the 'err' label entirely and the pre-initialisation of ret to
simplify code.
No functional change.
Assisted-by: LLM
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/base/regmap/regmap.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index bb5553ce58d1..88000d535985 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -681,18 +681,15 @@ struct regmap *__regmap_init(struct device *dev,
const char *lock_name)
{
struct regmap *map;
- int ret = -EINVAL;
enum regmap_endian reg_endian, val_endian;
- int i, j;
+ int i, j, ret;
if (!config)
- goto err;
+ return ERR_PTR(-EINVAL);
map = kzalloc_obj(*map);
- if (map == NULL) {
- ret = -ENOMEM;
- goto err;
- }
+ if (map == NULL)
+ return ERR_PTR(-ENOMEM);
ret = regmap_set_name(map, config);
if (ret)
@@ -1174,7 +1171,6 @@ struct regmap *__regmap_init(struct device *dev,
kfree_const(map->name);
err_map:
kfree(map);
-err:
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(__regmap_init);
--
2.51.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 7/7] regmap: fix potential double-free of map->reg_defaults on cache reinit
2026-09-30 9:46 [PATCH 0/7] regmap: cleanups for regcache and regmap init paths Peng Fan (OSS)
` (5 preceding siblings ...)
2026-09-30 9:47 ` [PATCH 6/7] regmap: return errors directly before map allocation in __regmap_init() Peng Fan (OSS)
@ 2026-09-30 9:47 ` Peng Fan (OSS)
6 siblings, 0 replies; 8+ messages in thread
From: Peng Fan (OSS) @ 2026-09-30 9:47 UTC (permalink / raw)
To: Mark Brown, Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich
Cc: linux-kernel, driver-core, Peng Fan
From: Peng Fan <peng.fan@nxp.com>
regcache_exit() frees map->reg_defaults but does not NULL the pointer.
If regmap_reinit_cache() is later called with a config that has neither
reg_defaults nor num_reg_defaults_raw, regcache_init() skips both
allocation branches and leaves the stale pointer in place. Should
cache_ops->init then fail, the err_free_reg_defaults error path calls
kfree(map->reg_defaults) a second time.
NULL the pointer after freeing so the error-path kfree() is a harmless
no-op.
Assisted-by: LLM
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/base/regmap/regcache.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 136d6adf3120..3b1c2f28d585 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -294,6 +294,7 @@ void regcache_exit(struct regmap *map)
regcache_locked_exit(map);
kfree(map->reg_defaults);
+ map->reg_defaults = NULL;
}
/**
--
2.51.0
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-09-30 9:50 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-30 9:46 [PATCH 0/7] regmap: cleanups for regcache and regmap init paths Peng Fan (OSS)
2026-09-30 9:46 ` [PATCH 1/7] regcache: extract locked helpers to replace open-coded lock/unlock pairs Peng Fan (OSS)
2026-09-30 9:46 ` [PATCH 2/7] regcache: extract __regcache_sync() to deduplicate sync dispatch Peng Fan (OSS)
2026-09-30 9:46 ` [PATCH 3/7] regcache: simplify control flow and reduce nesting Peng Fan (OSS)
2026-09-30 9:46 ` [PATCH 4/7] regmap: use krealloc_array() in regmap_register_patch() Peng Fan (OSS)
2026-09-30 9:46 ` [PATCH 5/7] regmap: use devm_kmemdup() for bus copies and remove free_on_exit Peng Fan (OSS)
2026-09-30 9:47 ` [PATCH 6/7] regmap: return errors directly before map allocation in __regmap_init() Peng Fan (OSS)
2026-09-30 9:47 ` [PATCH 7/7] regmap: fix potential double-free of map->reg_defaults on cache reinit Peng Fan (OSS)
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®