Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/fs/afs/cache.c
15109 views
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,
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
}
403
404