summaryrefslogtreecommitdiffstats
path: root/fs/overlayfs/export.c
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2018-01-19 20:33:44 +0100
committerMiklos Szeredi <mszeredi@redhat.com>2018-01-24 11:26:02 +0100
commitf941866fc4a8ad0d0b861cc2dbffa06a9f5e8963 (patch)
tree2600400b0ce59c94c28132e167441f5dc6486363 /fs/overlayfs/export.c
parentovl: encode lower file handles (diff)
downloadlinux-f941866fc4a8ad0d0b861cc2dbffa06a9f5e8963.tar.xz
linux-f941866fc4a8ad0d0b861cc2dbffa06a9f5e8963.zip
ovl: decode lower non-dir file handles
Decoding a lower non-dir file handle is done by decoding the lower dentry from underlying lower fs, finding or allocating an overlay inode that is hashed by the real lower inode and instantiating an overlay dentry with that inode. Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'fs/overlayfs/export.c')
-rw-r--r--fs/overlayfs/export.c53
1 files changed, 42 insertions, 11 deletions
diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c
index 8e37a07b9eff..8c0172d9b922 100644
--- a/fs/overlayfs/export.c
+++ b/fs/overlayfs/export.c
@@ -169,16 +169,16 @@ static struct dentry *ovl_obtain_alias(struct super_block *sb,
struct dentry *upper,
struct ovl_path *lowerpath)
{
- struct inode *inode;
+ struct dentry *lower = lowerpath ? lowerpath->dentry : NULL;
struct dentry *dentry;
+ struct inode *inode;
struct ovl_entry *oe;
- void *fsdata = &oe;
- /* TODO: obtain non pure-upper */
- if (lowerpath)
+ /* TODO: obtain an indexed non-dir upper with origin */
+ if (lower && (upper || d_is_dir(lower)))
return ERR_PTR(-EIO);
- inode = ovl_get_inode(sb, dget(upper), NULL, NULL, 0);
+ inode = ovl_get_inode(sb, dget(upper), lower, NULL, !!lower);
if (IS_ERR(inode)) {
dput(upper);
return ERR_CAST(inode);
@@ -189,12 +189,17 @@ static struct dentry *ovl_obtain_alias(struct super_block *sb,
dentry = d_alloc_anon(inode->i_sb);
if (!dentry)
goto nomem;
- oe = ovl_alloc_entry(0);
+ oe = ovl_alloc_entry(lower ? 1 : 0);
if (!oe)
goto nomem;
+ if (lower) {
+ oe->lowerstack->dentry = dget(lower);
+ oe->lowerstack->layer = lowerpath->layer;
+ }
dentry->d_fsdata = oe;
- ovl_dentry_set_upper_alias(dentry);
+ if (upper)
+ ovl_dentry_set_upper_alias(dentry);
}
return d_instantiate_anon(dentry, inode);
@@ -381,7 +386,14 @@ static struct dentry *ovl_get_dentry(struct super_block *sb,
struct ovl_fs *ofs = sb->s_fs_info;
struct ovl_layer upper_layer = { .mnt = ofs->upper_mnt };
- /* TODO: get non-upper dentry */
+ /*
+ * Obtain a disconnected overlay dentry from a disconnected non-dir
+ * real lower dentry.
+ */
+ if (!upper && !d_is_dir(lowerpath->dentry))
+ return ovl_obtain_alias(sb, NULL, lowerpath);
+
+ /* TODO: lookup connected dir from real lower dir */
if (!upper)
return ERR_PTR(-EACCES);
@@ -423,6 +435,25 @@ static struct dentry *ovl_upper_fh_to_d(struct super_block *sb,
return dentry;
}
+static struct dentry *ovl_lower_fh_to_d(struct super_block *sb,
+ struct ovl_fh *fh)
+{
+ struct ovl_fs *ofs = sb->s_fs_info;
+ struct ovl_path origin = { };
+ struct ovl_path *stack = &origin;
+ struct dentry *dentry = NULL;
+ int err;
+
+ err = ovl_check_origin_fh(ofs, fh, NULL, &stack);
+ if (err)
+ return ERR_PTR(err);
+
+ dentry = ovl_get_dentry(sb, NULL, &origin);
+ dput(origin.dentry);
+
+ return dentry;
+}
+
static struct dentry *ovl_fh_to_dentry(struct super_block *sb, struct fid *fid,
int fh_len, int fh_type)
{
@@ -440,10 +471,10 @@ static struct dentry *ovl_fh_to_dentry(struct super_block *sb, struct fid *fid,
if (err)
goto out_err;
- /* TODO: decode non-upper */
flags = fh->flags;
- if (flags & OVL_FH_FLAG_PATH_UPPER)
- dentry = ovl_upper_fh_to_d(sb, fh);
+ dentry = (flags & OVL_FH_FLAG_PATH_UPPER) ?
+ ovl_upper_fh_to_d(sb, fh) :
+ ovl_lower_fh_to_d(sb, fh);
err = PTR_ERR(dentry);
if (IS_ERR(dentry) && err != -ESTALE)
goto out_err;