Skip to content

Commit

Permalink
netfs: Add a netfs inode context
Browse files Browse the repository at this point in the history
Add a netfs_i_context struct that should be included in the network
filesystem's own inode struct wrapper, directly after the VFS's inode
struct, e.g.:

	struct my_inode {
		struct {
			/* These must be contiguous */
			struct inode		vfs_inode;
			struct netfs_i_context	netfs_ctx;
		};
	};

The netfs_i_context struct so far contains a single field for the network
filesystem to use - the cache cookie:

	struct netfs_i_context {
		...
		struct fscache_cookie	*cache;
	};

Three functions are provided to help with this:

 (1) void netfs_i_context_init(struct inode *inode,
			       const struct netfs_request_ops *ops);

     Initialise the netfs context and set the operations.

 (2) struct netfs_i_context *netfs_i_context(struct inode *inode);

     Find the netfs context from the VFS inode.

 (3) struct inode *netfs_inode(struct netfs_i_context *ctx);

     Find the VFS inode from the netfs context.

Changes
=======
ver #4)
 - Fix netfs_is_cache_enabled() to check cookie->cache_priv to see if a
   cache is present[3].
 - Fix netfs_skip_folio_read() to zero out all of the page, not just some
   of it[3].

ver #3)
 - Split out the bit to move ceph cap-getting on readahead into
   ceph_init_request()[1].
 - Stick in a comment to the netfs inode structs indicating the contiguity
   requirements[2].

ver #2)
 - Adjust documentation to match.
 - Use "#if IS_ENABLED()" in netfs_i_cookie(), not "#ifdef".
 - Move the cap check from ceph_readahead() to ceph_init_request() to be
   called from netfslib.
 - Remove ceph_readahead() and use  netfs_readahead() directly instead.

Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Jeff Layton <jlayton@kernel.org>
cc: linux-cachefs@redhat.com

Link: https://lore.kernel.org/r/8af0d47f17d89c06bbf602496dd845f2b0bf25b3.camel@kernel.org/ [1]
Link: https://lore.kernel.org/r/beaf4f6a6c2575ed489adb14b257253c868f9a5c.camel@kernel.org/ [2]
Link: https://lore.kernel.org/r/3536452.1647421585@warthog.procyon.org.uk/ [3]
Link: https://lore.kernel.org/r/164622984545.3564931.15691742939278418580.stgit@warthog.procyon.org.uk/ # v1
Link: https://lore.kernel.org/r/164678213320.1200972.16807551936267647470.stgit@warthog.procyon.org.uk/ # v2
Link: https://lore.kernel.org/r/164692909854.2099075.9535537286264248057.stgit@warthog.procyon.org.uk/ # v3
Link: https://lore.kernel.org/r/306388.1647595110@warthog.procyon.org.uk/ # v4
  • Loading branch information
dhowells committed Mar 18, 2022
1 parent a5c9dc4 commit bc899ee
Show file tree
Hide file tree
Showing 25 changed files with 318 additions and 278 deletions.
101 changes: 72 additions & 29 deletions Documentation/filesystems/netfs_library.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Network Filesystem Helper Library
.. Contents:
- Overview.
- Per-inode context.
- Inode context helper functions.
- Buffered read helpers.
- Read helper functions.
- Read helper structures.
Expand All @@ -28,6 +30,69 @@ Note that the library module doesn't link against local caching directly, so
access must be provided by the netfs.


Per-Inode Context
=================

The network filesystem helper library needs a place to store a bit of state for
its use on each netfs inode it is helping to manage. To this end, a context
structure is defined::

struct netfs_i_context {
const struct netfs_request_ops *ops;
struct fscache_cookie *cache;
};

A network filesystem that wants to use netfs lib must place one of these
directly after the VFS ``struct inode`` it allocates, usually as part of its
own struct. This can be done in a way similar to the following::

struct my_inode {
struct {
/* These must be contiguous */
struct inode vfs_inode;
struct netfs_i_context netfs_ctx;
};
...
};

This allows netfslib to find its state by simple offset from the inode pointer,
thereby allowing the netfslib helper functions to be pointed to directly by the
VFS/VM operation tables.

The structure contains the following fields:

* ``ops``

The set of operations provided by the network filesystem to netfslib.

* ``cache``

Local caching cookie, or NULL if no caching is enabled. This field does not
exist if fscache is disabled.


Inode Context Helper Functions
------------------------------

To help deal with the per-inode context, a number helper functions are
provided. Firstly, a function to perform basic initialisation on a context and
set the operations table pointer::

void netfs_i_context_init(struct inode *inode,
const struct netfs_request_ops *ops);

then two functions to cast between the VFS inode structure and the netfs
context::

struct netfs_i_context *netfs_i_context(struct inode *inode);
struct inode *netfs_inode(struct netfs_i_context *ctx);

and finally, a function to get the cache cookie pointer from the context
attached to an inode (or NULL if fscache is disabled)::

struct fscache_cookie *netfs_i_cookie(struct inode *inode);


Buffered Read Helpers
=====================

Expand Down Expand Up @@ -70,38 +135,22 @@ Read Helper Functions

Three read helpers are provided::

void netfs_readahead(struct readahead_control *ractl,
const struct netfs_request_ops *ops,
void *netfs_priv);
void netfs_readahead(struct readahead_control *ractl);
int netfs_readpage(struct file *file,
struct folio *folio,
const struct netfs_request_ops *ops,
void *netfs_priv);
struct page *page);
int netfs_write_begin(struct file *file,
struct address_space *mapping,
loff_t pos,
unsigned int len,
unsigned int flags,
struct folio **_folio,
void **_fsdata,
const struct netfs_request_ops *ops,
void *netfs_priv);

Each corresponds to a VM operation, with the addition of a couple of parameters
for the use of the read helpers:
void **_fsdata);

* ``ops``

A table of operations through which the helpers can talk to the filesystem.

* ``netfs_priv``
Each corresponds to a VM address space operation. These operations use the
state in the per-inode context.

Filesystem private data (can be NULL).

Both of these values will be stored into the read request structure.

For ->readahead() and ->readpage(), the network filesystem should just jump
into the corresponding read helper; whereas for ->write_begin(), it may be a
For ->readahead() and ->readpage(), the network filesystem just point directly
at the corresponding read helper; whereas for ->write_begin(), it may be a
little more complicated as the network filesystem might want to flush
conflicting writes or track dirty data and needs to put the acquired folio if
an error occurs after calling the helper.
Expand Down Expand Up @@ -246,7 +295,6 @@ through which it can issue requests and negotiate::

