| /* AFS caching stuff | |
| * | |
| * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved. | |
| * Written by David Howells (dhowells@redhat.com) | |
| * | |
| * This program is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU General Public License | |
| * as published by the Free Software Foundation; either version | |
| * 2 of the License, or (at your option) any later version. | |
| */ | |
| #include <linux/sched.h> | |
| #include "internal.h" | |
| static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data, | |
| void *buffer, uint16_t buflen); | |
| static uint16_t afs_volume_cache_get_key(const void *cookie_netfs_data, | |
| void *buffer, uint16_t buflen); | |
| static uint16_t afs_vnode_cache_get_key(const void *cookie_netfs_data, | |
| void *buffer, uint16_t buflen); | |
| static void afs_vnode_cache_get_attr(const void *cookie_netfs_data, | |
| uint64_t *size); | |
| static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data, | |
| void *buffer, uint16_t buflen); | |
| static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data, | |
| const void *buffer, | |
| uint16_t buflen); | |
| struct fscache_netfs afs_cache_netfs = { | |
| .name = "afs", | |
| .version = 1, | |
| }; | |
| struct fscache_cookie_def afs_cell_cache_index_def = { | |
| .name = "AFS.cell", | |
| .type = FSCACHE_COOKIE_TYPE_INDEX, | |
| .get_key = afs_cell_cache_get_key, | |
| }; | |
| struct fscache_cookie_def afs_volume_cache_index_def = { | |
| .name = "AFS.volume", | |
| .type = FSCACHE_COOKIE_TYPE_INDEX, | |
| .get_key = afs_volume_cache_get_key, | |
| }; | |
| struct fscache_cookie_def afs_vnode_cache_index_def = { | |
| .name = "AFS.vnode", | |
| .type = FSCACHE_COOKIE_TYPE_DATAFILE, | |
| .get_key = afs_vnode_cache_get_key, | |
| .get_attr = afs_vnode_cache_get_attr, | |
| .get_aux = afs_vnode_cache_get_aux, | |
| .check_aux = afs_vnode_cache_check_aux, | |
| }; | |
| /* | |
| * set the key for the index entry | |
| */ | |
| static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data, | |
| void *buffer, uint16_t bufmax) | |
| { | |
| const struct afs_cell *cell = cookie_netfs_data; | |
| uint16_t klen; | |
| _enter("%p,%p,%u", cell, buffer, bufmax); | |
| klen = strlen(cell->name); | |
| if (klen > bufmax) | |
| return 0; | |
| memcpy(buffer, cell->name, klen); | |
| return klen; | |
| } | |
| /*****************************************************************************/ | |
| /* | |
| * set the key for the volume index entry | |
| */ | |
| static uint16_t afs_volume_cache_get_key(const void *cookie_netfs_data, | |
| void *buffer, uint16_t bufmax) | |
| { | |
| const struct afs_volume *volume = cookie_netfs_data; | |
| struct { | |
| u64 volid; | |
| } __packed key; | |
| _enter("{%u},%p,%u", volume->type, buffer, bufmax); | |
| if (bufmax < sizeof(key)) | |
| return 0; | |
| key.volid = volume->vid; | |
| memcpy(buffer, &key, sizeof(key)); | |
| return sizeof(key); | |
| } | |
| /*****************************************************************************/ | |
| /* | |
| * set the key for the index entry | |
| */ | |
| static uint16_t afs_vnode_cache_get_key(const void *cookie_netfs_data, | |
| void *buffer, uint16_t bufmax) | |
| { | |
| const struct afs_vnode *vnode = cookie_netfs_data; | |
| struct { | |
| u32 vnode_id[3]; | |
| } __packed key; | |
| _enter("{%x,%x,%llx},%p,%u", | |
| vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version, | |
| buffer, bufmax); | |
| /* Allow for a 96-bit key */ | |
| memset(&key, 0, sizeof(key)); | |
| key.vnode_id[0] = vnode->fid.vnode; | |
| key.vnode_id[1] = 0; | |
| key.vnode_id[2] = 0; | |
| if (sizeof(key) > bufmax) | |
| return 0; | |
| memcpy(buffer, &key, sizeof(key)); | |
| return sizeof(key); | |
| } | |
| /* | |
| * provide updated file attributes | |
| */ | |
| static void afs_vnode_cache_get_attr(const void *cookie_netfs_data, | |
| uint64_t *size) | |
| { | |
| const struct afs_vnode *vnode = cookie_netfs_data; | |
| _enter("{%x,%x,%llx},", | |
| vnode->fid.vnode, vnode->fid.unique, | |
| vnode->status.data_version); | |
| *size = vnode->status.size; | |
| } | |
| struct afs_vnode_cache_aux { | |
| u64 data_version; | |
| u32 fid_unique; | |
| } __packed; | |
| /* | |
| * provide new auxiliary cache data | |
| */ | |
| static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data, | |
| void *buffer, uint16_t bufmax) | |
| { | |
| const struct afs_vnode *vnode = cookie_netfs_data; | |
| struct afs_vnode_cache_aux aux; | |
| _enter("{%x,%x,%Lx},%p,%u", | |
| vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version, | |
| buffer, bufmax); | |
| memset(&aux, 0, sizeof(aux)); | |
| aux.data_version = vnode->status.data_version; | |
| aux.fid_unique = vnode->fid.unique; | |
| if (bufmax < sizeof(aux)) | |
| return 0; | |
| memcpy(buffer, &aux, sizeof(aux)); | |
| return sizeof(aux); | |
| } | |
| /* | |
| * check that the auxiliary data indicates that the entry is still valid | |
| */ | |
| static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data, | |
| const void *buffer, | |
| uint16_t buflen) | |
| { | |
| struct afs_vnode *vnode = cookie_netfs_data; | |
| struct afs_vnode_cache_aux aux; | |
| _enter("{%x,%x,%llx},%p,%u", | |
| vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version, | |
| buffer, buflen); | |
| memcpy(&aux, buffer, sizeof(aux)); | |
| /* check the size of the data is what we're expecting */ | |
| if (buflen != sizeof(aux)) { | |
| _leave(" = OBSOLETE [len %hx != %zx]", buflen, sizeof(aux)); | |
| return FSCACHE_CHECKAUX_OBSOLETE; | |
| } | |
| if (vnode->fid.unique != aux.fid_unique) { | |
| _leave(" = OBSOLETE [uniq %x != %x]", | |
| aux.fid_unique, vnode->fid.unique); | |
| return FSCACHE_CHECKAUX_OBSOLETE; | |
| } | |
| if (vnode->status.data_version != aux.data_version) { | |
| _leave(" = OBSOLETE [vers %llx != %llx]", | |
| aux.data_version, vnode->status.data_version); | |
| return FSCACHE_CHECKAUX_OBSOLETE; | |
| } | |
| _leave(" = SUCCESS"); | |
| return FSCACHE_CHECKAUX_OKAY; | |
| } |