Subject: afs/fs/cachefs interface.c,NONE,1.1 super.c,1.24,1.25 rootdir.c,1.8,1.9 main.c,1.12,1.13 inode.c,1.15,1.16 index.c,1.13,1.14 cachetest-main.c,1.6,1.7 cachefs-layout.h,1.20,1.21 cachefs-int.h,1.25,1.26 block.c,1.1,1.2 aops.c,1.24,1.25 Makefile,1.14,1.15

From: [email-masked]
Date: Thu, 17 Apr 2003 12:59:06 +0100

Update of /home/cvs/afs/fs/cachefs
In directory phoenix.infradead.org:/tmp/cvs-serv12403/fs/cachefs

Modified Files:
	super.c rootdir.c main.c inode.c index.c cachetest-main.c 
	cachefs-layout.h cachefs-int.h block.c aops.c Makefile 
Added Files:
	interface.c 
Log Message:
wrote first part of proper netfs interface... netfs, index and files can now
be registered with the cache

--- NEW FILE interface.c ---
/* interface.c: network FS interface to cache
 *
 * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
 * Written by David Howells ([email-masked])
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 */

#include <linux/module.h>
#include "cachefs-int.h"

LIST_HEAD(cachefs_netfs_list);
LIST_HEAD(cachefs_cache_list);
DECLARE_RWSEM(cachefs_addremove_sem);

static cachefs_match_val_t cachefs_fsdef_index_match(struct cachefs_object *index,
						     const void *_entry);

static void cachefs_fsdef_index_update(struct cachefs_object *source, void *entry);

static struct cachefs_index_def cachefs_fsdef_index_def = {
	.name		= ".fsdef",
	.data_size	= sizeof(struct cachefs_ondisc_fsdef),
	.match		= cachefs_fsdef_index_match,
	.update		= cachefs_fsdef_index_update
};

static struct cachefs_object cachefs_fsdef_index = {
	.idef		= &cachefs_fsdef_index_def,
	.sem		= __RWSEM_INITIALIZER(cachefs_fsdef_index.sem),
	.active_inodes	= LIST_HEAD_INIT(cachefs_fsdef_index.active_inodes),
};

/* number expected in cachefs_file::numactive */
static int cachefs_num_active_inodes;

/*****************************************************************************/
/*
 * register a network filesystem for caching
 */
int cachefs_register_netfs(struct cachefs_netfs *netfs)
{
	struct cachefs_netfs *ptr;
	int ret;

	kenter("{%s}",netfs->name);

	INIT_LIST_HEAD(&netfs->link);

	INIT_LIST_HEAD(&netfs->primary_index.active_inodes);
	init_rwsem(&netfs->primary_index.sem);

	netfs->primary_index.iparent = &cachefs_fsdef_index;

	/* check it's not already present */
	down_write(&cachefs_addremove_sem);

	ret = -EEXIST;
	list_for_each_entry(ptr,&cachefs_netfs_list,link) {
		if (strcmp(ptr->name,netfs->name)==0)
			goto error;
	}

	list_add(&netfs->link,&cachefs_netfs_list);
	ret = 0;

 error:
	up_write(&cachefs_addremove_sem);

	kleave(" = %d",ret);
	return ret;
} /* end cachefs_register_netfs() */

EXPORT_SYMBOL(cachefs_register_netfs);

/*****************************************************************************/
/*
 * unregister a network filesystem from the cache
 */
void cachefs_unregister_netfs(struct cachefs_netfs *netfs)
{
	kenter("{%s.%u}",netfs->name,netfs->version);

	down_write(&cachefs_addremove_sem);

	list_del(&netfs->link);

	cachefs_unregister_object(&netfs->primary_index,0);

	up_write(&cachefs_addremove_sem);

	kleave("");
} /* end cachefs_unregister_netfs() */

EXPORT_SYMBOL(cachefs_unregister_netfs);

/*****************************************************************************/
/*
 * declare a mounted cache as being open for business
 * - we don't want to do any memory allocation here, lest we have to try and free super on error
 */
void cachefs_add_cache(struct cachefs_super *super, struct cachefs_active_inode *active)
{
	unsigned long flags;

	printk("\n\n\n");
	kenter("");

	/* prepare an active-inode record for the FSDEF index of this cache */
	atomic_set(&active->usage,2);

	active->super	= super;
	active->ino	= CACHEFS_INO_FSDEF_CATALOGUE;
	active->flags	= (1 << CACHEFS_ACTIVE_INODE_ISINDEX | 1 << CACHEFS_ACTIVE_INODE_LIVE);
	active->storage	= NULL;
	active->object	= &cachefs_fsdef_index;

	init_waitqueue_head(&active->initwq);

	/* actually do the stuff */
	down_write(&cachefs_addremove_sem);

	list_add(&super->mnt_link,&cachefs_cache_list);

	up_write(&cachefs_addremove_sem);

	write_lock_irqsave(&super->ino_tree_lock,flags);
	rb_link_node(&active->node,NULL,&super->ino_tree.rb_node);
	rb_insert_color(&active->node,&super->ino_tree);
	write_unlock_irqrestore(&super->ino_tree_lock,flags);

	down_write(&cachefs_fsdef_index.sem);
	list_add_tail(&active->link,&cachefs_fsdef_index.active_inodes);
	up_write(&cachefs_fsdef_index.sem);

	cachefs_num_active_inodes++;

	kleave("");
} /* end cachefs_add_cache() */

/*****************************************************************************/
/*
 * remove an unmounted cache from the list
 */
void cachefs_del_cache(struct cachefs_super *super)
{
	kenter("");

	down_write(&cachefs_addremove_sem);

	BUG();

	list_del_init(&super->mnt_link);

	up_write(&cachefs_addremove_sem);

	kleave("");
} /* end cachefs_del_cache() */

/*****************************************************************************/
/*
 * look the object up in the specified cache
 * - the specified object must be write-locked by the caller
 * - an inode is created on disc if not present if "create" is true
 *   - all parent index objects are created if necessary
 * - returns -ENODATA if the object doesn't exist and "create" is false
 */
static int cachefs_lookup_object(struct cachefs_object *object,
				 struct cachefs_super *super,
				 int create)
{
	struct cachefs_active_inode *ipactive, *active, *xactive;
	struct cachefs_object *iparent;
	struct rb_node *parent, **p;
	unsigned long flags;
	int ret;

	iparent = object->iparent;
	if (!iparent) return 0; /* FSDEF entries don't have a parent */

	kenter("{%s/%s},",iparent->idef->name,object->idef ? (char*)object->idef->name : "<file>");

	/* see if there's an entry for this object already */
	list_for_each_entry(active,&object->active_inodes,link) {
		kdebug("check entry %p x %p [ino %u]",object,super,active->ino);

		if (active->super==super) {
			kdebug("found entry");
			if (active->ino) {
				kleave(" = 0 [found ino %u]",active->ino);
				return 0;
			}

			/* entry is negative */
			if (!create)
				goto nodata;

			goto found_entry;
		}
	}

	/* allocate an entry for this object */
	kdebug("alloc entry %p x %p",object,super);

	active = kmalloc(sizeof(*active),GFP_KERNEL);
	if (!active) {
		kleave(" = -ENOMEM");
		return -ENOMEM;
	}

	active->super	= super;
	active->ino	= 0;
	active->flags	= 1 << CACHEFS_ACTIVE_INODE_LIVE;
	active->storage	= NULL;
	active->object	= object;

	if (object->idef)
		active->flags |= 1 << CACHEFS_ACTIVE_INODE_ISINDEX;

	atomic_set(&active->usage,1);
	INIT_LIST_HEAD(&active->link);
	init_waitqueue_head(&active->initwq);

 found_entry:
	/* we need to insert an entry for this object in the object's parent index, so the first
	 * thing to do is to see if the parent index is represented on disc, and if not, create it
	 * if necessary
	 */
	down_write(&iparent->sem);

	ret = cachefs_lookup_object(iparent,super,create);
	if (ret<0) {
		if (ret==-ENODATA) {
			/* set a negative entry */
			list_add_tail(&active->link,&object->active_inodes);
		}

		up_write(&iparent->sem);
		goto error2;
	}

	/* it should now be present - find it */
	list_for_each_entry(ipactive,&iparent->active_inodes,link) {
		if (ipactive->super==super && ipactive->ino)
			goto found_parent_entry;
	}

	BUG();

 found_parent_entry:
	kdebug("found_parent_entry");

	/* we only need a read-lock on the parent for the rest of this */
	downgrade_write(&iparent->sem);

	/* search the parent index for a reference compatible with this object */
	ret = cachefs_index_search(ipactive,active);
	switch (ret) {
	default:	goto error;
	case 0:		goto add_to_active_tree;

	case -ENOENT:
		/* we can at least set a valid negative entry */
		list_add_tail(&active->link,&object->active_inodes);

		if (!create) {
			up_read(&iparent->sem);
			goto nodata;
		}

		/* we need to add the object to the index */
		ret = cachefs_index_add(ipactive,active);
		if (ret<0)
			goto error;
		break;
	}

	/* add the inode to the active tree */
 add_to_active_tree:
	kdebug("add_to_active_tree");

	parent = NULL;

	atomic_inc(&active->usage);

	write_lock_irqsave(&super->ino_tree_lock,flags);

	p = &super->ino_tree.rb_node;
	while (*p) {
		parent = *p;
		xactive = rb_entry(parent,struct cachefs_active_inode,node);

		if (active->ino < xactive->ino)
			p = &(*p)->rb_left;
		else if (active->ino > xactive->ino)
			p = &(*p)->rb_right;
		else
			BUG();
	}

	rb_link_node(&active->node,parent,p);
	rb_insert_color(&active->node,&super->ino_tree);

	write_unlock_irqrestore(&super->ino_tree_lock,flags);

	up_read(&iparent->sem);
	kleave(" = 0");
	return 0;

 error:
	up_read(&iparent->sem);
 error2:
	if (list_empty(&active->link)) kfree(active);
	kleave(" = %d",ret);
	return ret;

 nodata:
	kleave(" = -ENODATA");
	return -ENODATA;

} /* end cachefs_lookup_object() */

/*****************************************************************************/
/*
 * select a cache on which to store a file
 * - the cache addremove semaphore must be at least read-locked by the caller
 */
static struct cachefs_super *cachefs_select_cache_for_file(void)
{
	struct cachefs_super *super;

	kenter("");

