1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
2 | /* NFS filesystem cache interface definitions |
3 | * |
4 | * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved. |
5 | * Written by David Howells (dhowells@redhat.com) |
6 | */ |
7 | |
8 | #ifndef _NFS_FSCACHE_H |
9 | #define _NFS_FSCACHE_H |
10 | |
11 | #include <linux/swap.h> |
12 | #include <linux/nfs_fs.h> |
13 | #include <linux/nfs_mount.h> |
14 | #include <linux/nfs4_mount.h> |
15 | #include <linux/fscache.h> |
16 | #include <linux/iversion.h> |
17 | |
18 | #ifdef CONFIG_NFS_FSCACHE |
19 | |
20 | /* |
21 | * Definition of the auxiliary data attached to NFS inode storage objects |
22 | * within the cache. |
23 | * |
24 | * The contents of this struct are recorded in the on-disk local cache in the |
25 | * auxiliary data attached to the data storage object backing an inode. This |
26 | * permits coherency to be managed when a new inode binds to an already extant |
27 | * cache object. |
28 | */ |
29 | struct nfs_fscache_inode_auxdata { |
30 | s64 mtime_sec; |
31 | s64 mtime_nsec; |
32 | s64 ctime_sec; |
33 | s64 ctime_nsec; |
34 | u64 change_attr; |
35 | }; |
36 | |
37 | struct nfs_netfs_io_data { |
38 | /* |
39 | * NFS may split a netfs_io_subrequest into multiple RPCs, each |
40 | * with their own read completion. In netfs, we can only call |
41 | * netfs_subreq_terminated() once for each subrequest. Use the |
42 | * refcount here to double as a marker of the last RPC completion, |
43 | * and only call netfs via netfs_subreq_terminated() once. |
44 | */ |
45 | refcount_t refcount; |
46 | struct netfs_io_subrequest *sreq; |
47 | |
48 | /* |
49 | * Final disposition of the netfs_io_subrequest, sent in |
50 | * netfs_subreq_terminated() |
51 | */ |
52 | atomic64_t transferred; |
53 | int error; |
54 | }; |
55 | |
56 | static inline void nfs_netfs_get(struct nfs_netfs_io_data *netfs) |
57 | { |
58 | refcount_inc(r: &netfs->refcount); |
59 | } |
60 | |
61 | static inline void nfs_netfs_put(struct nfs_netfs_io_data *netfs) |
62 | { |
63 | ssize_t final_len; |
64 | |
65 | /* Only the last RPC completion should call netfs_subreq_terminated() */ |
66 | if (!refcount_dec_and_test(r: &netfs->refcount)) |
67 | return; |
68 | |
69 | /* |
70 | * The NFS pageio interface may read a complete page, even when netfs |
71 | * only asked for a partial page. Specifically, this may be seen when |
72 | * one thread is truncating a file while another one is reading the last |
73 | * page of the file. |
74 | * Correct the final length here to be no larger than the netfs subrequest |
75 | * length, and thus avoid netfs's "Subreq overread" warning message. |
76 | */ |
77 | final_len = min_t(s64, netfs->sreq->len, atomic64_read(&netfs->transferred)); |
78 | netfs_subreq_terminated(netfs->sreq, netfs->error ?: final_len, false); |
79 | kfree(objp: netfs); |
80 | } |
81 | static inline void nfs_netfs_inode_init(struct nfs_inode *nfsi) |
82 | { |
83 | netfs_inode_init(ctx: &nfsi->netfs, ops: &nfs_netfs_ops); |
84 | } |
85 | extern void nfs_netfs_initiate_read(struct nfs_pgio_header *hdr); |
86 | extern void nfs_netfs_read_completion(struct nfs_pgio_header *hdr); |
87 | extern int nfs_netfs_folio_unlock(struct folio *folio); |
88 | |
89 | /* |
90 | * fscache.c |
91 | */ |
92 | extern int nfs_fscache_get_super_cookie(struct super_block *, const char *, int); |
93 | extern void nfs_fscache_release_super_cookie(struct super_block *); |
94 | |
95 | extern void nfs_fscache_init_inode(struct inode *); |
96 | extern void nfs_fscache_clear_inode(struct inode *); |
97 | extern void nfs_fscache_open_file(struct inode *, struct file *); |
98 | extern void nfs_fscache_release_file(struct inode *, struct file *); |
99 | extern int nfs_netfs_readahead(struct readahead_control *ractl); |
100 | extern int nfs_netfs_read_folio(struct file *file, struct folio *folio); |
101 | |
102 | static inline bool nfs_fscache_release_folio(struct folio *folio, gfp_t gfp) |
103 | { |
104 | if (folio_test_fscache(folio)) { |
105 | if (current_is_kswapd() || !(gfp & __GFP_FS)) |
106 | return false; |
107 | folio_wait_fscache(folio); |
108 | } |
109 | fscache_note_page_release(cookie: netfs_i_cookie(ctx: netfs_inode(inode: folio->mapping->host))); |
110 | return true; |
111 | } |
112 | |
113 | static inline void nfs_fscache_update_auxdata(struct nfs_fscache_inode_auxdata *auxdata, |
114 | struct inode *inode) |
115 | { |
116 | memset(auxdata, 0, sizeof(*auxdata)); |
117 | auxdata->mtime_sec = inode_get_mtime(inode).tv_sec; |
118 | auxdata->mtime_nsec = inode_get_mtime(inode).tv_nsec; |
119 | auxdata->ctime_sec = inode_get_ctime(inode).tv_sec; |
120 | auxdata->ctime_nsec = inode_get_ctime(inode).tv_nsec; |
121 | |
122 | if (NFS_SERVER(inode)->nfs_client->rpc_ops->version == 4) |
123 | auxdata->change_attr = inode_peek_iversion_raw(inode); |
124 | } |
125 | |
126 | /* |
127 | * Invalidate the contents of fscache for this inode. This will not sleep. |
128 | */ |
129 | static inline void nfs_fscache_invalidate(struct inode *inode, int flags) |
130 | { |
131 | struct nfs_fscache_inode_auxdata auxdata; |
132 | struct fscache_cookie *cookie = netfs_i_cookie(ctx: &NFS_I(inode)->netfs); |
133 | |
134 | nfs_fscache_update_auxdata(auxdata: &auxdata, inode); |
135 | fscache_invalidate(cookie, aux_data: &auxdata, size: i_size_read(inode), flags); |
136 | } |
137 | |
138 | /* |
139 | * indicate the client caching state as readable text |
140 | */ |
141 | static inline const char *nfs_server_fscache_state(struct nfs_server *server) |
142 | { |
143 | if (server->fscache) |
144 | return "yes" ; |
145 | return "no " ; |
146 | } |
147 | |
148 | static inline void (struct nfs_pgio_header *hdr, |
149 | struct nfs_pageio_descriptor *desc) |
150 | { |
151 | hdr->netfs = desc->pg_netfs; |
152 | } |
153 | static inline void nfs_netfs_set_pageio_descriptor(struct nfs_pageio_descriptor *desc, |
154 | struct nfs_pgio_header *hdr) |
155 | { |
156 | desc->pg_netfs = hdr->netfs; |
157 | } |
158 | static inline void nfs_netfs_reset_pageio_descriptor(struct nfs_pageio_descriptor *desc) |
159 | { |
160 | desc->pg_netfs = NULL; |
161 | } |
162 | #else /* CONFIG_NFS_FSCACHE */ |
163 | static inline void nfs_netfs_inode_init(struct nfs_inode *nfsi) {} |
164 | static inline void nfs_netfs_initiate_read(struct nfs_pgio_header *hdr) {} |
165 | static inline void nfs_netfs_read_completion(struct nfs_pgio_header *hdr) {} |
166 | static inline int nfs_netfs_folio_unlock(struct folio *folio) |
167 | { |
168 | return 1; |
169 | } |
170 | static inline void nfs_fscache_release_super_cookie(struct super_block *sb) {} |
171 | |
172 | static inline void nfs_fscache_init_inode(struct inode *inode) {} |
173 | static inline void nfs_fscache_clear_inode(struct inode *inode) {} |
174 | static inline void nfs_fscache_open_file(struct inode *inode, |
175 | struct file *filp) {} |
176 | static inline void nfs_fscache_release_file(struct inode *inode, struct file *file) {} |
177 | static inline int nfs_netfs_readahead(struct readahead_control *ractl) |
178 | { |
179 | return -ENOBUFS; |
180 | } |
181 | static inline int nfs_netfs_read_folio(struct file *file, struct folio *folio) |
182 | { |
183 | return -ENOBUFS; |
184 | } |
185 | |
186 | static inline bool nfs_fscache_release_folio(struct folio *folio, gfp_t gfp) |
187 | { |
188 | return true; /* may release folio */ |
189 | } |
190 | static inline void nfs_fscache_invalidate(struct inode *inode, int flags) {} |
191 | |
192 | static inline const char *nfs_server_fscache_state(struct nfs_server *server) |
193 | { |
194 | return "no " ; |
195 | } |
196 | static inline void nfs_netfs_set_pgio_header(struct nfs_pgio_header *hdr, |
197 | struct nfs_pageio_descriptor *desc) {} |
198 | static inline void nfs_netfs_set_pageio_descriptor(struct nfs_pageio_descriptor *desc, |
199 | struct nfs_pgio_header *hdr) {} |
200 | static inline void nfs_netfs_reset_pageio_descriptor(struct nfs_pageio_descriptor *desc) {} |
201 | #endif /* CONFIG_NFS_FSCACHE */ |
202 | #endif /* _NFS_FSCACHE_H */ |
203 | |