[PATCH 2/2] ovl: avoid lockdep warning with open and llseek of lower file

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

Drop upper sb_writers for lower file open and llseek to avoid the
lockdep warning.

Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx>
---
 fs/overlayfs/copy_up.c | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index 7e09c3187274..467107bb9f0e 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -233,6 +233,7 @@ static int ovl_copy_fileattr(struct inode *inode, const struct path *old,
 static int ovl_copy_up_file(struct ovl_fs *ofs, struct dentry *dentry,
 			    struct file *new_file, loff_t len)
 {
+	struct super_block *upper_sb = ovl_upper_mnt(ofs)->mnt_sb;
 	struct path datapath;
 	struct file *old_file;
 	loff_t old_pos = 0;
@@ -247,9 +248,21 @@ static int ovl_copy_up_file(struct ovl_fs *ofs, struct dentry *dentry,
 	if (WARN_ON(datapath.dentry == NULL))
 		return -EIO;
 
+	/*
+	 * Drop upper sb_writers to avert lockdep warning with open of lower
+	 * file in nested overlay:
+	 * - upper sb_writers
+	 * -- lower ovl_inode_lock (ovl_maybe_lookup_lowerdata)
+	 *
+	 * In case lower ovl uses same upper as this ovl, lockdep will warn
+	 * about (possibly false positive) circular lock dependency because the
+	 * ordering above is reverse to the order in ovl_copy_up_start().
+	 */
+	sb_end_write(upper_sb);
 	old_file = ovl_path_open(&datapath, O_LARGEFILE | O_RDONLY);
 	if (IS_ERR(old_file))
 		return PTR_ERR(old_file);
+	sb_start_write(upper_sb);
 
 	/* Try to use clone_file_range to clone up within the same fs */
 	cloned = do_clone_file_range(old_file, 0, new_file, 0, len, 0);
@@ -287,10 +300,16 @@ 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.
+		 *
+		 * Drop upper sb_writers 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) {
+			sb_end_write(upper_sb);
 			data_pos = vfs_llseek(old_file, old_pos, SEEK_DATA);
+			sb_start_write(upper_sb);
 			if (data_pos > old_pos) {
 				hole_len = data_pos - old_pos;
 				len -= hole_len;
-- 
2.34.1




[Index of Archives]     [Linux Filesystems Devel]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux