linux-unionfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Christian Brauner <brauner@kernel.org>
To: Miklos Szeredi <miklos@szeredi.hu>, Amir Goldstein <amir73il@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>,
	 linux-unionfs@vger.kernel.org, linux-fsdevel@vger.kernel.org,
	 Christian Brauner <brauner@kernel.org>
Subject: [PATCH v2 33/42] ovl: refactor ovl_rename()
Date: Thu, 13 Nov 2025 17:37:38 +0100	[thread overview]
Message-ID: <20251113-work-ovl-cred-guard-v2-33-c08940095e90@kernel.org> (raw)
In-Reply-To: <20251113-work-ovl-cred-guard-v2-0-c08940095e90@kernel.org>

Make use of fms extensions and add a struct ovl_renamedata which embedds
the vfs struct and adds overlayfs specific data.

Signed-off-by: Christian Brauner <brauner@kernel.org>
---
 fs/overlayfs/dir.c | 272 ++++++++++++++++++++++++++++-------------------------
 1 file changed, 144 insertions(+), 128 deletions(-)

diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index 86b72bf87833..cd2b397d23a0 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -1090,103 +1090,37 @@ static int ovl_set_redirect(struct dentry *dentry, bool samedir)
 	return err;
 }
 
-static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
-		      struct dentry *old, struct inode *newdir,
-		      struct dentry *new, unsigned int flags)
+struct ovl_renamedata {
+	struct renamedata;
+	struct dentry *opaquedir;
+	struct dentry *olddentry;
+	struct dentry *newdentry;
+	bool cleanup_whiteout;
+};
+
+static int do_ovl_rename(struct ovl_renamedata *ovlrd, struct list_head *list)
 {
-	int err;
-	struct dentry *old_upperdir;
-	struct dentry *new_upperdir;
-	struct dentry *olddentry = NULL;
-	struct dentry *newdentry = NULL;
-	struct dentry *trap, *de;
-	bool old_opaque;
-	bool new_opaque;
-	bool cleanup_whiteout = false;
-	bool update_nlink = false;
+	struct dentry *old = ovlrd->old_dentry;
+	struct dentry *new = ovlrd->new_dentry;
+	struct ovl_fs *ofs = OVL_FS(old->d_sb);
+	unsigned int flags = ovlrd->flags;
+	struct dentry *old_upperdir = ovl_dentry_upper(ovlrd->old_parent);
+	struct dentry *new_upperdir = ovl_dentry_upper(ovlrd->new_parent);
+	bool samedir = ovlrd->old_parent == ovlrd->new_parent;
 	bool overwrite = !(flags & RENAME_EXCHANGE);
 	bool is_dir = d_is_dir(old);
 	bool new_is_dir = d_is_dir(new);
-	bool samedir = olddir == newdir;
-	struct dentry *opaquedir = NULL;
-	const struct cred *old_cred = NULL;
-	struct ovl_fs *ofs = OVL_FS(old->d_sb);
-	LIST_HEAD(list);
-
-	err = -EINVAL;
-	if (flags & ~(RENAME_EXCHANGE | RENAME_NOREPLACE))
-		goto out;
-
-	flags &= ~RENAME_NOREPLACE;
-
-	/* Don't copy up directory trees */
-	err = -EXDEV;
-	if (!ovl_can_move(old))
-		goto out;
-	if (!overwrite && !ovl_can_move(new))
-		goto out;
-
-	if (overwrite && new_is_dir && !ovl_pure_upper(new)) {
-		err = ovl_check_empty_dir(new, &list);
-		if (err)
-			goto out;
-	}
-
-	if (overwrite) {
-		if (ovl_lower_positive(old)) {
-			if (!ovl_dentry_is_whiteout(new)) {
-				/* Whiteout source */
-				flags |= RENAME_WHITEOUT;
-			} else {
-				/* Switch whiteouts */
-				flags |= RENAME_EXCHANGE;
-			}
-		} else if (is_dir && ovl_dentry_is_whiteout(new)) {
-			flags |= RENAME_EXCHANGE;
-			cleanup_whiteout = true;
-		}
-	}
-
-	err = ovl_copy_up(old);
-	if (err)
-		goto out;
-
-	err = ovl_copy_up(new->d_parent);
-	if (err)
-		goto out;
-	if (!overwrite) {
-		err = ovl_copy_up(new);
-		if (err)
-			goto out;
-	} else if (d_inode(new)) {
-		err = ovl_nlink_start(new);
-		if (err)
-			goto out;
-
-		update_nlink = true;
-	}
-
-	if (!update_nlink) {
-		/* ovl_nlink_start() took ovl_want_write() */
-		err = ovl_want_write(old);
-		if (err)
-			goto out;
-	}
-
-	old_cred = ovl_override_creds(old->d_sb);
+	struct dentry *trap, *de;
+	bool old_opaque, new_opaque;
+	int err;
 
-	if (!list_empty(&list)) {
-		opaquedir = ovl_clear_empty(new, &list);
-		err = PTR_ERR(opaquedir);
-		if (IS_ERR(opaquedir)) {
-			opaquedir = NULL;
-			goto out_revert_creds;
-		}
+	if (!list_empty(list)) {
+		de = ovl_clear_empty(new, list);
+		if (IS_ERR(de))
+			return PTR_ERR(de);
+		ovlrd->opaquedir = de;
 	}
 
-	old_upperdir = ovl_dentry_upper(old->d_parent);
-	new_upperdir = ovl_dentry_upper(new->d_parent);
-
 	if (!samedir) {
 		/*
 		 * When moving a merge dir or non-dir with copy up origin into
@@ -1195,32 +1129,30 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
 		 * lookup the origin inodes of the entries to fill d_ino.
 		 */
 		if (ovl_type_origin(old)) {
-			err = ovl_set_impure(new->d_parent, new_upperdir);
+			err = ovl_set_impure(ovlrd->new_parent, new_upperdir);
 			if (err)
-				goto out_revert_creds;
+				return err;
 		}
 		if (!overwrite && ovl_type_origin(new)) {
-			err = ovl_set_impure(old->d_parent, old_upperdir);
+			err = ovl_set_impure(ovlrd->old_parent, old_upperdir);
 			if (err)
-				goto out_revert_creds;
+				return err;
 		}
 	}
 
 	trap = lock_rename(new_upperdir, old_upperdir);
-	if (IS_ERR(trap)) {
-		err = PTR_ERR(trap);
-		goto out_revert_creds;
-	}
+	if (IS_ERR(trap))
+		return PTR_ERR(trap);
 
 	de = ovl_lookup_upper(ofs, old->d_name.name, old_upperdir,
 			      old->d_name.len);
 	err = PTR_ERR(de);
 	if (IS_ERR(de))
 		goto out_unlock;
-	olddentry = de;
+	ovlrd->olddentry = de;
 
 	err = -ESTALE;
-	if (!ovl_matches_upper(old, olddentry))
+	if (!ovl_matches_upper(old, ovlrd->olddentry))
 		goto out_unlock;
 
 	de = ovl_lookup_upper(ofs, new->d_name.name, new_upperdir,
@@ -1228,23 +1160,23 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
 	err = PTR_ERR(de);
 	if (IS_ERR(de))
 		goto out_unlock;
-	newdentry = de;
+	ovlrd->newdentry = de;
 
 	old_opaque = ovl_dentry_is_opaque(old);
 	new_opaque = ovl_dentry_is_opaque(new);
 
 	err = -ESTALE;
 	if (d_inode(new) && ovl_dentry_upper(new)) {
-		if (opaquedir) {
-			if (newdentry != opaquedir)
+		if (ovlrd->opaquedir) {
+			if (ovlrd->newdentry != ovlrd->opaquedir)
 				goto out_unlock;
 		} else {
-			if (!ovl_matches_upper(new, newdentry))
+			if (!ovl_matches_upper(new, ovlrd->newdentry))
 				goto out_unlock;
 		}
 	} else {
-		if (!d_is_negative(newdentry)) {
-			if (!new_opaque || !ovl_upper_is_whiteout(ofs, newdentry))
+		if (!d_is_negative(ovlrd->newdentry)) {
+			if (!new_opaque || !ovl_upper_is_whiteout(ofs, ovlrd->newdentry))
 				goto out_unlock;
 		} else {
 			if (flags & RENAME_EXCHANGE)
@@ -1252,38 +1184,39 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
 		}
 	}
 
-	if (olddentry == trap)
+	if (ovlrd->olddentry == trap)
 		goto out_unlock;
-	if (newdentry == trap)
+	if (ovlrd->newdentry == trap)
 		goto out_unlock;
 
-	if (olddentry->d_inode == newdentry->d_inode)
+	if (ovlrd->olddentry->d_inode == ovlrd->newdentry->d_inode)
 		goto out_unlock;
 
 	err = 0;
 	if (ovl_type_merge_or_lower(old))
 		err = ovl_set_redirect(old, samedir);
-	else if (is_dir && !old_opaque && ovl_type_merge(new->d_parent))
-		err = ovl_set_opaque_xerr(old, olddentry, -EXDEV);
+	else if (is_dir && !old_opaque && ovl_type_merge(ovlrd->new_parent))
+		err = ovl_set_opaque_xerr(old, ovlrd->olddentry, -EXDEV);
 	if (err)
 		goto out_unlock;
 
 	if (!overwrite && ovl_type_merge_or_lower(new))
 		err = ovl_set_redirect(new, samedir);
 	else if (!overwrite && new_is_dir && !new_opaque &&
-		 ovl_type_merge(old->d_parent))
-		err = ovl_set_opaque_xerr(new, newdentry, -EXDEV);
+		 ovl_type_merge(ovlrd->old_parent))
+		err = ovl_set_opaque_xerr(new, ovlrd->newdentry, -EXDEV);
 	if (err)
 		goto out_unlock;
 
-	err = ovl_do_rename(ofs, old_upperdir, olddentry,
-			    new_upperdir, newdentry, flags);
+	err = ovl_do_rename(ofs, old_upperdir, ovlrd->olddentry,
+			    new_upperdir, ovlrd->newdentry, flags);
+out_unlock:
 	unlock_rename(new_upperdir, old_upperdir);
 	if (err)
-		goto out_revert_creds;
+		return err;
 
-	if (cleanup_whiteout)
-		ovl_cleanup(ofs, old_upperdir, newdentry);
+	if (ovlrd->cleanup_whiteout)
+		ovl_cleanup(ofs, old_upperdir, ovlrd->newdentry);
 
 	if (overwrite && d_inode(new)) {
 		if (new_is_dir)
@@ -1292,9 +1225,9 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
 			ovl_drop_nlink(new);
 	}
 
-	ovl_dir_modified(old->d_parent, ovl_type_origin(old) ||
+	ovl_dir_modified(ovlrd->old_parent, ovl_type_origin(old) ||
 			 (!overwrite && ovl_type_origin(new)));
-	ovl_dir_modified(new->d_parent, ovl_type_origin(old) ||
+	ovl_dir_modified(ovlrd->new_parent, ovl_type_origin(old) ||
 			 (d_inode(new) && ovl_type_origin(new)));
 
 	/* copy ctime: */
@@ -1302,22 +1235,105 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
 	if (d_inode(new) && ovl_dentry_upper(new))
 		ovl_copyattr(d_inode(new));
 
-out_revert_creds:
+	return err;
+}
+
+static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
+		      struct dentry *old, struct inode *newdir,
+		      struct dentry *new, unsigned int flags)
+{
+	int err;
+	bool update_nlink = false;
+	bool overwrite = !(flags & RENAME_EXCHANGE);
+	bool is_dir = d_is_dir(old);
+	bool new_is_dir = d_is_dir(new);
+	const struct cred *old_cred = NULL;
+	struct ovl_renamedata ovlrd = {
+		.old_parent		= old->d_parent,
+		.old_dentry		= old,
+		.new_parent		= new->d_parent,
+		.new_dentry		= new,
+		.flags			= flags,
+		.cleanup_whiteout	= false,
+	};
+	LIST_HEAD(list);
+
+	err = -EINVAL;
+	if (flags & ~(RENAME_EXCHANGE | RENAME_NOREPLACE))
+		goto out;
+
+	flags &= ~RENAME_NOREPLACE;
+
+	/* Don't copy up directory trees */
+	err = -EXDEV;
+	if (!ovl_can_move(old))
+		goto out;
+	if (!overwrite && !ovl_can_move(new))
+		goto out;
+
+	if (overwrite && new_is_dir && !ovl_pure_upper(new)) {
+		err = ovl_check_empty_dir(new, &list);
+		if (err)
+			goto out;
+	}
+
+	if (overwrite) {
+		if (ovl_lower_positive(old)) {
+			if (!ovl_dentry_is_whiteout(new)) {
+				/* Whiteout source */
+				ovlrd.flags |= RENAME_WHITEOUT;
+			} else {
+				/* Switch whiteouts */
+				ovlrd.flags |= RENAME_EXCHANGE;
+			}
+		} else if (is_dir && ovl_dentry_is_whiteout(new)) {
+			ovlrd.flags |= RENAME_EXCHANGE;
+			ovlrd.cleanup_whiteout = true;
+		}
+	}
+
+	err = ovl_copy_up(old);
+	if (err)
+		goto out;
+
+	err = ovl_copy_up(new->d_parent);
+	if (err)
+		goto out;
+	if (!overwrite) {
+		err = ovl_copy_up(new);
+		if (err)
+			goto out;
+	} else if (d_inode(new)) {
+		err = ovl_nlink_start(new);
+		if (err)
+			goto out;
+
+		update_nlink = true;
+	}
+
+	if (!update_nlink) {
+		/* ovl_nlink_start() took ovl_want_write() */
+		err = ovl_want_write(old);
+		if (err)
+			goto out;
+	}
+
+	old_cred = ovl_override_creds(old->d_sb);
+
+	err = do_ovl_rename(&ovlrd, &list);
+
 	ovl_revert_creds(old_cred);
 	if (update_nlink)
 		ovl_nlink_end(new);
 	else
 		ovl_drop_write(old);
+
+	dput(ovlrd.newdentry);
+	dput(ovlrd.olddentry);
+	dput(ovlrd.opaquedir);
 out:
-	dput(newdentry);
-	dput(olddentry);
-	dput(opaquedir);
 	ovl_cache_free(&list);
 	return err;
-
-out_unlock:
-	unlock_rename(new_upperdir, old_upperdir);
-	goto out_revert_creds;
 }
 
 static int ovl_create_tmpfile(struct file *file, struct dentry *dentry,

-- 
2.47.3


  parent reply	other threads:[~2025-11-13 16:38 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-11-13 16:37 [PATCH v2 00/42] ovl: convert to cred guard Christian Brauner
2025-11-13 16:37 ` [PATCH v2 01/42] ovl: add override_creds cleanup guard extension for overlayfs Christian Brauner
2025-11-13 16:37 ` [PATCH v2 02/42] ovl: port ovl_copy_up_flags() to cred guards Christian Brauner
2025-11-13 16:37 ` [PATCH v2 03/42] ovl: port ovl_create_or_link() to cred guard Christian Brauner
2025-11-13 16:37 ` [PATCH v2 04/42] ovl: port ovl_set_link_redirect() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 05/42] ovl: port ovl_do_remove() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 06/42] ovl: port ovl_create_tmpfile() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 07/42] ovl: port ovl_open_realfile() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 08/42] ovl: port ovl_llseek() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 09/42] ovl: port ovl_fsync() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 10/42] ovl: port ovl_fallocate() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 11/42] ovl: port ovl_fadvise() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 12/42] ovl: port ovl_flush() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 13/42] ovl: port ovl_setattr() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 14/42] ovl: port ovl_getattr() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 15/42] ovl: port ovl_permission() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 16/42] ovl: port ovl_get_link() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 17/42] ovl: port do_ovl_get_acl() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 18/42] ovl: port ovl_set_or_remove_acl() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 19/42] ovl: port ovl_fiemap() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 20/42] ovl: port ovl_fileattr_set() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 21/42] ovl: port ovl_fileattr_get() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 22/42] ovl: port ovl_maybe_validate_verity() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 23/42] ovl: port ovl_maybe_lookup_lowerdata() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 24/42] ovl: don't override credentials for ovl_check_whiteouts() Christian Brauner
2025-11-13 16:37 ` [PATCH v2 25/42] ovl: refactor ovl_iterate() and port to cred guard Christian Brauner
2025-11-13 16:37 ` [PATCH v2 26/42] ovl: port ovl_dir_llseek() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 27/42] ovl: port ovl_check_empty_dir() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 28/42] ovl: port ovl_nlink_start() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 29/42] ovl: port ovl_nlink_end() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 30/42] ovl: port ovl_xattr_set() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 31/42] ovl: port ovl_xattr_get() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 32/42] ovl: port ovl_listxattr() " Christian Brauner
2025-11-13 16:37 ` Christian Brauner [this message]
2025-11-13 16:37 ` [PATCH v2 34/42] ovl: port ovl_rename() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 35/42] ovl: port ovl_copyfile() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 36/42] ovl: refactor ovl_lookup() Christian Brauner
2025-11-13 16:37 ` [PATCH v2 37/42] ovl: port ovl_lookup() to cred guard Christian Brauner
2025-11-13 16:37 ` [PATCH v2 38/42] ovl: port ovl_lower_positive() " Christian Brauner
2025-11-13 16:37 ` [PATCH v2 39/42] ovl: refactor ovl_fill_super() Christian Brauner
2025-11-13 16:37 ` [PATCH v2 40/42] ovl: port ovl_fill_super() to cred guard Christian Brauner
2025-11-13 16:37 ` [PATCH v2 41/42] ovl: remove ovl_revert_creds() Christian Brauner
2025-11-13 16:37 ` [PATCH v2 42/42] ovl: detect double credential overrides Christian Brauner
2025-11-13 18:42   ` Amir Goldstein
2025-11-13 21:31     ` Christian Brauner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20251113-work-ovl-cred-guard-v2-33-c08940095e90@kernel.org \
    --to=brauner@kernel.org \
    --cc=amir73il@gmail.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-unionfs@vger.kernel.org \
    --cc=miklos@szeredi.hu \
    --cc=torvalds@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).