blob: 0fb315dd4d2a77758da40ae63ce9252282305fcd [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/sched.h>
13#include "internal.h"
David Howells08e0e7c2007-04-26 15:55:03 -070014
David Howells9b3f26c2009-04-03 16:42:41 +010015static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data,
16 void *buffer, uint16_t buflen);
17static uint16_t afs_cell_cache_get_aux(const void *cookie_netfs_data,
18 void *buffer, uint16_t buflen);
19static enum fscache_checkaux afs_cell_cache_check_aux(void *cookie_netfs_data,
20 const void *buffer,
21 uint16_t buflen);
22
23static uint16_t afs_vlocation_cache_get_key(const void *cookie_netfs_data,
24 void *buffer, uint16_t buflen);
25static uint16_t afs_vlocation_cache_get_aux(const void *cookie_netfs_data,
26 void *buffer, uint16_t buflen);
27static enum fscache_checkaux afs_vlocation_cache_check_aux(
28 void *cookie_netfs_data, const void *buffer, uint16_t buflen);
29
30static uint16_t afs_volume_cache_get_key(const void *cookie_netfs_data,
31 void *buffer, uint16_t buflen);
32
33static uint16_t afs_vnode_cache_get_key(const void *cookie_netfs_data,
34 void *buffer, uint16_t buflen);
35static void afs_vnode_cache_get_attr(const void *cookie_netfs_data,
36 uint64_t *size);
37static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data,
38 void *buffer, uint16_t buflen);
39static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data,
40 const void *buffer,
41 uint16_t buflen);
42static void afs_vnode_cache_now_uncached(void *cookie_netfs_data);
43
44struct fscache_netfs afs_cache_netfs = {
45 .name = "afs",
46 .version = 0,
David Howells08e0e7c2007-04-26 15:55:03 -070047};
David Howells9b3f26c2009-04-03 16:42:41 +010048
49struct fscache_cookie_def afs_cell_cache_index_def = {
50 .name = "AFS.cell",
51 .type = FSCACHE_COOKIE_TYPE_INDEX,
52 .get_key = afs_cell_cache_get_key,
53 .get_aux = afs_cell_cache_get_aux,
54 .check_aux = afs_cell_cache_check_aux,
55};
56
57struct fscache_cookie_def afs_vlocation_cache_index_def = {
58 .name = "AFS.vldb",
59 .type = FSCACHE_COOKIE_TYPE_INDEX,
60 .get_key = afs_vlocation_cache_get_key,
61 .get_aux = afs_vlocation_cache_get_aux,
62 .check_aux = afs_vlocation_cache_check_aux,
63};
64
65struct fscache_cookie_def afs_volume_cache_index_def = {
66 .name = "AFS.volume",
67 .type = FSCACHE_COOKIE_TYPE_INDEX,
68 .get_key = afs_volume_cache_get_key,
69};
70
71struct fscache_cookie_def afs_vnode_cache_index_def = {
72 .name = "AFS.vnode",
73 .type = FSCACHE_COOKIE_TYPE_DATAFILE,
74 .get_key = afs_vnode_cache_get_key,
75 .get_attr = afs_vnode_cache_get_attr,
76 .get_aux = afs_vnode_cache_get_aux,
77 .check_aux = afs_vnode_cache_check_aux,
78 .now_uncached = afs_vnode_cache_now_uncached,
79};
David Howells08e0e7c2007-04-26 15:55:03 -070080
81/*
David Howells9b3f26c2009-04-03 16:42:41 +010082 * set the key for the index entry
David Howells08e0e7c2007-04-26 15:55:03 -070083 */
David Howells9b3f26c2009-04-03 16:42:41 +010084static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data,
85 void *buffer, uint16_t bufmax)
David Howells08e0e7c2007-04-26 15:55:03 -070086{
David Howells9b3f26c2009-04-03 16:42:41 +010087 const struct afs_cell *cell = cookie_netfs_data;
88 uint16_t klen;
David Howells08e0e7c2007-04-26 15:55:03 -070089
David Howells9b3f26c2009-04-03 16:42:41 +010090 _enter("%p,%p,%u", cell, buffer, bufmax);
David Howells08e0e7c2007-04-26 15:55:03 -070091
David Howells9b3f26c2009-04-03 16:42:41 +010092 klen = strlen(cell->name);
93 if (klen > bufmax)
94 return 0;
95
96 memcpy(buffer, cell->name, klen);
97 return klen;
98}
99
100/*
101 * provide new auxilliary cache data
102 */
103static uint16_t afs_cell_cache_get_aux(const void *cookie_netfs_data,
104 void *buffer, uint16_t bufmax)
105{
106 const struct afs_cell *cell = cookie_netfs_data;
107 uint16_t dlen;
108
109 _enter("%p,%p,%u", cell, buffer, bufmax);
110
111 dlen = cell->vl_naddrs * sizeof(cell->vl_addrs[0]);
112 dlen = min(dlen, bufmax);
113 dlen &= ~(sizeof(cell->vl_addrs[0]) - 1);
114
115 memcpy(buffer, cell->vl_addrs, dlen);
116 return dlen;
117}
118
119/*
120 * check that the auxilliary data indicates that the entry is still valid
121 */
122static enum fscache_checkaux afs_cell_cache_check_aux(void *cookie_netfs_data,
123 const void *buffer,
124 uint16_t buflen)
125{
126 _leave(" = OKAY");
127 return FSCACHE_CHECKAUX_OKAY;
128}
129
130/*****************************************************************************/
131/*
132 * set the key for the index entry
133 */
134static uint16_t afs_vlocation_cache_get_key(const void *cookie_netfs_data,
135 void *buffer, uint16_t bufmax)
136{
137 const struct afs_vlocation *vlocation = cookie_netfs_data;
138 uint16_t klen;
139
140 _enter("{%s},%p,%u", vlocation->vldb.name, buffer, bufmax);
141
142 klen = strnlen(vlocation->vldb.name, sizeof(vlocation->vldb.name));
143 if (klen > bufmax)
144 return 0;
145
146 memcpy(buffer, vlocation->vldb.name, klen);
147
148 _leave(" = %u", klen);
149 return klen;
150}
151
152/*
153 * provide new auxilliary cache data
154 */
155static uint16_t afs_vlocation_cache_get_aux(const void *cookie_netfs_data,
156 void *buffer, uint16_t bufmax)
157{
158 const struct afs_vlocation *vlocation = cookie_netfs_data;
159 uint16_t dlen;
160
161 _enter("{%s},%p,%u", vlocation->vldb.name, buffer, bufmax);
162
163 dlen = sizeof(struct afs_cache_vlocation);
164 dlen -= offsetof(struct afs_cache_vlocation, nservers);
165 if (dlen > bufmax)
166 return 0;
167
168 memcpy(buffer, (uint8_t *)&vlocation->vldb.nservers, dlen);
169
170 _leave(" = %u", dlen);
171 return dlen;
172}
173
174/*
175 * check that the auxilliary data indicates that the entry is still valid
176 */
177static
178enum fscache_checkaux afs_vlocation_cache_check_aux(void *cookie_netfs_data,
179 const void *buffer,
180 uint16_t buflen)
181{
182 const struct afs_cache_vlocation *cvldb;
183 struct afs_vlocation *vlocation = cookie_netfs_data;
184 uint16_t dlen;
185
186 _enter("{%s},%p,%u", vlocation->vldb.name, buffer, buflen);
187
188 /* check the size of the data is what we're expecting */
189 dlen = sizeof(struct afs_cache_vlocation);
190 dlen -= offsetof(struct afs_cache_vlocation, nservers);
191 if (dlen != buflen)
192 return FSCACHE_CHECKAUX_OBSOLETE;
193
194 cvldb = container_of(buffer, struct afs_cache_vlocation, nservers);
195
196 /* if what's on disk is more valid than what's in memory, then use the
197 * VL record from the cache */
198 if (!vlocation->valid || vlocation->vldb.rtime == cvldb->rtime) {
199 memcpy((uint8_t *)&vlocation->vldb.nservers, buffer, dlen);
200 vlocation->valid = 1;
201 _leave(" = SUCCESS [c->m]");
202 return FSCACHE_CHECKAUX_OKAY;
David Howells08e0e7c2007-04-26 15:55:03 -0700203 }
204
David Howells9b3f26c2009-04-03 16:42:41 +0100205 /* need to update the cache if the cached info differs */
206 if (memcmp(&vlocation->vldb, buffer, dlen) != 0) {
207 /* delete if the volume IDs for this name differ */
208 if (memcmp(&vlocation->vldb.vid, &cvldb->vid,
209 sizeof(cvldb->vid)) != 0
David Howells08e0e7c2007-04-26 15:55:03 -0700210 ) {
David Howells9b3f26c2009-04-03 16:42:41 +0100211 _leave(" = OBSOLETE");
212 return FSCACHE_CHECKAUX_OBSOLETE;
David Howells08e0e7c2007-04-26 15:55:03 -0700213 }
David Howells9b3f26c2009-04-03 16:42:41 +0100214
215 _leave(" = UPDATE");
216 return FSCACHE_CHECKAUX_NEEDS_UPDATE;
David Howells08e0e7c2007-04-26 15:55:03 -0700217 }
218
David Howells9b3f26c2009-04-03 16:42:41 +0100219 _leave(" = OKAY");
220 return FSCACHE_CHECKAUX_OKAY;
David Howells08e0e7c2007-04-26 15:55:03 -0700221}
David Howells9b3f26c2009-04-03 16:42:41 +0100222
223/*****************************************************************************/
224/*
225 * set the key for the volume index entry
226 */
227static uint16_t afs_volume_cache_get_key(const void *cookie_netfs_data,
228 void *buffer, uint16_t bufmax)
229{
230 const struct afs_volume *volume = cookie_netfs_data;
231 uint16_t klen;
232
233 _enter("{%u},%p,%u", volume->type, buffer, bufmax);
234
235 klen = sizeof(volume->type);
236 if (klen > bufmax)
237 return 0;
238
239 memcpy(buffer, &volume->type, sizeof(volume->type));
240
241 _leave(" = %u", klen);
242 return klen;
243
244}
245
246/*****************************************************************************/
247/*
248 * set the key for the index entry
249 */
250static uint16_t afs_vnode_cache_get_key(const void *cookie_netfs_data,
251 void *buffer, uint16_t bufmax)
252{
253 const struct afs_vnode *vnode = cookie_netfs_data;
254 uint16_t klen;
255
256 _enter("{%x,%x,%llx},%p,%u",
257 vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version,
258 buffer, bufmax);
259
260 klen = sizeof(vnode->fid.vnode);
261 if (klen > bufmax)
262 return 0;
263
264 memcpy(buffer, &vnode->fid.vnode, sizeof(vnode->fid.vnode));
265
266 _leave(" = %u", klen);
267 return klen;
268}
David Howells08e0e7c2007-04-26 15:55:03 -0700269
270/*
David Howells9b3f26c2009-04-03 16:42:41 +0100271 * provide updated file attributes
David Howells08e0e7c2007-04-26 15:55:03 -0700272 */
David Howells9b3f26c2009-04-03 16:42:41 +0100273static void afs_vnode_cache_get_attr(const void *cookie_netfs_data,
274 uint64_t *size)
David Howells08e0e7c2007-04-26 15:55:03 -0700275{
David Howells9b3f26c2009-04-03 16:42:41 +0100276 const struct afs_vnode *vnode = cookie_netfs_data;
David Howells08e0e7c2007-04-26 15:55:03 -0700277
David Howells9b3f26c2009-04-03 16:42:41 +0100278 _enter("{%x,%x,%llx},",
279 vnode->fid.vnode, vnode->fid.unique,
280 vnode->status.data_version);
David Howells08e0e7c2007-04-26 15:55:03 -0700281
David Howells9b3f26c2009-04-03 16:42:41 +0100282 *size = vnode->status.size;
David Howells08e0e7c2007-04-26 15:55:03 -0700283}
David Howells08e0e7c2007-04-26 15:55:03 -0700284
285/*
David Howells9b3f26c2009-04-03 16:42:41 +0100286 * provide new auxilliary cache data
David Howells08e0e7c2007-04-26 15:55:03 -0700287 */
David Howells9b3f26c2009-04-03 16:42:41 +0100288static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data,
289 void *buffer, uint16_t bufmax)
David Howells08e0e7c2007-04-26 15:55:03 -0700290{
David Howells9b3f26c2009-04-03 16:42:41 +0100291 const struct afs_vnode *vnode = cookie_netfs_data;
292 uint16_t dlen;
David Howells08e0e7c2007-04-26 15:55:03 -0700293
David Howells9b3f26c2009-04-03 16:42:41 +0100294 _enter("{%x,%x,%Lx},%p,%u",
295 vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version,
296 buffer, bufmax);
David Howells08e0e7c2007-04-26 15:55:03 -0700297
David Howells9b3f26c2009-04-03 16:42:41 +0100298 dlen = sizeof(vnode->fid.unique) + sizeof(vnode->status.data_version);
299 if (dlen > bufmax)
300 return 0;
301
302 memcpy(buffer, &vnode->fid.unique, sizeof(vnode->fid.unique));
303 buffer += sizeof(vnode->fid.unique);
304 memcpy(buffer, &vnode->status.data_version,
305 sizeof(vnode->status.data_version));
306
307 _leave(" = %u", dlen);
308 return dlen;
309}
310
311/*
312 * check that the auxilliary data indicates that the entry is still valid
313 */
314static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data,
315 const void *buffer,
316 uint16_t buflen)
317{
318 struct afs_vnode *vnode = cookie_netfs_data;
319 uint16_t dlen;
320
321 _enter("{%x,%x,%llx},%p,%u",
322 vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version,
323 buffer, buflen);
324
325 /* check the size of the data is what we're expecting */
326 dlen = sizeof(vnode->fid.unique) + sizeof(vnode->status.data_version);
327 if (dlen != buflen) {
328 _leave(" = OBSOLETE [len %hx != %hx]", dlen, buflen);
329 return FSCACHE_CHECKAUX_OBSOLETE;
David Howells08e0e7c2007-04-26 15:55:03 -0700330 }
331
David Howells9b3f26c2009-04-03 16:42:41 +0100332 if (memcmp(buffer,
333 &vnode->fid.unique,
334 sizeof(vnode->fid.unique)
335 ) != 0) {
336 unsigned unique;
David Howells08e0e7c2007-04-26 15:55:03 -0700337
David Howells9b3f26c2009-04-03 16:42:41 +0100338 memcpy(&unique, buffer, sizeof(unique));
David Howells08e0e7c2007-04-26 15:55:03 -0700339
David Howells9b3f26c2009-04-03 16:42:41 +0100340 _leave(" = OBSOLETE [uniq %x != %x]",
341 unique, vnode->fid.unique);
342 return FSCACHE_CHECKAUX_OBSOLETE;
David Howells08e0e7c2007-04-26 15:55:03 -0700343 }
344
David Howells9b3f26c2009-04-03 16:42:41 +0100345 if (memcmp(buffer + sizeof(vnode->fid.unique),
346 &vnode->status.data_version,
347 sizeof(vnode->status.data_version)
348 ) != 0) {
349 afs_dataversion_t version;
350
351 memcpy(&version, buffer + sizeof(vnode->fid.unique),
352 sizeof(version));
353
354 _leave(" = OBSOLETE [vers %llx != %llx]",
355 version, vnode->status.data_version);
356 return FSCACHE_CHECKAUX_OBSOLETE;
David Howells08e0e7c2007-04-26 15:55:03 -0700357 }
358
359 _leave(" = SUCCESS");
David Howells9b3f26c2009-04-03 16:42:41 +0100360 return FSCACHE_CHECKAUX_OKAY;
David Howells08e0e7c2007-04-26 15:55:03 -0700361}
David Howells08e0e7c2007-04-26 15:55:03 -0700362
363/*
David Howells9b3f26c2009-04-03 16:42:41 +0100364 * indication the cookie is no longer uncached
365 * - this function is called when the backing store currently caching a cookie
366 * is removed
367 * - the netfs should use this to clean up any markers indicating cached pages
368 * - this is mandatory for any object that may have data
David Howells08e0e7c2007-04-26 15:55:03 -0700369 */
David Howells9b3f26c2009-04-03 16:42:41 +0100370static void afs_vnode_cache_now_uncached(void *cookie_netfs_data)
David Howells08e0e7c2007-04-26 15:55:03 -0700371{
David Howells9b3f26c2009-04-03 16:42:41 +0100372 struct afs_vnode *vnode = cookie_netfs_data;
373 struct pagevec pvec;
374 pgoff_t first;
375 int loop, nr_pages;
David Howells08e0e7c2007-04-26 15:55:03 -0700376
David Howells9b3f26c2009-04-03 16:42:41 +0100377 _enter("{%x,%x,%Lx}",
378 vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version);
David Howells08e0e7c2007-04-26 15:55:03 -0700379
David Howells9b3f26c2009-04-03 16:42:41 +0100380 pagevec_init(&pvec, 0);
381 first = 0;
382
383 for (;;) {
384 /* grab a bunch of pages to clean */
385 nr_pages = pagevec_lookup(&pvec, vnode->vfs_inode.i_mapping,
386 first,
387 PAGEVEC_SIZE - pagevec_count(&pvec));
388 if (!nr_pages)
389 break;
390
391 for (loop = 0; loop < nr_pages; loop++)
392 ClearPageFsCache(pvec.pages[loop]);
393
394 first = pvec.pages[nr_pages - 1]->index + 1;
395
396 pvec.nr = nr_pages;
397 pagevec_release(&pvec);
398 cond_resched();
399 }
400
401 _leave("");
David Howells08e0e7c2007-04-26 15:55:03 -0700402}