[RFC PATCH v2 5/6] fuse: factor out NFS export related code

Luis Henriques posted 6 patches 2 days, 6 hours ago
[RFC PATCH v2 5/6] fuse: factor out NFS export related code
Posted by Luis Henriques 2 days, 6 hours ago
Move all the NFS-related code into a different file.  This is just
preparatory work to be able to use the LOOKUP_HANDLE file handles as the NFS
handles.

Signed-off-by: Luis Henriques <luis@igalia.com>
---
 fs/fuse/Makefile |   2 +-
 fs/fuse/dir.c    |   1 +
 fs/fuse/export.c | 174 +++++++++++++++++++++++++++++++++++++++++++++++
 fs/fuse/fuse_i.h |   6 ++
 fs/fuse/inode.c  | 167 +--------------------------------------------
 5 files changed, 183 insertions(+), 167 deletions(-)
 create mode 100644 fs/fuse/export.c

diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile
index 22ad9538dfc4..1d1401658278 100644
--- a/fs/fuse/Makefile
+++ b/fs/fuse/Makefile
@@ -12,7 +12,7 @@ obj-$(CONFIG_VIRTIO_FS) += virtiofs.o
 
 fuse-y := trace.o	# put trace.o first so we see ftrace errors sooner
 fuse-y += dev.o dir.o file.o inode.o control.o xattr.o acl.o readdir.o ioctl.o
