• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   */
afs_cell_cache_get_key(const void * cookie_netfs_data,void * buffer,uint16_t bufmax)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   */
afs_cell_cache_get_aux(const void * cookie_netfs_data,void * buffer,uint16_t bufmax)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   */
afs_cell_cache_check_aux(void * cookie_netfs_data,const void * buffer,uint16_t buflen)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   */
afs_vlocation_cache_get_key(const void * cookie_netfs_data,void * buffer,uint16_t bufmax)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   */
afs_vlocation_cache_get_aux(const void * cookie_netfs_data,void * buffer,uint16_t bufmax)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
afs_vlocation_cache_check_aux(void * cookie_netfs_data,const void * buffer,uint16_t buflen)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   */
afs_volume_cache_get_key(const void * cookie_netfs_data,void * buffer,uint16_t bufmax)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   */
afs_vnode_cache_get_key(const void * cookie_netfs_data,void * buffer,uint16_t bufmax)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   */
afs_vnode_cache_get_attr(const void * cookie_netfs_data,uint64_t * size)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   */
afs_vnode_cache_get_aux(const void * cookie_netfs_data,void * buffer,uint16_t bufmax)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   */
afs_vnode_cache_check_aux(void * cookie_netfs_data,const void * buffer,uint16_t buflen)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   */
afs_vnode_cache_now_uncached(void * cookie_netfs_data)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  }
403