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