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