Skip to content

Commit e6cd0dc

Browse files
Wer-Wolfgregkh
authored andcommitted
eeprom: ee1004: Fix locking issues in ee1004_probe()
Currently, the devres-based management of ee1004_bus_data has several issues when it comes to locking: 1. It does not call mutex_unlock() before returning an error. 2. When encountering an error, it deadlocks when trying to recursively lock a mutex. Fix this by moving the mutex-protected bus data initialization into a separate function so that devm_add_action_or_reset() is called without the mutex being held. Reported-by: Dan Carpenter <[email protected]> Fixes: 55d57ef ("eeprom: ee1004: Use devres for bus data cleanup") Signed-off-by: Armin Wolf <[email protected]> Reviewed-by: Dan Carpenter <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent be62f12 commit e6cd0dc

File tree

1 file changed

+51
-34
lines changed

1 file changed

+51
-34
lines changed

drivers/misc/eeprom/ee1004.c

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,49 @@ static void ee1004_cleanup_bus_data(void *data)
233233
mutex_unlock(&ee1004_bus_lock);
234234
}
235235

236+
static int ee1004_init_bus_data(struct i2c_client *client)
237+
{
238+
struct ee1004_bus_data *bd;
239+
int err, cnr = 0;
240+
241+
bd = ee1004_get_bus_data(client->adapter);
242+
if (!bd)
243+
return dev_err_probe(&client->dev, -ENOSPC, "Only %d busses supported",
244+
EE1004_MAX_BUSSES);
245+
246+
i2c_set_clientdata(client, bd);
247+
248+
if (++bd->dev_count == 1) {
249+
/* Use 2 dummy devices for page select command */
250+
for (cnr = 0; cnr < EE1004_NUM_PAGES; cnr++) {
251+
struct i2c_client *cl;
252+
253+
cl = i2c_new_dummy_device(client->adapter, EE1004_ADDR_SET_PAGE + cnr);
254+
if (IS_ERR(cl)) {
255+
err = PTR_ERR(cl);
256+
goto err_out;
257+
}
258+
259+
bd->set_page[cnr] = cl;
260+
}
261+
262+
/* Remember current page to avoid unneeded page select */
263+
err = ee1004_get_current_page(bd);
264+
if (err < 0)
265+
goto err_out;
266+
267+
dev_dbg(&client->dev, "Currently selected page: %d\n", err);
268+
bd->current_page = err;
269+
}
270+
271+
return 0;
272+
273+
err_out:
274+
ee1004_cleanup(cnr, bd);
275+
276+
return err;
277+
}
278+
236279
static int ee1004_probe(struct i2c_client *client)
237280
{
238281
struct nvmem_config config = {
@@ -251,9 +294,8 @@ static int ee1004_probe(struct i2c_client *client)
251294
.compat = true,
252295
.base_dev = &client->dev,
253296
};
254-
struct ee1004_bus_data *bd;
255297
struct nvmem_device *ndev;
256-
int err, cnr = 0;
298+
int err;
257299

258300
/* Make sure we can operate on this adapter */
259301
if (!i2c_check_functionality(client->adapter,
@@ -264,46 +306,21 @@ static int ee1004_probe(struct i2c_client *client)
264306

265307
mutex_lock(&ee1004_bus_lock);
266308

267-
bd = ee1004_get_bus_data(client->adapter);
268-
if (!bd) {
309+
err = ee1004_init_bus_data(client);
310+
if (err < 0) {
269311
mutex_unlock(&ee1004_bus_lock);
270-
return dev_err_probe(&client->dev, -ENOSPC,
271-
"Only %d busses supported", EE1004_MAX_BUSSES);
272-
}
273-
274-
err = devm_add_action_or_reset(&client->dev, ee1004_cleanup_bus_data, bd);
275-
if (err < 0)
276312
return err;
277-
278-
i2c_set_clientdata(client, bd);
279-
280-
if (++bd->dev_count == 1) {
281-
/* Use 2 dummy devices for page select command */
282-
for (cnr = 0; cnr < EE1004_NUM_PAGES; cnr++) {
283-
struct i2c_client *cl;
284-
285-
cl = i2c_new_dummy_device(client->adapter, EE1004_ADDR_SET_PAGE + cnr);
286-
if (IS_ERR(cl)) {
287-
mutex_unlock(&ee1004_bus_lock);
288-
return PTR_ERR(cl);
289-
}
290-
bd->set_page[cnr] = cl;
291-
}
292-
293-
/* Remember current page to avoid unneeded page select */
294-
err = ee1004_get_current_page(bd);
295-
if (err < 0) {
296-
mutex_unlock(&ee1004_bus_lock);
297-
return err;
298-
}
299-
dev_dbg(&client->dev, "Currently selected page: %d\n", err);
300-
bd->current_page = err;
301313
}
302314

303315
ee1004_probe_temp_sensor(client);
304316

305317
mutex_unlock(&ee1004_bus_lock);
306318

319+
err = devm_add_action_or_reset(&client->dev, ee1004_cleanup_bus_data,
320+
i2c_get_clientdata(client));
321+
if (err < 0)
322+
return err;
323+
307324
ndev = devm_nvmem_register(&client->dev, &config);
308325
if (IS_ERR(ndev))
309326
return PTR_ERR(ndev);

0 commit comments

Comments
 (0)