	super = NULL;
	if (!list_empty(&cachefs_cache_list))
		super = list_entry(cachefs_cache_list.next,struct cachefs_super,mnt_link);

	kleave(" = %p",super);
	return super;
} /* end cachefs_select_cache_for_file() */

/*****************************************************************************/
/*
 * register an object
 * - all attached caches will be searched to see if they contain this object
 * - index objects aren't stored on disc until there's a dependent file that needs storing
 * - file objects are stored in a selected cache immediately, and all the indexes forming the path
 *   to it are instantiated if necessary
 */
int cachefs_register_object(struct cachefs_object *object)
{
	struct cachefs_active_inode *active;
	struct cachefs_super *super;
	struct list_head *_p, *_n;
	int ret = 0;

	kenter("{%s}",object->idef?(char*)object->idef->name:"<file>");

	INIT_LIST_HEAD(&object->active_inodes);
	init_rwsem(&object->sem);

	down_read(&cachefs_addremove_sem);
	if (list_empty(&cachefs_cache_list)) {
		up_read(&cachefs_addremove_sem);
		kleave(" = 0 [no caches]");
		return 0;
	}

	down_write(&object->sem);

	/* search every cache to see if the object is already present */
	list_for_each_entry(super,&cachefs_cache_list,mnt_link) {
		ret = cachefs_lookup_object(object,super,0);
		switch (ret) {
		case 0:
			if (!object->idef)
				break;	/* only want the first file entry */
		case -ENODATA:
			continue;
		default:
			goto error;
		}
	}

	/* if this object is a file, select a cache on which to store it */
	if (!object->idef) {
		super = cachefs_select_cache_for_file();

		/* we don't want to keep any negative records for a file other than the one for the
		 * chosen superblock (which we'll turn into a positive entry)
		 */
		list_for_each_safe(_p,_n,&object->active_inodes) {
			active = list_entry(_p,struct cachefs_active_inode,link);
			if (active->super==super || active->ino==0) {
				list_del(&active->link);
				kfree(active);
			}
		}

		ret = 0;
		if (!super)
			goto error; /* couldn't decide on a cache */

		/* instantiate the file */
		ret = cachefs_lookup_object(object,super,1);
		switch (ret) {
		case 0:		break;
		case -ENODATA:	BUG();
		default:	goto error;
		}
	}

	/* the caller shouldn't see the fact that we don't have any attached inodes yet */
	if (ret==-ENODATA) ret = 0;

 error:
	up_write(&object->sem);
	up_read(&cachefs_addremove_sem);

	kleave(" = %d",ret);
	return ret;
} /* end cachefs_register_object() */

EXPORT_SYMBOL(cachefs_register_object);

/*****************************************************************************/
/*
 * unregister an object from the cache
 * - the object will be marked as recyclable on disc if retire is true
 */
void cachefs_unregister_object(struct cachefs_object *object, int retire)
{
	kenter("{%s},%d",object->idef?(char*)object->idef->name:"<file>",retire);

	BUG();

} /* end cachefs_unregister_object() */

EXPORT_SYMBOL(cachefs_unregister_object);

/*****************************************************************************/
/*
 * see if the netfs definition matches
 */
static cachefs_match_val_t cachefs_fsdef_index_match(struct cachefs_object *index,
						     const void *_entry)
{
	const struct cachefs_ondisc_fsdef *fsdef = _entry;
	struct cachefs_netfs *netfs = container_of(index,struct cachefs_netfs,primary_index);

	kenter("{%s.%u},{%s.%u}",
	       netfs->name,netfs->version,
	       fsdef->name,fsdef->version);

	if (strncmp(netfs->name,fsdef->name,sizeof(fsdef->name))!=0) {
		kleave(" = FAILED");
		return CACHEFS_MATCH_FAILED;
	}

	if (netfs->version==fsdef->version) {
		kleave(" = SUCCESS");
		return CACHEFS_MATCH_SUCCESS;
	}

	kleave(" = SUCCESS_DELETE");
	return CACHEFS_MATCH_SUCCESS_DELETE;
} /* end cachefs_fsdef_index_match() */

/*****************************************************************************/
/*
 * update the netfs definition to be stored on disc
 */
static void cachefs_fsdef_index_update(struct cachefs_object *source, void *entry)
{
	struct cachefs_ondisc_fsdef *fsdef = entry;
	struct cachefs_netfs *netfs = container_of(source,struct cachefs_netfs,primary_index);

	kenter("{%s.%u},",netfs->name,netfs->version);

	strncpy(fsdef->name,netfs->name,sizeof(fsdef->name));

	fsdef->version = netfs->version;

} /* end cachefs_fsdef_index_update() */

Index: super.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/super.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -r1.24 -r1.25
--- super.c	2 Apr 2003 09:12:31 -0000	1.24
+++ super.c	17 Apr 2003 11:59:03 -0000	1.25
@@ -49,7 +49,6 @@
 	.statfs		= cachefs_statfs,
 	.alloc_inode	= cachefs_alloc_inode,
 	.write_inode	= cachefs_write_inode,
-	.drop_inode	= generic_delete_inode,
 	.destroy_inode	= cachefs_destroy_inode,
 	.clear_inode	= cachefs_clear_inode,
 	.write_super	= cachefs_write_super,
@@ -119,16 +118,29 @@
 					  char *dev_name,
 					  void *options)
 {
+	struct cachefs_active_inode *active;
 	struct super_block *sb;
 
 	_enter(",,%s,%p",dev_name,options);
 
+	/* pre-allocate an active-inode record for the FSDEF index of this cache
+	 * - we don't want to have to try and get rid of the superblock due to an error after
+	 *   we've got it
+	 */
+	active = kmalloc(sizeof(*active),GFP_KERNEL);
+	if (!active) {
+		kleave(" = -ENOMEM");
+		return ERR_PTR(-ENOMEM);
+	}
+
 	/* allocate a device superblock */
 	sb = get_sb_bdev(fs_type,flags,dev_name,options,cachefs_fill_super);
 
 	/* if successful add to the list of available caches */
 	if (!IS_ERR(sb) && sb->s_fs_info)
-		cachefs_add_cache((struct cachefs_super *)sb->s_fs_info);
+		cachefs_add_cache((struct cachefs_super *)sb->s_fs_info,active);
+	else
+		kfree(active);
 
 	_leave(" = %p",sb);
 	return sb;
@@ -260,7 +272,6 @@
 	super->ujnl_step	= bdev_hardsect_size(super->sb->s_bdev);
 
 	INIT_LIST_HEAD(&super->mnt_link);
-	INIT_LIST_HEAD(&super->cross_indexes);
 
 	rwlock_init(&super->blk_tree_lock);
 
@@ -297,12 +308,7 @@
 	init_completion(&super->dmn_dead);
 	init_waitqueue_head(&super->dmn_sleepq);
 
-	/* initialise the fsdef index */
-	ret = cachefs_generate_cross_index(super,&cachefs_fsdef,&super->fsdef_index);
-	if (ret<0)
-		goto error;
-
-	super->fsdef_index->entry_id	= UINT_MAX;
+	rwlock_init(&super->ino_tree_lock);
 
 	/* create the linear-mapping inode */
 	ret = cachefs_iget(super,CACHEFS_INO_MISC,&inode2);
@@ -408,7 +414,6 @@
 			wait_for_completion(&super->dmn_dead);
 		}
 
-		if (super->fsdef_index)		kfree(super->fsdef_index);
 		if (super->alloc_node)		page_cache_release(super->alloc_node);
 		if (super->recycle_node)	page_cache_release(super->recycle_node);
 		if (super->rcm_atm_list)	free_page((unsigned long)super->rcm_atm_list);
@@ -697,9 +702,6 @@
 	wake_up(&super->dmn_sleepq);
 	wait_for_completion(&super->dmn_dead);
 
-	if (super->fsdef_index)
-		kfree(super->fsdef_index);
-
 	if (super->alloc_node) {
 		dbgpgfree(super->alloc_node);
 		page_cache_release(super->alloc_node);
@@ -770,8 +772,6 @@
 
 	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) {
 		memset(inode,0,sizeof(*inode));
-		INIT_LIST_HEAD(&inode->index_link);
-		INIT_LIST_HEAD(&inode->cache_link);
 		inode_init_once(&inode->vfs_inode);
 	}

Index: rootdir.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/rootdir.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- rootdir.c	2 Apr 2003 09:12:31 -0000	1.8
+++ rootdir.c	17 Apr 2003 11:59:04 -0000	1.9
@@ -71,9 +71,9 @@
 	unsigned char *ptr;
 	void *content;
 	char *name;
-	int loop, ret;
+	int loop, ret, type;
 
-	kenter(",{%lu},%lu,%lu",page->index,offset,size);
+	_enter(",{%lu},%lu,%lu",page->index,offset,size);
 
 	rec = (struct cachefs_readdir_record *) desc->buf;
 
@@ -120,7 +120,7 @@
 		for (loop=0; loop<4; loop++) {
 			int ksize = rec->keys[loop] & CACHEFS_ONDISC_INDEXKEY_KLEN;
 
-			kdebug("- key %04hx",rec->keys[loop]);
+			_debug("- key %04hx",rec->keys[loop]);
 
 			if (loop>0) *name++ = ',';
 
@@ -161,7 +161,7 @@
 
 		tmp = rec->dpos_off + (page->index * rec->epp) + offset/rec->esize;
 
-		kdebug("dirent: %d '%s' ino=%u",name-rec->scratch,rec->scratch,xent->ino);
+		_debug("dirent: %d '%s' ino=%u",name-rec->scratch,rec->scratch,xent->ino);
 
 		if (name == rec->scratch) {
 			desc->count	-= rec->esize;
@@ -170,12 +170,16 @@
 			continue;
 		}
 
+		type = DT_REG;
+		if (xent->type==CACHEFS_ONDISC_INDEX_INDEXFILE)
+			type = DT_DIR;
+
 		if (rec->filldir(rec->cookie,
 				 rec->scratch,
 				 name - rec->scratch,
 				 tmp,
 				 xent->ino,
-				 DT_DIR)<0
+				 type)<0
 		    ) {
 			desc->count = 0;
 			goto done;
@@ -194,7 +198,7 @@
 	kunmap(page);
 
  done_already:
-	kleave(" = %d",ret);
+	_leave(" = %d",ret);
 	return ret;
 } /* end cachefs_readdir_actor() */
 
