summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/overlayfs/export.c53
-rw-r--r--fs/overlayfs/namei.c7
-rw-r--r--fs/overlayfs/overlayfs.h2
3 files changed, 47 insertions, 15 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;
diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
index a35c5eaa2c01..741a42d974a3 100644
--- a/fs/overlayfs/namei.c
+++ b/fs/overlayfs/namei.c
@@ -310,9 +310,8 @@ static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d,
}
-static int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh,
- struct dentry *upperdentry,
- struct ovl_path **stackp)
+int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh,
+ struct dentry *upperdentry, struct ovl_path **stackp)
{
struct dentry *origin = NULL;
int i;
@@ -328,7 +327,7 @@ static int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh,
else if (IS_ERR(origin))
return PTR_ERR(origin);
- if (!ovl_is_whiteout(upperdentry) &&
+ if (upperdentry && !ovl_is_whiteout(upperdentry) &&
((d_inode(origin)->i_mode ^ d_inode(upperdentry)->i_mode) & S_IFMT))
goto invalid;
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index 401113a2e9c7..40ba11e412b1 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -266,6 +266,8 @@ static inline bool ovl_is_impuredir(struct dentry *dentry)
/* namei.c */
int ovl_check_fh_len(struct ovl_fh *fh, int fh_len);
struct dentry *ovl_decode_fh(struct ovl_fh *fh, struct vfsmount *mnt);
+int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh,
+ struct dentry *upperdentry, struct ovl_path **stackp);
int ovl_verify_set_fh(struct dentry *dentry, const char *name,
struct dentry *real, bool is_upper, bool set);
int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index);