Merge branches 'sh/pci-express-integration', 'sh/rsk-updates', 'sh/platform-updates...
[linux-2.6] / fs / afs / cache.c
1 /* AFS caching stuff
2  *
3  * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
4  * 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
12 #include <linux/slab.h>
13 #include <linux/sched.h>
14 #include "internal.h"
15
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,
21                                                       const void *buffer,
22                                                       uint16_t buflen);
23
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);
30
31 static uint16_t afs_volume_cache_get_key(const void *cookie_netfs_data,
32                                          void *buffer, uint16_t buflen);
33
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,
37                                      uint64_t *size);
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,
41                                                        const void *buffer,
42                                                        uint16_t buflen);
43 static void afs_vnode_cache_now_uncached(void *cookie_netfs_data);
44
45 struct fscache_netfs afs_cache_netfs = {
46         .name                   = "afs",
47         .version                = 0,
48 };
49
50 struct 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
58 struct 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
66 struct 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
72 struct 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 };
81
82 /*
83  * set the key for the index entry
84  */
85 static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data,
86                                        void *buffer, uint16_t bufmax)
87 {
88         const struct afs_cell *cell = cookie_netfs_data;
89         uint16_t klen;
90
91         _enter("%p,%p,%u", cell, buffer, bufmax);
92
93         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  */
104 static 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  */
123 static 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  */
135 static 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  */
156 static 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  */
178 static
179 enum 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;
204         }
205
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
211                     ) {
212                         _leave(" = OBSOLETE");
213                         return FSCACHE_CHECKAUX_OBSOLETE;
214                 }
215
216                 _leave(" = UPDATE");
217                 return FSCACHE_CHECKAUX_NEEDS_UPDATE;
218         }
219
220         _leave(" = OKAY");
221         return FSCACHE_CHECKAUX_OKAY;
222 }
223
224 /*****************************************************************************/
225 /*
226  * set the key for the volume index entry
227  */
228 static 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  */
251 static 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 }
270
271 /*
272  * provide updated file attributes
273  */
274 static void afs_vnode_cache_get_attr(const void *cookie_netfs_data,
275                                      uint64_t *size)
276 {
277         const struct afs_vnode *vnode = cookie_netfs_data;
278
279         _enter("{%x,%x,%llx},",
280                vnode->fid.vnode, vnode->fid.unique,
281                vnode->status.data_version);
282
283         *size = vnode->status.size;
284 }
285
286 /*
287  * provide new auxilliary cache data
288  */
289 static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data,
290                                         void *buffer, uint16_t bufmax)
291 {
292         const struct afs_vnode *vnode = cookie_netfs_data;
293         uint16_t dlen;
294
295         _enter("{%x,%x,%Lx},%p,%u",
296                vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version,
297                buffer, bufmax);
298
299         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  */
315 static 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;
331         }
332
333         if (memcmp(buffer,
334                    &vnode->fid.unique,
335                    sizeof(vnode->fid.unique)
336                    ) != 0) {
337                 unsigned unique;
338
339                 memcpy(&unique, buffer, sizeof(unique));
340
341                 _leave(" = OBSOLETE [uniq %x != %x]",
342                        unique, vnode->fid.unique);
343                 return FSCACHE_CHECKAUX_OBSOLETE;
344         }
345
346         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;
358         }
359
360         _leave(" = SUCCESS");
361         return FSCACHE_CHECKAUX_OKAY;
362 }
363
364 /*
365  * 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
370  */
371 static void afs_vnode_cache_now_uncached(void *cookie_netfs_data)
372 {
373         struct afs_vnode *vnode = cookie_netfs_data;
374         struct pagevec pvec;
375         pgoff_t first;
376         int loop, nr_pages;
377
378         _enter("{%x,%x,%Lx}",
379                vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version);
380
381         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("");
403 }