From: Al Viro Date: Tue, 12 May 2026 07:19:41 +0000 (-0400) Subject: configfs: dentry refcount needs to be pinned only once X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1a29e25799bcd7c3b2285f46e2c630b62d969b25;p=thirdparty%2Fkernel%2Flinux.git configfs: dentry refcount needs to be pinned only once currently we have a weird situation where * symlinks and roots of subtrees created by mkdir are pinned once * subdirectories of subtrees created by mkdir are pinned twice * roots of subtrees created by register_{group,subsystem} are pinned twice. It makes things harder to follow for no good reason. The goal is to encapsulate the unbalanced dget/dput into d_{make,discard}_persisitent() and, preferably, allow a use of simple_recursive_removal() or analogue thereof. So let's regularize that and pin things only once. create_default_group() and configfs_register_subsystem() don't need to keep their reference around on success - configfs_create_dir() has pinned the sucker already. So we can drop the reference passed to configfs_create_dir() (via configfs_attach_group(), etc.) both on success and on failure. On the removal side we no longer have the double references, so we need an explicit dget() to compensate. Reviewed-by: Jan Kara Signed-off-by: Al Viro --- diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 87a0847d88b9d..4836ffb3b70f7 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -657,7 +657,7 @@ static void detach_groups(struct dentry *dentry) if (!(sd->s_type & CONFIGFS_USET_DEFAULT)) continue; - child = sd->s_dentry; + child = dget(sd->s_dentry); spin_unlock(&configfs_dirent_lock); inode_lock(d_inode(child)); @@ -708,8 +708,8 @@ static int create_default_group(struct config_group *parent_group, } else { BUG_ON(d_inode(child)); d_drop(child); - dput(child); } + dput(child); } return ret; @@ -1781,7 +1781,7 @@ EXPORT_SYMBOL(configfs_register_group); void configfs_unregister_group(struct config_group *group) { struct configfs_subsystem *subsys = group->cg_subsys; - struct dentry *dentry = group->cg_item.ci_dentry; + struct dentry *dentry = dget(group->cg_item.ci_dentry); struct dentry *parent = group->cg_item.ci_parent->ci_dentry; struct configfs_dirent *sd = dentry->d_fsdata; struct configfs_fragment *frag = sd->s_frag; @@ -1896,12 +1896,12 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys) if (err) { BUG_ON(d_inode(dentry)); d_drop(dentry); - dput(dentry); } else { spin_lock(&configfs_dirent_lock); configfs_dir_set_ready(dentry->d_fsdata); spin_unlock(&configfs_dirent_lock); } + dput(dentry); } inode_unlock(d_inode(root)); @@ -1920,7 +1920,7 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys) void configfs_unregister_subsystem(struct configfs_subsystem *subsys) { struct config_group *group = &subsys->su_group; - struct dentry *dentry = group->cg_item.ci_dentry; + struct dentry *dentry = dget(group->cg_item.ci_dentry); struct dentry *root = dentry->d_sb->s_root; struct configfs_dirent *sd = dentry->d_fsdata; struct configfs_fragment *frag = sd->s_frag;