GNU Linux-libre 4.14.266-gnu1
[releases.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
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  */
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  */
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  */
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  */
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  */
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
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  */
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  */
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  */
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  */
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  */
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 }