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

[PATCH] AFS update

parent d2a65691
......@@ -2,6 +2,8 @@
# Makefile for Red Hat Linux AFS client.
#
#CFLAGS += -finstrument-functions
kafs-objs := \
callback.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)
spin_unlock(&vnode->lock);
iput(inode);
if (release) afs_put_server(server);
afs_put_server(server);
spin_lock(&server->cb_lock);
}
......
......@@ -36,6 +36,19 @@ static char *rootcell;
MODULE_PARM(rootcell,"s");
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
......@@ -65,7 +78,6 @@ int afs_cell_create(const char *name, char *vllist, afs_cell_t **_cell)
atomic_set(&cell->usage,0);
INIT_LIST_HEAD(&cell->link);
INIT_LIST_HEAD(&cell->caches);
rwlock_init(&cell->sv_lock);
INIT_LIST_HEAD(&cell->sv_list);
......@@ -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 =
htonl((a<<24)|(b<<16)|(c<<8)|d);
if (cell->vl_naddrs>=16)
if (cell->vl_naddrs >= AFS_CELL_MAX_ADDRS)
break;
} while(vllist=next, vllist);
......@@ -106,6 +118,14 @@ int afs_cell_create(const char *name, char *vllist, afs_cell_t **_cell)
if (ret<0)
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 */
write_lock(&afs_cells_lock);
list_add_tail(&cell->link,&afs_cells);
......@@ -166,36 +186,45 @@ int afs_cell_init(void)
/*
* 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;
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 the cell was named, look for it in the cell record list */
ret = -ENOENT;
cell = NULL;
read_lock(&afs_cells_lock);
list_for_each(_p,&afs_cells) {
cell = list_entry(_p,afs_cell_t,link);
if (strcmp(cell->name,name)==0)
cell = list_entry(_p, struct afs_cell, link);
if (strncmp(cell->name, name, namesz) == 0) {
afs_get_cell(cell);
break;
}
cell = NULL;
}
read_unlock(&afs_cells_lock);
}
if (cell)
if (cell)
ret = 0;
}
else {
cell = afs_cell_root;
afs_get_cell(cell);
ret = 0;
}
*_cell = cell;
_leave(" = %d (%p)",cell?0:-ENOENT,cell);
return cell ? 0 : -ENOENT;
_leave(" = %d (%p)", ret, cell);
return ret;
} /* end afs_cell_lookup() */
......@@ -211,8 +240,8 @@ afs_cell_t *afs_get_cell_maybe(afs_cell_t **_cell)
cell = *_cell;
if (cell && !list_empty(&cell->link))
atomic_inc(&cell->usage);
else
afs_get_cell(cell);
else
cell = NULL;
write_unlock(&afs_cells_lock);
......@@ -226,6 +255,9 @@ afs_cell_t *afs_get_cell_maybe(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);
/* sanity check */
......@@ -278,6 +310,10 @@ static void afs_cell_destroy(afs_cell_t *cell)
list_del_init(&cell->proc_link);
up_write(&afs_proc_cells_sem);
#ifdef AFS_CACHING_SUPPORT
cachefs_relinquish_cookie(cell->cache,0);
#endif
up_write(&afs_cells_sem);
if (!list_empty(&cell->sv_list)) BUG();
......@@ -377,8 +413,7 @@ void afs_cell_purge(void)
_enter("");
if (afs_cell_root)
afs_put_cell(afs_cell_root);
afs_put_cell(afs_cell_root);
while (!list_empty(&afs_cells)) {
cell = NULL;
......@@ -450,3 +485,46 @@ void afs_cell_purge(void)
_leave("");
} /* 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 @@
#define _LINUX_AFS_CELL_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 */
/*****************************************************************************/
/*
* 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
......@@ -26,7 +39,9 @@ struct afs_cell
struct list_head link; /* main cell list link */
struct list_head proc_link; /* /proc cell list link */
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 */
rwlock_t sv_lock; /* active server list lock */
......@@ -41,22 +56,22 @@ struct afs_cell
spinlock_t vl_gylock; /* graveyard lock */
unsigned short vl_naddrs; /* number of VL servers in addr list */
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 */
};
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)
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);
......
......@@ -119,6 +119,7 @@ static int kafscmd(void *arg)
int die;
printk("kAFS: Started kafscmd %d\n",current->pid);
daemonize("kafscmd");
complete(&kafscmd_alive);
......@@ -293,15 +294,20 @@ int afscm_start(void)
down_write(&afscm_sem);
if (!afscm_usage) {
ret = kernel_thread(kafscmd,NULL,0);
if (ret<0)
ret = kernel_thread(kafscmd, NULL, 0);
if (ret < 0)
goto out;
wait_for_completion(&kafscmd_alive);
ret = rxrpc_add_service(afs_transport,&AFSCM_service);
ret = rxrpc_add_service(afs_transport, &AFSCM_service);
if (ret<0)
goto kill;
#ifdef AFS_AUTOMOUNT_SUPPORT
afs_kafstimod_add_timer(&afs_mntpt_expiry_timer,
afs_mntpt_expiry_timeout * HZ);
#endif
}
afscm_usage++;
......@@ -330,17 +336,20 @@ void afscm_stop(void)
down_write(&afscm_sem);
if (afscm_usage==0) BUG();
if (afscm_usage == 0) BUG();
afscm_usage--;
if (afscm_usage==0) {
if (afscm_usage == 0) {
/* 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) */
spin_lock(&afscm_calls_lock);
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);
rxrpc_get_call(call);
spin_unlock(&afscm_calls_lock);
......@@ -348,7 +357,8 @@ void afscm_stop(void)
rxrpc_call_abort(call,-ESRCH); /* abort, dequeue and put */
_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);
......@@ -376,6 +386,10 @@ void afscm_stop(void)
spin_lock(&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);
......@@ -490,7 +504,7 @@ static void _SRXAFSCM_CallBack(struct rxrpc_call *call)
if (ret<0)
rxrpc_call_abort(call,ret);
if (server) afs_put_server(server);
afs_put_server(server);
_leave(" = %d",ret);
......@@ -556,7 +570,7 @@ static void _SRXAFSCM_InitCallBackState(struct rxrpc_call *call)
if (ret<0)
rxrpc_call_abort(call,ret);
if (server) afs_put_server(server);
afs_put_server(server);
_leave(" = %d",ret);
......@@ -622,7 +636,7 @@ static void _SRXAFSCM_Probe(struct rxrpc_call *call)
if (ret<0)
rxrpc_call_abort(call,ret);
if (server) afs_put_server(server);
afs_put_server(server);
_leave(" = %d",ret);
......
......@@ -23,10 +23,11 @@
#include "super.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_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_dir_lookup_filldir(void *_cookie, const char *name, int nlen, loff_t fpos,
ino_t ino, unsigned dtype);
......@@ -70,7 +71,7 @@ typedef union afs_dirent {
u8 name[16];
u8 overflow[4]; /* if any char of the name (inc NUL) reaches here, consume
* the next dirent too */
} parts;
} u;
u8 extended_name[32];
} afs_dirent_t;
......@@ -256,7 +257,7 @@ static int afs_dir_iterate_block(unsigned *fpos,
/* got a valid entry */
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",
blkoff/sizeof(afs_dir_block_t),offset,
......@@ -288,11 +289,11 @@ static int afs_dir_iterate_block(unsigned *fpos,
/* found the next entry */
ret = filldir(cookie,
dire->parts.name,
dire->u.name,
nlen,
blkoff + offset * sizeof(afs_dirent_t),
ntohl(dire->parts.vnode),
filldir==afs_dir_lookup_filldir ? dire->parts.unique : DT_UNKNOWN);
ntohl(dire->u.vnode),
filldir==afs_dir_lookup_filldir ? dire->u.unique : DT_UNKNOWN);
if (ret<0) {
_leave(" = 0 [full]");
return 0;
......@@ -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
*/
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_super_info *as;
......@@ -423,11 +425,11 @@ static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, s
unsigned fpos;
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 */
if (sizeof(afs_dir_block_t) != 2048) BUG();
if (sizeof(afs_dirent_t) != 32) BUG();
BUG_ON(sizeof(afs_dir_block_t) != 2048);
BUG_ON(sizeof(afs_dirent_t) != 32);
if (dentry->d_name.len > 255) {
_leave(" = -ENAMETOOLONG");
......@@ -495,9 +497,11 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
unsigned fpos;
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;
inode = dentry->d_inode;
......
......@@ -16,6 +16,7 @@
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/buffer_head.h>
#include "volume.h"
#include "vnode.h"
#include <rxrpc/call.h>
......@@ -27,6 +28,8 @@ static int afs_file_release(struct inode *inode, struct file *file);
#endif
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);
......@@ -37,7 +40,7 @@ struct inode_operations afs_file_inode_operations = {
struct file_operations afs_file_file_operations = {
.read = generic_file_read,
.write = afs_file_write,
.mmap = generic_file_readonly_mmap,
.mmap = generic_file_mmap,
#if 0
.open = afs_file_open,
.release = afs_file_release,
......@@ -47,6 +50,10 @@ struct file_operations afs_file_file_operations = {
struct address_space_operations afs_fs_aops = {
.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
return -EIO;
} /* 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)
......@@ -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)
{
struct afs_rxfs_fetch_descriptor desc;
#ifdef AFS_CACHING_SUPPORT
struct cachefs_page *pageio;
#endif
struct inode *inode;
afs_vnode_t *vnode;
int ret;
......@@ -88,28 +132,73 @@ static int afs_file_readpage(struct file *file, struct page *page)
if (vnode->flags & AFS_VNODE_DELETED)
goto error;
/* work out how much to get and from where */
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
ret = cachefs_page_get_private(page,&pageio,GFP_NOIO);
if (ret<0)
goto error;
}
SetPageUptodate(page);
unlock_page(page);
/* is it cached? */
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");
return 0;
......@@ -122,3 +211,83 @@ static int afs_file_readpage(struct file *file, struct page *page)
return ret;
} /* 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)
inode->i_uid = vnode->status.owner;
inode->i_gid = 0;
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_atime.tv_nsec =
inode->i_mtime.tv_nsec =
inode->i_ctime.tv_nsec = 0;
inode->i_ctime.tv_sec = vnode->status.mtime_server;
inode->i_ctime.tv_nsec = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime;
inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_version = vnode->fid.unique;
inode->i_mapping->a_ops = &afs_fs_aops;
/* 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);
if (vnode->flags & AFS_VNODE_MOUNTPOINT) {
......@@ -105,7 +104,7 @@ int afs_inode_fetch_status(struct inode *inode)
ret = afs_vnode_fetch_status(vnode);
if (ret==0)
if (ret == 0)
ret = afs_inode_map_status(vnode);
return ret;
......@@ -120,8 +119,8 @@ static int afs_iget5_test(struct inode *inode, void *opaque)
{
struct afs_iget_data *data = opaque;
/* only match inodes with the same version number */
return inode->i_ino==data->fid.vnode && inode->i_version==data->fid.unique;
return inode->i_ino == data->fid.vnode &&
inode->i_version == data->fid.unique;
} /* end afs_iget5_test() */
/*****************************************************************************/
......@@ -145,20 +144,22 @@ static int afs_iget5_set(struct inode *inode, void *opaque)
/*
* 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_vnode *vnode;
struct inode *inode;
afs_vnode_t *vnode;
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;
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) {
_leave(" = -ENOMEM");
return -ENOMEM;
......@@ -173,10 +174,19 @@ inline int afs_iget(struct super_block *sb, afs_fid_t *fid, struct inode **_inod
*_inode = inode;
else
iput(inode);
_leave(" = %d",ret);
_leave(" = %d", 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 */
vnode->flags |= AFS_VNODE_CHANGED;
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
unlock_new_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_timeout.timo_jif,
vnode->cb_type,
vnode->nix
vnode->cache
);
return 0;
......@@ -201,7 +211,7 @@ inline int afs_iget(struct super_block *sb, afs_fid_t *fid, struct inode **_inod
unlock_new_inode(inode);
iput(inode);
_leave(" = %d [bad]",ret);
_leave(" = %d [bad]", ret);
return ret;
} /* end afs_iget() */
......@@ -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
*/
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;
afs_vnode_t *vnode;
......@@ -217,23 +228,25 @@ int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat
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);
ret = afs_inode_fetch_status(inode);
if (ret==-ENOENT) {
_leave(" = %d [%d %p]",ret,atomic_read(&dentry->d_count),dentry->d_inode);
if (ret == -ENOENT) {
_leave(" = %d [%d %p]",
ret, atomic_read(&dentry->d_count), dentry->d_inode);
return ret;
}
else if (ret<0) {
else if (ret < 0) {
make_bad_inode(inode);
_leave(" = %d",ret);
_leave(" = %d", ret);
return ret;
}
/* transfer attributes from the inode structure to the stat structure */
generic_fillattr(inode,stat);
/* transfer attributes from the inode structure to the stat
* structure */
generic_fillattr(inode, stat);
_leave(" = 0 CB { v=%u x=%u t=%u }",
vnode->cb_version,
......@@ -261,9 +274,14 @@ void afs_clear_inode(struct inode *inode)
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);
#ifdef AFS_CACHING_SUPPORT
cachefs_relinquish_cookie(vnode->cache, 0);
vnode->cache = NULL;
#endif
_leave("");
} /* end afs_clear_inode() */
......@@ -26,7 +26,7 @@
#define kproto(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 _leave(FMT, a...) kleave(FMT , ## a)
#define _debug(FMT, a...) kdebug(FMT , ## a)
......@@ -56,6 +56,9 @@ static inline void afs_discard_my_signals(void)
*/
extern struct rw_semaphore afs_proc_cells_sem;
extern struct list_head afs_proc_cells;
#ifdef AFS_CACHING_SUPPORT
extern struct cachefs_index_def afs_cache_cell_index_def;
#endif
/*
* dir.c
......@@ -70,6 +73,10 @@ extern struct address_space_operations afs_fs_aops;
extern struct inode_operations afs_file_inode_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
*/
......@@ -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 void afs_clear_inode(struct inode *inode);
/*
* main.c
*/
#ifdef AFS_CACHING_SUPPORT
extern struct cachefs_netfs afs_cache_netfs;
#endif
/*
* mntpt.c
*/
extern struct inode_operations afs_mntpt_inode_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);
......
......@@ -153,8 +153,7 @@ static int kafsasyncd(void *arg)
spin_lock(&kafsasyncd_async_lock);
/* fold the busy and attention queues together */
list_splice(&kafsasyncd_async_busyq,&kafsasyncd_async_attnq);
list_del_init(&kafsasyncd_async_busyq);
list_splice_init(&kafsasyncd_async_busyq,&kafsasyncd_async_attnq);
/* dequeue kafsasyncd from all their wait queues */
list_for_each(_p,&kafsasyncd_async_attnq) {
......@@ -197,6 +196,7 @@ void afs_kafsasyncd_begin_op(afs_async_op_t *op)
spin_lock(&kafsasyncd_async_lock);
init_waitqueue_entry(&op->waiter,kafsasyncd_task);
add_wait_queue(&op->call->waitq,&op->waiter);
list_del(&op->link);
list_add_tail(&op->link,&kafsasyncd_async_busyq);
......@@ -238,7 +238,10 @@ void afs_kafsasyncd_terminate_op(afs_async_op_t *op)
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);
......
......@@ -82,7 +82,7 @@ static int kafstimod(void *arg)
for (;;) {
unsigned long jif;
unsigned long timeout;
signed long timeout;
/* deal with the server being asked to die */
if (kafstimod_die) {
......@@ -98,18 +98,18 @@ static int kafstimod(void *arg)
spin_lock(&kafstimod_lock);
if (list_empty(&kafstimod_list)) {
timeout = MAX_SCHEDULE_TIMEOUT;
} else {
unsigned long tmo;
timer = list_entry(kafstimod_list.next,
afs_timer_t, link);
tmo = timer->timo_jif;
}
else {
timer = list_entry(kafstimod_list.next,afs_timer_t,link);
timeout = timer->timo_jif;
jif = jiffies;
if (time_before_eq(tmo,jif))
if (time_before_eq((unsigned long)timeout,jif))
goto immediate;
timeout = (long)tmo - (long)jiffies;
else {
timeout = (long)timeout - (long)jiffies;
}
}
spin_unlock(&kafstimod_lock);
......@@ -170,7 +170,7 @@ void afs_kafstimod_add_timer(afs_timer_t *timer, unsigned long timeout)
wake_up(&kafstimod_sleepq);
_leave("");
} /* end afs_kafstimod_queue_vlocation() */
} /* end afs_kafstimod_add_timer() */
/*****************************************************************************/
/*
......
......@@ -17,6 +17,7 @@
#include <rxrpc/transport.h>
#include <rxrpc/call.h>
#include <rxrpc/peer.h>
#include "cache.h"
#include "cell.h"
#include "server.h"
#include "fsclient.h"
......@@ -47,6 +48,18 @@ static struct rxrpc_peer_ops afs_peer_ops = {
struct list_head afs_cb_hash_tbl[AFS_CB_HASH_COUNT];
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
......@@ -64,34 +77,41 @@ static int afs_init(void)
/* register the /proc stuff */
ret = afs_proc_init();
if (ret<0)
if (ret < 0)
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 */
ret = afs_cell_init();
if (ret<0)
goto error;
if (ret < 0)
goto error_cache;
/* start the timeout daemon */
ret = afs_kafstimod_start();
if (ret<0)
goto error;
if (ret < 0)
goto error_cache;
/* start the async operation daemon */
ret = afs_kafsasyncd_start();
if (ret<0)
if (ret < 0)
goto error_kafstimod;
/* create the RxRPC transport */
ret = rxrpc_create_transport(7001,&afs_transport);
if (ret<0)
if (ret < 0)
goto error_kafsasyncd;
afs_transport->peer_ops = &afs_peer_ops;
/* register the filesystems */
ret = afs_fs_init();
if (ret<0)
if (ret < 0)
goto error_transport;
return ret;
......@@ -102,7 +122,11 @@ static int afs_init(void)
afs_kafsasyncd_stop();
error_kafstimod:
afs_kafstimod_stop();
error_cache:
#ifdef AFS_CACHING_SUPPORT
cachefs_unregister_netfs(&afs_cache_netfs);
error:
#endif
afs_cell_purge();
afs_proc_cleanup();
printk(KERN_ERR "kAFS: failed to register: %d\n",ret);
......@@ -122,6 +146,9 @@ static void __exit afs_exit(void)
afs_kafstimod_stop();
afs_kafsasyncd_stop();
afs_cell_purge();
#ifdef AFS_CACHING_SUPPORT
cachefs_unregister_netfs(&afs_cache_netfs);
#endif
afs_proc_cleanup();
} /* end afs_exit() */
......@@ -142,7 +169,7 @@ static int afs_adding_peer(struct rxrpc_peer *peer)
/* determine which server the peer resides in (if any) */
ret = afs_server_find_by_peer(peer,&server);
if (ret<0)
if (ret < 0)
return ret; /* none that we recognise, so abort */
_debug("Server %p{u=%d}\n",server,atomic_read(&server->usage));
......@@ -191,3 +218,48 @@ static void afs_discarding_peer(struct rxrpc_peer *peer)
_leave("");
} /* 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 @@
#include <linux/slab.h>
#include <linux/fs.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 "vnode.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);
#ifdef AFS_AUTOMOUNT_SUPPORT
static int afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd);
#endif
struct file_operations afs_mntpt_file_operations = {
.open = afs_mntpt_open,
};
struct inode_operations afs_mntpt_inode_operations = {
.lookup = afs_mntpt_lookup,
#ifdef AFS_AUTOMOUNT_SUPPORT
.follow_link = afs_mntpt_follow_link,
#endif
.readlink = page_readlink,
.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
......@@ -93,8 +121,17 @@ int afs_mntpt_check_symlink(afs_vnode_t *vnode)
/*
* 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);
} /* end afs_mntpt_lookup() */
......@@ -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)
{
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;
} /* 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 {
const char *cell; /* name of cell containing volume */
const char *cache; /* name of cache block device */
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 */
......@@ -148,6 +148,9 @@ void afs_put_server(afs_server_t *server)
{
afs_cell_t *cell;
if (!server)
return;
_enter("%p",server);
cell = server->cell;
......
This diff is collapsed.
......@@ -29,7 +29,7 @@
*/
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 */
};
......
......@@ -33,26 +33,13 @@ typedef struct afs_volsync afs_volsync_t;
typedef struct afs_volume afs_volume_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 enum {
AFSVL_RWVOL, /* read/write volume */
AFSVL_ROVOL, /* read-only volume */
AFSVL_BACKVOL, /* backup volume */
} afs_voltype_t;
} __attribute__((packed)) afs_voltype_t;
extern const char *afs_voltypes[];
......
......@@ -176,8 +176,8 @@ int afs_rxvl_probe(afs_server_t *server, int alloc_flags)
/*
* look up a volume location database entry by name
*/
int afs_rxvl_get_entry_by_name(afs_server_t *server, const char *volname,
afsc_vldb_record_t *entry)
int afs_rxvl_get_entry_by_name(afs_server_t *server, const char *volname, unsigned volnamesz,
struct afs_cache_vlocation *entry)
{
DECLARE_WAITQUEUE(myself,current);
......@@ -189,29 +189,29 @@ int afs_rxvl_get_entry_by_name(afs_server_t *server, const char *volname,
int ret, loop;
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 */
ret = afs_server_get_vlconn(server,&conn);
ret = afs_server_get_vlconn(server, &conn);
if (ret<0)
goto out;
/* create a call through that connection */
ret = rxrpc_create_call(conn,NULL,NULL,afs_rxvl_aemap,&call);
if (ret<0) {
printk("kAFS: Unable to create call: %d\n",ret);
ret = rxrpc_create_call(conn, NULL, NULL, afs_rxvl_aemap, &call);
if (ret < 0) {
printk("kAFS: Unable to create call: %d\n", ret);
goto out_put_conn;
}
call->app_opcode = VLGETENTRYBYNAME;
/* we want to get event notifications from the call */
add_wait_queue(&call->waitq,&myself);
add_wait_queue(&call->waitq, &myself);
/* marshall the parameters */
piov[1].iov_len = strlen(volname);
piov[1].iov_base = (char*)volname;
piov[1].iov_len = volnamesz;
piov[1].iov_base = (char*) volname;
zero = 0;
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,
piov[0].iov_base = param;
/* 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)
goto abort;
/* 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);
if (ret<0) {
if (ret==-ECONNABORTED) {
ret = rxrpc_call_read_data(call, bp, 384, RXRPC_CALL_READ_BLOCK|RXRPC_CALL_READ_ALL);
if (ret < 0) {
if (ret == -ECONNABORTED) {
ret = call->app_errno;
goto out_unwait;
}
......@@ -255,9 +255,9 @@ int afs_rxvl_get_entry_by_name(afs_server_t *server, const char *volname,
for (loop=0; loop<8; loop++) {
tmp = ntohl(*bp++);
if (tmp & AFS_VLSF_RWVOL ) entry->srvtmask[loop] |= AFSC_VOL_STM_RW;
if (tmp & AFS_VLSF_ROVOL ) entry->srvtmask[loop] |= AFSC_VOL_STM_RO;
if (tmp & AFS_VLSF_BACKVOL) entry->srvtmask[loop] |= AFSC_VOL_STM_BAK;
if (tmp & AFS_VLSF_RWVOL ) entry->srvtmask[loop] |= AFS_VOL_VTM_RW;
if (tmp & AFS_VLSF_ROVOL ) entry->srvtmask[loop] |= AFS_VOL_VTM_RO;
if (tmp & AFS_VLSF_BACKVOL) entry->srvtmask[loop] |= AFS_VOL_VTM_BAK;
}
entry->vid[0] = ntohl(*bp++);
......@@ -267,26 +267,26 @@ int afs_rxvl_get_entry_by_name(afs_server_t *server, const char *volname,
bp++; /* clone ID */
tmp = ntohl(*bp++); /* flags */
if (tmp & AFS_VLF_RWEXISTS ) entry->vidmask |= AFSC_VOL_STM_RW;
if (tmp & AFS_VLF_ROEXISTS ) entry->vidmask |= AFSC_VOL_STM_RO;
if (tmp & AFS_VLF_BACKEXISTS) entry->vidmask |= AFSC_VOL_STM_BAK;
if (tmp & AFS_VLF_RWEXISTS ) entry->vidmask |= AFS_VOL_VTM_RW;
if (tmp & AFS_VLF_ROEXISTS ) entry->vidmask |= AFS_VOL_VTM_RO;
if (tmp & AFS_VLF_BACKEXISTS) entry->vidmask |= AFS_VOL_VTM_BAK;
ret = -ENOMEDIUM;
if (!entry->vidmask)
goto abort;
/* success */
entry->ctime = get_seconds();
entry->rtime = get_seconds();
ret = 0;
out_unwait:
set_current_state(TASK_RUNNING);
remove_wait_queue(&call->waitq,&myself);
remove_wait_queue(&call->waitq, &myself);
rxrpc_put_call(call);
out_put_conn:
rxrpc_put_connection(conn);
out:
_leave(" = %d",ret);
_leave(" = %d", ret);
return ret;
abort:
......@@ -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,
afs_volid_t volid,
afs_voltype_t voltype,
afsc_vldb_record_t *entry)
struct afs_cache_vlocation *entry)
{
DECLARE_WAITQUEUE(myself,current);
......@@ -375,9 +375,9 @@ int afs_rxvl_get_entry_by_id(afs_server_t *server,
for (loop=0; loop<8; loop++) {
tmp = ntohl(*bp++);
if (tmp & AFS_VLSF_RWVOL ) entry->srvtmask[loop] |= AFSC_VOL_STM_RW;
if (tmp & AFS_VLSF_ROVOL ) entry->srvtmask[loop] |= AFSC_VOL_STM_RO;
if (tmp & AFS_VLSF_BACKVOL) entry->srvtmask[loop] |= AFSC_VOL_STM_BAK;
if (tmp & AFS_VLSF_RWVOL ) entry->srvtmask[loop] |= AFS_VOL_VTM_RW;
if (tmp & AFS_VLSF_ROVOL ) entry->srvtmask[loop] |= AFS_VOL_VTM_RO;
if (tmp & AFS_VLSF_BACKVOL) entry->srvtmask[loop] |= AFS_VOL_VTM_BAK;
}
entry->vid[0] = ntohl(*bp++);
......@@ -387,9 +387,9 @@ int afs_rxvl_get_entry_by_id(afs_server_t *server,
bp++; /* clone ID */
tmp = ntohl(*bp++); /* flags */
if (tmp & AFS_VLF_RWEXISTS ) entry->vidmask |= AFSC_VOL_STM_RW;
if (tmp & AFS_VLF_ROEXISTS ) entry->vidmask |= AFSC_VOL_STM_RO;
if (tmp & AFS_VLF_BACKEXISTS) entry->vidmask |= AFSC_VOL_STM_BAK;
if (tmp & AFS_VLF_RWEXISTS ) entry->vidmask |= AFS_VOL_VTM_RW;
if (tmp & AFS_VLF_ROEXISTS ) entry->vidmask |= AFS_VOL_VTM_RO;
if (tmp & AFS_VLF_BACKEXISTS) entry->vidmask |= AFS_VOL_VTM_BAK;
ret = -ENOMEDIUM;
if (!entry->vidmask)
......@@ -401,13 +401,13 @@ int afs_rxvl_get_entry_by_id(afs_server_t *server,
entry->servers[1].s_addr = htonl(0xac101243);
entry->servers[2].s_addr = htonl(0xac10125b /*0xac10125b*/);
entry->srvtmask[0] = AFSC_VOL_STM_RO;
entry->srvtmask[1] = AFSC_VOL_STM_RO;
entry->srvtmask[2] = AFSC_VOL_STM_RO | AFSC_VOL_STM_RW;
entry->srvtmask[0] = AFS_VOL_VTM_RO;
entry->srvtmask[1] = AFS_VOL_VTM_RO;
entry->srvtmask[2] = AFS_VOL_VTM_RO | AFS_VOL_VTM_RW;
#endif
/* success */
entry->ctime = get_seconds();
entry->rtime = get_seconds();
ret = 0;
out_unwait:
......@@ -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
*/
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;
int loop, ret;
......@@ -550,9 +550,9 @@ int afs_rxvl_get_entry_by_id_async2(afs_async_op_t *op,
for (loop=0; loop<8; loop++) {
tmp = ntohl(*bp++);
if (tmp & AFS_VLSF_RWVOL ) entry->srvtmask[loop] |= AFSC_VOL_STM_RW;
if (tmp & AFS_VLSF_ROVOL ) entry->srvtmask[loop] |= AFSC_VOL_STM_RO;
if (tmp & AFS_VLSF_BACKVOL) entry->srvtmask[loop] |= AFSC_VOL_STM_BAK;
if (tmp & AFS_VLSF_RWVOL ) entry->srvtmask[loop] |= AFS_VOL_VTM_RW;
if (tmp & AFS_VLSF_ROVOL ) entry->srvtmask[loop] |= AFS_VOL_VTM_RO;
if (tmp & AFS_VLSF_BACKVOL) entry->srvtmask[loop] |= AFS_VOL_VTM_BAK;
}
entry->vid[0] = ntohl(*bp++);
......@@ -562,9 +562,9 @@ int afs_rxvl_get_entry_by_id_async2(afs_async_op_t *op,
bp++; /* clone ID */
tmp = ntohl(*bp++); /* flags */
if (tmp & AFS_VLF_RWEXISTS ) entry->vidmask |= AFSC_VOL_STM_RW;
if (tmp & AFS_VLF_ROEXISTS ) entry->vidmask |= AFSC_VOL_STM_RO;
if (tmp & AFS_VLF_BACKEXISTS) entry->vidmask |= AFSC_VOL_STM_BAK;
if (tmp & AFS_VLF_RWEXISTS ) entry->vidmask |= AFS_VOL_VTM_RW;
if (tmp & AFS_VLF_ROEXISTS ) entry->vidmask |= AFS_VOL_VTM_RO;
if (tmp & AFS_VLF_BACKEXISTS) entry->vidmask |= AFS_VOL_VTM_BAK;
ret = -ENOMEDIUM;
if (!entry->vidmask) {
......@@ -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[2].s_addr = htonl(0xac10125b /*0xac10125b*/);
entry->srvtmask[0] = AFSC_VOL_STM_RO;
entry->srvtmask[1] = AFSC_VOL_STM_RO;
entry->srvtmask[2] = AFSC_VOL_STM_RO | AFSC_VOL_STM_RW;
entry->srvtmask[0] = AFS_VOL_VTM_RO;
entry->srvtmask[1] = AFS_VOL_VTM_RO;
entry->srvtmask[2] = AFS_VOL_VTM_RO | AFS_VOL_VTM_RW;
#endif
/* success */
entry->ctime = get_seconds();
entry->rtime = get_seconds();
ret = 0;
goto done;
}
......@@ -626,7 +626,8 @@ static void afs_rxvl_get_entry_by_id_attn(struct rxrpc_call *call)
case RXRPC_CSTATE_CLNT_GOT_REPLY:
if (call->app_read_count==0)
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_async_read,
call->app_mark,
......
......@@ -46,7 +46,7 @@ enum AFSVL_Errors {
};
/* maps to "struct vldbentry" in vvl-spec.pdf */
struct afsvl_dbentry {
struct afs_vldbentry {
char name[65]; /* name of volume (including NUL char) */
afs_voltype_t type; /* volume type */
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);
/* look up a volume location database entry by name */
extern int afs_rxvl_get_entry_by_name(afs_server_t *server,
const char *volname,
afsc_vldb_record_t *entry);
unsigned volnamesz,
struct afs_cache_vlocation *entry);
/* look up a volume location database entry by ID */
extern int afs_rxvl_get_entry_by_id(afs_server_t *server,
afs_volid_t volid,
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,
afs_volid_t volid,
afs_voltype_t voltype);
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 */
This diff is collapsed.
......@@ -29,6 +29,19 @@ struct afs_timer_ops afs_vnode_cb_timed_out_ops = {
.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
......@@ -61,8 +74,7 @@ static void afs_vnode_cb_timed_out(struct afs_timer *timer)
spin_unlock(&vnode->lock);
if (oldserver)
afs_put_server(oldserver);
afs_put_server(oldserver);
_leave("");
} /* end afs_vnode_cb_timed_out() */
......@@ -126,8 +138,7 @@ void afs_vnode_finalise_status_update(afs_vnode_t *vnode, afs_server_t *server,
wake_up_all(&vnode->update_waitq);
if (oldserver)
afs_put_server(oldserver);
afs_put_server(oldserver);
_leave("");
......@@ -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
* - only relevant to server that issued it
* - only relevent to server that issued it
*/
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);
return ret;
} /* 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 @@
#include <linux/fs.h>
#include "server.h"
#include "kafstimod.h"
#include "cache.h"
#ifdef __KERNEL__
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
......@@ -28,10 +44,12 @@ struct afs_vnode
{
struct inode vfs_inode; /* the VFS's inode record */
afs_volume_t *volume; /* volume on which vnode resides */
afs_fid_t fid; /* the file identifier for this inode */
afs_file_status_t status; /* AFS status info for this file */
unsigned nix; /* vnode index in cache */
struct afs_volume *volume; /* volume on which vnode resides */
struct afs_fid fid; /* the file identifier for this inode */
struct afs_file_status status; /* AFS status info for this file */
#ifdef AFS_CACHING_SUPPORT
struct cachefs_cookie *cache; /* caching cookie */
#endif
wait_queue_head_t update_waitq; /* status fetch waitqueue */
unsigned update_cnt; /* number of outstanding ops that will update the
......@@ -43,10 +61,10 @@ struct afs_vnode
#define AFS_VNODE_MOUNTPOINT 0x00000004 /* set if vnode is a mountpoint symlink */
/* 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_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_expiry; /* callback expiry time */
afs_callback_type_t cb_type; /* type of callback */
......
......@@ -16,7 +16,9 @@
#include <linux/fs.h>
#include <linux/pagemap.h>
#include "volume.h"
#include "vnode.h"
#include "cell.h"
#include "cache.h"
#include "cmservice.h"
#include "fsclient.h"
#include "vlclient.h"
......@@ -24,6 +26,20 @@
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
......@@ -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 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_volume_t *volume = NULL;
afs_cell_t *cell = NULL;
char *cellname, *volname, *suffix;
const char *cellname, *volname, *suffix;
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");
return -EINVAL;
}
......@@ -64,24 +80,22 @@ int afs_volume_lookup(const char *name, int rwparent, afs_volume_t **_volume)
force = 0;
type = AFSVL_ROVOL;
if (rwparent || name[0]=='%') {
if (rwpath || name[0] == '%') {
type = AFSVL_RWVOL;
force = 1;
}
suffix = strrchr(name,'.');
suffix = strrchr(name, '.');
if (suffix) {
if (strcmp(suffix,".readonly")==0) {
if (strcmp(suffix, ".readonly") == 0) {
type = AFSVL_ROVOL;
force = 1;
}
else if (strcmp(suffix,".backup")==0) {
else if (strcmp(suffix, ".backup") == 0) {
type = AFSVL_BACKVOL;
force = 1;
}
else if (suffix[1]==0) {
*suffix = 0;
suffix = NULL;
else if (suffix[1] == 0) {
}
else {
suffix = NULL;
......@@ -90,38 +104,45 @@ int afs_volume_lookup(const char *name, int rwparent, afs_volume_t **_volume)
/* split the cell and volume names */
name++;
volname = strchr(name,':');
volname = strchr(name, ':');
if (volname) {
*volname++ = 0;
cellname = name;
cellnamesz = volname - name;
}
else {
volname = name;
cellname = NULL;
cellnamesz = 0;
}
_debug("CELL:%s VOLUME:%s SUFFIX:%s TYPE:%d%s",
cellname,volname,suffix?:"-",type,force?" FORCE":"");
volnamesz = suffix ? suffix - volname : strlen(volname);
/* lookup the cell record */
ret = afs_cell_lookup(cellname,&cell);
if (ret<0)
printk("kAFS: unable to lookup cell '%s'\n",cellname?:"");
_debug("CELL:%*.*s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s",
cellnamesz, cellnamesz, cellname ?: "", cell,
volnamesz, volnamesz, volname, suffix ?: "-",
type,
force ? " FORCE" : "");
if (cellname) volname[-1] = ':';
if (ret<0)
goto error;
/* lookup the cell record */
if (cellname || !cell) {
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 */
if (suffix) *suffix = 0;
ret = afs_vlocation_lookup(cell,volname,&vlocation);
if (suffix) *suffix = '.';
if (ret<0)
ret = afs_vlocation_lookup(cell, volname, volnamesz, &vlocation);
if (ret < 0)
goto error;
/* make the final decision on the type we want */
ret = -ENOMEDIUM;
if (force && !(vlocation->vldb.vidmask & (1<<type)))
if (force && !(vlocation->vldb.vidmask & (1 << type)))
goto error;
srvtmask = 0;
......@@ -129,13 +150,13 @@ int afs_volume_lookup(const char *name, int rwparent, afs_volume_t **_volume)
srvtmask |= vlocation->vldb.srvtmask[loop];
if (force) {
if (!(srvtmask & (1 <<type)))
if (!(srvtmask & (1 << type)))
goto error;
}
else if (srvtmask & AFSC_VOL_STM_RO) {
else if (srvtmask & AFS_VOL_VTM_RO) {
type = AFSVL_ROVOL;
}
else if (srvtmask & AFSC_VOL_STM_RW) {
else if (srvtmask & AFS_VOL_VTM_RW) {
type = AFSVL_RWVOL;
}
else {
......@@ -156,16 +177,16 @@ int afs_volume_lookup(const char *name, int rwparent, afs_volume_t **_volume)
_debug("creating new volume record");
ret = -ENOMEM;
volume = kmalloc(sizeof(afs_volume_t),GFP_KERNEL);
volume = kmalloc(sizeof(afs_volume_t), GFP_KERNEL);
if (!volume)
goto error_up;
memset(volume,0,sizeof(afs_volume_t));
atomic_set(&volume->usage,1);
volume->type = type;
volume->type_force = force;
volume->cell = cell;
volume->vid = vlocation->vldb.vid[type];
memset(volume, 0, sizeof(afs_volume_t));
atomic_set(&volume->usage, 1);
volume->type = type;
volume->type_force = force;
volume->cell = cell;
volume->vid = vlocation->vldb.vid[type];
init_rwsem(&volume->server_sem);
......@@ -183,15 +204,20 @@ int afs_volume_lookup(const char *name, int rwparent, afs_volume_t **_volume)
}
/* attach the cache and volume location */
#if 0
afs_get_cache(cache); volume->cache = cache;
#ifdef AFS_CACHING_SUPPORT
cachefs_acquire_cookie(vlocation->cache,
&afs_vnode_cache_index_def,
volume,
&volume->cache);
#endif
afs_get_vlocation(vlocation); volume->vlocation = vlocation;
afs_get_vlocation(vlocation);
volume->vlocation = vlocation;
vlocation->vols[type] = volume;
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;
ret = 0;
......@@ -199,18 +225,17 @@ int afs_volume_lookup(const char *name, int rwparent, afs_volume_t **_volume)
error_up:
up_write(&cell->vl_sem);
error:
if (vlocation) afs_put_vlocation(vlocation);
if (cell) afs_put_cell(cell);
afs_put_vlocation(vlocation);
afs_put_cell(cell);
_leave(" = %d (%p)",ret,volume);
_leave(" = %d (%p)", ret, volume);
return ret;
error_discard:
up_write(&cell->vl_sem);
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);
goto error;
......@@ -225,6 +250,9 @@ void afs_put_volume(afs_volume_t *volume)
afs_vlocation_t *vlocation;
int loop;
if (!volume)
return;
_enter("%p",volume);
vlocation = volume->vlocation;
......@@ -246,16 +274,14 @@ void afs_put_volume(afs_volume_t *volume)
up_write(&vlocation->cell->vl_sem);
afs_put_vlocation(vlocation);
/* finish cleaning up the volume */
#if 0
if (volume->cache) afs_put_cache(volume->cache);
#ifdef AFS_CACHING_SUPPORT
cachefs_relinquish_cookie(volume->cache,0);
#endif
afs_put_vlocation(vlocation);
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);
......@@ -428,3 +454,42 @@ int afs_volume_release_fileserver(afs_volume_t *volume, afs_server_t *server, in
return 0;
} /* 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 @@
#include "fsclient.h"
#include "kafstimod.h"
#include "kafsasyncd.h"
#include "cache-layout.h"
#include "cache.h"
#define __packed __attribute__((packed))
......@@ -28,6 +28,43 @@ typedef enum {
} __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
......@@ -36,15 +73,17 @@ struct afs_vlocation
{
atomic_t usage;
struct list_head link; /* link in cell volume location list */
afs_timer_t timeout; /* decaching timer */
afs_cell_t *cell; /* cell to which volume belongs */
struct list_head caches; /* backing caches */
afsc_vldb_record_t vldb; /* volume information DB record */
struct afs_timer timeout; /* decaching timer */
struct afs_cell *cell; /* cell to which volume belongs */
#ifdef AFS_CACHING_SUPPORT
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) */
rwlock_t lock; /* access lock */
unsigned long read_jif; /* time at which last read from vlserver */
afs_timer_t upd_timer; /* update timer */
afs_async_op_t upd_op; /* update operation */
struct afs_timer upd_timer; /* update timer */
struct afs_async_op upd_op; /* update operation */
afs_vlocation_upd_t upd_state; /* update state */
unsigned short upd_first_svix; /* first server index during update */
unsigned short upd_curr_svix; /* current server index during update */
......@@ -53,13 +92,16 @@ struct afs_vlocation
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)
extern void __afs_put_vlocation(afs_vlocation_t *vlocation);
extern void afs_put_vlocation(afs_vlocation_t *vlocation);
extern void afs_vlocation_do_timeout(afs_vlocation_t *vlocation);
extern void __afs_put_vlocation(struct afs_vlocation *vlocation);
extern void afs_put_vlocation(struct afs_vlocation *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);
struct afs_volume
{
atomic_t usage;
afs_cell_t *cell; /* cell to which belongs (unrefd ptr) */
afs_vlocation_t *vlocation; /* volume location */
struct afs_cell *cell; /* cell to which belongs (unrefd ptr) */
struct afs_vlocation *vlocation; /* volume location */
#ifdef AFS_CACHING_SUPPORT
struct cachefs_cookie *cache; /* caching cookie */
#endif
afs_volid_t vid; /* volume ID */
afs_voltype_t __packed type; /* type of volume */
char type_force; /* force volume type (suppress R/O -> R/W) */
unsigned short nservers; /* number of server slots filled */
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 */
};
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)
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 */
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