-fuse-y += iomode.o
+fuse-y += iomode.o export.o
 fuse-$(CONFIG_FUSE_DAX) += dax.o
 fuse-$(CONFIG_FUSE_PASSTHROUGH) += passthrough.o backing.o
 fuse-$(CONFIG_SYSCTL) += sysctl.o
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index a6edb444180f..a885f1dc61eb 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -190,6 +190,7 @@ static void fuse_lookup_init(struct fuse_conn *fc, struct fuse_args *args,
 
 		args->opcode = FUSE_LOOKUP_HANDLE;
 		args->out_argvar = true;
+		args->out_argvar_idx = 0;
 
 		if (dir)
 			fi = get_fuse_inode(dir);
diff --git a/fs/fuse/export.c b/fs/fuse/export.c
new file mode 100644
index 000000000000..4a9c95fe578e
--- /dev/null
+++ b/fs/fuse/export.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * FUSE NFS export support.
+ *
+ * Copyright (C) 2001-2008  Miklos Szeredi <miklos@szeredi.hu>
+ */
+
+#include "fuse_i.h"
+#include <linux/exportfs.h>
+
+struct fuse_inode_handle {
+	u64 nodeid;
+	u32 generation;
+};
+
+static struct dentry *fuse_get_dentry(struct super_block *sb,
+				      struct fuse_inode_handle *handle)
+{
+	struct fuse_conn *fc = get_fuse_conn_super(sb);
+	struct inode *inode;
+	struct dentry *entry;
+	int err = -ESTALE;
+
+	if (handle->nodeid == 0)
+		goto out_err;
+
+	inode = ilookup5(sb, handle->nodeid, fuse_inode_eq, &handle->nodeid);
+	if (!inode) {
+		struct fuse_entry_out *outarg;
+		const struct qstr name = QSTR_INIT(".", 1);
+
+		if (!fc->export_support)
+			goto out_err;
+
+		outarg = fuse_entry_out_alloc(fc);
+		if (!outarg) {
+			err = -ENOMEM;
+			goto out_err;
+		}
+
+		err = fuse_lookup_name(sb, handle->nodeid, NULL, &name, outarg,
+				       &inode);
+		kfree(outarg);
+		if (err && err != -ENOENT)
+			goto out_err;
+		if (err || !inode) {
+			err = -ESTALE;
+			goto out_err;
+		}
+		err = -EIO;
+		if (get_node_id(inode) != handle->nodeid)
+			goto out_iput;
+	}
+	err = -ESTALE;
+	if (inode->i_generation != handle->generation)
+		goto out_iput;
+
+	entry = d_obtain_alias(inode);
+	if (!IS_ERR(entry) && get_node_id(inode) != FUSE_ROOT_ID)
+		fuse_invalidate_entry_cache(entry);
+
+	return entry;
+
+ out_iput:
+	iput(inode);
+ out_err:
+	return ERR_PTR(err);
+}
+
+static int fuse_encode_fh(struct inode *inode, u32 *fh, int *max_len,
+			   struct inode *parent)
+{
+	int len = parent ? 6 : 3;
+	u64 nodeid;
+	u32 generation;
+
+	if (*max_len < len) {
+		*max_len = len;
+		return  FILEID_INVALID;
+	}
+
+	nodeid = get_fuse_inode(inode)->nodeid;
+	generation = inode->i_generation;
+
+	fh[0] = (u32)(nodeid >> 32);
+	fh[1] = (u32)(nodeid & 0xffffffff);
+	fh[2] = generation;
+
+	if (parent) {
+		nodeid = get_fuse_inode(parent)->nodeid;
+		generation = parent->i_generation;
+
+		fh[3] = (u32)(nodeid >> 32);
+		fh[4] = (u32)(nodeid & 0xffffffff);
+		fh[5] = generation;
+	}
+
+	*max_len = len;
+	return parent ? FILEID_INO64_GEN_PARENT : FILEID_INO64_GEN;
+}
+
+static struct dentry *fuse_fh_to_dentry(struct super_block *sb,
+		struct fid *fid, int fh_len, int fh_type)
+{
+	struct fuse_inode_handle handle;
+
+	if ((fh_type != FILEID_INO64_GEN &&
+	     fh_type != FILEID_INO64_GEN_PARENT) || fh_len < 3)
+		return NULL;
+
+	handle.nodeid = (u64) fid->raw[0] << 32;
+	handle.nodeid |= (u64) fid->raw[1];
+	handle.generation = fid->raw[2];
+	return fuse_get_dentry(sb, &handle);
+}
+
+static struct dentry *fuse_fh_to_parent(struct super_block *sb,
+		struct fid *fid, int fh_len, int fh_type)
+{
+	struct fuse_inode_handle parent;
+
+	if (fh_type != FILEID_INO64_GEN_PARENT || fh_len < 6)
+		return NULL;
+
+	parent.nodeid = (u64) fid->raw[3] << 32;
+	parent.nodeid |= (u64) fid->raw[4];
+	parent.generation = fid->raw[5];
+	return fuse_get_dentry(sb, &parent);
+}
+
+static struct dentry *fuse_get_parent(struct dentry *child)
+{
+	struct inode *child_inode = d_inode(child);
+	struct fuse_conn *fc = get_fuse_conn(child_inode);
+	struct inode *inode;
+	struct dentry *parent;
+	struct fuse_entry_out *outarg;
+	int err;
+
+	if (!fc->export_support)
+		return ERR_PTR(-ESTALE);
+
+	outarg = fuse_entry_out_alloc(fc);
+	if (!outarg)
+		return ERR_PTR(-ENOMEM);
+
+	err = fuse_lookup_name(child_inode->i_sb, get_node_id(child_inode),
+			       child_inode, &dotdot_name, outarg, &inode);
+	kfree(outarg);
+	if (err) {
+		if (err == -ENOENT)
+			return ERR_PTR(-ESTALE);
+		return ERR_PTR(err);
+	}
+
+	parent = d_obtain_alias(inode);
+	if (!IS_ERR(parent) && get_node_id(inode) != FUSE_ROOT_ID)
+		fuse_invalidate_entry_cache(parent);
+
+	return parent;
+}
+
+/* only for fid encoding; no support for file handle */
+const struct export_operations fuse_export_fid_operations = {
+	.encode_fh	= fuse_encode_fh,
+};
+
+const struct export_operations fuse_export_operations = {
+	.fh_to_dentry	= fuse_fh_to_dentry,
+	.fh_to_parent	= fuse_fh_to_parent,
+	.encode_fh	= fuse_encode_fh,
+	.get_parent	= fuse_get_parent,
+};
+
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index d0f3c81b5612..b6afd909c857 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -1164,6 +1164,8 @@ extern const struct file_operations fuse_dev_operations;
 
 extern const struct dentry_operations fuse_dentry_operations;
 
+extern int fuse_inode_eq(struct inode *inode, void *_nodeidp);
+
 /**
  * Get a filled in inode
  */
@@ -1647,4 +1649,8 @@ extern void fuse_sysctl_unregister(void);
 #define fuse_sysctl_unregister()	do { } while (0)
 #endif /* CONFIG_SYSCTL */
 
+/* export.c */
+extern const struct export_operations fuse_export_operations;
+extern const struct export_operations fuse_export_fid_operations;
+
 #endif /* _FS_FUSE_I_H */
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index f565f7e8118d..60715d6476c9 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -23,7 +23,6 @@
 #include <linux/statfs.h>
 #include <linux/random.h>
 #include <linux/sched.h>
-#include <linux/exportfs.h>
 #include <linux/posix_acl.h>
 #include <linux/pid_namespace.h>
 #include <uapi/linux/magic.h>
@@ -476,7 +475,7 @@ static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr,
 		inode->i_acl = inode->i_default_acl = ACL_DONT_CACHE;
 }
 
