mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-01 00:58:39 +02:00 
			
		
		
		
	netfs: Add a netfs inode context
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
			
			
This commit is contained in:
		
							parent
							
								
									a5c9dc4451
								
							
						
					
					
						commit
						bc899ee1c8
					
				
					 25 changed files with 318 additions and 278 deletions
				
			
		|  | @ -7,6 +7,8 @@ Network Filesystem Helper Library | ||||||
| .. Contents: | .. Contents: | ||||||
| 
 | 
 | ||||||
|  - Overview. |  - Overview. | ||||||
|  |  - Per-inode context. | ||||||
|  |    - Inode context helper functions. | ||||||
|  - Buffered read helpers. |  - Buffered read helpers. | ||||||
|    - Read helper functions. |    - Read helper functions. | ||||||
|    - Read helper structures. |    - Read helper structures. | ||||||
|  | @ -28,6 +30,69 @@ Note that the library module doesn't link against local caching directly, so | ||||||
| access must be provided by the netfs. | 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 | Buffered Read Helpers | ||||||
| ===================== | ===================== | ||||||
| 
 | 
 | ||||||
|  | @ -70,38 +135,22 @@ Read Helper Functions | ||||||
| 
 | 
 | ||||||
| Three read helpers are provided:: | Three read helpers are provided:: | ||||||
| 
 | 
 | ||||||
