1
2
3
4
5
6
7
8#include <linux/init.h>
9#include <linux/kernel.h>
10#include <linux/sched.h>
11#include <linux/mm.h>
12#include <linux/nfs_fs.h>
13#include <linux/nfs_fs_sb.h>
14#include <linux/in6.h>
15#include <linux/seq_file.h>
16#include <linux/slab.h>
17#include <linux/iversion.h>
18
19#include "internal.h"
20#include "iostat.h"
21#include "fscache.h"
22#include "nfstrace.h"
23
24#define NFS_MAX_KEY_LEN 1000
25
26static bool nfs_append_int(char *key, int *_len, unsigned long long x)
27{
28 if (*_len > NFS_MAX_KEY_LEN)
29 return false;
30 if (x == 0)
31 key[(*_len)++] = ',';
32 else
33 *_len += sprintf(key + *_len, ",%llx", x);
34 return true;
35}
36
37
38
39
40
41
42
43static bool nfs_fscache_get_client_key(struct nfs_client *clp,
44 char *key, int *_len)
45{
46 const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &clp->cl_addr;
47 const struct sockaddr_in *sin = (struct sockaddr_in *) &clp->cl_addr;
48
49 *_len += snprintf(key + *_len, NFS_MAX_KEY_LEN - *_len,
50 ",%u.%u,%x",
51 clp->rpc_ops->version,
52 clp->cl_minorversion,
53 clp->cl_addr.ss_family);
54
55 switch (clp->cl_addr.ss_family) {
56 case AF_INET:
57 if (!nfs_append_int(key, _len, sin->sin_port) ||
58 !nfs_append_int(key, _len, sin->sin_addr.s_addr))
59 return false;
60 return true;
61
62 case AF_INET6:
63 if (!nfs_append_int(key, _len, sin6->sin6_port) ||
64 !nfs_append_int(key, _len, sin6->sin6_addr.s6_addr32[0]) ||
65 !nfs_append_int(key, _len, sin6->sin6_addr.s6_addr32[1]) ||
66 !nfs_append_int(key, _len, sin6->sin6_addr.s6_addr32[2]) ||
67 !nfs_append_int(key, _len, sin6->sin6_addr.s6_addr32[3]))
68 return false;
69 return true;
70
71 default:
72 printk(KERN_WARNING "NFS: Unknown network family '%d'\n",
73 clp->cl_addr.ss_family);
74 return false;
75 }
76}
77
78
79
80
81
82
83
84
85int nfs_fscache_get_super_cookie(struct super_block *sb, const char *uniq, int ulen)
86{
87 struct fscache_volume *vcookie;
88 struct nfs_server *nfss = NFS_SB(sb);
89 unsigned int len = 3;
90 char *key;
91
92 if (uniq) {
93 nfss->fscache_uniq = kmemdup_nul(uniq, ulen, GFP_KERNEL);
94 if (!nfss->fscache_uniq)
95 return -ENOMEM;
96 }
97
98 key = kmalloc(NFS_MAX_KEY_LEN + 24, GFP_KERNEL);
99 if (!key)
100 return -ENOMEM;
101
102 memcpy(key, "nfs", 3);
103 if (!nfs_fscache_get_client_key(nfss->nfs_client, key, &len) ||
104 !nfs_append_int(key, &len, nfss->fsid.major) ||
105 !nfs_append_int(key, &len, nfss->fsid.minor) ||
106 !nfs_append_int(key, &len, sb->s_flags & NFS_SB_MASK) ||
107 !nfs_append_int(key, &len, nfss->flags) ||
108 !nfs_append_int(key, &len, nfss->rsize) ||
109 !nfs_append_int(key, &len, nfss->wsize) ||
110 !nfs_append_int(key, &len, nfss->acregmin) ||
111 !nfs_append_int(key, &len, nfss->acregmax) ||
112 !nfs_append_int(key, &len, nfss->acdirmin) ||
113 !nfs_append_int(key, &len, nfss->acdirmax) ||
114 !nfs_append_int(key, &len, nfss->client->cl_auth->au_flavor))
115 goto out;
116
117 if (ulen > 0) {
118 if (ulen > NFS_MAX_KEY_LEN - len)
119 goto out;
120 key[len++] = ',';
121 memcpy(key + len, uniq, ulen);
122 len += ulen;
123 }
124 key[len] = 0;
125
126
127 vcookie = fscache_acquire_volume(key,
128 NULL,
129 NULL, 0 );
130 if (IS_ERR(vcookie)) {
131 if (vcookie != ERR_PTR(-EBUSY)) {
132 kfree(key);
133 return PTR_ERR(vcookie);
134 }
135 pr_err("NFS: Cache volume key already in use (%s)\n", key);
136 vcookie = NULL;
137 }
138 nfss->fscache = vcookie;
139
140out:
141 kfree(key);
142 return 0;
143}
144
145
146
147
148void nfs_fscache_release_super_cookie(struct super_block *sb)
149{
150 struct nfs_server *nfss = NFS_SB(sb);
151
152 fscache_relinquish_volume(nfss->fscache, NULL, false);
153 nfss->fscache = NULL;
154 kfree(nfss->fscache_uniq);
155}
156
157
158
159
160void nfs_fscache_init_inode(struct inode *inode)
161{
162 struct nfs_fscache_inode_auxdata auxdata;
163 struct nfs_server *nfss = NFS_SERVER(inode);
164 struct nfs_inode *nfsi = NFS_I(inode);
165
166 nfsi->fscache = NULL;
167 if (!(nfss->fscache && S_ISREG(inode->i_mode)))
168 return;
169
170 nfs_fscache_update_auxdata(&auxdata, inode);
171
172 nfsi->fscache = fscache_acquire_cookie(NFS_SB(inode->i_sb)->fscache,
173 0,
174 nfsi->fh.data,
175 nfsi->fh.size,
176 &auxdata,
177 sizeof(auxdata),
178 i_size_read(inode));
179}
180
181
182
183
184void nfs_fscache_clear_inode(struct inode *inode)
185{
186 struct nfs_inode *nfsi = NFS_I(inode);
187 struct fscache_cookie *cookie = nfs_i_fscache(inode);
188
189 fscache_relinquish_cookie(cookie, false);
190 nfsi->fscache = NULL;
191}
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212void nfs_fscache_open_file(struct inode *inode, struct file *filp)
213{
214 struct nfs_fscache_inode_auxdata auxdata;
215 struct fscache_cookie *cookie = nfs_i_fscache(inode);
216 bool open_for_write = inode_is_open_for_write(inode);
217
218 if (!fscache_cookie_valid(cookie))
219 return;
220
221 fscache_use_cookie(cookie, open_for_write);
222 if (open_for_write) {
223 nfs_fscache_update_auxdata(&auxdata, inode);
224 fscache_invalidate(cookie, &auxdata, i_size_read(inode),
225 FSCACHE_INVAL_DIO_WRITE);
226 }
227}
228EXPORT_SYMBOL_GPL(nfs_fscache_open_file);
229
230void nfs_fscache_release_file(struct inode *inode, struct file *filp)
231{
232 struct nfs_fscache_inode_auxdata auxdata;
233 struct fscache_cookie *cookie = nfs_i_fscache(inode);
234 loff_t i_size = i_size_read(inode);
235
236 nfs_fscache_update_auxdata(&auxdata, inode);
237 fscache_unuse_cookie(cookie, &auxdata, &i_size);
238}
239
240
241
242
243static int fscache_fallback_read_page(struct inode *inode, struct page *page)
244{
245 struct netfs_cache_resources cres;
246 struct fscache_cookie *cookie = nfs_i_fscache(inode);
247 struct iov_iter iter;
248 struct bio_vec bvec[1];
249 int ret;
250
251 memset(&cres, 0, sizeof(cres));
252 bvec[0].bv_page = page;
253 bvec[0].bv_offset = 0;
254 bvec[0].bv_len = PAGE_SIZE;
255 iov_iter_bvec(&iter, READ, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
256
257 ret = fscache_begin_read_operation(&cres, cookie);
258 if (ret < 0)
259 return ret;
260
261 ret = fscache_read(&cres, page_offset(page), &iter, NETFS_READ_HOLE_FAIL,
262 NULL, NULL);
263 fscache_end_operation(&cres);
264 return ret;
265}
266
267
268
269
270static int fscache_fallback_write_page(struct inode *inode, struct page *page,
271 bool no_space_allocated_yet)
272{
273 struct netfs_cache_resources cres;
274 struct fscache_cookie *cookie = nfs_i_fscache(inode);
275 struct iov_iter iter;
276 struct bio_vec bvec[1];
277 loff_t start = page_offset(page);
278 size_t len = PAGE_SIZE;
279 int ret;
280
281 memset(&cres, 0, sizeof(cres));
282 bvec[0].bv_page = page;
283 bvec[0].bv_offset = 0;
284 bvec[0].bv_len = PAGE_SIZE;
285 iov_iter_bvec(&iter, WRITE, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
286
287 ret = fscache_begin_write_operation(&cres, cookie);
288 if (ret < 0)
289 return ret;
290
291 ret = cres.ops->prepare_write(&cres, &start, &len, i_size_read(inode),
292 no_space_allocated_yet);
293 if (ret == 0)
294 ret = fscache_write(&cres, page_offset(page), &iter, NULL, NULL);
295 fscache_end_operation(&cres);
296 return ret;
297}
298
299
300
301
302int __nfs_fscache_read_page(struct inode *inode, struct page *page)
303{
304 int ret;
305
306 trace_nfs_fscache_read_page(inode, page);
307 if (PageChecked(page)) {
308 ClearPageChecked(page);
309 ret = 1;
310 goto out;
311 }
312
313 ret = fscache_fallback_read_page(inode, page);
314 if (ret < 0) {
315 nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_FAIL);
316 SetPageChecked(page);
317 goto out;
318 }
319
320
321 nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_OK);
322 SetPageUptodate(page);
323 ret = 0;
324out:
325 trace_nfs_fscache_read_page_exit(inode, page, ret);
326 return ret;
327}
328
329
330
331
332
333void __nfs_fscache_write_page(struct inode *inode, struct page *page)
334{
335 int ret;
336
337 trace_nfs_fscache_write_page(inode, page);
338
339 ret = fscache_fallback_write_page(inode, page, true);
340
341 if (ret != 0) {
342 nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_WRITTEN_FAIL);
343 nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_UNCACHED);
344 } else {
345 nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_WRITTEN_OK);
346 }
347 trace_nfs_fscache_write_page_exit(inode, page, ret);
348}
349