Commit 7a9df5e2 authored by David Howells's avatar David Howells Committed by Linus Torvalds

[PATCH] AFS update

parent d2a65691
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
# Makefile for Red Hat Linux AFS client. # Makefile for Red Hat Linux AFS client.
# #
#CFLAGS += -finstrument-functions
kafs-objs := \ kafs-objs := \
callback.o \ callback.o \
cell.o \ cell.o \
......
/* cache-layout.h: AFS cache layout
*
* Copyright (C) 2002 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.
*
*
* The cache is stored on a block device and is laid out as:
*
* 0 +------------------------------------------------
* |
* | SuperBlock
* |
* 1 +------------------------------------------------
* |
* | file-meta-data File: Data block #0
* | - file-meta-data file (volix #0 file #0) : Meta-data block
* | - contains direct pointers to first 64 file data blocks
* | - Cached cell catalogue file (volix #0 file #1) file: Meta-data block
* | - Cached volume location catalogue file (volix #0 file #2): Meta-data block
* | - Vnode catalogue hash bucket #n file: Meta-data block
* |
* 2 +------------------------------------------------
* |
* | Bitmap Block Allocation Bitmap
* | - 1 bit per block in the bitmap block
* | - bit 0 of dword 0 refers to the bitmap block 0
* | - set if the bitmap block is full
* | - 32768 bits per block, requiring 4 blocks for a 16Tb cache
* | - bitmap bitmap blocks are cleared initially
* | - not present if <4 bitmap blocks
* |
* +------------------------------------------------
* |
* | File Block Allocation Bitmap
* | - 1 bit per block in the cache
* | - bit 0 of dword 0 refers to the first block of the data cache
* | - set if block is allocated
* | - 32768 bits per block, requiring 131072 blocks for a 16Tb cache
* | - bitmap blocks are cleared lazily (sb->bix_bitmap_unready)
* |
* +------------------------------------------------
* |
* | Data Cache
* |
* End +------------------------------------------------
*
* Blocks are indexed by an unsigned 32-bit word, meaning that the cache can hold up to 2^32 pages,
* or 16Tb in total.
*
* Credentials will be cached in memory, since they are subject to change without notice, and are
* difficult to derive manually, being constructed from the following information:
* - per vnode user ID and mode mask
* - parent directory ACL
* - directory ACL (dirs only)
* - group lists from ptserver
*/
#ifndef _LINUX_AFS_CACHE_LAYOUT_H
#define _LINUX_AFS_CACHE_LAYOUT_H
#include "types.h"
typedef u32 afsc_blockix_t;
typedef u32 afsc_cellix_t;
/* Cached volume index
* - afsc_volix_t/4 is the index into the volume cache
* - afsc_volix_t%4 is 0 for R/W, 1 for R/O and 2 for Bak (3 is not used)
* - afsc_volix_t==0-3 refers to a "virtual" volume that stores meta-data about the cache
*/
typedef struct {
u32 index;
} afsc_volix_t;
#define AFSC_VNCAT_HASH_NBUCKETS 128
/* special meta file IDs (all cell 0 vol 0) */
enum afsc_meta_fids {
AFSC_META_FID_METADATA = 0,
AFSC_META_FID_CELL_CATALOGUE = 1,
AFSC_META_FID_VLDB_CATALOGUE = 2,
AFSC_META_FID_VNODE_CATALOGUE0 = 3,
AFSC_META_FID__COUNT = AFSC_VNCAT_HASH_NBUCKETS + 3
};
/*****************************************************************************/
/*
* cache superblock block layout
* - the blockdev is prepared for initialisation by 'echo "kafsuninit" >/dev/hdaXX' before mounting
* - when initialised, the magic number is changed to "kafs-cache"
*/
struct afsc_super_block
{
char magic[10]; /* magic number */
#define AFSC_SUPER_MAGIC "kafs-cache"
#define AFSC_SUPER_MAGIC_NEEDS_INIT "kafsuninit"
#define AFSC_SUPER_MAGIC_SIZE 10
unsigned short endian; /* 0x1234 stored CPU-normal order */
#define AFSC_SUPER_ENDIAN 0x1234
unsigned version; /* format version */
#define AFSC_SUPER_VERSION 1
/* layout */
unsigned bsize; /* cache block size */
afsc_blockix_t bix_bitmap_fullmap; /* block ix of bitmap full bitmap */
afsc_blockix_t bix_bitmap; /* block ix of alloc bitmap */
afsc_blockix_t bix_bitmap_unready; /* block ix of unready area of bitmap */
afsc_blockix_t bix_cache; /* block ix of data cache */
afsc_blockix_t bix_end; /* block ix of end of cache */
};
/*****************************************************************************/
/*
* vnode (inode) metadata cache record
* - padded out to 512 bytes and stored eight to a page
* - only the data version is necessary
* - disconnected operation is not supported
* - afs_iget() contacts the server to get the meta-data _anyway_ when an inode is first brought
* into memory
* - at least 64 direct block pointers will be available (a directory is max 256Kb)
* - any block pointer which is 0 indicates an uncached page
*/
struct afsc_vnode_meta
{
/* file ID */
afsc_volix_t volume_ix; /* volume catalogue index */
unsigned vnode; /* vnode number */
unsigned unique; /* FID unique */
unsigned size; /* size of file */
time_t mtime; /* last modification time */
/* file status */
afs_dataversion_t version; /* current data version */
/* file contents */
afsc_blockix_t dbl_indirect; /* double indirect block index */
afsc_blockix_t indirect; /* single indirect block 0 index */
afsc_blockix_t direct[0]; /* direct block index (#AFSC_VNODE_META_DIRECT) */
};
#define AFSC_VNODE_META_RECSIZE 512 /* record size */
#define AFSC_VNODE_META_DIRECT \
((AFSC_VNODE_META_RECSIZE-sizeof(struct afsc_vnode_meta))/sizeof(afsc_blockix_t))
#define AFSC_VNODE_META_PER_PAGE (PAGE_SIZE / AFSC_VNODE_META_RECSIZE)
/*****************************************************************************/
/*
* entry in the cached cell catalogue
*/
struct afsc_cell_record
{
char name[64]; /* cell name (padded with NULs) */
struct in_addr servers[16]; /* cached cell servers */
};
/*****************************************************************************/
/*
* entry in the cached volume location catalogue
* - indexed by afsc_volix_t/4
*/
struct afsc_vldb_record
{
char name[64]; /* volume name (padded with NULs) */
afs_volid_t vid[3]; /* volume IDs for R/W, R/O and Bak volumes */
unsigned char vidmask; /* voltype mask for vid[] */
unsigned char _pad[1];
unsigned short nservers; /* number of entries used in servers[] */
struct in_addr servers[8]; /* fileserver addresses */
unsigned char srvtmask[8]; /* voltype masks for servers[] */
#define AFSC_VOL_STM_RW 0x01 /* server holds a R/W version of the volume */
#define AFSC_VOL_STM_RO 0x02 /* server holds a R/O version of the volume */
#define AFSC_VOL_STM_BAK 0x04 /* server holds a backup version of the volume */
afsc_cellix_t cell_ix; /* cell catalogue index (MAX_UINT if unused) */
time_t ctime; /* time at which cached */
};
/*****************************************************************************/
/*
* vnode catalogue entry
* - must be 2^x size so that do_generic_file_read doesn't present them split across pages
*/
struct afsc_vnode_catalogue
{
afsc_volix_t volume_ix; /* volume catalogue index */
afs_vnodeid_t vnode; /* vnode ID */
u32 meta_ix; /* metadata file index */
u32 atime; /* last time entry accessed */
} __attribute__((packed));
#define AFSC_VNODE_CATALOGUE_PER_BLOCK ((size_t)(PAGE_SIZE/sizeof(struct afsc_vnode_catalogue)))
/*****************************************************************************/
/*
* vnode data "page directory" block
* - first 1024 pages don't map through here
* - PAGE_SIZE in size
*/
struct afsc_indirect_block
{
afsc_blockix_t pt_bix[1024]; /* "page table" block indices */
};
/*****************************************************************************/
/*
* vnode data "page table" block
* - PAGE_SIZE in size
*/
struct afsc_dbl_indirect_block
{
afsc_blockix_t page_bix[1024]; /* "page" block indices */
};
#endif /* _LINUX_AFS_CACHE_LAYOUT_H */
/* cache.h: AFS local cache management interface
*
* Copyright (C) 2002 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.
*/
#ifndef _LINUX_AFS_CACHE_H
#define _LINUX_AFS_CACHE_H
#undef AFS_CACHING_SUPPORT
#include <linux/mm.h>
#ifdef AFS_CACHING_SUPPORT
#include <linux/cachefs.h>
#endif
#include "types.h"
#ifdef __KERNEL__
#endif /* __KERNEL__ */
#endif /* _LINUX_AFS_CACHE_H */
...@@ -68,7 +68,7 @@ int SRXAFSCM_InitCallBackState(afs_server_t *server) ...@@ -68,7 +68,7 @@ int SRXAFSCM_InitCallBackState(afs_server_t *server)
spin_unlock(&vnode->lock); spin_unlock(&vnode->lock);
iput(inode); iput(inode);
if (release) afs_put_server(server); afs_put_server(server);
spin_lock(&server->cb_lock); spin_lock(&server->cb_lock);
} }
......
...@@ -36,6 +36,19 @@ static char *rootcell; ...@@ -36,6 +36,19 @@ static char *rootcell;
MODULE_PARM(rootcell,"s"); MODULE_PARM(rootcell,"s");
MODULE_PARM_DESC(rootcell,"root AFS cell name and VL server IP addr list"); MODULE_PARM_DESC(rootcell,"root AFS cell name and VL server IP addr list");
#ifdef AFS_CACHING_SUPPORT
static cachefs_match_val_t afs_cell_cache_match(void *target, const void *entry);
static void afs_cell_cache_update(void *source, void *entry);
struct cachefs_index_def afs_cache_cell_index_def = {
.name = "cell_ix",
.data_size = sizeof(afs_cell_t),
.keys[0] = { CACHEFS_INDEX_KEYS_ASCIIZ, 64 },
.match = afs_cell_cache_match,
.update = afs_cell_cache_update,
};
#endif
/*****************************************************************************/ /*****************************************************************************/
/* /*
* create a cell record * create a cell record
...@@ -65,7 +78,6 @@ int afs_cell_create(const char *name, char *vllist, afs_cell_t **_cell) ...@@ -65,7 +78,6 @@ int afs_cell_create(const char *name, char *vllist, afs_cell_t **_cell)
atomic_set(&cell->usage,0); atomic_set(&cell->usage,0);
INIT_LIST_HEAD(&cell->link); INIT_LIST_HEAD(&cell->link);
INIT_LIST_HEAD(&cell->caches);
rwlock_init(&cell->sv_lock); rwlock_init(&cell->sv_lock);
INIT_LIST_HEAD(&cell->sv_list); INIT_LIST_HEAD(&cell->sv_list);
...@@ -96,7 +108,7 @@ int afs_cell_create(const char *name, char *vllist, afs_cell_t **_cell) ...@@ -96,7 +108,7 @@ int afs_cell_create(const char *name, char *vllist, afs_cell_t **_cell)
cell->vl_addrs[cell->vl_naddrs++].s_addr = cell->vl_addrs[cell->vl_naddrs++].s_addr =
htonl((a<<24)|(b<<16)|(c<<8)|d); htonl((a<<24)|(b<<16)|(c<<8)|d);
if (cell->vl_naddrs>=16) if (cell->vl_naddrs >= AFS_CELL_MAX_ADDRS)
break; break;
} while(vllist=next, vllist); } while(vllist=next, vllist);
...@@ -106,6 +118,14 @@ int afs_cell_create(const char *name, char *vllist, afs_cell_t **_cell) ...@@ -106,6 +118,14 @@ int afs_cell_create(const char *name, char *vllist, afs_cell_t **_cell)
if (ret<0) if (ret<0)
goto error; goto error;
#ifdef AFS_CACHING_SUPPORT
/* put it up for caching */
cachefs_acquire_cookie(afs_cache_netfs.primary_index,
&afs_vlocation_cache_index_def,
cell,
&cell->cache);
#endif
/* add to the cell lists */ /* add to the cell lists */
write_lock(&afs_cells_lock); write_lock(&afs_cells_lock);
list_add_tail(&cell->link,&afs_cells); list_add_tail(&cell->link,&afs_cells);
...@@ -166,36 +186,45 @@ int afs_cell_init(void) ...@@ -166,36 +186,45 @@ int afs_cell_init(void)
/* /*
* lookup a cell record * lookup a cell record
*/ */
int afs_cell_lookup(const char *name, afs_cell_t **_cell) int afs_cell_lookup(const char *name, unsigned namesz, struct afs_cell **_cell)
{ {
struct list_head *_p; struct list_head *_p;
afs_cell_t *cell; afs_cell_t *cell;
int ret;
_enter("\"%s\",",name?name:"*thiscell*"); _enter("\"%*.*s\",", namesz, namesz, name ? name : "");
cell = afs_cell_root; *_cell = NULL;
if (name) { if (name) {
/* if the cell was named, look for it in the cell record list */ /* if the cell was named, look for it in the cell record list */
ret = -ENOENT;
cell = NULL; cell = NULL;
read_lock(&afs_cells_lock); read_lock(&afs_cells_lock);
list_for_each(_p,&afs_cells) { list_for_each(_p,&afs_cells) {
cell = list_entry(_p,afs_cell_t,link); cell = list_entry(_p, struct afs_cell, link);
if (strcmp(cell->name,name)==0) if (strncmp(cell->name, name, namesz) == 0) {
afs_get_cell(cell);
break; break;
}
cell = NULL; cell = NULL;
} }
read_unlock(&afs_cells_lock); read_unlock(&afs_cells_lock);
}
if (cell) if (cell)
ret = 0;
}
else {
cell = afs_cell_root;
afs_get_cell(cell); afs_get_cell(cell);
ret = 0;
}
*_cell = cell; *_cell = cell;
_leave(" = %d (%p)",cell?0:-ENOENT,cell); _leave(" = %d (%p)", ret, cell);
return cell ? 0 : -ENOENT; return ret;
} /* end afs_cell_lookup() */ } /* end afs_cell_lookup() */
...@@ -211,8 +240,8 @@ afs_cell_t *afs_get_cell_maybe(afs_cell_t **_cell) ...@@ -211,8 +240,8 @@ afs_cell_t *afs_get_cell_maybe(afs_cell_t **_cell)
cell = *_cell; cell = *_cell;
if (cell && !list_empty(&cell->link)) if (cell && !list_empty(&cell->link))
atomic_inc(&cell->usage); afs_get_cell(cell);
else else
cell = NULL; cell = NULL;
write_unlock(&afs_cells_lock); write_unlock(&afs_cells_lock);
...@@ -226,6 +255,9 @@ afs_cell_t *afs_get_cell_maybe(afs_cell_t **_cell) ...@@ -226,6 +255,9 @@ afs_cell_t *afs_get_cell_maybe(afs_cell_t **_cell)
*/ */
void afs_put_cell(afs_cell_t *cell) void afs_put_cell(afs_cell_t *cell)
{ {
if (!cell)
return;
_enter("%p{%d,%s}",cell,atomic_read(&cell->usage),cell->name); _enter("%p{%d,%s}",cell,atomic_read(&cell->usage),cell->name);
/* sanity check */ /* sanity check */
...@@ -278,6 +310,10 @@ static void afs_cell_destroy(afs_cell_t *cell) ...@@ -278,6 +310,10 @@ static void afs_cell_destroy(afs_cell_t *cell)
list_del_init(&cell->proc_link); list_del_init(&cell->proc_link);
up_write(&afs_proc_cells_sem); up_write(&afs_proc_cells_sem);
#ifdef AFS_CACHING_SUPPORT
cachefs_relinquish_cookie(cell->cache,0);
#endif
up_write(&afs_cells_sem); up_write(&afs_cells_sem);
if (!list_empty(&cell->sv_list)) BUG(); if (!list_empty(&cell->sv_list)) BUG();
...@@ -377,8 +413,7 @@ void afs_cell_purge(void) ...@@ -377,8 +413,7 @@ void afs_cell_purge(void)
_enter(""); _enter("");
if (afs_cell_root) afs_put_cell(afs_cell_root);
afs_put_cell(afs_cell_root);
while (!list_empty(&afs_cells)) { while (!list_empty(&afs_cells)) {
cell = NULL; cell = NULL;
...@@ -450,3 +485,46 @@ void afs_cell_purge(void) ...@@ -450,3 +485,46 @@ void afs_cell_purge(void)
_leave(""); _leave("");
} /* end afs_cell_purge() */ } /* end afs_cell_purge() */
/*****************************************************************************/
/*
* match a cell record obtained from the cache
*/
#ifdef AFS_CACHING_SUPPORT
static cachefs_match_val_t afs_cell_cache_match(void *target, const void *entry)
{
const struct afs_cache_cell *ccell = entry;
struct afs_cell *cell = target;
_enter("{%s},{%s}", ccell->name, cell->name);
if (strncmp(ccell->name, cell->name, sizeof(ccell->name)) == 0) {
_leave(" = SUCCESS");
return CACHEFS_MATCH_SUCCESS;
}
_leave(" = FAILED");
return CACHEFS_MATCH_FAILED;
} /* end afs_cell_cache_match() */
#endif
/*****************************************************************************/
/*
* update a cell record in the cache
*/
#ifdef AFS_CACHING_SUPPORT
static void afs_cell_cache_update(void *source, void *entry)
{
struct afs_cache_cell *ccell = entry;
struct afs_cell *cell = source;
_enter("%p,%p", source, entry);
strncpy(ccell->name, cell->name, sizeof(ccell->name));
memcpy(ccell->vl_servers,
cell->vl_addrs,
min(sizeof(ccell->vl_servers), sizeof(cell->vl_addrs)));
} /* end afs_cell_cache_update() */
#endif
...@@ -13,9 +13,22 @@ ...@@ -13,9 +13,22 @@
#define _LINUX_AFS_CELL_H #define _LINUX_AFS_CELL_H
#include "types.h" #include "types.h"
#include "cache.h"
#define AFS_CELL_MAX_ADDRS 15
extern volatile int afs_cells_being_purged; /* T when cells are being purged by rmmod */ extern volatile int afs_cells_being_purged; /* T when cells are being purged by rmmod */
/*****************************************************************************/
/*
* entry in the cached cell catalogue
*/
struct afs_cache_cell
{
char name[64]; /* cell name (padded with NULs) */
struct in_addr vl_servers[15]; /* cached cell VL servers */
};
/*****************************************************************************/ /*****************************************************************************/
/* /*
* AFS cell record * AFS cell record
...@@ -26,7 +39,9 @@ struct afs_cell ...@@ -26,7 +39,9 @@ struct afs_cell
struct list_head link; /* main cell list link */ struct list_head link; /* main cell list link */
struct list_head proc_link; /* /proc cell list link */ struct list_head proc_link; /* /proc cell list link */
struct proc_dir_entry *proc_dir; /* /proc dir for this cell */ struct proc_dir_entry *proc_dir; /* /proc dir for this cell */
struct list_head caches; /* list of caches currently backing this cell */ #ifdef AFS_CACHING_SUPPORT
struct cachefs_cookie *cache; /* caching cookie */
#endif
/* server record management */ /* server record management */
rwlock_t sv_lock; /* active server list lock */ rwlock_t sv_lock; /* active server list lock */
...@@ -41,22 +56,22 @@ struct afs_cell ...@@ -41,22 +56,22 @@ struct afs_cell
spinlock_t vl_gylock; /* graveyard lock */ spinlock_t vl_gylock; /* graveyard lock */
unsigned short vl_naddrs; /* number of VL servers in addr list */ unsigned short vl_naddrs; /* number of VL servers in addr list */
unsigned short vl_curr_svix; /* current server index */ unsigned short vl_curr_svix; /* current server index */
struct in_addr vl_addrs[16]; /* cell VL server addresses */ struct in_addr vl_addrs[AFS_CELL_MAX_ADDRS]; /* cell VL server addresses */
char name[0]; /* cell name - must go last */ char name[0]; /* cell name - must go last */
}; };
extern int afs_cell_init(void); extern int afs_cell_init(void);
extern int afs_cell_create(const char *name, char *vllist, afs_cell_t **_cell); extern int afs_cell_create(const char *name, char *vllist, struct afs_cell **_cell);
extern int afs_cell_lookup(const char *name, afs_cell_t **_cell); extern int afs_cell_lookup(const char *name, unsigned nmsize, struct afs_cell **_cell);
#define afs_get_cell(C) do { atomic_inc(&(C)->usage); } while(0) #define afs_get_cell(C) do { atomic_inc(&(C)->usage); } while(0)
extern afs_cell_t *afs_get_cell_maybe(afs_cell_t **_cell); extern struct afs_cell *afs_get_cell_maybe(struct afs_cell **_cell);
extern void afs_put_cell(afs_cell_t *cell); extern void afs_put_cell(struct afs_cell *cell);
extern void afs_cell_purge(void); extern void afs_cell_purge(void);
......
...@@ -119,6 +119,7 @@ static int kafscmd(void *arg) ...@@ -119,6 +119,7 @@ static int kafscmd(void *arg)
int die; int die;
printk("kAFS: Started kafscmd %d\n",current->pid); printk("kAFS: Started kafscmd %d\n",current->pid);
daemonize("kafscmd"); daemonize("kafscmd");
complete(&kafscmd_alive); complete(&kafscmd_alive);
...@@ -293,15 +294,20 @@ int afscm_start(void) ...@@ -293,15 +294,20 @@ int afscm_start(void)
down_write(&afscm_sem); down_write(&afscm_sem);
if (!afscm_usage) { if (!afscm_usage) {
ret = kernel_thread(kafscmd,NULL,0); ret = kernel_thread(kafscmd, NULL, 0);
if (ret<0) if (ret < 0)
goto out; goto out;
wait_for_completion(&kafscmd_alive); wait_for_completion(&kafscmd_alive);
ret = rxrpc_add_service(afs_transport,&AFSCM_service); ret = rxrpc_add_service(afs_transport, &AFSCM_service);
if (ret<0) if (ret<0)
goto kill; goto kill;
#ifdef AFS_AUTOMOUNT_SUPPORT
afs_kafstimod_add_timer(&afs_mntpt_expiry_timer,
afs_mntpt_expiry_timeout * HZ);
#endif
} }
afscm_usage++; afscm_usage++;
...@@ -330,17 +336,20 @@ void afscm_stop(void) ...@@ -330,17 +336,20 @@ void afscm_stop(void)
down_write(&afscm_sem); down_write(&afscm_sem);
if (afscm_usage==0) BUG(); if (afscm_usage == 0) BUG();
afscm_usage--; afscm_usage--;
if (afscm_usage==0) { if (afscm_usage == 0) {
/* don't want more incoming calls */ /* don't want more incoming calls */
rxrpc_del_service(afs_transport,&AFSCM_service); rxrpc_del_service(afs_transport, &AFSCM_service);
/* abort any calls I've still got open (the afscm_error() will dequeue them) */ /* abort any calls I've still got open (the afscm_error() will dequeue them) */
spin_lock(&afscm_calls_lock); spin_lock(&afscm_calls_lock);
while (!list_empty(&afscm_calls)) { while (!list_empty(&afscm_calls)) {
call = list_entry(afscm_calls.next,struct rxrpc_call,app_link); call = list_entry(afscm_calls.next,
struct rxrpc_call,
app_link);
list_del_init(&call->app_link); list_del_init(&call->app_link);
rxrpc_get_call(call); rxrpc_get_call(call);
spin_unlock(&afscm_calls_lock); spin_unlock(&afscm_calls_lock);
...@@ -348,7 +357,8 @@ void afscm_stop(void) ...@@ -348,7 +357,8 @@ void afscm_stop(void)
rxrpc_call_abort(call,-ESRCH); /* abort, dequeue and put */ rxrpc_call_abort(call,-ESRCH); /* abort, dequeue and put */
_debug("nuking active call %08x.%d", _debug("nuking active call %08x.%d",
ntohl(call->conn->conn_id),ntohl(call->call_id)); ntohl(call->conn->conn_id),
ntohl(call->call_id));
rxrpc_put_call(call); rxrpc_put_call(call);
rxrpc_put_call(call); rxrpc_put_call(call);
...@@ -376,6 +386,10 @@ void afscm_stop(void) ...@@ -376,6 +386,10 @@ void afscm_stop(void)
spin_lock(&kafscmd_attention_lock); spin_lock(&kafscmd_attention_lock);
} }
spin_unlock(&kafscmd_attention_lock); spin_unlock(&kafscmd_attention_lock);
#ifdef AFS_AUTOMOUNT_SUPPORT
afs_kafstimod_del_timer(&afs_mntpt_expiry_timer);
#endif
} }
up_write(&afscm_sem); up_write(&afscm_sem);
...@@ -490,7 +504,7 @@ static void _SRXAFSCM_CallBack(struct rxrpc_call *call) ...@@ -490,7 +504,7 @@ static void _SRXAFSCM_CallBack(struct rxrpc_call *call)
if (ret<0) if (ret<0)
rxrpc_call_abort(call,ret); rxrpc_call_abort(call,ret);
if (server) afs_put_server(server); afs_put_server(server);
_leave(" = %d",ret); _leave(" = %d",ret);
...@@ -556,7 +570,7 @@ static void _SRXAFSCM_InitCallBackState(struct rxrpc_call *call) ...@@ -556,7 +570,7 @@ static void _SRXAFSCM_InitCallBackState(struct rxrpc_call *call)
if (ret<0) if (ret<0)
rxrpc_call_abort(call,ret); rxrpc_call_abort(call,ret);
if (server) afs_put_server(server); afs_put_server(server);
_leave(" = %d",ret); _leave(" = %d",ret);
...@@ -622,7 +636,7 @@ static void _SRXAFSCM_Probe(struct rxrpc_call *call) ...@@ -622,7 +636,7 @@ static void _SRXAFSCM_Probe(struct rxrpc_call *call)
if (ret<0) if (ret<0)
rxrpc_call_abort(call,ret); rxrpc_call_abort(call,ret);
if (server) afs_put_server(server); afs_put_server(server);
_leave(" = %d",ret); _leave(" = %d",ret);
......
...@@ -23,10 +23,11 @@ ...@@ -23,10 +23,11 @@
#include "super.h" #include "super.h"
#include "internal.h" #include "internal.h"
static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *); static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nd);
static int afs_dir_open(struct inode *inode, struct file *file); static int afs_dir_open(struct inode *inode, struct file *file);
static int afs_dir_readdir(struct file *file, void *dirent, filldir_t filldir); static int afs_dir_readdir(struct file *file, void *dirent, filldir_t filldir);
static int afs_d_revalidate(struct dentry *dentry, struct nameidata *); static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd);
static int afs_d_delete(struct dentry *dentry); static int afs_d_delete(struct dentry *dentry);
static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, loff_t fpos, static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, loff_t fpos,
ino_t ino, unsigned dtype); ino_t ino, unsigned dtype);
...@@ -70,7 +71,7 @@ typedef union afs_dirent { ...@@ -70,7 +71,7 @@ typedef union afs_dirent {
u8 name[16]; u8 name[16];
u8 overflow[4]; /* if any char of the name (inc NUL) reaches here, consume u8 overflow[4]; /* if any char of the name (inc NUL) reaches here, consume
* the next dirent too */ * the next dirent too */
} parts; } u;
u8 extended_name[32]; u8 extended_name[32];
} afs_dirent_t; } afs_dirent_t;
...@@ -256,7 +257,7 @@ static int afs_dir_iterate_block(unsigned *fpos, ...@@ -256,7 +257,7 @@ static int afs_dir_iterate_block(unsigned *fpos,
/* got a valid entry */ /* got a valid entry */
dire = &block->dirents[offset]; dire = &block->dirents[offset];
nlen = strnlen(dire->parts.name,sizeof(*block) - offset*sizeof(afs_dirent_t)); nlen = strnlen(dire->u.name,sizeof(*block) - offset*sizeof(afs_dirent_t));
_debug("ENT[%Zu.%u]: %s %Zu \"%s\"\n", _debug("ENT[%Zu.%u]: %s %Zu \"%s\"\n",
blkoff/sizeof(afs_dir_block_t),offset, blkoff/sizeof(afs_dir_block_t),offset,
...@@ -288,11 +289,11 @@ static int afs_dir_iterate_block(unsigned *fpos, ...@@ -288,11 +289,11 @@ static int afs_dir_iterate_block(unsigned *fpos,
/* found the next entry */ /* found the next entry */
ret = filldir(cookie, ret = filldir(cookie,
dire->parts.name, dire->u.name,
nlen, nlen,
blkoff + offset * sizeof(afs_dirent_t), blkoff + offset * sizeof(afs_dirent_t),
ntohl(dire->parts.vnode), ntohl(dire->u.vnode),
filldir==afs_dir_lookup_filldir ? dire->parts.unique : DT_UNKNOWN); filldir==afs_dir_lookup_filldir ? dire->u.unique : DT_UNKNOWN);
if (ret<0) { if (ret<0) {
_leave(" = 0 [full]"); _leave(" = 0 [full]");
return 0; return 0;
...@@ -414,7 +415,8 @@ static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, lof ...@@ -414,7 +415,8 @@ static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, lof
/* /*
* look up an entry in a directory * look up an entry in a directory
*/ */
static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nd)
{ {
struct afs_dir_lookup_cookie cookie; struct afs_dir_lookup_cookie cookie;
struct afs_super_info *as; struct afs_super_info *as;
...@@ -423,11 +425,11 @@ static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, s ...@@ -423,11 +425,11 @@ static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, s
unsigned fpos; unsigned fpos;
int ret; int ret;
_enter("{%lu},{%s}",dir->i_ino,dentry->d_name.name); _enter("{%lu},%p{%s}",dir->i_ino,dentry,dentry->d_name.name);
/* insanity checks first */ /* insanity checks first */
if (sizeof(afs_dir_block_t) != 2048) BUG(); BUG_ON(sizeof(afs_dir_block_t) != 2048);
if (sizeof(afs_dirent_t) != 32) BUG(); BUG_ON(sizeof(afs_dirent_t) != 32);
if (dentry->d_name.len > 255) { if (dentry->d_name.len > 255) {
_leave(" = -ENAMETOOLONG"); _leave(" = -ENAMETOOLONG");
...@@ -495,9 +497,11 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) ...@@ -495,9 +497,11 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
unsigned fpos; unsigned fpos;
int ret; int ret;
_enter("%s,%p",dentry->d_name.name,nd); _enter("{sb=%p n=%s},",dentry->d_sb,dentry->d_name.name);
/* lock down the parent dentry so we can peer at it */
parent = dget_parent(dentry->d_parent);
parent = dget_parent(dentry);
dir = parent->d_inode; dir = parent->d_inode;
inode = dentry->d_inode; inode = dentry->d_inode;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/buffer_head.h>
#include "volume.h" #include "volume.h"
#include "vnode.h" #include "vnode.h"
#include <rxrpc/call.h> #include <rxrpc/call.h>
...@@ -27,6 +28,8 @@ static int afs_file_release(struct inode *inode, struct file *file); ...@@ -27,6 +28,8 @@ static int afs_file_release(struct inode *inode, struct file *file);
#endif #endif
static int afs_file_readpage(struct file *file, struct page *page); static int afs_file_readpage(struct file *file, struct page *page);
static int afs_file_invalidatepage(struct page *page, unsigned long offset);
static int afs_file_releasepage(struct page *page, int gfp_flags);
static ssize_t afs_file_write(struct file *file, const char *buf, size_t size, loff_t *off); static ssize_t afs_file_write(struct file *file, const char *buf, size_t size, loff_t *off);
...@@ -37,7 +40,7 @@ struct inode_operations afs_file_inode_operations = { ...@@ -37,7 +40,7 @@ struct inode_operations afs_file_inode_operations = {
struct file_operations afs_file_file_operations = { struct file_operations afs_file_file_operations = {
.read = generic_file_read, .read = generic_file_read,
.write = afs_file_write, .write = afs_file_write,
.mmap = generic_file_readonly_mmap, .mmap = generic_file_mmap,
#if 0 #if 0
.open = afs_file_open, .open = afs_file_open,
.release = afs_file_release, .release = afs_file_release,
...@@ -47,6 +50,10 @@ struct file_operations afs_file_file_operations = { ...@@ -47,6 +50,10 @@ struct file_operations afs_file_file_operations = {
struct address_space_operations afs_fs_aops = { struct address_space_operations afs_fs_aops = {
.readpage = afs_file_readpage, .readpage = afs_file_readpage,
.sync_page = block_sync_page,
.set_page_dirty = __set_page_dirty_nobuffers,
.releasepage = afs_file_releasepage,
.invalidatepage = afs_file_invalidatepage,
}; };
/*****************************************************************************/ /*****************************************************************************/
...@@ -64,6 +71,40 @@ static ssize_t afs_file_write(struct file *file, const char *buf, size_t size, l ...@@ -64,6 +71,40 @@ static ssize_t afs_file_write(struct file *file, const char *buf, size_t size, l
return -EIO; return -EIO;
} /* end afs_file_write() */ } /* end afs_file_write() */
/*****************************************************************************/
/*
* deal with notification that a page was read from the cache
*/
#ifdef AFS_CACHING_SUPPORT
static void afs_file_readpage_read_complete(void *cookie_data, struct page *page, void *data,
int error)
{
_enter("%p,%p,%p,%d",cookie_data,page,data,error);
if (error)
SetPageError(page);
else
SetPageUptodate(page);
unlock_page(page);
} /* end afs_file_readpage_read_complete() */
#endif
/*****************************************************************************/
/*
* deal with notification that a page was written to the cache
*/
#ifdef AFS_CACHING_SUPPORT
static void afs_file_readpage_write_complete(void *cookie_data, struct page *page, void *data,
int error)
{
_enter("%p,%p,%p,%d",cookie_data,page,data,error);
unlock_page(page);
} /* end afs_file_readpage_write_complete() */
#endif
/*****************************************************************************/ /*****************************************************************************/
/* /*
* AFS read page from file (or symlink) * AFS read page from file (or symlink)
...@@ -71,6 +112,9 @@ static ssize_t afs_file_write(struct file *file, const char *buf, size_t size, l ...@@ -71,6 +112,9 @@ static ssize_t afs_file_write(struct file *file, const char *buf, size_t size, l
static int afs_file_readpage(struct file *file, struct page *page) static int afs_file_readpage(struct file *file, struct page *page)
{ {
struct afs_rxfs_fetch_descriptor desc; struct afs_rxfs_fetch_descriptor desc;
#ifdef AFS_CACHING_SUPPORT
struct cachefs_page *pageio;
#endif
struct inode *inode; struct inode *inode;
afs_vnode_t *vnode; afs_vnode_t *vnode;
int ret; int ret;
...@@ -88,28 +132,73 @@ static int afs_file_readpage(struct file *file, struct page *page) ...@@ -88,28 +132,73 @@ static int afs_file_readpage(struct file *file, struct page *page)
if (vnode->flags & AFS_VNODE_DELETED) if (vnode->flags & AFS_VNODE_DELETED)
goto error; goto error;
/* work out how much to get and from where */ #ifdef AFS_CACHING_SUPPORT
desc.fid = vnode->fid; ret = cachefs_page_get_private(page,&pageio,GFP_NOIO);
desc.offset = page->index << PAGE_CACHE_SHIFT; if (ret<0)
desc.size = min((size_t)(inode->i_size - desc.offset),(size_t)PAGE_SIZE);
desc.buffer = kmap(page);
clear_page(desc.buffer);
/* read the contents of the file from the server into the page */
ret = afs_vnode_fetch_data(vnode,&desc);
kunmap(page);
if (ret<0) {
if (ret==-ENOENT) {
_debug("got NOENT from server - marking file deleted and stale");
vnode->flags |= AFS_VNODE_DELETED;
ret = -ESTALE;
}
goto error; goto error;
}
SetPageUptodate(page); /* is it cached? */
unlock_page(page); ret = cachefs_read_or_alloc_page(vnode->cache,
page,
afs_file_readpage_read_complete,
NULL,
GFP_KERNEL);
#else
ret = -ENOBUFS;
#endif
switch (ret) {
/* read BIO submitted and wb-journal entry found */
case 1:
BUG(); // TODO - handle wb-journal match
/* read BIO submitted (page in cache) */
case 0:
break;
/* no page available in cache */
case -ENOBUFS:
case -ENODATA:
default:
desc.fid = vnode->fid;
desc.offset = page->index << PAGE_CACHE_SHIFT;
desc.size = min((size_t)(inode->i_size - desc.offset),(size_t)PAGE_SIZE);
desc.buffer = kmap(page);
clear_page(desc.buffer);
/* read the contents of the file from the server into the page */
ret = afs_vnode_fetch_data(vnode,&desc);
kunmap(page);
if (ret<0) {
if (ret==-ENOENT) {
_debug("got NOENT from server - marking file deleted and stale");
vnode->flags |= AFS_VNODE_DELETED;
ret = -ESTALE;
}
#ifdef AFS_CACHING_SUPPORT
cachefs_uncache_page(vnode->cache,page);
#endif
goto error;
}
SetPageUptodate(page);
#ifdef AFS_CACHING_SUPPORT
if (cachefs_write_page(vnode->cache,
page,
afs_file_readpage_write_complete,
NULL,
GFP_KERNEL) != 0
) {
cachefs_uncache_page(vnode->cache,page);
unlock_page(page);
}
#else
unlock_page(page);
#endif
}
_leave(" = 0"); _leave(" = 0");
return 0; return 0;
...@@ -122,3 +211,83 @@ static int afs_file_readpage(struct file *file, struct page *page) ...@@ -122,3 +211,83 @@ static int afs_file_readpage(struct file *file, struct page *page)
return ret; return ret;
} /* end afs_file_readpage() */ } /* end afs_file_readpage() */
/*****************************************************************************/
/*
* get a page cookie for the specified page
*/
#ifdef AFS_CACHING_SUPPORT
int afs_cache_get_page_cookie(struct page *page, struct cachefs_page **_page_cookie)
{
int ret;
_enter("");
ret = cachefs_page_get_private(page,_page_cookie,GFP_NOIO);
_leave(" = %d",ret);
return ret;
} /* end afs_cache_get_page_cookie() */
#endif
/*****************************************************************************/
/*
* invalidate part or all of a page
*/
static int afs_file_invalidatepage(struct page *page, unsigned long offset)
{
int ret = 1;
_enter("{%lu},%lu",page->index,offset);
BUG_ON(!PageLocked(page));
if (PagePrivate(page)) {
#ifdef AFS_CACHING_SUPPORT
struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
cachefs_uncache_page(vnode->cache,page);
#endif
/*
* We release buffers only if the entire page is being invalidated.
* The get_block cached value has been unconditionally invalidated,
* so real IO is not possible anymore.
*/
if (offset == 0) {
BUG_ON(!PageLocked(page));
ret = 0;
if (!PageWriteback(page))
ret = page->mapping->a_ops->releasepage(page, 0);
}
}
_leave(" = %d",ret);
return ret;
} /* end afs_file_invalidatepage() */
/*****************************************************************************/
/*
* release a page and cleanup its private data
*/
static int afs_file_releasepage(struct page *page, int gfp_flags)
{
struct cachefs_page *pageio;
_enter("{%lu},%x",page->index,gfp_flags);
if (PagePrivate(page)) {
#ifdef AFS_CACHING_SUPPORT
struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
cachefs_uncache_page(vnode->cache,page);
#endif
pageio = (struct cachefs_page *) page->private;
page->private = 0;
ClearPagePrivate(page);
if (pageio)
kfree(pageio);
}
_leave(" = 0");
return 0;
} /* end afs_file_releasepage() */
...@@ -69,17 +69,16 @@ static int afs_inode_map_status(afs_vnode_t *vnode) ...@@ -69,17 +69,16 @@ static int afs_inode_map_status(afs_vnode_t *vnode)
inode->i_uid = vnode->status.owner; inode->i_uid = vnode->status.owner;
inode->i_gid = 0; inode->i_gid = 0;
inode->i_size = vnode->status.size; inode->i_size = vnode->status.size;
inode->i_atime.tv_sec = inode->i_mtime.tv_sec = inode->i_ctime.tv_sec = vnode->status.mtime_server; inode->i_ctime.tv_sec = vnode->status.mtime_server;
inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = 0;
inode->i_mtime.tv_nsec = inode->i_atime = inode->i_mtime = inode->i_ctime;
inode->i_ctime.tv_nsec = 0;
inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0; inode->i_blocks = 0;
inode->i_version = vnode->fid.unique; inode->i_version = vnode->fid.unique;
inode->i_mapping->a_ops = &afs_fs_aops; inode->i_mapping->a_ops = &afs_fs_aops;
/* check to see whether a symbolic link is really a mountpoint */ /* check to see whether a symbolic link is really a mountpoint */
if (vnode->status.type==AFS_FTYPE_SYMLINK) { if (vnode->status.type == AFS_FTYPE_SYMLINK) {
afs_mntpt_check_symlink(vnode); afs_mntpt_check_symlink(vnode);
if (vnode->flags & AFS_VNODE_MOUNTPOINT) { if (vnode->flags & AFS_VNODE_MOUNTPOINT) {
...@@ -105,7 +104,7 @@ int afs_inode_fetch_status(struct inode *inode) ...@@ -105,7 +104,7 @@ int afs_inode_fetch_status(struct inode *inode)
ret = afs_vnode_fetch_status(vnode); ret = afs_vnode_fetch_status(vnode);
if (ret==0) if (ret == 0)
ret = afs_inode_map_status(vnode); ret = afs_inode_map_status(vnode);
return ret; return ret;
...@@ -120,8 +119,8 @@ static int afs_iget5_test(struct inode *inode, void *opaque) ...@@ -120,8 +119,8 @@ static int afs_iget5_test(struct inode *inode, void *opaque)
{ {
struct afs_iget_data *data = opaque; struct afs_iget_data *data = opaque;
/* only match inodes with the same version number */ return inode->i_ino == data->fid.vnode &&
return inode->i_ino==data->fid.vnode && inode->i_version==data->fid.unique; inode->i_version == data->fid.unique;
} /* end afs_iget5_test() */ } /* end afs_iget5_test() */
/*****************************************************************************/ /*****************************************************************************/
...@@ -145,20 +144,22 @@ static int afs_iget5_set(struct inode *inode, void *opaque) ...@@ -145,20 +144,22 @@ static int afs_iget5_set(struct inode *inode, void *opaque)
/* /*
* inode retrieval * inode retrieval
*/ */
inline int afs_iget(struct super_block *sb, afs_fid_t *fid, struct inode **_inode) inline int afs_iget(struct super_block *sb, afs_fid_t *fid,
struct inode **_inode)
{ {
struct afs_iget_data data = { .fid = *fid }; struct afs_iget_data data = { fid: *fid };
struct afs_super_info *as; struct afs_super_info *as;
struct afs_vnode *vnode;
struct inode *inode; struct inode *inode;
afs_vnode_t *vnode;
int ret; int ret;
_enter(",{%u,%u,%u},,",fid->vid,fid->vnode,fid->unique); _enter(",{%u,%u,%u},,", fid->vid, fid->vnode, fid->unique);
as = sb->s_fs_info; as = sb->s_fs_info;
data.volume = as->volume; data.volume = as->volume;
inode = iget5_locked(sb,fid->vnode,afs_iget5_test,afs_iget5_set,&data); inode = iget5_locked(sb, fid->vnode, afs_iget5_test, afs_iget5_set,
&data);
if (!inode) { if (!inode) {
_leave(" = -ENOMEM"); _leave(" = -ENOMEM");
return -ENOMEM; return -ENOMEM;
...@@ -173,10 +174,19 @@ inline int afs_iget(struct super_block *sb, afs_fid_t *fid, struct inode **_inod ...@@ -173,10 +174,19 @@ inline int afs_iget(struct super_block *sb, afs_fid_t *fid, struct inode **_inod
*_inode = inode; *_inode = inode;
else else
iput(inode); iput(inode);
_leave(" = %d",ret); _leave(" = %d", ret);
return ret; return ret;
} }
#ifdef AFS_CACHING_SUPPORT
/* set up caching before reading the status, as fetch-status reads the
* first page of symlinks to see if they're really mntpts */
cachefs_acquire_cookie(vnode->volume->cache,
NULL,
vnode,
&vnode->cache);
#endif
/* okay... it's a new inode */ /* okay... it's a new inode */
vnode->flags |= AFS_VNODE_CHANGED; vnode->flags |= AFS_VNODE_CHANGED;
ret = afs_inode_fetch_status(inode); ret = afs_inode_fetch_status(inode);
...@@ -187,11 +197,11 @@ inline int afs_iget(struct super_block *sb, afs_fid_t *fid, struct inode **_inod ...@@ -187,11 +197,11 @@ inline int afs_iget(struct super_block *sb, afs_fid_t *fid, struct inode **_inod
unlock_new_inode(inode); unlock_new_inode(inode);
*_inode = inode; *_inode = inode;
_leave(" = 0 [CB { v=%u x=%lu t=%u nix=%u }]", _leave(" = 0 [CB { v=%u x=%lu t=%u } c=%p]",
vnode->cb_version, vnode->cb_version,
vnode->cb_timeout.timo_jif, vnode->cb_timeout.timo_jif,
vnode->cb_type, vnode->cb_type,
vnode->nix vnode->cache
); );
return 0; return 0;
...@@ -201,7 +211,7 @@ inline int afs_iget(struct super_block *sb, afs_fid_t *fid, struct inode **_inod ...@@ -201,7 +211,7 @@ inline int afs_iget(struct super_block *sb, afs_fid_t *fid, struct inode **_inod
unlock_new_inode(inode); unlock_new_inode(inode);
iput(inode); iput(inode);
_leave(" = %d [bad]",ret); _leave(" = %d [bad]", ret);
return ret; return ret;
} /* end afs_iget() */ } /* end afs_iget() */
...@@ -209,7 +219,8 @@ inline int afs_iget(struct super_block *sb, afs_fid_t *fid, struct inode **_inod ...@@ -209,7 +219,8 @@ inline int afs_iget(struct super_block *sb, afs_fid_t *fid, struct inode **_inod
/* /*
* read the attributes of an inode * read the attributes of an inode
*/ */
int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat)
{ {
struct inode *inode; struct inode *inode;
afs_vnode_t *vnode; afs_vnode_t *vnode;
...@@ -217,23 +228,25 @@ int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat ...@@ -217,23 +228,25 @@ int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat
inode = dentry->d_inode; inode = dentry->d_inode;
_enter("{ ino=%lu v=%lu }",inode->i_ino,inode->i_version); _enter("{ ino=%lu v=%lu }", inode->i_ino, inode->i_version);
vnode = AFS_FS_I(inode); vnode = AFS_FS_I(inode);
ret = afs_inode_fetch_status(inode); ret = afs_inode_fetch_status(inode);
if (ret==-ENOENT) { if (ret == -ENOENT) {
_leave(" = %d [%d %p]",ret,atomic_read(&dentry->d_count),dentry->d_inode); _leave(" = %d [%d %p]",
ret, atomic_read(&dentry->d_count), dentry->d_inode);
return ret; return ret;
} }
else if (ret<0) { else if (ret < 0) {
make_bad_inode(inode); make_bad_inode(inode);
_leave(" = %d",ret); _leave(" = %d", ret);
return ret; return ret;
} }
/* transfer attributes from the inode structure to the stat structure */ /* transfer attributes from the inode structure to the stat
generic_fillattr(inode,stat); * structure */
generic_fillattr(inode, stat);
_leave(" = 0 CB { v=%u x=%u t=%u }", _leave(" = 0 CB { v=%u x=%u t=%u }",
vnode->cb_version, vnode->cb_version,
...@@ -261,9 +274,14 @@ void afs_clear_inode(struct inode *inode) ...@@ -261,9 +274,14 @@ void afs_clear_inode(struct inode *inode)
vnode->cb_type vnode->cb_type
); );
if (inode->i_ino!=vnode->fid.vnode) BUG(); BUG_ON(inode->i_ino != vnode->fid.vnode);
afs_vnode_give_up_callback(vnode); afs_vnode_give_up_callback(vnode);
#ifdef AFS_CACHING_SUPPORT
cachefs_relinquish_cookie(vnode->cache, 0);
vnode->cache = NULL;
#endif
_leave(""); _leave("");
} /* end afs_clear_inode() */ } /* end afs_clear_inode() */
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#define kproto(FMT, a...) printk("### "FMT"\n" , ## a) #define kproto(FMT, a...) printk("### "FMT"\n" , ## a)
#define knet(FMT, a...) printk(FMT"\n" , ## a) #define knet(FMT, a...) printk(FMT"\n" , ## a)
#if 0 #ifdef __KDEBUG
#define _enter(FMT, a...) kenter(FMT , ## a) #define _enter(FMT, a...) kenter(FMT , ## a)
#define _leave(FMT, a...) kleave(FMT , ## a) #define _leave(FMT, a...) kleave(FMT , ## a)
#define _debug(FMT, a...) kdebug(FMT , ## a) #define _debug(FMT, a...) kdebug(FMT , ## a)
...@@ -56,6 +56,9 @@ static inline void afs_discard_my_signals(void) ...@@ -56,6 +56,9 @@ static inline void afs_discard_my_signals(void)
*/ */
extern struct rw_semaphore afs_proc_cells_sem; extern struct rw_semaphore afs_proc_cells_sem;
extern struct list_head afs_proc_cells; extern struct list_head afs_proc_cells;
#ifdef AFS_CACHING_SUPPORT
extern struct cachefs_index_def afs_cache_cell_index_def;
#endif
/* /*
* dir.c * dir.c
...@@ -70,6 +73,10 @@ extern struct address_space_operations afs_fs_aops; ...@@ -70,6 +73,10 @@ extern struct address_space_operations afs_fs_aops;
extern struct inode_operations afs_file_inode_operations; extern struct inode_operations afs_file_inode_operations;
extern struct file_operations afs_file_file_operations; extern struct file_operations afs_file_file_operations;
#ifdef AFS_CACHING_SUPPORT
extern int afs_cache_get_page_cookie(struct page *page, struct cachefs_page **_page_cookie);
#endif
/* /*
* inode.c * inode.c
*/ */
...@@ -77,11 +84,23 @@ extern int afs_iget(struct super_block *sb, afs_fid_t *fid, struct inode **_inod ...@@ -77,11 +84,23 @@ extern int afs_iget(struct super_block *sb, afs_fid_t *fid, struct inode **_inod
extern int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); extern int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
extern void afs_clear_inode(struct inode *inode); extern void afs_clear_inode(struct inode *inode);
/*
* main.c
*/
#ifdef AFS_CACHING_SUPPORT
extern struct cachefs_netfs afs_cache_netfs;
#endif
/* /*
* mntpt.c * mntpt.c
*/ */
extern struct inode_operations afs_mntpt_inode_operations; extern struct inode_operations afs_mntpt_inode_operations;
extern struct file_operations afs_mntpt_file_operations; extern struct file_operations afs_mntpt_file_operations;
#ifdef AFS_AUTOMOUNT_SUPPORT
extern struct afs_timer afs_mntpt_expiry_timer;
extern struct afs_timer_ops afs_mntpt_expiry_timer_ops;
extern unsigned long afs_mntpt_expiry_timeout;
#endif
extern int afs_mntpt_check_symlink(afs_vnode_t *vnode); extern int afs_mntpt_check_symlink(afs_vnode_t *vnode);
......
...@@ -153,8 +153,7 @@ static int kafsasyncd(void *arg) ...@@ -153,8 +153,7 @@ static int kafsasyncd(void *arg)
spin_lock(&kafsasyncd_async_lock); spin_lock(&kafsasyncd_async_lock);
/* fold the busy and attention queues together */ /* fold the busy and attention queues together */
list_splice(&kafsasyncd_async_busyq,&kafsasyncd_async_attnq); list_splice_init(&kafsasyncd_async_busyq,&kafsasyncd_async_attnq);
list_del_init(&kafsasyncd_async_busyq);
/* dequeue kafsasyncd from all their wait queues */ /* dequeue kafsasyncd from all their wait queues */
list_for_each(_p,&kafsasyncd_async_attnq) { list_for_each(_p,&kafsasyncd_async_attnq) {
...@@ -197,6 +196,7 @@ void afs_kafsasyncd_begin_op(afs_async_op_t *op) ...@@ -197,6 +196,7 @@ void afs_kafsasyncd_begin_op(afs_async_op_t *op)
spin_lock(&kafsasyncd_async_lock); spin_lock(&kafsasyncd_async_lock);
init_waitqueue_entry(&op->waiter,kafsasyncd_task); init_waitqueue_entry(&op->waiter,kafsasyncd_task);
add_wait_queue(&op->call->waitq,&op->waiter);
list_del(&op->link); list_del(&op->link);
list_add_tail(&op->link,&kafsasyncd_async_busyq); list_add_tail(&op->link,&kafsasyncd_async_busyq);
...@@ -238,7 +238,10 @@ void afs_kafsasyncd_terminate_op(afs_async_op_t *op) ...@@ -238,7 +238,10 @@ void afs_kafsasyncd_terminate_op(afs_async_op_t *op)
spin_lock(&kafsasyncd_async_lock); spin_lock(&kafsasyncd_async_lock);
list_del_init(&op->link); if (!list_empty(&op->link)) {
list_del_init(&op->link);
remove_wait_queue(&op->call->waitq,&op->waiter);
}
spin_unlock(&kafsasyncd_async_lock); spin_unlock(&kafsasyncd_async_lock);
......
...@@ -82,7 +82,7 @@ static int kafstimod(void *arg) ...@@ -82,7 +82,7 @@ static int kafstimod(void *arg)
for (;;) { for (;;) {
unsigned long jif; unsigned long jif;
unsigned long timeout; signed long timeout;
/* deal with the server being asked to die */ /* deal with the server being asked to die */
if (kafstimod_die) { if (kafstimod_die) {
...@@ -98,18 +98,18 @@ static int kafstimod(void *arg) ...@@ -98,18 +98,18 @@ static int kafstimod(void *arg)
spin_lock(&kafstimod_lock); spin_lock(&kafstimod_lock);
if (list_empty(&kafstimod_list)) { if (list_empty(&kafstimod_list)) {
timeout = MAX_SCHEDULE_TIMEOUT; timeout = MAX_SCHEDULE_TIMEOUT;
} else { }
unsigned long tmo; else {
timer = list_entry(kafstimod_list.next,afs_timer_t,link);
timer = list_entry(kafstimod_list.next, timeout = timer->timo_jif;
afs_timer_t, link);
tmo = timer->timo_jif;
jif = jiffies; jif = jiffies;
if (time_before_eq(tmo,jif)) if (time_before_eq((unsigned long)timeout,jif))
goto immediate; goto immediate;
timeout = (long)tmo - (long)jiffies; else {
timeout = (long)timeout - (long)jiffies;
}
} }
spin_unlock(&kafstimod_lock); spin_unlock(&kafstimod_lock);
...@@ -170,7 +170,7 @@ void afs_kafstimod_add_timer(afs_timer_t *timer, unsigned long timeout) ...@@ -170,7 +170,7 @@ void afs_kafstimod_add_timer(afs_timer_t *timer, unsigned long timeout)
wake_up(&kafstimod_sleepq); wake_up(&kafstimod_sleepq);
_leave(""); _leave("");
} /* end afs_kafstimod_queue_vlocation() */ } /* end afs_kafstimod_add_timer() */
/*****************************************************************************/ /*****************************************************************************/
/* /*
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <rxrpc/transport.h> #include <rxrpc/transport.h>
#include <rxrpc/call.h> #include <rxrpc/call.h>
#include <rxrpc/peer.h> #include <rxrpc/peer.h>
#include "cache.h"
#include "cell.h" #include "cell.h"
#include "server.h" #include "server.h"
#include "fsclient.h" #include "fsclient.h"
...@@ -47,6 +48,18 @@ static struct rxrpc_peer_ops afs_peer_ops = { ...@@ -47,6 +48,18 @@ static struct rxrpc_peer_ops afs_peer_ops = {
struct list_head afs_cb_hash_tbl[AFS_CB_HASH_COUNT]; struct list_head afs_cb_hash_tbl[AFS_CB_HASH_COUNT];
spinlock_t afs_cb_hash_lock = SPIN_LOCK_UNLOCKED; spinlock_t afs_cb_hash_lock = SPIN_LOCK_UNLOCKED;
#ifdef AFS_CACHING_SUPPORT
static struct cachefs_netfs_operations afs_cache_ops = {
.get_page_cookie = afs_cache_get_page_cookie,
};
struct cachefs_netfs afs_cache_netfs = {
.name = "afs",
.version = 0,
.ops = &afs_cache_ops,
};
#endif
/*****************************************************************************/ /*****************************************************************************/
/* /*
* initialise the AFS client FS module * initialise the AFS client FS module
...@@ -64,34 +77,41 @@ static int afs_init(void) ...@@ -64,34 +77,41 @@ static int afs_init(void)
/* register the /proc stuff */ /* register the /proc stuff */
ret = afs_proc_init(); ret = afs_proc_init();
if (ret<0) if (ret < 0)
return ret; return ret;
#ifdef AFS_CACHING_SUPPORT
/* we want to be able to cache */
ret = cachefs_register_netfs(&afs_cache_netfs,&afs_cache_cell_index_def);
if (ret < 0)
goto error;
#endif
/* initialise the cell DB */ /* initialise the cell DB */
ret = afs_cell_init(); ret = afs_cell_init();
if (ret<0) if (ret < 0)
goto error; goto error_cache;
/* start the timeout daemon */ /* start the timeout daemon */
ret = afs_kafstimod_start(); ret = afs_kafstimod_start();
if (ret<0) if (ret < 0)
goto error; goto error_cache;
/* start the async operation daemon */ /* start the async operation daemon */
ret = afs_kafsasyncd_start(); ret = afs_kafsasyncd_start();
if (ret<0) if (ret < 0)
goto error_kafstimod; goto error_kafstimod;
/* create the RxRPC transport */ /* create the RxRPC transport */
ret = rxrpc_create_transport(7001,&afs_transport); ret = rxrpc_create_transport(7001,&afs_transport);
if (ret<0) if (ret < 0)
goto error_kafsasyncd; goto error_kafsasyncd;
afs_transport->peer_ops = &afs_peer_ops; afs_transport->peer_ops = &afs_peer_ops;
/* register the filesystems */ /* register the filesystems */
ret = afs_fs_init(); ret = afs_fs_init();
if (ret<0) if (ret < 0)
goto error_transport; goto error_transport;
return ret; return ret;
...@@ -102,7 +122,11 @@ static int afs_init(void) ...@@ -102,7 +122,11 @@ static int afs_init(void)
afs_kafsasyncd_stop(); afs_kafsasyncd_stop();
error_kafstimod: error_kafstimod:
afs_kafstimod_stop(); afs_kafstimod_stop();
error_cache:
#ifdef AFS_CACHING_SUPPORT
cachefs_unregister_netfs(&afs_cache_netfs);
error: error:
#endif
afs_cell_purge(); afs_cell_purge();
afs_proc_cleanup(); afs_proc_cleanup();
printk(KERN_ERR "kAFS: failed to register: %d\n",ret); printk(KERN_ERR "kAFS: failed to register: %d\n",ret);
...@@ -122,6 +146,9 @@ static void __exit afs_exit(void) ...@@ -122,6 +146,9 @@ static void __exit afs_exit(void)
afs_kafstimod_stop(); afs_kafstimod_stop();
afs_kafsasyncd_stop(); afs_kafsasyncd_stop();
afs_cell_purge(); afs_cell_purge();
#ifdef AFS_CACHING_SUPPORT
cachefs_unregister_netfs(&afs_cache_netfs);
#endif
afs_proc_cleanup(); afs_proc_cleanup();
} /* end afs_exit() */ } /* end afs_exit() */
...@@ -142,7 +169,7 @@ static int afs_adding_peer(struct rxrpc_peer *peer) ...@@ -142,7 +169,7 @@ static int afs_adding_peer(struct rxrpc_peer *peer)
/* determine which server the peer resides in (if any) */ /* determine which server the peer resides in (if any) */
ret = afs_server_find_by_peer(peer,&server); ret = afs_server_find_by_peer(peer,&server);
if (ret<0) if (ret < 0)
return ret; /* none that we recognise, so abort */ return ret; /* none that we recognise, so abort */
_debug("Server %p{u=%d}\n",server,atomic_read(&server->usage)); _debug("Server %p{u=%d}\n",server,atomic_read(&server->usage));
...@@ -191,3 +218,48 @@ static void afs_discarding_peer(struct rxrpc_peer *peer) ...@@ -191,3 +218,48 @@ static void afs_discarding_peer(struct rxrpc_peer *peer)
_leave(""); _leave("");
} /* end afs_discarding_peer() */ } /* end afs_discarding_peer() */
/*****************************************************************************/
/*
* clear the dead space between task_struct and kernel stack
* - called by supplying -finstrument-functions to gcc
*/
#if 0
void __cyg_profile_func_enter (void *this_fn, void *call_site)
__attribute__((no_instrument_function));
void __cyg_profile_func_enter (void *this_fn, void *call_site)
{
asm volatile(" movl %%esp,%%edi \n"
" andl %0,%%edi \n"
" addl %1,%%edi \n"
" movl %%esp,%%ecx \n"
" subl %%edi,%%ecx \n"
" shrl $2,%%ecx \n"
" movl $0xedededed,%%eax \n"
" rep stosl \n"
:
: "i"(~(THREAD_SIZE-1)), "i"(sizeof(struct thread_info))
: "eax", "ecx", "edi", "memory", "cc"
);
}
void __cyg_profile_func_exit(void *this_fn, void *call_site)
__attribute__((no_instrument_function));
void __cyg_profile_func_exit(void *this_fn, void *call_site)
{
asm volatile(" movl %%esp,%%edi \n"
" andl %0,%%edi \n"
" addl %1,%%edi \n"
" movl %%esp,%%ecx \n"
" subl %%edi,%%ecx \n"
" shrl $2,%%ecx \n"
" movl $0xdadadada,%%eax \n"
" rep stosl \n"
:
: "i"(~(THREAD_SIZE-1)), "i"(sizeof(struct thread_info))
: "eax", "ecx", "edi", "memory", "cc"
);
}
#endif
...@@ -16,24 +16,52 @@ ...@@ -16,24 +16,52 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/namespace.h>
#include "super.h"
#include "cell.h"
#include "volume.h" #include "volume.h"
#include "vnode.h" #include "vnode.h"
#include "internal.h" #include "internal.h"
static struct dentry *afs_mntpt_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *); static struct dentry *afs_mntpt_lookup(struct inode *dir,
struct dentry *dentry,
struct nameidata *nd);
static int afs_mntpt_open(struct inode *inode, struct file *file); static int afs_mntpt_open(struct inode *inode, struct file *file);
#ifdef AFS_AUTOMOUNT_SUPPORT
static int afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd);
#endif
struct file_operations afs_mntpt_file_operations = { struct file_operations afs_mntpt_file_operations = {
.open = afs_mntpt_open, .open = afs_mntpt_open,
}; };
struct inode_operations afs_mntpt_inode_operations = { struct inode_operations afs_mntpt_inode_operations = {
.lookup = afs_mntpt_lookup, .lookup = afs_mntpt_lookup,
#ifdef AFS_AUTOMOUNT_SUPPORT
.follow_link = afs_mntpt_follow_link,
#endif
.readlink = page_readlink, .readlink = page_readlink,
.getattr = afs_inode_getattr, .getattr = afs_inode_getattr,
}; };
#ifdef AFS_AUTOMOUNT_SUPPORT
static LIST_HEAD(afs_vfsmounts);
static void afs_mntpt_expiry_timed_out(struct afs_timer *timer);
struct afs_timer_ops afs_mntpt_expiry_timer_ops = {
.timed_out = afs_mntpt_expiry_timed_out,
};
struct afs_timer afs_mntpt_expiry_timer;
unsigned long afs_mntpt_expiry_timeout = 20;
#endif
/*****************************************************************************/ /*****************************************************************************/
/* /*
* check a symbolic link to see whether it actually encodes a mountpoint * check a symbolic link to see whether it actually encodes a mountpoint
...@@ -93,8 +121,17 @@ int afs_mntpt_check_symlink(afs_vnode_t *vnode) ...@@ -93,8 +121,17 @@ int afs_mntpt_check_symlink(afs_vnode_t *vnode)
/* /*
* no valid lookup procedure on this sort of dir * no valid lookup procedure on this sort of dir
*/ */
static struct dentry *afs_mntpt_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) static struct dentry *afs_mntpt_lookup(struct inode *dir,
struct dentry *dentry,
struct nameidata *nd)
{ {
kenter("%p,%p{%p{%s},%s}",
dir,
dentry,
dentry->d_parent,
dentry->d_parent ? dentry->d_parent->d_name.name : (const unsigned char*)"",
dentry->d_name.name);
return ERR_PTR(-EREMOTE); return ERR_PTR(-EREMOTE);
} /* end afs_mntpt_lookup() */ } /* end afs_mntpt_lookup() */
...@@ -104,5 +141,146 @@ static struct dentry *afs_mntpt_lookup(struct inode *dir, struct dentry *dentry, ...@@ -104,5 +141,146 @@ static struct dentry *afs_mntpt_lookup(struct inode *dir, struct dentry *dentry,
*/ */
static int afs_mntpt_open(struct inode *inode, struct file *file) static int afs_mntpt_open(struct inode *inode, struct file *file)
{ {
kenter("%p,%p{%p{%s},%s}",
inode, file,
file->f_dentry->d_parent,
file->f_dentry->d_parent ? file->f_dentry->d_parent->d_name.name : (const unsigned char*)"",
file->f_dentry->d_name.name);
return -EREMOTE; return -EREMOTE;
} /* end afs_mntpt_open() */ } /* end afs_mntpt_open() */
#ifdef AFS_AUTOMOUNT_SUPPORT
/*****************************************************************************/
/*
* create a vfsmount to be automounted
*/
static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
{
struct afs_super_info *super;
struct vfsmount *mnt;
struct page *page = NULL;
size_t size;
char *buf, *devname = NULL, *options = NULL;
int ret;
kenter("{%s}", mntpt->d_name.name);
BUG_ON(!mntpt->d_inode);
ret = -EINVAL;
size = mntpt->d_inode->i_size;
if (size > PAGE_SIZE - 1)
goto error;
ret = -ENOMEM;
devname = (char *) get_zeroed_page(GFP_KERNEL);
if (!devname)
goto error;
options = (char *) get_zeroed_page(GFP_KERNEL);
if (!options)
goto error;
/* read the contents of the AFS special symlink */
page = read_cache_page(mntpt->d_inode->i_mapping,
0,
(filler_t*)mntpt->d_inode->i_mapping->a_ops->readpage,
NULL);
if (IS_ERR(page)) {
ret = PTR_ERR(page);
goto error;
}
ret = -EIO;
wait_on_page_locked(page);
if (!PageUptodate(page) || PageError(page))
goto error;
buf = kmap(page);
memcpy(devname, buf, size);
kunmap(page);
page_cache_release(page);
page = NULL;
/* work out what options we want */
super = AFS_FS_S(mntpt->d_sb);
memcpy(options, "cell=", 5);
strcpy(options + 5, super->volume->cell->name);
if (super->volume->type == AFSVL_RWVOL)
strcat(options,",rwpath");
/* try and do the mount */
kdebug("--- attempting mount %s -o %s ---", devname, options);
mnt = do_kern_mount("afs", 0, devname, options);
kdebug("--- mount result %p ---", mnt);
free_page((unsigned long)devname);
free_page((unsigned long)options);
kleave(" = %p",mnt);
return mnt;
error:
if (page)
page_cache_release(page);
if (devname)
free_page((unsigned long)devname);
if (options)
free_page((unsigned long)options);
kleave(" = %d",ret);
return ERR_PTR(ret);
} /* end afs_mntpt_do_automount() */
/*****************************************************************************/
/*
* follow a link from a mountpoint directory, thus causing it to be mounted
*/
static int afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct nameidata newnd;
struct vfsmount *newmnt;
int err;
kenter("%p{%s},{%s:%p{%s}}",
dentry,
dentry->d_name.name,
nd->mnt->mnt_devname,
dentry,
nd->dentry->d_name.name);
newmnt = afs_mntpt_do_automount(dentry);
if (IS_ERR(newmnt))
return PTR_ERR(newmnt);
struct_cpy(&newnd,nd);
newnd.dentry = dentry;
err = do_add_mount(newmnt, &newnd, 0, &afs_vfsmounts);
if (!err) {
path_release(nd);
mntget(newmnt);
nd->mnt = newmnt;
dget(newmnt->mnt_root);
nd->dentry = newmnt->mnt_root;
}
kleave(" = %d", err);
return err;
} /* end afs_mntpt_follow_link() */
/*****************************************************************************/
/*
* handle mountpoint expiry timer going off
*/
static void afs_mntpt_expiry_timed_out(struct afs_timer *timer)
{
kenter("");
mark_mounts_for_expiry(&afs_vfsmounts);
afs_kafstimod_add_timer(&afs_mntpt_expiry_timer,
afs_mntpt_expiry_timeout * HZ);
kleave("");
} /* end afs_mntpt_expiry_timed_out() */
#endif
...@@ -17,7 +17,7 @@ struct afs_mountdata { ...@@ -17,7 +17,7 @@ struct afs_mountdata {
const char *cell; /* name of cell containing volume */ const char *cell; /* name of cell containing volume */
const char *cache; /* name of cache block device */ const char *cache; /* name of cache block device */
size_t nservers; /* number of server addresses listed */ size_t nservers; /* number of server addresses listed */
u_int32_t servers[10]; /* IP addresses of servers in this cell */ uint32_t servers[10]; /* IP addresses of servers in this cell */
}; };
#endif /* _LINUX_AFS_MOUNT_H */ #endif /* _LINUX_AFS_MOUNT_H */
...@@ -148,6 +148,9 @@ void afs_put_server(afs_server_t *server) ...@@ -148,6 +148,9 @@ void afs_put_server(afs_server_t *server)
{ {
afs_cell_t *cell; afs_cell_t *cell;
if (!server)
return;
_enter("%p",server); _enter("%p",server);
cell = server->cell; cell = server->cell;
......
This diff is collapsed.
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
*/ */
struct afs_super_info struct afs_super_info
{ {
afs_volume_t *volume; /* volume record */ struct afs_volume *volume; /* volume record */
char rwparent; /* T if parent is R/W AFS volume */ char rwparent; /* T if parent is R/W AFS volume */
}; };
......
...@@ -33,26 +33,13 @@ typedef struct afs_volsync afs_volsync_t; ...@@ -33,26 +33,13 @@ typedef struct afs_volsync afs_volsync_t;
typedef struct afs_volume afs_volume_t; typedef struct afs_volume afs_volume_t;
typedef struct afs_volume_info afs_volume_info_t; typedef struct afs_volume_info afs_volume_info_t;
typedef struct afsc_cache afsc_cache_t;
typedef struct afsc_cache_cell afsc_cache_cell_t;
typedef struct afsc_cache_vldb afsc_cache_vldb_t;
typedef struct afsc_cell_record afsc_cell_record_t;
typedef struct afsc_inode afsc_inode_t;
typedef struct afsc_io afsc_io_t;
typedef struct afsc_io_subop afsc_io_subop_t;
typedef struct afsc_io_queue afsc_io_queue_t;
typedef struct afsc_super_block afsc_super_block_t;
typedef struct afsc_vldb_record afsc_vldb_record_t;
typedef struct afsc_vnode_catalogue afsc_vnode_catalogue_t;
typedef struct afsc_vnode_meta afsc_vnode_meta_t;
typedef struct afsvl_dbentry afsvl_dbentry_t; typedef struct afsvl_dbentry afsvl_dbentry_t;
typedef enum { typedef enum {
AFSVL_RWVOL, /* read/write volume */ AFSVL_RWVOL, /* read/write volume */
AFSVL_ROVOL, /* read-only volume */ AFSVL_ROVOL, /* read-only volume */
AFSVL_BACKVOL, /* backup volume */ AFSVL_BACKVOL, /* backup volume */
} afs_voltype_t; } __attribute__((packed)) afs_voltype_t;
extern const char *afs_voltypes[]; extern const char *afs_voltypes[];
......
...@@ -176,8 +176,8 @@ int afs_rxvl_probe(afs_server_t *server, int alloc_flags) ...@@ -176,8 +176,8 @@ int afs_rxvl_probe(afs_server_t *server, int alloc_flags)
/* /*
* look up a volume location database entry by name * look up a volume location database entry by name
*/ */
int afs_rxvl_get_entry_by_name(afs_server_t *server, const char *volname, int afs_rxvl_get_entry_by_name(afs_server_t *server, const char *volname, unsigned volnamesz,
afsc_vldb_record_t *entry) struct afs_cache_vlocation *entry)
{ {
DECLARE_WAITQUEUE(myself,current); DECLARE_WAITQUEUE(myself,current);
...@@ -189,29 +189,29 @@ int afs_rxvl_get_entry_by_name(afs_server_t *server, const char *volname, ...@@ -189,29 +189,29 @@ int afs_rxvl_get_entry_by_name(afs_server_t *server, const char *volname,
int ret, loop; int ret, loop;
u32 *bp, param[2], zero; u32 *bp, param[2], zero;
_enter(",%s,",volname); _enter(",%*.*s,%u,", volnamesz, volnamesz, volname, volnamesz);
memset(entry,0,sizeof(*entry)); memset(entry, 0, sizeof(*entry));
/* get hold of the vlserver connection */ /* get hold of the vlserver connection */
ret = afs_server_get_vlconn(server,&conn); ret = afs_server_get_vlconn(server, &conn);
if (ret<0) if (ret<0)
goto out; goto out;
/* create a call through that connection */ /* create a call through that connection */
ret = rxrpc_create_call(conn,NULL,NULL,afs_rxvl_aemap,&call); ret = rxrpc_create_call(conn, NULL, NULL, afs_rxvl_aemap, &call);
if (ret<0) { if (ret < 0) {
printk("kAFS: Unable to create call: %d\n",ret); printk("kAFS: Unable to create call: %d\n", ret);
goto out_put_conn; goto out_put_conn;
} }
call->app_opcode = VLGETENTRYBYNAME; call->app_opcode = VLGETENTRYBYNAME;
/* we want to get event notifications from the call */ /* we want to get event notifications from the call */
add_wait_queue(&call->waitq,&myself); add_wait_queue(&call->waitq, &myself);
/* marshall the parameters */ /* marshall the parameters */
piov[1].iov_len = strlen(volname); piov[1].iov_len = volnamesz;
piov[1].iov_base = (char*)volname; piov[1].iov_base = (char*) volname;
zero = 0; zero = 0;
piov[2].iov_len = (4 - (piov[1].iov_len & 3)) & 3; piov[2].iov_len = (4 - (piov[1].iov_len & 3)) & 3;
...@@ -224,16 +224,16 @@ int afs_rxvl_get_entry_by_name(afs_server_t *server, const char *volname, ...@@ -224,16 +224,16 @@ int afs_rxvl_get_entry_by_name(afs_server_t *server, const char *volname,
piov[0].iov_base = param; piov[0].iov_base = param;
/* send the parameters to the server */ /* send the parameters to the server */
ret = rxrpc_call_write_data(call,3,piov,RXRPC_LAST_PACKET,GFP_NOFS,0,&sent); ret = rxrpc_call_write_data(call, 3, piov, RXRPC_LAST_PACKET, GFP_NOFS, 0, &sent);
if (ret<0) if (ret<0)
goto abort; goto abort;
/* wait for the reply to completely arrive */ /* wait for the reply to completely arrive */
bp = rxrpc_call_alloc_scratch(call,384); bp = rxrpc_call_alloc_scratch(call, 384);
ret = rxrpc_call_read_data(call,bp,384,RXRPC_CALL_READ_BLOCK|RXRPC_CALL_READ_ALL); ret = rxrpc_call_read_data(call, bp, 384, RXRPC_CALL_READ_BLOCK|RXRPC_CALL_READ_ALL);
if (ret<0) { if (ret < 0) {
if (ret==-ECONNABORTED) { if (ret == -ECONNABORTED) {
ret = call->app_errno; ret = call->app_errno;
goto out_unwait; goto out_unwait;
} }
...@@ -255,9 +255,9 @@ int afs_rxvl_get_entry_by_name(afs_server_t *server, const char *volname, ...@@ -255,9 +255,9 @@ int afs_rxvl_get_entry_by_name(afs_server_t *server, const char *volname,
for (loop=0; loop<8; loop++) { for (loop=0; loop<8; loop++) {
tmp = ntohl(*bp++); tmp = ntohl(*bp++);
if (tmp & AFS_VLSF_RWVOL ) entry->srvtmask[loop] |= AFSC_VOL_STM_RW; if (tmp & AFS_VLSF_RWVOL ) entry->srvtmask[loop] |= AFS_VOL_VTM_RW;
if (tmp & AFS_VLSF_ROVOL ) entry->srvtmask[loop] |= AFSC_VOL_STM_RO; if (tmp & AFS_VLSF_ROVOL ) entry->srvtmask[loop] |= AFS_VOL_VTM_RO;
if (tmp & AFS_VLSF_BACKVOL) entry->srvtmask[loop] |= AFSC_VOL_STM_BAK; if (tmp & AFS_VLSF_BACKVOL) entry->srvtmask[loop] |= AFS_VOL_VTM_BAK;
} }
entry->vid[0] = ntohl(*bp++); entry->vid[0] = ntohl(*bp++);
...@@ -267,26 +267,26 @@ int afs_rxvl_get_entry_by_name(afs_server_t *server, const char *volname, ...@@ -267,26 +267,26 @@ int afs_rxvl_get_entry_by_name(afs_server_t *server, const char *volname,
bp++; /* clone ID */ bp++; /* clone ID */
tmp = ntohl(*bp++); /* flags */ tmp = ntohl(*bp++); /* flags */
if (tmp & AFS_VLF_RWEXISTS ) entry->vidmask |= AFSC_VOL_STM_RW; if (tmp & AFS_VLF_RWEXISTS ) entry->vidmask |= AFS_VOL_VTM_RW;
if (tmp & AFS_VLF_ROEXISTS ) entry->vidmask |= AFSC_VOL_STM_RO; if (tmp & AFS_VLF_ROEXISTS ) entry->vidmask |= AFS_VOL_VTM_RO;
if (tmp & AFS_VLF_BACKEXISTS) entry->vidmask |= AFSC_VOL_STM_BAK; if (tmp & AFS_VLF_BACKEXISTS) entry->vidmask |= AFS_VOL_VTM_BAK;
ret = -ENOMEDIUM; ret = -ENOMEDIUM;
if (!entry->vidmask) if (!entry->vidmask)
goto abort; goto abort;
/* success */ /* success */
entry->ctime = get_seconds(); entry->rtime = get_seconds();
ret = 0; ret = 0;
out_unwait: out_unwait:
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
remove_wait_queue(&call->waitq,&myself); remove_wait_queue(&call->waitq, &myself);
rxrpc_put_call(call); rxrpc_put_call(call);
out_put_conn: out_put_conn:
rxrpc_put_connection(conn); rxrpc_put_connection(conn);
out: out:
_leave(" = %d",ret); _leave(" = %d", ret);
return ret; return ret;
abort: abort:
...@@ -303,7 +303,7 @@ int afs_rxvl_get_entry_by_name(afs_server_t *server, const char *volname, ...@@ -303,7 +303,7 @@ int afs_rxvl_get_entry_by_name(afs_server_t *server, const char *volname,
int afs_rxvl_get_entry_by_id(afs_server_t *server, int afs_rxvl_get_entry_by_id(afs_server_t *server,
afs_volid_t volid, afs_volid_t volid,
afs_voltype_t voltype, afs_voltype_t voltype,
afsc_vldb_record_t *entry) struct afs_cache_vlocation *entry)
{ {
DECLARE_WAITQUEUE(myself,current); DECLARE_WAITQUEUE(myself,current);
...@@ -375,9 +375,9 @@ int afs_rxvl_get_entry_by_id(afs_server_t *server, ...@@ -375,9 +375,9 @@ int afs_rxvl_get_entry_by_id(afs_server_t *server,
for (loop=0; loop<8; loop++) { for (loop=0; loop<8; loop++) {
tmp = ntohl(*bp++); tmp = ntohl(*bp++);
if (tmp & AFS_VLSF_RWVOL ) entry->srvtmask[loop] |= AFSC_VOL_STM_RW; if (tmp & AFS_VLSF_RWVOL ) entry->srvtmask[loop] |= AFS_VOL_VTM_RW;
if (tmp & AFS_VLSF_ROVOL ) entry->srvtmask[loop] |= AFSC_VOL_STM_RO; if (tmp & AFS_VLSF_ROVOL ) entry->srvtmask[loop] |= AFS_VOL_VTM_RO;
if (tmp & AFS_VLSF_BACKVOL) entry->srvtmask[loop] |= AFSC_VOL_STM_BAK; if (tmp & AFS_VLSF_BACKVOL) entry->srvtmask[loop] |= AFS_VOL_VTM_BAK;
} }
entry->vid[0] = ntohl(*bp++); entry->vid[0] = ntohl(*bp++);
...@@ -387,9 +387,9 @@ int afs_rxvl_get_entry_by_id(afs_server_t *server, ...@@ -387,9 +387,9 @@ int afs_rxvl_get_entry_by_id(afs_server_t *server,
bp++; /* clone ID */ bp++; /* clone ID */
tmp = ntohl(*bp++); /* flags */ tmp = ntohl(*bp++); /* flags */
if (tmp & AFS_VLF_RWEXISTS ) entry->vidmask |= AFSC_VOL_STM_RW; if (tmp & AFS_VLF_RWEXISTS ) entry->vidmask |= AFS_VOL_VTM_RW;
if (tmp & AFS_VLF_ROEXISTS ) entry->vidmask |= AFSC_VOL_STM_RO; if (tmp & AFS_VLF_ROEXISTS ) entry->vidmask |= AFS_VOL_VTM_RO;
if (tmp & AFS_VLF_BACKEXISTS) entry->vidmask |= AFSC_VOL_STM_BAK; if (tmp & AFS_VLF_BACKEXISTS) entry->vidmask |= AFS_VOL_VTM_BAK;
ret = -ENOMEDIUM; ret = -ENOMEDIUM;
if (!entry->vidmask) if (!entry->vidmask)
...@@ -401,13 +401,13 @@ int afs_rxvl_get_entry_by_id(afs_server_t *server, ...@@ -401,13 +401,13 @@ int afs_rxvl_get_entry_by_id(afs_server_t *server,
entry->servers[1].s_addr = htonl(0xac101243); entry->servers[1].s_addr = htonl(0xac101243);
entry->servers[2].s_addr = htonl(0xac10125b /*0xac10125b*/); entry->servers[2].s_addr = htonl(0xac10125b /*0xac10125b*/);
entry->srvtmask[0] = AFSC_VOL_STM_RO; entry->srvtmask[0] = AFS_VOL_VTM_RO;
entry->srvtmask[1] = AFSC_VOL_STM_RO; entry->srvtmask[1] = AFS_VOL_VTM_RO;
entry->srvtmask[2] = AFSC_VOL_STM_RO | AFSC_VOL_STM_RW; entry->srvtmask[2] = AFS_VOL_VTM_RO | AFS_VOL_VTM_RW;
#endif #endif
/* success */ /* success */
entry->ctime = get_seconds(); entry->rtime = get_seconds();
ret = 0; ret = 0;
out_unwait: out_unwait:
...@@ -520,7 +520,7 @@ int afs_rxvl_get_entry_by_id_async(afs_async_op_t *op, ...@@ -520,7 +520,7 @@ int afs_rxvl_get_entry_by_id_async(afs_async_op_t *op,
* attend to the asynchronous get VLDB entry by ID * attend to the asynchronous get VLDB entry by ID
*/ */
int afs_rxvl_get_entry_by_id_async2(afs_async_op_t *op, int afs_rxvl_get_entry_by_id_async2(afs_async_op_t *op,
afsc_vldb_record_t *entry) struct afs_cache_vlocation *entry)
{ {
unsigned *bp, tmp; unsigned *bp, tmp;
int loop, ret; int loop, ret;
...@@ -550,9 +550,9 @@ int afs_rxvl_get_entry_by_id_async2(afs_async_op_t *op, ...@@ -550,9 +550,9 @@ int afs_rxvl_get_entry_by_id_async2(afs_async_op_t *op,
for (loop=0; loop<8; loop++) { for (loop=0; loop<8; loop++) {
tmp = ntohl(*bp++); tmp = ntohl(*bp++);
if (tmp & AFS_VLSF_RWVOL ) entry->srvtmask[loop] |= AFSC_VOL_STM_RW; if (tmp & AFS_VLSF_RWVOL ) entry->srvtmask[loop] |= AFS_VOL_VTM_RW;
if (tmp & AFS_VLSF_ROVOL ) entry->srvtmask[loop] |= AFSC_VOL_STM_RO; if (tmp & AFS_VLSF_ROVOL ) entry->srvtmask[loop] |= AFS_VOL_VTM_RO;
if (tmp & AFS_VLSF_BACKVOL) entry->srvtmask[loop] |= AFSC_VOL_STM_BAK; if (tmp & AFS_VLSF_BACKVOL) entry->srvtmask[loop] |= AFS_VOL_VTM_BAK;
} }
entry->vid[0] = ntohl(*bp++); entry->vid[0] = ntohl(*bp++);
...@@ -562,9 +562,9 @@ int afs_rxvl_get_entry_by_id_async2(afs_async_op_t *op, ...@@ -562,9 +562,9 @@ int afs_rxvl_get_entry_by_id_async2(afs_async_op_t *op,
bp++; /* clone ID */ bp++; /* clone ID */
tmp = ntohl(*bp++); /* flags */ tmp = ntohl(*bp++); /* flags */
if (tmp & AFS_VLF_RWEXISTS ) entry->vidmask |= AFSC_VOL_STM_RW; if (tmp & AFS_VLF_RWEXISTS ) entry->vidmask |= AFS_VOL_VTM_RW;
if (tmp & AFS_VLF_ROEXISTS ) entry->vidmask |= AFSC_VOL_STM_RO; if (tmp & AFS_VLF_ROEXISTS ) entry->vidmask |= AFS_VOL_VTM_RO;
if (tmp & AFS_VLF_BACKEXISTS) entry->vidmask |= AFSC_VOL_STM_BAK; if (tmp & AFS_VLF_BACKEXISTS) entry->vidmask |= AFS_VOL_VTM_BAK;
ret = -ENOMEDIUM; ret = -ENOMEDIUM;
if (!entry->vidmask) { if (!entry->vidmask) {
...@@ -578,13 +578,13 @@ int afs_rxvl_get_entry_by_id_async2(afs_async_op_t *op, ...@@ -578,13 +578,13 @@ int afs_rxvl_get_entry_by_id_async2(afs_async_op_t *op,
entry->servers[1].s_addr = htonl(0xac101243); entry->servers[1].s_addr = htonl(0xac101243);
entry->servers[2].s_addr = htonl(0xac10125b /*0xac10125b*/); entry->servers[2].s_addr = htonl(0xac10125b /*0xac10125b*/);
entry->srvtmask[0] = AFSC_VOL_STM_RO; entry->srvtmask[0] = AFS_VOL_VTM_RO;
entry->srvtmask[1] = AFSC_VOL_STM_RO; entry->srvtmask[1] = AFS_VOL_VTM_RO;
entry->srvtmask[2] = AFSC_VOL_STM_RO | AFSC_VOL_STM_RW; entry->srvtmask[2] = AFS_VOL_VTM_RO | AFS_VOL_VTM_RW;
#endif #endif
/* success */ /* success */
entry->ctime = get_seconds(); entry->rtime = get_seconds();
ret = 0; ret = 0;
goto done; goto done;
} }
...@@ -626,7 +626,8 @@ static void afs_rxvl_get_entry_by_id_attn(struct rxrpc_call *call) ...@@ -626,7 +626,8 @@ static void afs_rxvl_get_entry_by_id_attn(struct rxrpc_call *call)
case RXRPC_CSTATE_CLNT_GOT_REPLY: case RXRPC_CSTATE_CLNT_GOT_REPLY:
if (call->app_read_count==0) if (call->app_read_count==0)
break; break;
printk("kAFS: Reply bigger than expected {cst=%u asyn=%d mark=%Zu rdy=%Zu pr=%u%s}", printk("kAFS: Reply bigger than expected"
" {cst=%u asyn=%d mark=%Zu rdy=%Zu pr=%u%s}",
call->app_call_state, call->app_call_state,
call->app_async_read, call->app_async_read,
call->app_mark, call->app_mark,
......
...@@ -46,7 +46,7 @@ enum AFSVL_Errors { ...@@ -46,7 +46,7 @@ enum AFSVL_Errors {
}; };
/* maps to "struct vldbentry" in vvl-spec.pdf */ /* maps to "struct vldbentry" in vvl-spec.pdf */
struct afsvl_dbentry { struct afs_vldbentry {
char name[65]; /* name of volume (including NUL char) */ char name[65]; /* name of volume (including NUL char) */
afs_voltype_t type; /* volume type */ afs_voltype_t type; /* volume type */
unsigned num_servers; /* num servers that hold instances of this vol */ unsigned num_servers; /* num servers that hold instances of this vol */
...@@ -77,19 +77,20 @@ extern int afs_rxvl_probe(afs_server_t *server, int alloc_flags); ...@@ -77,19 +77,20 @@ extern int afs_rxvl_probe(afs_server_t *server, int alloc_flags);
/* look up a volume location database entry by name */ /* look up a volume location database entry by name */
extern int afs_rxvl_get_entry_by_name(afs_server_t *server, extern int afs_rxvl_get_entry_by_name(afs_server_t *server,
const char *volname, const char *volname,
afsc_vldb_record_t *entry); unsigned volnamesz,
struct afs_cache_vlocation *entry);
/* look up a volume location database entry by ID */ /* look up a volume location database entry by ID */
extern int afs_rxvl_get_entry_by_id(afs_server_t *server, extern int afs_rxvl_get_entry_by_id(afs_server_t *server,
afs_volid_t volid, afs_volid_t volid,
afs_voltype_t voltype, afs_voltype_t voltype,
afsc_vldb_record_t *entry); struct afs_cache_vlocation *entry);
extern int afs_rxvl_get_entry_by_id_async(afs_async_op_t *op, extern int afs_rxvl_get_entry_by_id_async(afs_async_op_t *op,
afs_volid_t volid, afs_volid_t volid,
afs_voltype_t voltype); afs_voltype_t voltype);
extern int afs_rxvl_get_entry_by_id_async2(afs_async_op_t *op, extern int afs_rxvl_get_entry_by_id_async2(afs_async_op_t *op,
afsc_vldb_record_t *entry); struct afs_cache_vlocation *entry);
#endif /* _LINUX_AFS_VLCLIENT_H */ #endif /* _LINUX_AFS_VLCLIENT_H */
This diff is collapsed.
...@@ -29,6 +29,19 @@ struct afs_timer_ops afs_vnode_cb_timed_out_ops = { ...@@ -29,6 +29,19 @@ struct afs_timer_ops afs_vnode_cb_timed_out_ops = {
.timed_out = afs_vnode_cb_timed_out, .timed_out = afs_vnode_cb_timed_out,
}; };
#ifdef AFS_CACHING_SUPPORT
static cachefs_match_val_t afs_vnode_cache_match(void *target, const void *entry);
static void afs_vnode_cache_update(void *source, void *entry);
struct cachefs_index_def afs_vnode_cache_index_def = {
.name = "vnode",
.data_size = sizeof(struct afs_cache_vnode),
.keys[0] = { CACHEFS_INDEX_KEYS_BIN, 4 },
.match = afs_vnode_cache_match,
.update = afs_vnode_cache_update,
};
#endif
/*****************************************************************************/ /*****************************************************************************/
/* /*
* handle a callback timing out * handle a callback timing out
...@@ -61,8 +74,7 @@ static void afs_vnode_cb_timed_out(struct afs_timer *timer) ...@@ -61,8 +74,7 @@ static void afs_vnode_cb_timed_out(struct afs_timer *timer)
spin_unlock(&vnode->lock); spin_unlock(&vnode->lock);
if (oldserver) afs_put_server(oldserver);
afs_put_server(oldserver);
_leave(""); _leave("");
} /* end afs_vnode_cb_timed_out() */ } /* end afs_vnode_cb_timed_out() */
...@@ -126,8 +138,7 @@ void afs_vnode_finalise_status_update(afs_vnode_t *vnode, afs_server_t *server, ...@@ -126,8 +138,7 @@ void afs_vnode_finalise_status_update(afs_vnode_t *vnode, afs_server_t *server,
wake_up_all(&vnode->update_waitq); wake_up_all(&vnode->update_waitq);
if (oldserver) afs_put_server(oldserver);
afs_put_server(oldserver);
_leave(""); _leave("");
...@@ -272,7 +283,7 @@ int afs_vnode_fetch_data(afs_vnode_t *vnode, struct afs_rxfs_fetch_descriptor *d ...@@ -272,7 +283,7 @@ int afs_vnode_fetch_data(afs_vnode_t *vnode, struct afs_rxfs_fetch_descriptor *d
/*****************************************************************************/ /*****************************************************************************/
/* /*
* break any outstanding callback on a vnode * break any outstanding callback on a vnode
* - only relevant to server that issued it * - only relevent to server that issued it
*/ */
int afs_vnode_give_up_callback(afs_vnode_t *vnode) int afs_vnode_give_up_callback(afs_vnode_t *vnode)
{ {
...@@ -314,3 +325,56 @@ int afs_vnode_give_up_callback(afs_vnode_t *vnode) ...@@ -314,3 +325,56 @@ int afs_vnode_give_up_callback(afs_vnode_t *vnode)
_leave(" = %d",ret); _leave(" = %d",ret);
return ret; return ret;
} /* end afs_vnode_give_up_callback() */ } /* end afs_vnode_give_up_callback() */
/*****************************************************************************/
/*
* match a vnode record stored in the cache
*/
#ifdef AFS_CACHING_SUPPORT
static cachefs_match_val_t afs_vnode_cache_match(void *target, const void *entry)
{
const struct afs_cache_vnode *cvnode = entry;
struct afs_vnode *vnode = target;
_enter("{%x,%x,%Lx},{%x,%x,%Lx}",
vnode->fid.vnode,
vnode->fid.unique,
vnode->status.version,
cvnode->vnode_id,
cvnode->vnode_unique,
cvnode->data_version);
if (vnode->fid.vnode != cvnode->vnode_id) {
_leave(" = FAILED");
return CACHEFS_MATCH_FAILED;
}
if (vnode->fid.unique != cvnode->vnode_unique ||
vnode->status.version != cvnode->data_version) {
_leave(" = DELETE");
return CACHEFS_MATCH_SUCCESS_DELETE;
}
_leave(" = SUCCESS");
return CACHEFS_MATCH_SUCCESS;
} /* end afs_vnode_cache_match() */
#endif
/*****************************************************************************/
/*
* update a vnode record stored in the cache
*/
#ifdef AFS_CACHING_SUPPORT
static void afs_vnode_cache_update(void *source, void *entry)
{
struct afs_cache_vnode *cvnode = entry;
struct afs_vnode *vnode = source;
_enter("");
cvnode->vnode_id = vnode->fid.vnode;
cvnode->vnode_unique = vnode->fid.unique;
cvnode->data_version = vnode->status.version;
} /* end afs_vnode_cache_update() */
#endif
...@@ -15,11 +15,27 @@ ...@@ -15,11 +15,27 @@
#include <linux/fs.h> #include <linux/fs.h>
#include "server.h" #include "server.h"
#include "kafstimod.h" #include "kafstimod.h"
#include "cache.h"
#ifdef __KERNEL__ #ifdef __KERNEL__
struct afs_rxfs_fetch_descriptor; struct afs_rxfs_fetch_descriptor;
/*****************************************************************************/
/*
* vnode catalogue entry
*/
struct afs_cache_vnode
{
afs_vnodeid_t vnode_id; /* vnode ID */
unsigned vnode_unique; /* vnode ID uniquifier */
afs_dataversion_t data_version; /* data version */
};
#ifdef AFS_CACHING_SUPPORT
extern struct cachefs_index_def afs_vnode_cache_index_def;
#endif
/*****************************************************************************/ /*****************************************************************************/
/* /*
* AFS inode private data * AFS inode private data
...@@ -28,10 +44,12 @@ struct afs_vnode ...@@ -28,10 +44,12 @@ struct afs_vnode
{ {
struct inode vfs_inode; /* the VFS's inode record */ struct inode vfs_inode; /* the VFS's inode record */
afs_volume_t *volume; /* volume on which vnode resides */ struct afs_volume *volume; /* volume on which vnode resides */
afs_fid_t fid; /* the file identifier for this inode */ struct afs_fid fid; /* the file identifier for this inode */
afs_file_status_t status; /* AFS status info for this file */ struct afs_file_status status; /* AFS status info for this file */
unsigned nix; /* vnode index in cache */ #ifdef AFS_CACHING_SUPPORT
struct cachefs_cookie *cache; /* caching cookie */
#endif
wait_queue_head_t update_waitq; /* status fetch waitqueue */ wait_queue_head_t update_waitq; /* status fetch waitqueue */
unsigned update_cnt; /* number of outstanding ops that will update the unsigned update_cnt; /* number of outstanding ops that will update the
...@@ -43,10 +61,10 @@ struct afs_vnode ...@@ -43,10 +61,10 @@ struct afs_vnode
#define AFS_VNODE_MOUNTPOINT 0x00000004 /* set if vnode is a mountpoint symlink */ #define AFS_VNODE_MOUNTPOINT 0x00000004 /* set if vnode is a mountpoint symlink */
/* outstanding callback notification on this file */ /* outstanding callback notification on this file */
afs_server_t *cb_server; /* server that made the current promise */ struct afs_server *cb_server; /* server that made the current promise */
struct list_head cb_link; /* link in server's promises list */ struct list_head cb_link; /* link in server's promises list */
struct list_head cb_hash_link; /* link in master callback hash */ struct list_head cb_hash_link; /* link in master callback hash */
afs_timer_t cb_timeout; /* timeout on promise */ struct afs_timer cb_timeout; /* timeout on promise */
unsigned cb_version; /* callback version */ unsigned cb_version; /* callback version */
unsigned cb_expiry; /* callback expiry time */ unsigned cb_expiry; /* callback expiry time */
afs_callback_type_t cb_type; /* type of callback */ afs_callback_type_t cb_type; /* type of callback */
......
...@@ -16,7 +16,9 @@ ...@@ -16,7 +16,9 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include "volume.h" #include "volume.h"
#include "vnode.h"
#include "cell.h" #include "cell.h"
#include "cache.h"
#include "cmservice.h" #include "cmservice.h"
#include "fsclient.h" #include "fsclient.h"
#include "vlclient.h" #include "vlclient.h"
...@@ -24,6 +26,20 @@ ...@@ -24,6 +26,20 @@
const char *afs_voltypes[] = { "R/W", "R/O", "BAK" }; const char *afs_voltypes[] = { "R/W", "R/O", "BAK" };
#ifdef AFS_CACHING_SUPPORT
static cachefs_match_val_t afs_volume_cache_match(void *target, const void *entry);
static void afs_volume_cache_update(void *source, void *entry);
struct cachefs_index_def afs_volume_cache_index_def = {
.name = "volume",
.data_size = sizeof(struct afs_cache_vhash),
.keys[0] = { CACHEFS_INDEX_KEYS_BIN, 1 },
.keys[1] = { CACHEFS_INDEX_KEYS_BIN, 1 },
.match = afs_volume_cache_match,
.update = afs_volume_cache_update,
};
#endif
/*****************************************************************************/ /*****************************************************************************/
/* /*
* lookup a volume by name * lookup a volume by name
...@@ -43,19 +59,19 @@ const char *afs_voltypes[] = { "R/W", "R/O", "BAK" }; ...@@ -43,19 +59,19 @@ const char *afs_voltypes[] = { "R/W", "R/O", "BAK" };
* - Rule 2: If parent volume is R/O, then mount R/O volume by preference, R/W if not available * - Rule 2: If parent volume is R/O, then mount R/O volume by preference, R/W if not available
* - Rule 3: If parent volume is R/W, then only mount R/W volume unless explicitly told otherwise * - Rule 3: If parent volume is R/W, then only mount R/W volume unless explicitly told otherwise
*/ */
int afs_volume_lookup(const char *name, int rwparent, afs_volume_t **_volume) int afs_volume_lookup(const char *name, struct afs_cell *cell, int rwpath,
afs_volume_t **_volume)
{ {
afs_vlocation_t *vlocation = NULL; struct afs_vlocation *vlocation = NULL;
struct afs_volume *volume = NULL;
afs_voltype_t type; afs_voltype_t type;
afs_volume_t *volume = NULL; const char *cellname, *volname, *suffix;
afs_cell_t *cell = NULL;
char *cellname, *volname, *suffix;
char srvtmask; char srvtmask;
int force, ret, loop; int force, ret, loop, cellnamesz, volnamesz;
_enter(",%s,",name); _enter("%s,,%d,", name, rwpath);
if (!name || (name[0]!='%' && name[0]!='#') || !name[1]) { if (!name || (name[0] != '%' && name[0] != '#') || !name[1]) {
printk("kAFS: unparsable volume name\n"); printk("kAFS: unparsable volume name\n");
return -EINVAL; return -EINVAL;
} }
...@@ -64,24 +80,22 @@ int afs_volume_lookup(const char *name, int rwparent, afs_volume_t **_volume) ...@@ -64,24 +80,22 @@ int afs_volume_lookup(const char *name, int rwparent, afs_volume_t **_volume)
force = 0; force = 0;
type = AFSVL_ROVOL; type = AFSVL_ROVOL;
if (rwparent || name[0]=='%') { if (rwpath || name[0] == '%') {
type = AFSVL_RWVOL; type = AFSVL_RWVOL;
force = 1; force = 1;
} }
suffix = strrchr(name,'.'); suffix = strrchr(name, '.');
if (suffix) { if (suffix) {
if (strcmp(suffix,".readonly")==0) { if (strcmp(suffix, ".readonly") == 0) {
type = AFSVL_ROVOL; type = AFSVL_ROVOL;
force = 1; force = 1;
} }
else if (strcmp(suffix,".backup")==0) { else if (strcmp(suffix, ".backup") == 0) {
type = AFSVL_BACKVOL; type = AFSVL_BACKVOL;
force = 1; force = 1;
} }
else if (suffix[1]==0) { else if (suffix[1] == 0) {
*suffix = 0;
suffix = NULL;
} }
else { else {
suffix = NULL; suffix = NULL;
...@@ -90,38 +104,45 @@ int afs_volume_lookup(const char *name, int rwparent, afs_volume_t **_volume) ...@@ -90,38 +104,45 @@ int afs_volume_lookup(const char *name, int rwparent, afs_volume_t **_volume)
/* split the cell and volume names */ /* split the cell and volume names */
name++; name++;
volname = strchr(name,':'); volname = strchr(name, ':');
if (volname) { if (volname) {
*volname++ = 0;
cellname = name; cellname = name;
cellnamesz = volname - name;
} }
else { else {
volname = name; volname = name;
cellname = NULL; cellname = NULL;
cellnamesz = 0;
} }
_debug("CELL:%s VOLUME:%s SUFFIX:%s TYPE:%d%s", volnamesz = suffix ? suffix - volname : strlen(volname);
cellname,volname,suffix?:"-",type,force?" FORCE":"");
/* lookup the cell record */ _debug("CELL:%*.*s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s",
ret = afs_cell_lookup(cellname,&cell); cellnamesz, cellnamesz, cellname ?: "", cell,
if (ret<0) volnamesz, volnamesz, volname, suffix ?: "-",
printk("kAFS: unable to lookup cell '%s'\n",cellname?:""); type,
force ? " FORCE" : "");
if (cellname) volname[-1] = ':'; /* lookup the cell record */
if (ret<0) if (cellname || !cell) {
goto error; ret = afs_cell_lookup(cellname, cellnamesz, &cell);
if (ret<0) {
printk("kAFS: unable to lookup cell '%s'\n", cellname ?: "");
goto error;
}
}
else {
afs_get_cell(cell);
}
/* lookup the volume location record */ /* lookup the volume location record */
if (suffix) *suffix = 0; ret = afs_vlocation_lookup(cell, volname, volnamesz, &vlocation);
ret = afs_vlocation_lookup(cell,volname,&vlocation); if (ret < 0)
if (suffix) *suffix = '.';
if (ret<0)
goto error; goto error;
/* make the final decision on the type we want */ /* make the final decision on the type we want */
ret = -ENOMEDIUM; ret = -ENOMEDIUM;
if (force && !(vlocation->vldb.vidmask & (1<<type))) if (force && !(vlocation->vldb.vidmask & (1 << type)))
goto error; goto error;
srvtmask = 0; srvtmask = 0;
...@@ -129,13 +150,13 @@ int afs_volume_lookup(const char *name, int rwparent, afs_volume_t **_volume) ...@@ -129,13 +150,13 @@ int afs_volume_lookup(const char *name, int rwparent, afs_volume_t **_volume)
srvtmask |= vlocation->vldb.srvtmask[loop]; srvtmask |= vlocation->vldb.srvtmask[loop];
if (force) { if (force) {
if (!(srvtmask & (1 <<type))) if (!(srvtmask & (1 << type)))
goto error; goto error;
} }
else if (srvtmask & AFSC_VOL_STM_RO) { else if (srvtmask & AFS_VOL_VTM_RO) {
type = AFSVL_ROVOL; type = AFSVL_ROVOL;
} }
else if (srvtmask & AFSC_VOL_STM_RW) { else if (srvtmask & AFS_VOL_VTM_RW) {
type = AFSVL_RWVOL; type = AFSVL_RWVOL;
} }
else { else {
...@@ -156,16 +177,16 @@ int afs_volume_lookup(const char *name, int rwparent, afs_volume_t **_volume) ...@@ -156,16 +177,16 @@ int afs_volume_lookup(const char *name, int rwparent, afs_volume_t **_volume)
_debug("creating new volume record"); _debug("creating new volume record");
ret = -ENOMEM; ret = -ENOMEM;
volume = kmalloc(sizeof(afs_volume_t),GFP_KERNEL); volume = kmalloc(sizeof(afs_volume_t), GFP_KERNEL);
if (!volume) if (!volume)
goto error_up; goto error_up;
memset(volume,0,sizeof(afs_volume_t)); memset(volume, 0, sizeof(afs_volume_t));
atomic_set(&volume->usage,1); atomic_set(&volume->usage, 1);
volume->type = type; volume->type = type;
volume->type_force = force; volume->type_force = force;
volume->cell = cell; volume->cell = cell;
volume->vid = vlocation->vldb.vid[type]; volume->vid = vlocation->vldb.vid[type];
init_rwsem(&volume->server_sem); init_rwsem(&volume->server_sem);
...@@ -183,15 +204,20 @@ int afs_volume_lookup(const char *name, int rwparent, afs_volume_t **_volume) ...@@ -183,15 +204,20 @@ int afs_volume_lookup(const char *name, int rwparent, afs_volume_t **_volume)
} }
/* attach the cache and volume location */ /* attach the cache and volume location */
#if 0 #ifdef AFS_CACHING_SUPPORT
afs_get_cache(cache); volume->cache = cache; cachefs_acquire_cookie(vlocation->cache,
&afs_vnode_cache_index_def,
volume,
&volume->cache);
#endif #endif
afs_get_vlocation(vlocation); volume->vlocation = vlocation;
afs_get_vlocation(vlocation);
volume->vlocation = vlocation;
vlocation->vols[type] = volume; vlocation->vols[type] = volume;
success: success:
_debug("kAFS selected %s volume %08x",afs_voltypes[volume->type],volume->vid); _debug("kAFS selected %s volume %08x", afs_voltypes[volume->type], volume->vid);
*_volume = volume; *_volume = volume;
ret = 0; ret = 0;
...@@ -199,18 +225,17 @@ int afs_volume_lookup(const char *name, int rwparent, afs_volume_t **_volume) ...@@ -199,18 +225,17 @@ int afs_volume_lookup(const char *name, int rwparent, afs_volume_t **_volume)
error_up: error_up:
up_write(&cell->vl_sem); up_write(&cell->vl_sem);
error: error:
if (vlocation) afs_put_vlocation(vlocation); afs_put_vlocation(vlocation);
if (cell) afs_put_cell(cell); afs_put_cell(cell);
_leave(" = %d (%p)",ret,volume); _leave(" = %d (%p)", ret, volume);
return ret; return ret;
error_discard: error_discard:
up_write(&cell->vl_sem); up_write(&cell->vl_sem);
for (loop=volume->nservers-1; loop>=0; loop--) for (loop=volume->nservers-1; loop>=0; loop--)
if (volume->servers[loop]) afs_put_server(volume->servers[loop]);
afs_put_server(volume->servers[loop]);
kfree(volume); kfree(volume);
goto error; goto error;
...@@ -225,6 +250,9 @@ void afs_put_volume(afs_volume_t *volume) ...@@ -225,6 +250,9 @@ void afs_put_volume(afs_volume_t *volume)
afs_vlocation_t *vlocation; afs_vlocation_t *vlocation;
int loop; int loop;
if (!volume)
return;
_enter("%p",volume); _enter("%p",volume);
vlocation = volume->vlocation; vlocation = volume->vlocation;
...@@ -246,16 +274,14 @@ void afs_put_volume(afs_volume_t *volume) ...@@ -246,16 +274,14 @@ void afs_put_volume(afs_volume_t *volume)
up_write(&vlocation->cell->vl_sem); up_write(&vlocation->cell->vl_sem);
afs_put_vlocation(vlocation);
/* finish cleaning up the volume */ /* finish cleaning up the volume */
#if 0 #ifdef AFS_CACHING_SUPPORT
if (volume->cache) afs_put_cache(volume->cache); cachefs_relinquish_cookie(volume->cache,0);
#endif #endif
afs_put_vlocation(vlocation);
for (loop=volume->nservers-1; loop>=0; loop--) for (loop=volume->nservers-1; loop>=0; loop--)
if (volume->servers[loop]) afs_put_server(volume->servers[loop]);
afs_put_server(volume->servers[loop]);
kfree(volume); kfree(volume);
...@@ -428,3 +454,42 @@ int afs_volume_release_fileserver(afs_volume_t *volume, afs_server_t *server, in ...@@ -428,3 +454,42 @@ int afs_volume_release_fileserver(afs_volume_t *volume, afs_server_t *server, in
return 0; return 0;
} /* end afs_volume_release_fileserver() */ } /* end afs_volume_release_fileserver() */
/*****************************************************************************/
/*
* match a volume hash record stored in the cache
*/
#ifdef AFS_CACHING_SUPPORT
static cachefs_match_val_t afs_volume_cache_match(void *target, const void *entry)
{
const struct afs_cache_vhash *vhash = entry;
struct afs_volume *volume = target;
_enter("{%u},{%u}", volume->type, vhash->vtype);
if (volume->type == vhash->vtype) {
_leave(" = SUCCESS");
return CACHEFS_MATCH_SUCCESS;
}
_leave(" = FAILED");
return CACHEFS_MATCH_FAILED;
} /* end afs_volume_cache_match() */
#endif
/*****************************************************************************/
/*
* update a volume hash record stored in the cache
*/
#ifdef AFS_CACHING_SUPPORT
static void afs_volume_cache_update(void *source, void *entry)
{
struct afs_cache_vhash *vhash = entry;
struct afs_volume *volume = source;
_enter("");
vhash->vtype = volume->type;
} /* end afs_volume_cache_update() */
#endif
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#include "fsclient.h" #include "fsclient.h"
#include "kafstimod.h" #include "kafstimod.h"
#include "kafsasyncd.h" #include "kafsasyncd.h"
#include "cache-layout.h" #include "cache.h"
#define __packed __attribute__((packed)) #define __packed __attribute__((packed))
...@@ -28,6 +28,43 @@ typedef enum { ...@@ -28,6 +28,43 @@ typedef enum {
} __attribute__((packed)) afs_vlocation_upd_t; } __attribute__((packed)) afs_vlocation_upd_t;
/*****************************************************************************/
/*
* entry in the cached volume location catalogue
*/
struct afs_cache_vlocation
{
uint8_t name[64]; /* volume name (lowercase, padded with NULs) */
uint8_t nservers; /* number of entries used in servers[] */
uint8_t vidmask; /* voltype mask for vid[] */
uint8_t srvtmask[8]; /* voltype masks for servers[] */
#define AFS_VOL_VTM_RW 0x01 /* R/W version of the volume is available (on this server) */
#define AFS_VOL_VTM_RO 0x02 /* R/O version of the volume is available (on this server) */
#define AFS_VOL_VTM_BAK 0x04 /* backup version of the volume is available (on this server) */
afs_volid_t vid[3]; /* volume IDs for R/W, R/O and Bak volumes */
struct in_addr servers[8]; /* fileserver addresses */
time_t rtime; /* last retrieval time */
};
#ifdef AFS_CACHING_SUPPORT
extern struct cachefs_index_def afs_vlocation_cache_index_def;
#endif
/*****************************************************************************/
/*
* volume -> vnode hash table entry
*/
struct afs_cache_vhash
{
afs_voltype_t vtype; /* which volume variation */
uint8_t hash_bucket; /* which hash bucket this represents */
} __attribute__((packed));
#ifdef AFS_CACHING_SUPPORT
extern struct cachefs_index_def afs_volume_cache_index_def;
#endif
/*****************************************************************************/ /*****************************************************************************/
/* /*
* AFS volume location record * AFS volume location record
...@@ -36,15 +73,17 @@ struct afs_vlocation ...@@ -36,15 +73,17 @@ struct afs_vlocation
{ {
atomic_t usage; atomic_t usage;
struct list_head link; /* link in cell volume location list */ struct list_head link; /* link in cell volume location list */
afs_timer_t timeout; /* decaching timer */ struct afs_timer timeout; /* decaching timer */
afs_cell_t *cell; /* cell to which volume belongs */ struct afs_cell *cell; /* cell to which volume belongs */
struct list_head caches; /* backing caches */ #ifdef AFS_CACHING_SUPPORT
afsc_vldb_record_t vldb; /* volume information DB record */ struct cachefs_cookie *cache; /* caching cookie */
#endif
struct afs_cache_vlocation vldb; /* volume information DB record */
struct afs_volume *vols[3]; /* volume access record pointer (index by type) */ struct afs_volume *vols[3]; /* volume access record pointer (index by type) */
rwlock_t lock; /* access lock */ rwlock_t lock; /* access lock */
unsigned long read_jif; /* time at which last read from vlserver */ unsigned long read_jif; /* time at which last read from vlserver */
afs_timer_t upd_timer; /* update timer */ struct afs_timer upd_timer; /* update timer */
afs_async_op_t upd_op; /* update operation */ struct afs_async_op upd_op; /* update operation */
afs_vlocation_upd_t upd_state; /* update state */ afs_vlocation_upd_t upd_state; /* update state */
unsigned short upd_first_svix; /* first server index during update */ unsigned short upd_first_svix; /* first server index during update */
unsigned short upd_curr_svix; /* current server index during update */ unsigned short upd_curr_svix; /* current server index during update */
...@@ -53,13 +92,16 @@ struct afs_vlocation ...@@ -53,13 +92,16 @@ struct afs_vlocation
unsigned short valid; /* T if valid */ unsigned short valid; /* T if valid */
}; };
extern int afs_vlocation_lookup(afs_cell_t *cell, const char *name, afs_vlocation_t **_vlocation); extern int afs_vlocation_lookup(struct afs_cell *cell,
const char *name,
unsigned namesz,
struct afs_vlocation **_vlocation);
#define afs_get_vlocation(V) do { atomic_inc(&(V)->usage); } while(0) #define afs_get_vlocation(V) do { atomic_inc(&(V)->usage); } while(0)
extern void __afs_put_vlocation(afs_vlocation_t *vlocation); extern void __afs_put_vlocation(struct afs_vlocation *vlocation);
extern void afs_put_vlocation(afs_vlocation_t *vlocation); extern void afs_put_vlocation(struct afs_vlocation *vlocation);
extern void afs_vlocation_do_timeout(afs_vlocation_t *vlocation); extern void afs_vlocation_do_timeout(struct afs_vlocation *vlocation);
/*****************************************************************************/ /*****************************************************************************/
/* /*
...@@ -68,25 +110,34 @@ extern void afs_vlocation_do_timeout(afs_vlocation_t *vlocation); ...@@ -68,25 +110,34 @@ extern void afs_vlocation_do_timeout(afs_vlocation_t *vlocation);
struct afs_volume struct afs_volume
{ {
atomic_t usage; atomic_t usage;
afs_cell_t *cell; /* cell to which belongs (unrefd ptr) */ struct afs_cell *cell; /* cell to which belongs (unrefd ptr) */
afs_vlocation_t *vlocation; /* volume location */ struct afs_vlocation *vlocation; /* volume location */
#ifdef AFS_CACHING_SUPPORT
struct cachefs_cookie *cache; /* caching cookie */
#endif
afs_volid_t vid; /* volume ID */ afs_volid_t vid; /* volume ID */
afs_voltype_t __packed type; /* type of volume */ afs_voltype_t __packed type; /* type of volume */
char type_force; /* force volume type (suppress R/O -> R/W) */ char type_force; /* force volume type (suppress R/O -> R/W) */
unsigned short nservers; /* number of server slots filled */ unsigned short nservers; /* number of server slots filled */
unsigned short rjservers; /* number of servers discarded due to -ENOMEDIUM */ unsigned short rjservers; /* number of servers discarded due to -ENOMEDIUM */
afs_server_t *servers[8]; /* servers on which volume resides (ordered) */ struct afs_server *servers[8]; /* servers on which volume resides (ordered) */
struct rw_semaphore server_sem; /* lock for accessing current server */ struct rw_semaphore server_sem; /* lock for accessing current server */
}; };
extern int afs_volume_lookup(const char *name, int ro, afs_volume_t **_volume); extern int afs_volume_lookup(const char *name,
struct afs_cell *cell,
int rwpath,
struct afs_volume **_volume);
#define afs_get_volume(V) do { atomic_inc(&(V)->usage); } while(0) #define afs_get_volume(V) do { atomic_inc(&(V)->usage); } while(0)
extern void afs_put_volume(afs_volume_t *volume); extern void afs_put_volume(struct afs_volume *volume);
extern int afs_volume_pick_fileserver(afs_volume_t *volume, afs_server_t **_server); extern int afs_volume_pick_fileserver(struct afs_volume *volume,
struct afs_server **_server);
extern int afs_volume_release_fileserver(afs_volume_t *volume, afs_server_t *server, int result); extern int afs_volume_release_fileserver(struct afs_volume *volume,
struct afs_server *server,
int result);
#endif /* _LINUX_AFS_VOLUME_H */ #endif /* _LINUX_AFS_VOLUME_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment