linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: NeilBrown <neil@brown.name>
To: Miklos Szeredi <miklos@szeredi.hu>, Amir Goldstein <amir73il@gmail.com>
Cc: linux-unionfs@vger.kernel.org, linux-fsdevel@vger.kernel.org
Subject: [PATCH v3 01/21] ovl: simplify an error path in ovl_copy_up_workdir()
Date: Wed, 16 Jul 2025 10:44:12 +1000	[thread overview]
Message-ID: <20250716004725.1206467-2-neil@brown.name> (raw)
In-Reply-To: <20250716004725.1206467-1-neil@brown.name>

If ovl_copy_up_data() fails the error is not immediately handled but the
code continues on to call ovl_start_write() and lock_rename(),
presumably because both of these locks are needed for the cleanup.
Only then (if the lock was successful) is the error checked.

This makes the code a little hard to follow and could be fragile.

This patch changes to handle the error after the ovl_start_write()
(which cannot fail, so there aren't multiple errors to deail with).  A
new ovl_cleanup_unlocked() is created which takes the required directory
lock.  This will be used extensively in later patches.

In general we need to check the parent is still correct after taking the
lock (as ovl_copy_up_workdir() does after a successful lock_rename()) so
that is included in ovl_cleanup_unlocked() using new ovl_parent_lock()
and ovl_parent_unlock() calls (it is planned to move this API into VFS code
eventually, though in a slightly different form).

Signed-off-by: NeilBrown <neil@brown.name>
---
 fs/overlayfs/copy_up.c   | 20 +++++++++++---------
 fs/overlayfs/dir.c       | 15 +++++++++++++++
 fs/overlayfs/overlayfs.h |  6 ++++++
 fs/overlayfs/util.c      | 10 ++++++++++
 4 files changed, 42 insertions(+), 9 deletions(-)

diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index 8a3c0d18ec2e..79f41ef6ffa7 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -794,23 +794,24 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
 	 */
 	path.dentry = temp;
 	err = ovl_copy_up_data(c, &path);
+	ovl_start_write(c->dentry);
+	if (err)
+		goto cleanup_unlocked;
+
 	/*
 	 * We cannot hold lock_rename() throughout this helper, because of
 	 * lock ordering with sb_writers, which shouldn't be held when calling
 	 * ovl_copy_up_data(), so lock workdir and destdir and make sure that
 	 * temp wasn't moved before copy up completion or cleanup.
 	 */
-	ovl_start_write(c->dentry);
 	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);
 		err = -EIO;
-		if (IS_ERR(trap))
-			goto out;
-		goto unlock;
-	} else if (err) {
-		goto cleanup;
+		if (!IS_ERR(trap))
+			unlock_rename(c->workdir, c->destdir);
+		goto out;
 	}
 
 	err = ovl_copy_up_metadata(c, temp);
@@ -846,7 +847,6 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
 	ovl_inode_update(inode, temp);
 	if (S_ISDIR(inode->i_mode))
 		ovl_set_flag(OVL_WHITEOUTS, inode);
-unlock:
 	unlock_rename(c->workdir, c->destdir);
 out:
 	ovl_end_write(c->dentry);
@@ -854,9 +854,11 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
 	return err;
 
 cleanup:
-	ovl_cleanup(ofs, wdir, temp);
+	unlock_rename(c->workdir, c->destdir);
+cleanup_unlocked:
+	ovl_cleanup_unlocked(ofs, c->workdir, temp);
 	dput(temp);
-	goto unlock;
+	goto out;
 }
 
 /* Copyup using O_TMPFILE which does not require cross dir locking */
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index 4fc221ea6480..67cad3dba8ad 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -43,6 +43,21 @@ int ovl_cleanup(struct ovl_fs *ofs, struct inode *wdir, struct dentry *wdentry)
 	return err;
 }
 
+int ovl_cleanup_unlocked(struct ovl_fs *ofs, struct dentry *workdir,
+			 struct dentry *wdentry)
+{
+	int err;
+
+	err = ovl_parent_lock(workdir, wdentry);
+	if (err)
+		return err;
+
+	ovl_cleanup(ofs, workdir->d_inode, wdentry);
+	ovl_parent_unlock(workdir);
+
+	return 0;
+}
+
 struct dentry *ovl_lookup_temp(struct ovl_fs *ofs, struct dentry *workdir)
 {
 	struct dentry *temp;
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index 42228d10f6b9..6737a4692eb2 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -416,6 +416,11 @@ 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);
@@ -843,6 +848,7 @@ struct dentry *ovl_create_real(struct ovl_fs *ofs,
 			       struct inode *dir, struct dentry *newdentry,
 			       struct ovl_cattr *attr);
 int ovl_cleanup(struct ovl_fs *ofs, struct inode *dir, struct dentry *dentry);
