Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cache.c
Go to the documentation of this file.
1 /* AFS caching stuff
2  *
3  * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells ([email protected])
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,
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,
42 static void afs_vnode_cache_now_uncached(void *cookie_netfs_data);
43 
45  .name = "afs",
46  .version = 0,
47 };
48 
50  .name = "AFS.cell",
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 
58  .name = "AFS.vldb",
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 
66  .name = "AFS.volume",
68  .get_key = afs_volume_cache_get_key,
69 };
70 
72  .name = "AFS.vnode",
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,
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,
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)
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");
213  }
214 
215  _leave(" = 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);
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);
343  }
344 
345  if (memcmp(buffer + sizeof(vnode->fid.unique),
346  &vnode->status.data_version,
347  sizeof(vnode->status.data_version)
348  ) != 0) {
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);
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 }