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
Unified · Split
| @@ -7,6 +7,8 @@ Network Filesystem Helper Library · 6 unmodified lines | |||
| 7 | .. Contents: | 7 | .. Contents: |
| 8 | 8 | ||
| 9 | - Overview. | 9 | - Overview. |
| 10 | - Per-inode context. | ||
| 11 | - Inode context helper functions. | ||
| 10 | - Buffered read helpers. | 12 | - Buffered read helpers. |
| 11 | - Read helper functions. | 13 | - Read helper functions. |
| 12 | - Read helper structures. | 14 | - Read helper structures. |
| @@ -28,6 +30,69 @@ Note that the library module doesn't link against local caching directly, so · 15 unmodified lines | |||
| 28 | access must be provided by the netfs. | 30 | access must be provided by the netfs. |
| 29 | 31 | ||
| 30 | 32 | ||
| 33 | Per-Inode Context | ||
| 34 | ================= | ||
| 35 | |||
| 36 | The network filesystem helper library needs a place to store a bit of state for | ||
| 37 | its use on each netfs inode it is helping to manage. To this end, a context | ||
| 38 | structure is defined:: | ||
| 39 | |||
| 40 | struct netfs_i_context { | ||
| 41 | const struct netfs_request_ops *ops; | ||
| 42 | struct fscache_cookie *cache; | ||
| 43 | }; | ||
| 44 | |||
| 45 | A network filesystem that wants to use netfs lib must place one of these | ||
| 46 | directly after the VFS ``struct inode`` it allocates, usually as part of its | ||
| 47 | own struct. This can be done in a way similar to the following:: | ||
| 48 | |||
| 49 | struct my_inode { | ||
| 50 | struct { | ||
| 51 | /* These must be contiguous */ | ||
| 52 | struct inode vfs_inode; | ||
| 53 | struct netfs_i_context netfs_ctx; | ||
| 54 | }; | ||
| 55 | ... | ||
| 56 | }; | ||
| 57 | |||
| 58 | This allows netfslib to find its state by simple offset from the inode pointer, | ||
| 59 | thereby allowing the netfslib helper functions to be pointed to directly by the | ||
| 60 | VFS/VM operation tables. | ||
| 61 | |||
| 62 | The structure contains the following fields: | ||
| 63 | |||
| 64 | * ``ops`` | ||
| 65 | |||
| 66 | The set of operations provided by the network filesystem to netfslib. | ||
| 67 | |||
| 68 | * ``cache`` | ||
| 69 | |||
| 70 | Local caching cookie, or NULL if no caching is enabled. This field does not | ||
| 71 | exist if fscache is disabled. | ||
| 72 | |||
| 73 | |||
| 74 | Inode Context Helper Functions | ||
| 75 | ------------------------------ | ||
| 76 | |||
| 77 | To help deal with the per-inode context, a number helper functions are | ||
| 78 | provided. Firstly, a function to perform basic initialisation on a context and | ||
| 79 | set the operations table pointer:: | ||
| 80 | |||
| 81 | void netfs_i_context_init(struct inode *inode, | ||
| 82 | const struct netfs_request_ops *ops); | ||
| 83 | |||
| 84 | then two functions to cast between the VFS inode structure and the netfs | ||
| 85 | context:: | ||
| 86 | |||
| 87 | struct netfs_i_context *netfs_i_context(struct inode *inode); | ||
| 88 | struct inode *netfs_inode(struct netfs_i_context *ctx); | ||
| 89 | |||
| 90 | and finally, a function to get the cache cookie pointer from the context | ||
| 91 | attached to an inode (or NULL if fscache is disabled):: | ||
| 92 | |||
| 93 | struct fscache_cookie *netfs_i_cookie(struct inode *inode); | ||
| 94 | |||
| 95 | |||
| 31 | Buffered Read Helpers | 96 | Buffered Read Helpers |
| 32 | ===================== | 97 | ===================== |
| 33 | 98 | ||
| @@ -70,38 +135,22 @@ Read Helper Functions · 36 unmodified lines | |||
| 70 | 135 | ||
| 71 | Three read helpers are provided:: | 136 | Three read helpers are provided:: |
| 72 | 137 | ||
| 73 | void netfs_readahead(struct readahead_control *ractl, | 138 | void netfs_readahead(struct readahead_control *ractl); |
| 74 | const struct netfs_request_ops *ops, | ||
| 75 | void *netfs_priv); | ||
| 76 | int netfs_readpage(struct file *file, | 139 | int netfs_readpage(struct file *file, |
| 77 | struct folio *folio, | 140 | struct page *page); |
| 78 | const struct netfs_request_ops *ops, | ||
| 79 | void *netfs_priv); | ||
| 80 | int netfs_write_begin(struct file *file, | 141 | int netfs_write_begin(struct file *file, |
| 81 | struct address_space *mapping, | 142 | struct address_space *mapping, |
| 82 | loff_t pos, | 143 | loff_t pos, |
| 83 | unsigned int len, | 144 | unsigned int len, |
| 84 | unsigned int flags, | 145 | unsigned int flags, |
| 85 | struct folio **_folio, | 146 | struct folio **_folio, |
| 86 | void **_fsdata, | 147 | void **_fsdata); |
| 87 | const struct netfs_request_ops *ops, | ||
| 88 | void *netfs_priv); | ||
| 89 | |||
| 90 | Each corresponds to a VM operation, with the addition of a couple of parameters | ||
| 91 | for the use of the read helpers: | ||
| 92 | 148 | ||
| 93 | * ``ops`` | 149 | Each corresponds to a VM address space operation. These operations use the |
| 94 | 150 | state in the per-inode context. | |
| 95 | A table of operations through which the helpers can talk to the filesystem. | ||
| 96 | |||
| 97 | * ``netfs_priv`` | ||
| 98 | 151 | ||
| 99 | Filesystem private data (can be NULL). | 152 | For ->readahead() and ->readpage(), the network filesystem just point directly |
| 100 | 153 | at the corresponding read helper; whereas for ->write_begin(), it may be a | |
| 101 | Both of these values will be stored into the read request structure. | ||
| 102 | |||
| 103 | For ->readahead() and ->readpage(), the network filesystem should just jump | ||
| 104 | into the corresponding read helper; whereas for ->write_begin(), it may be a | ||
| 105 | little more complicated as the network filesystem might want to flush | 154 | little more complicated as the network filesystem might want to flush |
| 106 | conflicting writes or track dirty data and needs to put the acquired folio if | 155 | conflicting writes or track dirty data and needs to put the acquired folio if |
| 107 | an error occurs after calling the helper. | 156 | an error occurs after calling the helper. |
| @@ -246,7 +295,6 @@ through which it can issue requests and negotiate:: · 138 unmodified lines | |||
| 246 | 295 | ||
| 247 | struct netfs_request_ops { | 296 | struct netfs_request_ops { |
| 248 | void (*init_request)(struct netfs_io_request *rreq, struct file *file); | 297 | void (*init_request)(struct netfs_io_request *rreq, struct file *file); |
| 249 | bool (*is_cache_enabled)(struct inode *inode); | ||
| 250 | int (*begin_cache_operation)(struct netfs_io_request *rreq); | 298 | int (*begin_cache_operation)(struct netfs_io_request *rreq); |
| 251 | void (*expand_readahead)(struct netfs_io_request *rreq); | 299 | void (*expand_readahead)(struct netfs_io_request *rreq); |
| 252 | bool (*clamp_length)(struct netfs_io_subrequest *subreq); | 300 | bool (*clamp_length)(struct netfs_io_subrequest *subreq); |
| @@ -265,11 +313,6 @@ The operations are as follows: · 12 unmodified lines | |||
| 265 | [Optional] This is called to initialise the request structure. It is given | 313 | [Optional] This is called to initialise the request structure. It is given |
| 266 | the file for reference and can modify the ->netfs_priv value. | 314 | the file for reference and can modify the ->netfs_priv value. |
| 267 | 315 | ||
| 268 | * ``is_cache_enabled()`` | ||
| 269 | |||
| 270 | [Required] This is called by netfs_write_begin() to ask if the file is being | ||
| 271 | cached. It should return true if it is being cached and false otherwise. | ||
| 272 | |||
| 273 | * ``begin_cache_operation()`` | 316 | * ``begin_cache_operation()`` |
| 274 | 317 | ||
| 275 | [Optional] This is called to ask the network filesystem to call into the | 318 | [Optional] This is called to ask the network filesystem to call into the |
| @@ -49,22 +49,20 @@ int v9fs_cache_session_get_cookie(struct v9fs_session_info *v9ses, · 48 unmodified lines | |||
| 49 | 49 | ||
| 50 | void v9fs_cache_inode_get_cookie(struct inode *inode) | 50 | void v9fs_cache_inode_get_cookie(struct inode *inode) |
| 51 | { | 51 | { |
| 52 | struct v9fs_inode *v9inode; | 52 | struct v9fs_inode *v9inode = V9FS_I(inode); |
| 53 | struct v9fs_session_info *v9ses; | 53 | struct v9fs_session_info *v9ses; |
| 54 | __le32 version; | 54 | __le32 version; |
| 55 | __le64 path; | 55 | __le64 path; |
| 56 | 56 | ||
| 57 | if (!S_ISREG(inode->i_mode)) | 57 | if (!S_ISREG(inode->i_mode)) |
| 58 | return; | 58 | return; |
| 59 | 59 | if (WARN_ON(v9fs_inode_cookie(v9inode))) | |
| 60 | v9inode = V9FS_I(inode); | ||
| 61 | if (WARN_ON(v9inode->fscache)) | ||
| 62 | return; | 60 | return; |
| 63 | 61 | ||
| 64 | version = cpu_to_le32(v9inode->qid.version); | 62 | version = cpu_to_le32(v9inode->qid.version); |
| 65 | path = cpu_to_le64(v9inode->qid.path); | 63 | path = cpu_to_le64(v9inode->qid.path); |
| 66 | v9ses = v9fs_inode2v9ses(inode); | 64 | v9ses = v9fs_inode2v9ses(inode); |
| 67 | v9inode->fscache = | 65 | v9inode->netfs_ctx.cache = |
| 68 | fscache_acquire_cookie(v9fs_session_cache(v9ses), | 66 | fscache_acquire_cookie(v9fs_session_cache(v9ses), |
| 69 | 0, | 67 | 0, |
| 70 | &path, sizeof(path), | 68 | &path, sizeof(path), |
| @@ -72,5 +70,5 @@ void v9fs_cache_inode_get_cookie(struct inode *inode) · 1 unmodified line | |||
| 72 | i_size_read(&v9inode->vfs_inode)); | 70 | i_size_read(&v9inode->vfs_inode)); |
| 73 | 71 | ||
| 74 | p9_debug(P9_DEBUG_FSC, "inode %p get cookie %p\n", | 72 | p9_debug(P9_DEBUG_FSC, "inode %p get cookie %p\n", |
| 75 | inode, v9inode->fscache); | 73 | inode, v9fs_inode_cookie(v9inode)); |
| 76 | } | 74 | } |
| @@ -623,9 +623,7 @@ static void v9fs_sysfs_cleanup(void) · 622 unmodified lines | |||
| 623 | static void v9fs_inode_init_once(void *foo) | 623 | static void v9fs_inode_init_once(void *foo) |
| 624 | { | 624 | { |
| 625 | struct v9fs_inode *v9inode = (struct v9fs_inode *)foo; | 625 | struct v9fs_inode *v9inode = (struct v9fs_inode *)foo; |
| 626 | #ifdef CONFIG_9P_FSCACHE | 626 | |
| 627 | v9inode->fscache = NULL; | ||
| 628 | #endif | ||
| 629 | memset(&v9inode->qid, 0, sizeof(v9inode->qid)); | 627 | memset(&v9inode->qid, 0, sizeof(v9inode->qid)); |
| 630 | inode_init_once(&v9inode->vfs_inode); | 628 | inode_init_once(&v9inode->vfs_inode); |
| 631 | } | 629 | } |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | |||
| 9 | #define FS_9P_V9FS_H | 9 | #define FS_9P_V9FS_H |
| 10 | 10 | ||
| 11 | #include <linux/backing-dev.h> | 11 | #include <linux/backing-dev.h> |
| 12 | #include <linux/netfs.h> | ||
| 12 | 13 | ||
| 13 | /** | 14 | /** |
| 14 | * enum p9_session_flags - option flags for each 9P session | 15 | * enum p9_session_flags - option flags for each 9P session |
| @@ -108,14 +109,15 @@ struct v9fs_session_info { · 93 unmodified lines | |||
| 108 | #define V9FS_INO_INVALID_ATTR 0x01 | 109 | #define V9FS_INO_INVALID_ATTR 0x01 |
| 109 | 110 | ||
| 110 | struct v9fs_inode { | 111 | struct v9fs_inode { |
| 111 | #ifdef CONFIG_9P_FSCACHE | 112 | struct { |
| 112 | struct fscache_cookie *fscache; | 113 | /* These must be contiguous */ |
| 113 | #endif | 114 | struct inode vfs_inode; /* the VFS's inode record */ |
| 115 | struct netfs_i_context netfs_ctx; /* Netfslib context */ | ||
| 116 | }; | ||
| 114 | struct p9_qid qid; | 117 | struct p9_qid qid; |
| 115 | unsigned int cache_validity; | 118 | unsigned int cache_validity; |
| 116 | struct p9_fid *writeback_fid; | 119 | struct p9_fid *writeback_fid; |
| 117 | struct mutex v_mutex; | 120 | struct mutex v_mutex; |
| 118 | struct inode vfs_inode; | ||
| 119 | }; | 121 | }; |
| 120 | 122 | ||
| 121 | static inline struct v9fs_inode *V9FS_I(const struct inode *inode) | 123 | static inline struct v9fs_inode *V9FS_I(const struct inode *inode) |
| @@ -126,7 +128,7 @@ static inline struct v9fs_inode *V9FS_I(const struct inode *inode) · 4 unmodified lines | |||
| 126 | static inline struct fscache_cookie *v9fs_inode_cookie(struct v9fs_inode *v9inode) | 128 | static inline struct fscache_cookie *v9fs_inode_cookie(struct v9fs_inode *v9inode) |
| 127 | { | 129 | { |
| 128 | #ifdef CONFIG_9P_FSCACHE | 130 | #ifdef CONFIG_9P_FSCACHE |
| 129 | return v9inode->fscache; | 131 | return netfs_i_cookie(&v9inode->vfs_inode); |
| 130 | #else | 132 | #else |
| 131 | return NULL; | 133 | return NULL; |
| 132 | #endif | 134 | #endif |
| @@ -163,6 +165,7 @@ extern struct inode *v9fs_inode_from_fid(struct v9fs_session_info *v9ses, · 30 unmodified lines | |||
| 163 | extern const struct inode_operations v9fs_dir_inode_operations_dotl; | 165 | extern const struct inode_operations v9fs_dir_inode_operations_dotl; |
| 164 | extern const struct inode_operations v9fs_file_inode_operations_dotl; | 166 | extern const struct inode_operations v9fs_file_inode_operations_dotl; |
| 165 | extern const struct inode_operations v9fs_symlink_inode_operations_dotl; | 167 | extern const struct inode_operations v9fs_symlink_inode_operations_dotl; |
| 168 | extern const struct netfs_request_ops v9fs_req_ops; | ||
| 166 | extern struct inode *v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, | 169 | extern struct inode *v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, |
| 167 | struct p9_fid *fid, | 170 | struct p9_fid *fid, |
| 168 | struct super_block *sb, int new); | 171 | struct super_block *sb, int new); |
| @@ -77,17 +77,6 @@ static void v9fs_req_cleanup(struct address_space *mapping, void *priv) · 76 unmodified lines | |||
| 77 | p9_client_clunk(fid); | 77 | p9_client_clunk(fid); |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | /** | ||
| 81 | * v9fs_is_cache_enabled - Determine if caching is enabled for an inode | ||
| 82 | * @inode: The inode to check | ||
| 83 | */ | ||
| 84 | static bool v9fs_is_cache_enabled(struct inode *inode) | ||
| 85 | { | ||
| 86 | struct fscache_cookie *cookie = v9fs_inode_cookie(V9FS_I(inode)); | ||
| 87 | |||
| 88 | return fscache_cookie_enabled(cookie) && cookie->cache_priv; | ||
| 89 | } | ||
| 90 | |||
| 91 | /** | 80 | /** |
| 92 | * v9fs_begin_cache_operation - Begin a cache operation for a read | 81 | * v9fs_begin_cache_operation - Begin a cache operation for a read |
| 93 | * @rreq: The read request | 82 | * @rreq: The read request |
| @@ -103,36 +92,13 @@ static int v9fs_begin_cache_operation(struct netfs_io_request *rreq) · 9 unmodified lines | |||
| 103 | #endif | 92 | #endif |
| 104 | } | 93 | } |
| 105 | 94 | ||
| 106 | static const struct netfs_request_ops v9fs_req_ops = { | 95 | const struct netfs_request_ops v9fs_req_ops = { |
| 107 | .init_request = v9fs_init_request, | 96 | .init_request = v9fs_init_request, |
| 108 | .is_cache_enabled = v9fs_is_cache_enabled, | ||
| 109 | .begin_cache_operation = v9fs_begin_cache_operation, | 97 | .begin_cache_operation = v9fs_begin_cache_operation, |
| 110 | .issue_read = v9fs_issue_read, | 98 | .issue_read = v9fs_issue_read, |
| 111 | .cleanup = v9fs_req_cleanup, | 99 | .cleanup = v9fs_req_cleanup, |
| 112 | }; | 100 | }; |
| 113 | 101 | ||
| 114 | /** | ||
| 115 | * v9fs_vfs_readpage - read an entire page in from 9P | ||
| 116 | * @file: file being read | ||
| 117 | * @page: structure to page | ||
| 118 | * | ||
| 119 | */ | ||
| 120 | static int v9fs_vfs_readpage(struct file *file, struct page *page) | ||
| 121 | { | ||
| 122 | struct folio *folio = page_folio(page); | ||
| 123 | |||
| 124 | return netfs_readpage(file, folio, &v9fs_req_ops, NULL); | ||
| 125 | } | ||
| 126 | |||
| 127 | /** | ||
| 128 | * v9fs_vfs_readahead - read a set of pages from 9P | ||
| 129 | * @ractl: The readahead parameters | ||
| 130 | */ | ||
| 131 | static void v9fs_vfs_readahead(struct readahead_control *ractl) | ||
| 132 | { | ||
| 133 | netfs_readahead(ractl, &v9fs_req_ops, NULL); | ||
| 134 | } | ||
| 135 | |||
| 136 | /** | 102 | /** |
| 137 | * v9fs_release_page - release the private state associated with a page | 103 | * v9fs_release_page - release the private state associated with a page |
| 138 | * @page: The page to be released | 104 | * @page: The page to be released |
| @@ -326,8 +292,7 @@ static int v9fs_write_begin(struct file *filp, struct address_space *mapping, · 187 unmodified lines | |||
| 326 | * file. We need to do this before we get a lock on the page in case | 292 | * file. We need to do this before we get a lock on the page in case |
| 327 | * there's more than one writer competing for the same cache block. | 293 | * there's more than one writer competing for the same cache block. |
| 328 | */ | 294 | */ |
| 329 | retval = netfs_write_begin(filp, mapping, pos, len, flags, &folio, fsdata, | 295 | retval = netfs_write_begin(filp, mapping, pos, len, flags, &folio, fsdata); |
| 330 | &v9fs_req_ops, NULL); | ||
| 331 | if (retval < 0) | 296 | if (retval < 0) |
| 332 | return retval; | 297 | return retval; |
| 333 | 298 | ||
| @@ -388,8 +353,8 @@ static int v9fs_set_page_dirty(struct page *page) · 54 unmodified lines | |||
| 388 | #endif | 353 | #endif |
| 389 | 354 | ||
| 390 | const struct address_space_operations v9fs_addr_operations = { | 355 | const struct address_space_operations v9fs_addr_operations = { |
| 391 | .readpage = v9fs_vfs_readpage, | 356 | .readpage = netfs_readpage, |
| 392 | .readahead = v9fs_vfs_readahead, | 357 | .readahead = netfs_readahead, |
| 393 | .set_page_dirty = v9fs_set_page_dirty, | 358 | .set_page_dirty = v9fs_set_page_dirty, |
| 394 | .writepage = v9fs_vfs_writepage, | 359 | .writepage = v9fs_vfs_writepage, |
| 395 | .write_begin = v9fs_write_begin, | 360 | .write_begin = v9fs_write_begin, |
| @@ -231,9 +231,6 @@ struct inode *v9fs_alloc_inode(struct super_block *sb) · 230 unmodified lines | |||
| 231 | v9inode = kmem_cache_alloc(v9fs_inode_cache, GFP_KERNEL); | 231 | v9inode = kmem_cache_alloc(v9fs_inode_cache, GFP_KERNEL); |
| 232 | if (!v9inode) | 232 | if (!v9inode) |
| 233 | return NULL; | 233 | return NULL; |
| 234 | #ifdef CONFIG_9P_FSCACHE | ||
| 235 | v9inode->fscache = NULL; | ||
| 236 | #endif | ||
| 237 | v9inode->writeback_fid = NULL; | 234 | v9inode->writeback_fid = NULL; |
| 238 | v9inode->cache_validity = 0; | 235 | v9inode->cache_validity = 0; |
| 239 | mutex_init(&v9inode->v_mutex); | 236 | mutex_init(&v9inode->v_mutex); |
| @@ -250,6 +247,14 @@ void v9fs_free_inode(struct inode *inode) · 10 unmodified lines | |||
| 250 | kmem_cache_free(v9fs_inode_cache, V9FS_I(inode)); | 247 | kmem_cache_free(v9fs_inode_cache, V9FS_I(inode)); |
| 251 | } | 248 | } |
| 252 | 249 | ||
| 250 | /* | ||
| 251 | * Set parameters for the netfs library | ||
| 252 | */ | ||
| 253 | static void v9fs_set_netfs_context(struct inode *inode) | ||
| 254 | { | ||
| 255 | netfs_i_context_init(inode, &v9fs_req_ops); | ||
| 256 | } | ||
| 257 | |||
| 253 | int v9fs_init_inode(struct v9fs_session_info *v9ses, | 258 | int v9fs_init_inode(struct v9fs_session_info *v9ses, |
| 254 | struct inode *inode, umode_t mode, dev_t rdev) | 259 | struct inode *inode, umode_t mode, dev_t rdev) |
| 255 | { | 260 | { |
| @@ -338,6 +343,8 @@ int v9fs_init_inode(struct v9fs_session_info *v9ses, · 82 unmodified lines | |||
| 338 | err = -EINVAL; | 343 | err = -EINVAL; |
| 339 | goto error; | 344 | goto error; |
| 340 | } | 345 | } |
| 346 | |||
| 347 | v9fs_set_netfs_context(inode); | ||
| 341 | error: | 348 | error: |
| 342 | return err; | 349 | return err; |
| 343 | 350 | ||
| @@ -76,6 +76,7 @@ struct inode *afs_iget_pseudo_dir(struct super_block *sb, bool root) · 75 unmodified lines | |||
| 76 | /* there shouldn't be an existing inode */ | 76 | /* there shouldn't be an existing inode */ |
| 77 | BUG_ON(!(inode->i_state & I_NEW)); | 77 | BUG_ON(!(inode->i_state & I_NEW)); |
| 78 | 78 | ||
| 79 | netfs_i_context_init(inode, NULL); | ||
| 79 | inode->i_size = 0; | 80 | inode->i_size = 0; |
| 80 | inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; | 81 | inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; |
| 81 | if (root) { | 82 | if (root) { |
| @@ -19,13 +19,11 @@ · 18 unmodified lines | |||
| 19 | #include "internal.h" | 19 | #include "internal.h" |
| 20 | 20 | ||
| 21 | static int afs_file_mmap(struct file *file, struct vm_area_struct *vma); | 21 | static int afs_file_mmap(struct file *file, struct vm_area_struct *vma); |
| 22 | static int afs_readpage(struct file *file, struct page *page); | ||
| 23 | static int afs_symlink_readpage(struct file *file, struct page *page); | 22 | static int afs_symlink_readpage(struct file *file, struct page *page); |
| 24 | static void afs_invalidatepage(struct page *page, unsigned int offset, | 23 | static void afs_invalidatepage(struct page *page, unsigned int offset, |
| 25 | unsigned int length); | 24 | unsigned int length); |
| 26 | static int afs_releasepage(struct page *page, gfp_t gfp_flags); | 25 | static int afs_releasepage(struct page *page, gfp_t gfp_flags); |
| 27 | 26 | ||
| 28 | static void afs_readahead(struct readahead_control *ractl); | ||
| 29 | static ssize_t afs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter); | 27 | static ssize_t afs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter); |
| 30 | static void afs_vm_open(struct vm_area_struct *area); | 28 | static void afs_vm_open(struct vm_area_struct *area); |
| 31 | static void afs_vm_close(struct vm_area_struct *area); | 29 | static void afs_vm_close(struct vm_area_struct *area); |
| @@ -52,8 +50,8 @@ const struct inode_operations afs_file_inode_operations = { · 20 unmodified lines | |||
| 52 | }; | 50 | }; |
| 53 | 51 | ||
| 54 | const struct address_space_operations afs_file_aops = { | 52 | const struct address_space_operations afs_file_aops = { |
| 55 | .readpage = afs_readpage, | 53 | .readpage = netfs_readpage, |
| 56 | .readahead = afs_readahead, | 54 | .readahead = netfs_readahead, |
| 57 | .set_page_dirty = afs_set_page_dirty, | 55 | .set_page_dirty = afs_set_page_dirty, |
| 58 | .launder_page = afs_launder_page, | 56 | .launder_page = afs_launder_page, |
| 59 | .releasepage = afs_releasepage, | 57 | .releasepage = afs_releasepage, |
| @@ -365,13 +363,6 @@ static int afs_init_request(struct netfs_io_request *rreq, struct file *file) · 305 unmodified lines | |||
| 365 | return 0; | 363 | return 0; |
| 366 | } | 364 | } |
| 367 | 365 | ||
| 368 | static bool afs_is_cache_enabled(struct inode *inode) | ||
| 369 | { | ||
| 370 | struct fscache_cookie *cookie = afs_vnode_cache(AFS_FS_I(inode)); | ||
| 371 | |||
| 372 | return fscache_cookie_enabled(cookie) && cookie->cache_priv; | ||
| 373 | } | ||
| 374 | |||
| 375 | static int afs_begin_cache_operation(struct netfs_io_request *rreq) | 366 | static int afs_begin_cache_operation(struct netfs_io_request *rreq) |
| 376 | { | 367 | { |
| 377 | #ifdef CONFIG_AFS_FSCACHE | 368 | #ifdef CONFIG_AFS_FSCACHE |
| @@ -399,25 +390,12 @@ static void afs_priv_cleanup(struct address_space *mapping, void *netfs_priv) · 21 unmodified lines | |||
| 399 | 390 | ||
| 400 | const struct netfs_request_ops afs_req_ops = { | 391 | const struct netfs_request_ops afs_req_ops = { |
| 401 | .init_request = afs_init_request, | 392 | .init_request = afs_init_request, |
| 402 | .is_cache_enabled = afs_is_cache_enabled, | ||
| 403 | .begin_cache_operation = afs_begin_cache_operation, | 393 | .begin_cache_operation = afs_begin_cache_operation, |
| 404 | .check_write_begin = afs_check_write_begin, | 394 | .check_write_begin = afs_check_write_begin, |
| 405 | .issue_read = afs_issue_read, | 395 | .issue_read = afs_issue_read, |
| 406 | .cleanup = afs_priv_cleanup, | 396 | .cleanup = afs_priv_cleanup, |
| 407 | }; | 397 | }; |
| 408 | 398 | ||
| 409 | static int afs_readpage(struct file *file, struct page *page) | ||
| 410 | { | ||
| 411 | struct folio *folio = page_folio(page); | ||
| 412 | |||
| 413 | return netfs_readpage(file, folio, &afs_req_ops, NULL); | ||
| 414 | } | ||
| 415 | |||
| 416 | static void afs_readahead(struct readahead_control *ractl) | ||
| 417 | { | ||
| 418 | netfs_readahead(ractl, &afs_req_ops, NULL); | ||
| 419 | } | ||
| 420 | |||
| 421 | int afs_write_inode(struct inode *inode, struct writeback_control *wbc) | 399 | int afs_write_inode(struct inode *inode, struct writeback_control *wbc) |
| 422 | { | 400 | { |
| 423 | fscache_unpin_writeback(wbc, afs_vnode_cache(AFS_FS_I(inode))); | 401 | fscache_unpin_writeback(wbc, afs_vnode_cache(AFS_FS_I(inode))); |
| @@ -53,6 +53,14 @@ static noinline void dump_vnode(struct afs_vnode *vnode, struct afs_vnode *paren · 52 unmodified lines | |||
| 53 | dump_stack(); | 53 | dump_stack(); |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | /* | ||
| 57 | * Set parameters for the netfs library | ||
| 58 | */ | ||
| 59 | static void afs_set_netfs_context(struct afs_vnode *vnode) | ||
| 60 | { | ||
| 61 | netfs_i_context_init(&vnode->vfs_inode, &afs_req_ops); | ||
| 62 | } | ||
| 63 | |||
| 56 | /* | 64 | /* |
| 57 | * Initialise an inode from the vnode status. | 65 | * Initialise an inode from the vnode status. |
| 58 | */ | 66 | */ |
| @@ -128,6 +136,7 @@ static int afs_inode_init_from_status(struct afs_operation *op, · 69 unmodified lines | |||
| 128 | } | 136 | } |
| 129 | 137 | ||
| 130 | afs_set_i_size(vnode, status->size); | 138 | afs_set_i_size(vnode, status->size); |
| 139 | afs_set_netfs_context(vnode); | ||
| 131 | 140 | ||
| 132 | vnode->invalid_before = status->data_version; | 141 | vnode->invalid_before = status->data_version; |
| 133 | inode_set_iversion_raw(&vnode->vfs_inode, status->data_version); | 142 | inode_set_iversion_raw(&vnode->vfs_inode, status->data_version); |
| @@ -420,7 +429,7 @@ static void afs_get_inode_cache(struct afs_vnode *vnode) · 286 unmodified lines | |||
| 420 | struct afs_vnode_cache_aux aux; | 429 | struct afs_vnode_cache_aux aux; |
| 421 | 430 | ||
| 422 | if (vnode->status.type != AFS_FTYPE_FILE) { | 431 | if (vnode->status.type != AFS_FTYPE_FILE) { |
| 423 | vnode->cache = NULL; | 432 | vnode->netfs_ctx.cache = NULL; |
| 424 | return; | 433 | return; |
| 425 | } | 434 | } |
| 426 | 435 | ||
| @@ -430,12 +439,14 @@ static void afs_get_inode_cache(struct afs_vnode *vnode) · 3 unmodified lines | |||
| 430 | key.vnode_id_ext[1] = htonl(vnode->fid.vnode_hi); | 439 | key.vnode_id_ext[1] = htonl(vnode->fid.vnode_hi); |
| 431 | afs_set_cache_aux(vnode, &aux); | 440 | afs_set_cache_aux(vnode, &aux); |
| 432 | 441 | ||
| 433 | vnode->cache = fscache_acquire_cookie( | 442 | afs_vnode_set_cache(vnode, |
| 434 | vnode->volume->cache, | 443 | fscache_acquire_cookie( |
| 435 | vnode->status.type == AFS_FTYPE_FILE ? 0 : FSCACHE_ADV_SINGLE_CHUNK, | 444 | vnode->volume->cache, |
| 436 | &key, sizeof(key), | 445 | vnode->status.type == AFS_FTYPE_FILE ? |
| 437 | &aux, sizeof(aux), | 446 | 0 : FSCACHE_ADV_SINGLE_CHUNK, |
| 438 | vnode->status.size); | 447 | &key, sizeof(key), |
| 448 | &aux, sizeof(aux), | ||
| 449 | vnode->status.size)); | ||
| 439 | #endif | 450 | #endif |
| 440 | } | 451 | } |
| 441 | 452 | ||
| @@ -528,6 +539,7 @@ struct inode *afs_root_iget(struct super_block *sb, struct key *key) · 86 unmodified lines | |||
| 528 | 539 | ||
| 529 | vnode = AFS_FS_I(inode); | 540 | vnode = AFS_FS_I(inode); |
| 530 | vnode->cb_v_break = as->volume->cb_v_break, | 541 | vnode->cb_v_break = as->volume->cb_v_break, |
| 542 | afs_set_netfs_context(vnode); | ||
| 531 | 543 | ||
| 532 | op = afs_alloc_operation(key, as->volume); | 544 | op = afs_alloc_operation(key, as->volume); |
| 533 | if (IS_ERR(op)) { | 545 | if (IS_ERR(op)) { |
| @@ -786,11 +798,8 @@ void afs_evict_inode(struct inode *inode) · 252 unmodified lines | |||
| 786 | afs_put_wb_key(wbk); | 798 | afs_put_wb_key(wbk); |
| 787 | } | 799 | } |
| 788 | 800 | ||
| 789 | #ifdef CONFIG_AFS_FSCACHE | 801 | fscache_relinquish_cookie(afs_vnode_cache(vnode), |
| 790 | fscache_relinquish_cookie(vnode->cache, | ||
| 791 | test_bit(AFS_VNODE_DELETED, &vnode->flags)); | 802 | test_bit(AFS_VNODE_DELETED, &vnode->flags)); |
| 792 | vnode->cache = NULL; | ||
| 793 | #endif | ||
| 794 | 803 | ||
| 795 | afs_prune_wb_keys(vnode); | 804 | afs_prune_wb_keys(vnode); |
| 796 | afs_put_permits(rcu_access_pointer(vnode->permit_cache)); | 805 | afs_put_permits(rcu_access_pointer(vnode->permit_cache)); |
| @@ -619,15 +619,16 @@ enum afs_lock_state { · 618 unmodified lines | |||
| 619 | * leak from one inode to another. | 619 | * leak from one inode to another. |
| 620 | */ | 620 | */ |
| 621 | struct afs_vnode { | 621 | struct afs_vnode { |
| 622 | struct inode vfs_inode; /* the VFS's inode record */ | 622 | struct { |
| 623 | /* These must be contiguous */ | ||
| 624 | struct inode vfs_inode; /* the VFS's inode record */ | ||
| 625 | struct netfs_i_context netfs_ctx; /* Netfslib context */ | ||
| 626 | }; | ||
| 623 | 627 | ||
| 624 | struct afs_volume *volume; /* volume on which vnode resides */ | 628 | struct afs_volume *volume; /* volume on which vnode resides */ |
| 625 | struct afs_fid fid; /* the file identifier for this inode */ | 629 | struct afs_fid fid; /* the file identifier for this inode */ |
| 626 | struct afs_file_status status; /* AFS status info for this file */ | 630 | struct afs_file_status status; /* AFS status info for this file */ |
| 627 | afs_dataversion_t invalid_before; /* Child dentries are invalid before this */ | 631 | afs_dataversion_t invalid_before; /* Child dentries are invalid before this */ |
| 628 | #ifdef CONFIG_AFS_FSCACHE | ||
| 629 | struct fscache_cookie *cache; /* caching cookie */ | ||
| 630 | #endif | ||
| 631 | struct afs_permits __rcu *permit_cache; /* cache of permits so far obtained */ | 632 | struct afs_permits __rcu *permit_cache; /* cache of permits so far obtained */ |
| 632 | struct mutex io_lock; /* Lock for serialising I/O on this mutex */ | 633 | struct mutex io_lock; /* Lock for serialising I/O on this mutex */ |
| 633 | struct rw_semaphore validate_lock; /* lock for validating this vnode */ | 634 | struct rw_semaphore validate_lock; /* lock for validating this vnode */ |
| @@ -674,12 +675,20 @@ struct afs_vnode { · 40 unmodified lines | |||
| 674 | static inline struct fscache_cookie *afs_vnode_cache(struct afs_vnode *vnode) | 675 | static inline struct fscache_cookie *afs_vnode_cache(struct afs_vnode *vnode) |
| 675 | { | 676 | { |
| 676 | #ifdef CONFIG_AFS_FSCACHE | 677 | #ifdef CONFIG_AFS_FSCACHE |
| 677 | return vnode->cache; | 678 | return netfs_i_cookie(&vnode->vfs_inode); |
| 678 | #else | 679 | #else |
| 679 | return NULL; | 680 | return NULL; |
| 680 | #endif | 681 | #endif |
| 681 | } | 682 | } |
| 682 | 683 | ||
| 684 | static inline void afs_vnode_set_cache(struct afs_vnode *vnode, | ||
| 685 | struct fscache_cookie *cookie) | ||
| 686 | { | ||
| 687 | #ifdef CONFIG_AFS_FSCACHE | ||
| 688 | vnode->netfs_ctx.cache = cookie; | ||
| 689 | #endif | ||
| 690 | } | ||
| 691 | |||
| 683 | /* | 692 | /* |
| 684 | * cached security record for one user's attempt to access a vnode | 693 | * cached security record for one user's attempt to access a vnode |
| 685 | */ | 694 | */ |
| @@ -688,13 +688,11 @@ static struct inode *afs_alloc_inode(struct super_block *sb) · 687 unmodified lines | |||
| 688 | /* Reset anything that shouldn't leak from one inode to the next. */ | 688 | /* Reset anything that shouldn't leak from one inode to the next. */ |
| 689 | memset(&vnode->fid, 0, sizeof(vnode->fid)); | 689 | memset(&vnode->fid, 0, sizeof(vnode->fid)); |
| 690 | memset(&vnode->status, 0, sizeof(vnode->status)); | 690 | memset(&vnode->status, 0, sizeof(vnode->status)); |
| 691 | afs_vnode_set_cache(vnode, NULL); | ||
| 691 | 692 | ||
| 692 | vnode->volume = NULL; | 693 | vnode->volume = NULL; |
| 693 | vnode->lock_key = NULL; | 694 | vnode->lock_key = NULL; |
| 694 | vnode->permit_cache = NULL; | 695 | vnode->permit_cache = NULL; |
| 695 | #ifdef CONFIG_AFS_FSCACHE | ||
| 696 | vnode->cache = NULL; | ||
| 697 | #endif | ||
| 698 | 696 | ||
| 699 | vnode->flags = 1 << AFS_VNODE_UNSET; | 697 | vnode->flags = 1 << AFS_VNODE_UNSET; |
| 700 | vnode->lock_state = AFS_VNODE_LOCK_NONE; | 698 | vnode->lock_state = AFS_VNODE_LOCK_NONE; |
| @@ -59,8 +59,7 @@ int afs_write_begin(struct file *file, struct address_space *mapping, · 58 unmodified lines | |||
| 59 | * file. We need to do this before we get a lock on the page in case | 59 | * file. We need to do this before we get a lock on the page in case |
| 60 | * there's more than one writer competing for the same cache block. | 60 | * there's more than one writer competing for the same cache block. |
| 61 | */ | 61 | */ |
| 62 | ret = netfs_write_begin(file, mapping, pos, len, flags, &folio, fsdata, | 62 | ret = netfs_write_begin(file, mapping, pos, len, flags, &folio, fsdata); |
| 63 | &afs_req_ops, NULL); | ||
| 64 | if (ret < 0) | 63 | if (ret < 0) |
| 65 | return ret; | 64 | return ret; |
| 66 | 65 | ||
| @@ -403,7 +403,7 @@ static void ceph_readahead_cleanup(struct address_space *mapping, void *priv) · 402 unmodified lines | |||
| 403 | ceph_put_cap_refs(ci, got); | 403 | ceph_put_cap_refs(ci, got); |
| 404 | } | 404 | } |
| 405 | 405 | ||
| 406 | static const struct netfs_request_ops ceph_netfs_read_ops = { | 406 | const struct netfs_request_ops ceph_netfs_ops = { |
| 407 | .init_request = ceph_init_request, | 407 | .init_request = ceph_init_request, |
| 408 | .begin_cache_operation = ceph_begin_cache_operation, | 408 | .begin_cache_operation = ceph_begin_cache_operation, |
| 409 | .issue_read = ceph_netfs_issue_read, | 409 | .issue_read = ceph_netfs_issue_read, |
| @@ -413,28 +413,6 @@ static const struct netfs_request_ops ceph_netfs_read_ops = { · 3 unmodified lines | |||
| 413 | .cleanup = ceph_readahead_cleanup, | 413 | .cleanup = ceph_readahead_cleanup, |
| 414 | }; | 414 | }; |
| 415 | 415 | ||
| 416 | /* read a single page, without unlocking it. */ | ||
| 417 | static int ceph_readpage(struct file *file, struct page *subpage) | ||
| 418 | { | ||
| 419 | struct folio *folio = page_folio(subpage); | ||
| 420 | struct inode *inode = file_inode(file); | ||
| 421 | struct ceph_inode_info *ci = ceph_inode(inode); | ||
| 422 | struct ceph_vino vino = ceph_vino(inode); | ||
| 423 | size_t len = folio_size(folio); | ||
| 424 | u64 off = folio_file_pos(folio); | ||
| 425 | |||
| 426 | dout("readpage ino %llx.%llx file %p off %llu len %zu folio %p index %lu\n inline %d", | ||
| 427 | vino.ino, vino.snap, file, off, len, folio, folio_index(folio), | ||
| 428 | ci->i_inline_version != CEPH_INLINE_NONE); | ||
| 429 | |||
| 430 | return netfs_readpage(file, folio, &ceph_netfs_read_ops, NULL); | ||
| 431 | } | ||
| 432 | |||
| 433 | static void ceph_readahead(struct readahead_control *ractl) | ||
| 434 | { | ||
| 435 | netfs_readahead(ractl, &ceph_netfs_read_ops, NULL); | ||
| 436 | } | ||
| 437 | |||
| 438 | #ifdef CONFIG_CEPH_FSCACHE | 416 | #ifdef CONFIG_CEPH_FSCACHE |
| 439 | static void ceph_set_page_fscache(struct page *page) | 417 | static void ceph_set_page_fscache(struct page *page) |
| 440 | { | 418 | { |
| @@ -1333,8 +1311,7 @@ static int ceph_write_begin(struct file *file, struct address_space *mapping, · 892 unmodified lines | |||
| 1333 | struct folio *folio = NULL; | 1311 | struct folio *folio = NULL; |
| 1334 | int r; | 1312 | int r; |
| 1335 | 1313 | ||
| 1336 | r = netfs_write_begin(file, inode->i_mapping, pos, len, 0, &folio, NULL, | 1314 | r = netfs_write_begin(file, inode->i_mapping, pos, len, 0, &folio, NULL); |
| 1337 | &ceph_netfs_read_ops, NULL); | ||
| 1338 | if (r == 0) | 1315 | if (r == 0) |
| 1339 | folio_wait_fscache(folio); | 1316 | folio_wait_fscache(folio); |
| 1340 | if (r < 0) { | 1317 | if (r < 0) { |
| @@ -1388,8 +1365,8 @@ out: · 47 unmodified lines | |||
| 1388 | } | 1365 | } |
| 1389 | 1366 | ||
| 1390 | const struct address_space_operations ceph_aops = { | 1367 | const struct address_space_operations ceph_aops = { |
| 1391 | .readpage = ceph_readpage, | 1368 | .readpage = netfs_readpage, |
| 1392 | .readahead = ceph_readahead, | 1369 | .readahead = netfs_readahead, |
| 1393 | .writepage = ceph_writepage, | 1370 | .writepage = ceph_writepage, |
| 1394 | .writepages = ceph_writepages_start, | 1371 | .writepages = ceph_writepages_start, |
| 1395 | .write_begin = ceph_write_begin, | 1372 | .write_begin = ceph_write_begin, |
| @@ -29,26 +29,25 @@ void ceph_fscache_register_inode_cookie(struct inode *inode) · 28 unmodified lines | |||
| 29 | if (!(inode->i_state & I_NEW)) | 29 | if (!(inode->i_state & I_NEW)) |
| 30 | return; | 30 | return; |
| 31 | 31 | ||
| 32 | WARN_ON_ONCE(ci->fscache); | 32 | WARN_ON_ONCE(ci->netfs_ctx.cache); |
| 33 | 33 | ||
| 34 | ci->fscache = fscache_acquire_cookie(fsc->fscache, 0, | 34 | ci->netfs_ctx.cache = |
| 35 | &ci->i_vino, sizeof(ci->i_vino), | 35 | fscache_acquire_cookie(fsc->fscache, 0, |
| 36 | &ci->i_version, sizeof(ci->i_version), | 36 | &ci->i_vino, sizeof(ci->i_vino), |
| 37 | i_size_read(inode)); | 37 | &ci->i_version, sizeof(ci->i_version), |
| 38 | i_size_read(inode)); | ||
| 38 | } | 39 | } |
| 39 | 40 | ||
| 40 | void ceph_fscache_unregister_inode_cookie(struct ceph_inode_info* ci) | 41 | void ceph_fscache_unregister_inode_cookie(struct ceph_inode_info *ci) |
| 41 | { | 42 | { |
| 42 | struct fscache_cookie *cookie = ci->fscache; | 43 | fscache_relinquish_cookie(ceph_fscache_cookie(ci), false); |
| 43 | |||
| 44 | fscache_relinquish_cookie(cookie, false); | ||
| 45 | } | 44 | } |
| 46 | 45 | ||
| 47 | void ceph_fscache_use_cookie(struct inode *inode, bool will_modify) | 46 | void ceph_fscache_use_cookie(struct inode *inode, bool will_modify) |
| 48 | { | 47 | { |
| 49 | struct ceph_inode_info *ci = ceph_inode(inode); | 48 | struct ceph_inode_info *ci = ceph_inode(inode); |
| 50 | 49 | ||
| 51 | fscache_use_cookie(ci->fscache, will_modify); | 50 | fscache_use_cookie(ceph_fscache_cookie(ci), will_modify); |
| 52 | } | 51 | } |
| 53 | 52 | ||
| 54 | void ceph_fscache_unuse_cookie(struct inode *inode, bool update) | 53 | void ceph_fscache_unuse_cookie(struct inode *inode, bool update) |
| @@ -58,9 +57,10 @@ void ceph_fscache_unuse_cookie(struct inode *inode, bool update) · 3 unmodified lines | |||
| 58 | if (update) { | 57 | if (update) { |
| 59 | loff_t i_size = i_size_read(inode); | 58 | loff_t i_size = i_size_read(inode); |
| 60 | 59 | ||
| 61 | fscache_unuse_cookie(ci->fscache, &ci->i_version, &i_size); | 60 | fscache_unuse_cookie(ceph_fscache_cookie(ci), |
| 61 | &ci->i_version, &i_size); | ||
| 62 | } else { | 62 | } else { |
| 63 | fscache_unuse_cookie(ci->fscache, NULL, NULL); | 63 | fscache_unuse_cookie(ceph_fscache_cookie(ci), NULL, NULL); |
| 64 | } | 64 | } |
| 65 | } | 65 | } |
| 66 | 66 | ||
| @@ -69,14 +69,14 @@ void ceph_fscache_update(struct inode *inode) · 2 unmodified lines | |||
| 69 | struct ceph_inode_info *ci = ceph_inode(inode); | 69 | struct ceph_inode_info *ci = ceph_inode(inode); |
| 70 | loff_t i_size = i_size_read(inode); | 70 | loff_t i_size = i_size_read(inode); |
| 71 | 71 | ||
| 72 | fscache_update_cookie(ci->fscache, &ci->i_version, &i_size); | 72 | fscache_update_cookie(ceph_fscache_cookie(ci), &ci->i_version, &i_size); |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | void ceph_fscache_invalidate(struct inode *inode, bool dio_write) | 75 | void ceph_fscache_invalidate(struct inode *inode, bool dio_write) |
| 76 | { | 76 | { |
| 77 | struct ceph_inode_info *ci = ceph_inode(inode); | 77 | struct ceph_inode_info *ci = ceph_inode(inode); |
| 78 | 78 | ||
| 79 | fscache_invalidate(ceph_inode(inode)->fscache, | 79 | fscache_invalidate(ceph_fscache_cookie(ci), |
| 80 | &ci->i_version, i_size_read(inode), | 80 | &ci->i_version, i_size_read(inode), |
| 81 | dio_write ? FSCACHE_INVAL_DIO_WRITE : 0); | 81 | dio_write ? FSCACHE_INVAL_DIO_WRITE : 0); |
| 82 | } | 82 | } |
| @@ -26,14 +26,9 @@ void ceph_fscache_unuse_cookie(struct inode *inode, bool update); · 25 unmodified lines | |||
| 26 | void ceph_fscache_update(struct inode *inode); | 26 | void ceph_fscache_update(struct inode *inode); |
| 27 | void ceph_fscache_invalidate(struct inode *inode, bool dio_write); | 27 | void ceph_fscache_invalidate(struct inode *inode, bool dio_write); |
| 28 | 28 | ||
| 29 | static inline void ceph_fscache_inode_init(struct ceph_inode_info *ci) | ||
| 30 | { | ||
| 31 | ci->fscache = NULL; | ||
| 32 | } | ||
| 33 | |||
| 34 | static inline struct fscache_cookie *ceph_fscache_cookie(struct ceph_inode_info *ci) | 29 | static inline struct fscache_cookie *ceph_fscache_cookie(struct ceph_inode_info *ci) |
| 35 | { | 30 | { |
| 36 | return ci->fscache; | 31 | return netfs_i_cookie(&ci->vfs_inode); |
| 37 | } | 32 | } |
| 38 | 33 | ||
| 39 | static inline void ceph_fscache_resize(struct inode *inode, loff_t to) | 34 | static inline void ceph_fscache_resize(struct inode *inode, loff_t to) |
| @@ -91,10 +86,6 @@ static inline void ceph_fscache_unregister_fs(struct ceph_fs_client* fsc) · 51 unmodified lines | |||
| 91 | { | 86 | { |
| 92 | } | 87 | } |
| 93 | 88 | ||
| 94 | static inline void ceph_fscache_inode_init(struct ceph_inode_info *ci) | ||
| 95 | { | ||
| 96 | } | ||
| 97 | |||
| 98 | static inline void ceph_fscache_register_inode_cookie(struct inode *inode) | 89 | static inline void ceph_fscache_register_inode_cookie(struct inode *inode) |
| 99 | { | 90 | { |
| 100 | } | 91 | } |
| @@ -453,6 +453,9 @@ struct inode *ceph_alloc_inode(struct super_block *sb) · 452 unmodified lines | |||
| 453 | 453 | ||
| 454 | dout("alloc_inode %p\n", &ci->vfs_inode); | 454 | dout("alloc_inode %p\n", &ci->vfs_inode); |
| 455 | 455 | ||
| 456 | /* Set parameters for the netfs library */ | ||
| 457 | netfs_i_context_init(&ci->vfs_inode, &ceph_netfs_ops); | ||
| 458 | |||
| 456 | spin_lock_init(&ci->i_ceph_lock); | 459 | spin_lock_init(&ci->i_ceph_lock); |
| 457 | 460 | ||
| 458 | ci->i_version = 0; | 461 | ci->i_version = 0; |
| @@ -538,9 +541,6 @@ struct inode *ceph_alloc_inode(struct super_block *sb) · 79 unmodified lines | |||
| 538 | INIT_WORK(&ci->i_work, ceph_inode_work); | 541 | INIT_WORK(&ci->i_work, ceph_inode_work); |
| 539 | ci->i_work_mask = 0; | 542 | ci->i_work_mask = 0; |
| 540 | memset(&ci->i_btime, '\0', sizeof(ci->i_btime)); | 543 | memset(&ci->i_btime, '\0', sizeof(ci->i_btime)); |
| 541 | |||
| 542 | ceph_fscache_inode_init(ci); | ||
| 543 | |||
| 544 | return &ci->vfs_inode; | 544 | return &ci->vfs_inode; |
| 545 | } | 545 | } |
| 546 | 546 | ||
| @@ -17,13 +17,11 @@ · 16 unmodified lines | |||
| 17 | #include <linux/posix_acl.h> | 17 | #include <linux/posix_acl.h> |
| 18 | #include <linux/refcount.h> | 18 | #include <linux/refcount.h> |
| 19 | #include <linux/security.h> | 19 | #include <linux/security.h> |
| 20 | #include <linux/netfs.h> | ||
| 21 | #include <linux/fscache.h> | ||
| 20 | 22 | ||
| 21 | #include <linux/ceph/libceph.h> | 23 | #include <linux/ceph/libceph.h> |
| 22 | 24 | ||
| 23 | #ifdef CONFIG_CEPH_FSCACHE | ||
| 24 | #include <linux/fscache.h> | ||
| 25 | #endif | ||
| 26 | |||
| 27 | /* large granularity for statfs utilization stats to facilitate | 25 | /* large granularity for statfs utilization stats to facilitate |
| 28 | * large volume sizes on 32-bit machines. */ | 26 | * large volume sizes on 32-bit machines. */ |
| 29 | #define CEPH_BLOCK_SHIFT 22 /* 4 MB */ | 27 | #define CEPH_BLOCK_SHIFT 22 /* 4 MB */ |
| @@ -317,6 +315,11 @@ struct ceph_inode_xattrs_info { · 287 unmodified lines | |||
| 317 | * Ceph inode. | 315 | * Ceph inode. |
| 318 | */ | 316 | */ |
| 319 | struct ceph_inode_info { | 317 | struct ceph_inode_info { |
| 318 | struct { | ||
| 319 | /* These must be contiguous */ | ||
| 320 | struct inode vfs_inode; | ||
| 321 | struct netfs_i_context netfs_ctx; /* Netfslib context */ | ||
| 322 | }; | ||
| 320 | struct ceph_vino i_vino; /* ceph ino + snap */ | 323 | struct ceph_vino i_vino; /* ceph ino + snap */ |
| 321 | 324 | ||
| 322 | spinlock_t i_ceph_lock; | 325 | spinlock_t i_ceph_lock; |
| @@ -427,11 +430,6 @@ struct ceph_inode_info { · 104 unmodified lines | |||
| 427 | 430 | ||
| 428 | struct work_struct i_work; | 431 | struct work_struct i_work; |
| 429 | unsigned long i_work_mask; | 432 | unsigned long i_work_mask; |
| 430 | |||
| 431 | #ifdef CONFIG_CEPH_FSCACHE | ||
| 432 | struct fscache_cookie *fscache; | ||
| 433 | #endif | ||
| 434 | struct inode vfs_inode; /* at end */ | ||
| 435 | }; | 433 | }; |
| 436 | 434 | ||
| 437 | static inline struct ceph_inode_info * | 435 | static inline struct ceph_inode_info * |
| @@ -1215,6 +1213,7 @@ extern void __ceph_touch_fmode(struct ceph_inode_info *ci, · 777 unmodified lines | |||
| 1215 | 1213 | ||
| 1216 | /* addr.c */ | 1214 | /* addr.c */ |
| 1217 | extern const struct address_space_operations ceph_aops; | 1215 | extern const struct address_space_operations ceph_aops; |
| 1216 | extern const struct netfs_request_ops ceph_netfs_ops; | ||
| 1218 | extern int ceph_mmap(struct file *file, struct vm_area_struct *vma); | 1217 | extern int ceph_mmap(struct file *file, struct vm_area_struct *vma); |
| 1219 | extern int ceph_uninline_data(struct file *file); | 1218 | extern int ceph_uninline_data(struct file *file); |
| 1220 | extern int ceph_pool_perm_check(struct inode *inode, int need); | 1219 | extern int ceph_pool_perm_check(struct inode *inode, int need); |
| @@ -16,6 +16,7 @@ · 15 unmodified lines | |||
| 16 | #include <linux/mempool.h> | 16 | #include <linux/mempool.h> |
| 17 | #include <linux/workqueue.h> | 17 | #include <linux/workqueue.h> |
| 18 | #include <linux/utsname.h> | 18 | #include <linux/utsname.h> |
| 19 | #include <linux/netfs.h> | ||
| 19 | #include "cifs_fs_sb.h" | 20 | #include "cifs_fs_sb.h" |
| 20 | #include "cifsacl.h" | 21 | #include "cifsacl.h" |
| 21 | #include <crypto/internal/hash.h> | 22 | #include <crypto/internal/hash.h> |
| @@ -1402,6 +1403,11 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file); · 1380 unmodified lines | |||
| 1402 | */ | 1403 | */ |
| 1403 | 1404 | ||
| 1404 | struct cifsInodeInfo { | 1405 | struct cifsInodeInfo { |
| 1406 | struct { | ||
| 1407 | /* These must be contiguous */ | ||
| 1408 | struct inode vfs_inode; /* the VFS's inode record */ | ||
| 1409 | struct netfs_i_context netfs_ctx; /* Netfslib context */ | ||
| 1410 | }; | ||
| 1405 | bool can_cache_brlcks; | 1411 | bool can_cache_brlcks; |
| 1406 | struct list_head llist; /* locks helb by this inode */ | 1412 | struct list_head llist; /* locks helb by this inode */ |
| 1407 | /* | 1413 | /* |
| @@ -1432,10 +1438,6 @@ struct cifsInodeInfo { · 24 unmodified lines | |||
| 1432 | u64 uniqueid; /* server inode number */ | 1438 | u64 uniqueid; /* server inode number */ |
| 1433 | u64 createtime; /* creation time on server */ | 1439 | u64 createtime; /* creation time on server */ |
| 1434 | __u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for this inode */ | 1440 | __u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for this inode */ |
| 1435 | #ifdef CONFIG_CIFS_FSCACHE | ||
| 1436 | struct fscache_cookie *fscache; | ||
| 1437 | #endif | ||
| 1438 | struct inode vfs_inode; | ||
| 1439 | struct list_head deferred_closes; /* list of deferred closes */ | 1441 | struct list_head deferred_closes; /* list of deferred closes */ |
| 1440 | spinlock_t deferred_lock; /* protection on deferred list */ | 1442 | spinlock_t deferred_lock; /* protection on deferred list */ |
| 1441 | bool lease_granted; /* Flag to indicate whether lease or oplock is granted. */ | 1443 | bool lease_granted; /* Flag to indicate whether lease or oplock is granted. */ |
| @@ -103,7 +103,7 @@ void cifs_fscache_get_inode_cookie(struct inode *inode) · 102 unmodified lines | |||
| 103 | 103 | ||
| 104 | cifs_fscache_fill_coherency(&cifsi->vfs_inode, &cd); | 104 | cifs_fscache_fill_coherency(&cifsi->vfs_inode, &cd); |
| 105 | 105 | ||
| 106 | cifsi->fscache = | 106 | cifsi->netfs_ctx.cache = |
| 107 | fscache_acquire_cookie(tcon->fscache, 0, | 107 | fscache_acquire_cookie(tcon->fscache, 0, |
| 108 | &cifsi->uniqueid, sizeof(cifsi->uniqueid), | 108 | &cifsi->uniqueid, sizeof(cifsi->uniqueid), |
| 109 | &cd, sizeof(cd), | 109 | &cd, sizeof(cd), |
| @@ -126,11 +126,12 @@ void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool update) · 16 unmodified lines | |||
| 126 | void cifs_fscache_release_inode_cookie(struct inode *inode) | 126 | void cifs_fscache_release_inode_cookie(struct inode *inode) |
| 127 | { | 127 | { |
| 128 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | 128 | struct cifsInodeInfo *cifsi = CIFS_I(inode); |
| 129 | struct fscache_cookie *cookie = cifs_inode_cookie(inode); | ||
| 129 | 130 | ||
| 130 | if (cifsi->fscache) { | 131 | if (cookie) { |
| 131 | cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cifsi->fscache); | 132 | cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cookie); |
| 132 | fscache_relinquish_cookie(cifsi->fscache, false); | 133 | fscache_relinquish_cookie(cookie, false); |
| 133 | cifsi->fscache = NULL; | 134 | cifsi->netfs_ctx.cache = NULL; |
| 134 | } | 135 | } |
| 135 | } | 136 | } |
| 136 | 137 | ||
| @@ -61,7 +61,7 @@ void cifs_fscache_fill_coherency(struct inode *inode, · 60 unmodified lines | |||
| 61 | 61 | ||
| 62 | static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode) | 62 | static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode) |
| 63 | { | 63 | { |
| 64 | return CIFS_I(inode)->fscache; | 64 | return netfs_i_cookie(inode); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | static inline void cifs_invalidate_cache(struct inode *inode, unsigned int flags) | 67 | static inline void cifs_invalidate_cache(struct inode *inode, unsigned int flags) |
| @@ -6,6 +6,7 @@ · 5 unmodified lines | |||
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include <linux/netfs.h> | 8 | #include <linux/netfs.h> |
| 9 | #include <linux/fscache.h> | ||
| 9 | #include <trace/events/netfs.h> | 10 | #include <trace/events/netfs.h> |
| 10 | 11 | ||
| 11 | #ifdef pr_fmt | 12 | #ifdef pr_fmt |
| @@ -19,8 +20,6 @@ · 7 unmodified lines | |||
| 19 | */ | 20 | */ |
| 20 | struct netfs_io_request *netfs_alloc_request(struct address_space *mapping, | 21 | struct netfs_io_request *netfs_alloc_request(struct address_space *mapping, |
| 21 | struct file *file, | 22 | struct file *file, |
| 22 | const struct netfs_request_ops *ops, | ||
| 23 | void *netfs_priv, | ||
| 24 | loff_t start, size_t len, | 23 | loff_t start, size_t len, |
| 25 | enum netfs_io_origin origin); | 24 | enum netfs_io_origin origin); |
| 26 | void netfs_get_request(struct netfs_io_request *rreq, enum netfs_rreq_ref_trace what); | 25 | void netfs_get_request(struct netfs_io_request *rreq, enum netfs_rreq_ref_trace what); |
| @@ -81,6 +80,21 @@ static inline void netfs_stat_d(atomic_t *stat) · 54 unmodified lines | |||
| 81 | #define netfs_stat_d(x) do {} while(0) | 80 | #define netfs_stat_d(x) do {} while(0) |
| 82 | #endif | 81 | #endif |
| 83 | 82 | ||
| 83 | /* | ||
| 84 | * Miscellaneous functions. | ||
| 85 | */ | ||
| 86 | static inline bool netfs_is_cache_enabled(struct netfs_i_context *ctx) | ||
| 87 | { | ||
| 88 | #if IS_ENABLED(CONFIG_FSCACHE) | ||
| 89 | struct fscache_cookie *cookie = ctx->cache; | ||
| 90 | |||
| 91 | return fscache_cookie_valid(cookie) && cookie->cache_priv && | ||
| 92 | fscache_cookie_enabled(cookie); | ||
| 93 | #else | ||
| 94 | return false; | ||
| 95 | #endif | ||
| 96 | } | ||
| 97 | |||
| 84 | /*****************************************************************************/ | 98 | /*****************************************************************************/ |
| 85 | /* | 99 | /* |
| 86 | * debug tracing | 100 | * debug tracing |
| @@ -13,12 +13,12 @@ · 12 unmodified lines | |||
| 13 | */ | 13 | */ |
| 14 | struct netfs_io_request *netfs_alloc_request(struct address_space *mapping, | 14 | struct netfs_io_request *netfs_alloc_request(struct address_space *mapping, |
| 15 | struct file *file, | 15 | struct file *file, |
| 16 | const struct netfs_request_ops *ops, | ||
| 17 | void *netfs_priv, | ||
| 18 | loff_t start, size_t len, | 16 | loff_t start, size_t len, |
| 19 | enum netfs_io_origin origin) | 17 | enum netfs_io_origin origin) |
| 20 | { | 18 | { |
| 21 | static atomic_t debug_ids; | 19 | static atomic_t debug_ids; |
| 20 | struct inode *inode = file ? file_inode(file) : mapping->host; | ||
| 21 | struct netfs_i_context *ctx = netfs_i_context(inode); | ||
| 22 | struct netfs_io_request *rreq; | 22 | struct netfs_io_request *rreq; |
| 23 | int ret; | 23 | int ret; |
| 24 | 24 | ||
| @@ -29,11 +29,10 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping, · 4 unmodified lines | |||
| 29 | rreq->start = start; | 29 | rreq->start = start; |
| 30 | rreq->len = len; | 30 | rreq->len = len; |
| 31 | rreq->origin = origin; | 31 | rreq->origin = origin; |
| 32 | rreq->netfs_ops = ops; | 32 | rreq->netfs_ops = ctx->ops; |
| 33 | rreq->netfs_priv = netfs_priv; | ||
| 34 | rreq->mapping = mapping; | 33 | rreq->mapping = mapping; |
| 35 | rreq->inode = file_inode(file); | 34 | rreq->inode = inode; |
| 36 | rreq->i_size = i_size_read(rreq->inode); | 35 | rreq->i_size = i_size_read(inode); |
| 37 | rreq->debug_id = atomic_inc_return(&debug_ids); | 36 | rreq->debug_id = atomic_inc_return(&debug_ids); |
| 38 | INIT_LIST_HEAD(&rreq->subrequests); | 37 | INIT_LIST_HEAD(&rreq->subrequests); |
| 39 | INIT_WORK(&rreq->work, netfs_rreq_work); | 38 | INIT_WORK(&rreq->work, netfs_rreq_work); |
| @@ -76,6 +75,7 @@ static void netfs_free_request(struct work_struct *work) · 36 unmodified lines | |||
| 76 | { | 75 | { |
| 77 | struct netfs_io_request *rreq = | 76 | struct netfs_io_request *rreq = |
| 78 | container_of(work, struct netfs_io_request, work); | 77 | container_of(work, struct netfs_io_request, work); |
| 78 | |||
| 79 | netfs_clear_subrequests(rreq, false); | 79 | netfs_clear_subrequests(rreq, false); |
| 80 | if (rreq->netfs_priv) | 80 | if (rreq->netfs_priv) |
| 81 | rreq->netfs_ops->cleanup(rreq->mapping, rreq->netfs_priv); | 81 | rreq->netfs_ops->cleanup(rreq->mapping, rreq->netfs_priv); |
| @@ -14,7 +14,6 @@ · 13 unmodified lines | |||
| 14 | #include <linux/uio.h> | 14 | #include <linux/uio.h> |
| 15 | #include <linux/sched/mm.h> | 15 | #include <linux/sched/mm.h> |
| 16 | #include <linux/task_io_accounting_ops.h> | 16 | #include <linux/task_io_accounting_ops.h> |
| 17 | #include <linux/netfs.h> | ||
| 18 | #include "internal.h" | 17 | #include "internal.h" |
| 19 | #define CREATE_TRACE_POINTS | 18 | #define CREATE_TRACE_POINTS |
| 20 | #include <trace/events/netfs.h> | 19 | #include <trace/events/netfs.h> |
| @@ -735,8 +734,6 @@ static void netfs_rreq_expand(struct netfs_io_request *rreq, · 714 unmodified lines | |||
| 735 | /** | 734 | /** |
| 736 | * netfs_readahead - Helper to manage a read request | 735 | * netfs_readahead - Helper to manage a read request |
| 737 | * @ractl: The description of the readahead request | 736 | * @ractl: The description of the readahead request |
| 738 | * @ops: The network filesystem's operations for the helper to use | ||
| 739 | * @netfs_priv: Private netfs data to be retained in the request | ||
| 740 | * | 737 | * |
| 741 | * Fulfil a readahead request by drawing data from the cache if possible, or | 738 | * Fulfil a readahead request by drawing data from the cache if possible, or |
| 742 | * the netfs if not. Space beyond the EOF is zero-filled. Multiple I/O | 739 | * the netfs if not. Space beyond the EOF is zero-filled. Multiple I/O |
| @@ -744,35 +741,32 @@ static void netfs_rreq_expand(struct netfs_io_request *rreq, · 1 unmodified line | |||
| 744 | * readahead window can be expanded in either direction to a more convenient | 741 | * readahead window can be expanded in either direction to a more convenient |
| 745 | * alighment for RPC efficiency or to make storage in the cache feasible. | 742 | * alighment for RPC efficiency or to make storage in the cache feasible. |
| 746 | * | 743 | * |
| 747 | * The calling netfs must provide a table of operations, only one of which, | 744 | * The calling netfs must initialise a netfs context contiguous to the vfs |
| 748 | * issue_op, is mandatory. It may also be passed a private token, which will | 745 | * inode before calling this. |
| 749 | * be retained in rreq->netfs_priv and will be cleaned up by ops->cleanup(). | ||
| 750 | * | 746 | * |
| 751 | * This is usable whether or not caching is enabled. | 747 | * This is usable whether or not caching is enabled. |
| 752 | */ | 748 | */ |
| 753 | void netfs_readahead(struct readahead_control *ractl, | 749 | void netfs_readahead(struct readahead_control *ractl) |
| 754 | const struct netfs_request_ops *ops, | ||
| 755 | void *netfs_priv) | ||
| 756 | { | 750 | { |
| 757 | struct netfs_io_request *rreq; | 751 | struct netfs_io_request *rreq; |
| 752 | struct netfs_i_context *ctx = netfs_i_context(ractl->mapping->host); | ||
| 758 | unsigned int debug_index = 0; | 753 | unsigned int debug_index = 0; |
| 759 | int ret; | 754 | int ret; |
| 760 | 755 | ||
| 761 | _enter("%lx,%x", readahead_index(ractl), readahead_count(ractl)); | 756 | _enter("%lx,%x", readahead_index(ractl), readahead_count(ractl)); |
| 762 | 757 | ||
| 763 | if (readahead_count(ractl) == 0) | 758 | if (readahead_count(ractl) == 0) |
| 764 | goto cleanup; | 759 | return; |
| 765 | 760 | ||
| 766 | rreq = netfs_alloc_request(ractl->mapping, ractl->file, | 761 | rreq = netfs_alloc_request(ractl->mapping, ractl->file, |
| 767 | ops, netfs_priv, | ||
| 768 | readahead_pos(ractl), | 762 | readahead_pos(ractl), |
| 769 | readahead_length(ractl), | 763 | readahead_length(ractl), |
| 770 | NETFS_READAHEAD); | 764 | NETFS_READAHEAD); |
| 771 | if (IS_ERR(rreq)) | 765 | if (IS_ERR(rreq)) |
| 772 | goto cleanup; | 766 | return; |
| 773 | 767 | ||
| 774 | if (ops->begin_cache_operation) { | 768 | if (ctx->ops->begin_cache_operation) { |
| 775 | ret = ops->begin_cache_operation(rreq); | 769 | ret = ctx->ops->begin_cache_operation(rreq); |
| 776 | if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS) | 770 | if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS) |
| 777 | goto cleanup_free; | 771 | goto cleanup_free; |
| 778 | } | 772 | } |
| @@ -804,42 +798,35 @@ void netfs_readahead(struct readahead_control *ractl, · 25 unmodified lines | |||
| 804 | cleanup_free: | 798 | cleanup_free: |
| 805 | netfs_put_request(rreq, false, netfs_rreq_trace_put_failed); | 799 | netfs_put_request(rreq, false, netfs_rreq_trace_put_failed); |
| 806 | return; | 800 | return; |
| 807 | cleanup: | ||
| 808 | if (netfs_priv) | ||
| 809 | ops->cleanup(ractl->mapping, netfs_priv); | ||
| 810 | return; | ||
| 811 | } | 801 | } |
| 812 | EXPORT_SYMBOL(netfs_readahead); | 802 | EXPORT_SYMBOL(netfs_readahead); |
| 813 | 803 | ||
| 814 | /** | 804 | /** |
| 815 | * netfs_readpage - Helper to manage a readpage request | 805 | * netfs_readpage - Helper to manage a readpage request |
| 816 | * @file: The file to read from | 806 | * @file: The file to read from |
| 817 | * @folio: The folio to read | 807 | * @subpage: A subpage of the folio to read |
| 818 | * @ops: The network filesystem's operations for the helper to use | ||
| 819 | * @netfs_priv: Private netfs data to be retained in the request | ||
| 820 | * | 808 | * |
| 821 | * Fulfil a readpage request by drawing data from the cache if possible, or the | 809 | * Fulfil a readpage request by drawing data from the cache if possible, or the |
| 822 | * netfs if not. Space beyond the EOF is zero-filled. Multiple I/O requests | 810 | * netfs if not. Space beyond the EOF is zero-filled. Multiple I/O requests |
| 823 | * from different sources will get munged together. | 811 | * from different sources will get munged together. |
| 824 | * | 812 | * |
| 825 | * The calling netfs must provide a table of operations, only one of which, | 813 | * The calling netfs must initialise a netfs context contiguous to the vfs |
| 826 | * issue_op, is mandatory. It may also be passed a private token, which will | 814 | * inode before calling this. |
| 827 | * be retained in rreq->netfs_priv and will be cleaned up by ops->cleanup(). | ||
| 828 | * | 815 | * |
| 829 | * This is usable whether or not caching is enabled. | 816 | * This is usable whether or not caching is enabled. |
| 830 | */ | 817 | */ |
| 831 | int netfs_readpage(struct file *file, | 818 | int netfs_readpage(struct file *file, struct page *subpage) |
| 832 | struct folio *folio, | ||
| 833 | const struct netfs_request_ops *ops, | ||
| 834 | void *netfs_priv) | ||
| 835 | { | 819 | { |
| 820 | struct folio *folio = page_folio(subpage); | ||
| 821 | struct address_space *mapping = folio->mapping; | ||
| 836 | struct netfs_io_request *rreq; | 822 | struct netfs_io_request *rreq; |
| 823 | struct netfs_i_context *ctx = netfs_i_context(mapping->host); | ||
| 837 | unsigned int debug_index = 0; | 824 | unsigned int debug_index = 0; |
| 838 | int ret; | 825 | int ret; |
| 839 | 826 | ||
| 840 | _enter("%lx", folio_index(folio)); | 827 | _enter("%lx", folio_index(folio)); |
| 841 | 828 | ||
| 842 | rreq = netfs_alloc_request(folio->mapping, file, ops, netfs_priv, | 829 | rreq = netfs_alloc_request(mapping, file, |
| 843 | folio_file_pos(folio), folio_size(folio), | 830 | folio_file_pos(folio), folio_size(folio), |
| 844 | NETFS_READPAGE); | 831 | NETFS_READPAGE); |
| 845 | if (IS_ERR(rreq)) { | 832 | if (IS_ERR(rreq)) { |
| @@ -847,8 +834,8 @@ int netfs_readpage(struct file *file, · 1 unmodified line | |||
| 847 | goto alloc_error; | 834 | goto alloc_error; |
| 848 | } | 835 | } |
| 849 | 836 | ||
| 850 | if (ops->begin_cache_operation) { | 837 | if (ctx->ops->begin_cache_operation) { |
| 851 | ret = ops->begin_cache_operation(rreq); | 838 | ret = ctx->ops->begin_cache_operation(rreq); |
| 852 | if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS) { | 839 | if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS) { |
| 853 | folio_unlock(folio); | 840 | folio_unlock(folio); |
| 854 | goto out; | 841 | goto out; |
| @@ -886,8 +873,6 @@ out: · 31 unmodified lines | |||
| 886 | netfs_put_request(rreq, false, netfs_rreq_trace_put_hold); | 873 | netfs_put_request(rreq, false, netfs_rreq_trace_put_hold); |
| 887 | return ret; | 874 | return ret; |
| 888 | alloc_error: | 875 | alloc_error: |
| 889 | if (netfs_priv) | ||
| 890 | ops->cleanup(folio_file_mapping(folio), netfs_priv); | ||
| 891 | folio_unlock(folio); | 876 | folio_unlock(folio); |
| 892 | return ret; | 877 | return ret; |
| 893 | } | 878 | } |
| @@ -898,6 +883,7 @@ EXPORT_SYMBOL(netfs_readpage); · 4 unmodified lines | |||
| 898 | * @folio: The folio being prepared | 883 | * @folio: The folio being prepared |
| 899 | * @pos: starting position for the write | 884 | * @pos: starting position for the write |
| 900 | * @len: length of write | 885 | * @len: length of write |
| 886 | * @always_fill: T if the folio should always be completely filled/cleared | ||
| 901 | * | 887 | * |
| 902 | * In some cases, write_begin doesn't need to read at all: | 888 | * In some cases, write_begin doesn't need to read at all: |
| 903 | * - full folio write | 889 | * - full folio write |
| @@ -907,17 +893,27 @@ EXPORT_SYMBOL(netfs_readpage); · 3 unmodified lines | |||
| 907 | * If any of these criteria are met, then zero out the unwritten parts | 893 | * If any of these criteria are met, then zero out the unwritten parts |
| 908 | * of the folio and return true. Otherwise, return false. | 894 | * of the folio and return true. Otherwise, return false. |
| 909 | */ | 895 | */ |
| 910 | static bool netfs_skip_folio_read(struct folio *folio, loff_t pos, size_t len) | 896 | static bool netfs_skip_folio_read(struct folio *folio, loff_t pos, size_t len, |
| 897 | bool always_fill) | ||
| 911 | { | 898 | { |
| 912 | struct inode *inode = folio_inode(folio); | 899 | struct inode *inode = folio_inode(folio); |
| 913 | loff_t i_size = i_size_read(inode); | 900 | loff_t i_size = i_size_read(inode); |
| 914 | size_t offset = offset_in_folio(folio, pos); | 901 | size_t offset = offset_in_folio(folio, pos); |
| 902 | size_t plen = folio_size(folio); | ||
| 903 | |||
| 904 | if (unlikely(always_fill)) { | ||
| 905 | if (pos - offset + len <= i_size) | ||
| 906 | return false; /* Page entirely before EOF */ | ||
| 907 | zero_user_segment(&folio->page, 0, plen); | ||
| 908 | folio_mark_uptodate(folio); | ||
| 909 | return true; | ||
| 910 | } | ||
| 915 | 911 | ||
| 916 | /* Full folio write */ | 912 | /* Full folio write */ |
| 917 | if (offset == 0 && len >= folio_size(folio)) | 913 | if (offset == 0 && len >= plen) |
| 918 | return true; | 914 | return true; |
| 919 | 915 | ||
| 920 | /* pos beyond last folio in the file */ | 916 | /* Page entirely beyond the end of the file */ |
| 921 | if (pos - offset >= i_size) | 917 | if (pos - offset >= i_size) |
| 922 | goto zero_out; | 918 | goto zero_out; |
| 923 | 919 | ||
| @@ -927,7 +923,7 @@ static bool netfs_skip_folio_read(struct folio *folio, loff_t pos, size_t len) · 3 unmodified lines | |||
| 927 | 923 | ||
| 928 | return false; | 924 | return false; |
| 929 | zero_out: | 925 | zero_out: |
| 930 | zero_user_segments(&folio->page, 0, offset, offset + len, folio_size(folio)); | 926 | zero_user_segments(&folio->page, 0, offset, offset + len, plen); |
| 931 | return true; | 927 | return true; |
| 932 | } | 928 | } |
| 933 | 929 | ||
| @@ -940,8 +936,6 @@ zero_out: · 6 unmodified lines | |||
| 940 | * @aop_flags: AOP_* flags | 936 | * @aop_flags: AOP_* flags |
| 941 | * @_folio: Where to put the resultant folio | 937 | * @_folio: Where to put the resultant folio |
| 942 | * @_fsdata: Place for the netfs to store a cookie | 938 | * @_fsdata: Place for the netfs to store a cookie |
| 943 | * @ops: The network filesystem's operations for the helper to use | ||
| 944 | * @netfs_priv: Private netfs data to be retained in the request | ||
| 945 | * | 939 | * |
| 946 | * Pre-read data for a write-begin request by drawing data from the cache if | 940 | * Pre-read data for a write-begin request by drawing data from the cache if |
| 947 | * possible, or the netfs if not. Space beyond the EOF is zero-filled. | 941 | * possible, or the netfs if not. Space beyond the EOF is zero-filled. |
| @@ -960,17 +954,18 @@ zero_out: · 12 unmodified lines | |||
| 960 | * should go ahead; unlock the folio and return -EAGAIN to cause the folio to | 954 | * should go ahead; unlock the folio and return -EAGAIN to cause the folio to |
| 961 | * be regot; or return an error. | 955 | * be regot; or return an error. |
| 962 | * | 956 | * |
| 957 | * The calling netfs must initialise a netfs context contiguous to the vfs | ||
| 958 | * inode before calling this. | ||
| 959 | * | ||
| 963 | * This is usable whether or not caching is enabled. | 960 | * This is usable whether or not caching is enabled. |
| 964 | */ | 961 | */ |
| 965 | int netfs_write_begin(struct file *file, struct address_space *mapping, | 962 | int netfs_write_begin(struct file *file, struct address_space *mapping, |
| 966 | loff_t pos, unsigned int len, unsigned int aop_flags, | 963 | loff_t pos, unsigned int len, unsigned int aop_flags, |
| 967 | struct folio **_folio, void **_fsdata, | 964 | struct folio **_folio, void **_fsdata) |
| 968 | const struct netfs_request_ops *ops, | ||
| 969 | void *netfs_priv) | ||
| 970 | { | 965 | { |
| 971 | struct netfs_io_request *rreq; | 966 | struct netfs_io_request *rreq; |
| 967 | struct netfs_i_context *ctx = netfs_i_context(file_inode(file )); | ||
| 972 | struct folio *folio; | 968 | struct folio *folio; |
| 973 | struct inode *inode = file_inode(file); | ||
| 974 | unsigned int debug_index = 0, fgp_flags; | 969 | unsigned int debug_index = 0, fgp_flags; |
| 975 | pgoff_t index = pos >> PAGE_SHIFT; | 970 | pgoff_t index = pos >> PAGE_SHIFT; |
| 976 | int ret; | 971 | int ret; |
| @@ -986,9 +981,9 @@ retry: · 9 unmodified lines | |||
| 986 | if (!folio) | 981 | if (!folio) |
| 987 | return -ENOMEM; | 982 | return -ENOMEM; |
| 988 | 983 | ||
| 989 | if (ops->check_write_begin) { | 984 | if (ctx->ops->check_write_begin) { |
| 990 | /* Allow the netfs (eg. ceph) to flush conflicts. */ | 985 | /* Allow the netfs (eg. ceph) to flush conflicts. */ |
| 991 | ret = ops->check_write_begin(file, pos, len, folio, _fsdata); | 986 | ret = ctx->ops->check_write_begin(file, pos, len, folio, _fsdata); |
| 992 | if (ret < 0) { | 987 | if (ret < 0) { |
| 993 | trace_netfs_failure(NULL, NULL, ret, netfs_fail_check_write_begin); | 988 | trace_netfs_failure(NULL, NULL, ret, netfs_fail_check_write_begin); |
| 994 | if (ret == -EAGAIN) | 989 | if (ret == -EAGAIN) |
| @@ -1004,13 +999,13 @@ retry: · 9 unmodified lines | |||
| 1004 | * within the cache granule containing the EOF, in which case we need | 999 | * within the cache granule containing the EOF, in which case we need |
| 1005 | * to preload the granule. | 1000 | * to preload the granule. |
| 1006 | */ | 1001 | */ |
| 1007 | if (!ops->is_cache_enabled(inode) && | 1002 | if (!netfs_is_cache_enabled(ctx) && |
| 1008 | netfs_skip_folio_read(folio, pos, len)) { | 1003 | netfs_skip_folio_read(folio, pos, len, false)) { |
| 1009 | netfs_stat(&netfs_n_rh_write_zskip); | 1004 | netfs_stat(&netfs_n_rh_write_zskip); |
| 1010 | goto have_folio_no_wait; | 1005 | goto have_folio_no_wait; |
| 1011 | } | 1006 | } |
| 1012 | 1007 | ||
| 1013 | rreq = netfs_alloc_request(mapping, file, ops, netfs_priv, | 1008 | rreq = netfs_alloc_request(mapping, file, |
| 1014 | folio_file_pos(folio), folio_size(folio), | 1009 | folio_file_pos(folio), folio_size(folio), |
| 1015 | NETFS_READ_FOR_WRITE); | 1010 | NETFS_READ_FOR_WRITE); |
| 1016 | if (IS_ERR(rreq)) { | 1011 | if (IS_ERR(rreq)) { |
| @@ -1019,10 +1014,9 @@ retry: · 2 unmodified lines | |||
| 1019 | } | 1014 | } |
| 1020 | rreq->no_unlock_folio = folio_index(folio); | 1015 | rreq->no_unlock_folio = folio_index(folio); |
| 1021 | __set_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, &rreq->flags); | 1016 | __set_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, &rreq->flags); |
| 1022 | netfs_priv = NULL; | ||
| 1023 | 1017 | ||
| 1024 | if (ops->begin_cache_operation) { | 1018 | if (ctx->ops->begin_cache_operation) { |
| 1025 | ret = ops->begin_cache_operation(rreq); | 1019 | ret = ctx->ops->begin_cache_operation(rreq); |
| 1026 | if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS) | 1020 | if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS) |
| 1027 | goto error_put; | 1021 | goto error_put; |
| 1028 | } | 1022 | } |
| @@ -1076,8 +1070,6 @@ have_folio: · 47 unmodified lines | |||
| 1076 | if (ret < 0) | 1070 | if (ret < 0) |
| 1077 | goto error; | 1071 | goto error; |
| 1078 | have_folio_no_wait: | 1072 | have_folio_no_wait: |
| 1079 | if (netfs_priv) | ||
| 1080 | ops->cleanup(mapping, netfs_priv); | ||
| 1081 | *_folio = folio; | 1073 | *_folio = folio; |
| 1082 | _leave(" = 0"); | 1074 | _leave(" = 0"); |
| 1083 | return 0; | 1075 | return 0; |
| @@ -1087,8 +1079,6 @@ error_put: · 3 unmodified lines | |||
| 1087 | error: | 1079 | error: |
| 1088 | folio_unlock(folio); | 1080 | folio_unlock(folio); |
| 1089 | folio_put(folio); | 1081 | folio_put(folio); |
| 1090 | if (netfs_priv) | ||
| 1091 | ops->cleanup(mapping, netfs_priv); | ||
| 1092 | _leave(" = %d", ret); | 1082 | _leave(" = %d", ret); |
| 1093 | return ret; | 1083 | return ret; |
| 1094 | } | 1084 | } |
| @@ -7,7 +7,6 @@ · 6 unmodified lines | |||
| 7 | 7 | ||
| 8 | #include <linux/export.h> | 8 | #include <linux/export.h> |
| 9 | #include <linux/seq_file.h> | 9 | #include <linux/seq_file.h> |
| 10 | #include <linux/netfs.h> | ||
| 11 | #include "internal.h" | 10 | #include "internal.h" |
| 12 | 11 | ||
| 13 | atomic_t netfs_n_rh_readahead; | 12 | atomic_t netfs_n_rh_readahead; |
| @@ -118,6 +118,16 @@ enum netfs_io_source { · 117 unmodified lines | |||
| 118 | typedef void (*netfs_io_terminated_t)(void *priv, ssize_t transferred_or_error, | 118 | typedef void (*netfs_io_terminated_t)(void *priv, ssize_t transferred_or_error, |
| 119 | bool was_async); | 119 | bool was_async); |
| 120 | 120 | ||
| 121 | /* | ||
| 122 | * Per-inode description. This must be directly after the inode struct. | ||
| 123 | */ | ||
| 124 | struct netfs_i_context { | ||
| 125 | const struct netfs_request_ops *ops; | ||
| 126 | #if IS_ENABLED(CONFIG_FSCACHE) | ||
| 127 | struct fscache_cookie *cache; | ||
| 128 | #endif | ||
| 129 | }; | ||
| 130 | |||
| 121 | /* | 131 | /* |
| 122 | * Resources required to do operations on a cache. | 132 | * Resources required to do operations on a cache. |
| 123 | */ | 133 | */ |
| @@ -192,7 +202,6 @@ struct netfs_io_request { · 68 unmodified lines | |||
| 192 | * Operations the network filesystem can/must provide to the helpers. | 202 | * Operations the network filesystem can/must provide to the helpers. |
| 193 | */ | 203 | */ |
| 194 | struct netfs_request_ops { | 204 | struct netfs_request_ops { |
| 195 | bool (*is_cache_enabled)(struct inode *inode); | ||
| 196 | int (*init_request)(struct netfs_io_request *rreq, struct file *file); | 205 | int (*init_request)(struct netfs_io_request *rreq, struct file *file); |
| 197 | int (*begin_cache_operation)(struct netfs_io_request *rreq); | 206 | int (*begin_cache_operation)(struct netfs_io_request *rreq); |
| 198 | void (*expand_readahead)(struct netfs_io_request *rreq); | 207 | void (*expand_readahead)(struct netfs_io_request *rreq); |
| @@ -263,18 +272,11 @@ struct netfs_cache_ops { · 64 unmodified lines | |||
| 263 | }; | 272 | }; |
| 264 | 273 | ||
| 265 | struct readahead_control; | 274 | struct readahead_control; |
| 266 | extern void netfs_readahead(struct readahead_control *, | 275 | extern void netfs_readahead(struct readahead_control *); |
| 267 | const struct netfs_request_ops *, | 276 | extern int netfs_readpage(struct file *, struct page *); |
| 268 | void *); | ||
| 269 | extern int netfs_readpage(struct file *, | ||
| 270 | struct folio *, | ||
| 271 | const struct netfs_request_ops *, | ||
| 272 | void *); | ||
| 273 | extern int netfs_write_begin(struct file *, struct address_space *, | 277 | extern int netfs_write_begin(struct file *, struct address_space *, |
| 274 | loff_t, unsigned int, unsigned int, struct folio **, | 278 | loff_t, unsigned int, unsigned int, struct folio **, |
| 275 | void **, | 279 | void **); |
| 276 | const struct netfs_request_ops *, | ||
| 277 | void *); | ||
| 278 | 280 | ||
| 279 | extern void netfs_subreq_terminated(struct netfs_io_subrequest *, ssize_t, bool); | 281 | extern void netfs_subreq_terminated(struct netfs_io_subrequest *, ssize_t, bool); |
| 280 | extern void netfs_get_subrequest(struct netfs_io_subrequest *subreq, | 282 | extern void netfs_get_subrequest(struct netfs_io_subrequest *subreq, |
| @@ -283,4 +285,61 @@ extern void netfs_put_subrequest(struct netfs_io_subrequest *subreq, · 2 unmodified lines | |||
| 283 | bool was_async, enum netfs_sreq_ref_trace what); | 285 | bool was_async, enum netfs_sreq_ref_trace what); |
| 284 | extern void netfs_stats_show(struct seq_file *); | 286 | extern void netfs_stats_show(struct seq_file *); |
| 285 | 287 | ||
| 288 | /** | ||
| 289 | * netfs_i_context - Get the netfs inode context from the inode | ||
| 290 | * @inode: The inode to query | ||
| 291 | * | ||
| 292 | * Get the netfs lib inode context from the network filesystem's inode. The | ||
| 293 | * context struct is expected to directly follow on from the VFS inode struct. | ||
| 294 | */ | ||
| 295 | static inline struct netfs_i_context *netfs_i_context(struct inode *inode) | ||
| 296 | { | ||
| 297 | return (struct netfs_i_context *)(inode + 1); | ||
| 298 | } | ||
| 299 | |||
| 300 | /** | ||
| 301 | * netfs_inode - Get the netfs inode from the inode context | ||
| 302 | * @ctx: The context to query | ||
| 303 | * | ||
| 304 | * Get the netfs inode from the netfs library's inode context. The VFS inode | ||
| 305 | * is expected to directly precede the context struct. | ||
| 306 | */ | ||
| 307 | static inline struct inode *netfs_inode(struct netfs_i_context *ctx) | ||
| 308 | { | ||
| 309 | return ((struct inode *)ctx) - 1; | ||
| 310 | } | ||
| 311 | |||
| 312 | /** | ||
| 313 | * netfs_i_context_init - Initialise a netfs lib context | ||
| 314 | * @inode: The inode with which the context is associated | ||
| 315 | * @ops: The netfs's operations list | ||
| 316 | * | ||
| 317 | * Initialise the netfs library context struct. This is expected to follow on | ||
| 318 | * directly from the VFS inode struct. | ||
| 319 | */ | ||
| 320 | static inline void netfs_i_context_init(struct inode *inode, | ||
| 321 | const struct netfs_request_ops *ops) | ||
| 322 | { | ||
| 323 | struct netfs_i_context *ctx = netfs_i_context(inode); | ||
| 324 | |||
| 325 | memset(ctx, 0, sizeof(*ctx)); | ||
| 326 | ctx->ops = ops; | ||
| 327 | } | ||
| 328 | |||
| 329 | /** | ||
| 330 | * netfs_i_cookie - Get the cache cookie from the inode | ||
| 331 | * @inode: The inode to query | ||
| 332 | * | ||
| 333 | * Get the caching cookie (if enabled) from the network filesystem's inode. | ||
| 334 | */ | ||
| 335 | static inline struct fscache_cookie *netfs_i_cookie(struct inode *inode) | ||
| 336 | { | ||
| 337 | #if IS_ENABLED(CONFIG_FSCACHE) | ||
| 338 | struct netfs_i_context *ctx = netfs_i_context(inode); | ||
| 339 | return ctx->cache; | ||
| 340 | #else | ||
| 341 | return NULL; | ||
| 342 | #endif | ||
| 343 | } | ||
| 344 | |||
| 286 | #endif /* _LINUX_NETFS_H */ | 345 | #endif /* _LINUX_NETFS_H */ |