struct netfs_request_ops {
void (*init_request)(struct netfs_io_request *rreq, struct file *file);
bool (*is_cache_enabled)(struct inode *inode);
int (*begin_cache_operation)(struct netfs_io_request *rreq);
void (*expand_readahead)(struct netfs_io_request *rreq);
bool (*clamp_length)(struct netfs_io_subrequest *subreq);
Expand All @@ -265,11 +313,6 @@ The operations are as follows:
[Optional] This is called to initialise the request structure. It is given
the file for reference and can modify the ->netfs_priv value.

* ``is_cache_enabled()``

[Required] This is called by netfs_write_begin() to ask if the file is being
cached. It should return true if it is being cached and false otherwise.

* ``begin_cache_operation()``

[Optional] This is called to ask the network filesystem to call into the
Expand Down
10 changes: 4 additions & 6 deletions fs/9p/cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,28 +49,26 @@ int v9fs_cache_session_get_cookie(struct v9fs_session_info *v9ses,

void v9fs_cache_inode_get_cookie(struct inode *inode)
{
struct v9fs_inode *v9inode;
struct v9fs_inode *v9inode = V9FS_I(inode);
struct v9fs_session_info *v9ses;
__le32 version;
__le64 path;

if (!S_ISREG(inode->i_mode))
return;

v9inode = V9FS_I(inode);
if (WARN_ON(v9inode->fscache))
if (WARN_ON(v9fs_inode_cookie(v9inode)))
return;

version = cpu_to_le32(v9inode->qid.version);
path = cpu_to_le64(v9inode->qid.path);
v9ses = v9fs_inode2v9ses(inode);
v9inode->fscache =
v9inode->netfs_ctx.cache =
fscache_acquire_cookie(v9fs_session_cache(v9ses),
0,
&path, sizeof(path),
&version, sizeof(version),
i_size_read(&v9inode->vfs_inode));

p9_debug(P9_DEBUG_FSC, "inode %p get cookie %p\n",
inode, v9inode->fscache);
inode, v9fs_inode_cookie(v9inode));
}
4 changes: 1 addition & 3 deletions fs/9p/v9fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -623,9 +623,7 @@ static void v9fs_sysfs_cleanup(void)
static void v9fs_inode_init_once(void *foo)
{
struct v9fs_inode *v9inode = (struct v9fs_inode *)foo;
#ifdef CONFIG_9P_FSCACHE
v9inode->fscache = NULL;
#endif

memset(&v9inode->qid, 0, sizeof(v9inode->qid));
inode_init_once(&v9inode->vfs_inode);
}
Expand Down
13 changes: 8 additions & 5 deletions fs/9p/v9fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#define FS_9P_V9FS_H

#include <linux/backing-dev.h>
#include <linux/netfs.h>

/**
* enum p9_session_flags - option flags for each 9P session
Expand Down Expand Up @@ -108,14 +109,15 @@ struct v9fs_session_info {
#define V9FS_INO_INVALID_ATTR 0x01

struct v9fs_inode {
#ifdef CONFIG_9P_FSCACHE
struct fscache_cookie *fscache;
#endif
struct {
/* These must be contiguous */
struct inode vfs_inode; /* the VFS's inode record */
struct netfs_i_context netfs_ctx; /* Netfslib context */
};
struct p9_qid qid;
unsigned int cache_validity;
struct p9_fid *writeback_fid;
struct mutex v_mutex;
struct inode vfs_inode;
};

static inline struct v9fs_inode *V9FS_I(const struct inode *inode)
Expand All @@ -126,7 +128,7 @@ static inline struct v9fs_inode *V9FS_I(const struct inode *inode)
static inline struct fscache_cookie *v9fs_inode_cookie(struct v9fs_inode *v9inode)
{
#ifdef CONFIG_9P_FSCACHE
return v9inode->fscache;
return netfs_i_cookie(&v9inode->vfs_inode);
#else
return NULL;
#endif
Expand Down Expand Up @@ -163,6 +165,7 @@ extern struct inode *v9fs_inode_from_fid(struct v9fs_session_info *v9ses,
extern const struct inode_operations v9fs_dir_inode_operations_dotl;
extern const struct inode_operations v9fs_file_inode_operations_dotl;
extern const struct inode_operations v9fs_symlink_inode_operations_dotl;
extern const struct netfs_request_ops v9fs_req_ops;
extern struct inode *v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses,
struct p9_fid *fid,
struct super_block *sb, int new);
Expand Down
43 changes: 4 additions & 39 deletions fs/9p/vfs_addr.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,6 @@ static void v9fs_req_cleanup(struct address_space *mapping, void *priv)
p9_client_clunk(fid);
}

/**
* v9fs_is_cache_enabled - Determine if caching is enabled for an inode
* @inode: The inode to check
*/
static bool v9fs_is_cache_enabled(struct inode *inode)
{
struct fscache_cookie *cookie = v9fs_inode_cookie(V9FS_I(inode));

return fscache_cookie_enabled(cookie) && cookie->cache_priv;
}

