erofs: make filesystem exportable
authorHongnan Li <hongnan.li@linux.alibaba.com>
Mon, 25 Apr 2022 04:07:12 +0000 (12:07 +0800)
committerGao Xiang <hsiangkao@linux.alibaba.com>
Tue, 17 May 2022 15:48:54 +0000 (23:48 +0800)
Implement export operations in order to make EROFS support accessing
inodes with filehandles so that it can be exported via NFS and used
by overlayfs.

Without this patch, 'exportfs -rv' will report:
exportfs: /root/erofs_mp does not support NFS export

Also tested with unionmount-testsuite and the testcase below passes now:
./run --ov --erofs --verify hard-link

For more details about the testcase, see:
https://github.com/amir73il/unionmount-testsuite/pull/6

Signed-off-by: Hongnan Li <hongnan.li@linux.alibaba.com>
Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Link: https://lore.kernel.org/r/20220425040712.91685-1-hongnan.li@linux.alibaba.com
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
fs/erofs/internal.h
fs/erofs/namei.c
fs/erofs/super.c

index 39eb48c..df0c05c 100644 (file)
@@ -484,7 +484,7 @@ int erofs_getattr(struct user_namespace *mnt_userns, const struct path *path,
 /* namei.c */
 extern const struct inode_operations erofs_dir_iops;
 
-int erofs_namei(struct inode *dir, struct qstr *name,
+int erofs_namei(struct inode *dir, const struct qstr *name,
                erofs_nid_t *nid, unsigned int *d_type);
 
 /* dir.c */
index 554efa3..fd75506 100644 (file)
@@ -165,9 +165,8 @@ out:                /* free if the candidate is valid */
        return candidate;
 }
 
-int erofs_namei(struct inode *dir,
-               struct qstr *name,
-               erofs_nid_t *nid, unsigned int *d_type)
+int erofs_namei(struct inode *dir, const struct qstr *name, erofs_nid_t *nid,
+               unsigned int *d_type)
 {
        int ndirents;
        struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
index 0c4b411..dbfe2cb 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/fs_context.h>
 #include <linux/fs_parser.h>
 #include <linux/dax.h>
+#include <linux/exportfs.h>
 #include "xattr.h"
 
 #define CREATE_TRACE_POINTS
@@ -577,6 +578,44 @@ static int erofs_init_managed_cache(struct super_block *sb)
 static int erofs_init_managed_cache(struct super_block *sb) { return 0; }
 #endif
 
+static struct inode *erofs_nfs_get_inode(struct super_block *sb,
+                                        u64 ino, u32 generation)
+{
+       return erofs_iget(sb, ino, false);
+}
+
+static struct dentry *erofs_fh_to_dentry(struct super_block *sb,
+               struct fid *fid, int fh_len, int fh_type)
+{
+       return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
+                                   erofs_nfs_get_inode);
+}
+
+static struct dentry *erofs_fh_to_parent(struct super_block *sb,
+               struct fid *fid, int fh_len, int fh_type)
+{
+       return generic_fh_to_parent(sb, fid, fh_len, fh_type,
+                                   erofs_nfs_get_inode);
+}
+
+static struct dentry *erofs_get_parent(struct dentry *child)
+{
+       erofs_nid_t nid;
+       unsigned int d_type;
+       int err;
+
+       err = erofs_namei(d_inode(child), &dotdot_name, &nid, &d_type);
+       if (err)
+               return ERR_PTR(err);
+       return d_obtain_alias(erofs_iget(child->d_sb, nid, d_type == FT_DIR));
+}
+
+static const struct export_operations erofs_export_ops = {
+       .fh_to_dentry = erofs_fh_to_dentry,
+       .fh_to_parent = erofs_fh_to_parent,
+       .get_parent = erofs_get_parent,
+};
+
 static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc)
 {
        struct inode *inode;
@@ -619,6 +658,7 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc)
 
        sb->s_op = &erofs_sops;
        sb->s_xattr = erofs_xattr_handlers;
+       sb->s_export_op = &erofs_export_ops;
 
        if (test_opt(&sbi->opt, POSIX_ACL))
                sb->s_flags |= SB_POSIXACL;