Commit 726218fd authored by David Howells's avatar David Howells

netfs: Define an interface to talk to a cache

Add an interface to the netfs helper library for reading data from the
cache instead of downloading it from the server and support for writing
data just downloaded or cleared to the cache.

The API passes an iov_iter to the cache read/write routines to indicate the
data/buffer to be used.  This is done using the ITER_XARRAY type to provide
direct access to the netfs inode's pagecache.

When the netfs's ->begin_cache_operation() method is called, this must fill
in the cache_resources in the netfs_read_request struct, including the
netfs_cache_ops used by the helper lib to talk to the cache.  The helper
lib does not directly access the cache.

Changes:
v6:
- Call trace_netfs_read() after beginning the cache op so that the cookie
  debug ID can be logged[3].
- Don't record the error from writing to the cache.  We don't want to pass
  it back to the netfs[4].
- Fix copy-to-cache subreq amalgamation to not round up as it goes along
  otherwise it overcalculates the length of the write[5].

v5:
- Use end_page_fscache() rather than unlock_page_fscache()[2].

v4:
- Added flag to netfs_subreq_terminated() to indicate that the caller may
  have been running async and stuff that might sleep needs punting to a
  workqueue (can't use in_softirq()[1]).
- Add missing inc of netfs_n_rh_read stat.
- Move initial definition of fscache_begin_read_operation() elsewhere.
- Need to call op->begin_cache_operation() from netfs_write_begin().
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Reviewed-and-tested-by: default avatarJeff Layton <jlayton@kernel.org>
Tested-by: default avatarDave Wysochanski <dwysocha@redhat.com>
Tested-By: default avatarMarc Dionne <marc.dionne@auristor.com>
cc: Matthew Wilcox <willy@infradead.org>
cc: linux-mm@kvack.org
cc: linux-cachefs@redhat.com
cc: linux-afs@lists.infradead.org
cc: linux-nfs@vger.kernel.org
cc: linux-cifs@vger.kernel.org
cc: ceph-devel@vger.kernel.org
cc: v9fs-developer@lists.sourceforge.net
cc: linux-fsdevel@vger.kernel.org
Link: https://lore.kernel.org/r/20210216084230.GA23669@lst.de/ [1]
Link: https://lore.kernel.org/r/2499407.1616505440@warthog.procyon.org.uk/ [2]
Link: https://lore.kernel.org/r/161781045123.463527.14533348855710902201.stgit@warthog.procyon.org.uk/ [3]
Link: https://lore.kernel.org/r/161781046256.463527.18158681600085556192.stgit@warthog.procyon.org.uk/ [4]
Link: https://lore.kernel.org/r/161781047695.463527.7463536103593997492.stgit@warthog.procyon.org.uk/ [5]
Link: https://lore.kernel.org/r/161118141321.1232039.8296910406755622458.stgit@warthog.procyon.org.uk/ # rfc
Link: https://lore.kernel.org/r/161161036700.2537118.11170748455436854978.stgit@warthog.procyon.org.uk/ # v2
Link: https://lore.kernel.org/r/161340399569.1303470.1138884774643385730.stgit@warthog.procyon.org.uk/ # v3
Link: https://lore.kernel.org/r/161539542874.286939.13337898213448136687.stgit@warthog.procyon.org.uk/ # v4
Link: https://lore.kernel.org/r/161653799826.2770958.9015430297426331950.stgit@warthog.procyon.org.uk/ # v5
Link: https://lore.kernel.org/r/161789081462.6155.3853904866933313256.stgit@warthog.procyon.org.uk/ # v6
parent e1b1240c
This diff is collapsed.
...@@ -92,6 +92,18 @@ enum netfs_read_source { ...@@ -92,6 +92,18 @@ enum netfs_read_source {
NETFS_INVALID_READ, NETFS_INVALID_READ,
} __mode(byte); } __mode(byte);
typedef void (*netfs_io_terminated_t)(void *priv, ssize_t transferred_or_error,
bool was_async);
/*
* Resources required to do operations on a cache.
*/
struct netfs_cache_resources {
const struct netfs_cache_ops *ops;
void *cache_priv;
void *cache_priv2;
};
/* /*
* Descriptor for a single component subrequest. * Descriptor for a single component subrequest.
*/ */
...@@ -121,11 +133,13 @@ struct netfs_read_request { ...@@ -121,11 +133,13 @@ struct netfs_read_request {
struct work_struct work; struct work_struct work;
struct inode *inode; /* The file being accessed */ struct inode *inode; /* The file being accessed */
struct address_space *mapping; /* The mapping being accessed */ struct address_space *mapping; /* The mapping being accessed */
struct netfs_cache_resources cache_resources;
struct list_head subrequests; /* Requests to fetch I/O from disk or net */ struct list_head subrequests; /* Requests to fetch I/O from disk or net */
void *netfs_priv; /* Private data for the netfs */ void *netfs_priv; /* Private data for the netfs */
unsigned int debug_id; unsigned int debug_id;
unsigned int cookie_debug_id; unsigned int cookie_debug_id;
atomic_t nr_rd_ops; /* Number of read ops in progress */ atomic_t nr_rd_ops; /* Number of read ops in progress */
atomic_t nr_wr_ops; /* Number of write ops in progress */
size_t submitted; /* Amount submitted for I/O so far */ size_t submitted; /* Amount submitted for I/O so far */
size_t len; /* Length of the request */ size_t len; /* Length of the request */
short error; /* 0 or error that occurred */ short error; /* 0 or error that occurred */
...@@ -149,6 +163,7 @@ struct netfs_read_request { ...@@ -149,6 +163,7 @@ struct netfs_read_request {
struct netfs_read_request_ops { struct netfs_read_request_ops {
bool (*is_cache_enabled)(struct inode *inode); bool (*is_cache_enabled)(struct inode *inode);
void (*init_rreq)(struct netfs_read_request *rreq, struct file *file); void (*init_rreq)(struct netfs_read_request *rreq, struct file *file);
int (*begin_cache_operation)(struct netfs_read_request *rreq);
void (*expand_readahead)(struct netfs_read_request *rreq); void (*expand_readahead)(struct netfs_read_request *rreq);
bool (*clamp_length)(struct netfs_read_subrequest *subreq); bool (*clamp_length)(struct netfs_read_subrequest *subreq);
void (*issue_op)(struct netfs_read_subrequest *subreq); void (*issue_op)(struct netfs_read_subrequest *subreq);
...@@ -159,6 +174,46 @@ struct netfs_read_request_ops { ...@@ -159,6 +174,46 @@ struct netfs_read_request_ops {
void (*cleanup)(struct address_space *mapping, void *netfs_priv); void (*cleanup)(struct address_space *mapping, void *netfs_priv);
}; };
/*
* Table of operations for access to a cache. This is obtained by
* rreq->ops->begin_cache_operation().
*/
struct netfs_cache_ops {
/* End an operation */
void (*end_operation)(struct netfs_cache_resources *cres);
/* Read data from the cache */
int (*read)(struct netfs_cache_resources *cres,
loff_t start_pos,
struct iov_iter *iter,
bool seek_data,
netfs_io_terminated_t term_func,
void *term_func_priv);
/* Write data to the cache */
int (*write)(struct netfs_cache_resources *cres,
loff_t start_pos,
struct iov_iter *iter,
netfs_io_terminated_t term_func,
void *term_func_priv);
/* Expand readahead request */
void (*expand_readahead)(struct netfs_cache_resources *cres,
loff_t *_start, size_t *_len, loff_t i_size);
/* Prepare a read operation, shortening it to a cached/uncached
* boundary as appropriate.
*/
enum netfs_read_source (*prepare_read)(struct netfs_read_subrequest *subreq,
loff_t i_size);
/* Prepare a write operation, working out what part of the write we can
* actually do.
*/
int (*prepare_write)(struct netfs_cache_resources *cres,
loff_t *_start, size_t *_len, loff_t i_size);
};
struct readahead_control; struct readahead_control;
extern void netfs_readahead(struct readahead_control *, extern void netfs_readahead(struct readahead_control *,
const struct netfs_read_request_ops *, const struct netfs_read_request_ops *,
......
...@@ -43,6 +43,7 @@ enum netfs_sreq_trace { ...@@ -43,6 +43,7 @@ enum netfs_sreq_trace {
netfs_sreq_trace_submit, netfs_sreq_trace_submit,
netfs_sreq_trace_terminated, netfs_sreq_trace_terminated,
netfs_sreq_trace_write, netfs_sreq_trace_write,
netfs_sreq_trace_write_skip,
netfs_sreq_trace_write_term, netfs_sreq_trace_write_term,
}; };
...@@ -77,6 +78,7 @@ enum netfs_sreq_trace { ...@@ -77,6 +78,7 @@ enum netfs_sreq_trace {
EM(netfs_sreq_trace_submit, "SUBMT") \ EM(netfs_sreq_trace_submit, "SUBMT") \
EM(netfs_sreq_trace_terminated, "TERM ") \ EM(netfs_sreq_trace_terminated, "TERM ") \
EM(netfs_sreq_trace_write, "WRITE") \ EM(netfs_sreq_trace_write, "WRITE") \
EM(netfs_sreq_trace_write_skip, "SKIP ") \
E_(netfs_sreq_trace_write_term, "WTERM") E_(netfs_sreq_trace_write_term, "WTERM")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment