577763c3d88bb51e1ee41003298a4b545a1bb2fb
[sfrench/cifs-2.6.git] / 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/sched.h>
13 #include "internal.h"
14
15 static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data,
16                                        void *buffer, uint16_t buflen);
17 static uint16_t afs_cell_cache_get_aux(const void *cookie_netfs_data,
18                                        void *buffer, uint16_t buflen);
19 static enum fscache_checkaux afs_cell_cache_check_aux(void *cookie_netfs_data,
20                                                       const void *buffer,
21                                                       uint16_t buflen);
22
23 static uint16_t afs_vlocation_cache_get_key(const void *cookie_netfs_data,
24                                             void *buffer, uint16_t buflen);
25 static uint16_t afs_vlocation_cache_get_aux(const void *cookie_netfs_data,
26                                             void *buffer, uint16_t buflen);
27 static enum fscache_checkaux afs_vlocation_cache_check_aux(
28         void *cookie_netfs_data, const void *buffer, uint16_t buflen);
29
30 static uint16_t afs_volume_cache_get_key(const void *cookie_netfs_data,
31                                          void *buffer, uint16_t buflen);
32
33 static uint16_t afs_vnode_cache_get_key(const void *cookie_netfs_data,
34                                         void *buffer, uint16_t buflen);
35 static void afs_vnode_cache_get_attr(const void *cookie_netfs_data,
36                                      uint64_t *size);
37 static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data,
38                                         void *buffer, uint16_t buflen);
39 static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data,
40                                                        const void *buffer,
41                                                        uint16_t buflen);
42 static void afs_vnode_cache_now_uncached(void *cookie_netfs_data);
43
44 struct fscache_netfs afs_cache_netfs = {
45         .name                   = "afs",
46         .version                = 0,
47 };
48
49 struct 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
57 struct 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
65 struct 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
71 struct 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 };
80
81 /*
82  * set the key for the index entry
83  */
84 static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data,
85                                        void *buffer, uint16_t bufmax)
86 {
87         const struct afs_cell *cell = cookie_netfs_data;
88         uint16_t klen;
89
90         _enter("%p,%p,%u", cell, buffer, bufmax);
91
92         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 auxiliary cache data
102  */
103 static 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 auxiliary data indicates that the entry is still valid
121  */
122 static 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  */
134 static 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 auxiliary cache data
154  */
155 static 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 auxiliary data indicates that the entry is still valid
176  */
177 static
178 enum 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;
203         }
204
205         /* 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
210                     ) {
211                         _leave(" = OBSOLETE");
212                         return FSCACHE_CHECKAUX_OBSOLETE;
213                 }
214
215                 _leave(" = UPDATE");
216                 return FSCACHE_CHECKAUX_NEEDS_UPDATE;
217         }
218
219         _leave(" = OKAY");
220         return FSCACHE_CHECKAUX_OKAY;
221 }
222
223 /*****************************************************************************/
224 /*
225  * set the key for the volume index entry
226  */
227 static 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  */
250 static 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 }
269
270 /*
271  * provide updated file attributes
272  */
273 static void afs_vnode_cache_get_attr(const void *cookie_netfs_data,
274                                      uint64_t *size)
275 {
276         const struct afs_vnode *vnode = cookie_netfs_data;
277
278         _enter("{%x,%x,%llx},",
279                vnode->fid.vnode, vnode->fid.unique,
280                vnode->status.data_version);
281
282         *size = vnode->status.size;
283 }
284
285 /*
286  * provide new auxiliary cache data
287  */
288 static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data,
289                                         void *buffer, uint16_t bufmax)
290 {
291         const struct afs_vnode *vnode = cookie_netfs_data;
292         uint16_t dlen;
293
294         _enter("{%x,%x,%Lx},%p,%u",
295                vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version,
296                buffer, bufmax);
297
298         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 auxiliary data indicates that the entry is still valid
313  */
314 static 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;
330         }
331
332         if (memcmp(buffer,
333                    &vnode->fid.unique,
334                    sizeof(vnode->fid.unique)
335                    ) != 0) {
336                 unsigned unique;
337
338                 memcpy(&unique, buffer, sizeof(unique));
339
340                 _leave(" = OBSOLETE [uniq %x != %x]",
341                        unique, vnode->fid.unique);
342                 return FSCACHE_CHECKAUX_OBSOLETE;
343         }
344
345         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;
357         }
358
359         _leave(" = SUCCESS");
360         return FSCACHE_CHECKAUX_OKAY;
361 }
362
363 /*
364  * 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
369  */
370 static void afs_vnode_cache_now_uncached(void *cookie_netfs_data)
371 {
372         struct afs_vnode *vnode = cookie_netfs_data;
373         struct pagevec pvec;
374         pgoff_t first;
375         int loop, nr_pages;
376
377         _enter("{%x,%x,%Lx}",
378                vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version);
379
380         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("");
402 }