blob: e2b1d3f165191444e96f3eebfbeb909aa07f5db1 [file] [log] [blame]
David Howells08e0e7c2007-04-26 15:55:03 -07001/* AFS caching stuff
2 *
David Howells9b3f26c2009-04-03 16:42:41 +01003 * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
David Howells08e0e7c2007-04-26 15:55:03 -07004 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
David Howells9b3f26c2009-04-03 16:42:41 +010012#include <linux/slab.h>
13#include <linux/sched.h>
14#include "internal.h"
David Howells08e0e7c2007-04-26 15:55:03 -070015
David Howells9b3f26c2009-04-03 16:42:41 +010016static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data,
17 void *buffer, uint16_t buflen);
18static uint16_t afs_cell_cache_get_aux(const void *cookie_netfs_data,
19 void *buffer, uint16_t buflen);
20static enum fscache_checkaux afs_cell_cache_check_aux(void *cookie_netfs_data,
21 const void *buffer,
22 uint16_t buflen);
23
24static uint16_t afs_vlocation_cache_get_key(const void *cookie_netfs_data,
25 void *buffer, uint16_t buflen);
26static uint16_t afs_vlocation_cache_get_aux(const void *cookie_netfs_data,
27 void *buffer, uint16_t buflen);
28static enum fscache_checkaux afs_vlocation_cache_check_aux(
29 void *cookie_netfs_data, const void *buffer, uint16_t buflen);
30
31static uint16_t afs_volume_cache_get_key(const void *cookie_netfs_data,
32 void *buffer, uint16_t buflen);
33
34static uint16_t afs_vnode_cache_get_key(const void *cookie_netfs_data,
35 void *buffer, uint16_t buflen);
36static void afs_vnode_cache_get_attr(const void *cookie_netfs_data,
37 uint64_t *size);
38static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data,
39 void *buffer, uint16_t buflen);
40static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data,
41 const void *buffer,
42 uint16_t buflen);
43static void afs_vnode_cache_now_uncached(void *cookie_netfs_data);
44
45struct fscache_netfs afs_cache_netfs = {
46 .name = "afs",
47 .version = 0,
David Howells08e0e7c2007-04-26 15:55:03 -070048};
David Howells9b3f26c2009-04-03 16:42:41 +010049
50struct fscache_cookie_def afs_cell_cache_index_def = {
51 .name = "AFS.cell",
52 .type = FSCACHE_COOKIE_TYPE_INDEX,
53 .get_key = afs_cell_cache_get_key,
54 .get_aux = afs_cell_cache_get_aux,
55 .check_aux = afs_cell_cache_check_aux,
56};
57
58struct fscache_cookie_def afs_vlocation_cache_index_def = {
59 .name = "AFS.vldb",
60 .type = FSCACHE_COOKIE_TYPE_INDEX,
61 .get_key = afs_vlocation_cache_get_key,
62 .get_aux = afs_vlocation_cache_get_aux,
63 .check_aux = afs_vlocation_cache_check_aux,
64};
65
66struct fscache_cookie_def afs_volume_cache_index_def = {
67 .name = "AFS.volume",
68 .type = FSCACHE_COOKIE_TYPE_INDEX,
69 .get_key = afs_volume_cache_get_key,
70};
71
72struct fscache_cookie_def afs_vnode_cache_index_def = {
73 .name = "AFS.vnode",
74 .type = FSCACHE_COOKIE_TYPE_DATAFILE,
75 .get_key = afs_vnode_cache_get_key,
76 .get_attr = afs_vnode_cache_get_attr,
77 .get_aux = afs_vnode_cache_get_aux,
78 .check_aux = afs_vnode_cache_check_aux,
79 .now_uncached = afs_vnode_cache_now_uncached,
80};
David Howells08e0e7c2007-04-26 15:55:03 -070081
82/*
David Howells9b3f26c2009-04-03 16:42:41 +010083 * set the key for the index entry
David Howells08e0e7c2007-04-26 15:55:03 -070084 */
David Howells9b3f26c2009-04-03 16:42:41 +010085static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data,
86 void *buffer, uint16_t bufmax)
David Howells08e0e7c2007-04-26 15:55:03 -070087{
David Howells9b3f26c2009-04-03 16:42:41 +010088 const struct afs_cell *cell = cookie_netfs_data;
89 uint16_t klen;
David Howells08e0e7c2007-04-26 15:55:03 -070090
David Howells9b3f26c2009-04-03 16:42:41 +010091 _enter("%p,%p,%u", cell, buffer, bufmax);
David Howells08e0e7c2007-04-26 15:55:03 -070092
David Howells9b3f26c2009-04-03 16:42:41 +010093 klen = strlen(cell->name);
94 if (klen > bufmax)
95 return 0;
96
97 memcpy(buffer, cell->name, klen);
98 return klen;
99}
100
101/*
102 * provide new auxilliary cache data
103 */
104static uint16_t afs_cell_cache_get_aux(const void *cookie_netfs_data,
105 void *buffer, uint16_t bufmax)
106{
107 const struct afs_cell *cell = cookie_netfs_data;
108 uint16_t dlen;
109
110 _enter("%p,%p,%u", cell, buffer, bufmax);
111
112 dlen = cell->vl_naddrs * sizeof(cell->vl_addrs[0]);
113 dlen = min(dlen, bufmax);
114 dlen &= ~(sizeof(cell->vl_addrs[0]) - 1);
115
116 memcpy(buffer, cell->vl_addrs, dlen);
117 return dlen;
118}
119
120/*
121 * check that the auxilliary data indicates that the entry is still valid
122 */
123static enum fscache_checkaux afs_cell_cache_check_aux(void *cookie_netfs_data,
124 const void *buffer,
125 uint16_t buflen)
126{
127 _leave(" = OKAY");
128 return FSCACHE_CHECKAUX_OKAY;
129}
130
131/*****************************************************************************/
132/*
133 * set the key for the index entry
134 */
135static uint16_t afs_vlocation_cache_get_key(const void *cookie_netfs_data,
136 void *buffer, uint16_t bufmax)
137{
138 const struct afs_vlocation *vlocation = cookie_netfs_data;
139 uint16_t klen;
140
141 _enter("{%s},%p,%u", vlocation->vldb.name, buffer, bufmax);
142
143 klen = strnlen(vlocation->vldb.name, sizeof(vlocation->vldb.name));
144 if (klen > bufmax)
145 return 0;
146
147 memcpy(buffer, vlocation->vldb.name, klen);
148
149 _leave(" = %u", klen);
150 return klen;
151}
152
153/*
154 * provide new auxilliary cache data
155 */
156static uint16_t afs_vlocation_cache_get_aux(const void *cookie_netfs_data,
157 void *buffer, uint16_t bufmax)
158{
159 const struct afs_vlocation *vlocation = cookie_netfs_data;
160 uint16_t dlen;
161
162 _enter("{%s},%p,%u", vlocation->vldb.name, buffer, bufmax);
163
164 dlen = sizeof(struct afs_cache_vlocation);
165 dlen -= offsetof(struct afs_cache_vlocation, nservers);
166 if (dlen > bufmax)
167 return 0;
168
169 memcpy(buffer, (uint8_t *)&vlocation->vldb.nservers, dlen);
170
171 _leave(" = %u", dlen);
172 return dlen;
173}
174
175/*
176 * check that the auxilliary data indicates that the entry is still valid
177 */
178static
179enum fscache_checkaux afs_vlocation_cache_check_aux(void *cookie_netfs_data,
180 const void *buffer,
181 uint16_t buflen)
182{
183 const struct afs_cache_vlocation *cvldb;
184 struct afs_vlocation *vlocation = cookie_netfs_data;
185 uint16_t dlen;
186
187 _enter("{%s},%p,%u", vlocation->vldb.name, buffer, buflen);
188
189 /* check the size of the data is what we're expecting */
190 dlen = sizeof(struct afs_cache_vlocation);
191 dlen -= offsetof(struct afs_cache_vlocation, nservers);
192 if (dlen != buflen)
193 return FSCACHE_CHECKAUX_OBSOLETE;
194
195 cvldb = container_of(buffer, struct afs_cache_vlocation, nservers);
196
197 /* if what's on disk is more valid than what's in memory, then use the
198 * VL record from the cache */
199 if (!vlocation->valid || vlocation->vldb.rtime == cvldb->rtime) {
200 memcpy((uint8_t *)&vlocation->vldb.nservers, buffer, dlen);
201 vlocation->valid = 1;
202 _leave(" = SUCCESS [c->m]");
203 return FSCACHE_CHECKAUX_OKAY;
David Howells08e0e7c2007-04-26 15:55:03 -0700204 }
205
David Howells9b3f26c2009-04-03 16:42:41 +0100206 /* need to update the cache if the cached info differs */
207 if (memcmp(&vlocation->vldb, buffer, dlen) != 0) {
208 /* delete if the volume IDs for this name differ */
209 if (memcmp(&vlocation->vldb.vid, &cvldb->vid,
210 sizeof(cvldb->vid)) != 0
David Howells08e0e7c2007-04-26 15:55:03 -0700211 ) {
David Howells9b3f26c2009-04-03 16:42:41 +0100212 _leave(" = OBSOLETE");
213 return FSCACHE_CHECKAUX_OBSOLETE;
David Howells08e0e7c2007-04-26 15:55:03 -0700214 }
David Howells9b3f26c2009-04-03 16:42:41 +0100215
216 _leave(" = UPDATE");
217 return FSCACHE_CHECKAUX_NEEDS_UPDATE;
David Howells08e0e7c2007-04-26 15:55:03 -0700218 }
219
David Howells9b3f26c2009-04-03 16:42:41 +0100220 _leave(" = OKAY");
221 return FSCACHE_CHECKAUX_OKAY;
David Howells08e0e7c2007-04-26 15:55:03 -0700222}
David Howells9b3f26c2009-04-03 16:42:41 +0100223
224/*****************************************************************************/
225/*
226 * set the key for the volume index entry
227 */
228static uint16_t afs_volume_cache_get_key(const void *cookie_netfs_data,
229 void *buffer, uint16_t bufmax)
230{
231 const struct afs_volume *volume = cookie_netfs_data;
232 uint16_t klen;
233
234 _enter("{%u},%p,%u", volume->type, buffer, bufmax);
235
236 klen = sizeof(volume->type);
237 if (klen > bufmax)
238 return 0;
239
240 memcpy(buffer, &volume->type, sizeof(volume->type));
241
242 _leave(" = %u", klen);
243 return klen;
244
245}
246
247/*****************************************************************************/
248/*
249 * set the key for the index entry
250 */
251static uint16_t afs_vnode_cache_get_key(const void *cookie_netfs_data,
252 void *buffer, uint16_t bufmax)
253{
254 const struct afs_vnode *vnode = cookie_netfs_data;
255 uint16_t klen;
256
257 _enter("{%x,%x,%llx},%p,%u",
258 vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version,
259 buffer, bufmax);
260
261 klen = sizeof(vnode->fid.vnode);
262 if (klen > bufmax)
263 return 0;
264
265 memcpy(buffer, &vnode->fid.vnode, sizeof(vnode->fid.vnode));
266
267 _leave(" = %u", klen);
268 return klen;
269}
David Howells08e0e7c2007-04-26 15:55:03 -0700270
271/*
David Howells9b3f26c2009-04-03 16:42:41 +0100272 * provide updated file attributes
David Howells08e0e7c2007-04-26 15:55:03 -0700273 */
David Howells9b3f26c2009-04-03 16:42:41 +0100274static void afs_vnode_cache_get_attr(const void *cookie_netfs_data,
275 uint64_t *size)
David Howells08e0e7c2007-04-26 15:55:03 -0700276{
David Howells9b3f26c2009-04-03 16:42:41 +0100277 const struct afs_vnode *vnode = cookie_netfs_data;
David Howells08e0e7c2007-04-26 15:55:03 -0700278
David Howells9b3f26c2009-04-03 16:42:41 +0100279 _enter("{%x,%x,%llx},",
280 vnode->fid.vnode, vnode->fid.unique,
281 vnode->status.data_version);
David Howells08e0e7c2007-04-26 15:55:03 -0700282
David Howells9b3f26c2009-04-03 16:42:41 +0100283 *size = vnode->status.size;
David Howells08e0e7c2007-04-26 15:55:03 -0700284}
David Howells08e0e7c2007-04-26 15:55:03 -0700285
286/*
David Howells9b3f26c2009-04-03 16:42:41 +0100287 * provide new auxilliary cache data
David Howells08e0e7c2007-04-26 15:55:03 -0700288 */
David Howells9b3f26c2009-04-03 16:42:41 +0100289static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data,
290 void *buffer, uint16_t bufmax)
David Howells08e0e7c2007-04-26 15:55:03 -0700291{
David Howells9b3f26c2009-04-03 16:42:41 +0100292 const struct afs_vnode *vnode = cookie_netfs_data;
293 uint16_t dlen;
David Howells08e0e7c2007-04-26 15:55:03 -0700294
David Howells9b3f26c2009-04-03 16:42:41 +0100295 _enter("{%x,%x,%Lx},%p,%u",
296 vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version,
297 buffer, bufmax);
David Howells08e0e7c2007-04-26 15:55:03 -0700298
David Howells9b3f26c2009-04-03 16:42:41 +0100299 dlen = sizeof(vnode->fid.unique) + sizeof(vnode->status.data_version);
300 if (dlen > bufmax)
301 return 0;
302
303 memcpy(buffer, &vnode->fid.unique, sizeof(vnode->fid.unique));
304 buffer += sizeof(vnode->fid.unique);
305 memcpy(buffer, &vnode->status.data_version,
306 sizeof(vnode->status.data_version));
307
308 _leave(" = %u", dlen);
309 return dlen;
310}
311
312/*
313 * check that the auxilliary data indicates that the entry is still valid
314 */
315static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data,
316 const void *buffer,
317 uint16_t buflen)
318{
319 struct afs_vnode *vnode = cookie_netfs_data;
320 uint16_t dlen;
321
322 _enter("{%x,%x,%llx},%p,%u",
323 vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version,
324 buffer, buflen);
325
326 /* check the size of the data is what we're expecting */
327 dlen = sizeof(vnode->fid.unique) + sizeof(vnode->status.data_version);
328 if (dlen != buflen) {
329 _leave(" = OBSOLETE [len %hx != %hx]", dlen, buflen);
330 return FSCACHE_CHECKAUX_OBSOLETE;
David Howells08e0e7c2007-04-26 15:55:03 -0700331 }
332
David Howells9b3f26c2009-04-03 16:42:41 +0100333 if (memcmp(buffer,
334 &vnode->fid.unique,
335 sizeof(vnode->fid.unique)
336 ) != 0) {
337 unsigned unique;
David Howells08e0e7c2007-04-26 15:55:03 -0700338
David Howells9b3f26c2009-04-03 16:42:41 +0100339 memcpy(&unique, buffer, sizeof(unique));
David Howells08e0e7c2007-04-26 15:55:03 -0700340
David Howells9b3f26c2009-04-03 16:42:41 +0100341 _leave(" = OBSOLETE [uniq %x != %x]",
342 unique, vnode->fid.unique);
343 return FSCACHE_CHECKAUX_OBSOLETE;
David Howells08e0e7c2007-04-26 15:55:03 -0700344 }
345
David Howells9b3f26c2009-04-03 16:42:41 +0100346 if (memcmp(buffer + sizeof(vnode->fid.unique),
347 &vnode->status.data_version,
348 sizeof(vnode->status.data_version)
349 ) != 0) {
350 afs_dataversion_t version;
351
352 memcpy(&version, buffer + sizeof(vnode->fid.unique),
353 sizeof(version));
354
355 _leave(" = OBSOLETE [vers %llx != %llx]",
356 version, vnode->status.data_version);
357 return FSCACHE_CHECKAUX_OBSOLETE;
David Howells08e0e7c2007-04-26 15:55:03 -0700358 }
359
360 _leave(" = SUCCESS");
David Howells9b3f26c2009-04-03 16:42:41 +0100361 return FSCACHE_CHECKAUX_OKAY;
David Howells08e0e7c2007-04-26 15:55:03 -0700362}
David Howells08e0e7c2007-04-26 15:55:03 -0700363
364/*
David Howells9b3f26c2009-04-03 16:42:41 +0100365 * indication the cookie is no longer uncached
366 * - this function is called when the backing store currently caching a cookie
367 * is removed
368 * - the netfs should use this to clean up any markers indicating cached pages
369 * - this is mandatory for any object that may have data
David Howells08e0e7c2007-04-26 15:55:03 -0700370 */
David Howells9b3f26c2009-04-03 16:42:41 +0100371static void afs_vnode_cache_now_uncached(void *cookie_netfs_data)
David Howells08e0e7c2007-04-26 15:55:03 -0700372{
David Howells9b3f26c2009-04-03 16:42:41 +0100373 struct afs_vnode *vnode = cookie_netfs_data;
374 struct pagevec pvec;
375 pgoff_t first;
376 int loop, nr_pages;
David Howells08e0e7c2007-04-26 15:55:03 -0700377
David Howells9b3f26c2009-04-03 16:42:41 +0100378 _enter("{%x,%x,%Lx}",
379 vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version);
David Howells08e0e7c2007-04-26 15:55:03 -0700380
David Howells9b3f26c2009-04-03 16:42:41 +0100381 pagevec_init(&pvec, 0);
382 first = 0;
383
384 for (;;) {
385 /* grab a bunch of pages to clean */
386 nr_pages = pagevec_lookup(&pvec, vnode->vfs_inode.i_mapping,
387 first,
388 PAGEVEC_SIZE - pagevec_count(&pvec));
389 if (!nr_pages)
390 break;
391
392 for (loop = 0; loop < nr_pages; loop++)
393 ClearPageFsCache(pvec.pages[loop]);
394
395 first = pvec.pages[nr_pages - 1]->index + 1;
396
397 pvec.nr = nr_pages;
398 pagevec_release(&pvec);
399 cond_resched();
400 }
401
402 _leave("");
David Howells08e0e7c2007-04-26 15:55:03 -0700403}