Commit | Line | Data |
---|---|---|
b4d0d230 | 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
8ec442ae DH |
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) | |
8ec442ae DH |
6 | */ |
7 | ||
8 | #ifndef _NFS_FSCACHE_H | |
9 | #define _NFS_FSCACHE_H | |
10 | ||
d7bdba1c | 11 | #include <linux/swap.h> |
8ec442ae DH |
12 | #include <linux/nfs_fs.h> |
13 | #include <linux/nfs_mount.h> | |
14 | #include <linux/nfs4_mount.h> | |
15 | #include <linux/fscache.h> | |
a6b5a28e | 16 | #include <linux/iversion.h> |
8ec442ae DH |
17 | |
18 | #ifdef CONFIG_NFS_FSCACHE | |
19 | ||
402cb8dd DH |
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 { | |
6e31ded6 AB |
30 | s64 mtime_sec; |
31 | s64 mtime_nsec; | |
32 | s64 ctime_sec; | |
33 | s64 ctime_nsec; | |
34 | u64 change_attr; | |
402cb8dd DH |
35 | }; |
36 | ||
000dbe0b DW |
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(&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(&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(netfs); | |
80 | } | |
81 | static inline void nfs_netfs_inode_init(struct nfs_inode *nfsi) | |
82 | { | |
83 | netfs_inode_init(&nfsi->netfs, &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 | ||
14727281 DH |
89 | /* |
90 | * fscache.c | |
91 | */ | |
a6b5a28e | 92 | extern int nfs_fscache_get_super_cookie(struct super_block *, const char *, int); |
08734048 DH |
93 | extern void nfs_fscache_release_super_cookie(struct super_block *); |
94 | ||
f1fe29b4 DH |
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 *); | |
a6b5a28e | 98 | extern void nfs_fscache_release_file(struct inode *, struct file *); |
000dbe0b DW |
99 | extern int nfs_netfs_readahead(struct readahead_control *ractl); |
100 | extern int nfs_netfs_read_folio(struct file *file, struct folio *folio); | |
9a9fc1c0 | 101 | |
3577da4a | 102 | static inline bool nfs_fscache_release_folio(struct folio *folio, gfp_t gfp) |
545db45f | 103 | { |
3577da4a | 104 | if (folio_test_fscache(folio)) { |
d7bdba1c | 105 | if (current_is_kswapd() || !(gfp & __GFP_FS)) |
a6b5a28e | 106 | return false; |
3577da4a | 107 | folio_wait_fscache(folio); |
a6b5a28e | 108 | } |
000dbe0b | 109 | fscache_note_page_release(netfs_i_cookie(netfs_inode(folio->mapping->host))); |
a6b5a28e | 110 | return true; |
545db45f DH |
111 | } |
112 | ||
a6b5a28e | 113 | static inline void nfs_fscache_update_auxdata(struct nfs_fscache_inode_auxdata *auxdata, |
45f3a70b | 114 | struct inode *inode) |
de242c0b | 115 | { |
a6b5a28e | 116 | memset(auxdata, 0, sizeof(*auxdata)); |
41d581a9 JL |
117 | auxdata->mtime_sec = inode_get_mtime(inode).tv_sec; |
118 | auxdata->mtime_nsec = inode_get_mtime(inode).tv_nsec; | |
55e04e9c JL |
119 | auxdata->ctime_sec = inode_get_ctime(inode).tv_sec; |
120 | auxdata->ctime_nsec = inode_get_ctime(inode).tv_nsec; | |
a6b5a28e | 121 | |
45f3a70b DW |
122 | if (NFS_SERVER(inode)->nfs_client->rpc_ops->version == 4) |
123 | auxdata->change_attr = inode_peek_iversion_raw(inode); | |
de242c0b DH |
124 | } |
125 | ||
126 | /* | |
a6b5a28e | 127 | * Invalidate the contents of fscache for this inode. This will not sleep. |
de242c0b | 128 | */ |
a6b5a28e | 129 | static inline void nfs_fscache_invalidate(struct inode *inode, int flags) |
de242c0b | 130 | { |
a6b5a28e | 131 | struct nfs_fscache_inode_auxdata auxdata; |
88a4d7bd | 132 | struct fscache_cookie *cookie = netfs_i_cookie(&NFS_I(inode)->netfs); |
a6b5a28e | 133 | |
88a4d7bd DW |
134 | nfs_fscache_update_auxdata(&auxdata, inode); |
135 | fscache_invalidate(cookie, &auxdata, i_size_read(inode), flags); | |
de242c0b DH |
136 | } |
137 | ||
5d1acff1 DH |
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 | { | |
dea1bb35 | 143 | if (server->fscache) |
5d1acff1 DH |
144 | return "yes"; |
145 | return "no "; | |
146 | } | |
147 | ||
000dbe0b DW |
148 | static inline void nfs_netfs_set_pgio_header(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 | } | |
8ec442ae | 162 | #else /* CONFIG_NFS_FSCACHE */ |
000dbe0b DW |
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 | } | |
08734048 DH |
170 | static inline void nfs_fscache_release_super_cookie(struct super_block *sb) {} |
171 | ||
f1fe29b4 DH |
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) {} | |
a6b5a28e | 176 | static inline void nfs_fscache_release_file(struct inode *inode, struct file *file) {} |
000dbe0b | 177 | static inline int nfs_netfs_readahead(struct readahead_control *ractl) |
545db45f | 178 | { |
000dbe0b | 179 | return -ENOBUFS; |
545db45f | 180 | } |
000dbe0b | 181 | static inline int nfs_netfs_read_folio(struct file *file, struct folio *folio) |
9a9fc1c0 DH |
182 | { |
183 | return -ENOBUFS; | |
184 | } | |
000dbe0b DW |
185 | |
186 | static inline bool nfs_fscache_release_folio(struct folio *folio, gfp_t gfp) | |
187 | { | |
188 | return true; /* may release folio */ | |
189 | } | |
a6b5a28e | 190 | static inline void nfs_fscache_invalidate(struct inode *inode, int flags) {} |
de242c0b | 191 | |
5d1acff1 DH |
192 | static inline const char *nfs_server_fscache_state(struct nfs_server *server) |
193 | { | |
194 | return "no "; | |
195 | } | |
000dbe0b DW |
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) {} | |
8ec442ae DH |
201 | #endif /* CONFIG_NFS_FSCACHE */ |
202 | #endif /* _NFS_FSCACHE_H */ |