| 	void netfs_readahead(struct readahead_control *ractl, | 	void netfs_readahead(struct readahead_control *ractl); | ||||||
| 			     const struct netfs_request_ops *ops, |  | ||||||
| 			     void *netfs_priv); |  | ||||||
| 	int netfs_readpage(struct file *file, | 	int netfs_readpage(struct file *file, | ||||||
| 			   struct folio *folio, | 			   struct page *page); | ||||||
| 			   const struct netfs_request_ops *ops, |  | ||||||
| 			   void *netfs_priv); |  | ||||||
| 	int netfs_write_begin(struct file *file, | 	int netfs_write_begin(struct file *file, | ||||||
| 			      struct address_space *mapping, | 			      struct address_space *mapping, | ||||||
| 			      loff_t pos, | 			      loff_t pos, | ||||||
| 			      unsigned int len, | 			      unsigned int len, | ||||||
| 			      unsigned int flags, | 			      unsigned int flags, | ||||||
| 			      struct folio **_folio, | 			      struct folio **_folio, | ||||||
| 			      void **_fsdata, | 			      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 | Each corresponds to a VM address space operation.  These operations use the | ||||||
| for the use of the read helpers: | state in the per-inode context. | ||||||
| 
 | 
 | ||||||
|  * ``ops`` | For ->readahead() and ->readpage(), the network filesystem just point directly | ||||||
| 
 | at the corresponding read helper; whereas for ->write_begin(), it may be a | ||||||
|    A table of operations through which the helpers can talk to the filesystem. |  | ||||||
| 
 |  | ||||||
|  * ``netfs_priv`` |  | ||||||
| 
 |  | ||||||
|    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 |  | ||||||
| little more complicated as the network filesystem might want to flush | 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 | conflicting writes or track dirty data and needs to put the acquired folio if | ||||||
| an error occurs after calling the helper. | an error occurs after calling the helper. | ||||||
|  | @ -246,7 +295,6 @@ through which it can issue requests and negotiate:: | ||||||
| 
 | 
 | ||||||
| 	struct netfs_request_ops { | 	struct netfs_request_ops { | ||||||
| 		void (*init_request)(struct netfs_io_request *rreq, struct file *file); | 		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); | 		int (*begin_cache_operation)(struct netfs_io_request *rreq); | ||||||
| 		void (*expand_readahead)(struct netfs_io_request *rreq); | 		void (*expand_readahead)(struct netfs_io_request *rreq); | ||||||
| 		bool (*clamp_length)(struct netfs_io_subrequest *subreq); | 		bool (*clamp_length)(struct netfs_io_subrequest *subreq); | ||||||
|  | @ -265,11 +313,6 @@ The operations are as follows: | ||||||
|    [Optional] This is called to initialise the request structure.  It is given |    [Optional] This is called to initialise the request structure.  It is given | ||||||
|    the file for reference and can modify the ->netfs_priv value. |    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()`` |  * ``begin_cache_operation()`` | ||||||
| 
 | 
 | ||||||
|    [Optional] This is called to ask the network filesystem to call into the |    [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, | ||||||
| 
 | 
 | ||||||
| void v9fs_cache_inode_get_cookie(struct inode *inode) | 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; | 	struct v9fs_session_info *v9ses; | ||||||
| 	__le32 version; | 	__le32 version; | ||||||
| 	__le64 path; | 	__le64 path; | ||||||
| 
 | 
 | ||||||
| 	if (!S_ISREG(inode->i_mode)) | 	if (!S_ISREG(inode->i_mode)) | ||||||
| 		return; | 		return; | ||||||
| 
 | 	if (WARN_ON(v9fs_inode_cookie(v9inode))) | ||||||
| 	v9inode = V9FS_I(inode); |  | ||||||
| 	if (WARN_ON(v9inode->fscache)) |  | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	version = cpu_to_le32(v9inode->qid.version); | 	version = cpu_to_le32(v9inode->qid.version); | ||||||
| 	path = cpu_to_le64(v9inode->qid.path); | 	path = cpu_to_le64(v9inode->qid.path); | ||||||
| 	v9ses = v9fs_inode2v9ses(inode); | 	v9ses = v9fs_inode2v9ses(inode); | ||||||
| 	v9inode->fscache = | 	v9inode->netfs_ctx.cache = | ||||||
| 		fscache_acquire_cookie(v9fs_session_cache(v9ses), | 		fscache_acquire_cookie(v9fs_session_cache(v9ses), | ||||||
| 				       0, | 				       0, | ||||||
| 				       &path, sizeof(path), | 				       &path, sizeof(path), | ||||||
|  | @ -72,5 +70,5 @@ void v9fs_cache_inode_get_cookie(struct inode *inode) | ||||||
| 				       i_size_read(&v9inode->vfs_inode)); | 				       i_size_read(&v9inode->vfs_inode)); | ||||||
| 
 | 
 | ||||||
| 	p9_debug(P9_DEBUG_FSC, "inode %p get cookie %p\n", | 	p9_debug(P9_DEBUG_FSC, "inode %p get cookie %p\n", | ||||||
| 		 inode, v9inode->fscache); | 		 inode, v9fs_inode_cookie(v9inode)); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -623,9 +623,7 @@ static void v9fs_sysfs_cleanup(void) | ||||||
| static void v9fs_inode_init_once(void *foo) | static void v9fs_inode_init_once(void *foo) | ||||||
| { | { | ||||||
| 	struct v9fs_inode *v9inode = (struct v9fs_inode *)foo; | 	struct v9fs_inode *v9inode = (struct v9fs_inode *)foo; | ||||||
| #ifdef CONFIG_9P_FSCACHE | 
 | ||||||
| 	v9inode->fscache = NULL; |  | ||||||
| #endif |  | ||||||
| 	memset(&v9inode->qid, 0, sizeof(v9inode->qid)); | 	memset(&v9inode->qid, 0, sizeof(v9inode->qid)); | ||||||
| 	inode_init_once(&v9inode->vfs_inode); | 	inode_init_once(&v9inode->vfs_inode); | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										13
									
								
								fs/9p/v9fs.h
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								fs/9p/v9fs.h
									
									
									
									
									
								
							|  | @ -9,6 +9,7 @@ | ||||||
| #define FS_9P_V9FS_H | #define FS_9P_V9FS_H | ||||||
| 
 | 
 | ||||||
| #include <linux/backing-dev.h> | #include <linux/backing-dev.h> | ||||||
|  | #include <linux/netfs.h> | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * enum p9_session_flags - option flags for each 9P session |  * enum p9_session_flags - option flags for each 9P session | ||||||
|  | @ -108,14 +109,15 @@ struct v9fs_session_info { | ||||||
| #define V9FS_INO_INVALID_ATTR 0x01 | #define V9FS_INO_INVALID_ATTR 0x01 | ||||||
| 
 | 
 | ||||||
| struct v9fs_inode { | struct v9fs_inode { | ||||||
| #ifdef CONFIG_9P_FSCACHE | 	struct { | ||||||
| 	struct fscache_cookie *fscache; | 		/* These must be contiguous */ | ||||||
| #endif | 		struct inode	vfs_inode;	/* the VFS's inode record */ | ||||||
|  | 		struct netfs_i_context netfs_ctx; /* Netfslib context */ | ||||||
|  | 	}; | ||||||
| 	struct p9_qid qid; | 	struct p9_qid qid; | ||||||
| 	unsigned int cache_validity; | 	unsigned int cache_validity; | ||||||
| 	struct p9_fid *writeback_fid; | 	struct p9_fid *writeback_fid; | ||||||
| 	struct mutex v_mutex; | 	struct mutex v_mutex; | ||||||
| 	struct inode vfs_inode; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static inline struct v9fs_inode *V9FS_I(const struct inode *inode) | 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) | ||||||
| static inline struct fscache_cookie *v9fs_inode_cookie(struct v9fs_inode *v9inode) | static inline struct fscache_cookie *v9fs_inode_cookie(struct v9fs_inode *v9inode) | ||||||
| { | { | ||||||
| #ifdef CONFIG_9P_FSCACHE | #ifdef CONFIG_9P_FSCACHE | ||||||
| 	return v9inode->fscache; | 	return netfs_i_cookie(&v9inode->vfs_inode); | ||||||
| #else | #else | ||||||
| 	return NULL; | 	return NULL; | ||||||
| #endif | #endif | ||||||
|  | @ -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_dir_inode_operations_dotl; | ||||||
| extern const struct inode_operations v9fs_file_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 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, | extern struct inode *v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, | ||||||
| 					      struct p9_fid *fid, | 					      struct p9_fid *fid, | ||||||
| 					      struct super_block *sb, int new); | 					      struct super_block *sb, int new); | ||||||
|  |  | ||||||
|  | @ -77,17 +77,6 @@ static void v9fs_req_cleanup(struct address_space *mapping, void *priv) | ||||||
| 	p9_client_clunk(fid); | 	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 |  * v9fs_begin_cache_operation - Begin a cache operation for a read | ||||||
|  * @rreq: The read request |  * @rreq: The read request | ||||||
|  | @ -103,36 +92,13 @@ static int v9fs_begin_cache_operation(struct netfs_io_request *rreq) | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct netfs_request_ops v9fs_req_ops = { | const struct netfs_request_ops v9fs_req_ops = { | ||||||
| 	.init_request		= v9fs_init_request, | 	.init_request		= v9fs_init_request, | ||||||
| 	.is_cache_enabled	= v9fs_is_cache_enabled, |  | ||||||
| 	.begin_cache_operation	= v9fs_begin_cache_operation, | 	.begin_cache_operation	= v9fs_begin_cache_operation, | ||||||
| 	.issue_read		= v9fs_issue_read, | 	.issue_read		= v9fs_issue_read, | ||||||
| 	.cleanup		= v9fs_req_cleanup, | 	.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 |  * v9fs_release_page - release the private state associated with a page | ||||||
|  * @page: The page to be released |  * @page: The page to be released | ||||||
|  | @ -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 | 	 * 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. | 	 * there's more than one writer competing for the same cache block. | ||||||
| 	 */ | 	 */ | ||||||
| 	retval = netfs_write_begin(filp, mapping, pos, len, flags, &folio, fsdata, | 	retval = netfs_write_begin(filp, mapping, pos, len, flags, &folio, fsdata); | ||||||
| 				   &v9fs_req_ops, NULL); |  | ||||||
| 	if (retval < 0) | 	if (retval < 0) | ||||||
| 		return retval; | 		return retval; | ||||||
| 
 | 
 | ||||||
|  | @ -388,8 +353,8 @@ static int v9fs_set_page_dirty(struct page *page) | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| const struct address_space_operations v9fs_addr_operations = { | const struct address_space_operations v9fs_addr_operations = { | ||||||
| 	.readpage = v9fs_vfs_readpage, | 	.readpage = netfs_readpage, | ||||||
| 	.readahead = v9fs_vfs_readahead, | 	.readahead = netfs_readahead, | ||||||
| 	.set_page_dirty = v9fs_set_page_dirty, | 	.set_page_dirty = v9fs_set_page_dirty, | ||||||
| 	.writepage = v9fs_vfs_writepage, | 	.writepage = v9fs_vfs_writepage, | ||||||
| 	.write_begin = v9fs_write_begin, | 	.write_begin = v9fs_write_begin, | ||||||
|  |  | ||||||
|  | @ -231,9 +231,6 @@ struct inode *v9fs_alloc_inode(struct super_block *sb) | ||||||
| 	v9inode = kmem_cache_alloc(v9fs_inode_cache, GFP_KERNEL); | 	v9inode = kmem_cache_alloc(v9fs_inode_cache, GFP_KERNEL); | ||||||
| 	if (!v9inode) | 	if (!v9inode) | ||||||
| 		return NULL; | 		return NULL; | ||||||
| #ifdef CONFIG_9P_FSCACHE |  | ||||||
| 	v9inode->fscache = NULL; |  | ||||||
| #endif |  | ||||||
| 	v9inode->writeback_fid = NULL; | 	v9inode->writeback_fid = NULL; | ||||||
| 	v9inode->cache_validity = 0; | 	v9inode->cache_validity = 0; | ||||||
| 	mutex_init(&v9inode->v_mutex); | 	mutex_init(&v9inode->v_mutex); | ||||||
|  | @ -250,6 +247,14 @@ void v9fs_free_inode(struct inode *inode) | ||||||
| 	kmem_cache_free(v9fs_inode_cache, V9FS_I(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, | int v9fs_init_inode(struct v9fs_session_info *v9ses, | ||||||
| 		    struct inode *inode, umode_t mode, dev_t rdev) | 		    struct inode *inode, umode_t mode, dev_t rdev) | ||||||
| { | { | ||||||
|  | @ -338,6 +343,8 @@ int v9fs_init_inode(struct v9fs_session_info *v9ses, | ||||||
| 		err = -EINVAL; | 		err = -EINVAL; | ||||||
| 		goto error; | 		goto error; | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	v9fs_set_netfs_context(inode); | ||||||
| error: | error: | ||||||
| 	return err; | 	return err; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -76,6 +76,7 @@ struct inode *afs_iget_pseudo_dir(struct super_block *sb, bool root) | ||||||
| 	/* there shouldn't be an existing inode */ | 	/* there shouldn't be an existing inode */ | ||||||
| 	BUG_ON(!(inode->i_state & I_NEW)); | 	BUG_ON(!(inode->i_state & I_NEW)); | ||||||
| 
 | 
 | ||||||
|  | 	netfs_i_context_init(inode, NULL); | ||||||
| 	inode->i_size		= 0; | 	inode->i_size		= 0; | ||||||
| 	inode->i_mode		= S_IFDIR | S_IRUGO | S_IXUGO; | 	inode->i_mode		= S_IFDIR | S_IRUGO | S_IXUGO; | ||||||
| 	if (root) { | 	if (root) { | ||||||
|  |  | ||||||
|  | @ -19,13 +19,11 @@ | ||||||
| #include "internal.h" | #include "internal.h" | ||||||
| 
 | 
 | ||||||
| static int afs_file_mmap(struct file *file, struct vm_area_struct *vma); | static int afs_file_mmap(struct file *file, struct vm_area_struct *vma); | ||||||
| static int afs_readpage(struct file *file, struct page *page); |  | ||||||
| static int afs_symlink_readpage(struct file *file, struct page *page); | static int afs_symlink_readpage(struct file *file, struct page *page); | ||||||
| static void afs_invalidatepage(struct page *page, unsigned int offset, | static void afs_invalidatepage(struct page *page, unsigned int offset, | ||||||
| 			       unsigned int length); | 			       unsigned int length); | ||||||
| static int afs_releasepage(struct page *page, gfp_t gfp_flags); | static int afs_releasepage(struct page *page, gfp_t gfp_flags); | ||||||
| 
 | 
 | ||||||
| static void afs_readahead(struct readahead_control *ractl); |  | ||||||
| static ssize_t afs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter); | static ssize_t afs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter); | ||||||
| static void afs_vm_open(struct vm_area_struct *area); | static void afs_vm_open(struct vm_area_struct *area); | ||||||
| static void afs_vm_close(struct vm_area_struct *area); | static void afs_vm_close(struct vm_area_struct *area); | ||||||
|  | @ -52,8 +50,8 @@ const struct inode_operations afs_file_inode_operations = { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const struct address_space_operations afs_file_aops = { | const struct address_space_operations afs_file_aops = { | ||||||
| 	.readpage	= afs_readpage, | 	.readpage	= netfs_readpage, | ||||||
| 	.readahead	= afs_readahead, | 	.readahead	= netfs_readahead, | ||||||
| 	.set_page_dirty	= afs_set_page_dirty, | 	.set_page_dirty	= afs_set_page_dirty, | ||||||
| 	.launder_page	= afs_launder_page, | 	.launder_page	= afs_launder_page, | ||||||
| 	.releasepage	= afs_releasepage, | 	.releasepage	= afs_releasepage, | ||||||
|  | @ -365,13 +363,6 @@ static int afs_init_request(struct netfs_io_request *rreq, struct file *file) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool afs_is_cache_enabled(struct inode *inode) |  | ||||||
| { |  | ||||||
| 	struct fscache_cookie *cookie = afs_vnode_cache(AFS_FS_I(inode)); |  | ||||||
| 
 |  | ||||||
| 	return fscache_cookie_enabled(cookie) && cookie->cache_priv; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int afs_begin_cache_operation(struct netfs_io_request *rreq) | static int afs_begin_cache_operation(struct netfs_io_request *rreq) | ||||||
| { | { | ||||||
| #ifdef CONFIG_AFS_FSCACHE | #ifdef CONFIG_AFS_FSCACHE | ||||||
|  | @ -399,25 +390,12 @@ static void afs_priv_cleanup(struct address_space *mapping, void *netfs_priv) | ||||||
| 
 | 
 | ||||||
| const struct netfs_request_ops afs_req_ops = { | const struct netfs_request_ops afs_req_ops = { | ||||||
| 	.init_request		= afs_init_request, | 	.init_request		= afs_init_request, | ||||||
| 	.is_cache_enabled	= afs_is_cache_enabled, |  | ||||||
| 	.begin_cache_operation	= afs_begin_cache_operation, | 	.begin_cache_operation	= afs_begin_cache_operation, | ||||||
| 	.check_write_begin	= afs_check_write_begin, | 	.check_write_begin	= afs_check_write_begin, | ||||||
| 	.issue_read		= afs_issue_read, | 	.issue_read		= afs_issue_read, | ||||||
| 	.cleanup		= afs_priv_cleanup, | 	.cleanup		= afs_priv_cleanup, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static int afs_readpage(struct file *file, struct page *page) |  | ||||||
| { |  | ||||||
| 	struct folio *folio = page_folio(page); |  | ||||||
| 
 |  | ||||||
| 	return netfs_readpage(file, folio, &afs_req_ops, NULL); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void afs_readahead(struct readahead_control *ractl) |  | ||||||
| { |  | ||||||
| 	netfs_readahead(ractl, &afs_req_ops, NULL); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int afs_write_inode(struct inode *inode, struct writeback_control *wbc) | int afs_write_inode(struct inode *inode, struct writeback_control *wbc) | ||||||
| { | { | ||||||
| 	fscache_unpin_writeback(wbc, afs_vnode_cache(AFS_FS_I(inode))); | 	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 | ||||||
| 		dump_stack(); | 		dump_stack(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * Set parameters for the netfs library | ||||||
|  |  */ | ||||||
|  | static void afs_set_netfs_context(struct afs_vnode *vnode) | ||||||
|  | { | ||||||
|  | 	netfs_i_context_init(&vnode->vfs_inode, &afs_req_ops); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Initialise an inode from the vnode status. |  * Initialise an inode from the vnode status. | ||||||
|  */ |  */ | ||||||
|  | @ -128,6 +136,7 @@ static int afs_inode_init_from_status(struct afs_operation *op, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	afs_set_i_size(vnode, status->size); | 	afs_set_i_size(vnode, status->size); | ||||||
|  | 	afs_set_netfs_context(vnode); | ||||||
| 
 | 
 | ||||||
| 	vnode->invalid_before	= status->data_version; | 	vnode->invalid_before	= status->data_version; | ||||||
| 	inode_set_iversion_raw(&vnode->vfs_inode, status->data_version); | 	inode_set_iversion_raw(&vnode->vfs_inode, status->data_version); | ||||||
|  | @ -420,7 +429,7 @@ static void afs_get_inode_cache(struct afs_vnode *vnode) | ||||||
| 	struct afs_vnode_cache_aux aux; | 	struct afs_vnode_cache_aux aux; | ||||||
| 
 | 
 | ||||||
| 	if (vnode->status.type != AFS_FTYPE_FILE) { | 	if (vnode->status.type != AFS_FTYPE_FILE) { | ||||||
| 		vnode->cache = NULL; | 		vnode->netfs_ctx.cache = NULL; | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -430,12 +439,14 @@ static void afs_get_inode_cache(struct afs_vnode *vnode) | ||||||
| 	key.vnode_id_ext[1]	= htonl(vnode->fid.vnode_hi); | 	key.vnode_id_ext[1]	= htonl(vnode->fid.vnode_hi); | ||||||
| 	afs_set_cache_aux(vnode, &aux); | 	afs_set_cache_aux(vnode, &aux); | ||||||
| 
 | 
 | ||||||
| 	vnode->cache = fscache_acquire_cookie( | 	afs_vnode_set_cache(vnode, | ||||||
| 		vnode->volume->cache, | 			    fscache_acquire_cookie( | ||||||
| 		vnode->status.type == AFS_FTYPE_FILE ? 0 : FSCACHE_ADV_SINGLE_CHUNK, | 				    vnode->volume->cache, | ||||||
| 		&key, sizeof(key), | 				    vnode->status.type == AFS_FTYPE_FILE ? | ||||||
| 		&aux, sizeof(aux), | 				    0 : FSCACHE_ADV_SINGLE_CHUNK, | ||||||
| 		vnode->status.size); | 				    &key, sizeof(key), | ||||||
|  | 				    &aux, sizeof(aux), | ||||||
|  | 				    vnode->status.size)); | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -528,6 +539,7 @@ struct inode *afs_root_iget(struct super_block *sb, struct key *key) | ||||||
| 
 | 
 | ||||||
| 	vnode = AFS_FS_I(inode); | 	vnode = AFS_FS_I(inode); | ||||||
| 	vnode->cb_v_break = as->volume->cb_v_break, | 	vnode->cb_v_break = as->volume->cb_v_break, | ||||||
|  | 	afs_set_netfs_context(vnode); | ||||||
| 
 | 
 | ||||||
| 	op = afs_alloc_operation(key, as->volume); | 	op = afs_alloc_operation(key, as->volume); | ||||||
| 	if (IS_ERR(op)) { | 	if (IS_ERR(op)) { | ||||||
|  | @ -786,11 +798,8 @@ void afs_evict_inode(struct inode *inode) | ||||||
| 		afs_put_wb_key(wbk); | 		afs_put_wb_key(wbk); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_AFS_FSCACHE | 	fscache_relinquish_cookie(afs_vnode_cache(vnode), | ||||||
| 	fscache_relinquish_cookie(vnode->cache, |  | ||||||
| 				  test_bit(AFS_VNODE_DELETED, &vnode->flags)); | 				  test_bit(AFS_VNODE_DELETED, &vnode->flags)); | ||||||
| 	vnode->cache = NULL; |  | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
| 	afs_prune_wb_keys(vnode); | 	afs_prune_wb_keys(vnode); | ||||||
| 	afs_put_permits(rcu_access_pointer(vnode->permit_cache)); | 	afs_put_permits(rcu_access_pointer(vnode->permit_cache)); | ||||||
|  |  | ||||||
|  | @ -619,15 +619,16 @@ enum afs_lock_state { | ||||||
|  * leak from one inode to another. |  * leak from one inode to another. | ||||||
|  */ |  */ | ||||||
| struct afs_vnode { | struct afs_vnode { | ||||||
| 	struct inode		vfs_inode;	/* the VFS's inode record */ | 	struct { | ||||||
|  | 		/* These must be contiguous */ | ||||||
|  | 		struct inode	vfs_inode;	/* the VFS's inode record */ | ||||||
|  | 		struct netfs_i_context netfs_ctx; /* Netfslib context */ | ||||||
|  | 	}; | ||||||
| 
 | 
 | ||||||
| 	struct afs_volume	*volume;	/* volume on which vnode resides */ | 	struct afs_volume	*volume;	/* volume on which vnode resides */ | ||||||
| 	struct afs_fid		fid;		/* the file identifier for this inode */ | 	struct afs_fid		fid;		/* the file identifier for this inode */ | ||||||
| 	struct afs_file_status	status;		/* AFS status info for this file */ | 	struct afs_file_status	status;		/* AFS status info for this file */ | ||||||
| 	afs_dataversion_t	invalid_before;	/* Child dentries are invalid before this */ | 	afs_dataversion_t	invalid_before;	/* Child dentries are invalid before this */ | ||||||
| #ifdef CONFIG_AFS_FSCACHE |  | ||||||
| 	struct fscache_cookie	*cache;		/* caching cookie */ |  | ||||||
| #endif |  | ||||||
| 	struct afs_permits __rcu *permit_cache;	/* cache of permits so far obtained */ | 	struct afs_permits __rcu *permit_cache;	/* cache of permits so far obtained */ | ||||||
| 	struct mutex		io_lock;	/* Lock for serialising I/O on this mutex */ | 	struct mutex		io_lock;	/* Lock for serialising I/O on this mutex */ | ||||||
| 	struct rw_semaphore	validate_lock;	/* lock for validating this vnode */ | 	struct rw_semaphore	validate_lock;	/* lock for validating this vnode */ | ||||||
|  | @ -674,12 +675,20 @@ struct afs_vnode { | ||||||
| static inline struct fscache_cookie *afs_vnode_cache(struct afs_vnode *vnode) | static inline struct fscache_cookie *afs_vnode_cache(struct afs_vnode *vnode) | ||||||
| { | { | ||||||
| #ifdef CONFIG_AFS_FSCACHE | #ifdef CONFIG_AFS_FSCACHE | ||||||
| 	return vnode->cache; | 	return netfs_i_cookie(&vnode->vfs_inode); | ||||||
| #else | #else | ||||||
| 	return NULL; | 	return NULL; | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static inline void afs_vnode_set_cache(struct afs_vnode *vnode, | ||||||
|  | 				       struct fscache_cookie *cookie) | ||||||
|  | { | ||||||
|  | #ifdef CONFIG_AFS_FSCACHE | ||||||
|  | 	vnode->netfs_ctx.cache = cookie; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * cached security record for one user's attempt to access a vnode |  * cached security record for one user's attempt to access a vnode | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  | @ -688,13 +688,11 @@ static struct inode *afs_alloc_inode(struct super_block *sb) | ||||||
| 	/* Reset anything that shouldn't leak from one inode to the next. */ | 	/* Reset anything that shouldn't leak from one inode to the next. */ | ||||||
| 	memset(&vnode->fid, 0, sizeof(vnode->fid)); | 	memset(&vnode->fid, 0, sizeof(vnode->fid)); | ||||||
| 	memset(&vnode->status, 0, sizeof(vnode->status)); | 	memset(&vnode->status, 0, sizeof(vnode->status)); | ||||||
|  | 	afs_vnode_set_cache(vnode, NULL); | ||||||
| 
 | 
 | ||||||
| 	vnode->volume		= NULL; | 	vnode->volume		= NULL; | ||||||
| 	vnode->lock_key		= NULL; | 	vnode->lock_key		= NULL; | ||||||
| 	vnode->permit_cache	= NULL; | 	vnode->permit_cache	= NULL; | ||||||
| #ifdef CONFIG_AFS_FSCACHE |  | ||||||
| 	vnode->cache		= NULL; |  | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
| 	vnode->flags		= 1 << AFS_VNODE_UNSET; | 	vnode->flags		= 1 << AFS_VNODE_UNSET; | ||||||
| 	vnode->lock_state	= AFS_VNODE_LOCK_NONE; | 	vnode->lock_state	= AFS_VNODE_LOCK_NONE; | ||||||
|  |  | ||||||
|  | @ -59,8 +59,7 @@ int afs_write_begin(struct file *file, struct address_space *mapping, | ||||||
| 	 * file.  We need to do this before we get a lock on the page in case | 	 * 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. | 	 * there's more than one writer competing for the same cache block. | ||||||
| 	 */ | 	 */ | ||||||
| 	ret = netfs_write_begin(file, mapping, pos, len, flags, &folio, fsdata, | 	ret = netfs_write_begin(file, mapping, pos, len, flags, &folio, fsdata); | ||||||
| 				&afs_req_ops, NULL); |  | ||||||
| 	if (ret < 0) | 	if (ret < 0) | ||||||
| 		return ret; | 		return ret; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -403,7 +403,7 @@ static void ceph_readahead_cleanup(struct address_space *mapping, void *priv) | ||||||
| 		ceph_put_cap_refs(ci, got); | 		ceph_put_cap_refs(ci, got); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct netfs_request_ops ceph_netfs_read_ops = { | const struct netfs_request_ops ceph_netfs_ops = { | ||||||
| 	.init_request		= ceph_init_request, | 	.init_request		= ceph_init_request, | ||||||
| 	.begin_cache_operation	= ceph_begin_cache_operation, | 	.begin_cache_operation	= ceph_begin_cache_operation, | ||||||
| 	.issue_read		= ceph_netfs_issue_read, | 	.issue_read		= ceph_netfs_issue_read, | ||||||
|  | @ -413,28 +413,6 @@ static const struct netfs_request_ops ceph_netfs_read_ops = { | ||||||
| 	.cleanup		= ceph_readahead_cleanup, | 	.cleanup		= ceph_readahead_cleanup, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /* read a single page, without unlocking it. */ |  | ||||||
| static int ceph_readpage(struct file *file, struct page *subpage) |  | ||||||
| { |  | ||||||
| 	struct folio *folio = page_folio(subpage); |  | ||||||
| 	struct inode *inode = file_inode(file); |  | ||||||
| 	struct ceph_inode_info *ci = ceph_inode(inode); |  | ||||||
| 	struct ceph_vino vino = ceph_vino(inode); |  | ||||||
| 	size_t len = folio_size(folio); |  | ||||||
| 	u64 off = folio_file_pos(folio); |  | ||||||
| 
 |  | ||||||
| 	dout("readpage ino %llx.%llx file %p off %llu len %zu folio %p index %lu\n inline %d", |  | ||||||
| 	     vino.ino, vino.snap, file, off, len, folio, folio_index(folio), |  | ||||||
| 	     ci->i_inline_version != CEPH_INLINE_NONE); |  | ||||||
| 
 |  | ||||||
| 	return netfs_readpage(file, folio, &ceph_netfs_read_ops, NULL); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void ceph_readahead(struct readahead_control *ractl) |  | ||||||
| { |  | ||||||
| 	netfs_readahead(ractl, &ceph_netfs_read_ops, NULL); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #ifdef CONFIG_CEPH_FSCACHE | #ifdef CONFIG_CEPH_FSCACHE | ||||||
| static void ceph_set_page_fscache(struct page *page) | static void ceph_set_page_fscache(struct page *page) | ||||||
| { | { | ||||||
|  | @ -1333,8 +1311,7 @@ static int ceph_write_begin(struct file *file, struct address_space *mapping, | ||||||
| 	struct folio *folio = NULL; | 	struct folio *folio = NULL; | ||||||
| 	int r; | 	int r; | ||||||
| 
 | 
 | ||||||
| 	r = netfs_write_begin(file, inode->i_mapping, pos, len, 0, &folio, NULL, | 	r = netfs_write_begin(file, inode->i_mapping, pos, len, 0, &folio, NULL); | ||||||
| 			      &ceph_netfs_read_ops, NULL); |  | ||||||
| 	if (r == 0) | 	if (r == 0) | ||||||
| 		folio_wait_fscache(folio); | 		folio_wait_fscache(folio); | ||||||
| 	if (r < 0) { | 	if (r < 0) { | ||||||
|  | @ -1388,8 +1365,8 @@ static int ceph_write_end(struct file *file, struct address_space *mapping, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const struct address_space_operations ceph_aops = { | const struct address_space_operations ceph_aops = { | ||||||
| 	.readpage = ceph_readpage, | 	.readpage = netfs_readpage, | ||||||
| 	.readahead = ceph_readahead, | 	.readahead = netfs_readahead, | ||||||
| 	.writepage = ceph_writepage, | 	.writepage = ceph_writepage, | ||||||
| 	.writepages = ceph_writepages_start, | 	.writepages = ceph_writepages_start, | ||||||
| 	.write_begin = ceph_write_begin, | 	.write_begin = ceph_write_begin, | ||||||
|  |  | ||||||
|  | @ -29,26 +29,25 @@ void ceph_fscache_register_inode_cookie(struct inode *inode) | ||||||
| 	if (!(inode->i_state & I_NEW)) | 	if (!(inode->i_state & I_NEW)) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	WARN_ON_ONCE(ci->fscache); | 	WARN_ON_ONCE(ci->netfs_ctx.cache); | ||||||
| 
 | 
 | ||||||
| 	ci->fscache = fscache_acquire_cookie(fsc->fscache, 0, | 	ci->netfs_ctx.cache = | ||||||
| 					     &ci->i_vino, sizeof(ci->i_vino), | 		fscache_acquire_cookie(fsc->fscache, 0, | ||||||
| 					     &ci->i_version, sizeof(ci->i_version), | 				       &ci->i_vino, sizeof(ci->i_vino), | ||||||
| 					     i_size_read(inode)); | 				       &ci->i_version, sizeof(ci->i_version), | ||||||
|  | 				       i_size_read(inode)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ceph_fscache_unregister_inode_cookie(struct ceph_inode_info* ci) | void ceph_fscache_unregister_inode_cookie(struct ceph_inode_info *ci) | ||||||
| { | { | ||||||
| 	struct fscache_cookie *cookie = ci->fscache; | 	fscache_relinquish_cookie(ceph_fscache_cookie(ci), false); | ||||||
| 
 |  | ||||||
| 	fscache_relinquish_cookie(cookie, false); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ceph_fscache_use_cookie(struct inode *inode, bool will_modify) | void ceph_fscache_use_cookie(struct inode *inode, bool will_modify) | ||||||
| { | { | ||||||
| 	struct ceph_inode_info *ci = ceph_inode(inode); | 	struct ceph_inode_info *ci = ceph_inode(inode); | ||||||
| 
 | 
 | ||||||
| 	fscache_use_cookie(ci->fscache, will_modify); | 	fscache_use_cookie(ceph_fscache_cookie(ci), will_modify); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ceph_fscache_unuse_cookie(struct inode *inode, bool update) | void ceph_fscache_unuse_cookie(struct inode *inode, bool update) | ||||||
|  | @ -58,9 +57,10 @@ void ceph_fscache_unuse_cookie(struct inode *inode, bool update) | ||||||
| 	if (update) { | 	if (update) { | ||||||
| 		loff_t i_size = i_size_read(inode); | 		loff_t i_size = i_size_read(inode); | ||||||
| 
 | 
 | ||||||
| 		fscache_unuse_cookie(ci->fscache, &ci->i_version, &i_size); | 		fscache_unuse_cookie(ceph_fscache_cookie(ci), | ||||||
|  | 				     &ci->i_version, &i_size); | ||||||
| 	} else { | 	} else { | ||||||
| 		fscache_unuse_cookie(ci->fscache, NULL, NULL); | 		fscache_unuse_cookie(ceph_fscache_cookie(ci), NULL, NULL); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -69,14 +69,14 @@ void ceph_fscache_update(struct inode *inode) | ||||||
| 	struct ceph_inode_info *ci = ceph_inode(inode); | 	struct ceph_inode_info *ci = ceph_inode(inode); | ||||||
| 	loff_t i_size = i_size_read(inode); | 	loff_t i_size = i_size_read(inode); | ||||||
| 
 | 
 | ||||||
| 	fscache_update_cookie(ci->fscache, &ci->i_version, &i_size); | 	fscache_update_cookie(ceph_fscache_cookie(ci), &ci->i_version, &i_size); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ceph_fscache_invalidate(struct inode *inode, bool dio_write) | void ceph_fscache_invalidate(struct inode *inode, bool dio_write) | ||||||
| { | { | ||||||
| 	struct ceph_inode_info *ci = ceph_inode(inode); | 	struct ceph_inode_info *ci = ceph_inode(inode); | ||||||
| 
 | 
 | ||||||
| 	fscache_invalidate(ceph_inode(inode)->fscache, | 	fscache_invalidate(ceph_fscache_cookie(ci), | ||||||
| 			   &ci->i_version, i_size_read(inode), | 			   &ci->i_version, i_size_read(inode), | ||||||
| 			   dio_write ? FSCACHE_INVAL_DIO_WRITE : 0); | 			   dio_write ? FSCACHE_INVAL_DIO_WRITE : 0); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -26,14 +26,9 @@ void ceph_fscache_unuse_cookie(struct inode *inode, bool update); | ||||||
| void ceph_fscache_update(struct inode *inode); | void ceph_fscache_update(struct inode *inode); | ||||||
| void ceph_fscache_invalidate(struct inode *inode, bool dio_write); | void ceph_fscache_invalidate(struct inode *inode, bool dio_write); | ||||||
| 
 | 
 | ||||||
| static inline void ceph_fscache_inode_init(struct ceph_inode_info *ci) |  | ||||||
| { |  | ||||||
| 	ci->fscache = NULL; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline struct fscache_cookie *ceph_fscache_cookie(struct ceph_inode_info *ci) | static inline struct fscache_cookie *ceph_fscache_cookie(struct ceph_inode_info *ci) | ||||||
| { | { | ||||||
| 	return ci->fscache; | 	return netfs_i_cookie(&ci->vfs_inode); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline void ceph_fscache_resize(struct inode *inode, loff_t to) | 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) | ||||||
| { | { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline void ceph_fscache_inode_init(struct ceph_inode_info *ci) |  | ||||||
| { |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline void ceph_fscache_register_inode_cookie(struct inode *inode) | static inline void ceph_fscache_register_inode_cookie(struct inode *inode) | ||||||
| { | { | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -453,6 +453,9 @@ struct inode *ceph_alloc_inode(struct super_block *sb) | ||||||
| 
 | 
 | ||||||
| 	dout("alloc_inode %p\n", &ci->vfs_inode); | 	dout("alloc_inode %p\n", &ci->vfs_inode); | ||||||
| 
 | 
 | ||||||
|  | 	/* Set parameters for the netfs library */ | ||||||
|  | 	netfs_i_context_init(&ci->vfs_inode, &ceph_netfs_ops); | ||||||
|  | 
 | ||||||
| 	spin_lock_init(&ci->i_ceph_lock); | 	spin_lock_init(&ci->i_ceph_lock); | ||||||
| 
 | 
 | ||||||
| 	ci->i_version = 0; | 	ci->i_version = 0; | ||||||
|  | @ -538,9 +541,6 @@ struct inode *ceph_alloc_inode(struct super_block *sb) | ||||||
| 	INIT_WORK(&ci->i_work, ceph_inode_work); | 	INIT_WORK(&ci->i_work, ceph_inode_work); | ||||||
| 	ci->i_work_mask = 0; | 	ci->i_work_mask = 0; | ||||||
| 	memset(&ci->i_btime, '\0', sizeof(ci->i_btime)); | 	memset(&ci->i_btime, '\0', sizeof(ci->i_btime)); | ||||||
| 
 |  | ||||||
| 	ceph_fscache_inode_init(ci); |  | ||||||
| 
 |  | ||||||
| 	return &ci->vfs_inode; | 	return &ci->vfs_inode; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -17,13 +17,11 @@ | ||||||
| #include <linux/posix_acl.h> | #include <linux/posix_acl.h> | ||||||
| #include <linux/refcount.h> | #include <linux/refcount.h> | ||||||
| #include <linux/security.h> | #include <linux/security.h> | ||||||
|  | #include <linux/netfs.h> | ||||||
|  | #include <linux/fscache.h> | ||||||
| 
 | 
 | ||||||
| #include <linux/ceph/libceph.h> | #include <linux/ceph/libceph.h> | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_CEPH_FSCACHE |  | ||||||
| #include <linux/fscache.h> |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| /* large granularity for statfs utilization stats to facilitate
 | /* large granularity for statfs utilization stats to facilitate
 | ||||||
|  * large volume sizes on 32-bit machines. */ |  * large volume sizes on 32-bit machines. */ | ||||||
| #define CEPH_BLOCK_SHIFT   22  /* 4 MB */ | #define CEPH_BLOCK_SHIFT   22  /* 4 MB */ | ||||||
|  | @ -317,6 +315,11 @@ struct ceph_inode_xattrs_info { | ||||||
|  * Ceph inode. |  * Ceph inode. | ||||||
|  */ |  */ | ||||||
| struct ceph_inode_info { | struct ceph_inode_info { | ||||||
|  | 	struct { | ||||||
|  | 		/* These must be contiguous */ | ||||||
|  | 		struct inode vfs_inode; | ||||||
|  | 		struct netfs_i_context netfs_ctx; /* Netfslib context */ | ||||||
|  | 	}; | ||||||
| 	struct ceph_vino i_vino;   /* ceph ino + snap */ | 	struct ceph_vino i_vino;   /* ceph ino + snap */ | ||||||
| 
 | 
 | ||||||
| 	spinlock_t i_ceph_lock; | 	spinlock_t i_ceph_lock; | ||||||
|  | @ -427,11 +430,6 @@ struct ceph_inode_info { | ||||||
| 
 | 
 | ||||||
| 	struct work_struct i_work; | 	struct work_struct i_work; | ||||||
| 	unsigned long  i_work_mask; | 	unsigned long  i_work_mask; | ||||||
| 
 |  | ||||||
| #ifdef CONFIG_CEPH_FSCACHE |  | ||||||
| 	struct fscache_cookie *fscache; |  | ||||||
| #endif |  | ||||||
| 	struct inode vfs_inode; /* at end */ |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static inline struct ceph_inode_info * | static inline struct ceph_inode_info * | ||||||
|  | @ -1215,6 +1213,7 @@ extern void __ceph_touch_fmode(struct ceph_inode_info *ci, | ||||||
| 
 | 
 | ||||||
| /* addr.c */ | /* addr.c */ | ||||||
| extern const struct address_space_operations ceph_aops; | extern const struct address_space_operations ceph_aops; | ||||||
|  | extern const struct netfs_request_ops ceph_netfs_ops; | ||||||
| extern int ceph_mmap(struct file *file, struct vm_area_struct *vma); | extern int ceph_mmap(struct file *file, struct vm_area_struct *vma); | ||||||
| extern int ceph_uninline_data(struct file *file); | extern int ceph_uninline_data(struct file *file); | ||||||
| extern int ceph_pool_perm_check(struct inode *inode, int need); | extern int ceph_pool_perm_check(struct inode *inode, int need); | ||||||
|  |  | ||||||
|  | @ -16,6 +16,7 @@ | ||||||
| #include <linux/mempool.h> | #include <linux/mempool.h> | ||||||
| #include <linux/workqueue.h> | #include <linux/workqueue.h> | ||||||
| #include <linux/utsname.h> | #include <linux/utsname.h> | ||||||
|  | #include <linux/netfs.h> | ||||||
| #include "cifs_fs_sb.h" | #include "cifs_fs_sb.h" | ||||||
| #include "cifsacl.h" | #include "cifsacl.h" | ||||||
| #include <crypto/internal/hash.h> | #include <crypto/internal/hash.h> | ||||||
|  | @ -1402,6 +1403,11 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file); | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| struct cifsInodeInfo { | struct cifsInodeInfo { | ||||||
|  | 	struct { | ||||||
|  | 		/* These must be contiguous */ | ||||||
|  | 		struct inode	vfs_inode;	/* the VFS's inode record */ | ||||||
|  | 		struct netfs_i_context netfs_ctx; /* Netfslib context */ | ||||||
|  | 	}; | ||||||
| 	bool can_cache_brlcks; | 	bool can_cache_brlcks; | ||||||
| 	struct list_head llist;	/* locks helb by this inode */ | 	struct list_head llist;	/* locks helb by this inode */ | ||||||
| 	/*
 | 	/*
 | ||||||
|  | @ -1432,10 +1438,6 @@ struct cifsInodeInfo { | ||||||
| 	u64  uniqueid;			/* server inode number */ | 	u64  uniqueid;			/* server inode number */ | ||||||
| 	u64  createtime;		/* creation time on server */ | 	u64  createtime;		/* creation time on server */ | ||||||
| 	__u8 lease_key[SMB2_LEASE_KEY_SIZE];	/* lease key for this inode */ | 	__u8 lease_key[SMB2_LEASE_KEY_SIZE];	/* lease key for this inode */ | ||||||
| #ifdef CONFIG_CIFS_FSCACHE |  | ||||||
| 	struct fscache_cookie *fscache; |  | ||||||
| #endif |  | ||||||
| 	struct inode vfs_inode; |  | ||||||
| 	struct list_head deferred_closes; /* list of deferred closes */ | 	struct list_head deferred_closes; /* list of deferred closes */ | ||||||
| 	spinlock_t deferred_lock; /* protection on deferred list */ | 	spinlock_t deferred_lock; /* protection on deferred list */ | ||||||
| 	bool lease_granted; /* Flag to indicate whether lease or oplock is granted. */ | 	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) | ||||||
| 
 | 
 | ||||||
| 	cifs_fscache_fill_coherency(&cifsi->vfs_inode, &cd); | 	cifs_fscache_fill_coherency(&cifsi->vfs_inode, &cd); | ||||||
| 
 | 
 | ||||||
| 	cifsi->fscache = | 	cifsi->netfs_ctx.cache = | ||||||
| 		fscache_acquire_cookie(tcon->fscache, 0, | 		fscache_acquire_cookie(tcon->fscache, 0, | ||||||
| 				       &cifsi->uniqueid, sizeof(cifsi->uniqueid), | 				       &cifsi->uniqueid, sizeof(cifsi->uniqueid), | ||||||
| 				       &cd, sizeof(cd), | 				       &cd, sizeof(cd), | ||||||
|  | @ -126,11 +126,12 @@ void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool update) | ||||||
| void cifs_fscache_release_inode_cookie(struct inode *inode) | void cifs_fscache_release_inode_cookie(struct inode *inode) | ||||||
| { | { | ||||||
| 	struct cifsInodeInfo *cifsi = CIFS_I(inode); | 	struct cifsInodeInfo *cifsi = CIFS_I(inode); | ||||||
|  | 	struct fscache_cookie *cookie = cifs_inode_cookie(inode); | ||||||
| 
 | 
 | ||||||
| 	if (cifsi->fscache) { | 	if (cookie) { | ||||||
| 		cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cifsi->fscache); | 		cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cookie); | ||||||
| 		fscache_relinquish_cookie(cifsi->fscache, false); | 		fscache_relinquish_cookie(cookie, false); | ||||||
| 		cifsi->fscache = NULL; | 		cifsi->netfs_ctx.cache = NULL; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -61,7 +61,7 @@ void cifs_fscache_fill_coherency(struct inode *inode, | ||||||
| 
 | 
 | ||||||
| static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode) | static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode) | ||||||
| { | { | ||||||
| 	return CIFS_I(inode)->fscache; | 	return netfs_i_cookie(inode); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline void cifs_invalidate_cache(struct inode *inode, unsigned int flags) | static inline void cifs_invalidate_cache(struct inode *inode, unsigned int flags) | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include <linux/netfs.h> | #include <linux/netfs.h> | ||||||
|  | #include <linux/fscache.h> | ||||||
| #include <trace/events/netfs.h> | #include <trace/events/netfs.h> | ||||||
| 
 | 
 | ||||||
| #ifdef pr_fmt | #ifdef pr_fmt | ||||||
|  | @ -19,8 +20,6 @@ | ||||||
|  */ |  */ | ||||||
| struct netfs_io_request *netfs_alloc_request(struct address_space *mapping, | struct netfs_io_request *netfs_alloc_request(struct address_space *mapping, | ||||||
| 					     struct file *file, | 					     struct file *file, | ||||||
| 					     const struct netfs_request_ops *ops, |  | ||||||
| 					     void *netfs_priv, |  | ||||||
| 					     loff_t start, size_t len, | 					     loff_t start, size_t len, | ||||||
| 					     enum netfs_io_origin origin); | 					     enum netfs_io_origin origin); | ||||||
| void netfs_get_request(struct netfs_io_request *rreq, enum netfs_rreq_ref_trace what); | 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) | ||||||
| #define netfs_stat_d(x) do {} while(0) | #define netfs_stat_d(x) do {} while(0) | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * Miscellaneous functions. | ||||||
|  |  */ | ||||||
|  | static inline bool netfs_is_cache_enabled(struct netfs_i_context *ctx) | ||||||
|  | { | ||||||
|  | #if IS_ENABLED(CONFIG_FSCACHE) | ||||||
|  | 	struct fscache_cookie *cookie = ctx->cache; | ||||||
|  | 
 | ||||||
|  | 	return fscache_cookie_valid(cookie) && cookie->cache_priv && | ||||||
|  | 		fscache_cookie_enabled(cookie); | ||||||
|  | #else | ||||||
|  | 	return false; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*****************************************************************************/ | /*****************************************************************************/ | ||||||
| /*
 | /*
 | ||||||
|  * debug tracing |  * debug tracing | ||||||
|  |  | ||||||
|  | @ -13,12 +13,12 @@ | ||||||
|  */ |  */ | ||||||
| struct netfs_io_request *netfs_alloc_request(struct address_space *mapping, | struct netfs_io_request *netfs_alloc_request(struct address_space *mapping, | ||||||
| 					     struct file *file, | 					     struct file *file, | ||||||
| 					     const struct netfs_request_ops *ops, |  | ||||||
| 					     void *netfs_priv, |  | ||||||
| 					     loff_t start, size_t len, | 					     loff_t start, size_t len, | ||||||
| 					     enum netfs_io_origin origin) | 					     enum netfs_io_origin origin) | ||||||
| { | { | ||||||
| 	static atomic_t debug_ids; | 	static atomic_t debug_ids; | ||||||
|  | 	struct inode *inode = file ? file_inode(file) : mapping->host; | ||||||
|  | 	struct netfs_i_context *ctx = netfs_i_context(inode); | ||||||
| 	struct netfs_io_request *rreq; | 	struct netfs_io_request *rreq; | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
|  | @ -29,11 +29,10 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping, | ||||||
| 	rreq->start	= start; | 	rreq->start	= start; | ||||||
| 	rreq->len	= len; | 	rreq->len	= len; | ||||||
| 	rreq->origin	= origin; | 	rreq->origin	= origin; | ||||||
| 	rreq->netfs_ops	= ops; | 	rreq->netfs_ops	= ctx->ops; | ||||||
| 	rreq->netfs_priv = netfs_priv; |  | ||||||
| 	rreq->mapping	= mapping; | 	rreq->mapping	= mapping; | ||||||
| 	rreq->inode	= file_inode(file); | 	rreq->inode	= inode; | ||||||
| 	rreq->i_size	= i_size_read(rreq->inode); | 	rreq->i_size	= i_size_read(inode); | ||||||
| 	rreq->debug_id	= atomic_inc_return(&debug_ids); | 	rreq->debug_id	= atomic_inc_return(&debug_ids); | ||||||
| 	INIT_LIST_HEAD(&rreq->subrequests); | 	INIT_LIST_HEAD(&rreq->subrequests); | ||||||
| 	INIT_WORK(&rreq->work, netfs_rreq_work); | 	INIT_WORK(&rreq->work, netfs_rreq_work); | ||||||
|  | @ -76,6 +75,7 @@ static void netfs_free_request(struct work_struct *work) | ||||||
| { | { | ||||||
| 	struct netfs_io_request *rreq = | 	struct netfs_io_request *rreq = | ||||||
| 		container_of(work, struct netfs_io_request, work); | 		container_of(work, struct netfs_io_request, work); | ||||||
|  | 
 | ||||||
| 	netfs_clear_subrequests(rreq, false); | 	netfs_clear_subrequests(rreq, false); | ||||||
| 	if (rreq->netfs_priv) | 	if (rreq->netfs_priv) | ||||||
| 		rreq->netfs_ops->cleanup(rreq->mapping, rreq->netfs_priv); | 		rreq->netfs_ops->cleanup(rreq->mapping, rreq->netfs_priv); | ||||||
|  |  | ||||||
|  | @ -14,7 +14,6 @@ | ||||||
| #include <linux/uio.h> | #include <linux/uio.h> | ||||||
| #include <linux/sched/mm.h> | #include <linux/sched/mm.h> | ||||||
| #include <linux/task_io_accounting_ops.h> | #include <linux/task_io_accounting_ops.h> | ||||||
| #include <linux/netfs.h> |  | ||||||
| #include "internal.h" | #include "internal.h" | ||||||
| #define CREATE_TRACE_POINTS | #define CREATE_TRACE_POINTS | ||||||
| #include <trace/events/netfs.h> | #include <trace/events/netfs.h> | ||||||
|  | @ -735,8 +734,6 @@ static void netfs_rreq_expand(struct netfs_io_request *rreq, | ||||||
| /**
 | /**
 | ||||||
|  * netfs_readahead - Helper to manage a read request |  * netfs_readahead - Helper to manage a read request | ||||||
|  * @ractl: The description of the readahead request |  * @ractl: The description of the readahead request | ||||||
|  * @ops: The network filesystem's operations for the helper to use |  | ||||||
|  * @netfs_priv: Private netfs data to be retained in the request |  | ||||||
|  * |  * | ||||||
|  * Fulfil a readahead request by drawing data from the cache if possible, or |  * Fulfil a readahead request by drawing data from the cache if possible, or | ||||||
|  * the netfs if not.  Space beyond the EOF is zero-filled.  Multiple I/O |  * 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, | ||||||
|  * readahead window can be expanded in either direction to a more convenient |  * readahead window can be expanded in either direction to a more convenient | ||||||
|  * alighment for RPC efficiency or to make storage in the cache feasible. |  * alighment for RPC efficiency or to make storage in the cache feasible. | ||||||
|  * |  * | ||||||
|  * The calling netfs must provide a table of operations, only one of which, |  * The calling netfs must initialise a netfs context contiguous to the vfs | ||||||
|  * issue_op, is mandatory.  It may also be passed a private token, which will |  * inode before calling this. | ||||||
|  * be retained in rreq->netfs_priv and will be cleaned up by ops->cleanup(). |  | ||||||
|  * |  * | ||||||
|  * This is usable whether or not caching is enabled. |  * This is usable whether or not caching is enabled. | ||||||
|  */ |  */ | ||||||
| void netfs_readahead(struct readahead_control *ractl, | void netfs_readahead(struct readahead_control *ractl) | ||||||
| 		     const struct netfs_request_ops *ops, |  | ||||||
| 		     void *netfs_priv) |  | ||||||
| { | { | ||||||
| 	struct netfs_io_request *rreq; | 	struct netfs_io_request *rreq; | ||||||
|  | 	struct netfs_i_context *ctx = netfs_i_context(ractl->mapping->host); | ||||||
| 	unsigned int debug_index = 0; | 	unsigned int debug_index = 0; | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	_enter("%lx,%x", readahead_index(ractl), readahead_count(ractl)); | 	_enter("%lx,%x", readahead_index(ractl), readahead_count(ractl)); | ||||||
| 
 | 
 | ||||||
| 	if (readahead_count(ractl) == 0) | 	if (readahead_count(ractl) == 0) | ||||||
| 		goto cleanup; | 		return; | ||||||
| 
 | 
 | ||||||
| 	rreq = netfs_alloc_request(ractl->mapping, ractl->file, | 	rreq = netfs_alloc_request(ractl->mapping, ractl->file, | ||||||
| 				   ops, netfs_priv, |  | ||||||
| 				   readahead_pos(ractl), | 				   readahead_pos(ractl), | ||||||
| 				   readahead_length(ractl), | 				   readahead_length(ractl), | ||||||
| 				   NETFS_READAHEAD); | 				   NETFS_READAHEAD); | ||||||
| 	if (IS_ERR(rreq)) | 	if (IS_ERR(rreq)) | ||||||
| 		goto cleanup; | 		return; | ||||||
| 
 | 
 | ||||||
| 	if (ops->begin_cache_operation) { | 	if (ctx->ops->begin_cache_operation) { | ||||||
| 		ret = ops->begin_cache_operation(rreq); | 		ret = ctx->ops->begin_cache_operation(rreq); | ||||||
| 		if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS) | 		if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS) | ||||||
| 			goto cleanup_free; | 			goto cleanup_free; | ||||||
| 	} | 	} | ||||||
|  | @ -804,42 +798,35 @@ void netfs_readahead(struct readahead_control *ractl, | ||||||
| cleanup_free: | cleanup_free: | ||||||
| 	netfs_put_request(rreq, false, netfs_rreq_trace_put_failed); | 	netfs_put_request(rreq, false, netfs_rreq_trace_put_failed); | ||||||
| 	return; | 	return; | ||||||
| cleanup: |  | ||||||
| 	if (netfs_priv) |  | ||||||
| 		ops->cleanup(ractl->mapping, netfs_priv); |  | ||||||
| 	return; |  | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(netfs_readahead); | EXPORT_SYMBOL(netfs_readahead); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * netfs_readpage - Helper to manage a readpage request |  * netfs_readpage - Helper to manage a readpage request | ||||||
|  * @file: The file to read from |  * @file: The file to read from | ||||||
|  * @folio: The folio to read |  * @subpage: A subpage of the folio to read | ||||||
|  * @ops: The network filesystem's operations for the helper to use |  | ||||||
|  * @netfs_priv: Private netfs data to be retained in the request |  | ||||||
|  * |  * | ||||||
|  * Fulfil a readpage request by drawing data from the cache if possible, or the |  * Fulfil a readpage request by drawing data from the cache if possible, or the | ||||||
|  * netfs if not.  Space beyond the EOF is zero-filled.  Multiple I/O requests |  * netfs if not.  Space beyond the EOF is zero-filled.  Multiple I/O requests | ||||||
|  * from different sources will get munged together. |  * from different sources will get munged together. | ||||||
|  * |  * | ||||||
|  * The calling netfs must provide a table of operations, only one of which, |  * The calling netfs must initialise a netfs context contiguous to the vfs | ||||||
|  * issue_op, is mandatory.  It may also be passed a private token, which will |  * inode before calling this. | ||||||
|  * be retained in rreq->netfs_priv and will be cleaned up by ops->cleanup(). |  | ||||||
|  * |  * | ||||||
|  * This is usable whether or not caching is enabled. |  * This is usable whether or not caching is enabled. | ||||||
|  */ |  */ | ||||||
| int netfs_readpage(struct file *file, | int netfs_readpage(struct file *file, struct page *subpage) | ||||||
| 		   struct folio *folio, |  | ||||||
| 		   const struct netfs_request_ops *ops, |  | ||||||
| 		   void *netfs_priv) |  | ||||||
| { | { | ||||||
|  | 	struct folio *folio = page_folio(subpage); | ||||||
|  | 	struct address_space *mapping = folio->mapping; | ||||||
| 	struct netfs_io_request *rreq; | 	struct netfs_io_request *rreq; | ||||||
|  | 	struct netfs_i_context *ctx = netfs_i_context(mapping->host); | ||||||
| 	unsigned int debug_index = 0; | 	unsigned int debug_index = 0; | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	_enter("%lx", folio_index(folio)); | 	_enter("%lx", folio_index(folio)); | ||||||
| 
 | 
 | ||||||
| 	rreq = netfs_alloc_request(folio->mapping, file, ops, netfs_priv, | 	rreq = netfs_alloc_request(mapping, file, | ||||||
| 				   folio_file_pos(folio), folio_size(folio), | 				   folio_file_pos(folio), folio_size(folio), | ||||||
| 				   NETFS_READPAGE); | 				   NETFS_READPAGE); | ||||||
| 	if (IS_ERR(rreq)) { | 	if (IS_ERR(rreq)) { | ||||||
|  | @ -847,8 +834,8 @@ int netfs_readpage(struct file *file, | ||||||
| 		goto alloc_error; | 		goto alloc_error; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (ops->begin_cache_operation) { | 	if (ctx->ops->begin_cache_operation) { | ||||||
| 		ret = ops->begin_cache_operation(rreq); | 		ret = ctx->ops->begin_cache_operation(rreq); | ||||||
| 		if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS) { | 		if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS) { | ||||||
| 			folio_unlock(folio); | 			folio_unlock(folio); | ||||||
| 			goto out; | 			goto out; | ||||||
|  | @ -886,8 +873,6 @@ int netfs_readpage(struct file *file, | ||||||
| 	netfs_put_request(rreq, false, netfs_rreq_trace_put_hold); | 	netfs_put_request(rreq, false, netfs_rreq_trace_put_hold); | ||||||
| 	return ret; | 	return ret; | ||||||
| alloc_error: | alloc_error: | ||||||
| 	if (netfs_priv) |  | ||||||
| 		ops->cleanup(folio_file_mapping(folio), netfs_priv); |  | ||||||
| 	folio_unlock(folio); | 	folio_unlock(folio); | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  | @ -898,6 +883,7 @@ EXPORT_SYMBOL(netfs_readpage); | ||||||
|  * @folio: The folio being prepared |  * @folio: The folio being prepared | ||||||
|  * @pos: starting position for the write |  * @pos: starting position for the write | ||||||
|  * @len: length of write |  * @len: length of write | ||||||
|  |  * @always_fill: T if the folio should always be completely filled/cleared | ||||||
|  * |  * | ||||||
|  * In some cases, write_begin doesn't need to read at all: |  * In some cases, write_begin doesn't need to read at all: | ||||||
|  * - full folio write |  * - full folio write | ||||||
|  | @ -907,17 +893,27 @@ EXPORT_SYMBOL(netfs_readpage); | ||||||
|  * If any of these criteria are met, then zero out the unwritten parts |  * If any of these criteria are met, then zero out the unwritten parts | ||||||
|  * of the folio and return true. Otherwise, return false. |  * of the folio and return true. Otherwise, return false. | ||||||
|  */ |  */ | ||||||
| static bool netfs_skip_folio_read(struct folio *folio, loff_t pos, size_t len) | static bool netfs_skip_folio_read(struct folio *folio, loff_t pos, size_t len, | ||||||
|  | 				 bool always_fill) | ||||||
| { | { | ||||||
| 	struct inode *inode = folio_inode(folio); | 	struct inode *inode = folio_inode(folio); | ||||||
| 	loff_t i_size = i_size_read(inode); | 	loff_t i_size = i_size_read(inode); | ||||||
| 	size_t offset = offset_in_folio(folio, pos); | 	size_t offset = offset_in_folio(folio, pos); | ||||||
|  | 	size_t plen = folio_size(folio); | ||||||
|  | 
 | ||||||
|  | 	if (unlikely(always_fill)) { | ||||||
|  | 		if (pos - offset + len <= i_size) | ||||||
|  | 			return false; /* Page entirely before EOF */ | ||||||
|  | 		zero_user_segment(&folio->page, 0, plen); | ||||||
|  | 		folio_mark_uptodate(folio); | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Full folio write */ | 	/* Full folio write */ | ||||||
| 	if (offset == 0 && len >= folio_size(folio)) | 	if (offset == 0 && len >= plen) | ||||||
| 		return true; | 		return true; | ||||||
| 
 | 
 | ||||||
| 	/* pos beyond last folio in the file */ | 	/* Page entirely beyond the end of the file */ | ||||||
| 	if (pos - offset >= i_size) | 	if (pos - offset >= i_size) | ||||||
| 		goto zero_out; | 		goto zero_out; | ||||||
| 
 | 
 | ||||||
|  | @ -927,7 +923,7 @@ static bool netfs_skip_folio_read(struct folio *folio, loff_t pos, size_t len) | ||||||
| 
 | 
 | ||||||
| 	return false; | 	return false; | ||||||
| zero_out: | zero_out: | ||||||
| 	zero_user_segments(&folio->page, 0, offset, offset + len, folio_size(folio)); | 	zero_user_segments(&folio->page, 0, offset, offset + len, plen); | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -940,8 +936,6 @@ static bool netfs_skip_folio_read(struct folio *folio, loff_t pos, size_t len) | ||||||
|  * @aop_flags: AOP_* flags |  * @aop_flags: AOP_* flags | ||||||
|  * @_folio: Where to put the resultant folio |  * @_folio: Where to put the resultant folio | ||||||
|  * @_fsdata: Place for the netfs to store a cookie |  * @_fsdata: Place for the netfs to store a cookie | ||||||
|  * @ops: The network filesystem's operations for the helper to use |  | ||||||
|  * @netfs_priv: Private netfs data to be retained in the request |  | ||||||
|  * |  * | ||||||
|  * Pre-read data for a write-begin request by drawing data from the cache if |  * Pre-read data for a write-begin request by drawing data from the cache if | ||||||
|  * possible, or the netfs if not.  Space beyond the EOF is zero-filled. |  * possible, or the netfs if not.  Space beyond the EOF is zero-filled. | ||||||
|  | @ -960,17 +954,18 @@ static bool netfs_skip_folio_read(struct folio *folio, loff_t pos, size_t len) | ||||||
|  * should go ahead; unlock the folio and return -EAGAIN to cause the folio to |  * should go ahead; unlock the folio and return -EAGAIN to cause the folio to | ||||||
|  * be regot; or return an error. |  * be regot; or return an error. | ||||||
|  * |  * | ||||||
|  |  * The calling netfs must initialise a netfs context contiguous to the vfs | ||||||
|  |  * inode before calling this. | ||||||
|  |  * | ||||||
|  * This is usable whether or not caching is enabled. |  * This is usable whether or not caching is enabled. | ||||||
|  */ |  */ | ||||||
| int netfs_write_begin(struct file *file, struct address_space *mapping, | int netfs_write_begin(struct file *file, struct address_space *mapping, | ||||||
| 		      loff_t pos, unsigned int len, unsigned int aop_flags, | 		      loff_t pos, unsigned int len, unsigned int aop_flags, | ||||||
| 		      struct folio **_folio, void **_fsdata, | 		      struct folio **_folio, void **_fsdata) | ||||||
| 		      const struct netfs_request_ops *ops, |  | ||||||
| 		      void *netfs_priv) |  | ||||||
| { | { | ||||||
| 	struct netfs_io_request *rreq; | 	struct netfs_io_request *rreq; | ||||||
|  | 	struct netfs_i_context *ctx = netfs_i_context(file_inode(file )); | ||||||
| 	struct folio *folio; | 	struct folio *folio; | ||||||
| 	struct inode *inode = file_inode(file); |  | ||||||
| 	unsigned int debug_index = 0, fgp_flags; | 	unsigned int debug_index = 0, fgp_flags; | ||||||
| 	pgoff_t index = pos >> PAGE_SHIFT; | 	pgoff_t index = pos >> PAGE_SHIFT; | ||||||
| 	int ret; | 	int ret; | ||||||
|  | @ -986,9 +981,9 @@ int netfs_write_begin(struct file *file, struct address_space *mapping, | ||||||
| 	if (!folio) | 	if (!folio) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
| 	if (ops->check_write_begin) { | 	if (ctx->ops->check_write_begin) { | ||||||
| 		/* Allow the netfs (eg. ceph) to flush conflicts. */ | 		/* Allow the netfs (eg. ceph) to flush conflicts. */ | ||||||
| 		ret = ops->check_write_begin(file, pos, len, folio, _fsdata); | 		ret = ctx->ops->check_write_begin(file, pos, len, folio, _fsdata); | ||||||
| 		if (ret < 0) { | 		if (ret < 0) { | ||||||
| 			trace_netfs_failure(NULL, NULL, ret, netfs_fail_check_write_begin); | 			trace_netfs_failure(NULL, NULL, ret, netfs_fail_check_write_begin); | ||||||
| 			if (ret == -EAGAIN) | 			if (ret == -EAGAIN) | ||||||
|  | @ -1004,13 +999,13 @@ int netfs_write_begin(struct file *file, struct address_space *mapping, | ||||||
| 	 * within the cache granule containing the EOF, in which case we need | 	 * within the cache granule containing the EOF, in which case we need | ||||||
| 	 * to preload the granule. | 	 * to preload the granule. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (!ops->is_cache_enabled(inode) && | 	if (!netfs_is_cache_enabled(ctx) && | ||||||
| 	    netfs_skip_folio_read(folio, pos, len)) { | 	    netfs_skip_folio_read(folio, pos, len, false)) { | ||||||
| 		netfs_stat(&netfs_n_rh_write_zskip); | 		netfs_stat(&netfs_n_rh_write_zskip); | ||||||
| 		goto have_folio_no_wait; | 		goto have_folio_no_wait; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	rreq = netfs_alloc_request(mapping, file, ops, netfs_priv, | 	rreq = netfs_alloc_request(mapping, file, | ||||||
| 				   folio_file_pos(folio), folio_size(folio), | 				   folio_file_pos(folio), folio_size(folio), | ||||||
| 				   NETFS_READ_FOR_WRITE); | 				   NETFS_READ_FOR_WRITE); | ||||||
| 	if (IS_ERR(rreq)) { | 	if (IS_ERR(rreq)) { | ||||||
|  | @ -1019,10 +1014,9 @@ int netfs_write_begin(struct file *file, struct address_space *mapping, | ||||||
| 	} | 	} | ||||||
| 	rreq->no_unlock_folio	= folio_index(folio); | 	rreq->no_unlock_folio	= folio_index(folio); | ||||||
| 	__set_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, &rreq->flags); | 	__set_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, &rreq->flags); | ||||||
| 	netfs_priv = NULL; |  | ||||||
| 
 | 
 | ||||||
| 	if (ops->begin_cache_operation) { | 	if (ctx->ops->begin_cache_operation) { | ||||||
| 		ret = ops->begin_cache_operation(rreq); | 		ret = ctx->ops->begin_cache_operation(rreq); | ||||||
| 		if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS) | 		if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS) | ||||||
| 			goto error_put; | 			goto error_put; | ||||||
| 	} | 	} | ||||||
|  | @ -1076,8 +1070,6 @@ int netfs_write_begin(struct file *file, struct address_space *mapping, | ||||||
| 	if (ret < 0) | 	if (ret < 0) | ||||||
| 		goto error; | 		goto error; | ||||||
| have_folio_no_wait: | have_folio_no_wait: | ||||||
| 	if (netfs_priv) |  | ||||||
| 		ops->cleanup(mapping, netfs_priv); |  | ||||||
| 	*_folio = folio; | 	*_folio = folio; | ||||||
| 	_leave(" = 0"); | 	_leave(" = 0"); | ||||||
| 	return 0; | 	return 0; | ||||||
|  | @ -1087,8 +1079,6 @@ int netfs_write_begin(struct file *file, struct address_space *mapping, | ||||||
| error: | error: | ||||||
| 	folio_unlock(folio); | 	folio_unlock(folio); | ||||||
| 	folio_put(folio); | 	folio_put(folio); | ||||||
| 	if (netfs_priv) |  | ||||||
| 		ops->cleanup(mapping, netfs_priv); |  | ||||||
| 	_leave(" = %d", ret); | 	_leave(" = %d", ret); | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -7,7 +7,6 @@ | ||||||
| 
 | 
 | ||||||
| #include <linux/export.h> | #include <linux/export.h> | ||||||
| #include <linux/seq_file.h> | #include <linux/seq_file.h> | ||||||
| #include <linux/netfs.h> |  | ||||||
| #include "internal.h" | #include "internal.h" | ||||||
| 
 | 
 | ||||||
| atomic_t netfs_n_rh_readahead; | atomic_t netfs_n_rh_readahead; | ||||||
|  |  | ||||||
|  | @ -118,6 +118,16 @@ enum netfs_io_source { | ||||||
| typedef void (*netfs_io_terminated_t)(void *priv, ssize_t transferred_or_error, | typedef void (*netfs_io_terminated_t)(void *priv, ssize_t transferred_or_error, | ||||||
| 				      bool was_async); | 				      bool was_async); | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * Per-inode description.  This must be directly after the inode struct. | ||||||
|  |  */ | ||||||
|  | struct netfs_i_context { | ||||||
|  | 	const struct netfs_request_ops *ops; | ||||||
|  | #if IS_ENABLED(CONFIG_FSCACHE) | ||||||
|  | 	struct fscache_cookie	*cache; | ||||||
|  | #endif | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Resources required to do operations on a cache. |  * Resources required to do operations on a cache. | ||||||
|  */ |  */ | ||||||
|  | @ -192,7 +202,6 @@ struct netfs_io_request { | ||||||
|  * Operations the network filesystem can/must provide to the helpers. |  * Operations the network filesystem can/must provide to the helpers. | ||||||
|  */ |  */ | ||||||
| struct netfs_request_ops { | struct netfs_request_ops { | ||||||
| 	bool (*is_cache_enabled)(struct inode *inode); |  | ||||||
| 	int (*init_request)(struct netfs_io_request *rreq, struct file *file); | 	int (*init_request)(struct netfs_io_request *rreq, struct file *file); | ||||||
| 	int (*begin_cache_operation)(struct netfs_io_request *rreq); | 	int (*begin_cache_operation)(struct netfs_io_request *rreq); | ||||||
| 	void (*expand_readahead)(struct netfs_io_request *rreq); | 	void (*expand_readahead)(struct netfs_io_request *rreq); | ||||||
|  | @ -263,18 +272,11 @@ struct netfs_cache_ops { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct readahead_control; | struct readahead_control; | ||||||
| extern void netfs_readahead(struct readahead_control *, | extern void netfs_readahead(struct readahead_control *); | ||||||
| 			    const struct netfs_request_ops *, | extern int netfs_readpage(struct file *, struct page *); | ||||||
| 			    void *); |  | ||||||
| extern int netfs_readpage(struct file *, |  | ||||||
| 			  struct folio *, |  | ||||||
| 			  const struct netfs_request_ops *, |  | ||||||
| 			  void *); |  | ||||||
| extern int netfs_write_begin(struct file *, struct address_space *, | extern int netfs_write_begin(struct file *, struct address_space *, | ||||||
| 			     loff_t, unsigned int, unsigned int, struct folio **, | 			     loff_t, unsigned int, unsigned int, struct folio **, | ||||||
| 			     void **, | 			     void **); | ||||||
| 			     const struct netfs_request_ops *, |  | ||||||
| 			     void *); |  | ||||||
| 
 | 
 | ||||||
| extern void netfs_subreq_terminated(struct netfs_io_subrequest *, ssize_t, bool); | extern void netfs_subreq_terminated(struct netfs_io_subrequest *, ssize_t, bool); | ||||||
| extern void netfs_get_subrequest(struct netfs_io_subrequest *subreq, | extern void netfs_get_subrequest(struct netfs_io_subrequest *subreq, | ||||||
|  | @ -283,4 +285,61 @@ extern void netfs_put_subrequest(struct netfs_io_subrequest *subreq, | ||||||
| 				 bool was_async, enum netfs_sreq_ref_trace what); | 				 bool was_async, enum netfs_sreq_ref_trace what); | ||||||
| extern void netfs_stats_show(struct seq_file *); | extern void netfs_stats_show(struct seq_file *); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * netfs_i_context - Get the netfs inode context from the inode | ||||||
|  |  * @inode: The inode to query | ||||||
|  |  * | ||||||
|  |  * Get the netfs lib inode context from the network filesystem's inode.  The | ||||||
|  |  * context struct is expected to directly follow on from the VFS inode struct. | ||||||
|  |  */ | ||||||
|  | static inline struct netfs_i_context *netfs_i_context(struct inode *inode) | ||||||
|  | { | ||||||
|  | 	return (struct netfs_i_context *)(inode + 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * netfs_inode - Get the netfs inode from the inode context | ||||||
|  |  * @ctx: The context to query | ||||||
|  |  * | ||||||
|  |  * Get the netfs inode from the netfs library's inode context.  The VFS inode | ||||||
|  |  * is expected to directly precede the context struct. | ||||||
|  |  */ | ||||||
|  | static inline struct inode *netfs_inode(struct netfs_i_context *ctx) | ||||||
|  | { | ||||||
|  | 	return ((struct inode *)ctx) - 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * netfs_i_context_init - Initialise a netfs lib context | ||||||
|  |  * @inode: The inode with which the context is associated | ||||||
|  |  * @ops: The netfs's operations list | ||||||
|  |  * | ||||||
|  |  * Initialise the netfs library context struct.  This is expected to follow on | ||||||
|  |  * directly from the VFS inode struct. | ||||||
|  |  */ | ||||||
|  | static inline void netfs_i_context_init(struct inode *inode, | ||||||
|  | 					const struct netfs_request_ops *ops) | ||||||
|  | { | ||||||
|  | 	struct netfs_i_context *ctx = netfs_i_context(inode); | ||||||
|  | 
 | ||||||
|  | 	memset(ctx, 0, sizeof(*ctx)); | ||||||
|  | 	ctx->ops = ops; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * netfs_i_cookie - Get the cache cookie from the inode | ||||||
|  |  * @inode: The inode to query | ||||||
|  |  * | ||||||
|  |  * Get the caching cookie (if enabled) from the network filesystem's inode. | ||||||
|  |  */ | ||||||
|  | static inline struct fscache_cookie *netfs_i_cookie(struct inode *inode) | ||||||
|  | { | ||||||
|  | #if IS_ENABLED(CONFIG_FSCACHE) | ||||||
|  | 	struct netfs_i_context *ctx = netfs_i_context(inode); | ||||||
|  | 	return ctx->cache; | ||||||
|  | #else | ||||||
|  | 	return NULL; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #endif /* _LINUX_NETFS_H */ | #endif /* _LINUX_NETFS_H */ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 David Howells
						David Howells