@@ -214,7 +218,7 @@
 
 	inode = CACHEFS_FS_I(file->f_dentry->d_inode);
 
-	kenter("{%Ld,{%lu}}",file->f_pos,inode->vfs_inode.i_ino);
+	_enter("{%Ld,{%lu}}",file->f_pos,inode->vfs_inode.i_ino);
 
 	rec.scratch = (char*) get_zeroed_page(GFP_KERNEL);
 	dbgpgalloc(rec.scratch);
@@ -286,7 +290,7 @@
 		desc.buf	= (char*) &rec;
 		desc.error	= 0;
 
-		kdebug("do read: isz=%llu pos=%llu count=%u",
+		_debug("do read: isz=%llu pos=%llu count=%u",
 		       inode->vfs_inode.i_size,pos,desc.count);
 
 		do_generic_file_read(file,&pos,&desc,cachefs_readdir_actor);
@@ -295,7 +299,7 @@
 		file->f_pos += ((unsigned)(pos & ~PAGE_MASK) + rec.esize - 1) / rec.esize;
 		file->f_pos += rec.dpos_off;
 
-		kdebug("done read: err=%d pos=%llu fpos=%llu",desc.error,pos,file->f_pos);
+		_debug("done read: err=%d pos=%llu fpos=%llu",desc.error,pos,file->f_pos);
 
 		ret = desc.error;
 		if (ret<0)
@@ -308,7 +312,7 @@
  error:
 	dbgpgfree(rec.scratch);
 	free_page((unsigned long) rec.scratch);
-	kleave(" = %d",ret);
+	_leave(" = %d",ret);
 	return ret;
 } /* end cachefs_root_readdir() */
 
@@ -327,7 +331,7 @@
 	void *content;
 	int ret;
 
-	kenter(",{%lu},%lu,%lu",page->index,offset,size);
+	_enter(",{%lu},%lu,%lu",page->index,offset,size);
 
 	rec = (struct cachefs_lookup_record *) desc->buf;
 	ret = size;
@@ -372,7 +376,7 @@
 	desc->count -= ret;
 	desc->written += ret;
 
-	kleave(" = %d",ret);
+	_leave(" = %d",ret);
 	return ret;
 } /* end cachefs_lookup_actor() */
 
@@ -397,7 +401,7 @@
 	dir = CACHEFS_FS_I(_dir);
 	name = dentry->d_name.name;
 
-	kenter("{%lu},{%s}",dir->vfs_inode.i_ino,name);
+	_enter("{%lu},{%s}",dir->vfs_inode.i_ino,name);
 
 	rec.key		= NULL;
 	rec.esize	= dir->index_esize;
@@ -487,7 +491,7 @@
 					goto not_found;
 				x = isdigit(*name) ? *name-'0' : toupper(*name)-'A'+10;
 				name++;
-				x <<= 0x10;
+				x <<= 4;
 
 				if (!isxdigit(*name))
 					goto not_found;
@@ -576,7 +580,7 @@
 	ret = -ENOENT;
  error:
 	if (rec.key) free_page((unsigned long) rec.key);
-	kleave(" = %d",ret);
+	_leave(" = %d",ret);
 	return ERR_PTR(ret);
 
 	/* get the inode */
@@ -585,14 +589,14 @@
  get:
 	ret = cachefs_iget(dir->vfs_inode.i_sb->s_fs_info,ino,&target);
 	if (ret<0) {
-		kleave(" = %d",ret);
+		_leave(" = %d",ret);
 		return ERR_PTR(ret);
 	}
 
 	/* instantiate the dentry */
  instantiate:
 	d_add(dentry,&target->vfs_inode);
-	kleave(" = NULL");
+	_leave(" = NULL");
 	return NULL;
 } /* end cachefs_root_lookup() */
 
@@ -609,11 +613,11 @@
 	unsigned long flags;
 	int ret;
 
-	kenter("{%lx},{%s,%p}",dir->i_ino,dentry->d_name.name,dentry->d_inode);
+	_enter("{%lx},{%s,%p}",dir->i_ino,dentry->d_name.name,dentry->d_inode);
 
 	if (!dentry->d_inode) {
 		printk("&&& no inode &&&\n");
-		kleave(" = -ENOANO");
+		_leave(" = -ENOANO");
 		return -ENOANO;
 	}
 
@@ -622,7 +626,7 @@
 	/* mark for reclamation under journalling */
 	trans = cachefs_trans_alloc(super,GFP_KERNEL);
 	if (!trans) {
-		kleave(" = -ENOMEM");
+		_leave(" = -ENOMEM");
 		return -ENOMEM;
 	}
 
@@ -634,7 +638,7 @@
 	ret = cachefs_trans_mark(trans);
 	if (ret<0) {
 		cachefs_trans_put(trans);
-		kleave(" = %d",ret);
+		_leave(" = %d",ret);
 		return ret;
 	}
 
@@ -661,6 +665,6 @@
 	set_bit(CACHEFS_SUPER_DO_RECLAIM,&super->flags);
 	wake_up(&super->dmn_sleepq);
 
-	kleave(" = 0");
+	_leave(" = 0");
 	return 0;
 } /* end cachefs_root_rmdir_unlink() */

Index: main.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/main.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- main.c	7 Mar 2003 23:53:38 -0000	1.12
+++ main.c	17 Apr 2003 11:59:04 -0000	1.13
@@ -16,17 +16,6 @@
 #include <linux/slab.h>
 #include "cachefs-int.h"
 
-struct cell_data {
-	u_int8_t	name[64];
-	u_int32_t	servers[15];
-} cell_data = { "cambridge.redhat.com", { 0x12345678, 0x11223344 } };
-
-static struct cachefs_index cachetest_vldb = {
-	.name		= "vldb",
-	.data_size	= 124,
-	.keys[0]	= { CACHEFS_INDEX_KEYS_ASCIIZ, 64 },
-};
-
 int cachefs_debug = 0;
 
 static int cachefs_init(void);
@@ -39,78 +28,6 @@
 MODULE_AUTHOR("Red Hat, Inc.");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(cachefs_register_netfs);
