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