-static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
+int fuse_inode_eq(struct inode *inode, void *_nodeidp)
 {
 	u64 nodeid = *(u64 *) _nodeidp;
 	if (get_node_id(inode) == nodeid)
@@ -1116,170 +1115,6 @@ static struct inode *fuse_get_root_inode(struct super_block *sb, unsigned int mo
 	return fuse_iget(sb, FUSE_ROOT_ID, 0, &attr, 0, 0, 0, NULL); // XXX
 }
 
-struct fuse_inode_handle {
-	u64 nodeid;
-	u32 generation;
-};
-
-static struct dentry *fuse_get_dentry(struct super_block *sb,
-				      struct fuse_inode_handle *handle)
-{
-	struct fuse_conn *fc = get_fuse_conn_super(sb);
-	struct inode *inode;
-	struct dentry *entry;
-	int err = -ESTALE;
-
-	if (handle->nodeid == 0)
-		goto out_err;
-
-	inode = ilookup5(sb, handle->nodeid, fuse_inode_eq, &handle->nodeid);
-	if (!inode) {
-		struct fuse_entry_out *outarg;
-		const struct qstr name = QSTR_INIT(".", 1);
-
-		if (!fc->export_support)
-			goto out_err;
-
-		outarg = fuse_entry_out_alloc(fc);
-		if (!outarg) {
-			err = -ENOMEM;
-			goto out_err;
-		}
-
-		err = fuse_lookup_name(sb, handle->nodeid, NULL, &name, outarg,
-				       &inode);
-		kfree(outarg);
-		if (err && err != -ENOENT)
-			goto out_err;
-		if (err || !inode) {
-			err = -ESTALE;
-			goto out_err;
-		}
-		err = -EIO;
-		if (get_node_id(inode) != handle->nodeid)
-			goto out_iput;
-	}
-	err = -ESTALE;
-	if (inode->i_generation != handle->generation)
-		goto out_iput;
-
-	entry = d_obtain_alias(inode);
-	if (!IS_ERR(entry) && get_node_id(inode) != FUSE_ROOT_ID)
-		fuse_invalidate_entry_cache(entry);
-
-	return entry;
-
- out_iput:
-	iput(inode);
- out_err:
-	return ERR_PTR(err);
-}
-
-static int fuse_encode_fh(struct inode *inode, u32 *fh, int *max_len,
-			   struct inode *parent)
-{
-	int len = parent ? 6 : 3;
-	u64 nodeid;
-	u32 generation;
-
-	if (*max_len < len) {
-		*max_len = len;
-		return  FILEID_INVALID;
-	}
-
-	nodeid = get_fuse_inode(inode)->nodeid;
-	generation = inode->i_generation;
-
-	fh[0] = (u32)(nodeid >> 32);
-	fh[1] = (u32)(nodeid & 0xffffffff);
-	fh[2] = generation;
-
-	if (parent) {
-		nodeid = get_fuse_inode(parent)->nodeid;
-		generation = parent->i_generation;
-
-		fh[3] = (u32)(nodeid >> 32);
-		fh[4] = (u32)(nodeid & 0xffffffff);
-		fh[5] = generation;
-	}
-
-	*max_len = len;
-	return parent ? FILEID_INO64_GEN_PARENT : FILEID_INO64_GEN;
-}
-
-static struct dentry *fuse_fh_to_dentry(struct super_block *sb,
-		struct fid *fid, int fh_len, int fh_type)
-{
-	struct fuse_inode_handle handle;
-
-	if ((fh_type != FILEID_INO64_GEN &&
-	     fh_type != FILEID_INO64_GEN_PARENT) || fh_len < 3)
-		return NULL;
-
-	handle.nodeid = (u64) fid->raw[0] << 32;
-	handle.nodeid |= (u64) fid->raw[1];
-	handle.generation = fid->raw[2];
-	return fuse_get_dentry(sb, &handle);
-}
-
-static struct dentry *fuse_fh_to_parent(struct super_block *sb,
-		struct fid *fid, int fh_len, int fh_type)
-{
-	struct fuse_inode_handle parent;
-
-	if (fh_type != FILEID_INO64_GEN_PARENT || fh_len < 6)
-		return NULL;
-
-	parent.nodeid = (u64) fid->raw[3] << 32;
-	parent.nodeid |= (u64) fid->raw[4];
-	parent.generation = fid->raw[5];
-	return fuse_get_dentry(sb, &parent);
-}
-
-static struct dentry *fuse_get_parent(struct dentry *child)
-{
-	struct inode *child_inode = d_inode(child);
-	struct fuse_conn *fc = get_fuse_conn(child_inode);
-	struct inode *inode;
-	struct dentry *parent;
-	struct fuse_entry_out *outarg;
-	int err;
-
-	if (!fc->export_support)
-		return ERR_PTR(-ESTALE);
-
-	outarg = fuse_entry_out_alloc(fc);
-	if (!outarg)
-		return ERR_PTR(-ENOMEM);
-
-	err = fuse_lookup_name(child_inode->i_sb, get_node_id(child_inode),
-			       child_inode, &dotdot_name, outarg, &inode);
-	kfree(outarg);
-	if (err) {
-		if (err == -ENOENT)
-			return ERR_PTR(-ESTALE);
-		return ERR_PTR(err);
-	}
-
-	parent = d_obtain_alias(inode);
-	if (!IS_ERR(parent) && get_node_id(inode) != FUSE_ROOT_ID)
-		fuse_invalidate_entry_cache(parent);
-
-	return parent;
-}
-
-/* only for fid encoding; no support for file handle */
-static const struct export_operations fuse_export_fid_operations = {
-	.encode_fh	= fuse_encode_fh,
-};
-
-static const struct export_operations fuse_export_operations = {
-	.fh_to_dentry	= fuse_fh_to_dentry,
-	.fh_to_parent	= fuse_fh_to_parent,
-	.encode_fh	= fuse_encode_fh,
-	.get_parent	= fuse_get_parent,
-};
-
 static const struct super_operations fuse_super_operations = {
 	.alloc_inode    = fuse_alloc_inode,
 	.free_inode     = fuse_free_inode,
Re: [RFC PATCH v2 5/6] fuse: factor out NFS export related code
Posted by Amir Goldstein 9 hours ago
On Fri, Dec 12, 2025 at 7:13 PM Luis Henriques <luis@igalia.com> wrote:
>
> Move all the NFS-related code into a different file.  This is just
> preparatory work to be able to use the LOOKUP_HANDLE file handles as the NFS
> handles.
>
> Signed-off-by: Luis Henriques <luis@igalia.com>

Very nice.
Apart from minor nit below, feel free to add:

Reviewed-by: Amir Goldstein <amir73il@gmail.com>

> ---
>  fs/fuse/Makefile |   2 +-
>  fs/fuse/dir.c    |   1 +
>  fs/fuse/export.c | 174 +++++++++++++++++++++++++++++++++++++++++++++++
>  fs/fuse/fuse_i.h |   6 ++
>  fs/fuse/inode.c  | 167 +--------------------------------------------
>  5 files changed, 183 insertions(+), 167 deletions(-)
>  create mode 100644 fs/fuse/export.c
>
> diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile
> index 22ad9538dfc4..1d1401658278 100644
> --- a/fs/fuse/Makefile
> +++ b/fs/fuse/Makefile
> @@ -12,7 +12,7 @@ obj-$(CONFIG_VIRTIO_FS) += virtiofs.o
>
>  fuse-y := trace.o      # put trace.o first so we see ftrace errors sooner
>  fuse-y += dev.o dir.o file.o inode.o control.o xattr.o acl.o readdir.o ioctl.o
> -fuse-y += iomode.o
> +fuse-y += iomode.o export.o
>  fuse-$(CONFIG_FUSE_DAX) += dax.o
>  fuse-$(CONFIG_FUSE_PASSTHROUGH) += passthrough.o backing.o
>  fuse-$(CONFIG_SYSCTL) += sysctl.o
> diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
> index a6edb444180f..a885f1dc61eb 100644
> --- a/fs/fuse/dir.c
> +++ b/fs/fuse/dir.c
> @@ -190,6 +190,7 @@ static void fuse_lookup_init(struct fuse_conn *fc, struct fuse_args *args,
>
>                 args->opcode = FUSE_LOOKUP_HANDLE;
>                 args->out_argvar = true;
> +               args->out_argvar_idx = 0;
>

This change looks out of place.

Keep in mind that it may take me some time to get to the rest of the patches,
but this one was a low hanging review.

Thanks,
Amir.