/**
* v9fs_begin_cache_operation - Begin a cache operation for a read
* @rreq: The read request
Expand All @@ -103,36 +92,13 @@ static int v9fs_begin_cache_operation(struct netfs_io_request *rreq)
#endif
}

static const struct netfs_request_ops v9fs_req_ops = {
const struct netfs_request_ops v9fs_req_ops = {
.init_request = v9fs_init_request,
.is_cache_enabled = v9fs_is_cache_enabled,
.begin_cache_operation = v9fs_begin_cache_operation,
.issue_read = v9fs_issue_read,
.cleanup = v9fs_req_cleanup,
};

/**
* v9fs_vfs_readpage - read an entire page in from 9P
* @file: file being read
* @page: structure to page
*
*/
static int v9fs_vfs_readpage(struct file *file, struct page *page)
{
struct folio *folio = page_folio(page);

return netfs_readpage(file, folio, &v9fs_req_ops, NULL);
}

/**
* v9fs_vfs_readahead - read a set of pages from 9P
* @ractl: The readahead parameters
*/
static void v9fs_vfs_readahead(struct readahead_control *ractl)
{
netfs_readahead(ractl, &v9fs_req_ops, NULL);
}

/**
* v9fs_release_page - release the private state associated with a page
* @page: The page to be released
Expand Down Expand Up @@ -326,8 +292,7 @@ static int v9fs_write_begin(struct file *filp, struct address_space *mapping,
* file. We need to do this before we get a lock on the page in case
* there's more than one writer competing for the same cache block.
*/
retval = netfs_write_begin(filp, mapping, pos, len, flags, &folio, fsdata,
&v9fs_req_ops, NULL);
retval = netfs_write_begin(filp, mapping, pos, len, flags, &folio, fsdata);
if (retval < 0)
return retval;

Expand Down Expand Up @@ -388,8 +353,8 @@ static int v9fs_set_page_dirty(struct page *page)
#endif

const struct address_space_operations v9fs_addr_operations = {
.readpage = v9fs_vfs_readpage,
.readahead = v9fs_vfs_readahead,
.readpage = netfs_readpage,
.readahead = netfs_readahead,
.set_page_dirty = v9fs_set_page_dirty,
.writepage = v9fs_vfs_writepage,
.write_begin = v9fs_write_begin,
Expand Down
13 changes: 10 additions & 3 deletions fs/9p/vfs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,6 @@ struct inode *v9fs_alloc_inode(struct super_block *sb)
v9inode = kmem_cache_alloc(v9fs_inode_cache, GFP_KERNEL);
if (!v9inode)
return NULL;
#ifdef CONFIG_9P_FSCACHE
v9inode->fscache = NULL;
#endif
v9inode->writeback_fid = NULL;
v9inode->cache_validity = 0;
mutex_init(&v9inode->v_mutex);
Expand All @@ -250,6 +247,14 @@ void v9fs_free_inode(struct inode *inode)
kmem_cache_free(v9fs_inode_cache, V9FS_I(inode));
}

/*
* Set parameters for the netfs library
*/
static void v9fs_set_netfs_context(struct inode *inode)
{
netfs_i_context_init(inode, &v9fs_req_ops);
}

int v9fs_init_inode(struct v9fs_session_info *v9ses,
struct inode *inode, umode_t mode, dev_t rdev)
{
Expand Down Expand Up @@ -338,6 +343,8 @@ int v9fs_init_inode(struct v9fs_session_info *v9ses,
err = -EINVAL;
goto error;
}

v9fs_set_netfs_context(inode);
error:
return err;

Expand Down
1 change: 1 addition & 0 deletions fs/afs/dynroot.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ struct inode *afs_iget_pseudo_dir(struct super_block *sb, bool root)
/* there shouldn't be an existing inode */
BUG_ON(!(inode->i_state & I_NEW));

netfs_i_context_init(inode, NULL);
inode->i_size = 0;
inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
if (root) {
Expand Down
Loading

0 comments on commit bc899ee

Please sign in to comment.