ovl: pass layer mnt to ovl_open_realfile()
authorAmir Goldstein <amir73il@gmail.com>
Mon, 4 Apr 2022 10:51:47 +0000 (12:51 +0200)
committerMiklos Szeredi <mszeredi@redhat.com>
Thu, 28 Apr 2022 14:31:11 +0000 (16:31 +0200)
Ensure that ovl_open_realfile() takes the mount's idmapping into
account. We add a new helper ovl_path_realdata() that can be used to
easily retrieve the relevant path which we can pass down. This is needed
to support idmapped base layers with overlay.

Cc: <linux-unionfs@vger.kernel.org>
Tested-by: Giuseppe Scrivano <gscrivan@redhat.com>
Reviewed-by: Christian Brauner (Microsoft) <brauner@kernel.org>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Christian Brauner (Microsoft) <brauner@kernel.org>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/overlayfs/file.c
fs/overlayfs/overlayfs.h
fs/overlayfs/util.c

index fa125fe..9250e04 100644 (file)
@@ -38,8 +38,9 @@ static char ovl_whatisit(struct inode *inode, struct inode *realinode)
 #define OVL_OPEN_FLAGS (O_NOATIME | FMODE_NONOTIFY)
 
 static struct file *ovl_open_realfile(const struct file *file,
-                                     struct inode *realinode)
+                                     struct path *realpath)
 {
+       struct inode *realinode = d_inode(realpath->dentry);
        struct inode *inode = file_inode(file);
        struct file *realfile;
        const struct cred *old_cred;
@@ -104,21 +105,21 @@ static int ovl_change_flags(struct file *file, unsigned int flags)
 static int ovl_real_fdget_meta(const struct file *file, struct fd *real,
                               bool allow_meta)
 {
-       struct inode *inode = file_inode(file);
-       struct inode *realinode;
+       struct dentry *dentry = file_dentry(file);
+       struct path realpath;
 
        real->flags = 0;
        real->file = file->private_data;
 
        if (allow_meta)
-               realinode = ovl_inode_real(inode);
+               ovl_path_real(dentry, &realpath);
        else
-               realinode = ovl_inode_realdata(inode);
+               ovl_path_realdata(dentry, &realpath);
 
        /* Has it been copied up since we'd opened it? */
-       if (unlikely(file_inode(real->file) != realinode)) {
+       if (unlikely(file_inode(real->file) != d_inode(realpath.dentry))) {
                real->flags = FDPUT_FPUT;
-               real->file = ovl_open_realfile(file, realinode);
+               real->file = ovl_open_realfile(file, &realpath);
 
                return PTR_ERR_OR_ZERO(real->file);
        }
@@ -144,17 +145,20 @@ static int ovl_real_fdget(const struct file *file, struct fd *real)
 
 static int ovl_open(struct inode *inode, struct file *file)
 {
+       struct dentry *dentry = file_dentry(file);
        struct file *realfile;
+       struct path realpath;
        int err;
 
-       err = ovl_maybe_copy_up(file_dentry(file), file->f_flags);
+       err = ovl_maybe_copy_up(dentry, file->f_flags);
        if (err)
                return err;
 
        /* No longer need these flags, so don't pass them on to underlying fs */
        file->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
 
-       realfile = ovl_open_realfile(file, ovl_inode_realdata(inode));
+       ovl_path_realdata(dentry, &realpath);
+       realfile = ovl_open_realfile(file, &realpath);
        if (IS_ERR(realfile))
                return PTR_ERR(realfile);
 
index 40bf3d1..d6405c2 100644 (file)
@@ -320,6 +320,7 @@ void ovl_path_upper(struct dentry *dentry, struct path *path);
 void ovl_path_lower(struct dentry *dentry, struct path *path);
 void ovl_path_lowerdata(struct dentry *dentry, struct path *path);
 enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path);
+enum ovl_path_type ovl_path_realdata(struct dentry *dentry, struct path *path);
 struct dentry *ovl_dentry_upper(struct dentry *dentry);
 struct dentry *ovl_dentry_lower(struct dentry *dentry);
 struct dentry *ovl_dentry_lowerdata(struct dentry *dentry);
index 5a7e5d1..4229361 100644 (file)
@@ -194,6 +194,20 @@ enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path)
        return type;
 }
 
+enum ovl_path_type ovl_path_realdata(struct dentry *dentry, struct path *path)
+{
+       enum ovl_path_type type = ovl_path_type(dentry);
+
+       WARN_ON_ONCE(d_is_dir(dentry));
+
+       if (!OVL_TYPE_UPPER(type) || OVL_TYPE_MERGE(type))
+               ovl_path_lowerdata(dentry, path);
+       else
+               ovl_path_upper(dentry, path);
+
+       return type;
+}
+
 struct dentry *ovl_dentry_upper(struct dentry *dentry)
 {
        return ovl_upperdentry_dereference(OVL_I(d_inode(dentry)));