3 * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
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.
12 #include <linux/slab.h>
13 #include <linux/sched.h>
16 static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data
,
17 void *buffer
, uint16_t buflen
);
18 static uint16_t afs_cell_cache_get_aux(const void *cookie_netfs_data
,
19 void *buffer
, uint16_t buflen
);
20 static enum fscache_checkaux
afs_cell_cache_check_aux(void *cookie_netfs_data
,
24 static uint16_t afs_vlocation_cache_get_key(const void *cookie_netfs_data
,
25 void *buffer
, uint16_t buflen
);
26 static uint16_t afs_vlocation_cache_get_aux(const void *cookie_netfs_data
,
27 void *buffer
, uint16_t buflen
);
28 static enum fscache_checkaux
afs_vlocation_cache_check_aux(
29 void *cookie_netfs_data
, const void *buffer
, uint16_t buflen
);
31 static uint16_t afs_volume_cache_get_key(const void *cookie_netfs_data
,
32 void *buffer
, uint16_t buflen
);
34 static uint16_t afs_vnode_cache_get_key(const void *cookie_netfs_data
,
35 void *buffer
, uint16_t buflen
);
36 static void afs_vnode_cache_get_attr(const void *cookie_netfs_data
,
38 static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data
,
39 void *buffer
, uint16_t buflen
);
40 static enum fscache_checkaux
afs_vnode_cache_check_aux(void *cookie_netfs_data
,
43 static void afs_vnode_cache_now_uncached(void *cookie_netfs_data
);
45 struct fscache_netfs afs_cache_netfs
= {
50 struct fscache_cookie_def afs_cell_cache_index_def
= {
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
,
58 struct fscache_cookie_def afs_vlocation_cache_index_def
= {
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
,
66 struct fscache_cookie_def afs_volume_cache_index_def
= {
68 .type
= FSCACHE_COOKIE_TYPE_INDEX
,
69 .get_key
= afs_volume_cache_get_key
,
72 struct fscache_cookie_def afs_vnode_cache_index_def
= {
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
,
83 * set the key for the index entry
85 static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data
,
86 void *buffer
, uint16_t bufmax
)
88 const struct afs_cell
*cell
= cookie_netfs_data
;
91 _enter("%p,%p,%u", cell
, buffer
, bufmax
);
93 klen
= strlen(cell
->name
);
97 memcpy(buffer
, cell
->name
, klen
);
102 * provide new auxilliary cache data
104 static uint16_t afs_cell_cache_get_aux(const void *cookie_netfs_data
,
105 void *buffer
, uint16_t bufmax
)
107 const struct afs_cell
*cell
= cookie_netfs_data
;
110 _enter("%p,%p,%u", cell
, buffer
, bufmax
);
112 dlen
= cell
->vl_naddrs
* sizeof(cell
->vl_addrs
[0]);
113 dlen
= min(dlen
, bufmax
);
114 dlen
&= ~(sizeof(cell
->vl_addrs
[0]) - 1);
116 memcpy(buffer
, cell
->vl_addrs
, dlen
);
121 * check that the auxilliary data indicates that the entry is still valid
123 static enum fscache_checkaux
afs_cell_cache_check_aux(void *cookie_netfs_data
,
128 return FSCACHE_CHECKAUX_OKAY
;
131 /*****************************************************************************/
133 * set the key for the index entry
135 static uint16_t afs_vlocation_cache_get_key(const void *cookie_netfs_data
,
136 void *buffer
, uint16_t bufmax
)
138 const struct afs_vlocation
*vlocation
= cookie_netfs_data
;
141 _enter("{%s},%p,%u", vlocation
->vldb
.name
, buffer
, bufmax
);
143 klen
= strnlen(vlocation
->vldb
.name
, sizeof(vlocation
->vldb
.name
));
147 memcpy(buffer
, vlocation
->vldb
.name
, klen
);
149 _leave(" = %u", klen
);
154 * provide new auxilliary cache data
156 static uint16_t afs_vlocation_cache_get_aux(const void *cookie_netfs_data
,
157 void *buffer
, uint16_t bufmax
)
159 const struct afs_vlocation
*vlocation
= cookie_netfs_data
;
162 _enter("{%s},%p,%u", vlocation
->vldb
.name
, buffer
, bufmax
);
164 dlen
= sizeof(struct afs_cache_vlocation
);
165 dlen
-= offsetof(struct afs_cache_vlocation
, nservers
);
169 memcpy(buffer
, (uint8_t *)&vlocation
->vldb
.nservers
, dlen
);
171 _leave(" = %u", dlen
);
176 * check that the auxilliary data indicates that the entry is still valid
179 enum fscache_checkaux
afs_vlocation_cache_check_aux(void *cookie_netfs_data
,
183 const struct afs_cache_vlocation
*cvldb
;
184 struct afs_vlocation
*vlocation
= cookie_netfs_data
;
187 _enter("{%s},%p,%u", vlocation
->vldb
.name
, buffer
, buflen
);
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
);
193 return FSCACHE_CHECKAUX_OBSOLETE
;
195 cvldb
= container_of(buffer
, struct afs_cache_vlocation
, nservers
);
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
;
206 /* 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
212 _leave(" = OBSOLETE");
213 return FSCACHE_CHECKAUX_OBSOLETE
;
217 return FSCACHE_CHECKAUX_NEEDS_UPDATE
;
221 return FSCACHE_CHECKAUX_OKAY
;
224 /*****************************************************************************/
226 * set the key for the volume index entry
228 static uint16_t afs_volume_cache_get_key(const void *cookie_netfs_data
,
229 void *buffer
, uint16_t bufmax
)
231 const struct afs_volume
*volume
= cookie_netfs_data
;
234 _enter("{%u},%p,%u", volume
->type
, buffer
, bufmax
);
236 klen
= sizeof(volume
->type
);
240 memcpy(buffer
, &volume
->type
, sizeof(volume
->type
));
242 _leave(" = %u", klen
);
247 /*****************************************************************************/
249 * set the key for the index entry
251 static uint16_t afs_vnode_cache_get_key(const void *cookie_netfs_data
,
252 void *buffer
, uint16_t bufmax
)
254 const struct afs_vnode
*vnode
= cookie_netfs_data
;
257 _enter("{%x,%x,%llx},%p,%u",
258 vnode
->fid
.vnode
, vnode
->fid
.unique
, vnode
->status
.data_version
,
261 klen
= sizeof(vnode
->fid
.vnode
);
265 memcpy(buffer
, &vnode
->fid
.vnode
, sizeof(vnode
->fid
.vnode
));
267 _leave(" = %u", klen
);
272 * provide updated file attributes
274 static void afs_vnode_cache_get_attr(const void *cookie_netfs_data
,
277 const struct afs_vnode
*vnode
= cookie_netfs_data
;
279 _enter("{%x,%x,%llx},",
280 vnode
->fid
.vnode
, vnode
->fid
.unique
,
281 vnode
->status
.data_version
);
283 *size
= vnode
->status
.size
;
287 * provide new auxilliary cache data
289 static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data
,
290 void *buffer
, uint16_t bufmax
)
292 const struct afs_vnode
*vnode
= cookie_netfs_data
;
295 _enter("{%x,%x,%Lx},%p,%u",
296 vnode
->fid
.vnode
, vnode
->fid
.unique
, vnode
->status
.data_version
,
299 dlen
= sizeof(vnode
->fid
.unique
) + sizeof(vnode
->status
.data_version
);
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
));
308 _leave(" = %u", dlen
);
313 * check that the auxilliary data indicates that the entry is still valid
315 static enum fscache_checkaux
afs_vnode_cache_check_aux(void *cookie_netfs_data
,
319 struct afs_vnode
*vnode
= cookie_netfs_data
;
322 _enter("{%x,%x,%llx},%p,%u",
323 vnode
->fid
.vnode
, vnode
->fid
.unique
, vnode
->status
.data_version
,
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
;
335 sizeof(vnode
->fid
.unique
)
339 memcpy(&unique
, buffer
, sizeof(unique
));
341 _leave(" = OBSOLETE [uniq %x != %x]",
342 unique
, vnode
->fid
.unique
);
343 return FSCACHE_CHECKAUX_OBSOLETE
;
346 if (memcmp(buffer
+ sizeof(vnode
->fid
.unique
),
347 &vnode
->status
.data_version
,
348 sizeof(vnode
->status
.data_version
)
350 afs_dataversion_t version
;
352 memcpy(&version
, buffer
+ sizeof(vnode
->fid
.unique
),
355 _leave(" = OBSOLETE [vers %llx != %llx]",
356 version
, vnode
->status
.data_version
);
357 return FSCACHE_CHECKAUX_OBSOLETE
;
360 _leave(" = SUCCESS");
361 return FSCACHE_CHECKAUX_OKAY
;
365 * indication the cookie is no longer uncached
366 * - this function is called when the backing store currently caching a cookie
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
371 static void afs_vnode_cache_now_uncached(void *cookie_netfs_data
)
373 struct afs_vnode
*vnode
= cookie_netfs_data
;
378 _enter("{%x,%x,%Lx}",
379 vnode
->fid
.vnode
, vnode
->fid
.unique
, vnode
->status
.data_version
);
381 pagevec_init(&pvec
, 0);
385 /* grab a bunch of pages to clean */
386 nr_pages
= pagevec_lookup(&pvec
, vnode
->vfs_inode
.i_mapping
,
388 PAGEVEC_SIZE
- pagevec_count(&pvec
));
392 for (loop
= 0; loop
< nr_pages
; loop
++)
393 ClearPageFsCache(pvec
.pages
[loop
]);
395 first
= pvec
.pages
[nr_pages
- 1]->index
+ 1;
398 pagevec_release(&pvec
);