at v2.6.30-rc4 403 lines 11 kB view raw
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/slab.h> 13#include <linux/sched.h> 14#include "internal.h" 15 16static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data, 17 void *buffer, uint16_t buflen); 18static uint16_t afs_cell_cache_get_aux(const void *cookie_netfs_data, 19 void *buffer, uint16_t buflen); 20static enum fscache_checkaux afs_cell_cache_check_aux(void *cookie_netfs_data, 21 const void *buffer, 22 uint16_t buflen); 23 24static uint16_t afs_vlocation_cache_get_key(const void *cookie_netfs_data, 25 void *buffer, uint16_t buflen); 26static uint16_t afs_vlocation_cache_get_aux(const void *cookie_netfs_data, 27 void *buffer, uint16_t buflen); 28static enum fscache_checkaux afs_vlocation_cache_check_aux( 29 void *cookie_netfs_data, const void *buffer, uint16_t buflen); 30 31static uint16_t afs_volume_cache_get_key(const void *cookie_netfs_data, 32 void *buffer, uint16_t buflen); 33 34static uint16_t afs_vnode_cache_get_key(const void *cookie_netfs_data, 35 void *buffer, uint16_t buflen); 36static void afs_vnode_cache_get_attr(const void *cookie_netfs_data, 37 uint64_t *size); 38static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data, 39 void *buffer, uint16_t buflen); 40static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data, 41 const void *buffer, 42 uint16_t buflen); 43static void afs_vnode_cache_now_uncached(void *cookie_netfs_data); 44 45struct fscache_netfs afs_cache_netfs = { 46 .name = "afs", 47 .version = 0, 48}; 49 50struct fscache_cookie_def afs_cell_cache_index_def = { 51 .name = "AFS.cell", 52 .type = FSCACHE_COOKIE_TYPE_INDEX, 53 .get_key = afs_cell_cache_get_key, 54 .get_aux = afs_cell_cache_get_aux, 55 .check_aux = afs_cell_cache_check_aux, 56}; 57 58struct fscache_cookie_def afs_vlocation_cache_index_def = { 59 .name = "AFS.vldb", 60 .type = FSCACHE_COOKIE_TYPE_INDEX, 61 .get_key = afs_vlocation_cache_get_key, 62 .get_aux = afs_vlocation_cache_get_aux, 63 .check_aux = afs_vlocation_cache_check_aux, 64}; 65 66struct fscache_cookie_def afs_volume_cache_index_def = { 67 .name = "AFS.volume", 68 .type = FSCACHE_COOKIE_TYPE_INDEX, 69 .get_key = afs_volume_cache_get_key, 70}; 71 72struct fscache_cookie_def afs_vnode_cache_index_def = { 73 .name = "AFS.vnode", 74 .type = FSCACHE_COOKIE_TYPE_DATAFILE, 75 .get_key = afs_vnode_cache_get_key, 76 .get_attr = afs_vnode_cache_get_attr, 77 .get_aux = afs_vnode_cache_get_aux, 78 .check_aux = afs_vnode_cache_check_aux, 79 .now_uncached = afs_vnode_cache_now_uncached, 80}; 81 82/* 83 * set the key for the index entry 84 */ 85static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data, 86 void *buffer, uint16_t bufmax) 87{ 88 const struct afs_cell *cell = cookie_netfs_data; 89 uint16_t klen; 90 91 _enter("%p,%p,%u", cell, buffer, bufmax); 92 93 klen = strlen(cell->name); 94 if (klen > bufmax) 95 return 0; 96 97 memcpy(buffer, cell->name, klen); 98 return klen; 99} 100 101/* 102 * provide new auxilliary cache data 103 */ 104static uint16_t afs_cell_cache_get_aux(const void *cookie_netfs_data, 105 void *buffer, uint16_t bufmax) 106{ 107 const struct afs_cell *cell = cookie_netfs_data; 108 uint16_t dlen; 109 110 _enter("%p,%p,%u", cell, buffer, bufmax); 111 112 dlen = cell->vl_naddrs * sizeof(cell->vl_addrs[0]); 113 dlen = min(dlen, bufmax); 114 dlen &= ~(sizeof(cell->vl_addrs[0]) - 1); 115 116 memcpy(buffer, cell->vl_addrs, dlen); 117 return dlen; 118} 119 120/* 121 * check that the auxilliary data indicates that the entry is still valid 122 */ 123static enum fscache_checkaux afs_cell_cache_check_aux(void *cookie_netfs_data, 124 const void *buffer, 125 uint16_t buflen) 126{ 127 _leave(" = OKAY"); 128 return FSCACHE_CHECKAUX_OKAY; 129} 130 131/*****************************************************************************/ 132/* 133 * set the key for the index entry 134 */ 135static uint16_t afs_vlocation_cache_get_key(const void *cookie_netfs_data, 136 void *buffer, uint16_t bufmax) 137{ 138 const struct afs_vlocation *vlocation = cookie_netfs_data; 139 uint16_t klen; 140 141 _enter("{%s},%p,%u", vlocation->vldb.name, buffer, bufmax); 142 143 klen = strnlen(vlocation->vldb.name, sizeof(vlocation->vldb.name)); 144 if (klen > bufmax) 145 return 0; 146 147 memcpy(buffer, vlocation->vldb.name, klen); 148 149 _leave(" = %u", klen); 150 return klen; 151} 152 153/* 154 * provide new auxilliary cache data 155 */ 156static uint16_t afs_vlocation_cache_get_aux(const void *cookie_netfs_data, 157 void *buffer, uint16_t bufmax) 158{ 159 const struct afs_vlocation *vlocation = cookie_netfs_data; 160 uint16_t dlen; 161 162 _enter("{%s},%p,%u", vlocation->vldb.name, buffer, bufmax); 163 164 dlen = sizeof(struct afs_cache_vlocation); 165 dlen -= offsetof(struct afs_cache_vlocation, nservers); 166 if (dlen > bufmax) 167 return 0; 168 169 memcpy(buffer, (uint8_t *)&vlocation->vldb.nservers, dlen); 170 171 _leave(" = %u", dlen); 172 return dlen; 173} 174 175/* 176 * check that the auxilliary data indicates that the entry is still valid 177 */ 178static 179enum fscache_checkaux afs_vlocation_cache_check_aux(void *cookie_netfs_data, 180 const void *buffer, 181 uint16_t buflen) 182{ 183 const struct afs_cache_vlocation *cvldb; 184 struct afs_vlocation *vlocation = cookie_netfs_data; 185 uint16_t dlen; 186 187 _enter("{%s},%p,%u", vlocation->vldb.name, buffer, buflen); 188 189 /* check the size of the data is what we're expecting */ 190 dlen = sizeof(struct afs_cache_vlocation); 191 dlen -= offsetof(struct afs_cache_vlocation, nservers); 192 if (dlen != buflen) 193 return FSCACHE_CHECKAUX_OBSOLETE; 194 195 cvldb = container_of(buffer, struct afs_cache_vlocation, nservers); 196 197 /* if what's on disk is more valid than what's in memory, then use the 198 * VL record from the cache */ 199 if (!vlocation->valid || vlocation->vldb.rtime == cvldb->rtime) { 200 memcpy((uint8_t *)&vlocation->vldb.nservers, buffer, dlen); 201 vlocation->valid = 1; 202 _leave(" = SUCCESS [c->m]"); 203 return FSCACHE_CHECKAUX_OKAY; 204 } 205 206 /* need to update the cache if the cached info differs */ 207 if (memcmp(&vlocation->vldb, buffer, dlen) != 0) { 208 /* delete if the volume IDs for this name differ */ 209 if (memcmp(&vlocation->vldb.vid, &cvldb->vid, 210 sizeof(cvldb->vid)) != 0 211 ) { 212 _leave(" = OBSOLETE"); 213 return FSCACHE_CHECKAUX_OBSOLETE; 214 } 215 216 _leave(" = UPDATE"); 217 return FSCACHE_CHECKAUX_NEEDS_UPDATE; 218 } 219 220 _leave(" = OKAY"); 221 return FSCACHE_CHECKAUX_OKAY; 222} 223 224/*****************************************************************************/ 225/* 226 * set the key for the volume index entry 227 */ 228static uint16_t afs_volume_cache_get_key(const void *cookie_netfs_data, 229 void *buffer, uint16_t bufmax) 230{ 231 const struct afs_volume *volume = cookie_netfs_data; 232 uint16_t klen; 233 234 _enter("{%u},%p,%u", volume->type, buffer, bufmax); 235 236 klen = sizeof(volume->type); 237 if (klen > bufmax) 238 return 0; 239 240 memcpy(buffer, &volume->type, sizeof(volume->type)); 241 242 _leave(" = %u", klen); 243 return klen; 244 245} 246 247/*****************************************************************************/ 248/* 249 * set the key for the index entry 250 */ 251static uint16_t afs_vnode_cache_get_key(const void *cookie_netfs_data, 252 void *buffer, uint16_t bufmax) 253{ 254 const struct afs_vnode *vnode = cookie_netfs_data; 255 uint16_t klen; 256 257 _enter("{%x,%x,%llx},%p,%u", 258 vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version, 259 buffer, bufmax); 260 261 klen = sizeof(vnode->fid.vnode); 262 if (klen > bufmax) 263 return 0; 264 265 memcpy(buffer, &vnode->fid.vnode, sizeof(vnode->fid.vnode)); 266 267 _leave(" = %u", klen); 268 return klen; 269} 270 271/* 272 * provide updated file attributes 273 */ 274static void afs_vnode_cache_get_attr(const void *cookie_netfs_data, 275 uint64_t *size) 276{ 277 const struct afs_vnode *vnode = cookie_netfs_data; 278 279 _enter("{%x,%x,%llx},", 280 vnode->fid.vnode, vnode->fid.unique, 281 vnode->status.data_version); 282 283 *size = vnode->status.size; 284} 285 286/* 287 * provide new auxilliary cache data 288 */ 289static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data, 290 void *buffer, uint16_t bufmax) 291{ 292 const struct afs_vnode *vnode = cookie_netfs_data; 293 uint16_t dlen; 294 295 _enter("{%x,%x,%Lx},%p,%u", 296 vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version, 297 buffer, bufmax); 298 299 dlen = sizeof(vnode->fid.unique) + sizeof(vnode->status.data_version); 300 if (dlen > bufmax) 301 return 0; 302 303 memcpy(buffer, &vnode->fid.unique, sizeof(vnode->fid.unique)); 304 buffer += sizeof(vnode->fid.unique); 305 memcpy(buffer, &vnode->status.data_version, 306 sizeof(vnode->status.data_version)); 307 308 _leave(" = %u", dlen); 309 return dlen; 310} 311 312/* 313 * check that the auxilliary data indicates that the entry is still valid 314 */ 315static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data, 316 const void *buffer, 317 uint16_t buflen) 318{ 319 struct afs_vnode *vnode = cookie_netfs_data; 320 uint16_t dlen; 321 322 _enter("{%x,%x,%llx},%p,%u", 323 vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version, 324 buffer, buflen); 325 326 /* check the size of the data is what we're expecting */ 327 dlen = sizeof(vnode->fid.unique) + sizeof(vnode->status.data_version); 328 if (dlen != buflen) { 329 _leave(" = OBSOLETE [len %hx != %hx]", dlen, buflen); 330 return FSCACHE_CHECKAUX_OBSOLETE; 331 } 332 333 if (memcmp(buffer, 334 &vnode->fid.unique, 335 sizeof(vnode->fid.unique) 336 ) != 0) { 337 unsigned unique; 338 339 memcpy(&unique, buffer, sizeof(unique)); 340 341 _leave(" = OBSOLETE [uniq %x != %x]", 342 unique, vnode->fid.unique); 343 return FSCACHE_CHECKAUX_OBSOLETE; 344 } 345 346 if (memcmp(buffer + sizeof(vnode->fid.unique), 347 &vnode->status.data_version, 348 sizeof(vnode->status.data_version) 349 ) != 0) { 350 afs_dataversion_t version; 351 352 memcpy(&version, buffer + sizeof(vnode->fid.unique), 353 sizeof(version)); 354 355 _leave(" = OBSOLETE [vers %llx != %llx]", 356 version, vnode->status.data_version); 357 return FSCACHE_CHECKAUX_OBSOLETE; 358 } 359 360 _leave(" = SUCCESS"); 361 return FSCACHE_CHECKAUX_OKAY; 362} 363 364/* 365 * indication the cookie is no longer uncached 366 * - this function is called when the backing store currently caching a cookie 367 * is removed 368 * - the netfs should use this to clean up any markers indicating cached pages 369 * - this is mandatory for any object that may have data 370 */ 371static void afs_vnode_cache_now_uncached(void *cookie_netfs_data) 372{ 373 struct afs_vnode *vnode = cookie_netfs_data; 374 struct pagevec pvec; 375 pgoff_t first; 376 int loop, nr_pages; 377 378 _enter("{%x,%x,%Lx}", 379 vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version); 380 381 pagevec_init(&pvec, 0); 382 first = 0; 383 384 for (;;) { 385 /* grab a bunch of pages to clean */ 386 nr_pages = pagevec_lookup(&pvec, vnode->vfs_inode.i_mapping, 387 first, 388 PAGEVEC_SIZE - pagevec_count(&pvec)); 389 if (!nr_pages) 390 break; 391 392 for (loop = 0; loop < nr_pages; loop++) 393 ClearPageFsCache(pvec.pages[loop]); 394 395 first = pvec.pages[nr_pages - 1]->index + 1; 396 397 pvec.nr = nr_pages; 398 pagevec_release(&pvec); 399 cond_resched(); 400 } 401 402 _leave(""); 403}