2007-04-27 02:55:03 +04:00
/* AFS caching stuff
*
2009-04-03 19:42:41 +04:00
* Copyright ( C ) 2008 Red Hat , Inc . All Rights Reserved .
2007-04-27 02:55:03 +04:00
* 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 .
*/
2009-04-03 19:42:41 +04:00
# include <linux/slab.h>
# 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_cell_cache_get_aux ( const void * cookie_netfs_data ,
void * buffer , uint16_t buflen ) ;
static enum fscache_checkaux afs_cell_cache_check_aux ( void * cookie_netfs_data ,
const void * buffer ,
uint16_t buflen ) ;
static uint16_t afs_vlocation_cache_get_key ( const void * cookie_netfs_data ,
void * buffer , uint16_t buflen ) ;
static uint16_t afs_vlocation_cache_get_aux ( const void * cookie_netfs_data ,
void * buffer , uint16_t buflen ) ;
static enum fscache_checkaux afs_vlocation_cache_check_aux (
void * cookie_netfs_data , const 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 ) ;
static void afs_vnode_cache_now_uncached ( void * cookie_netfs_data ) ;
struct fscache_netfs afs_cache_netfs = {
. name = " afs " ,
. version = 0 ,
} ;
struct fscache_cookie_def afs_cell_cache_index_def = {
. name = " AFS.cell " ,
. type = FSCACHE_COOKIE_TYPE_INDEX ,
. get_key = afs_cell_cache_get_key ,
. get_aux = afs_cell_cache_get_aux ,
. check_aux = afs_cell_cache_check_aux ,
} ;
struct fscache_cookie_def afs_vlocation_cache_index_def = {
. name = " AFS.vldb " ,
. type = FSCACHE_COOKIE_TYPE_INDEX ,
. get_key = afs_vlocation_cache_get_key ,
. get_aux = afs_vlocation_cache_get_aux ,
. check_aux = afs_vlocation_cache_check_aux ,
} ;
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 ,
. now_uncached = afs_vnode_cache_now_uncached ,
2007-04-27 02:55:03 +04:00
} ;
/*
2009-04-03 19:42:41 +04:00
* set the key for the index entry
2007-04-27 02:55:03 +04:00
*/
2009-04-03 19:42:41 +04:00
static uint16_t afs_cell_cache_get_key ( const void * cookie_netfs_data ,
void * buffer , uint16_t bufmax )
2007-04-27 02:55:03 +04:00
{
2009-04-03 19:42:41 +04:00
const struct afs_cell * cell = cookie_netfs_data ;
uint16_t klen ;
2007-04-27 02:55:03 +04:00
2009-04-03 19:42:41 +04:00
_enter ( " %p,%p,%u " , cell , buffer , bufmax ) ;
2007-04-27 02:55:03 +04:00
2009-04-03 19:42:41 +04:00
klen = strlen ( cell - > name ) ;
if ( klen > bufmax )
return 0 ;
2007-04-27 02:55:03 +04:00
2009-04-03 19:42:41 +04:00
memcpy ( buffer , cell - > name , klen ) ;
return klen ;
2007-04-27 02:55:03 +04:00
}
/*
2009-04-03 19:42:41 +04:00
* provide new auxilliary cache data
2007-04-27 02:55:03 +04:00
*/
2009-04-03 19:42:41 +04:00
static uint16_t afs_cell_cache_get_aux ( const void * cookie_netfs_data ,
void * buffer , uint16_t bufmax )
2007-04-27 02:55:03 +04:00
{
2009-04-03 19:42:41 +04:00
const struct afs_cell * cell = cookie_netfs_data ;
uint16_t dlen ;
2007-04-27 02:55:03 +04:00
2009-04-03 19:42:41 +04:00
_enter ( " %p,%p,%u " , cell , buffer , bufmax ) ;
2007-04-27 02:55:03 +04:00
2009-04-03 19:42:41 +04:00
dlen = cell - > vl_naddrs * sizeof ( cell - > vl_addrs [ 0 ] ) ;
dlen = min ( dlen , bufmax ) ;
dlen & = ~ ( sizeof ( cell - > vl_addrs [ 0 ] ) - 1 ) ;
2007-04-27 02:55:03 +04:00
2009-04-03 19:42:41 +04:00
memcpy ( buffer , cell - > vl_addrs , dlen ) ;
return dlen ;
}
2007-04-27 02:55:03 +04:00
2009-04-03 19:42:41 +04:00
/*
* check that the auxilliary data indicates that the entry is still valid
*/
static enum fscache_checkaux afs_cell_cache_check_aux ( void * cookie_netfs_data ,
const void * buffer ,
uint16_t buflen )
{
_leave ( " = OKAY " ) ;
return FSCACHE_CHECKAUX_OKAY ;
2007-04-27 02:55:03 +04:00
}
2009-04-03 19:42:41 +04:00
/*****************************************************************************/
2007-04-27 02:55:03 +04:00
/*
2009-04-03 19:42:41 +04:00
* set the key for the index entry
2007-04-27 02:55:03 +04:00
*/
2009-04-03 19:42:41 +04:00
static uint16_t afs_vlocation_cache_get_key ( const void * cookie_netfs_data ,
void * buffer , uint16_t bufmax )
2007-04-27 02:55:03 +04:00
{
2009-04-03 19:42:41 +04:00
const struct afs_vlocation * vlocation = cookie_netfs_data ;
uint16_t klen ;
_enter ( " {%s},%p,%u " , vlocation - > vldb . name , buffer , bufmax ) ;
klen = strnlen ( vlocation - > vldb . name , sizeof ( vlocation - > vldb . name ) ) ;
if ( klen > bufmax )
return 0 ;
2007-04-27 02:55:03 +04:00
2009-04-03 19:42:41 +04:00
memcpy ( buffer , vlocation - > vldb . name , klen ) ;
2007-04-27 02:55:03 +04:00
2009-04-03 19:42:41 +04:00
_leave ( " = %u " , klen ) ;
return klen ;
}
/*
* provide new auxilliary cache data
*/
static uint16_t afs_vlocation_cache_get_aux ( const void * cookie_netfs_data ,
void * buffer , uint16_t bufmax )
{
const struct afs_vlocation * vlocation = cookie_netfs_data ;
uint16_t dlen ;
_enter ( " {%s},%p,%u " , vlocation - > vldb . name , buffer , bufmax ) ;
dlen = sizeof ( struct afs_cache_vlocation ) ;
dlen - = offsetof ( struct afs_cache_vlocation , nservers ) ;
if ( dlen > bufmax )
return 0 ;
memcpy ( buffer , ( uint8_t * ) & vlocation - > vldb . nservers , dlen ) ;
_leave ( " = %u " , dlen ) ;
return dlen ;
}
/*
* check that the auxilliary data indicates that the entry is still valid
*/
static
enum fscache_checkaux afs_vlocation_cache_check_aux ( void * cookie_netfs_data ,
const void * buffer ,
uint16_t buflen )
{
const struct afs_cache_vlocation * cvldb ;
struct afs_vlocation * vlocation = cookie_netfs_data ;
uint16_t dlen ;
_enter ( " {%s},%p,%u " , vlocation - > vldb . name , buffer , buflen ) ;
/* check the size of the data is what we're expecting */
dlen = sizeof ( struct afs_cache_vlocation ) ;
dlen - = offsetof ( struct afs_cache_vlocation , nservers ) ;
if ( dlen ! = buflen )
return FSCACHE_CHECKAUX_OBSOLETE ;
cvldb = container_of ( buffer , struct afs_cache_vlocation , nservers ) ;
/* if what's on disk is more valid than what's in memory, then use the
* VL record from the cache */
if ( ! vlocation - > valid | | vlocation - > vldb . rtime = = cvldb - > rtime ) {
memcpy ( ( uint8_t * ) & vlocation - > vldb . nservers , buffer , dlen ) ;
vlocation - > valid = 1 ;
_leave ( " = SUCCESS [c->m] " ) ;
return FSCACHE_CHECKAUX_OKAY ;
}
/* need to update the cache if the cached info differs */
if ( memcmp ( & vlocation - > vldb , buffer , dlen ) ! = 0 ) {
/* delete if the volume IDs for this name differ */
if ( memcmp ( & vlocation - > vldb . vid , & cvldb - > vid ,
sizeof ( cvldb - > vid ) ) ! = 0
2007-04-27 02:55:03 +04:00
) {
2009-04-03 19:42:41 +04:00
_leave ( " = OBSOLETE " ) ;
return FSCACHE_CHECKAUX_OBSOLETE ;
2007-04-27 02:55:03 +04:00
}
2009-04-03 19:42:41 +04:00
_leave ( " = UPDATE " ) ;
return FSCACHE_CHECKAUX_NEEDS_UPDATE ;
2007-04-27 02:55:03 +04:00
}
2009-04-03 19:42:41 +04:00
_leave ( " = OKAY " ) ;
return FSCACHE_CHECKAUX_OKAY ;
2007-04-27 02:55:03 +04:00
}
2009-04-03 19:42:41 +04:00
/*****************************************************************************/
2007-04-27 02:55:03 +04:00
/*
2009-04-03 19:42:41 +04:00
* set the key for the volume index entry
2007-04-27 02:55:03 +04:00
*/
2009-04-03 19:42:41 +04:00
static uint16_t afs_volume_cache_get_key ( const void * cookie_netfs_data ,
void * buffer , uint16_t bufmax )
2007-04-27 02:55:03 +04:00
{
2009-04-03 19:42:41 +04:00
const struct afs_volume * volume = cookie_netfs_data ;
uint16_t klen ;
_enter ( " {%u},%p,%u " , volume - > type , buffer , bufmax ) ;
klen = sizeof ( volume - > type ) ;
if ( klen > bufmax )
return 0 ;
2007-04-27 02:55:03 +04:00
2009-04-03 19:42:41 +04:00
memcpy ( buffer , & volume - > type , sizeof ( volume - > type ) ) ;
_leave ( " = %u " , klen ) ;
return klen ;
2007-04-27 02:55:03 +04:00
}
2009-04-03 19:42:41 +04:00
/*****************************************************************************/
2007-04-27 02:55:03 +04:00
/*
2009-04-03 19:42:41 +04:00
* set the key for the index entry
2007-04-27 02:55:03 +04:00
*/
2009-04-03 19:42:41 +04:00
static uint16_t afs_vnode_cache_get_key ( const void * cookie_netfs_data ,
void * buffer , uint16_t bufmax )
2007-04-27 02:55:03 +04:00
{
2009-04-03 19:42:41 +04:00
const struct afs_vnode * vnode = cookie_netfs_data ;
uint16_t klen ;
2007-04-27 02:55:03 +04:00
2009-04-03 19:42:41 +04:00
_enter ( " {%x,%x,%llx},%p,%u " ,
vnode - > fid . vnode , vnode - > fid . unique , vnode - > status . data_version ,
buffer , bufmax ) ;
2007-04-27 02:55:03 +04:00
2009-04-03 19:42:41 +04:00
klen = sizeof ( vnode - > fid . vnode ) ;
if ( klen > bufmax )
return 0 ;
memcpy ( buffer , & vnode - > fid . vnode , sizeof ( vnode - > fid . vnode ) ) ;
2007-04-27 02:55:03 +04:00
2009-04-03 19:42:41 +04:00
_leave ( " = %u " , klen ) ;
return klen ;
2007-04-27 02:55:03 +04:00
}
/*
2009-04-03 19:42:41 +04:00
* provide updated file attributes
2007-04-27 02:55:03 +04:00
*/
2009-04-03 19:42:41 +04:00
static void afs_vnode_cache_get_attr ( const void * cookie_netfs_data ,
uint64_t * size )
2007-04-27 02:55:03 +04:00
{
2009-04-03 19:42:41 +04:00
const struct afs_vnode * vnode = cookie_netfs_data ;
2007-04-27 02:55:03 +04:00
2009-04-03 19:42:41 +04:00
_enter ( " {%x,%x,%llx}, " ,
vnode - > fid . vnode , vnode - > fid . unique ,
vnode - > status . data_version ) ;
2007-04-27 02:55:03 +04:00
2009-04-03 19:42:41 +04:00
* size = vnode - > status . size ;
2007-04-27 02:55:03 +04:00
}
/*
2009-04-03 19:42:41 +04:00
* provide new auxilliary 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 ;
uint16_t dlen ;
_enter ( " {%x,%x,%Lx},%p,%u " ,
vnode - > fid . vnode , vnode - > fid . unique , vnode - > status . data_version ,
buffer , bufmax ) ;
dlen = sizeof ( vnode - > fid . unique ) + sizeof ( vnode - > status . data_version ) ;
if ( dlen > bufmax )
return 0 ;
memcpy ( buffer , & vnode - > fid . unique , sizeof ( vnode - > fid . unique ) ) ;
buffer + = sizeof ( vnode - > fid . unique ) ;
memcpy ( buffer , & vnode - > status . data_version ,
sizeof ( vnode - > status . data_version ) ) ;
_leave ( " = %u " , dlen ) ;
return dlen ;
}
/*
* check that the auxilliary data indicates that the entry is still valid
2007-04-27 02:55:03 +04:00
*/
2009-04-03 19:42:41 +04:00
static enum fscache_checkaux afs_vnode_cache_check_aux ( void * cookie_netfs_data ,
const void * buffer ,
uint16_t buflen )
2007-04-27 02:55:03 +04:00
{
2009-04-03 19:42:41 +04:00
struct afs_vnode * vnode = cookie_netfs_data ;
uint16_t dlen ;
_enter ( " {%x,%x,%llx},%p,%u " ,
vnode - > fid . vnode , vnode - > fid . unique , vnode - > status . data_version ,
buffer , buflen ) ;
/* check the size of the data is what we're expecting */
dlen = sizeof ( vnode - > fid . unique ) + sizeof ( vnode - > status . data_version ) ;
if ( dlen ! = buflen ) {
_leave ( " = OBSOLETE [len %hx != %hx] " , dlen , buflen ) ;
return FSCACHE_CHECKAUX_OBSOLETE ;
2007-04-27 02:55:03 +04:00
}
2009-04-03 19:42:41 +04:00
if ( memcmp ( buffer ,
& vnode - > fid . unique ,
sizeof ( vnode - > fid . unique )
) ! = 0 ) {
unsigned unique ;
memcpy ( & unique , buffer , sizeof ( unique ) ) ;
_leave ( " = OBSOLETE [uniq %x != %x] " ,
unique , vnode - > fid . unique ) ;
return FSCACHE_CHECKAUX_OBSOLETE ;
}
if ( memcmp ( buffer + sizeof ( vnode - > fid . unique ) ,
& vnode - > status . data_version ,
sizeof ( vnode - > status . data_version )
) ! = 0 ) {
afs_dataversion_t version ;
memcpy ( & version , buffer + sizeof ( vnode - > fid . unique ) ,
sizeof ( version ) ) ;
_leave ( " = OBSOLETE [vers %llx != %llx] " ,
version , vnode - > status . data_version ) ;
return FSCACHE_CHECKAUX_OBSOLETE ;
2007-04-27 02:55:03 +04:00
}
_leave ( " = SUCCESS " ) ;
2009-04-03 19:42:41 +04:00
return FSCACHE_CHECKAUX_OKAY ;
2007-04-27 02:55:03 +04:00
}
/*
2009-04-03 19:42:41 +04:00
* indication the cookie is no longer uncached
* - this function is called when the backing store currently caching a cookie
* is removed
* - the netfs should use this to clean up any markers indicating cached pages
* - this is mandatory for any object that may have data
2007-04-27 02:55:03 +04:00
*/
2009-04-03 19:42:41 +04:00
static void afs_vnode_cache_now_uncached ( void * cookie_netfs_data )
2007-04-27 02:55:03 +04:00
{
2009-04-03 19:42:41 +04:00
struct afs_vnode * vnode = cookie_netfs_data ;
struct pagevec pvec ;
pgoff_t first ;
int loop , nr_pages ;
_enter ( " {%x,%x,%Lx} " ,
vnode - > fid . vnode , vnode - > fid . unique , vnode - > status . data_version ) ;
pagevec_init ( & pvec , 0 ) ;
first = 0 ;
for ( ; ; ) {
/* grab a bunch of pages to clean */
nr_pages = pagevec_lookup ( & pvec , vnode - > vfs_inode . i_mapping ,
first ,
PAGEVEC_SIZE - pagevec_count ( & pvec ) ) ;
if ( ! nr_pages )
break ;
2007-04-27 02:55:03 +04:00
2009-04-03 19:42:41 +04:00
for ( loop = 0 ; loop < nr_pages ; loop + + )
ClearPageFsCache ( pvec . pages [ loop ] ) ;
first = pvec . pages [ nr_pages - 1 ] - > index + 1 ;
pvec . nr = nr_pages ;
pagevec_release ( & pvec ) ;
cond_resched ( ) ;
}
2007-04-27 02:55:03 +04:00
2009-04-03 19:42:41 +04:00
_leave ( " " ) ;
2007-04-27 02:55:03 +04:00
}