The logic of dentries expiring after 2 seconds can be useful elsewhere
as well, so factor this out as seed for a new netfs lib that is going to
be used for 9pfs as well.

Signed-off-by: Ahmad Fatoum <a.fat...@barebox.org>
---
 fs/Kconfig            |  4 +++
 fs/Makefile           |  1 +
 fs/netfs.c            | 25 ++++++++++++++
 fs/tftp.c             | 35 +++++--------------
 include/linux/netfs.h | 78 +++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 116 insertions(+), 27 deletions(-)
 create mode 100644 fs/netfs.c
 create mode 100644 include/linux/netfs.h

diff --git a/fs/Kconfig b/fs/Kconfig
index 01ac3040438d..f94488e643bf 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -19,6 +19,9 @@ config FS_WRITABLE
          invisible option selected by filesystem drivers that can
          write and are not fully read-only.
 
+config NETFS_SUPPORT
+       bool
+
 if FS_LEGACY
 comment "Some selected filesystems still use the legacy FS API."
 comment "Consider updating them."
@@ -51,6 +54,7 @@ config FS_TFTP
        prompt "tftp support"
        depends on NET
        select FS_WRITABLE
+       select NETFS_SUPPORT
 
 config FS_TFTP_MAX_WINDOW_SIZE
        int
diff --git a/fs/Makefile b/fs/Makefile
index 20a26a16c5ab..b6a44ff82a38 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_FS_LEGACY) += legacy.o
 obj-$(CONFIG_FS_DEVFS) += devfs.o
 obj-pbl-$(CONFIG_FS_FAT)       += fat/
 obj-y  += fs.o libfs.o
+obj-$(CONFIG_NETFS_SUPPORT)    += netfs.o
 obj-$(CONFIG_FS_JFFS2) += jffs2/
 obj-$(CONFIG_FS_UBIFS) += ubifs/
 obj-$(CONFIG_FS_TFTP)  += tftp.o
diff --git a/fs/netfs.c b/fs/netfs.c
new file mode 100644
index 000000000000..446377130d61
--- /dev/null
+++ b/fs/netfs.c
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/dcache.h>
+#include <clock.h>
+#include <linux/netfs.h>
+
+
+static int netfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
+{
+       struct netfs_inode *node;
+
+       if (!dentry->d_inode)
+               return 0;
+
+       node = netfs_inode(dentry->d_inode);
+
+       if (is_timeout(node->time, NETFS_INODE_VALID_TIME))
+               return 0;
+
+       return 1;
+}
+
+const struct dentry_operations netfs_dentry_operations_timed = {
+       .d_revalidate = netfs_lookup_revalidate,
+};
diff --git a/fs/tftp.c b/fs/tftp.c
index cf91f66ed88b..5cb71431eb49 100644
--- a/fs/tftp.c
+++ b/fs/tftp.c
@@ -35,6 +35,7 @@
 #include <kfifo.h>
 #include <parseopt.h>
 #include <linux/sizes.h>
+#include <linux/netfs.h>
 
 #include "tftp-selftest.h"
 
@@ -131,13 +132,12 @@ struct tftp_priv {
 };
 
 struct tftp_inode {
-       struct inode inode;
-       u64 time;
+       struct netfs_inode netfs_node;
 };
 
 static struct tftp_inode *to_tftp_inode(struct inode *inode)
 {
-       return container_of(inode, struct tftp_inode, inode);
+       return container_of(inode, struct tftp_inode, netfs_node.inode);
 }
 
 static inline bool is_block_before(uint16_t a, uint16_t b)
