Skip to content

Commit 299632e

Browse files
diandersbroonie
authored andcommitted
regmap: debugfs: Don't sleep while atomic for fast_io regmaps
If a regmap has "fast_io" set then its lock function uses a spinlock. That doesn't work so well with the functions: * regmap_cache_only_write_file() * regmap_cache_bypass_write_file() Both of the above functions have the pattern: 1. Lock the regmap. 2. Call: debugfs_write_file_bool() copy_from_user() __might_fault() __might_sleep() Let's reorder things a bit so that we do all of our sleepable functions before we grab the lock. Fixes: d3dc543 ("regmap: debugfs: Allow writes to cache state settings") Signed-off-by: Douglas Anderson <[email protected]> Link: https://lore.kernel.org/r/20200715164611.1.I35b3533e8a80efde0cec1cc70f71e1e74b2fa0da@changeid Signed-off-by: Mark Brown <[email protected]>
1 parent 443a34b commit 299632e

File tree

1 file changed

+29
-23
lines changed

1 file changed

+29
-23
lines changed

drivers/base/regmap/regmap-debugfs.c

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -457,37 +457,39 @@ static ssize_t regmap_cache_only_write_file(struct file *file,
457457
{
458458
struct regmap *map = container_of(file->private_data,
459459
struct regmap, cache_only);
460-
ssize_t result;
461-
bool was_enabled, require_sync = false;
460+
bool new_val, require_sync = false;
462461
int err;
463462

464-
map->lock(map->lock_arg);
463+
err = kstrtobool_from_user(user_buf, count, &new_val);
464+
/* Ignore malforned data like debugfs_write_file_bool() */
465+
if (err)
466+
return count;
465467

466-
was_enabled = map->cache_only;
468+
err = debugfs_file_get(file->f_path.dentry);
469+
if (err)
470+
return err;
467471

468-
result = debugfs_write_file_bool(file, user_buf, count, ppos);
469-
if (result < 0) {
470-
map->unlock(map->lock_arg);
471-
return result;
472-
}
472+
map->lock(map->lock_arg);
473473

474-
if (map->cache_only && !was_enabled) {
474+
if (new_val && !map->cache_only) {
475475
dev_warn(map->dev, "debugfs cache_only=Y forced\n");
476476
add_taint(TAINT_USER, LOCKDEP_STILL_OK);
477-
} else if (!map->cache_only && was_enabled) {
477+
} else if (!new_val && map->cache_only) {
478478
dev_warn(map->dev, "debugfs cache_only=N forced: syncing cache\n");
479479
require_sync = true;
480480
}
481+
map->cache_only = new_val;
481482

482483
map->unlock(map->lock_arg);
484+
debugfs_file_put(file->f_path.dentry);
483485

484486
if (require_sync) {
485487
err = regcache_sync(map);
486488
if (err)
487489
dev_err(map->dev, "Failed to sync cache %d\n", err);
488490
}
489491

490-
return result;
492+
return count;
491493
}
492494

493495
static const struct file_operations regmap_cache_only_fops = {
@@ -502,28 +504,32 @@ static ssize_t regmap_cache_bypass_write_file(struct file *file,
502504
{
503505
struct regmap *map = container_of(file->private_data,
504506
struct regmap, cache_bypass);
505-
ssize_t result;
506-
bool was_enabled;
507+
bool new_val;
508+
int err;
507509

508-
map->lock(map->lock_arg);
510+
err = kstrtobool_from_user(user_buf, count, &new_val);
511+
/* Ignore malforned data like debugfs_write_file_bool() */
512+
if (err)
513+
return count;
509514

510-
was_enabled = map->cache_bypass;
515+
err = debugfs_file_get(file->f_path.dentry);
516+
if (err)
517+
return err;
511518

512-
result = debugfs_write_file_bool(file, user_buf, count, ppos);
513-
if (result < 0)
514-
goto out;
519+
map->lock(map->lock_arg);
515520

516-
if (map->cache_bypass && !was_enabled) {
521+
if (new_val && !map->cache_bypass) {
517522
dev_warn(map->dev, "debugfs cache_bypass=Y forced\n");
518523
add_taint(TAINT_USER, LOCKDEP_STILL_OK);
519-
} else if (!map->cache_bypass && was_enabled) {
524+
} else if (!new_val && map->cache_bypass) {
520525
dev_warn(map->dev, "debugfs cache_bypass=N forced\n");
521526
}
527+
map->cache_bypass = new_val;
522528

523-
out:
524529
map->unlock(map->lock_arg);
530+
debugfs_file_put(file->f_path.dentry);
525531

526-
return result;
532+
return count;
527533
}
528534

529535
static const struct file_operations regmap_cache_bypass_fops = {

0 commit comments

Comments
 (0)