diff options
author | Amir Goldstein <amir73il@gmail.com> | 2023-08-16 12:42:18 +0300 |
---|---|---|
committer | Amir Goldstein <amir73il@gmail.com> | 2023-10-31 01:12:57 +0300 |
commit | c63e56a4a6523fcb1358e1878607d77a40b534bb (patch) | |
tree | 2c8b9e0f4c23495df940722abfb6eaf1133ad482 /fs/overlayfs/util.c | |
parent | 162d06444070c12827d604a2cb6b6bd98d48cbb0 (diff) | |
download | linux-c63e56a4a6523fcb1358e1878607d77a40b534bb.tar.xz |
ovl: do not open/llseek lower file with upper sb_writers held
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>
Diffstat (limited to 'fs/overlayfs/util.c')
-rw-r--r-- | fs/overlayfs/util.c | 8 |
1 files changed, 6 insertions, 2 deletions
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index af11c83b7a25..12156e2091ad 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_write_access(dentry); if (err) goto out_unlock; @@ -695,7 +699,7 @@ out_unlock: void ovl_copy_up_end(struct dentry *dentry) { - ovl_drop_write(dentry); + ovl_put_write_access(dentry); ovl_inode_unlock(d_inode(dentry)); } |