Skip to content

Commit 615def7

Browse files
committed
saner replacement for debugfs_rename()
JIRA: https://issues.redhat.com/browse/RHEL-87378 commit f7862df Author: Al Viro <viro@zeniv.linux.org.uk> Date: Sun Jan 12 08:07:05 2025 +0000 saner replacement for debugfs_rename() Existing primitive has several problems: 1) calling conventions are clumsy - it returns a dentry reference that is either identical to its second argument or is an ERR_PTR(-E...); in both cases no refcount changes happen. Inconvenient for users and bug-prone; it would be better to have it return 0 on success and -E... on failure. 2) it allows cross-directory moves; however, no such caller have ever materialized and considering the way debugfs is used, it's unlikely to happen in the future. What's more, any such caller would have fun issues to deal with wrt interplay with recursive removal. It also makes the calling conventions clumsier... 3) tautological rename fails; the callers have no race-free way to deal with that. 4) new name must have been formed by the caller; quite a few callers have it done by sprintf/kasprintf/etc., ending up with considerable boilerplate. Proposed replacement: int debugfs_change_name(dentry, fmt, ...). All callers convert to that easily, and it's simpler internally. IMO debugfs_rename() should go; if we ever get a real-world use case for cross-directory moves in debugfs, we can always look into the right way to handle that. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Link: https://lore.kernel.org/r/20250112080705.141166-21-viro@zeniv.linux.org.uk Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
1 parent e095420 commit 615def7

File tree

13 files changed

+77
-145
lines changed

13 files changed

+77
-145
lines changed

Documentation/filesystems/debugfs.rst

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -211,18 +211,16 @@ seq_file content.
211211

212212
There are a couple of other directory-oriented helper functions::
213213

214-
struct dentry *debugfs_rename(struct dentry *old_dir,
215-
struct dentry *old_dentry,
216-
struct dentry *new_dir,
217-
const char *new_name);
214+
struct dentry *debugfs_change_name(struct dentry *dentry,
215+
const char *fmt, ...);
218216

219217
struct dentry *debugfs_create_symlink(const char *name,
220218
struct dentry *parent,
221219
const char *target);
222220

223-
A call to debugfs_rename() will give a new name to an existing debugfs
224-
file, possibly in a different directory. The new_name must not exist prior
225-
to the call; the return value is old_dentry with updated information.
221+
A call to debugfs_change_name() will give a new name to an existing debugfs
222+
file, always in the same directory. The new_name must not exist prior
223+
to the call; the return value is 0 on success and -E... on failuer.
226224
Symbolic links can be created with debugfs_create_symlink().
227225

228226
There is one important thing that all debugfs users must take into account:

drivers/net/bonding/bond_debugfs.c

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,8 @@ void bond_debug_unregister(struct bonding *bond)
6363

