Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Al Viro and committed by
Greg Kroah-Hartman
f7862dfe c2a3a216

+74 -142
+5 -7
Documentation/filesystems/debugfs.rst
··· 211 211 212 212 There are a couple of other directory-oriented helper functions:: 213 213 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, ...); 218 216 219 217 struct dentry *debugfs_create_symlink(const char *name, 220 218 struct dentry *parent, 221 219 const char *target); 222 220 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. 226 224 Symbolic links can be created with debugfs_create_symlink(). 227 225 228 226 There is one important thing that all debugfs users must take into account:
+2 -7
drivers/net/bonding/bond_debugfs.c
··· 63 63 64 64 void bond_debug_reregister(struct bonding *bond) 65 65 { 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) { 73 68 netdev_warn(bond->dev, "failed to reregister, so just unregister old one\n"); 74 69 bond_debug_unregister(bond); 75 70 }
+2 -17
drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c
··· 505 505 506 506 void xgbe_debugfs_rename(struct xgbe_prv_data *pdata) 507 507 { 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); 525 510 }
+1 -4
drivers/net/ethernet/marvell/skge.c
··· 3742 3742 skge = netdev_priv(dev); 3743 3743 switch (event) { 3744 3744 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); 3749 3746 break; 3750 3747 3751 3748 case NETDEV_GOING_DOWN:
+1 -4
drivers/net/ethernet/marvell/sky2.c
··· 4494 4494 4495 4495 switch (event) { 4496 4496 case NETDEV_CHANGENAME: 4497 - if (sky2->debugfs) { 4498 - sky2->debugfs = debugfs_rename(sky2_debug, sky2->debugfs, 4499 - sky2_debug, dev->name); 4500 - } 4497 + debugfs_change_name(sky2->debugfs, "%s", dev->name); 4501 4498 break; 4502 4499 4503 4500 case NETDEV_GOING_DOWN:
+1 -5
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
··· 6489 6489 6490 6490 switch (event) { 6491 6491 case NETDEV_CHANGENAME: 6492 - if (priv->dbgfs_dir) 6493 - priv->dbgfs_dir = debugfs_rename(stmmac_fs_dir, 6494 - priv->dbgfs_dir, 6495 - stmmac_fs_dir, 6496 - dev->name); 6492 + debugfs_change_name(priv->dbgfs_dir, "%s", dev->name); 6497 6493 break; 6498 6494 } 6499 6495 done:
+4 -6
drivers/opp/debugfs.c
··· 217 217 { 218 218 struct opp_device *new_dev = NULL, *iter; 219 219 const struct device *dev; 220 - struct dentry *dentry; 220 + int err; 221 221 222 222 /* Look for next opp-dev */ 223 223 list_for_each_entry(iter, &opp_table->dev_list, node) ··· 234 234 235 235 opp_set_dev_name(dev, opp_table->dentry_name); 236 236 237 - dentry = debugfs_rename(rootdir, opp_dev->dentry, rootdir, 238 - opp_table->dentry_name); 239 - if (IS_ERR(dentry)) { 237 + err = debugfs_change_name(opp_dev->dentry, "%s", opp_table->dentry_name); 238 + if (err) { 240 239 dev_err(dev, "%s: Failed to rename link from: %s to %s\n", 241 240 __func__, dev_name(opp_dev->dev), dev_name(dev)); 242 241 return; 243 242 } 244 243 245 - new_dev->dentry = dentry; 246 - opp_table->dentry = dentry; 244 + new_dev->dentry = opp_table->dentry = opp_dev->dentry; 247 245 } 248 246 249 247 /**
+47 -53
fs/debugfs/inode.c
··· 830 830 EXPORT_SYMBOL_GPL(debugfs_lookup_and_remove); 831 831 832 832 /** 833 - * debugfs_rename - rename a file/directory in the debugfs filesystem 834 - * @old_dir: a pointer to the parent dentry for the renamed object. This 835 - * should be a directory dentry. 836 - * @old_dentry: dentry of an object to be renamed. 837 - * @new_dir: a pointer to the parent dentry where the object should be 838 - * moved. This should be a directory dentry. 839 - * @new_name: a pointer to a string containing the target name. 833 + * debugfs_change_name - rename a file/directory in the debugfs filesystem 834 + * @dentry: dentry of an object to be renamed. 835 + * @fmt: format for new name 840 836 * 841 837 * This function renames a file/directory in debugfs. The target must not 842 838 * exist for rename to succeed. 843 839 * 844 - * This function will return a pointer to old_dentry (which is updated to 845 - * reflect renaming) if it succeeds. If an error occurs, ERR_PTR(-ERROR) 846 - * will be returned. 840 + * This function will return 0 on success and -E... on failure. 847 841 * 848 842 * If debugfs is not enabled in the kernel, the value -%ENODEV will be 849 843 * returned. 850 844 */ 851 - struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry, 852 - struct dentry *new_dir, const char *new_name) 845 + int __printf(2, 3) debugfs_change_name(struct dentry *dentry, const char *fmt, ...) 853 846 { 854 - int error; 855 - struct dentry *dentry = NULL, *trap; 847 + int error = 0; 848 + const char *new_name; 856 849 struct name_snapshot old_name; 850 + struct dentry *parent, *target; 851 + struct inode *dir; 852 + va_list ap; 857 853 858 - if (IS_ERR(old_dir)) 859 - return old_dir; 860 - if (IS_ERR(new_dir)) 861 - return new_dir; 862 - if (IS_ERR_OR_NULL(old_dentry)) 863 - return old_dentry; 854 + if (IS_ERR_OR_NULL(dentry)) 855 + return 0; 864 856 865 - trap = lock_rename(new_dir, old_dir); 866 - /* Source or destination directories don't exist? */ 867 - if (d_really_is_negative(old_dir) || d_really_is_negative(new_dir)) 868 - goto exit; 869 - /* Source does not exist, cyclic rename, or mountpoint? */ 870 - if (d_really_is_negative(old_dentry) || old_dentry == trap || 871 - d_mountpoint(old_dentry)) 872 - goto exit; 873 - dentry = lookup_one_len(new_name, new_dir, strlen(new_name)); 874 - /* Lookup failed, cyclic rename or target exists? */ 875 - if (IS_ERR(dentry) || dentry == trap || d_really_is_positive(dentry)) 876 - goto exit; 857 + va_start(ap, fmt); 858 + new_name = kvasprintf_const(GFP_KERNEL, fmt, ap); 859 + va_end(ap); 860 + if (!new_name) 861 + return -ENOMEM; 877 862 878 - take_dentry_name_snapshot(&old_name, old_dentry); 863 + parent = dget_parent(dentry); 864 + dir = d_inode(parent); 865 + inode_lock(dir); 879 866 880 - error = simple_rename(&nop_mnt_idmap, d_inode(old_dir), old_dentry, 881 - d_inode(new_dir), dentry, 0); 882 - if (error) { 883 - release_dentry_name_snapshot(&old_name); 884 - goto exit; 867 + take_dentry_name_snapshot(&old_name, dentry); 868 + 869 + if (WARN_ON_ONCE(dentry->d_parent != parent)) { 870 + error = -EINVAL; 871 + goto out; 885 872 } 886 - d_move(old_dentry, dentry); 887 - fsnotify_move(d_inode(old_dir), d_inode(new_dir), &old_name.name, 888 - d_is_dir(old_dentry), 889 - NULL, old_dentry); 873 + if (strcmp(old_name.name.name, new_name) == 0) 874 + goto out; 875 + target = lookup_one_len(new_name, parent, strlen(new_name)); 876 + if (IS_ERR(target)) { 877 + error = PTR_ERR(target); 878 + goto out; 879 + } 880 + if (d_really_is_positive(target)) { 881 + dput(target); 882 + error = -EINVAL; 883 + goto out; 884 + } 885 + simple_rename_timestamp(dir, dentry, dir, target); 886 + d_move(dentry, target); 887 + dput(target); 888 + fsnotify_move(dir, dir, &old_name.name, d_is_dir(dentry), NULL, dentry); 889 + out: 890 890 release_dentry_name_snapshot(&old_name); 891 - unlock_rename(new_dir, old_dir); 892 - dput(dentry); 893 - return old_dentry; 894 - exit: 895 - if (dentry && !IS_ERR(dentry)) 896 - dput(dentry); 897 - unlock_rename(new_dir, old_dir); 898 - if (IS_ERR(dentry)) 899 - return dentry; 900 - return ERR_PTR(-EINVAL); 891 + inode_unlock(dir); 892 + dput(parent); 893 + kfree_const(new_name); 894 + return error; 901 895 } 902 - EXPORT_SYMBOL_GPL(debugfs_rename); 896 + EXPORT_SYMBOL_GPL(debugfs_change_name); 903 897 904 898 /** 905 899 * debugfs_initialized - Tells whether debugfs has been registered
+4 -5
include/linux/debugfs.h
··· 175 175 ssize_t debugfs_attr_write_signed(struct file *file, const char __user *buf, 176 176 size_t len, loff_t *ppos); 177 177 178 - struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry, 179 - struct dentry *new_dir, const char *new_name); 178 + int debugfs_change_name(struct dentry *dentry, const char *fmt, ...) __printf(2, 3); 180 179 181 180 void debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent, 182 181 u8 *value); ··· 360 361 return -ENODEV; 361 362 } 362 363 363 - static inline struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry, 364 - struct dentry *new_dir, char *new_name) 364 + static inline int __printf(2, 3) debugfs_change_name(struct dentry *dentry, 365 + const char *fmt, ...) 365 366 { 366 - return ERR_PTR(-ENODEV); 367 + return -ENODEV; 367 368 } 368 369 369 370 static inline void debugfs_create_u8(const char *name, umode_t mode,
+2 -14
mm/shrinker_debug.c
··· 195 195 196 196 int shrinker_debugfs_rename(struct shrinker *shrinker, const char *fmt, ...) 197 197 { 198 - struct dentry *entry; 199 - char buf[128]; 200 198 const char *new, *old; 201 199 va_list ap; 202 200 int ret = 0; ··· 211 213 old = shrinker->name; 212 214 shrinker->name = new; 213 215 214 - if (shrinker->debugfs_entry) { 215 - snprintf(buf, sizeof(buf), "%s-%d", shrinker->name, 216 - shrinker->debugfs_id); 217 - 218 - entry = debugfs_rename(shrinker_debugfs_root, 219 - shrinker->debugfs_entry, 220 - shrinker_debugfs_root, buf); 221 - if (IS_ERR(entry)) 222 - ret = PTR_ERR(entry); 223 - else 224 - shrinker->debugfs_entry = entry; 225 - } 216 + ret = debugfs_change_name(shrinker->debugfs_entry, "%s-%d", 217 + shrinker->name, shrinker->debugfs_id); 226 218 227 219 mutex_unlock(&shrinker_mutex); 228 220
+3 -6
net/hsr/hsr_debugfs.c
··· 57 57 void hsr_debugfs_rename(struct net_device *dev) 58 58 { 59 59 struct hsr_priv *priv = netdev_priv(dev); 60 - struct dentry *d; 60 + int err; 61 61 62 - d = debugfs_rename(hsr_debugfs_root_dir, priv->node_tbl_root, 63 - hsr_debugfs_root_dir, dev->name); 64 - if (IS_ERR(d)) 62 + err = debugfs_change_name(priv->node_tbl_root, "%s", dev->name); 63 + if (err) 65 64 netdev_warn(dev, "failed to rename\n"); 66 - else 67 - priv->node_tbl_root = d; 68 65 } 69 66 70 67 /* hsr_debugfs_init - create hsr node_table file for dumping
+1 -10
net/mac80211/debugfs_netdev.c
··· 1025 1025 1026 1026 void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata) 1027 1027 { 1028 - struct dentry *dir; 1029 - char buf[10 + IFNAMSIZ]; 1030 - 1031 - dir = sdata->vif.debugfs_dir; 1032 - 1033 - if (IS_ERR_OR_NULL(dir)) 1034 - return; 1035 - 1036 - sprintf(buf, "netdev:%s", sdata->name); 1037 - debugfs_rename(dir->d_parent, dir, dir->d_parent, buf); 1028 + debugfs_change_name(sdata->vif.debugfs_dir, "netdev:%s", sdata->name); 1038 1029 } 1039 1030 1040 1031 void ieee80211_debugfs_recreate_netdev(struct ieee80211_sub_if_data *sdata,
+1 -4
net/wireless/core.c
··· 143 143 if (result) 144 144 return result; 145 145 146 - if (!IS_ERR_OR_NULL(rdev->wiphy.debugfsdir)) 147 - debugfs_rename(rdev->wiphy.debugfsdir->d_parent, 148 - rdev->wiphy.debugfsdir, 149 - rdev->wiphy.debugfsdir->d_parent, newname); 146 + debugfs_change_name(rdev->wiphy.debugfsdir, "%s", newname); 150 147 151 148 nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY); 152 149