ovl: encode pure upper file handles
authorAmir Goldstein <amir73il@gmail.com>
Wed, 12 Jul 2017 11:17:16 +0000 (14:17 +0300)
committerMiklos Szeredi <mszeredi@redhat.com>
Wed, 24 Jan 2018 10:25:59 +0000 (11:25 +0100)
Encode overlay file handles as struct ovl_fh containing the file handle
encoding of the real upper inode.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/overlayfs/Makefile
fs/overlayfs/export.c [new file with mode: 0644]
fs/overlayfs/overlayfs.h

index 99373bb..3080234 100644 (file)
@@ -4,4 +4,5 @@
 
 obj-$(CONFIG_OVERLAY_FS) += overlay.o
 
-overlay-objs := super.o namei.o util.o inode.o dir.o readdir.o copy_up.o
+overlay-objs := super.o namei.o util.o inode.o dir.o readdir.o copy_up.o \
+               export.o
diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c
new file mode 100644 (file)
index 0000000..67b907c
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Overlayfs NFS export support.
+ *
+ * Amir Goldstein <amir73il@gmail.com>
+ *
+ * Copyright (C) 2017-2018 CTERA Networks. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/fs.h>
+#include <linux/cred.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/xattr.h>
+#include <linux/exportfs.h>
+#include <linux/ratelimit.h>
+#include "overlayfs.h"
+
+static int ovl_d_to_fh(struct dentry *dentry, char *buf, int buflen)
+{
+       struct dentry *upper = ovl_dentry_upper(dentry);
+       struct dentry *origin = ovl_dentry_lower(dentry);
+       struct ovl_fh *fh = NULL;
+       int err;
+
+       /*
+        * On overlay with an upper layer, overlay root inode is encoded as
+        * an upper file handle, because upper root dir is not indexed.
+        */
+       if (dentry == dentry->d_sb->s_root && upper)
+               origin = NULL;
+
+       err = -EACCES;
+       if (!upper || origin)
+               goto fail;
+
+       /* TODO: encode non pure-upper by origin */
+       fh = ovl_encode_fh(upper, true);
+
+       err = -EOVERFLOW;
+       if (fh->len > buflen)
+               goto fail;
+
+       memcpy(buf, (char *)fh, fh->len);
+       err = fh->len;
+
+out:
+       kfree(fh);
+       return err;
+
+fail:
+       pr_warn_ratelimited("overlayfs: failed to encode file handle (%pd2, err=%i, buflen=%d, len=%d, type=%d)\n",
+                           dentry, err, buflen, fh ? (int)fh->len : 0,
+                           fh ? fh->type : 0);
+       goto out;
+}
+
+static int ovl_dentry_to_fh(struct dentry *dentry, u32 *fid, int *max_len)
+{
+       int res, len = *max_len << 2;
+
+       res = ovl_d_to_fh(dentry, (char *)fid, len);
+       if (res <= 0)
+               return FILEID_INVALID;
+
+       len = res;
+
+       /* Round up to dwords */
+       *max_len = (len + 3) >> 2;
+       return OVL_FILEID;
+}
+
+static int ovl_encode_inode_fh(struct inode *inode, u32 *fid, int *max_len,
+                              struct inode *parent)
+{
+       struct dentry *dentry;
+       int type;
+
+       /* TODO: encode connectable file handles */
+       if (parent)
+               return FILEID_INVALID;
+
+       dentry = d_find_any_alias(inode);
+       if (WARN_ON(!dentry))
+               return FILEID_INVALID;
+
+       type = ovl_dentry_to_fh(dentry, fid, max_len);
+
+       dput(dentry);
+       return type;
+}
+
+const struct export_operations ovl_export_operations = {
+       .encode_fh      = ovl_encode_inode_fh,
+};
index 2dddcd2..f2baa2c 100644 (file)
@@ -68,6 +68,9 @@ enum ovl_entry_flag {
 #error Endianness not defined
 #endif
 
+/* The type returned by overlay exportfs ops when encoding an ovl_fh handle */
+#define OVL_FILEID     0xfb
+
 /* On-disk and in-memeory format for redirect by file handle */
 struct ovl_fh {
        u8 version;     /* 0 */
@@ -351,3 +354,6 @@ int ovl_set_attr(struct dentry *upper, struct kstat *stat);
 struct ovl_fh *ovl_encode_fh(struct dentry *real, bool is_upper);
 int ovl_set_origin(struct dentry *dentry, struct dentry *lower,
                   struct dentry *upper);
+
+/* export.c */
+extern const struct export_operations ovl_export_operations;