Skip to content

Commit

Permalink
nvmem: core: fix registration vs use race
Browse files Browse the repository at this point in the history
The i.MX6 CPU frequency driver sometimes fails to register at boot time
due to nvmem_cell_read_u32() sporadically returning -ENOENT.

This happens because there is a window where __nvmem_device_get() in
of_nvmem_cell_get() is able to return the nvmem device, but as cells
have been setup, nvmem_find_cell_entry_by_node() returns NULL.

The occurs because the nvmem core registration code violates one of the
fundamental principles of kernel programming: do not publish data
structures before their setup is complete.

Fix this by making nvmem core code conform with this principle.

Fixes: eace75c ("nvmem: Add a simple NVMEM framework for nvmem providers")
Cc: stable@vger.kernel.org
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20230127104015.23839-7-srinivas.kandagatla@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Russell King (Oracle) authored and Greg Kroah-Hartman committed Jan 28, 2023
1 parent 560181d commit ab3428c
Showing 1 changed file with 8 additions and 10 deletions.
18 changes: 8 additions & 10 deletions drivers/nvmem/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -832,22 +832,16 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
nvmem->dev.groups = nvmem_dev_groups;
#endif

dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);

rval = device_add(&nvmem->dev);
if (rval)
goto err_put_device;

if (nvmem->nkeepout) {
rval = nvmem_validate_keepouts(nvmem);
if (rval)
goto err_device_del;
goto err_put_device;
}

if (config->compat) {
rval = nvmem_sysfs_setup_compat(nvmem, config);
if (rval)
goto err_device_del;
goto err_put_device;
}

if (config->cells) {
Expand All @@ -864,6 +858,12 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
if (rval)
goto err_remove_cells;

dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);

rval = device_add(&nvmem->dev);
if (rval)
goto err_remove_cells;

blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem);

return nvmem;
Expand All @@ -873,8 +873,6 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
err_teardown_compat:
if (config->compat)
nvmem_sysfs_remove_compat(nvmem, config);
err_device_del:
device_del(&nvmem->dev);
err_put_device:
put_device(&nvmem->dev);

Expand Down

0 comments on commit ab3428c

Please sign in to comment.