ovl: pass layer mnt to ovl_open_realfile()

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>
This commit is contained in:
Amir Goldstein 2022-04-04 12:51:47 +02:00 committed by Miklos Szeredi
parent 5272eaf3a5
commit 1248ea4b91
3 changed files with 28 additions and 9 deletions

View File

@ -38,8 +38,9 @@ static char ovl_whatisit(struct inode *inode, struct inode *realinode)
#define OVL_OPEN_FLAGS (O_NOATIME | FMODE_NONOTIFY) #define OVL_OPEN_FLAGS (O_NOATIME | FMODE_NONOTIFY)
static struct file *ovl_open_realfile(const struct file *file, 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 inode *inode = file_inode(file);
struct file *realfile; struct file *realfile;
const struct cred *old_cred; 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, static int ovl_real_fdget_meta(const struct file *file, struct fd *real,
bool allow_meta) bool allow_meta)
{ {
struct inode *inode = file_inode(file); struct dentry *dentry = file_dentry(file);
struct inode *realinode; struct path realpath;
real->flags = 0; real->flags = 0;
real->file = file->private_data; real->file = file->private_data;
if (allow_meta) if (allow_meta)
realinode = ovl_inode_real(inode); ovl_path_real(dentry, &realpath);
else else
realinode = ovl_inode_realdata(inode); ovl_path_realdata(dentry, &realpath);
/* Has it been copied up since we'd opened it? */ /* 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->flags = FDPUT_FPUT;
real->file = ovl_open_realfile(file, realinode); real->file = ovl_open_realfile(file, &realpath);
return PTR_ERR_OR_ZERO(real->file); 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) static int ovl_open(struct inode *inode, struct file *file)
{ {
struct dentry *dentry = file_dentry(file);
struct file *realfile; struct file *realfile;
struct path realpath;
int err; int err;
err = ovl_maybe_copy_up(file_dentry(file), file->f_flags); err = ovl_maybe_copy_up(dentry, file->f_flags);
if (err) if (err)
return err; return err;
/* No longer need these flags, so don't pass them on to underlying fs */ /* 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); 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)) if (IS_ERR(realfile))
return PTR_ERR(realfile); return PTR_ERR(realfile);

View 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_lower(struct dentry *dentry, struct path *path);
void ovl_path_lowerdata(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_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_upper(struct dentry *dentry);
struct dentry *ovl_dentry_lower(struct dentry *dentry); struct dentry *ovl_dentry_lower(struct dentry *dentry);
struct dentry *ovl_dentry_lowerdata(struct dentry *dentry); struct dentry *ovl_dentry_lowerdata(struct dentry *dentry);

View File

@ -194,6 +194,20 @@ enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path)
return type; 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) struct dentry *ovl_dentry_upper(struct dentry *dentry)
{ {
return ovl_upperdentry_dereference(OVL_I(d_inode(dentry))); return ovl_upperdentry_dereference(OVL_I(d_inode(dentry)));