diff --git a/fs/open.c b/fs/open.c index e43f02ff64ac..bb484b07390a 100644 --- a/fs/open.c +++ b/fs/open.c @@ -1172,6 +1172,7 @@ struct file *dentry_open_nonotify(const struct path *path, int flags, } return f; } +EXPORT_SYMBOL_GPL(dentry_open_nonotify); /** * kernel_file_open - open a file for kernel internal use diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index e9389a10452e..b5a672e8e476 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -531,7 +531,14 @@ void ovl_dir_modified(struct dentry *dentry, bool impurity); u64 ovl_inode_version_get(struct inode *inode); bool ovl_is_whiteout(struct dentry *dentry); bool ovl_path_is_whiteout(struct ovl_fs *ofs, const struct path *path); -struct file *ovl_path_open(const struct path *path, int flags); +struct file *ovl_path_open_realfile(const struct file *user_file, + const struct path *path, int flags); + +static inline struct file *ovl_path_open(const struct path *path, int flags) +{ + return ovl_path_open_realfile(NULL, path, flags); +} + int ovl_copy_up_start(struct dentry *dentry, int flags); void ovl_copy_up_end(struct dentry *dentry); bool ovl_already_copied_up(struct dentry *dentry, int flags); diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index b862309eba4d..5d21a328fad4 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c @@ -994,7 +994,8 @@ static struct file *ovl_dir_open_realfile(const struct file *file, const struct path *realpath) { with_ovl_creds(file_inode(file)->i_sb) - return ovl_path_open(realpath, O_RDONLY | (file->f_flags & O_LARGEFILE)); + return ovl_path_open_realfile(file, realpath, + O_RDONLY | (file->f_flags & O_LARGEFILE)); } /* diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index 6c3fda047f94..788c6870d67d 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -654,7 +654,8 @@ bool ovl_path_is_whiteout(struct ovl_fs *ofs, const struct path *path) ovl_path_check_xwhiteout_xattr(ofs, path); } -struct file *ovl_path_open(const struct path *path, int flags) +struct file *ovl_path_open_realfile(const struct file *user_file, + const struct path *path, int flags) { struct inode *inode = d_inode(path->dentry); const struct mnt_idmap *real_idmap = mnt_idmap(path->mnt); @@ -682,6 +683,14 @@ struct file *ovl_path_open(const struct path *path, int flags) if (inode_owner_or_capable(real_idmap, inode)) flags |= O_NOATIME; + /* + * Directory opens use dentry_open() here, not backing_file_open(). + * Inherit FMODE_NONOTIFY from a fanotify permission fd so a listener + * that also watches the real filesystem does not deadlock. + */ + if (user_file && FMODE_FSNOTIFY_NONE(user_file->f_mode)) + return dentry_open_nonotify(path, flags, current_cred()); + return dentry_open(path, flags, current_cred()); }