-EXPORT_SYMBOL(cachefs_unregister_netfs);
-
-static LIST_HEAD(cachefs_netfs_list);
-static rwlock_t cachefs_netfs_list_lock = RW_LOCK_UNLOCKED;
-static LIST_HEAD(cachefs_cache_list);
-static rwlock_t cachefs_cache_list_lock = RW_LOCK_UNLOCKED;
-static DECLARE_RWSEM(cachefs_addremove_sem);
-
-static void cachefs_mesh_cache_and_netfs(struct cachefs_super *super, struct cachefs_netfs *netfs);
-
-static void cachefs_unmesh_cache_and_netfs(struct cachefs_super *super,
-					   struct cachefs_netfs *netfs);
-
-static int cachefs_fsdef_index_match(const void *_entry, const void *_data);
-
-struct cachefs_netfs cachefs_fsdef = {
-	.name		= "CacheFS",
-	.version	= 1,
-	.link		= LIST_HEAD_INIT(cachefs_fsdef.link),
-};
-
-struct cachefs_index cachefs_fsdef_index = {
-	.name		= "FSDEF",
-	.data_size	= sizeof(struct cachefs_ondisc_fsdef),
-};
-
-/*****************************************************************************/
-/*
- * clear the dead space between task_struct and kernel stack
- * - called by supplying -finstrument-functions to gcc
- */
-#if 1
-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
-
 /*****************************************************************************/
 /*
  * initialise the fs caching module
@@ -153,318 +70,45 @@
 
 /*****************************************************************************/
 /*
- * register a network filesystem for caching
- */
-int cachefs_register_netfs(struct cachefs_netfs *netfs)
-{
-	struct cachefs_super *super;
-	struct cachefs_netfs *ptr;
-	struct list_head *_p;
-	unsigned long flags;
-	int ret;
-
-	kenter("{%s}",netfs->name);
-
-	INIT_LIST_HEAD(&netfs->link);
-	INIT_LIST_HEAD(&netfs->cross_indexes);
-
-	/* check it's not already there */
-	down_write(&cachefs_addremove_sem);
-
-	ret = -EEXIST;
-	read_lock_irqsave(&cachefs_netfs_list_lock,flags);
-	list_for_each(_p,&cachefs_netfs_list) {
-		ptr = list_entry(_p,struct cachefs_netfs,link);
-		if (strcmp(ptr->name,netfs->name)==0)
-			break;
-	}
-	if (_p==&cachefs_netfs_list)
-		ret = 0;
-	read_unlock_irqrestore(&cachefs_netfs_list_lock,flags);
-
-	if (ret==0) {
-		write_lock_irqsave(&cachefs_netfs_list_lock,flags);
-		list_add(&netfs->link,&cachefs_netfs_list);
-		write_unlock_irqrestore(&cachefs_netfs_list_lock,flags);
-
-		/* prepare the netfs for caching on every cache we know about already
-		 * - don't need to lock the caches list as it can only be changed by someone
-		 *   holding the addremove sem, and we've got a write lock on that
-		 */
-		list_for_each(_p,&cachefs_cache_list) {
-			super = list_entry(_p,struct cachefs_super,mnt_link);
-			cachefs_mesh_cache_and_netfs(super,netfs);
-		}
-	}
-
-	up_write(&cachefs_addremove_sem);
-
-	kleave(" = %d",ret);
-	return ret;
-} /* end cachefs_register_netfs() */
-
-/*****************************************************************************/
-/*
- * unregister a network filesystem from the cache
- */
-void cachefs_unregister_netfs(struct cachefs_netfs *netfs)
-{
-	struct cachefs_super *super;
-	struct list_head *_p;
-	unsigned long flags;
-
-	kenter("{%s}",netfs->name);
-
-	down_write(&cachefs_addremove_sem);
-
-	list_for_each(_p,&cachefs_cache_list) {
-		super = list_entry(_p,struct cachefs_super,mnt_link);
-		cachefs_unmesh_cache_and_netfs(super,netfs);
-	}
-
-	write_lock_irqsave(&cachefs_netfs_list_lock,flags);
-	list_del_init(&netfs->link);
-	write_unlock_irqrestore(&cachefs_netfs_list_lock,flags);
-
-	up_write(&cachefs_addremove_sem);
-
-	kleave("");
-} /* end cachefs_unregister_fs() */
-
-/*****************************************************************************/
-/*
- * generate an internal cross-index block from a netfs definition
- */
-int cachefs_generate_cross_index(struct cachefs_super *super,
-				 struct cachefs_netfs *netfs,
-				 struct cachefs_cross_index **_cross)
-{
-	struct cachefs_cross_index *cross;
-
-	kenter(",%s,",netfs->name);
-
-	cross = kmalloc(sizeof(struct cachefs_cross_index),GFP_KERNEL);
-	if (!cross) {
-		kleave(" = -ENOMEM");
-		return -ENOMEM;
-	}
-	memset(cross,0,sizeof(*cross));
-
-	cross->netfs = netfs;
-	cross->super = super;
-
-	INIT_LIST_HEAD(&cross->netfs_link);
-	INIT_LIST_HEAD(&cross->super_link);
-
-	memcpy(cross->layout.name,netfs->name,sizeof(cross->layout.name));
-
-	cross->layout.version		= netfs->version;
-
-	*_cross = cross;
-	kleave(" = 0 [%p]",*_cross);
-	return 0;
-} /* end cachefs_generate_cross_index() */
-
-/*****************************************************************************/
-/*
- * make sure a cache and a filesystem are cross-linked
- * - the addremove semaphore must be held write-locked by the caller
- */
-static void cachefs_mesh_cache_and_netfs(struct cachefs_super *super, struct cachefs_netfs *netfs)
-{
-	struct cachefs_cross_index *cross;
-	int ret;
-
-	kenter("%p,{%s}",super,netfs->name);
-
-	ret = cachefs_generate_cross_index(super,netfs,&cross);
-	if (ret<0) {
-		printk("CacheFS: Couldn't generate cross-index: %d\n",ret);
-		return;
-	}
-
-	/* TODO: see if the cache already knows about this filesystem */
-	ret = cachefs_index_search(super->fsdef_index,
-				   CACHEFS_INO_FSDEF_CATALOGUE,
-				   cachefs_fsdef_index_match,
-				   &cross->layout);
-	if (ret<0) {
-		struct cachefs_ondisc_fsdef data;
-
-		if (ret!=-ENOENT) {
-			printk("CacheFS: Couldn't scan fsdef catalogue: %d\n",ret);
-			goto error;
-		}
-
-		kdebug("FSDEF entry not in cache");
-
-		memset(&data,0,sizeof(data));
-		strncpy(data.name,netfs->name,sizeof(data.name));
-		data.version = netfs->version;
-
-		ret = cachefs_index_add(super,CACHEFS_INO_FSDEF_CATALOGUE,netfs->primary,&data);
-		if (ret<0) {
-			printk("CacheFS: Couldn't add fsdef to catalogue: %d\n",ret);
-			goto error;
-		}
-		kdebug("FSDEF entry added to cache at %d\n",ret);
-
-		int cell = cachefs_index_add(super,ret,&cachetest_vldb,&cell_data);
-		if (cell<0) {
-			printk("CacheFS: Couldn't add CELL to catalogue: %d\n",cell);
-			ret = cell;
-			goto error;
-		}
-		kdebug("CELL entry added to cache at %d\n",cell);
-
-	}
-	else {
-		kdebug("FSDEF entry in cache at %d",ret);
-	}
-
-	/* polish off the definitions */
-	cross->entry_id	= ret;
-
-	write_lock(&cachefs_netfs_list_lock);
-	write_lock(&cachefs_cache_list_lock);
-
-	list_add(&cross->netfs_link,&netfs->cross_indexes);
-	list_add(&cross->super_link,&super->cross_indexes);
-
-	write_unlock(&cachefs_cache_list_lock);
-	write_unlock(&cachefs_netfs_list_lock);
-
-	kleave("");
-	return;
-
- error:
-	kfree(cross);
-	kleave(" [error %d]",ret);
-} /* end cachefs_mesh_cache_and_netfs() */
-
-/*****************************************************************************/
-/*
- * disassociate a cache and a filesystem
- * - the addremove semaphore must be held write-locked by the caller
- */
-static void cachefs_unmesh_cache_and_netfs(struct cachefs_super *super,
-					   struct cachefs_netfs *netfs)
-{
-	struct cachefs_cross_index *cross;
-	struct list_head *_p;
-
-	kenter("");
-
-	/* find and unlink the cross-bonding record */
-	cross = NULL;
-	write_lock(&cachefs_netfs_list_lock);
-	write_lock(&cachefs_cache_list_lock);
-
-	list_for_each(_p,&super->cross_indexes) {
-		cross = list_entry(_p,struct cachefs_cross_index,super_link);
-		if (cross->super==super)
-			break;
-	}
-
-	if (_p==&super->cross_indexes) {
-		cross = NULL;
-	}
-	else {
-		list_del_init(&cross->netfs_link);
-		list_del_init(&cross->super_link);
-	}
-
-	write_unlock(&cachefs_cache_list_lock);
-	write_unlock(&cachefs_netfs_list_lock);
-
-	if (!cross) {
-		kleave(" [unattached]");
-		return;
-	}
-
-	dbgfree(cross);
-	kfree(cross);
-
-	kleave("");
-} /* end cachefs_unmesh_cache_and_netfs() */
-
-/*****************************************************************************/
-/*
- * add a freshly mounted cache to the list
+ * clear the dead space between task_struct and kernel stack
+ * - called by supplying -finstrument-functions to gcc
  */
-void cachefs_add_cache(struct cachefs_super *super)
-{
-	struct cachefs_netfs *netfs;
-	struct list_head *_p;
-
-	printk("\n\n\n");
-	kenter("");
-
-	down_write(&cachefs_addremove_sem);
-
-	list_add(&super->mnt_link,&cachefs_cache_list);
-
-	/* prepare the newly mounted cache for caching every cacheable fs we know about already
-	 * - don't need to lock the fsdefs list as it can only be changed by someone holding the
-	 *   addremove sem, and we've got a write lock on that
-	 */
-	list_for_each(_p,&cachefs_netfs_list) {
-		netfs = list_entry(_p,struct cachefs_netfs,link);
-		cachefs_mesh_cache_and_netfs(super,netfs);
-	}
-
-	up_write(&cachefs_addremove_sem);
-
-	kleave("");
-} /* end cachefs_add_cache() */
+#if 1
+void __cyg_profile_func_enter (void *this_fn, void *call_site)
+__attribute__((no_instrument_function));
 
-/*****************************************************************************/
-/*
- * remove an unmounted cache from the list
- */
-void cachefs_del_cache(struct cachefs_super *super)
+void __cyg_profile_func_enter (void *this_fn, void *call_site)
 {
-	struct cachefs_netfs *netfs;
-	struct list_head *_p;
-
-	kenter("");
-
-	down_write(&cachefs_addremove_sem);
-
-	list_for_each(_p,&cachefs_netfs_list) {
-		netfs = list_entry(_p,struct cachefs_netfs,link);
-		cachefs_unmesh_cache_and_netfs(super,netfs);
-	}
-
-	list_del_init(&super->mnt_link);
-
-	up_write(&cachefs_addremove_sem);
+       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"
+                    );
+}
 
-	kleave("");
-} /* end cachefs_del_cache() */
+void __cyg_profile_func_exit(void *this_fn, void *call_site)
+__attribute__((no_instrument_function));
 
-/*****************************************************************************/
-/*
- * see if a file definition entry matches a key
- */
-static int cachefs_fsdef_index_match(const void *_entry, const void *_data)
+void __cyg_profile_func_exit(void *this_fn, void *call_site)
 {
-	const struct cachefs_ondisc_fsdef *entry = _entry;
-	const struct cachefs_ondisc_fsdef *data = _data;
-	int ret;
-
-	kenter("");
-
-	ret = 0;
-	if (entry->name[0]) {
-		if (memcmp(entry->name,data->name,sizeof(entry->name))==0) {
-			ret = 1;
-
-			if (memcmp(entry,data,sizeof(entry))!=0)
-				ret = 2; /* incompatible layout */
-		}
-	}
-
-	kleave(" = %d",ret);
-	return ret;
-} /* end cachefs_fsdef_index_match() */
+       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

Index: inode.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/inode.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- inode.c	21 Mar 2003 14:01:01 -0000	1.15
+++ inode.c	17 Apr 2003 11:59:04 -0000	1.16
@@ -202,7 +202,7 @@
 
 	storage = kmap(inode->storage) + inode->storage_offset;
 
-	inode->vfs_inode.i_mode		= S_IFREG | S_IRUGO | S_IWUSR;
+	inode->vfs_inode.i_mode		= S_IFREG | S_IRUGO;
 	inode->vfs_inode.i_uid		= 0;
 	inode->vfs_inode.i_gid		= 0;
 	inode->vfs_inode.i_nlink	= 1;
@@ -228,6 +228,7 @@
 	if (inode->index_esize || inode->vfs_inode.i_ino==CACHEFS_INO_ROOTDIR) {
 		inode->index_epp = PAGE_SIZE / storage->index_esize;
 		inode->vfs_inode.i_mode		= S_IFDIR | S_IRUGO | S_IXUGO;
+		inode->vfs_inode.i_nlink	= 2;
 		inode->vfs_inode.i_op		= &cachefs_root_inode_operations;
 		inode->vfs_inode.i_fop		= &cachefs_root_file_operations;
 	}
@@ -439,7 +440,7 @@
 
 /*****************************************************************************/
 /*
- * clear an AFS inode
+ * clear an inode
  */
 void cachefs_clear_inode(struct inode *vfs_inode)
 {
@@ -447,7 +448,7 @@
 
 	inode = CACHEFS_FS_I(vfs_inode);
 
-	kenter("ino=%lu",inode->vfs_inode.i_ino);
+	kenter("{ino=%lu nl=%u}",inode->vfs_inode.i_ino,inode->vfs_inode.i_nlink);
 
 	_leave("");
 } /* end cachefs_clear_inode() */

Index: index.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/index.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- index.c	2 Apr 2003 09:12:31 -0000	1.13
+++ index.c	17 Apr 2003 11:59:04 -0000	1.14
@@ -29,9 +29,9 @@
 #include "cachefs-int.h"
 
 struct cachefs_index_search_record {
+	struct cachefs_object		*index;
+	struct cachefs_object		*target;
 	struct cachefs_inode		*iinode;
-	cachefs_index_match_t		matchfnx;
-	void				*data;
 	unsigned			entsize;
 	int				entry;
 };
@@ -82,7 +82,7 @@
 		    xent->state==CACHEFS_ONDISC_INDEX_RECYCLE)
 			continue;
 