@@ -957,12 +957,12 @@ static struct inode *tftp_get_inode(struct super_block 
*sb, const struct inode *
        if (!inode)
                return NULL;
 
-       node = to_tftp_inode(inode);
-       node->time = get_time_ns();
-
        inode->i_ino = get_next_ino();
        inode->i_mode = mode;
 
+       node = to_tftp_inode(inode);
+       netfs_inode_init(&node->netfs_node);
+
        switch (mode & S_IFMT) {
        default:
                return NULL;
@@ -1040,7 +1040,7 @@ static struct inode *tftp_alloc_inode(struct super_block 
*sb)
        if (!node)
                return NULL;
 
-       return &node->inode;
+       return &node->netfs_node.inode;
 }
 
 static void tftp_destroy_inode(struct inode *inode)
@@ -1055,25 +1055,6 @@ static const struct super_operations tftp_ops = {
        .destroy_inode = tftp_destroy_inode,
 };
 
-static int tftp_lookup_revalidate(struct dentry *dentry, unsigned int flags)
-{
-       struct tftp_inode *node;
-
-       if (!dentry->d_inode)
-               return 0;
-
-       node = to_tftp_inode(dentry->d_inode);
-
-       if (is_timeout(node->time, 2 * SECOND))
-               return 0;
-
-       return 1;
-}
-
-static const struct dentry_operations tftp_dentry_operations = {
-       .d_revalidate = tftp_lookup_revalidate,
-};
-
 static int tftp_probe(struct device *dev)
 {
        struct fs_device *fsdev = dev_to_fs_device(dev);
@@ -1091,7 +1072,7 @@ static int tftp_probe(struct device *dev)
        }
 
        sb->s_op = &tftp_ops;
-       sb->s_d_op = &tftp_dentry_operations;
+       sb->s_d_op = &netfs_dentry_operations_timed;
 
        inode = tftp_get_inode(sb, NULL, S_IFDIR);
        sb->s_root = d_make_root(inode);
diff --git a/include/linux/netfs.h b/include/linux/netfs.h
new file mode 100644
index 000000000000..4aa2e2223d4a
--- /dev/null
+++ b/include/linux/netfs.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Network filesystem support services.
+ *
+ * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowe...@redhat.com)
+ *
+ * See:
+ *
+ *     Documentation/filesystems/netfs_library.rst
+ *
+ * for a description of the network filesystem interface declared here.
+ */
+
+#ifndef _LINUX_NETFS_H
+#define _LINUX_NETFS_H
+
+#include <linux/fs.h>
+#include <linux/container_of.h>
+#include <clock.h>
+
+/*
+ * Per-inode context.  This wraps the VFS inode.
+ */
+struct netfs_inode {
+       struct inode            inode;          /* The VFS inode */
+       u64                     time;           /* Time the inode was allocated 
*/
+};
+
+enum netfs_io_origin {
+       NETFS_READPAGE,                 /* This read is a synchronous read */
+       NETFS_WRITETHROUGH,             /* This write was made by 
netfs_perform_write() */
+} __mode(byte);
+
+/*
+ * Descriptor for an I/O helper request.  This is used to make multiple I/O
+ * operations to a variety of data stores and then stitch the result together.
+ */
+struct netfs_io_request {
+       struct inode            *inode;         /* The file being accessed */
+       void                    *netfs_priv;    /* Private data for the netfs */
+       enum netfs_io_origin    origin;         /* Origin of the request */
+};
+
+/**
+ * netfs_inode - Get the netfs inode context from the inode
+ * @inode: The inode to query
+ *
+ * Get the netfs lib inode context from the network filesystem's inode.  The
+ * context struct is expected to directly follow on from the VFS inode struct.
+ */
+static inline struct netfs_inode *netfs_inode(struct inode *inode)
+{
+       return container_of(inode, struct netfs_inode, inode);
+}
+
+/**
+ * netfs_inode_init - Initialise a netfslib inode context
+ * @ctx: The netfs inode to initialise
+ *
+ * Initialise the netfs library context struct.  This is expected to follow on
+ * directly from the VFS inode struct.
+ */
+static inline void netfs_inode_init(struct netfs_inode *ctx)
+{
+       ctx->time = get_time_ns();
+}
+
+#define NETFS_INODE_VALID_TIME         (2 * NSEC_PER_SEC)
+
+static inline void netfs_invalidate_inode_attr(struct netfs_inode *ctx)
+{
+       /* ensure that we always detect the inode to be stale */
+       ctx->time = -NETFS_INODE_VALID_TIME;
+}
+
+extern const struct dentry_operations netfs_dentry_operations_timed;
+
+#endif /* _LINUX_NETFS_H */
-- 
2.39.5


Reply via email to