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
next prev 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).