summaryrefslogtreecommitdiff
path: root/fs/overlayfs/export.c
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2018-01-19 01:03:23 +0200
committerMiklos Szeredi <mszeredi@redhat.com>2018-01-24 11:26:00 +0100
commit8556a4205b111c4dac931ee5eba4fcce74c3cb21 (patch)
tree91e96d4841893b6b7e5b938e59725f6a31996add /fs/overlayfs/export.c
parent8ed5eec9d6c4c013aa657ebefbd10a1a0d15893d (diff)
ovl: decode pure upper file handles
Decoding an upper file handle is done by decoding the upper dentry from underlying upper fs, finding or allocating an overlay inode that is hashed by the real upper 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.c97
1 files changed, 97 insertions, 0 deletions
diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c
index 67b907ca9cdc..a7d57bf9c9d8 100644
--- a/fs/overlayfs/export.c
+++ b/fs/overlayfs/export.c
@@ -93,6 +93,103 @@ static int ovl_encode_inode_fh(struct inode *inode, u32 *fid, int *max_len,
return type;
}
+/*
+ * Find or instantiate an overlay dentry from real dentries.
+ */
+static struct dentry *ovl_obtain_alias(struct super_block *sb,
+ struct dentry *upper,
+ struct ovl_path *lowerpath)
+{
+ struct inode *inode;
+ struct dentry *dentry;
+ struct ovl_entry *oe;
+ void *fsdata = &oe;
+
+ /* TODO: obtain non pure-upper */
+ if (lowerpath)
+ return ERR_PTR(-EIO);
+
+ inode = ovl_get_inode(sb, dget(upper), NULL, NULL, 0);
+ if (IS_ERR(inode)) {
+ dput(upper);
+ return ERR_CAST(inode);
+ }
+
+ dentry = d_find_any_alias(inode);
+ if (!dentry) {
+ dentry = d_alloc_anon(inode->i_sb);
+ if (!dentry)
+ goto nomem;
+ oe = ovl_alloc_entry(0);
+ if (!oe)
+ goto nomem;
+
+ dentry->d_fsdata = oe;
+ ovl_dentry_set_upper_alias(dentry);
+ }
+
+ return d_instantiate_anon(dentry, inode);
+
+nomem:
+ iput(inode);
+ dput(dentry);
+ return ERR_PTR(-ENOMEM);
+}
+
+static struct dentry *ovl_upper_fh_to_d(struct super_block *sb,
+ struct ovl_fh *fh)
+{
+ struct ovl_fs *ofs = sb->s_fs_info;
+ struct dentry *dentry;
+ struct dentry *upper;
+
+ if (!ofs->upper_mnt)
+ return ERR_PTR(-EACCES);
+
+ upper = ovl_decode_fh(fh, ofs->upper_mnt);
+ if (IS_ERR_OR_NULL(upper))
+ return upper;
+
+ dentry = ovl_obtain_alias(sb, upper, NULL);
+ dput(upper);
+
+ return dentry;
+}
+
+static struct dentry *ovl_fh_to_dentry(struct super_block *sb, struct fid *fid,
+ int fh_len, int fh_type)
+{
+ struct dentry *dentry = NULL;
+ struct ovl_fh *fh = (struct ovl_fh *) fid;
+ int len = fh_len << 2;
+ unsigned int flags = 0;
+ int err;
+
+ err = -EINVAL;
+ if (fh_type != OVL_FILEID)
+ goto out_err;
+
+ err = ovl_check_fh_len(fh, len);
+ 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);
+ err = PTR_ERR(dentry);
+ if (IS_ERR(dentry) && err != -ESTALE)
+ goto out_err;
+
+ return dentry;
+
+out_err:
+ pr_warn_ratelimited("overlayfs: failed to decode file handle (len=%d, type=%d, flags=%x, err=%i)\n",
+ len, fh_type, flags, err);
+ return ERR_PTR(err);
+}
+
const struct export_operations ovl_export_operations = {
.encode_fh = ovl_encode_inode_fh,
+ .fh_to_dentry = ovl_fh_to_dentry,
};