• 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 
43 struct fscache_netfs afs_cache_netfs = {
44 	.name			= "afs",
45 	.version		= 0,
46 };
47 
48 struct fscache_cookie_def afs_cell_cache_index_def = {
49 	.name		= "AFS.cell",
50 	.type		= FSCACHE_COOKIE_TYPE_INDEX,
51 	.get_key	= afs_cell_cache_get_key,
52 	.get_aux	= afs_cell_cache_get_aux,
53 	.check_aux	= afs_cell_cache_check_aux,
54 };
55 
56 struct fscache_cookie_def afs_vlocation_cache_index_def = {
57 	.name			= "AFS.vldb",
58 	.type			= FSCACHE_COOKIE_TYPE_INDEX,
59 	.get_key		= afs_vlocation_cache_get_key,
60 	.get_aux		= afs_vlocation_cache_get_aux,
61 	.check_aux		= afs_vlocation_cache_check_aux,
62 };
63 
64 struct fscache_cookie_def afs_volume_cache_index_def = {
65 	.name		= "AFS.volume",
66 	.type		= FSCACHE_COOKIE_TYPE_INDEX,
67 	.get_key	= afs_volume_cache_get_key,
68 };
69 
70 struct fscache_cookie_def afs_vnode_cache_index_def = {
71 	.name			= "AFS.vnode",
72 	.type			= FSCACHE_COOKIE_TYPE_DATAFILE,
73 	.get_key		= afs_vnode_cache_get_key,
74 	.get_attr		= afs_vnode_cache_get_attr,
75 	.get_aux		= afs_vnode_cache_get_aux,
76 	.check_aux		= afs_vnode_cache_check_aux,
77 };
78 
79 /*
80  * set the key for the index entry
81  */
afs_cell_cache_get_key(const void * cookie_netfs_data,void * buffer,uint16_t bufmax)82 static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data,
83 				       void *buffer, uint16_t bufmax)
84 {
85 	const struct afs_cell *cell = cookie_netfs_data;
86 	uint16_t klen;
87 
88 	_enter("%p,%p,%u", cell, buffer, bufmax);
89 
90 	klen = strlen(cell->name);
91 	if (klen > bufmax)
92 		return 0;
93 
94 	memcpy(buffer, cell->name, klen);
95 	return klen;
96 }
97 
98 /*
99  * provide new auxiliary cache data
100  */
afs_cell_cache_get_aux(const void * cookie_netfs_data,void * buffer,uint16_t bufmax)101 static uint16_t afs_cell_cache_get_aux(const void *cookie_netfs_data,
102 				       void *buffer, uint16_t bufmax)
103 {
104 	const struct afs_cell *cell = cookie_netfs_data;
105 	uint16_t dlen;
106 
107 	_enter("%p,%p,%u", cell, buffer, bufmax);
108 
109 	dlen = cell->vl_naddrs * sizeof(cell->vl_addrs[0]);
110 	dlen = min(dlen, bufmax);
111 	dlen &= ~(sizeof(cell->vl_addrs[0]) - 1);
112 
113 	memcpy(buffer, cell->vl_addrs, dlen);
114 	return dlen;
115 }
116 
117 /*
118  * check that the auxiliary data indicates that the entry is still valid
119  */
afs_cell_cache_check_aux(void * cookie_netfs_data,const void * buffer,uint16_t buflen)120 static enum fscache_checkaux afs_cell_cache_check_aux(void *cookie_netfs_data,
121 						      const void *buffer,
122 						      uint16_t buflen)
123 {
124 	_leave(" = OKAY");
125 	return FSCACHE_CHECKAUX_OKAY;
126 }
127 
128 /*****************************************************************************/
129 /*
130  * set the key for the index entry
131  */
afs_vlocation_cache_get_key(const void * cookie_netfs_data,void * buffer,uint16_t bufmax)132 static uint16_t afs_vlocation_cache_get_key(const void *cookie_netfs_data,
133 					    void *buffer, uint16_t bufmax)
134 {
135 	const struct afs_vlocation *vlocation = cookie_netfs_data;
136 	uint16_t klen;
137 
138 	_enter("{%s},%p,%u", vlocation->vldb.name, buffer, bufmax);
139 
140 	klen = strnlen(vlocation->vldb.name, sizeof(vlocation->vldb.name));
141 	if (klen > bufmax)
142 		return 0;
143 
144 	memcpy(buffer, vlocation->vldb.name, klen);
145 
146 	_leave(" = %u", klen);
147 	return klen;
148 }
149 
150 /*
151  * provide new auxiliary cache data
152  */
afs_vlocation_cache_get_aux(const void * cookie_netfs_data,void * buffer,uint16_t bufmax)153 static uint16_t afs_vlocation_cache_get_aux(const void *cookie_netfs_data,
154 					    void *buffer, uint16_t bufmax)
155 {
156 	const struct afs_vlocation *vlocation = cookie_netfs_data;
157 	uint16_t dlen;
158 
159 	_enter("{%s},%p,%u", vlocation->vldb.name, buffer, bufmax);
160 
161 	dlen = sizeof(struct afs_cache_vlocation);
162 	dlen -= offsetof(struct afs_cache_vlocation, nservers);
163 	if (dlen > bufmax)
164 		return 0;
165 
166 	memcpy(buffer, (uint8_t *)&vlocation->vldb.nservers, dlen);
167 
168 	_leave(" = %u", dlen);
169 	return dlen;
170 }
171 
172 /*
173  * check that the auxiliary data indicates that the entry is still valid
174  */
175 static
afs_vlocation_cache_check_aux(void * cookie_netfs_data,const void * buffer,uint16_t buflen)176 enum fscache_checkaux afs_vlocation_cache_check_aux(void *cookie_netfs_data,
177 						    const void *buffer,
178 						    uint16_t buflen)
179 {
180 	const struct afs_cache_vlocation *cvldb;
181 	struct afs_vlocation *vlocation = cookie_netfs_data;
182 	uint16_t dlen;
183 
184 	_enter("{%s},%p,%u", vlocation->vldb.name, buffer, buflen);
185 
186 	/* check the size of the data is what we're expecting */
187 	dlen = sizeof(struct afs_cache_vlocation);
188 	dlen -= offsetof(struct afs_cache_vlocation, nservers);
189 	if (dlen != buflen)
190 		return FSCACHE_CHECKAUX_OBSOLETE;
191 
192 	cvldb = container_of(buffer, struct afs_cache_vlocation, nservers);
193 
194 	/* if what's on disk is more valid than what's in memory, then use the
195 	 * VL record from the cache */
196 	if (!vlocation->valid || vlocation->vldb.rtime == cvldb->rtime) {
197 		memcpy((uint8_t *)&vlocation->vldb.nservers, buffer, dlen);
198 		vlocation->valid = 1;
199 		_leave(" = SUCCESS [c->m]");
200 		return FSCACHE_CHECKAUX_OKAY;
201 	}
202 
203 	/* need to update the cache if the cached info differs */
204 	if (memcmp(&vlocation->vldb, buffer, dlen) != 0) {
205 		/* delete if the volume IDs for this name differ */
206 		if (memcmp(&vlocation->vldb.vid, &cvldb->vid,
207 			   sizeof(cvldb->vid)) != 0
208 		    ) {
209 			_leave(" = OBSOLETE");
210 			return FSCACHE_CHECKAUX_OBSOLETE;
211 		}
212 
213 		_leave(" = UPDATE");
214 		return FSCACHE_CHECKAUX_NEEDS_UPDATE;
215 	}
216 
217 	_leave(" = OKAY");
218 	return FSCACHE_CHECKAUX_OKAY;
219 }
220 
221 /*****************************************************************************/
222 /*
223  * set the key for the volume index entry
224  */
afs_volume_cache_get_key(const void * cookie_netfs_data,void * buffer,uint16_t bufmax)225 static uint16_t afs_volume_cache_get_key(const void *cookie_netfs_data,
226 					void *buffer, uint16_t bufmax)
227 {
228 	const struct afs_volume *volume = cookie_netfs_data;
229 	uint16_t klen;
230 
231 	_enter("{%u},%p,%u", volume->type, buffer, bufmax);
232 
233 	klen = sizeof(volume->type);
234 	if (klen > bufmax)
235 		return 0;
236 
237 	memcpy(buffer, &volume->type, sizeof(volume->type));
238 
239 	_leave(" = %u", klen);
240 	return klen;
241 
242 }
243 
244 /*****************************************************************************/
245 /*
246  * set the key for the index entry
247  */
afs_vnode_cache_get_key(const void * cookie_netfs_data,void * buffer,uint16_t bufmax)248 static uint16_t afs_vnode_cache_get_key(const void *cookie_netfs_data,
249 					void *buffer, uint16_t bufmax)
250 {
251 	const struct afs_vnode *vnode = cookie_netfs_data;
252 	uint16_t klen;
253 
254 	_enter("{%x,%x,%llx},%p,%u",
255 	       vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version,
256 	       buffer, bufmax);
257 
258 	klen = sizeof(vnode->fid.vnode);
259 	if (klen > bufmax)
260 		return 0;
261 
262 	memcpy(buffer, &vnode->fid.vnode, sizeof(vnode->fid.vnode));
263 
264 	_leave(" = %u", klen);
265 	return klen;
266 }
267 
268 /*
269  * provide updated file attributes
270  */
afs_vnode_cache_get_attr(const void * cookie_netfs_data,uint64_t * size)271 static void afs_vnode_cache_get_attr(const void *cookie_netfs_data,
272 				     uint64_t *size)
273 {
274 	const struct afs_vnode *vnode = cookie_netfs_data;
275 
276 	_enter("{%x,%x,%llx},",
277 	       vnode->fid.vnode, vnode->fid.unique,
278 	       vnode->status.data_version);
279 
280 	*size = vnode->status.size;
281 }
282 
283 /*
284  * provide new auxiliary cache data
285  */
afs_vnode_cache_get_aux(const void * cookie_netfs_data,void * buffer,uint16_t bufmax)286 static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data,
287 					void *buffer, uint16_t bufmax)
288 {
289 	const struct afs_vnode *vnode = cookie_netfs_data;
290 	uint16_t dlen;
291 
292 	_enter("{%x,%x,%Lx},%p,%u",
293 	       vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version,
294 	       buffer, bufmax);
295 
296 	dlen = sizeof(vnode->fid.unique) + sizeof(vnode->status.data_version);
297 	if (dlen > bufmax)
298 		return 0;
299 
300 	memcpy(buffer, &vnode->fid.unique, sizeof(vnode->fid.unique));
301 	buffer += sizeof(vnode->fid.unique);
302 	memcpy(buffer, &vnode->status.data_version,
303 	       sizeof(vnode->status.data_version));
304 
305 	_leave(" = %u", dlen);
306 	return dlen;
307 }
308 
309 /*
310  * check that the auxiliary data indicates that the entry is still valid
311  */
afs_vnode_cache_check_aux(void * cookie_netfs_data,const void * buffer,uint16_t buflen)312 static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data,
313 						       const void *buffer,
314 						       uint16_t buflen)
315 {
316 	struct afs_vnode *vnode = cookie_netfs_data;
317 	uint16_t dlen;
318 
319 	_enter("{%x,%x,%llx},%p,%u",
320 	       vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version,
321 	       buffer, buflen);
322 
323 	/* check the size of the data is what we're expecting */
324 	dlen = sizeof(vnode->fid.unique) + sizeof(vnode->status.data_version);
325 	if (dlen != buflen) {
326 		_leave(" = OBSOLETE [len %hx != %hx]", dlen, buflen);
327 		return FSCACHE_CHECKAUX_OBSOLETE;
328 	}
329 
330 	if (memcmp(buffer,
331 		   &vnode->fid.unique,
332 		   sizeof(vnode->fid.unique)
333 		   ) != 0) {
334 		unsigned unique;
335 
336 		memcpy(&unique, buffer, sizeof(unique));
337 
338 		_leave(" = OBSOLETE [uniq %x != %x]",
339 		       unique, vnode->fid.unique);
340 		return FSCACHE_CHECKAUX_OBSOLETE;
341 	}
342 
343 	if (memcmp(buffer + sizeof(vnode->fid.unique),
344 		   &vnode->status.data_version,
345 		   sizeof(vnode->status.data_version)
346 		   ) != 0) {
347 		afs_dataversion_t version;
348 
349 		memcpy(&version, buffer + sizeof(vnode->fid.unique),
350 		       sizeof(version));
351 
352 		_leave(" = OBSOLETE [vers %llx != %llx]",
353 		       version, vnode->status.data_version);
354 		return FSCACHE_CHECKAUX_OBSOLETE;
355 	}
356 
357 	_leave(" = SUCCESS");
358 	return FSCACHE_CHECKAUX_OKAY;
359 }
360