-		if (rec->matchfnx(xent->data,rec->data)) {
+		if (rec->index->idef->match(rec->index,xent->data)) {
 			rec->entry = offset/tmp + page->index*(PAGE_SIZE/tmp);
 			desc->count = 0;
 			ret = 0;
@@ -102,12 +102,12 @@
 
 /*****************************************************************************/
 /*
- * search for the specified key in an index in one cache
+ * search for the specified target object in an index in one cache
  * - returns -ENOENT if not found
  * - returns index number (>=0) if found and updates the atime for that entry
  */
-int cachefs_index_search(struct cachefs_cross_index *cross, unsigned ino,
-			 cachefs_index_match_t matchfnx, void *data)
+int cachefs_index_search(struct cachefs_active_inode *index,
+			 struct cachefs_active_inode *target)
 {
 	struct cachefs_index_search_record rec;
 	struct file_ra_state ra;
@@ -115,15 +115,15 @@
 	loff_t pos;
 	int ret;
 
-	kenter("{%s},%u,",cross->layout.name,ino);
+	kenter("{%s,%u}",index->object->idef->name,index->ino);
 
 	/* get the inode */
-	ret = cachefs_iget(cross->super,ino,&rec.iinode);
+	ret = cachefs_iget(index->super,index->ino,&rec.iinode);
 	if (ret<0)
 		goto error;
 
-	rec.matchfnx	= matchfnx;
-	rec.data	= data;
+	rec.index	= index->object;
+	rec.target	= target->object;
 	rec.entry	= UINT_MAX;
 	rec.entsize	= rec.iinode->index_esize;
 
@@ -156,7 +156,6 @@
 {
 	struct cachefs_ondisc_index_entry *xent;
 	struct cachefs_ondisc_storage *storage;
-	struct cachefs_cross_index *cross;
 	struct cachefs_inode *iinode;
 	struct cachefs_page *pageio;
 	u_int32_t entry, next;
@@ -174,7 +173,6 @@
 	next = storage->freelink;
 	kunmap(storage);
 
-	cross = iinode->cross_index;
 	entry = page->index * iinode->index_epp;
 
 	content = kmap(page);
@@ -294,12 +292,12 @@
 /*****************************************************************************/
 /*
  * allocate an entry in the specified index file and associate an inode with it
- * - if an index definition is supplied, then the new inode is formatted according to that
- * - if an index definition is not supplied, then the new inode will be a flat data file
+ * - target->object->def determines whether the new inode will be a file or an index
+ * - if an inode is successfully allocated, target->ino will be set with the inode number
  */
 int cachefs_index_allocate(struct cachefs_inode *iinode,
-			   const struct cachefs_index *definition,
-			   const void *data)
+			   struct cachefs_active_inode *index,
+			   struct cachefs_active_inode *target)
 {
 	struct cachefs_ondisc_index_entry *xent;
 	struct cachefs_ondisc_storage *storage;
@@ -309,9 +307,9 @@
 	unsigned ino, ixentry, offset, inonext, ixnext, ino_offset;
 	int ret, loop;
 
-	kenter("{%lu},,,",iinode->vfs_inode.i_ino);
+	kenter("{%lu},{%s},",iinode->vfs_inode.i_ino,index->object->idef->name);
 
-	super = iinode->vfs_inode.i_sb->s_fs_info;
+	super = index->super;
 	inopage = NULL;
 	ixpage = NULL;
 	trans = NULL;
@@ -336,7 +334,7 @@
 	offset = (ixentry % iinode->index_epp) * iinode->index_esize;
 
 	trans->jentry->mark = CACHEFS_ONDISC_UJNL_INDEX_ALLOCING;
-	if (!definition)
+	if (!target->object->idef)
 		trans->jentry->mark = CACHEFS_ONDISC_UJNL_INODE_ALLOCING;
 
 	trans->jentry->index	= iinode->vfs_inode.i_ino;
@@ -369,7 +367,13 @@
 	xent = kmap(ixpage) + offset;
 	xent->state	= CACHEFS_ONDISC_INDEX_ACTIVE;
 	xent->ino	= ino;
-	memcpy(xent->data,data,iinode->index_dsize);
+	xent->type	= CACHEFS_ONDISC_INDEX_DATAFILE;
+
+	if (target->object->idef)
+		xent->type = CACHEFS_ONDISC_INDEX_INDEXFILE;
+
+	index->object->idef->update(target->object,xent->data);
+
 	kunmap(ixpage);
 
 	/* modify the index inode storage entry */
@@ -391,7 +395,9 @@
 	storage->pindex		= iinode->vfs_inode.i_ino;
 	storage->pindex_entry	= ixentry;
 
-	if (definition) {
+	if (target->object->idef) {
+		struct cachefs_index_def *definition = target->object->idef;
+
 		storage->index_dsize	= definition->data_size;
 		storage->index_esize	= storage->index_dsize;
 		storage->index_esize	+= sizeof(struct cachefs_ondisc_index_entry);
@@ -417,7 +423,7 @@
 	cachefs_trans_commit(trans);
 	trans = NULL;
 
-	ret = ino;
+	target->ino = ino;
 
  error:
 	if (trans)	cachefs_trans_put(trans);
@@ -432,22 +438,20 @@
 /*
  * allocate an entry in the specified index and associate a new inode with it
  */
-int cachefs_index_add(struct cachefs_super *super,
-		      unsigned iino,
-		      const struct cachefs_index *definition,
-		      const void *data)
+int cachefs_index_add(struct cachefs_active_inode *index,
+		      struct cachefs_active_inode *target)
 {
 	struct cachefs_inode *iinode;
 	int ret;
 
-	kenter(",%u,{%s},",iino,definition->name);
+	kenter("{%u,%s},",index->ino,index->object->idef->name);
 
 	/* get the index inode */
-	ret = cachefs_iget(super,iino,&iinode);
+	ret = cachefs_iget(index->super,index->ino,&iinode);
 	if (ret<0)
 		goto error;
 
-	ret = cachefs_index_allocate(iinode,definition,data);
+	ret = cachefs_index_allocate(iinode,index,target);
 
 	cachefs_iput(iinode);
  error:
@@ -552,4 +556,4 @@
 	kleave(" = %d",ret);
 	return ret;
 
-} /* end cachefs_index_add() */
+} /* end cachefs_index_zap() */

Index: cachetest-main.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/cachetest-main.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- cachetest-main.c	7 Mar 2003 23:53:38 -0000	1.6
+++ cachetest-main.c	17 Apr 2003 11:59:04 -0000	1.7
@@ -13,8 +13,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/pagemap.h>
+#include <linux/in.h>
 #include <linux/cachefs.h>
 
 #define kenter(FMT,...)	printk("==> %s("FMT")\n",__FUNCTION__,##__VA_ARGS__)
@@ -31,36 +30,105 @@
 MODULE_AUTHOR("Red Hat, Inc.");
 MODULE_LICENSE("GPL");
 
-static int cells_match(const void *_entry, const void *_data);
-static int vldb_match(const void *_entry, const void *_data);
-static int files_match(const void *_entry, const void *_data);
+struct afs_cell {
+	char			name[64];	/* [KEY] cell name */
+	struct in_addr		vlservers[15];	/* VLDB server IP addresses */
+	struct cachefs_object	cache;		/* caching cookie */
+};
+
+struct afs_volume {
+	char			name[64];	/* [KEY] volume name */
+	u_int32_t		vids[3];	/* volume IDs */
+	struct in_addr		fsservers[8];	/* file server IP addresses */
+	u_int8_t		fstypemsks[8];	/* file server volume type masks */
+	struct cachefs_object	cache;		/* caching cookie */
+};
+
+struct afs_inode {
+	u_int32_t		fid;		/* [KEY] file ID */
+	struct cachefs_object	cache;		/* caching cookie */
+};
 
-static struct cachefs_index cachetest_cells = {
-	.name		= "cells",
+/* AFS network filesystem
+ * - the primary index contains cell references
+ */
+static cachefs_match_val_t cell_match(struct cachefs_object *target, const void *entry);
+static void cell_update(struct cachefs_object *source, void *entry);
+
+static struct cachefs_index_def cachetest_netfs = {
+	.name		= "AFS",
 	.data_size	= 124,
 	.keys[0]	= { CACHEFS_INDEX_KEYS_ASCIIZ, 64 },
+	.match		= cell_match,
+	.update		= cell_update,
+};
+
+static struct cachefs_netfs_operations cachetest_ops = {
 };
 
-static struct cachefs_index cachetest_vldb = {
-	.name		= "vldb",
+static struct cachefs_netfs cachetest = {
+	.name		= "cachetest",
+	.version	= 0,
+	.primary_index	= { .idef = &cachetest_netfs},
+	.ops		= &cachetest_ops,
+};
+
+/* AFS cell
+ * - this is an index containing volume location database references
+ * - objects of this type will be typically embedded in the AFS fs's cell record structures
+ */
+static cachefs_match_val_t vldb_match(struct cachefs_object *target, const void *entry);
+static void vldb_update(struct cachefs_object *source, void *entry);
+
+static struct cachefs_index_def cachetest_cell = {
+	.name		= "cell",
 	.data_size	= 124,
 	.keys[0]	= { CACHEFS_INDEX_KEYS_ASCIIZ, 64 },
+	.match		= vldb_match,
+	.update		= vldb_update,
 };
 
-static struct cachefs_index cachetest_files = {
-	.name		= "files",
+static struct afs_cell afs_mycell = {
+	.name		= "cambridge.redhat.com",
+	.cache		= {
+		.idef		= &cachetest_cell,
+		.iparent	= &cachetest.primary_index,
+	},
+};
+
+/* AFS root volume
+ * - this is an index containing file references
+ * - objects of this type will be typically embedded in the AFS fs's volume record structures
+ */
+static cachefs_match_val_t file_match(struct cachefs_object *target, const void *entry);
+static void file_update(struct cachefs_object *source, void *entry);
+
+static struct cachefs_index_def cachetest_volume = {
+	.name		= "volume",
 	.data_size	= 4,
 	.keys[0]	= { CACHEFS_INDEX_KEYS_BIN, 4 },
+	.match		= file_match,
+	.update		= file_update,
 };
 
-static struct cachefs_netfs_operations cachetest_ops = {
+static struct afs_volume afs_root_volume = {
+	.name		= "#afs.root",
+	.cache		= {
+		.idef		= &cachetest_volume,
+		.iparent	= &afs_mycell.cache,
+	},
 };
 
-static struct cachefs_netfs cachetest = {
-	.name		= "sillynetfs",
-	.version	= 0,
-	.primary	= &cachetest_cells,
-	.ops		= &cachetest_ops,
+/* AFS root dir
+ * - this is a file (hence .idef is NULL)
+ * - objects of this type will be typically embedded in the AFS fs's inode structures
+ */
+static struct afs_inode afs_root_dir = {
+	.fid		= 0x1234abcd,
+	.cache		= {
+		.idef		= NULL,
+		.iparent	= &afs_root_volume.cache,
+	},
 };
 
 /*****************************************************************************/
@@ -77,6 +145,21 @@
 	if (ret<0)
 		goto error;
 
+	printk("\n### Register cell object\n");
+	ret = cachefs_register_object(&afs_mycell.cache);
+	if (ret<0)
+		goto error;
+
+	printk("\n### Register volume object\n");
+	ret = cachefs_register_object(&afs_root_volume.cache);
+	if (ret<0)
+		goto error;
+
+	printk("\n### Register file object\n");
+	ret = cachefs_register_object(&afs_root_dir.cache);
+	if (ret<0)
+		goto error;
+
 	return ret;
 
  error:
@@ -92,6 +175,9 @@
 {
 	printk(KERN_INFO "cachefstest: general fs caching v0.1 tester unregistering.\n");
 
+	cachefs_unregister_object(&afs_root_dir.cache,0);
+	cachefs_unregister_object(&afs_root_volume.cache,0);
+	cachefs_unregister_object(&afs_mycell.cache,0);
 	cachefs_unregister_netfs(&cachetest);
 
 } /* end cachefstest_exit() */
@@ -100,31 +186,93 @@
 /*
  * 
  */
-static int cells_match(const void *_entry, const void *_data)
+static cachefs_match_val_t cell_match(struct cachefs_object *target, const void *entry)
 {
+	struct afs_cell *cell = container_of(target,struct afs_cell,cache);
+
 	kenter("");
-	return 0;
-} /* end cells_match() */
+
+	if (strncmp(entry,cell->name,sizeof(cell->name))==0)
+		return CACHEFS_MATCH_SUCCESS;
+
+	return CACHEFS_MATCH_FAILED;
+} /* end cell_match() */
+
+/*****************************************************************************/
+/*
+ * update a cell entry from the specified object
+ */
+static void cell_update(struct cachefs_object *source, void *entry)
+{
+	struct afs_cell *cell = container_of(source,struct afs_cell,cache);
+
+	kenter("%p,%p",source,entry);
+
+	strncpy(entry,cell->name,sizeof(cell->name));
+
+} /* end cell_update() */
 
 /*****************************************************************************/
 /*
  * 
  */
-static int vldb_match(const void *_entry, const void *_data)
+static cachefs_match_val_t vldb_match(struct cachefs_object *target, const void *entry)
 {
+	struct afs_volume *volume = container_of(target,struct afs_volume,cache);
+
 	kenter("");
-	return 0;
+
+	if (strncmp(entry,volume->name,sizeof(volume->name))==0)
+		return CACHEFS_MATCH_SUCCESS;
+
+	return CACHEFS_MATCH_FAILED;
 } /* end vldb_match() */
 
 /*****************************************************************************/
 /*
  * 
  */
-static int files_match(const void *_entry, const void *_data)
+static void vldb_update(struct cachefs_object *source, void *entry)
 {
+	struct afs_volume *volume = container_of(source,struct afs_volume,cache);
+
+	kenter("%p,%p",source,entry);
+
+	strncpy(entry,volume->name,sizeof(volume->name));
+
+} /* end vldb_update() */
+
+/*****************************************************************************/
+/*
+ * 
+ */
+static cachefs_match_val_t file_match(struct cachefs_object *target, const void *entry)
+{
+	struct afs_inode *inode = container_of(target,struct afs_inode,cache);
+	u_int32_t fid = htonl(inode->fid);
+
 	kenter("");
-	return 0;
-} /* end files_match() */
+
+	if (memcmp(entry,&fid,sizeof(fid))==0)
+		return CACHEFS_MATCH_SUCCESS;
+
+	return CACHEFS_MATCH_FAILED;
+} /* end file_match() */
+
+/*****************************************************************************/
+/*
+ * 
+ */
+static void file_update(struct cachefs_object *source, void *entry)
+{
+	struct afs_inode *inode = container_of(source,struct afs_inode,cache);
+	u_int32_t fid = htonl(inode->fid);
+
+	kenter("%p,%p",source,entry);
+
+	memcpy(entry,&fid,sizeof(fid));
+
+} /* end file_update() */
 
 /*****************************************************************************/
 /*

Index: cachefs-layout.h
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/cachefs-layout.h,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -r1.20 -r1.21
--- cachefs-layout.h	2 Apr 2003 09:12:31 -0000	1.20
+++ cachefs-layout.h	17 Apr 2003 11:59:04 -0000	1.21
@@ -68,10 +68,14 @@
  */
 struct cachefs_ondisc_index_entry
 {
-	u_int32_t			state : 8;
-#define CACHEFS_ONDISC_INDEX_FREE	0xf9
-#define CACHEFS_ONDISC_INDEX_RECYCLE	0xe5
-#define CACHEFS_ONDISC_INDEX_ACTIVE	0xbc
+	u_int32_t			state : 7;
+#define CACHEFS_ONDISC_INDEX_FREE	0x7e
+#define CACHEFS_ONDISC_INDEX_RECYCLE	0x65
+#define CACHEFS_ONDISC_INDEX_ACTIVE	0x2c
+
+	u_int32_t			type : 1;
+#define CACHEFS_ONDISC_INDEX_DATAFILE	0
+#define CACHEFS_ONDISC_INDEX_INDEXFILE	1
 
 	u_int32_t			ino : 24;	/* inode containing catalogue/data */
 	union {

Index: cachefs-int.h
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/cachefs-int.h,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -r1.25 -r1.26
--- cachefs-int.h	2 Apr 2003 09:12:31 -0000	1.25
+++ cachefs-int.h	17 Apr 2003 11:59:04 -0000	1.26
@@ -26,13 +26,16 @@
 extern int cachefs_debug;
 
 struct cachefs_super;
-struct cachefs_cross_index;
+struct cachefs_block;
+struct cachefs_active_inode;
 
 extern struct address_space_operations cachefs_addrspace_operations;
 extern struct address_space_operations cachefs_vio_addrspace_operations;
 extern struct file_operations cachefs_root_file_operations;
 extern struct inode_operations cachefs_root_inode_operations;
-extern struct cachefs_netfs cachefs_fsdef;
+extern struct rw_semaphore cachefs_addremove_sem;
+extern struct list_head cachefs_cache_list;
+extern struct list_head cachefs_netfs_list;
 
 extern int cachefs_fs_init(void);
 extern void cachefs_fs_exit(void);
@@ -57,10 +60,10 @@
 /*
  * cachefs superblock private information
  */
-struct cachefs_super {
+struct cachefs_super
+{
 	struct super_block		*sb;
 	struct list_head		mnt_link;	/* link in list of mounted caches */
-	struct list_head		cross_indexes;	/* netfs's cached in this cache */
 	struct cachefs_inode		*istorage;	/* the storage metadata records file */
 	struct inode			*imisc;		/* an inode covering the whole blkdev */
 
@@ -162,14 +165,15 @@
 	atomic_t			cnt_ujnl_akwr;	/* number of ACKs written */
 	atomic_t			cnt_ujnl_free;	/* number of marks freed */
 
-	/* dummy index for accessing fsdef file */
-	struct cachefs_cross_index	*fsdef_index;
+	/* index management */
+	struct rb_root			ino_tree;	/* tree of active inodes */
+	rwlock_t			ino_tree_lock;
 
 	/* superblock copy */
 	struct cachefs_ondisc_superblock *layout;
 };
 
-extern void cachefs_add_cache(struct cachefs_super *super);
+extern void cachefs_add_cache(struct cachefs_super *super, struct cachefs_active_inode *active);
 extern void cachefs_del_cache(struct cachefs_super *super);
 
 extern void cachefs_recycle_unready_blocks(struct cachefs_super *super);
@@ -178,30 +182,33 @@
 
 /*****************************************************************************/
 /*
- * cache/netfs cross-indexing record
+ * cache file and directory management
+ * - negative entry if .ino==0 (and node will be unused)
  */
-struct cachefs_cross_index
+struct cachefs_active_inode
 {
-	struct cachefs_netfs		*netfs;		/* network filesystem definition */
-	struct cachefs_super		*super;		/* device to which refers */
-	struct list_head		netfs_link;	/* link in netfs's list */
-	struct list_head		super_link;	/* link in cache's list */
+	struct rb_node			node;		/* node in active inode tracking tree */
+	atomic_t			usage;		/* usage count */
+	struct cachefs_super		*super;		/* cache in which resident */
+	unsigned			ino;		/* inode in cache */
+	unsigned long			flags;
+#define CACHEFS_ACTIVE_INODE_ISINDEX	0	/* T if inode is index file (F if file) */
+#define CACHEFS_ACTIVE_INODE_LIVE	1	/* T if struct is live */
+#define CACHEFS_ACTIVE_INODE_INITING	2	/* T if struct is being initialised */
+#define CACHEFS_ACTIVE_INODE_RETIRING	3	/* T if inode is being retired */
 
-	struct cachefs_ondisc_fsdef	layout;		/* raw index description */
-	unsigned			entry_id;	/* fsdef ID (record index) */
+	struct cachefs_block		*storage;	/* block containing data storage info */
+	wait_queue_head_t		initwq;		/* initialisation wait queue */
+
+	struct cachefs_object		*object;	/* netfs's file/index object */
+	struct list_head		link;		/* link in object->active_inodes */
 };
 
-extern int cachefs_generate_cross_index(struct cachefs_super *super,
-					struct cachefs_netfs *netfs,
-					struct cachefs_cross_index **_cross);
-
-extern int cachefs_index_search(struct cachefs_cross_index *cross, unsigned ino,
-				cachefs_index_match_t matchfnx, void *data);
-
-extern int cachefs_index_add(struct cachefs_super *super,
-			     unsigned iino,
-			     const struct cachefs_index *definition,
-			     const void *data);
+extern int cachefs_index_search(struct cachefs_active_inode *index,
+				struct cachefs_active_inode *target);
+
+extern int cachefs_index_add(struct cachefs_active_inode *index,
+			     struct cachefs_active_inode *target);
 
 extern int cachefs_index_zap(struct cachefs_super *super);
 
@@ -212,9 +219,7 @@
 struct cachefs_inode
 {
 	struct inode			vfs_inode;	/* VFS inode record for this file */
-	struct cachefs_cross_index	*cross_index;	/* index of which this is part (or NULL)*/
-	struct list_head		index_link;	/* link in index's list */
-	struct list_head		cache_link;	/* link in cache's list */
+	struct cachefs_active_inode	*active;	/* inode management */
 	unsigned			storage_offset;	/* data storage record offset */
 	unsigned short			index_dsize;	/* size of data in each index entry */
 	unsigned short			index_esize;	/* size of index entries */
@@ -256,6 +261,7 @@
 struct cachefs_block
 {
 	struct rb_node			lookup_node;	/* node in superblock's lookup tree */
+	struct cachefs_super		*super;		/* superblock on which block resides */
 	cachefs_blockix_t		bix;		/* index of block on disc */
 	atomic_t			usage;		/* usage count */
 	wait_queue_head_t		writewq;	/* write completion sleep queue */
@@ -277,6 +283,7 @@
 	struct list_head		batch_link;	/* link in batch writer's list */
 	struct page			*page;		/* current data for this block */
 	struct page			*writeback;	/* source of writeback for this block */
+	struct cachefs_page		*ref;		/* netfs's ref to this page */
 };
 
 extern int cachefs_block_insert(struct cachefs_super *super,
@@ -438,7 +445,7 @@
 /*
  * debug tracing
  */
-#define dbgprintk(FMT,...) printk("[%-6.6s] "FMT"\n",current->comm ,##__VA_ARGS__)
+#define dbgprintk(FMT,...) printk("[%-5.5hu] "FMT"\n",(u16)jiffies ,##__VA_ARGS__)
 #define _dbprintk(FMT,...) do { } while(0)
 
 #define kenter(FMT,...)	dbgprintk("==> %s("FMT")",__FUNCTION__ ,##__VA_ARGS__)

Index: block.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/block.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- block.c	21 Mar 2003 14:01:01 -0000	1.1
+++ block.c	17 Apr 2003 11:59:04 -0000	1.2
@@ -404,7 +404,8 @@
 	atomic_set(&newblock->usage,1);
 	init_waitqueue_head(&newblock->writewq);
 	INIT_LIST_HEAD(&newblock->batch_link);
-	newblock->bix = bix;
+	newblock->bix	= bix;
+	newblock->super	= super;
 
 	parent = NULL;
 	block = NULL;

Index: aops.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/aops.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -r1.24 -r1.25
--- aops.c	2 Apr 2003 09:12:31 -0000	1.24
+++ aops.c	17 Apr 2003 11:59:04 -0000	1.25
@@ -69,17 +69,23 @@
 	.invalidatepage		= cachefs_invalidatepage,
 };
 
-int cachefs_get_page_private(struct page *page, struct cachefs_page **_pageio, unsigned gfp_flags)
+int cachefs_get_page_private(struct page *page, struct cachefs_page **_cookie, unsigned gfp_flags)
 {
-	if (!page->private) {
-		page->private = (unsigned long) kmalloc(sizeof(struct cachefs_page),gfp_flags);
-		if (!page->private)
+	struct cachefs_page *cookie = (struct cachefs_page*) page->private;
+
+	if (!cookie) {
+		cookie = kmalloc(sizeof(*cookie),gfp_flags);
+		if (!cookie)
 			return -ENOMEM;
-		memset((void*)page->private,0,sizeof(struct cachefs_page));
+
+		memset(cookie,0,sizeof(*cookie));
+		rwlock_init(&cookie->lock);
+
+		page->private = (unsigned long) cookie;
 		SetPagePrivate(page);
 	}
 
-	*_pageio = (struct cachefs_page*) page->private;
+	*_cookie = cookie;
 	return 0;
 }
 
@@ -268,14 +274,14 @@
 static int cachefs_do_readpage(struct bio **_bio, struct page *page, unsigned nr_pages,
 			       sector_t *last_block_in_bio)
 {
-	struct cachefs_page *pageio;
+	struct cachefs_page *cookie;
 	struct inode *inode = page->mapping->host;
 	sector_t last_block;
 	int ret;
 
 	_enter("");
 
-	ret = cachefs_get_page_private(page,&pageio,GFP_KERNEL);
+	ret = cachefs_get_page_private(page,&cookie,GFP_KERNEL);
 	if (ret<0)
 		goto error;
 
@@ -294,7 +300,7 @@
 	}
 
 	/* handle a hole */
-	if (!pageio->mapped_block) {
+	if (!cookie->mapped_block) {
 		memset(kmap(page),0,PAGE_SIZE);
 		flush_dcache_page(page);
 		kunmap(page);
@@ -303,12 +309,12 @@
 	}
 	else {
 		/* this page will go to BIO.  Do we need to send this BIO off first? */
-		if (*_bio && *last_block_in_bio != pageio->mapped_block->bix-1)
+		if (*_bio && *last_block_in_bio != cookie->mapped_block->bix-1)
 			cachefs_io_bio_submit(READ,_bio);
 
 	alloc_new:
 		if (!*_bio) {
-			ret = cachefs_io_alloc(inode->i_sb,pageio->mapped_block->bix,
+			ret = cachefs_io_alloc(inode->i_sb,cookie->mapped_block->bix,
 					       nr_pages,GFP_KERNEL,_bio);
 			if (ret<0)
 				goto error;
@@ -319,10 +325,10 @@
 			goto alloc_new;
 		}
 
-		if (pageio->flags & CACHEFS_PAGE_BOUNDARY)
+		if (cookie->flags & CACHEFS_PAGE_BOUNDARY)
 			cachefs_io_bio_submit(READ,_bio);
 		else
-			*last_block_in_bio = pageio->mapped_block->bix;
+			*last_block_in_bio = cookie->mapped_block->bix;
 	}
 
 	_leave(" = 0");
@@ -415,19 +421,19 @@
 void cachefs_do_writepage(struct bio **_bio, struct page *page,
 			  sector_t *last_block_in_bio, int *_ret)
 {
-	struct cachefs_page *pageio;
+	struct cachefs_page *cookie;
 	struct inode *inode = page->mapping->host;
 	unsigned long end_index;
 	int ret;
 
 	_enter(",{%lu},%llu,",page->index,*last_block_in_bio);
 
-	ret = cachefs_get_page_private(page,&pageio,GFP_KERNEL);
+	ret = cachefs_get_page_private(page,&cookie,GFP_KERNEL);
 	if (ret<0)
 		goto error;
 
 	/* deal with a block not that's yet mapped */
-	if (!pageio->mapped_block) {
+	if (!cookie->mapped_block) {
 		/* map the page to a block on the blockdev */
 		BUG_ON(!PageUptodate(page));
 
@@ -437,8 +443,8 @@
 			goto out;
 		}
 
-		if (pageio->flags & CACHEFS_PAGE_NEW)
-			BUG();//unmap_underlying_metadata(inode->i_sb->s_bdev,pageio->mapped_block)
+		if (cookie->flags & CACHEFS_PAGE_NEW)
+			BUG();//unmap_underlying_metadata(inode->i_sb->s_bdev,cookie->mapped_block)
 
 		/* clear the tail end of the last block */
 		end_index = inode->i_size >> PAGE_CACHE_SHIFT;
@@ -454,13 +460,13 @@
 	}
 
 	/* dispatch the outstanding BIO if not immediately preceding this page */
-	if (*_bio && *last_block_in_bio != pageio->mapped_block->bix-1)
+	if (*_bio && *last_block_in_bio != cookie->mapped_block->bix-1)
 		cachefs_io_bio_submit(WRITE,_bio);
 
 alloc_new:
 	if (!*_bio) {
 		ret = cachefs_io_alloc(inode->i_sb,
-				       pageio->mapped_block->bix,
+				       cookie->mapped_block->bix,
 				       bio_get_nr_vecs(inode->i_sb->s_bdev),
 				       GFP_NOFS|__GFP_HIGH,
 				       _bio);
@@ -477,12 +483,12 @@
 	BUG_ON(PageWriteback(page));
 	SetPageWriteback(page);
 	unlock_page(page);
-	if (pageio->flags & CACHEFS_PAGE_BOUNDARY) {
+	if (cookie->flags & CACHEFS_PAGE_BOUNDARY) {
 		cachefs_io_bio_submit(WRITE,_bio);
 //		write_boundary_block(inode->i_sb->s_bdev,
-//				     pageio->mapped_block->bix, 1 << PAGE_CACHE_SHIFT);
+//				     cookie->mapped_block->bix, 1 << PAGE_CACHE_SHIFT);
 	} else {
-		*last_block_in_bio = pageio->mapped_block->bix;
+		*last_block_in_bio = cookie->mapped_block->bix;
 	}
 	goto out;
 
@@ -619,7 +625,7 @@
  */
 static int cachefs_writepage(struct page *page, struct writeback_control *wbc)
 {
-	struct cachefs_page *pageio;
+	struct cachefs_page *cookie;
 	unsigned long end_index;
 	struct inode * const inode = page->mapping->host;
 	struct bio *bio;
@@ -631,7 +637,7 @@
 	BUG_ON(!PageUptodate(page));
 	BUG_ON(PageWriteback(page));
 
-	ret = cachefs_get_page_private(page,&pageio,GFP_NOFS);
+	ret = cachefs_get_page_private(page,&cookie,GFP_NOFS);
 	if (ret<0)
 		goto error;
 
@@ -653,20 +659,20 @@
 		kunmap_atomic(kaddr, KM_USER0);
 	}
 
-	if (!pageio->mapped_block) {
+	if (!cookie->mapped_block) {
 		ret = cachefs_get_block(inode,page,1);
 		if (ret<0)
 			goto error;
 
-		if (!pageio->mapped_block) BUG();
+		if (!cookie->mapped_block) BUG();
 
-		if (pageio->flags & CACHEFS_PAGE_NEW) {
+		if (cookie->flags & CACHEFS_PAGE_NEW) {
 			//unmap_underlying_metadata(bh->b_bdev,bh->b_blocknr);
-			pageio->flags &= ~CACHEFS_PAGE_NEW;
+			cookie->flags &= ~CACHEFS_PAGE_NEW;
 		}
 	}
 
-	ret = cachefs_io_alloc(inode->i_sb,pageio->mapped_block->bix,1,GFP_NOFS,&bio);
+	ret = cachefs_io_alloc(inode->i_sb,cookie->mapped_block->bix,1,GFP_NOFS,&bio);
 	if (ret<0)
 		goto error;
 
@@ -689,7 +695,7 @@
  */
 static int cachefs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
 {
-	struct cachefs_page *pageio;
+	struct cachefs_page *cookie;
 	struct inode *inode = page->mapping->host;
 	struct bio *bio = NULL;
 	int ret;
@@ -698,21 +704,21 @@
 
 	_enter(",{%lu},%u,%u",page->index,from,to);
 
-	ret = cachefs_get_page_private(page,&pageio,GFP_NOFS);
+	ret = cachefs_get_page_private(page,&cookie,GFP_NOFS);
 	if (ret<0)
 		goto error;
 
 	/* map the page to a disc block and prepare a new page for writing */
-	if (!pageio->mapped_block) {
+	if (!cookie->mapped_block) {
 		ret = cachefs_get_block(inode,page,1);
 		if (ret<0)
 			goto error;
 
-		BUG_ON(!pageio->mapped_block);
+		BUG_ON(!cookie->mapped_block);
 	}
 
 	if (!PageUptodate(page)) {
-		if (pageio->flags & CACHEFS_PAGE_NEW) {
+		if (cookie->flags & CACHEFS_PAGE_NEW) {
 			//unmap_underlying_metadata(bh->b_bdev,bh->b_blocknr);
 			if (from>0 || to<PAGE_SIZE) {
 				void *kaddr;
@@ -734,7 +740,7 @@
 			goto error;
 
 		bio->bi_bdev	= inode->i_sb->s_bdev;
-		bio->bi_sector	= pageio->mapped_block->bix;
+		bio->bi_sector	= cookie->mapped_block->bix;
 		bio->bi_sector	<<= (PAGE_SHIFT - inode->i_sb->s_blocksize_bits);
 		bio->bi_end_io	= cachefs_io_end_io_prepare;
 		bio->bi_private	= &cpl;
@@ -747,19 +753,19 @@
 		wait_for_completion(&cpl);
 	}
 
-	pageio->flags &= ~CACHEFS_PAGE_NEW;
+	cookie->flags &= ~CACHEFS_PAGE_NEW;
 
 	_leave(" = 0");
 	return 0;
 
  error:
-	if (pageio->flags & CACHEFS_PAGE_NEW) {
+	if (cookie->flags & CACHEFS_PAGE_NEW) {
 		memset(kmap(page),0,PAGE_SIZE);
 		flush_dcache_page(page);
 		kunmap(page);
 		SetPageUptodate(page);
 		set_page_dirty(page);
-		pageio->flags &= ~CACHEFS_PAGE_NEW;
+		cookie->flags &= ~CACHEFS_PAGE_NEW;
 	}
 
 	_leave(" = %d",ret);
@@ -796,7 +802,7 @@
 static int cachefs_invalidatepage(struct page *page, unsigned long offset)
 {
 	struct cachefs_block *block;
-	struct cachefs_page *pageio;
+	struct cachefs_page *cookie;
 	int ret = 1;
 
 	_enter("{%lu},%lu",page->index,offset);
@@ -805,10 +811,10 @@
 	if (!PagePrivate(page))
 		goto out;
 
-	pageio = (struct cachefs_page*) page->private;
-	block = xchg(&pageio->mapped_block,NULL);
+	cookie = (struct cachefs_page*) page->private;
+	block = xchg(&cookie->mapped_block,NULL);
 	ClearPageMappedToDisk(page);
-	pageio->flags = 0;
+	cookie->flags = 0;
 
 	if (block) cachefs_block_put(page->mapping->host->i_sb->s_fs_info,block);
 
@@ -832,22 +838,22 @@
  */
 static int cachefs_releasepage(struct page *page, int gfp_flags)
 {
-	struct cachefs_page *pageio;
+	struct cachefs_page *cookie;
 
 	_enter("{%lu},%x",page->index,gfp_flags);
 
 	if (PagePrivate(page)) {
-		pageio = (struct cachefs_page*) page->private;
+		cookie = (struct cachefs_page*) page->private;
 		page->private = 0;
 		ClearPagePrivate(page);
 		ClearPageMappedToDisk(page);
 
-		if (pageio) {
-			if (pageio->mapped_block)
+		if (cookie) {
+			if (cookie->mapped_block)
 				cachefs_block_put(page->mapping->host->i_sb->s_fs_info,
-						  pageio->mapped_block);
-			dbgfree(pageio);
-			kfree(pageio);
+						  cookie->mapped_block);
+			dbgfree(cookie);
+			kfree(cookie);
 		}
 	}
 
@@ -1091,7 +1097,7 @@
 	struct cachefs_io_block_path path[4];
 	struct cachefs_inode *inode = CACHEFS_FS_I(vfs_inode);
 	struct cachefs_super *super = inode->vfs_inode.i_sb->s_fs_info;
-	struct cachefs_page *pageio = __cachefs_get_page_private(page);
+	struct cachefs_page *cookie = __cachefs_get_page_private(page);
 	const size_t ptrperblk = PAGE_SIZE / sizeof(cachefs_blockix_t);
 	sector_t iblock;
 	size_t ptrqty, notboundary = 1;
@@ -1100,7 +1106,7 @@
 #if 0
 	if (inode->vfs_inode.i_ino == CACHEFS_INO_WIBBLE) {
 		ret = cachefs_block_insert(inode->vfs_inode.i_sb->s_fs_info,page->index+1000,
-					   &pageio->mapped_block);
+					   &cookie->mapped_block);
 		if (ret==0)
 			SetPageMappedToDisk(page);
 		return ret;
@@ -1110,7 +1116,7 @@
 
 	_enter("%lu,{%p}%lu,%d",inode->vfs_inode.i_ino,page,page->index,create);
 
-	BUG_ON(pageio->mapped_block);
+	BUG_ON(cookie->mapped_block);
 
 	if (page->index/ptrperblk >= ptrperblk) {
 		_leave(" = -EIO [range]");
@@ -1282,26 +1288,26 @@
 		}
 
 	if (ret<0) {
-		if (pageio->mapped_block)
-			cachefs_block_put(inode->vfs_inode.i_sb->s_fs_info,pageio->mapped_block);
-		pageio->mapped_block = NULL;
+		if (cookie->mapped_block)
+			cachefs_block_put(inode->vfs_inode.i_sb->s_fs_info,cookie->mapped_block);
+		cookie->mapped_block = NULL;
 		_leave(" = %d",ret);
 		return ret;
 	}
 
 	/* got the block - set the block offset in the page mapping record */
 	if (path[0].flags & CACHEFS_BLOCK_NEW)
-		pageio->flags |= CACHEFS_PAGE_NEW;
+		cookie->flags |= CACHEFS_PAGE_NEW;
 
 	_debug("notboundary = %u",notboundary);
 	if (!notboundary)
-		pageio->flags |= CACHEFS_PAGE_BOUNDARY;
+		cookie->flags |= CACHEFS_PAGE_BOUNDARY;
 
 	_leave(" = 0 [bix=%u %c%c%c]",
-	       pageio->mapped_block->bix,
-	       pageio->flags & CACHEFS_PAGE_BOUNDARY	?'b':'-',
-	       pageio->flags & CACHEFS_PAGE_NEW		?'n':'-',
-	       pageio->flags & CACHEFS_PAGE_BYSECTORS	?'s':'-'
+	       cookie->mapped_block->bix,
+	       cookie->flags & CACHEFS_PAGE_BOUNDARY	?'b':'-',
+	       cookie->flags & CACHEFS_PAGE_NEW		?'n':'-',
+	       cookie->flags & CACHEFS_PAGE_BYSECTORS	?'s':'-'
 	       );
 	return 0;
 } /* end cachefs_get_block() */
@@ -1341,3 +1347,57 @@
 	_leave(" = -EIO");
 	return -EIO;
 } /* end cachefs_get_page() */
+
+/*****************************************************************************/
+/*
+ * read a block from disc into a page provided by a netfs
+ * - returns -ENODATA if there's no cache block mapped
+ */
+int cachefs_file_readpage(struct cachefs_netfs *netfs, struct page *page)
+{
+	struct cachefs_block *block;
+	struct cachefs_page *cookie;
+	struct super_block *sb;
+	unsigned long flags;
+	struct bio *bio;
+	int ret;
+
+	kenter("{%s},{%lu}",netfs->name,page->index);
+
+	ret = netfs->ops->get_page_cookie(page,&cookie);
+	if (ret<0)
+		goto error;
+
+	/* protect against cache removal */
+	read_lock_irqsave(&cookie->lock,flags);
+
+	block = cookie->mapped_block;
+	if (block)
+		cachefs_block_get(block);
+
+	read_unlock_irqrestore(&cookie->lock,flags);
+
+	ret = -ENODATA;
+	if (!block)
+		goto error;
+
+	/* generate a BIO to read the page */
+	ret = -ENOMEM;
+	bio = bio_alloc(GFP_KERNEL,1);
+	if (!bio)
+		goto error;
+
+	sb = block->super->sb;
+
+	bio->bi_bdev	= sb->s_bdev;
+	bio->bi_sector	= block->bix << (PAGE_SHIFT - sb->s_blocksize_bits);
+	bio->bi_end_io	= cachefs_io_end_io_read;
+	//dump_bio(bio,1);
+	submit_bio(READ,bio);
+	ret = 0;
+
+ error:
+	kleave(" = %d",ret);
+	return ret;
+
+} /* end cachefs_file_readpage() */

Index: Makefile
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/Makefile,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- Makefile	2 Apr 2003 09:12:31 -0000	1.14
+++ Makefile	17 Apr 2003 11:59:04 -0000	1.15
@@ -2,13 +2,14 @@
 # Makefile for general caching filesystem
 #
 
-#CFLAGS += -finstrument-functions
+CFLAGS += -finstrument-functions
 
 cachefs-objs := \
 	block.o \
 	aops.o \
 	index.o \
 	inode.o \
+	interface.o \
 	io.o \
 	journal.o \
 	kcachefs_jnld.o \