6464
void bond_debug_reregister(struct bonding *bond)
6565
{
66-
struct dentry *d;
67-
68-
d = debugfs_rename(bonding_debug_root, bond->debug_dir,
69-
bonding_debug_root, bond->dev->name);
70-
if (!IS_ERR(d)) {
71-
bond->debug_dir = d;
72-
} else {
66+
int err = debugfs_change_name(bond->debug_dir, "%s", bond->dev->name);
67+
if (err) {
7368
netdev_warn(bond->dev, "failed to reregister, so just unregister old one\n");
7469
bond_debug_unregister(bond);
7570
}

drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -505,21 +505,6 @@ void xgbe_debugfs_exit(struct xgbe_prv_data *pdata)
505505

506506
void xgbe_debugfs_rename(struct xgbe_prv_data *pdata)
507507
{
508-
char *buf;
509-
510-
if (!pdata->xgbe_debugfs)
511-
return;
512-
513-
buf = kasprintf(GFP_KERNEL, "amd-xgbe-%s", pdata->netdev->name);
514-
if (!buf)
515-
return;
516-
517-
if (!strcmp(pdata->xgbe_debugfs->d_name.name, buf))
518-
goto out;
519-
520-
debugfs_rename(pdata->xgbe_debugfs->d_parent, pdata->xgbe_debugfs,
521-
pdata->xgbe_debugfs->d_parent, buf);
522-
523-
out:
524-
kfree(buf);
508+
debugfs_change_name(pdata->xgbe_debugfs,
509+
"amd-xgbe-%s", pdata->netdev->name);
525510
}

drivers/net/ethernet/marvell/skge.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3742,10 +3742,7 @@ static int skge_device_event(struct notifier_block *unused,
37423742
skge = netdev_priv(dev);
37433743
switch (event) {
37443744
case NETDEV_CHANGENAME:
3745-
if (skge->debugfs)
3746-
skge->debugfs = debugfs_rename(skge_debug,
3747-
skge->debugfs,
3748-
skge_debug, dev->name);
3745+
debugfs_change_name(skge->debugfs, "%s", dev->name);
37493746
break;
37503747

37513748
case NETDEV_GOING_DOWN:

drivers/net/ethernet/marvell/sky2.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4635,10 +4635,7 @@ static int sky2_device_event(struct notifier_block *unused,
46354635

46364636
switch (event) {
46374637
case NETDEV_CHANGENAME:
4638-
if (sky2->debugfs) {
4639-
sky2->debugfs = debugfs_rename(sky2_debug, sky2->debugfs,
4640-
sky2_debug, dev->name);
4641-
}
4638+
debugfs_change_name(sky2->debugfs, "%s", dev->name);
46424639
break;
46434640

46444641
case NETDEV_GOING_DOWN:

drivers/net/ethernet/stmicro/stmmac/stmmac_main.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6564,11 +6564,7 @@ static int stmmac_device_event(struct notifier_block *unused,
65646564

65656565
switch (event) {
65666566
case NETDEV_CHANGENAME:
6567-
if (priv->dbgfs_dir)
6568-
priv->dbgfs_dir = debugfs_rename(stmmac_fs_dir,
6569-
priv->dbgfs_dir,
6570-
stmmac_fs_dir,
6571-
dev->name);
6567+
debugfs_change_name(priv->dbgfs_dir, "%s", dev->name);
65726568
break;
65736569
}
65746570
done:

drivers/opp/debugfs.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ static void opp_migrate_dentry(struct opp_device *opp_dev,
215215
{
216216
struct opp_device *new_dev = NULL, *iter;
217217
const struct device *dev;
218-
struct dentry *dentry;
218+
int err;
219219

220220
/* Look for next opp-dev */
221221
list_for_each_entry(iter, &opp_table->dev_list, node)
@@ -232,16 +232,14 @@ static void opp_migrate_dentry(struct opp_device *opp_dev,
232232

233233
opp_set_dev_name(dev, opp_table->dentry_name);
234234

235-
dentry = debugfs_rename(rootdir, opp_dev->dentry, rootdir,
236-
opp_table->dentry_name);
237-
if (IS_ERR(dentry)) {
235+
err = debugfs_change_name(opp_dev->dentry, "%s", opp_table->dentry_name);
236+
if (err) {
238237
dev_err(dev, "%s: Failed to rename link from: %s to %s\n",
239238
__func__, dev_name(opp_dev->dev), dev_name(dev));
240239
return;
241240
}
242241

243-
new_dev->dentry = dentry;
244-
opp_table->dentry = dentry;
242+
new_dev->dentry = opp_table->dentry = opp_dev->dentry;
245243
}
246244

247245
/**

fs/debugfs/inode.c

Lines changed: 50 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -812,76 +812,70 @@ void debugfs_lookup_and_remove(const char *name, struct dentry *parent)
812812
EXPORT_SYMBOL_GPL(debugfs_lookup_and_remove);
813813

814814
/**
815-
* debugfs_rename - rename a file/directory in the debugfs filesystem
816-
* @old_dir: a pointer to the parent dentry for the renamed object. This
817-
* should be a directory dentry.
818-
* @old_dentry: dentry of an object to be renamed.
819-
* @new_dir: a pointer to the parent dentry where the object should be
820-
* moved. This should be a directory dentry.
821-
* @new_name: a pointer to a string containing the target name.
815+
* debugfs_change_name - rename a file/directory in the debugfs filesystem
816+
* @dentry: dentry of an object to be renamed.
817+
* @fmt: format for new name
822818
*
823819
* This function renames a file/directory in debugfs. The target must not
824820
* exist for rename to succeed.
825821
*
826-
* This function will return a pointer to old_dentry (which is updated to
827-
* reflect renaming) if it succeeds. If an error occurs, ERR_PTR(-ERROR)
828-
* will be returned.
822+
* This function will return 0 on success and -E... on failure.
829823
*
830824
* If debugfs is not enabled in the kernel, the value -%ENODEV will be
831825
* returned.
832826
*/
833-
struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
834-
struct dentry *new_dir, const char *new_name)
827+
int __printf(2, 3) debugfs_change_name(struct dentry *dentry, const char *fmt, ...)
835828
{
836-
int error;
837-
struct dentry *dentry = NULL, *trap;
829+
int error = 0;
830+
const char *new_name;
838831
struct name_snapshot old_name;
832+
struct dentry *parent, *target;
833+
struct inode *dir;
834+
va_list ap;
839835

840-
if (IS_ERR(old_dir))
841-
return old_dir;
842-
if (IS_ERR(new_dir))
843-
return new_dir;
844-
if (IS_ERR_OR_NULL(old_dentry))
845-
return old_dentry;
846-
847-
trap = lock_rename(new_dir, old_dir);
848-
/* Source or destination directories don't exist? */
849-
if (d_really_is_negative(old_dir) || d_really_is_negative(new_dir))
850-
goto exit;
851-
/* Source does not exist, cyclic rename, or mountpoint? */
852-
if (d_really_is_negative(old_dentry) || old_dentry == trap ||
853-
d_mountpoint(old_dentry))
854-
goto exit;
855-
dentry = lookup_one_len(new_name, new_dir, strlen(new_name));
856-
/* Lookup failed, cyclic rename or target exists? */
857-
if (IS_ERR(dentry) || dentry == trap || d_really_is_positive(dentry))
858-
goto exit;
859-
860-
take_dentry_name_snapshot(&old_name, old_dentry);
861-
862-
error = simple_rename(&nop_mnt_idmap, d_inode(old_dir), old_dentry,
863-
d_inode(new_dir), dentry, 0);
864-
if (error) {
865-
release_dentry_name_snapshot(&old_name);
866-
goto exit;
836+
if (IS_ERR_OR_NULL(dentry))
837+
return 0;
838+
839+
va_start(ap, fmt);
840+
new_name = kvasprintf_const(GFP_KERNEL, fmt, ap);
841+
va_end(ap);
842+
if (!new_name)
843+
return -ENOMEM;
844+
845+
parent = dget_parent(dentry);
846+
dir = d_inode(parent);
847+
inode_lock(dir);
848+
849+
take_dentry_name_snapshot(&old_name, dentry);
850+
851+
if (WARN_ON_ONCE(dentry->d_parent != parent)) {
852+
error = -EINVAL;
853+
goto out;
854+
}
855+
if (strcmp(old_name.name.name, new_name) == 0)
856+
goto out;
857+
target = lookup_one_len(new_name, parent, strlen(new_name));
858+
if (IS_ERR(target)) {
859+
error = PTR_ERR(target);
860+
goto out;
867861
}
868-
d_move(old_dentry, dentry);
869-
fsnotify_move(d_inode(old_dir), d_inode(new_dir), &old_name.name,
870-
d_is_dir(old_dentry),
871-
NULL, old_dentry);
862+
if (d_really_is_positive(target)) {
863+
dput(target);
864+
error = -EINVAL;
865+
goto out;
866+
}
867+
simple_rename_timestamp(dir, dentry, dir, target);
868+
d_move(dentry, target);
869+
dput(target);
870+
fsnotify_move(dir, dir, &old_name.name, d_is_dir(dentry), NULL, dentry);
871+
out:
872872
release_dentry_name_snapshot(&old_name);
873-
unlock_rename(new_dir, old_dir);
874-
dput(dentry);
875-
return old_dentry;
876-
exit:
877-
if (dentry && !IS_ERR(dentry))
878-
dput(dentry);
879-
unlock_rename(new_dir, old_dir);
880-
if (IS_ERR(dentry))
881-
return dentry;
882-
return ERR_PTR(-EINVAL);
873+
inode_unlock(dir);
874+
dput(parent);
875+
kfree_const(new_name);
876+
return error;
883877
}
884-
EXPORT_SYMBOL_GPL(debugfs_rename);
878+
EXPORT_SYMBOL_GPL(debugfs_change_name);
885879

886880
/**
887881
* debugfs_initialized - Tells whether debugfs has been registered

include/linux/debugfs.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,7 @@ ssize_t debugfs_attr_write(struct file *file, const char __user *buf,
176176
ssize_t debugfs_attr_write_signed(struct file *file, const char __user *buf,
177177
size_t len, loff_t *ppos);
178178

179-
struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
180-
struct dentry *new_dir, const char *new_name);
179+
int debugfs_change_name(struct dentry *dentry, const char *fmt, ...) __printf(2, 3);
181180

182181
void debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent,
183182
u8 *value);
@@ -362,10 +361,10 @@ static inline ssize_t debugfs_attr_write_signed(struct file *file,
362361
return -ENODEV;
363362
}
364363

365-
static inline struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
366-
struct dentry *new_dir, char *new_name)
364+
static inline int __printf(2, 3) debugfs_change_name(struct dentry *dentry,
365+
const char *fmt, ...)
367366
{
368-
return ERR_PTR(-ENODEV);
367+
return -ENODEV;
369368
}
370369

371370
static inline void debugfs_create_u8(const char *name, umode_t mode,

mm/shrinker_debug.c

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,6 @@ int shrinker_debugfs_add(struct shrinker *shrinker)
195195

196196
int shrinker_debugfs_rename(struct shrinker *shrinker, const char *fmt, ...)
197197
{
198-
struct dentry *entry;
199-
char buf[128];
200198
const char *new, *old;
201199
va_list ap;
202200
int ret = 0;
@@ -213,18 +211,8 @@ int shrinker_debugfs_rename(struct shrinker *shrinker, const char *fmt, ...)
213211
old = shrinker->name;
214212
shrinker->name = new;
215213

216-
if (shrinker->debugfs_entry) {
217-
snprintf(buf, sizeof(buf), "%s-%d", shrinker->name,
218-
shrinker->debugfs_id);
219-
220-
entry = debugfs_rename(shrinker_debugfs_root,
221-
shrinker->debugfs_entry,
222-
shrinker_debugfs_root, buf);
223-
if (IS_ERR(entry))
224-
ret = PTR_ERR(entry);
225-
else
226-
shrinker->debugfs_entry = entry;
227-
}
214+
ret = debugfs_change_name(shrinker->debugfs_entry, "%s-%d",
215+
shrinker->name, shrinker->debugfs_id);
228216

229217
up_write(&shrinker_rwsem);
230218

0 commit comments

Comments
 (0)