Re: [PATCH v5 10/14] VFS/ovl/smb: introduce start_renaming_dentry()

Jeff Layton <[email protected]>
Newsgroups org.kernel.vger.ecryptfs,dev.linux.lists.netfs,org.kernel.vger.linux-cifs,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-nfs,org.kernel.vger.linux-security-module,org.kernel.vger.linux-unionfs,org.kernel.vger.linux-xfs,org.kernel.vger.selinux
Message-ID <[email protected]>
On Thu, 2025-11-06 at 11:50 +1100, NeilBrown wrote:
> From: NeilBrown <[email protected]>
> 
> Several callers perform a rename on a dentry they already have, and only
> require lookup for the target name.  This includes smb/server and a few
> different places in overlayfs.
> 
> start_renaming_dentry() performs the required lookup and takes the
> required lock using lock_rename_child()
> 
> It is used in three places in overlayfs and in ksmbd_vfs_rename().
> 
> In the ksmbd case, the parent of the source is not important - the
> source must be renamed from wherever it is.  So start_renaming_dentry()
> allows rd->old_parent to be NULL and only checks it if it is non-NULL.
> On success rd->old_parent will be the parent of old_dentry with an extra
> reference taken.  Other start_renaming function also now take the extra
> reference and end_renaming() now drops this reference as well.
> 
> ovl_lookup_temp(), ovl_parent_lock(), and ovl_parent_unlock() are
> all removed as they are no longer needed.
> 
> OVL_TEMPNAME_SIZE and ovl_tempname() are now declared in overlayfs.h so
> that ovl_check_rename_whiteout() can access them.
> 
> ovl_copy_up_workdir() now always cleans up on error.
> 
> Reviewed-by: Namjae Jeon <[email protected]> (for ksmbd part)
> Reviewed-by: Amir Goldstein <[email protected]>
> Signed-off-by: NeilBrown <[email protected]>
> ---
>  fs/namei.c               | 108 ++++++++++++++++++++++++++++++++++++---
>  fs/overlayfs/copy_up.c   |  54 +++++++++-----------
>  fs/overlayfs/dir.c       |  19 +------
>  fs/overlayfs/overlayfs.h |   8 +--
>  fs/overlayfs/super.c     |  22 ++++----
>  fs/overlayfs/util.c      |  11 ----
>  fs/smb/server/vfs.c      |  60 ++++------------------
>  include/linux/namei.h    |   2 +
>  8 files changed, 150 insertions(+), 134 deletions(-)
> 
> diff --git a/fs/namei.c b/fs/namei.c
> index bad6c9d540f9..4b740048df97 100644
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -3669,7 +3669,7 @@ EXPORT_SYMBOL(unlock_rename);
>  
>  /**
>   * __start_renaming - lookup and lock names for rename
> - * @rd:           rename data containing parent and flags, and
> + * @rd:           rename data containing parents and flags, and
>   *                for receiving found dentries
>   * @lookup_flags: extra flags to pass to ->lookup (e.g. LOOKUP_REVAL,
>   *                LOOKUP_NO_SYMLINKS etc).
> @@ -3680,8 +3680,8 @@ EXPORT_SYMBOL(unlock_rename);
>   * rename.
>   *
>   * On success the found dentries are stored in @rd.old_dentry,
> - * @rd.new_dentry.  These references and the lock are dropped by
> - * end_renaming().
> + * @rd.new_dentry and an extra ref is taken on @rd.old_parent.
> + * These references and the lock are dropped by end_renaming().
>   *
>   * The passed in qstrs must have the hash calculated, and no permission
>   * checking is performed.
> @@ -3735,6 +3735,7 @@ __start_renaming(struct renamedata *rd, int lookup_flags,
>  
>  	rd->old_dentry = d1;
>  	rd->new_dentry = d2;
> +	dget(rd->old_parent);
>  	return 0;
>  
>  out_dput_d2:
> @@ -3748,7 +3749,7 @@ __start_renaming(struct renamedata *rd, int lookup_flags,
>  
>  /**
>   * start_renaming - lookup and lock names for rename with permission checking
> - * @rd:           rename data containing parent and flags, and
> + * @rd:           rename data containing parents and flags, and
>   *                for receiving found dentries
>   * @lookup_flags: extra flags to pass to ->lookup (e.g. LOOKUP_REVAL,
>   *                LOOKUP_NO_SYMLINKS etc).
> @@ -3759,8 +3760,8 @@ __start_renaming(struct renamedata *rd, int lookup_flags,
>   * rename.
>   *
>   * On success the found dentries are stored in @rd.old_dentry,
> - * @rd.new_dentry.  These references and the lock are dropped by
> - * end_renaming().
> + * @rd.new_dentry.  Also the refcount on @rd->old_parent is increased.
> + * These references and the lock are dropped by end_renaming().
>   *
>   * The passed in qstrs need not have the hash calculated, and basic
>   * eXecute permission checking is performed against @rd.mnt_idmap.
> @@ -3782,11 +3783,106 @@ int start_renaming(struct renamedata *rd, int lookup_flags,
>  }
>  EXPORT_SYMBOL(start_renaming);
>  
> +static int
> +__start_renaming_dentry(struct renamedata *rd, int lookup_flags,
> +			struct dentry *old_dentry, struct qstr *new_last)
> +{
> +	struct dentry *trap;
> +	struct dentry *d2;
> +	int target_flags = LOOKUP_RENAME_TARGET | LOOKUP_CREATE;
> +	int err;
> +
> +	if (rd->flags & RENAME_EXCHANGE)
> +		target_flags = 0;
> +	if (rd->flags & RENAME_NOREPLACE)
> +		target_flags |= LOOKUP_EXCL;
> +
> +	/* Already have the dentry - need to be sure to lock the correct parent */
> +	trap = lock_rename_child(old_dentry, rd->new_parent);
> +	if (IS_ERR(trap))
> +		return PTR_ERR(trap);
> +	if (d_unhashed(old_dentry) ||
> +	    (rd->old_parent && rd->old_parent != old_dentry->d_parent)) {
> +		/* dentry was removed, or moved and explicit parent requested */
> +		err = -EINVAL;
> +		goto out_unlock;
> +	}
> +
> +	d2 = lookup_one_qstr_excl(new_last, rd->new_parent,
> +				  lookup_flags | target_flags);
> +	err = PTR_ERR(d2);
> +	if (IS_ERR(d2))
> +		goto out_unlock;
> +
> +	if (old_dentry == trap) {
> +		/* source is an ancestor of target */
> +		err = -EINVAL;
> +		goto out_dput_d2;
> +	}
> +
> +	if (d2 == trap) {
> +		/* target is an ancestor of source */
> +		if (rd->flags & RENAME_EXCHANGE)
> +			err = -EINVAL;
> +		else
> +			err = -ENOTEMPTY;
> +		goto out_dput_d2;
> +	}
> +
> +	rd->old_dentry = dget(old_dentry);
> +	rd->new_dentry = d2;
> +	rd->old_parent = dget(old_dentry->d_parent);
> +	return 0;
> +
> +out_dput_d2:
> +	dput(d2);
> +out_unlock:
> +	unlock_rename(old_dentry->d_parent, rd->new_parent);
> +	return err;
> +}
> +
> +/**
> + * start_renaming_dentry - lookup and lock name for rename with permission checking
> + * @rd:           rename data containing parents and flags, and
> + *                for receiving found dentries
> + * @lookup_flags: extra flags to pass to ->lookup (e.g. LOOKUP_REVAL,
> + *                LOOKUP_NO_SYMLINKS etc).
> + * @old_dentry:   dentry of name to move
> + * @new_last:     name of target in @rd.new_parent
> + *
> + * Look up target name and ensure locks are in place for
> + * rename.
> + *
> + * On success the found dentry is stored in @rd.new_dentry and
> + * @rd.old_parent is confirmed to be the parent of @old_dentry.  If it
> + * was originally %NULL, it is set.  In either case a reference is taken
> + * so that end_renaming() can have a stable reference to unlock.
> + *
> + * References and the lock can be dropped with end_renaming()
> + *
> + * The passed in qstr need not have the hash calculated, and basic
> + * eXecute permission checking is performed against @rd.mnt_idmap.
> + *
> + * Returns: zero or an error.
> + */
> +int start_renaming_dentry(struct renamedata *rd, int lookup_flags,
> +			  struct dentry *old_dentry, struct qstr *new_last)
> +{
> +	int err;
> +
> +	err = lookup_one_common(rd->mnt_idmap, new_last, rd->new_parent);
> +	if (err)
> +		return err;
> +	return __start_renaming_dentry(rd, lookup_flags, old_dentry, new_last);
> +}
> +EXPORT_SYMBOL(start_renaming_dentry);
> +
>  void end_renaming(struct renamedata *rd)
>  {
>  	unlock_rename(rd->old_parent, rd->new_parent);
>  	dput(rd->old_dentry);
>  	dput(rd->new_dentry);
> +	dput(rd->old_parent);
>  }
>  EXPORT_SYMBOL(end_renaming);
>  
> diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
> index e2bdac4317e7..9911a346b477 100644
> --- a/fs/overlayfs/copy_up.c
> +++ b/fs/overlayfs/copy_up.c
> @@ -523,8 +523,8 @@ static int ovl_create_index(struct dentry *dentry, const struct ovl_fh *fh,
>  {
>  	struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
>  	struct dentry *indexdir = ovl_indexdir(dentry->d_sb);
> -	struct dentry *index = NULL;
>  	struct dentry *temp = NULL;
> +	struct renamedata rd = {};
>  	struct qstr name = { };
>  	int err;
>  
> @@ -556,17 +556,15 @@ static int ovl_create_index(struct dentry *dentry, const struct ovl_fh *fh,
>  	if (err)
>  		goto out;
>  
> -	err = ovl_parent_lock(indexdir, temp);
> +	rd.mnt_idmap = ovl_upper_mnt_idmap(ofs);
> +	rd.old_parent = indexdir;
> +	rd.new_parent = indexdir;
> +	err = start_renaming_dentry(&rd, 0, temp, &name);
>  	if (err)
>  		goto out;
> -	index = ovl_lookup_upper(ofs, name.name, indexdir, name.len);
> -	if (IS_ERR(index)) {
> -		err = PTR_ERR(index);
> -	} else {
> -		err = ovl_do_rename(ofs, indexdir, temp, indexdir, index, 0);
> -		dput(index);
> -	}
> -	ovl_parent_unlock(indexdir);
> +
> +	err = ovl_do_rename_rd(&rd);
> +	end_renaming(&rd);
>  out:
>  	if (err)
>  		ovl_cleanup(ofs, indexdir, temp);
> @@ -763,7 +761,8 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
>  	struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
>  	struct inode *inode;
>  	struct path path = { .mnt = ovl_upper_mnt(ofs) };
> -	struct dentry *temp, *upper, *trap;
> +	struct renamedata rd = {};
> +	struct dentry *temp;
>  	struct ovl_cu_creds cc;
>  	int err;
>  	struct ovl_cattr cattr = {
> @@ -807,29 +806,24 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
>  	 * ovl_copy_up_data(), so lock workdir and destdir and make sure that
>  	 * temp wasn't moved before copy up completion or cleanup.
>  	 */
> -	trap = lock_rename(c->workdir, c->destdir);
> -	if (trap || temp->d_parent != c->workdir) {
> -		/* temp or workdir moved underneath us? abort without cleanup */
> -		dput(temp);
> +	rd.mnt_idmap = ovl_upper_mnt_idmap(ofs);
> +	rd.old_parent = c->workdir;
> +	rd.new_parent = c->destdir;
> +	rd.flags = 0;
> +	err = start_renaming_dentry(&rd, 0, temp,
> +				    &QSTR_LEN(c->destname.name, c->destname.len));
> +	if (err) {
> +		/* temp or workdir moved underneath us? map to -EIO */
>  		err = -EIO;
> -		if (!IS_ERR(trap))
> -			unlock_rename(c->workdir, c->destdir);
> -		goto out;
>  	}
> -
> -	err = ovl_copy_up_metadata(c, temp);
>  	if (err)
> -		goto cleanup;
> +		goto cleanup_unlocked;
>  
> -	upper = ovl_lookup_upper(ofs, c->destname.name, c->destdir,
> -				 c->destname.len);
> -	err = PTR_ERR(upper);
> -	if (IS_ERR(upper))
> -		goto cleanup;
> +	err = ovl_copy_up_metadata(c, temp);
> +	if (!err)
> +		err = ovl_do_rename_rd(&rd);
> +	end_renaming(&rd);
>  
> -	err = ovl_do_rename(ofs, c->workdir, temp, c->destdir, upper, 0);
> -	unlock_rename(c->workdir, c->destdir);
> -	dput(upper);
>  	if (err)
>  		goto cleanup_unlocked;
>  
> @@ -850,8 +844,6 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
>  
>  	return err;
>  
> -cleanup:
> -	unlock_rename(c->workdir, c->destdir);
>  cleanup_unlocked:
>  	ovl_cleanup(ofs, c->workdir, temp);
>  	dput(temp);
> diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
> index cf6fc48459f3..6b2f88edb497 100644
> --- a/fs/overlayfs/dir.c
> +++ b/fs/overlayfs/dir.c
> @@ -57,8 +57,7 @@ int ovl_cleanup(struct ovl_fs *ofs, struct dentry *workdir,
>  	return 0;
>  }
>  
> -#define OVL_TEMPNAME_SIZE 20
> -static void ovl_tempname(char name[OVL_TEMPNAME_SIZE])
> +void ovl_tempname(char name[OVL_TEMPNAME_SIZE])
>  {
>  	static atomic_t temp_id = ATOMIC_INIT(0);
>  
> @@ -66,22 +65,6 @@ static void ovl_tempname(char name[OVL_TEMPNAME_SIZE])
>  	snprintf(name, OVL_TEMPNAME_SIZE, "#%x", atomic_inc_return(&temp_id));
>  }
>  
> -struct dentry *ovl_lookup_temp(struct ovl_fs *ofs, struct dentry *workdir)
> -{
> -	struct dentry *temp;
> -	char name[OVL_TEMPNAME_SIZE];
> -
> -	ovl_tempname(name);
> -	temp = ovl_lookup_upper(ofs, name, workdir, strlen(name));
> -	if (!IS_ERR(temp) && temp->d_inode) {
> -		pr_err("workdir/%s already exists\n", name);
> -		dput(temp);
> -		temp = ERR_PTR(-EIO);
> -	}
> -
> -	return temp;
> -}
> -
>  static struct dentry *ovl_start_creating_temp(struct ovl_fs *ofs,
>  					      struct dentry *workdir)
>  {
> diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
> index 3cc85a893b5c..746bc4ad7b37 100644
> --- a/fs/overlayfs/overlayfs.h
> +++ b/fs/overlayfs/overlayfs.h
> @@ -447,11 +447,6 @@ static inline bool ovl_open_flags_need_copy_up(int flags)
>  }
>  
>  /* util.c */
> -int ovl_parent_lock(struct dentry *parent, struct dentry *child);
> -static inline void ovl_parent_unlock(struct dentry *parent)
> -{
> -	inode_unlock(parent->d_inode);
> -}
>  int ovl_get_write_access(struct dentry *dentry);
>  void ovl_put_write_access(struct dentry *dentry);
>  void ovl_start_write(struct dentry *dentry);
> @@ -888,7 +883,8 @@ struct dentry *ovl_create_real(struct ovl_fs *ofs,
>  			       struct dentry *parent, struct dentry *newdentry,
>  			       struct ovl_cattr *attr);
>  int ovl_cleanup(struct ovl_fs *ofs, struct dentry *workdir, struct dentry *dentry);
> -struct dentry *ovl_lookup_temp(struct ovl_fs *ofs, struct dentry *workdir);
> +#define OVL_TEMPNAME_SIZE 20
> +void ovl_tempname(char name[OVL_TEMPNAME_SIZE]);
>  struct dentry *ovl_create_temp(struct ovl_fs *ofs, struct dentry *workdir,
>  			       struct ovl_cattr *attr);
>  
> diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
> index 6e0816c1147a..a721ef2b90e8 100644
> --- a/fs/overlayfs/super.c
> +++ b/fs/overlayfs/super.c
> @@ -566,9 +566,10 @@ static int ovl_check_rename_whiteout(struct ovl_fs *ofs)
>  {
>  	struct dentry *workdir = ofs->workdir;
>  	struct dentry *temp;
> -	struct dentry *dest;
>  	struct dentry *whiteout;
>  	struct name_snapshot name;
> +	struct renamedata rd = {};
> +	char name2[OVL_TEMPNAME_SIZE];
>  	int err;
>  
>  	temp = ovl_create_temp(ofs, workdir, OVL_CATTR(S_IFREG | 0));
> @@ -576,23 +577,21 @@ static int ovl_check_rename_whiteout(struct ovl_fs *ofs)
>  	if (IS_ERR(temp))
>  		return err;
>  
> -	err = ovl_parent_lock(workdir, temp);
> +	rd.mnt_idmap = ovl_upper_mnt_idmap(ofs);
> +	rd.old_parent = workdir;
> +	rd.new_parent = workdir;
> +	rd.flags = RENAME_WHITEOUT;
> +	ovl_tempname(name2);
> +	err = start_renaming_dentry(&rd, 0, temp, &QSTR(name2));
>  	if (err) {
>  		dput(temp);
>  		return err;
>  	}
> -	dest = ovl_lookup_temp(ofs, workdir);
> -	err = PTR_ERR(dest);
> -	if (IS_ERR(dest)) {
> -		dput(temp);
> -		ovl_parent_unlock(workdir);
> -		return err;
> -	}
>  
>  	/* Name is inline and stable - using snapshot as a copy helper */
>  	take_dentry_name_snapshot(&name, temp);
> -	err = ovl_do_rename(ofs, workdir, temp, workdir, dest, RENAME_WHITEOUT);
> -	ovl_parent_unlock(workdir);
> +	err = ovl_do_rename_rd(&rd);
> +	end_renaming(&rd);
>  	if (err) {
>  		if (err == -EINVAL)
>  			err = 0;
> @@ -616,7 +615,6 @@ static int ovl_check_rename_whiteout(struct ovl_fs *ofs)
>  	ovl_cleanup(ofs, workdir, temp);
>  	release_dentry_name_snapshot(&name);
>  	dput(temp);
> -	dput(dest);
>  
>  	return err;
>  }
> diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
> index 2da1c035f716..fffc22859211 100644
> --- a/fs/overlayfs/util.c
> +++ b/fs/overlayfs/util.c
> @@ -1548,14 +1548,3 @@ void ovl_copyattr(struct inode *inode)
>  	i_size_write(inode, i_size_read(realinode));
>  	spin_unlock(&inode->i_lock);
>  }
> -
> -int ovl_parent_lock(struct dentry *parent, struct dentry *child)
> -{
> -	inode_lock_nested(parent->d_inode, I_MUTEX_PARENT);
> -	if (!child ||
> -	    (!d_unhashed(child) && child->d_parent == parent))
> -		return 0;
> -
> -	inode_unlock(parent->d_inode);
> -	return -EINVAL;
> -}
> diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
> index 7c4ddc43ab39..f54b5b0aaba2 100644
> --- a/fs/smb/server/vfs.c
> +++ b/fs/smb/server/vfs.c
> @@ -663,7 +663,6 @@ int ksmbd_vfs_link(struct ksmbd_work *work, const char *oldname,
>  int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path,
>  		     char *newname, int flags)
>  {
> -	struct dentry *old_parent, *new_dentry, *trap;
>  	struct dentry *old_child = old_path->dentry;
>  	struct path new_path;
>  	struct qstr new_last;
> @@ -673,7 +672,6 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path,
>  	struct ksmbd_file *parent_fp;
>  	int new_type;
>  	int err, lookup_flags = LOOKUP_NO_SYMLINKS;
> -	int target_lookup_flags = LOOKUP_RENAME_TARGET | LOOKUP_CREATE;
>  
>  	if (ksmbd_override_fsids(work))
>  		return -ENOMEM;
> @@ -684,14 +682,6 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path,
>  		goto revert_fsids;
>  	}
>  
> -	/*
> -	 * explicitly handle file overwrite case, for compatibility with
> -	 * filesystems that may not support rename flags (e.g: fuse)
> -	 */
> -	if (flags & RENAME_NOREPLACE)
> -		target_lookup_flags |= LOOKUP_EXCL;
> -	flags &= ~(RENAME_NOREPLACE);
> -
>  retry:
>  	err = vfs_path_parent_lookup(to, lookup_flags | LOOKUP_BENEATH,
>  				     &new_path, &new_last, &new_type,
> @@ -708,17 +698,14 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path,
>  	if (err)
>  		goto out2;
>  
> -	trap = lock_rename_child(old_child, new_path.dentry);
> -	if (IS_ERR(trap)) {
> -		err = PTR_ERR(trap);
> +	rd.mnt_idmap		= mnt_idmap(old_path->mnt);
> +	rd.old_parent		= NULL;
> +	rd.new_parent		= new_path.dentry;
> +	rd.flags		= flags;
> +	rd.delegated_inode	= NULL,
> +	err = start_renaming_dentry(&rd, lookup_flags, old_child, &new_last);
> +	if (err)
>  		goto out_drop_write;
> -	}
> -
> -	old_parent = dget(old_child->d_parent);
> -	if (d_unhashed(old_child)) {
> -		err = -EINVAL;
> -		goto out3;
> -	}
>  
>  	parent_fp = ksmbd_lookup_fd_inode(old_child->d_parent);
>  	if (parent_fp) {
> @@ -731,44 +718,17 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path,
>  		ksmbd_fd_put(work, parent_fp);
>  	}
>  
> -	new_dentry = lookup_one_qstr_excl(&new_last, new_path.dentry,
> -					  lookup_flags | target_lookup_flags);
> -	if (IS_ERR(new_dentry)) {
> -		err = PTR_ERR(new_dentry);
> -		goto out3;
> -	}
> -
> -	if (d_is_symlink(new_dentry)) {
> +	if (d_is_symlink(rd.new_dentry)) {
>  		err = -EACCES;
> -		goto out4;
> -	}
> -
> -	if (old_child == trap) {
> -		err = -EINVAL;
> -		goto out4;
> -	}
> -
> -	if (new_dentry == trap) {
> -		err = -ENOTEMPTY;
> -		goto out4;
> +		goto out3;
>  	}
>  
> -	rd.mnt_idmap		= mnt_idmap(old_path->mnt),
> -	rd.old_parent		= old_parent,
> -	rd.old_dentry		= old_child,
> -	rd.new_parent		= new_path.dentry,
> -	rd.new_dentry		= new_dentry,
> -	rd.flags		= flags,
> -	rd.delegated_inode	= NULL,
>  	err = vfs_rename(&rd);
>  	if (err)
>  		ksmbd_debug(VFS, "vfs_rename failed err %d\n", err);
>  
> -out4:
> -	dput(new_dentry);
>  out3:
> -	dput(old_parent);
> -	unlock_rename(old_parent, new_path.dentry);
> +	end_renaming(&rd);
>  out_drop_write:
>  	mnt_drop_write(old_path->mnt);
>  out2:
> diff --git a/include/linux/namei.h b/include/linux/namei.h
> index 7fdd9fdcbd2b..c47713e9867c 100644
> --- a/include/linux/namei.h
> +++ b/include/linux/namei.h
> @@ -159,6 +159,8 @@ extern struct dentry *lock_rename_child(struct dentry *, struct dentry *);
>  extern void unlock_rename(struct dentry *, struct dentry *);
>  int start_renaming(struct renamedata *rd, int lookup_flags,
>  		   struct qstr *old_last, struct qstr *new_last);
> +int start_renaming_dentry(struct renamedata *rd, int lookup_flags,
> +			  struct dentry *old_dentry, struct qstr *new_last);
>  void end_renaming(struct renamedata *rd);
>  
>  /**

Reviewed-by: Jeff Layton <[email protected]>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.