+int ovl_cleanup_unlocked(struct ovl_fs *ofs, struct dentry *workdir, struct dentry *dentry);
 struct dentry *ovl_lookup_temp(struct ovl_fs *ofs, struct dentry *workdir);
 struct dentry *ovl_create_temp(struct ovl_fs *ofs, struct dentry *workdir,
 			       struct ovl_cattr *attr);
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
index 2b4754c645ee..f4944f11d5eb 100644
--- a/fs/overlayfs/util.c
+++ b/fs/overlayfs/util.c
@@ -1544,3 +1544,13 @@ 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 || child->d_parent == parent)
+		return 0;
+
+	inode_unlock(parent->d_inode);
+	return -EINVAL;
+}
-- 
2.49.0


  reply	other threads:[~2025-07-16  0:47 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-07-16  0:44 [PATCH v3 00/21] ovl: narrow regions protected by i_rw_sem NeilBrown
2025-07-16  0:44 ` NeilBrown [this message]
2025-07-16  7:12   ` [PATCH v3 01/21] ovl: simplify an error path in ovl_copy_up_workdir() Amir Goldstein
2025-08-04  8:57   ` Miklos Szeredi
2025-07-16  0:44 ` [PATCH v3 02/21] ovl: change ovl_create_index() to take dir locks NeilBrown
2025-07-16  0:44 ` [PATCH v3 03/21] ovl: Call ovl_create_temp() without lock held NeilBrown
2025-07-16  0:44 ` [PATCH v3 04/21] ovl: narrow the locked region in ovl_copy_up_workdir() NeilBrown
2025-07-16  7:13   ` Amir Goldstein
2025-07-16  0:44 ` [PATCH v3 05/21] ovl: narrow locking in ovl_create_upper() NeilBrown
2025-07-16  0:44 ` [PATCH v3 06/21] ovl: narrow locking in ovl_clear_empty() NeilBrown
2025-07-16  0:44 ` [PATCH v3 07/21] ovl: narrow locking in ovl_create_over_whiteout() NeilBrown
2025-07-16  0:44 ` [PATCH v3 08/21] ovl: simplify gotos in ovl_rename() NeilBrown
2025-07-16  7:13   ` Amir Goldstein
2025-07-16  0:44 ` [PATCH v3 09/21] ovl: narrow locking " NeilBrown
2025-07-16  7:13   ` Amir Goldstein
2025-07-16  0:44 ` [PATCH v3 10/21] ovl: narrow locking in ovl_cleanup_whiteouts() NeilBrown
2025-07-16  0:44 ` [PATCH v3 11/21] ovl: narrow locking in ovl_cleanup_index() NeilBrown
2025-07-16  7:14   ` Amir Goldstein
2025-07-16  0:44 ` [PATCH v3 12/21] ovl: narrow locking in ovl_workdir_create() NeilBrown
2025-07-16  7:15   ` Amir Goldstein
2025-07-16  0:44 ` [PATCH v3 13/21] ovl: narrow locking in ovl_indexdir_cleanup() NeilBrown
2025-07-16  7:15   ` Amir Goldstein
2025-07-16  0:44 ` [PATCH v3 14/21] ovl: narrow locking in ovl_workdir_cleanup_recurse() NeilBrown
2025-07-16  7:16   ` Amir Goldstein
2025-07-16  0:44 ` [PATCH v3 15/21] ovl: change ovl_workdir_cleanup() to take dir lock as needed NeilBrown
2025-07-16  7:16   ` Amir Goldstein
2025-07-16  0:44 ` [PATCH v3 16/21] ovl: narrow locking on ovl_remove_and_whiteout() NeilBrown
2025-07-16  7:16   ` Amir Goldstein
2025-07-16  0:44 ` [PATCH v3 17/21] ovl: change ovl_cleanup_and_whiteout() to take rename lock as needed NeilBrown
2025-07-16  0:44 ` [PATCH v3 18/21] ovl: narrow locking in ovl_whiteout() NeilBrown
2025-07-16  7:15   ` Amir Goldstein
2025-07-16  0:44 ` [PATCH v3 19/21] ovl: narrow locking in ovl_check_rename_whiteout() NeilBrown
2025-07-16  0:44 ` [PATCH v3 20/21] ovl: change ovl_create_real() to receive dentry parent NeilBrown
2025-07-16  0:44 ` [PATCH v3 21/21] ovl: rename ovl_cleanup_unlocked() to ovl_cleanup() NeilBrown
2025-07-16  7:14   ` Amir Goldstein
2025-07-16  7:10 ` [PATCH v3 00/21] ovl: narrow regions protected by i_rw_sem Amir Goldstein
2025-07-16  7:19   ` NeilBrown
2025-07-16  7:35     ` Amir Goldstein
2025-07-16  8:05       ` NeilBrown
2025-07-16  9:09         ` Amir Goldstein
2025-07-18  9:11 ` 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=20250716004725.1206467-2-neil@brown.name \
    --to=neil@brown.name \
    --cc=amir73il@gmail.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-unionfs@vger.kernel.org \
    --cc=miklos@szeredi.hu \
    /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).