* [PATCH v3 0/4] overlayfs lock ordering changes
@ 2023-08-16 15:23 Amir Goldstein
2023-08-16 15:23 ` [PATCH v3 1/4] ovl: reorder ovl_want_write() after ovl_inode_lock() Amir Goldstein
` (4 more replies)
0 siblings, 5 replies; 10+ messages in thread
From: Amir Goldstein @ 2023-08-16 15:23 UTC (permalink / raw)
To: Miklos Szeredi; +Cc: linux-unionfs
Hi Miklos,
I went for the less intrusive approach of holding mnt_writers
only throughout copy up instead of a long lived elevated refcount.
We could reconsider the long lived reference in the future.
Thanks,
Amir.
Changes since v2:
- Separate mnt_writers and sb_writers locks during copy up
- Fixs error handling bugs found by Miklos
Changes since v1:
- Breakup the large ovl_want_write() transaction in copy up
- Add fix to possible deadlock with encode lower ovl fh
Amir Goldstein (4):
ovl: reorder ovl_want_write() after ovl_inode_lock()
ovl: split ovl_want_write() into two helpers
ovl: do not open/llseek lower file with upper sb_writers held
ovl: do not encode lower fh with upper sb_writers held
fs/overlayfs/copy_up.c | 141 +++++++++++++++++++++++++--------------
fs/overlayfs/dir.c | 60 ++++++++---------
fs/overlayfs/export.c | 7 +-
fs/overlayfs/inode.c | 57 ++++++++--------
fs/overlayfs/namei.c | 37 +++++++---
fs/overlayfs/overlayfs.h | 30 +++++++--
fs/overlayfs/super.c | 20 ++++--
fs/overlayfs/util.c | 73 ++++++++++++++++++--
8 files changed, 275 insertions(+), 150 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v3 1/4] ovl: reorder ovl_want_write() after ovl_inode_lock()
2023-08-16 15:23 [PATCH v3 0/4] overlayfs lock ordering changes Amir Goldstein
@ 2023-08-16 15:23 ` Amir Goldstein
2023-08-16 15:23 ` [PATCH v3 2/4] ovl: split ovl_want_write() into two helpers Amir Goldstein
` (3 subsequent siblings)
4 siblings, 0 replies; 10+ messages in thread
From: Amir Goldstein @ 2023-08-16 15:23 UTC (permalink / raw)
To: Miklos Szeredi; +Cc: linux-unionfs
Make the locking order of ovl_inode_lock() strictly between the two
vfs stacked layers, i.e.:
- ovl vfs locks: sb_writers, inode_lock, ...
- ovl_inode_lock
- upper vfs locks: sb_writers, inode_lock, ...
To that effect, move ovl_want_write() into the helpers ovl_nlink_start()
and ovl_copy_up_start which currently take the ovl_inode_lock() after
ovl_want_write().
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
fs/overlayfs/copy_up.c | 13 +++------
fs/overlayfs/dir.c | 60 ++++++++++++++++++------------------------
fs/overlayfs/export.c | 7 +----
fs/overlayfs/inode.c | 57 +++++++++++++++++++--------------------
fs/overlayfs/util.c | 34 +++++++++++++++++++-----
5 files changed, 84 insertions(+), 87 deletions(-)
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index bae404a1bad4..e9adff187284 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -1169,17 +1169,10 @@ static bool ovl_open_need_copy_up(struct dentry *dentry, int flags)
int ovl_maybe_copy_up(struct dentry *dentry, int flags)
{
- int err = 0;
-
- if (ovl_open_need_copy_up(dentry, flags)) {
- err = ovl_want_write(dentry);
- if (!err) {
- err = ovl_copy_up_flags(dentry, flags);
- ovl_drop_write(dentry);
- }
- }
+ if (!ovl_open_need_copy_up(dentry, flags))
+ return 0;
- return err;
+ return ovl_copy_up_flags(dentry, flags);
}
int ovl_copy_up_with_data(struct dentry *dentry)
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index 033fc0458a3d..768120c20f85 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -559,10 +559,6 @@ static int ovl_create_or_link(struct dentry *dentry, struct inode *inode,
struct cred *override_cred;
struct dentry *parent = dentry->d_parent;
- err = ovl_copy_up(parent);
- if (err)
- return err;
-
old_cred = ovl_override_creds(dentry->d_sb);
/*
@@ -626,6 +622,10 @@ static int ovl_create_object(struct dentry *dentry, int mode, dev_t rdev,
.link = link,
};
+ err = ovl_copy_up(dentry->d_parent);
+ if (err)
+ return err;
+
err = ovl_want_write(dentry);
if (err)
goto out;
@@ -700,28 +700,24 @@ static int ovl_link(struct dentry *old, struct inode *newdir,
int err;
struct inode *inode;
- err = ovl_want_write(old);
+ err = ovl_copy_up(old);
if (err)
goto out;
- err = ovl_copy_up(old);
+ err = ovl_copy_up(new->d_parent);
if (err)
- goto out_drop_write;
+ goto out;
- err = ovl_copy_up(new->d_parent);
+ err = ovl_nlink_start(old);
if (err)
- goto out_drop_write;
+ goto out;
if (ovl_is_metacopy_dentry(old)) {
err = ovl_set_link_redirect(old);
if (err)
- goto out_drop_write;
+ goto out_nlink_end;
}
- err = ovl_nlink_start(old);
- if (err)
- goto out_drop_write;
-
inode = d_inode(old);
ihold(inode);
@@ -731,9 +727,8 @@ static int ovl_link(struct dentry *old, struct inode *newdir,
if (err)
iput(inode);
+out_nlink_end:
ovl_nlink_end(old);
-out_drop_write:
- ovl_drop_write(old);
out:
return err;
}
@@ -891,17 +886,13 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir)
goto out;
}
- err = ovl_want_write(dentry);
- if (err)
- goto out;
-
err = ovl_copy_up(dentry->d_parent);
if (err)
- goto out_drop_write;
+ goto out;
err = ovl_nlink_start(dentry);
if (err)
- goto out_drop_write;
+ goto out;
old_cred = ovl_override_creds(dentry->d_sb);
if (!lower_positive)
@@ -926,8 +917,6 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir)
if (ovl_dentry_upper(dentry))
ovl_copyattr(d_inode(dentry));
-out_drop_write:
- ovl_drop_write(dentry);
out:
ovl_cache_free(&list);
return err;
@@ -1131,29 +1120,32 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
}
}
- err = ovl_want_write(old);
- if (err)
- goto out;
-
err = ovl_copy_up(old);
if (err)
- goto out_drop_write;
+ goto out;
err = ovl_copy_up(new->d_parent);
if (err)
- goto out_drop_write;
+ goto out;
if (!overwrite) {
err = ovl_copy_up(new);
if (err)
- goto out_drop_write;
+ goto out;
} else if (d_inode(new)) {
err = ovl_nlink_start(new);
if (err)
- goto out_drop_write;
+ 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);
if (!list_empty(&list)) {
@@ -1286,8 +1278,8 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
revert_creds(old_cred);
if (update_nlink)
ovl_nlink_end(new);
-out_drop_write:
- ovl_drop_write(old);
+ else
+ ovl_drop_write(old);
out:
dput(opaquedir);
ovl_cache_free(&list);
diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c
index c8c8588bd98c..4a79c479c971 100644
--- a/fs/overlayfs/export.c
+++ b/fs/overlayfs/export.c
@@ -23,12 +23,7 @@ static int ovl_encode_maybe_copy_up(struct dentry *dentry)
if (ovl_dentry_upper(dentry))
return 0;
- err = ovl_want_write(dentry);
- if (!err) {
- err = ovl_copy_up(dentry);
- ovl_drop_write(dentry);
- }
-
+ err = ovl_copy_up(dentry);
if (err) {
pr_warn_ratelimited("failed to copy up on encode (%pd2, err=%i)\n",
dentry, err);
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index b395cd84bfce..ed0de98602ed 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -32,10 +32,6 @@ int ovl_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
if (err)
return err;
- err = ovl_want_write(dentry);
- if (err)
- goto out;
-
if (attr->ia_valid & ATTR_SIZE) {
/* Truncate should trigger data copy up as well */
full_copy_up = true;
@@ -54,7 +50,7 @@ int ovl_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
winode = d_inode(upperdentry);
err = get_write_access(winode);
if (err)
- goto out_drop_write;
+ goto out;
}
if (attr->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
@@ -78,6 +74,10 @@ int ovl_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
*/
attr->ia_valid &= ~ATTR_OPEN;
+ err = ovl_want_write(dentry);
+ if (err)
+ goto out_put_write;
+
inode_lock(upperdentry->d_inode);
old_cred = ovl_override_creds(dentry->d_sb);
err = ovl_do_notify_change(ofs, upperdentry, attr);
@@ -85,12 +85,12 @@ int ovl_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
if (!err)
ovl_copyattr(dentry->d_inode);
inode_unlock(upperdentry->d_inode);
+ ovl_drop_write(dentry);
+out_put_write:
if (winode)
put_write_access(winode);
}
-out_drop_write:
- ovl_drop_write(dentry);
out:
return err;
}
@@ -361,27 +361,27 @@ int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
struct path realpath;
const struct cred *old_cred;
- err = ovl_want_write(dentry);
- if (err)
- goto out;
-
if (!value && !upperdentry) {
ovl_path_lower(dentry, &realpath);
old_cred = ovl_override_creds(dentry->d_sb);
err = vfs_getxattr(mnt_idmap(realpath.mnt), realdentry, name, NULL, 0);
revert_creds(old_cred);
if (err < 0)
- goto out_drop_write;
+ goto out;
}
if (!upperdentry) {
err = ovl_copy_up(dentry);
if (err)
- goto out_drop_write;
+ goto out;
realdentry = ovl_dentry_upper(dentry);
}
+ err = ovl_want_write(dentry);
+ if (err)
+ goto out;
+
old_cred = ovl_override_creds(dentry->d_sb);
if (value) {
err = ovl_do_setxattr(ofs, realdentry, name, value, size,
@@ -391,12 +391,10 @@ int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
err = ovl_do_removexattr(ofs, realdentry, name);
}
revert_creds(old_cred);
+ ovl_drop_write(dentry);
/* copy c/mtime */
ovl_copyattr(inode);
-
-out_drop_write:
- ovl_drop_write(dentry);
out:
return err;
}
@@ -611,10 +609,6 @@ static int ovl_set_or_remove_acl(struct dentry *dentry, struct inode *inode,
struct dentry *upperdentry = ovl_dentry_upper(dentry);
struct dentry *realdentry = upperdentry ?: ovl_dentry_lower(dentry);
- err = ovl_want_write(dentry);
- if (err)
- return err;
-
/*
* If ACL is to be removed from a lower file, check if it exists in
* the first place before copying it up.
@@ -630,7 +624,7 @@ static int ovl_set_or_remove_acl(struct dentry *dentry, struct inode *inode,
revert_creds(old_cred);
if (IS_ERR(real_acl)) {
err = PTR_ERR(real_acl);
- goto out_drop_write;
+ goto out;
}
posix_acl_release(real_acl);
}
@@ -638,23 +632,26 @@ static int ovl_set_or_remove_acl(struct dentry *dentry, struct inode *inode,
if (!upperdentry) {
err = ovl_copy_up(dentry);
if (err)
- goto out_drop_write;
+ goto out;
realdentry = ovl_dentry_upper(dentry);
}
+ err = ovl_want_write(dentry);
+ if (err)
+ goto out;
+
old_cred = ovl_override_creds(dentry->d_sb);
if (acl)
err = ovl_do_set_acl(ofs, realdentry, acl_name, acl);
else
err = ovl_do_remove_acl(ofs, realdentry, acl_name);
revert_creds(old_cred);
+ ovl_drop_write(dentry);
/* copy c/mtime */
ovl_copyattr(inode);
-
-out_drop_write:
- ovl_drop_write(dentry);
+out:
return err;
}
@@ -777,14 +774,14 @@ int ovl_fileattr_set(struct mnt_idmap *idmap,
unsigned int flags;
int err;
- err = ovl_want_write(dentry);
- if (err)
- goto out;
-
err = ovl_copy_up(dentry);
if (!err) {
ovl_path_real(dentry, &upperpath);
+ err = ovl_want_write(dentry);
+ if (err)
+ goto out;
+
old_cred = ovl_override_creds(inode->i_sb);
/*
* Store immutable/append-only flags in xattr and clear them
@@ -797,6 +794,7 @@ int ovl_fileattr_set(struct mnt_idmap *idmap,
if (!err)
err = ovl_real_fileattr_set(&upperpath, fa);
revert_creds(old_cred);
+ ovl_drop_write(dentry);
/*
* Merge real inode flags with inode flags read from
@@ -811,7 +809,6 @@ int ovl_fileattr_set(struct mnt_idmap *idmap,
/* Update ctime */
ovl_copyattr(inode);
}
- ovl_drop_write(dentry);
out:
return err;
}
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
index 0f387092450e..753734c55647 100644
--- a/fs/overlayfs/util.c
+++ b/fs/overlayfs/util.c
@@ -650,16 +650,26 @@ int ovl_copy_up_start(struct dentry *dentry, int flags)
int err;
err = ovl_inode_lock_interruptible(inode);
- if (!err && ovl_already_copied_up_locked(dentry, flags)) {
+ if (err)
+ return err;
+
+ if (ovl_already_copied_up_locked(dentry, flags))
err = 1; /* Already copied up */
- ovl_inode_unlock(inode);
- }
+ else
+ err = ovl_want_write(dentry);
+ if (err)
+ goto out_unlock;
+
+ return 0;
+out_unlock:
+ ovl_inode_unlock(inode);
return err;
}
void ovl_copy_up_end(struct dentry *dentry)
{
+ ovl_drop_write(dentry);
ovl_inode_unlock(d_inode(dentry));
}
@@ -1062,8 +1072,12 @@ int ovl_nlink_start(struct dentry *dentry)
if (err)
return err;
+ err = ovl_want_write(dentry);
+ if (err)
+ goto out_unlock;
+
if (d_is_dir(dentry) || !ovl_test_flag(OVL_INDEX, inode))
- goto out;
+ return 0;
old_cred = ovl_override_creds(dentry->d_sb);
/*
@@ -1074,10 +1088,15 @@ int ovl_nlink_start(struct dentry *dentry)
*/
err = ovl_set_nlink_upper(dentry);
revert_creds(old_cred);
-
-out:
if (err)
- ovl_inode_unlock(inode);
+ goto out_drop_write;
+
+ return 0;
+
+out_drop_write:
+ ovl_drop_write(dentry);
+out_unlock:
+ ovl_inode_unlock(inode);
return err;
}
@@ -1094,6 +1113,7 @@ void ovl_nlink_end(struct dentry *dentry)
revert_creds(old_cred);
}
+ ovl_drop_write(dentry);
ovl_inode_unlock(inode);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 2/4] ovl: split ovl_want_write() into two helpers
2023-08-16 15:23 [PATCH v3 0/4] overlayfs lock ordering changes Amir Goldstein
2023-08-16 15:23 ` [PATCH v3 1/4] ovl: reorder ovl_want_write() after ovl_inode_lock() Amir Goldstein
@ 2023-08-16 15:23 ` Amir Goldstein
2023-08-16 15:23 ` [PATCH v3 3/4] ovl: do not open/llseek lower file with upper sb_writers held Amir Goldstein
` (2 subsequent siblings)
4 siblings, 0 replies; 10+ messages in thread
From: Amir Goldstein @ 2023-08-16 15:23 UTC (permalink / raw)
To: Miklos Szeredi; +Cc: linux-unionfs
ovl_get_mnt_write() gets write access to upper mnt without taking freeze
protection on upper sb and ovl_start_write() only takes freeze
protection on upper sb.
These helpers will be used to breakup the large ovl_want_write() scope
during copy up into finer grained freeze protection scopes.
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
fs/overlayfs/overlayfs.h | 4 ++++
fs/overlayfs/util.c | 26 ++++++++++++++++++++++++++
2 files changed, 30 insertions(+)
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index 72f57d919aa9..6da49bf78b90 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -398,7 +398,11 @@ static inline bool ovl_open_flags_need_copy_up(int flags)
}
/* util.c */
+int ovl_get_mnt_write(struct dentry *dentry);
+void ovl_start_write(struct dentry *dentry);
int ovl_want_write(struct dentry *dentry);
+void ovl_put_mnt_write(struct dentry *dentry);
+void ovl_end_write(struct dentry *dentry);
void ovl_drop_write(struct dentry *dentry);
struct dentry *ovl_workdir(struct dentry *dentry);
const struct cred *ovl_override_creds(struct super_block *sb);
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
index 753734c55647..980e128ba0a4 100644
--- a/fs/overlayfs/util.c
+++ b/fs/overlayfs/util.c
@@ -17,12 +17,38 @@
#include <linux/ratelimit.h>
#include "overlayfs.h"
+/* Get write access to upper mnt - may fail if upper sb was remounted ro */
+int ovl_get_mnt_write(struct dentry *dentry)
+{
+ struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
+ return __mnt_want_write(ovl_upper_mnt(ofs));
+}
+
+/* Get write access to upper sb - may block if upper sb is frozen */
+void ovl_start_write(struct dentry *dentry)
+{
+ struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
+ sb_start_write(ovl_upper_mnt(ofs)->mnt_sb);
+}
+
int ovl_want_write(struct dentry *dentry)
{
struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
return mnt_want_write(ovl_upper_mnt(ofs));
}
+void ovl_put_mnt_write(struct dentry *dentry)
+{
+ struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
+ __mnt_drop_write(ovl_upper_mnt(ofs));
+}
+
+void ovl_end_write(struct dentry *dentry)
+{
+ struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
+ sb_end_write(ovl_upper_mnt(ofs)->mnt_sb);
+}
+
void ovl_drop_write(struct dentry *dentry)
{
struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 3/4] ovl: do not open/llseek lower file with upper sb_writers held
2023-08-16 15:23 [PATCH v3 0/4] overlayfs lock ordering changes Amir Goldstein
2023-08-16 15:23 ` [PATCH v3 1/4] ovl: reorder ovl_want_write() after ovl_inode_lock() Amir Goldstein
2023-08-16 15:23 ` [PATCH v3 2/4] ovl: split ovl_want_write() into two helpers Amir Goldstein
@ 2023-08-16 15:23 ` Amir Goldstein
2023-08-16 15:23 ` [PATCH v3 4/4] ovl: do not encode lower fh " Amir Goldstein
2023-08-17 5:44 ` [PATCH v3 0/4] fs: export __mnt_{want,drop}_write to modules Amir Goldstein
4 siblings, 0 replies; 10+ messages in thread
From: Amir Goldstein @ 2023-08-16 15:23 UTC (permalink / raw)
To: Miklos Szeredi; +Cc: linux-unionfs
overlayfs file open (ovl_maybe_lookup_lowerdata) and overlay file llseek
take the ovl_inode_lock, without holding upper sb_writers.
In case of nested lower overlay that uses same upper fs as this overlay,
lockdep will warn about (possibly false positive) circular lock
dependency when doing open/llseek of lower ovl file during copy up with
our upper sb_writers held, because the locking ordering seems reverse to
the locking order in ovl_copy_up_start():
- lower ovl_inode_lock
- upper sb_writers
Let the copy up "transaction" keeps an elevated mnt write count on upper
mnt, but leaves taking upper sb_writers to lower level helpers only when
they actually need it. This allows to avoid holding upper sb_writers
during lower file open/llseek and prevents the lockdep warning.
Minimizing the scope of upper sb_writers during copy up is also needed
for fixing another possible deadlocks by a following patch.
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
fs/overlayfs/copy_up.c | 76 ++++++++++++++++++++++++++++++------------
fs/overlayfs/util.c | 8 +++--
2 files changed, 61 insertions(+), 23 deletions(-)
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index e9adff187284..add5861cf06b 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -252,7 +252,9 @@ static int ovl_copy_up_file(struct ovl_fs *ofs, struct dentry *dentry,
return PTR_ERR(old_file);
/* Try to use clone_file_range to clone up within the same fs */
+ ovl_start_write(dentry);
cloned = do_clone_file_range(old_file, 0, new_file, 0, len, 0);
+ ovl_end_write(dentry);
if (cloned == len)
goto out_fput;
/* Couldn't clone, so now we try to copy the data */
@@ -287,8 +289,12 @@ static int ovl_copy_up_file(struct ovl_fs *ofs, struct dentry *dentry,
* it may not recognize all kind of holes and sometimes
* only skips partial of hole area. However, it will be
* enough for most of the use cases.
+ *
+ * We do not hold upper sb_writers throughout the loop to avert
+ * lockdep warning with llseek of lower file in nested overlay:
+ * - upper sb_writers
+ * -- lower ovl_inode_lock (ovl_llseek)
*/
-
if (skip_hole && data_pos < old_pos) {
data_pos = vfs_llseek(old_file, old_pos, SEEK_DATA);
if (data_pos > old_pos) {
@@ -303,9 +309,11 @@ static int ovl_copy_up_file(struct ovl_fs *ofs, struct dentry *dentry,
}
}
+ ovl_start_write(dentry);
bytes = do_splice_direct(old_file, &old_pos,
new_file, &new_pos,
this_len, SPLICE_F_MOVE);
+ ovl_end_write(dentry);
if (bytes <= 0) {
error = bytes;
break;
@@ -555,14 +563,16 @@ static int ovl_link_up(struct ovl_copy_up_ctx *c)
struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
struct inode *udir = d_inode(upperdir);
+ ovl_start_write(c->dentry);
+
/* Mark parent "impure" because it may now contain non-pure upper */
err = ovl_set_impure(c->parent, upperdir);
if (err)
- return err;
+ goto out;
err = ovl_set_nlink_lower(c->dentry);
if (err)
- return err;
+ goto out;
inode_lock_nested(udir, I_MUTEX_PARENT);
upper = ovl_lookup_upper(ofs, c->dentry->d_name.name, upperdir,
@@ -581,10 +591,12 @@ static int ovl_link_up(struct ovl_copy_up_ctx *c)
}
inode_unlock(udir);
if (err)
- return err;
+ goto out;
err = ovl_set_nlink_upper(c->dentry);
+out:
+ ovl_end_write(c->dentry);
return err;
}
@@ -718,21 +730,19 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
.link = c->link
};
- /* workdir and destdir could be the same when copying up to indexdir */
- err = -EIO;
- if (lock_rename(c->workdir, c->destdir) != NULL)
- goto unlock;
-
err = ovl_prep_cu_creds(c->dentry, &cc);
if (err)
- goto unlock;
+ return err;
+ ovl_start_write(c->dentry);
+ inode_lock(wdir);
temp = ovl_create_temp(ofs, c->workdir, &cattr);
+ inode_unlock(wdir);
+ ovl_end_write(c->dentry);
ovl_revert_cu_creds(&cc);
- err = PTR_ERR(temp);
if (IS_ERR(temp))
- goto unlock;
+ return PTR_ERR(temp);
/*
* Copy up data first and then xattrs. Writing data after
@@ -740,8 +750,21 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
*/
path.dentry = temp;
err = ovl_copy_up_data(c, &path);
- if (err)
+ /*
+ * We cannot hold lock_rename() throughout this helper, because or
+ * 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.
+ * If temp was moved, abort without the cleanup.
+ */
+ ovl_start_write(c->dentry);
+ if (lock_rename(c->workdir, c->destdir) != NULL ||
+ temp->d_parent != c->workdir) {
+ err = -EIO;
+ goto unlock;
+ } else if (err) {
goto cleanup;
+ }
err = ovl_copy_up_metadata(c, temp);
if (err)
@@ -778,6 +801,7 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
ovl_set_flag(OVL_WHITEOUTS, inode);
unlock:
unlock_rename(c->workdir, c->destdir);
+ ovl_end_write(c->dentry);
return err;
@@ -801,9 +825,10 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
if (err)
return err;
+ ovl_start_write(c->dentry);
tmpfile = ovl_do_tmpfile(ofs, c->workdir, c->stat.mode);
+ ovl_end_write(c->dentry);
ovl_revert_cu_creds(&cc);
-
if (IS_ERR(tmpfile))
return PTR_ERR(tmpfile);
@@ -814,9 +839,11 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
goto out_fput;
}
+ ovl_start_write(c->dentry);
+
err = ovl_copy_up_metadata(c, temp);
if (err)
- goto out_fput;
+ goto out;
inode_lock_nested(udir, I_MUTEX_PARENT);
@@ -830,7 +857,7 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
inode_unlock(udir);
if (err)
- goto out_fput;
+ goto out;
if (c->metacopy_digest)
ovl_set_flag(OVL_HAS_DIGEST, d_inode(c->dentry));
@@ -842,6 +869,8 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
ovl_set_upperdata(d_inode(c->dentry));
ovl_inode_update(d_inode(c->dentry), dget(temp));
+out:
+ ovl_end_write(c->dentry);
out_fput:
fput(tmpfile);
return err;
@@ -892,7 +921,9 @@ static int ovl_do_copy_up(struct ovl_copy_up_ctx *c)
* Mark parent "impure" because it may now contain non-pure
* upper
*/
+ ovl_start_write(c->dentry);
err = ovl_set_impure(c->parent, c->destdir);
+ ovl_end_write(c->dentry);
if (err)
return err;
}
@@ -908,6 +939,7 @@ static int ovl_do_copy_up(struct ovl_copy_up_ctx *c)
if (c->indexed)
ovl_set_flag(OVL_INDEX, d_inode(c->dentry));
+ ovl_start_write(c->dentry);
if (to_index) {
/* Initialize nlink for copy up of disconnected dentry */
err = ovl_set_nlink_upper(c->dentry);
@@ -922,6 +954,7 @@ static int ovl_do_copy_up(struct ovl_copy_up_ctx *c)
ovl_dentry_set_upper_alias(c->dentry);
ovl_dentry_update_reval(c->dentry, ovl_dentry_upper(c->dentry));
}
+ ovl_end_write(c->dentry);
out:
if (to_index)
@@ -1010,15 +1043,16 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c)
* Writing to upper file will clear security.capability xattr. We
* don't want that to happen for normal copy-up operation.
*/
+ ovl_start_write(c->dentry);
if (capability) {
err = ovl_do_setxattr(ofs, upperpath.dentry, XATTR_NAME_CAPS,
capability, cap_size, 0);
- if (err)
- goto out_free;
}
-
-
- err = ovl_removexattr(ofs, upperpath.dentry, OVL_XATTR_METACOPY);
+ if (!err) {
+ err = ovl_removexattr(ofs, upperpath.dentry,
+ OVL_XATTR_METACOPY);
+ }
+ ovl_end_write(c->dentry);
if (err)
goto out_free;
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
index 980e128ba0a4..4e67ef0cc8da 100644
--- a/fs/overlayfs/util.c
+++ b/fs/overlayfs/util.c
@@ -670,6 +670,10 @@ bool ovl_already_copied_up(struct dentry *dentry, int flags)
return false;
}
+/*
+ * The copy up "transaction" keeps an elevated mnt write count on upper mnt,
+ * but leaves taking freeze protection on upper sb to lower level helpers.
+ */
int ovl_copy_up_start(struct dentry *dentry, int flags)
{
struct inode *inode = d_inode(dentry);
@@ -682,7 +686,7 @@ int ovl_copy_up_start(struct dentry *dentry, int flags)
if (ovl_already_copied_up_locked(dentry, flags))
err = 1; /* Already copied up */
else
- err = ovl_want_write(dentry);
+ err = ovl_get_mnt_write(dentry);
if (err)
goto out_unlock;
@@ -695,7 +699,7 @@ int ovl_copy_up_start(struct dentry *dentry, int flags)
void ovl_copy_up_end(struct dentry *dentry)
{
- ovl_drop_write(dentry);
+ ovl_put_mnt_write(dentry);
ovl_inode_unlock(d_inode(dentry));
}
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 4/4] ovl: do not encode lower fh with upper sb_writers held
2023-08-16 15:23 [PATCH v3 0/4] overlayfs lock ordering changes Amir Goldstein
` (2 preceding siblings ...)
2023-08-16 15:23 ` [PATCH v3 3/4] ovl: do not open/llseek lower file with upper sb_writers held Amir Goldstein
@ 2023-08-16 15:23 ` Amir Goldstein
2023-08-17 5:44 ` [PATCH v3 0/4] fs: export __mnt_{want,drop}_write to modules Amir Goldstein
4 siblings, 0 replies; 10+ messages in thread
From: Amir Goldstein @ 2023-08-16 15:23 UTC (permalink / raw)
To: Miklos Szeredi; +Cc: linux-unionfs
When lower fs is a nested overlayfs, calling encode_fh() on a lower
directory dentry may trigger copy up and take sb_writers on the upper fs
of the lower nested overlayfs.
The lower nested overlayfs may have the same upper fs as this overlayfs,
so nested sb_writers lock is illegal.
Move all the callers that encode lower fh to before ovl_want_write().
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
fs/overlayfs/copy_up.c | 52 ++++++++++++++++++++++++----------------
fs/overlayfs/namei.c | 37 +++++++++++++++++++++-------
fs/overlayfs/overlayfs.h | 26 ++++++++++++++------
fs/overlayfs/super.c | 20 +++++++++++-----
fs/overlayfs/util.c | 11 ++++++++-
5 files changed, 103 insertions(+), 43 deletions(-)
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index add5861cf06b..c0bac6bd90cf 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -434,29 +434,29 @@ struct ovl_fh *ovl_encode_real_fh(struct ovl_fs *ofs, struct dentry *real,
return ERR_PTR(err);
}
-int ovl_set_origin(struct ovl_fs *ofs, struct dentry *lower,
- struct dentry *upper)
+struct ovl_fh *ovl_get_origin_fh(struct ovl_fs *ofs, struct dentry *origin)
{
- const struct ovl_fh *fh = NULL;
- int err;
-
/*
* When lower layer doesn't support export operations store a 'null' fh,
* so we can use the overlay.origin xattr to distignuish between a copy
* up and a pure upper inode.
*/
- if (ovl_can_decode_fh(lower->d_sb)) {
- fh = ovl_encode_real_fh(ofs, lower, false);
- if (IS_ERR(fh))
- return PTR_ERR(fh);
- }
+ if (!ovl_can_decode_fh(origin->d_sb))
+ return NULL;
+
+ return ovl_encode_real_fh(ofs, origin, false);
+}
+
+int ovl_set_origin_fh(struct ovl_fs *ofs, const struct ovl_fh *fh,
+ struct dentry *upper)
+{
+ int err;
/*
* Do not fail when upper doesn't support xattrs.
*/
err = ovl_check_setxattr(ofs, upper, OVL_XATTR_ORIGIN, fh->buf,
fh ? fh->fb.len : 0, 0);
- kfree(fh);
/* Ignore -EPERM from setting "user.*" on symlink/special */
return err == -EPERM ? 0 : err;
@@ -484,7 +484,7 @@ static int ovl_set_upper_fh(struct ovl_fs *ofs, struct dentry *upper,
*
* Caller must hold i_mutex on indexdir.
*/
-static int ovl_create_index(struct dentry *dentry, struct dentry *origin,
+static int ovl_create_index(struct dentry *dentry, const struct ovl_fh *fh,
struct dentry *upper)
{
struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
@@ -510,7 +510,7 @@ static int ovl_create_index(struct dentry *dentry, struct dentry *origin,
if (WARN_ON(ovl_test_flag(OVL_INDEX, d_inode(dentry))))
return -EIO;
- err = ovl_get_index_name(ofs, origin, &name);
+ err = ovl_get_index_name_fh(fh, &name);
if (err)
return err;
@@ -549,6 +549,7 @@ struct ovl_copy_up_ctx {
struct dentry *destdir;
struct qstr destname;
struct dentry *workdir;
+ const struct ovl_fh *origin_fh;
bool origin;
bool indexed;
bool metacopy;
@@ -648,7 +649,7 @@ static int ovl_copy_up_metadata(struct ovl_copy_up_ctx *c, struct dentry *temp)
* hard link.
*/
if (c->origin) {
- err = ovl_set_origin(ofs, c->lowerpath.dentry, temp);
+ err = ovl_set_origin_fh(ofs, c->origin_fh, temp);
if (err)
return err;
}
@@ -771,7 +772,7 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
goto cleanup;
if (S_ISDIR(c->stat.mode) && c->indexed) {
- err = ovl_create_index(c->dentry, c->lowerpath.dentry, temp);
+ err = ovl_create_index(c->dentry, c->origin_fh, temp);
if (err)
goto cleanup;
}
@@ -889,6 +890,8 @@ static int ovl_do_copy_up(struct ovl_copy_up_ctx *c)
{
int err;
struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
+ struct dentry *origin = c->lowerpath.dentry;
+ struct ovl_fh *fh = NULL;
bool to_index = false;
/*
@@ -905,17 +908,25 @@ static int ovl_do_copy_up(struct ovl_copy_up_ctx *c)
to_index = true;
}
- if (S_ISDIR(c->stat.mode) || c->stat.nlink == 1 || to_index)
+ if (S_ISDIR(c->stat.mode) || c->stat.nlink == 1 || to_index) {
+ fh = ovl_get_origin_fh(ofs, origin);
+ if (IS_ERR(fh))
+ return PTR_ERR(fh);
+
+ /* origin_fh may be NULL */
+ c->origin_fh = fh;
c->origin = true;
+ }
if (to_index) {
c->destdir = ovl_indexdir(c->dentry->d_sb);
- err = ovl_get_index_name(ofs, c->lowerpath.dentry, &c->destname);
+ err = ovl_get_index_name(ofs, origin, &c->destname);
if (err)
- return err;
+ goto out;
} else if (WARN_ON(!c->parent)) {
/* Disconnected dentry must be copied up to index dir */
- return -EIO;
+ err = -EIO;
+ goto out;
} else {
/*
* Mark parent "impure" because it may now contain non-pure
@@ -925,7 +936,7 @@ static int ovl_do_copy_up(struct ovl_copy_up_ctx *c)
err = ovl_set_impure(c->parent, c->destdir);
ovl_end_write(c->dentry);
if (err)
- return err;
+ goto out;
}
/* Should we copyup with O_TMPFILE or with workdir? */
@@ -959,6 +970,7 @@ static int ovl_do_copy_up(struct ovl_copy_up_ctx *c)
out:
if (to_index)
kfree(c->destname.name);
+ kfree(fh);
return err;
}
diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
index 80391c687c2a..f10ac4ae35f0 100644
--- a/fs/overlayfs/namei.c
+++ b/fs/overlayfs/namei.c
@@ -507,6 +507,19 @@ static int ovl_verify_fh(struct ovl_fs *ofs, struct dentry *dentry,
return err;
}
+int ovl_verify_set_fh(struct ovl_fs *ofs, struct dentry *dentry,
+ enum ovl_xattr ox, const struct ovl_fh *fh,
+ bool is_upper, bool set)
+{
+ int err;
+
+ err = ovl_verify_fh(ofs, dentry, ox, fh);
+ if (set && err == -ENODATA)
+ err = ovl_setxattr(ofs, dentry, ox, fh->buf, fh->fb.len);
+
+ return err;
+}
+
/*
* Verify that @real dentry matches the file handle stored in xattr @name.
*
@@ -515,9 +528,9 @@ static int ovl_verify_fh(struct ovl_fs *ofs, struct dentry *dentry,
*
* Return 0 on match, -ESTALE on mismatch, -ENODATA on no xattr, < 0 on error.
*/
-int ovl_verify_set_fh(struct ovl_fs *ofs, struct dentry *dentry,
- enum ovl_xattr ox, struct dentry *real, bool is_upper,
- bool set)
+int ovl_verify_origin_xattr(struct ovl_fs *ofs, struct dentry *dentry,
+ enum ovl_xattr ox, struct dentry *real,
+ bool is_upper, bool set)
{
struct inode *inode;
struct ovl_fh *fh;
@@ -530,9 +543,7 @@ int ovl_verify_set_fh(struct ovl_fs *ofs, struct dentry *dentry,
goto fail;
}
- err = ovl_verify_fh(ofs, dentry, ox, fh);
- if (set && err == -ENODATA)
- err = ovl_setxattr(ofs, dentry, ox, fh->buf, fh->fb.len);
+ err = ovl_verify_set_fh(ofs, dentry, ox, fh, is_upper, set);
if (err)
goto fail;
@@ -548,6 +559,7 @@ int ovl_verify_set_fh(struct ovl_fs *ofs, struct dentry *dentry,
goto out;
}
+
/* Get upper dentry from index */
struct dentry *ovl_index_upper(struct ovl_fs *ofs, struct dentry *index,
bool connected)
@@ -684,7 +696,7 @@ int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index)
goto out;
}
-static int ovl_get_index_name_fh(struct ovl_fh *fh, struct qstr *name)
+int ovl_get_index_name_fh(const struct ovl_fh *fh, struct qstr *name)
{
char *n, *s;
@@ -873,20 +885,27 @@ int ovl_path_next(int idx, struct dentry *dentry, struct path *path)
static int ovl_fix_origin(struct ovl_fs *ofs, struct dentry *dentry,
struct dentry *lower, struct dentry *upper)
{
+ const struct ovl_fh *fh;
int err;
if (ovl_check_origin_xattr(ofs, upper))
return 0;
+ fh = ovl_get_origin_fh(ofs, lower);
+ if (IS_ERR(fh))
+ return PTR_ERR(fh);
+
err = ovl_want_write(dentry);
if (err)
- return err;
+ goto out;
- err = ovl_set_origin(ofs, lower, upper);
+ err = ovl_set_origin_fh(ofs, fh, upper);
if (!err)
err = ovl_set_impure(dentry->d_parent, upper->d_parent);
ovl_drop_write(dentry);
+out:
+ kfree(fh);
return err;
}
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index 6da49bf78b90..4e8a2b830c71 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -628,11 +628,15 @@ struct dentry *ovl_decode_real_fh(struct ovl_fs *ofs, struct ovl_fh *fh,
int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh, bool connected,
struct dentry *upperdentry, struct ovl_path **stackp);
int ovl_verify_set_fh(struct ovl_fs *ofs, struct dentry *dentry,
- enum ovl_xattr ox, struct dentry *real, bool is_upper,
- bool set);
+ enum ovl_xattr ox, const struct ovl_fh *fh,
+ bool is_upper, bool set);
+int ovl_verify_origin_xattr(struct ovl_fs *ofs, struct dentry *dentry,
+ enum ovl_xattr ox, struct dentry *real,
+ bool is_upper, bool set);
struct dentry *ovl_index_upper(struct ovl_fs *ofs, struct dentry *index,
bool connected);
int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index);
+int ovl_get_index_name_fh(const struct ovl_fh *fh, struct qstr *name);
int ovl_get_index_name(struct ovl_fs *ofs, struct dentry *origin,
struct qstr *name);
struct dentry *ovl_get_index_fh(struct ovl_fs *ofs, struct ovl_fh *fh);
@@ -644,17 +648,24 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
unsigned int flags);
bool ovl_lower_positive(struct dentry *dentry);
+static inline int ovl_verify_origin_fh(struct ovl_fs *ofs, struct dentry *upper,
+ const struct ovl_fh *fh, bool set)
+{
+ return ovl_verify_set_fh(ofs, upper, OVL_XATTR_ORIGIN, fh, false, set);
+}
+
static inline int ovl_verify_origin(struct ovl_fs *ofs, struct dentry *upper,
struct dentry *origin, bool set)
{
- return ovl_verify_set_fh(ofs, upper, OVL_XATTR_ORIGIN, origin,
- false, set);
+ return ovl_verify_origin_xattr(ofs, upper, OVL_XATTR_ORIGIN, origin,
+ false, set);
}
static inline int ovl_verify_upper(struct ovl_fs *ofs, struct dentry *index,
struct dentry *upper, bool set)
{
- return ovl_verify_set_fh(ofs, index, OVL_XATTR_UPPER, upper, true, set);
+ return ovl_verify_origin_xattr(ofs, index, OVL_XATTR_UPPER, upper,
+ true, set);
}
/* readdir.c */
@@ -819,8 +830,9 @@ int ovl_copy_xattr(struct super_block *sb, const struct path *path, struct dentr
int ovl_set_attr(struct ovl_fs *ofs, struct dentry *upper, struct kstat *stat);
struct ovl_fh *ovl_encode_real_fh(struct ovl_fs *ofs, struct dentry *real,
bool is_upper);
-int ovl_set_origin(struct ovl_fs *ofs, struct dentry *lower,
- struct dentry *upper);
+struct ovl_fh *ovl_get_origin_fh(struct ovl_fs *ofs, struct dentry *origin);
+int ovl_set_origin_fh(struct ovl_fs *ofs, const struct ovl_fh *fh,
+ struct dentry *upper);
/* export.c */
extern const struct export_operations ovl_export_operations;
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index def266b5e2a3..93d500d4fda9 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -881,15 +881,20 @@ static int ovl_get_indexdir(struct super_block *sb, struct ovl_fs *ofs,
{
struct vfsmount *mnt = ovl_upper_mnt(ofs);
struct dentry *indexdir;
+ struct dentry *origin = ovl_lowerstack(oe)->dentry;
+ const struct ovl_fh *fh;
int err;
+ fh = ovl_get_origin_fh(ofs, origin);
+ if (IS_ERR(fh))
+ return PTR_ERR(fh);
+
err = mnt_want_write(mnt);
if (err)
- return err;
+ goto out_free_fh;
/* Verify lower root is upper root origin */
- err = ovl_verify_origin(ofs, upperpath->dentry,
- ovl_lowerstack(oe)->dentry, true);
+ err = ovl_verify_origin_fh(ofs, upperpath->dentry, fh, true);
if (err) {
pr_err("failed to verify upper root origin\n");
goto out;
@@ -921,9 +926,10 @@ static int ovl_get_indexdir(struct super_block *sb, struct ovl_fs *ofs,
* directory entries.
*/
if (ovl_check_origin_xattr(ofs, ofs->indexdir)) {
- err = ovl_verify_set_fh(ofs, ofs->indexdir,
- OVL_XATTR_ORIGIN,
- upperpath->dentry, true, false);
+ err = ovl_verify_origin_xattr(ofs, ofs->indexdir,
+ OVL_XATTR_ORIGIN,
+ upperpath->dentry, true,
+ false);
if (err)
pr_err("failed to verify index dir 'origin' xattr\n");
}
@@ -941,6 +947,8 @@ static int ovl_get_indexdir(struct super_block *sb, struct ovl_fs *ofs,
out:
mnt_drop_write(mnt);
+out_free_fh:
+ kfree(fh);
return err;
}
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
index 4e67ef0cc8da..5d92252cee30 100644
--- a/fs/overlayfs/util.c
+++ b/fs/overlayfs/util.c
@@ -1013,12 +1013,18 @@ static void ovl_cleanup_index(struct dentry *dentry)
struct dentry *index = NULL;
struct inode *inode;
struct qstr name = { };
+ bool got_write = false;
int err;
err = ovl_get_index_name(ofs, lowerdentry, &name);
if (err)
goto fail;
+ err = ovl_want_write(dentry);
+ if (err)
+ goto fail;
+
+ got_write = true;
inode = d_inode(upperdentry);
if (!S_ISDIR(inode->i_mode) && inode->i_nlink != 1) {
pr_warn_ratelimited("cleanup linked index (%pd2, ino=%lu, nlink=%u)\n",
@@ -1056,6 +1062,8 @@ static void ovl_cleanup_index(struct dentry *dentry)
goto fail;
out:
+ if (got_write)
+ ovl_drop_write(dentry);
kfree(name.name);
dput(index);
return;
@@ -1135,6 +1143,8 @@ void ovl_nlink_end(struct dentry *dentry)
{
struct inode *inode = d_inode(dentry);
+ ovl_drop_write(dentry);
+
if (ovl_test_flag(OVL_INDEX, inode) && inode->i_nlink == 0) {
const struct cred *old_cred;
@@ -1143,7 +1153,6 @@ void ovl_nlink_end(struct dentry *dentry)
revert_creds(old_cred);
}
- ovl_drop_write(dentry);
ovl_inode_unlock(inode);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 0/4] fs: export __mnt_{want,drop}_write to modules
2023-08-16 15:23 [PATCH v3 0/4] overlayfs lock ordering changes Amir Goldstein
` (3 preceding siblings ...)
2023-08-16 15:23 ` [PATCH v3 4/4] ovl: do not encode lower fh " Amir Goldstein
@ 2023-08-17 5:44 ` Amir Goldstein
2023-08-17 13:38 ` Christian Brauner
4 siblings, 1 reply; 10+ messages in thread
From: Amir Goldstein @ 2023-08-17 5:44 UTC (permalink / raw)
To: Miklos Szeredi; +Cc: Christian Brauner, linux-unionfs
overlayfs is going to use those to grab a write reference on the
upper fs during copy up.
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
Christian,
This patch is needed for the ovl_want_write() changes [1],
which I forgot to CC you on.
Please ACK if you approve.
Thanks,
Amir.
[1] https://lore.kernel.org/linux-unionfs/20230816152334.924960-1-amir73il@gmail.com/
fs/namespace.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/fs/namespace.c b/fs/namespace.c
index e157efc54023..370328b204f1 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -386,6 +386,7 @@ int __mnt_want_write(struct vfsmount *m)
return ret;
}
+EXPORT_SYMBOL_GPL(__mnt_want_write);
/**
* mnt_want_write - get write access to a mount
@@ -466,6 +467,7 @@ void __mnt_drop_write(struct vfsmount *mnt)
mnt_dec_writers(real_mount(mnt));
preempt_enable();
}
+EXPORT_SYMBOL_GPL(__mnt_drop_write);
/**
* mnt_drop_write - give up write access to a mount
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v3 0/4] fs: export __mnt_{want,drop}_write to modules
2023-08-17 5:44 ` [PATCH v3 0/4] fs: export __mnt_{want,drop}_write to modules Amir Goldstein
@ 2023-08-17 13:38 ` Christian Brauner
2023-08-17 13:55 ` Amir Goldstein
0 siblings, 1 reply; 10+ messages in thread
From: Christian Brauner @ 2023-08-17 13:38 UTC (permalink / raw)
To: Amir Goldstein; +Cc: Miklos Szeredi, linux-unionfs
On Thu, Aug 17, 2023 at 08:44:46AM +0300, Amir Goldstein wrote:
> overlayfs is going to use those to grab a write reference on the
> upper fs during copy up.
>
> Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> ---
>
> Christian,
>
> This patch is needed for the ovl_want_write() changes [1],
> which I forgot to CC you on.
>
> Please ACK if you approve.
>
> Thanks,
> Amir.
>
> [1] https://lore.kernel.org/linux-unionfs/20230816152334.924960-1-amir73il@gmail.com/
>
> fs/namespace.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/fs/namespace.c b/fs/namespace.c
> index e157efc54023..370328b204f1 100644
> --- a/fs/namespace.c
> +++ b/fs/namespace.c
> @@ -386,6 +386,7 @@ int __mnt_want_write(struct vfsmount *m)
>
> return ret;
> }
> +EXPORT_SYMBOL_GPL(__mnt_want_write);
Puh, not excited about that but also no real reason to say no other than
generic worries about it being abused.
But maybe let's not export underscore variants. Might make sense to at
least name them differently? mnt_want_write_locked()?
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 0/4] fs: export __mnt_{want,drop}_write to modules
2023-08-17 13:38 ` Christian Brauner
@ 2023-08-17 13:55 ` Amir Goldstein
2023-08-17 14:32 ` Christian Brauner
0 siblings, 1 reply; 10+ messages in thread
From: Amir Goldstein @ 2023-08-17 13:55 UTC (permalink / raw)
To: Christian Brauner; +Cc: Miklos Szeredi, linux-unionfs
On Thu, Aug 17, 2023 at 4:38 PM Christian Brauner <brauner@kernel.org> wrote:
>
> On Thu, Aug 17, 2023 at 08:44:46AM +0300, Amir Goldstein wrote:
> > overlayfs is going to use those to grab a write reference on the
> > upper fs during copy up.
> >
> > Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> > ---
> >
> > Christian,
> >
> > This patch is needed for the ovl_want_write() changes [1],
> > which I forgot to CC you on.
> >
> > Please ACK if you approve.
> >
> > Thanks,
> > Amir.
> >
> > [1] https://lore.kernel.org/linux-unionfs/20230816152334.924960-1-amir73il@gmail.com/
> >
> > fs/namespace.c | 2 ++
> > 1 file changed, 2 insertions(+)
> >
> > diff --git a/fs/namespace.c b/fs/namespace.c
> > index e157efc54023..370328b204f1 100644
> > --- a/fs/namespace.c
> > +++ b/fs/namespace.c
> > @@ -386,6 +386,7 @@ int __mnt_want_write(struct vfsmount *m)
> >
> > return ret;
> > }
> > +EXPORT_SYMBOL_GPL(__mnt_want_write);
>
> Puh, not excited about that but also no real reason to say no other than
> generic worries about it being abused.
> But maybe let's not export underscore variants. Might make sense to at
> least name them differently? mnt_want_write_locked()?
Heh, it's not locked. It happens to be called with sb_start_write() from
mnt_want_write(), but from do_dentry_open() it's actually called *before*
file_start_write(), because the mnt_writers refcount and sb_writers lock
are not strictly ordered, which is very convenient for ovl copy up.
We could go for mnt_{get,put}_write(), but that's a bit close to
mnt_get_writers().
We could go for mnt_{get,put}_write_access(), like helpers with similar
names for inode.
I don't really mind, as long as this doesn't become a bike shedding thing...
Thanks,
Amir.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 0/4] fs: export __mnt_{want,drop}_write to modules
2023-08-17 13:55 ` Amir Goldstein
@ 2023-08-17 14:32 ` Christian Brauner
2023-08-17 14:41 ` Amir Goldstein
0 siblings, 1 reply; 10+ messages in thread
From: Christian Brauner @ 2023-08-17 14:32 UTC (permalink / raw)
To: Amir Goldstein; +Cc: Miklos Szeredi, linux-unionfs
On Thu, Aug 17, 2023 at 04:55:55PM +0300, Amir Goldstein wrote:
> On Thu, Aug 17, 2023 at 4:38 PM Christian Brauner <brauner@kernel.org> wrote:
> >
> > On Thu, Aug 17, 2023 at 08:44:46AM +0300, Amir Goldstein wrote:
> > > overlayfs is going to use those to grab a write reference on the
> > > upper fs during copy up.
> > >
> > > Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> > > ---
> > >
> > > Christian,
> > >
> > > This patch is needed for the ovl_want_write() changes [1],
> > > which I forgot to CC you on.
> > >
> > > Please ACK if you approve.
> > >
> > > Thanks,
> > > Amir.
> > >
> > > [1] https://lore.kernel.org/linux-unionfs/20230816152334.924960-1-amir73il@gmail.com/
> > >
> > > fs/namespace.c | 2 ++
> > > 1 file changed, 2 insertions(+)
> > >
> > > diff --git a/fs/namespace.c b/fs/namespace.c
> > > index e157efc54023..370328b204f1 100644
> > > --- a/fs/namespace.c
> > > +++ b/fs/namespace.c
> > > @@ -386,6 +386,7 @@ int __mnt_want_write(struct vfsmount *m)
> > >
> > > return ret;
> > > }
> > > +EXPORT_SYMBOL_GPL(__mnt_want_write);
> >
> > Puh, not excited about that but also no real reason to say no other than
> > generic worries about it being abused.
> > But maybe let's not export underscore variants. Might make sense to at
> > least name them differently? mnt_want_write_locked()?
>
> Heh, it's not locked. It happens to be called with sb_start_write() from
> mnt_want_write(), but from do_dentry_open() it's actually called *before*
> file_start_write(), because the mnt_writers refcount and sb_writers lock
> are not strictly ordered, which is very convenient for ovl copy up.
>
> We could go for mnt_{get,put}_write(), but that's a bit close to
> mnt_get_writers().
>
> We could go for mnt_{get,put}_write_access(), like helpers with similar
> names for inode.
Fine by me. I'm just not happy with this __*() thing.
>
> I don't really mind, as long as this doesn't become a bike shedding thing...
So I brought all that paint for nothing?
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 0/4] fs: export __mnt_{want,drop}_write to modules
2023-08-17 14:32 ` Christian Brauner
@ 2023-08-17 14:41 ` Amir Goldstein
0 siblings, 0 replies; 10+ messages in thread
From: Amir Goldstein @ 2023-08-17 14:41 UTC (permalink / raw)
To: Christian Brauner; +Cc: Miklos Szeredi, linux-unionfs
On Thu, Aug 17, 2023 at 5:32 PM Christian Brauner <brauner@kernel.org> wrote:
>
> On Thu, Aug 17, 2023 at 04:55:55PM +0300, Amir Goldstein wrote:
> > On Thu, Aug 17, 2023 at 4:38 PM Christian Brauner <brauner@kernel.org> wrote:
> > >
> > > On Thu, Aug 17, 2023 at 08:44:46AM +0300, Amir Goldstein wrote:
> > > > overlayfs is going to use those to grab a write reference on the
> > > > upper fs during copy up.
> > > >
> > > > Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> > > > ---
> > > >
> > > > Christian,
> > > >
> > > > This patch is needed for the ovl_want_write() changes [1],
> > > > which I forgot to CC you on.
> > > >
> > > > Please ACK if you approve.
> > > >
> > > > Thanks,
> > > > Amir.
> > > >
> > > > [1] https://lore.kernel.org/linux-unionfs/20230816152334.924960-1-amir73il@gmail.com/
> > > >
> > > > fs/namespace.c | 2 ++
> > > > 1 file changed, 2 insertions(+)
> > > >
> > > > diff --git a/fs/namespace.c b/fs/namespace.c
> > > > index e157efc54023..370328b204f1 100644
> > > > --- a/fs/namespace.c
> > > > +++ b/fs/namespace.c
> > > > @@ -386,6 +386,7 @@ int __mnt_want_write(struct vfsmount *m)
> > > >
> > > > return ret;
> > > > }
> > > > +EXPORT_SYMBOL_GPL(__mnt_want_write);
> > >
> > > Puh, not excited about that but also no real reason to say no other than
> > > generic worries about it being abused.
> > > But maybe let's not export underscore variants. Might make sense to at
> > > least name them differently? mnt_want_write_locked()?
> >
> > Heh, it's not locked. It happens to be called with sb_start_write() from
> > mnt_want_write(), but from do_dentry_open() it's actually called *before*
> > file_start_write(), because the mnt_writers refcount and sb_writers lock
> > are not strictly ordered, which is very convenient for ovl copy up.
> >
> > We could go for mnt_{get,put}_write(), but that's a bit close to
> > mnt_get_writers().
> >
> > We could go for mnt_{get,put}_write_access(), like helpers with similar
> > names for inode.
>
> Fine by me. I'm just not happy with this __*() thing.
>
> >
> > I don't really mind, as long as this doesn't become a bike shedding thing...
>
> So I brought all that paint for nothing?
LoL :)
I will take it as an ACK for exporting either mnt_{get,put}_write() or
mnt_{get,put}_write_access() symbols.
If no objections are raised I will go for the shorter option.
Thanks,
Amir.
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2023-08-17 14:44 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-08-16 15:23 [PATCH v3 0/4] overlayfs lock ordering changes Amir Goldstein
2023-08-16 15:23 ` [PATCH v3 1/4] ovl: reorder ovl_want_write() after ovl_inode_lock() Amir Goldstein
2023-08-16 15:23 ` [PATCH v3 2/4] ovl: split ovl_want_write() into two helpers Amir Goldstein
2023-08-16 15:23 ` [PATCH v3 3/4] ovl: do not open/llseek lower file with upper sb_writers held Amir Goldstein
2023-08-16 15:23 ` [PATCH v3 4/4] ovl: do not encode lower fh " Amir Goldstein
2023-08-17 5:44 ` [PATCH v3 0/4] fs: export __mnt_{want,drop}_write to modules Amir Goldstein
2023-08-17 13:38 ` Christian Brauner
2023-08-17 13:55 ` Amir Goldstein
2023-08-17 14:32 ` Christian Brauner
2023-08-17 14:41 ` Amir Goldstein
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).