Subject: afs/fs/cachefs super.c,1.25,1.26 recycling.c,1.16,1.17 journal.c,1.29,1.30 io.c,1.11,1.12 interface.c,1.1,1.2 inode.c,1.16,1.17 index.c,1.14,1.15 cachetest-main.c,1.7,1.8 cachefs-int.h,1.26,1.27 block.c,1.2,1.3 aops.c,1.25,1.26

From: [email-masked]
Date: Thu, 24 Apr 2003 13:02:37 +0100

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

Modified Files:
	super.c recycling.c journal.c io.c interface.c inode.c index.c 
	cachetest-main.c cachefs-int.h block.c aops.c 
Log Message:
advanced the netfs API some more
implemented the journalling sync function
now clear ptr2ptr targets for returning things in func prologue
added a missing pointer clearance

Index: super.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/super.c,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -r1.25 -r1.26
--- super.c	17 Apr 2003 11:59:03 -0000	1.25
+++ super.c	24 Apr 2003 12:02:33 -0000	1.26
@@ -297,6 +297,7 @@
 	INIT_LIST_HEAD(&super->batch_errorq);
 	init_waitqueue_head(&super->batch_done_wq);
 	init_waitqueue_head(&super->batch_timer_wq);
+	init_waitqueue_head(&super->batch_sync_wq);
 	init_timer(&super->batch_timer);
 	super->batch_timer.function = cachefs_trans_batch_timer;
 	super->batch_timer.data = (unsigned long) super;
@@ -308,7 +309,7 @@
 	init_completion(&super->dmn_dead);
 	init_waitqueue_head(&super->dmn_sleepq);
 
-	rwlock_init(&super->ino_tree_lock);
+	spin_lock_init(&super->ino_tree_lock);
 
 	/* create the linear-mapping inode */
 	ret = cachefs_iget(super,CACHEFS_INO_MISC,&inode2);
@@ -692,15 +693,20 @@
 {
 	struct cachefs_super *super = sb->s_fs_info;
 
+	printk("\n\n");
 	kenter("{%p}",super);
 
 	if (!super) BUG();
 
-	cachefs_del_cache(super);
+	cachefs_withdraw_cache(super);
+
+	cachefs_trans_sync(super,1);
 
 	super->dmn_die = 1;
 	wake_up(&super->dmn_sleepq);
 	wait_for_completion(&super->dmn_dead);
+
+	del_timer_sync(&super->batch_timer);
 
 	if (super->alloc_node) {
 		dbgpgfree(super->alloc_node);

Index: recycling.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/recycling.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- recycling.c	2 Apr 2003 09:12:31 -0000	1.16
+++ recycling.c	24 Apr 2003 12:02:33 -0000	1.17
@@ -228,6 +228,7 @@
 
 	/* if the front recycling node is saturated, then transfer the entire stack */
 	if (super->recycle_room==0) {
+		kdebug("transfer entire stack");
 		allocTOS = super->recycle_cur;
 		cur_n	= super->recycle_cur_n;
 		block	= super->recycle_block;
@@ -250,12 +251,14 @@
 			return;
 		}
 
+		super->recycle_block	= NULL;
 		super->recycle_node	= NULL;
 		super->recycle_cur	= 0;
 		super->recycle_cur_n	= 0;
 	}
 	/* otherwise transfer from the second-in-line if there is one */
 	else {
+		kdebug("transfer 2OS+ of stack");
 		node = (struct cachefs_ondisc_free_node *) kmap(super->recycle_node);
 		allocTOS = node->next;
 		kunmap(super->recycle_node);

Index: journal.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/journal.c,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -r1.29 -r1.30
--- journal.c	2 Apr 2003 09:12:31 -0000	1.29
+++ journal.c	24 Apr 2003 12:02:33 -0000	1.30
@@ -145,7 +145,7 @@
 
 	for (loop=0; loop<CACHEFS_EFFECTS_PER_TRANS; loop++) {
 		if (trans->effects[loop].block)
-			cachefs_block_put(trans->super,trans->effects[loop].block);
+			cachefs_block_put(trans->super,xchg(&trans->effects[loop].block,NULL));
 		if (trans->effects[loop].held_page)
 			put_page(trans->effects[loop].held_page);
 	}
@@ -161,7 +161,7 @@
 	}
 
 	if (trans->jblock)
-		cachefs_block_put(trans->super,trans->jblock);
+		cachefs_block_put(trans->super,xchg(&trans->jblock,NULL));
 
 	atomic_inc(&trans->super->cnt_ujnl_free);
 	dbgfree(trans);
@@ -561,6 +561,8 @@
 
 	up(&super->batch_sem);
 
+	wake_up_all(&super->batch_sync_wq);
+
 } /* end cachefs_trans_batch_write() */
 
 /*****************************************************************************/
@@ -660,6 +662,7 @@
 					   offset<<super->sb->s_blocksize_bits);
 
 			cachefs_block_put(super,block);
+			block = NULL;
 			if (!tmp)
 				break;
 
@@ -1186,20 +1189,54 @@
  */
 void cachefs_trans_sync(struct cachefs_super *super, int wait)
 {
-	_enter("{batch=%hd}",super->ujnl_batch);
+	int16_t next_batch;
+	
+	DECLARE_WAITQUEUE(myself,current);
 
-	set_bit(CACHEFS_SUPER_BATCH_TIMER,&super->flags);
-	wake_up_all(&super->batch_timer_wq);
+	kenter("{batch=%hd}",super->ujnl_batch);
 
-#if 0
-	if (wait) {
-		yield();
-		down(&super->batch_sem);
-		up(&super->batch_sem);
+	/* if we're not supposed to wait, just induce consideration of a batch write */
+	if (!wait) {
+		set_bit(CACHEFS_SUPER_BATCH_TIMER,&super->flags);
+		wake_up_all(&super->batch_timer_wq);
+		kleave("");
+		return;
 	}
-#endif
 
-	_leave("");
+	/* prevent new transactions starting until we've worked out where the sync ends */
+	down_write(&super->batch_ctrl_sem);
+
+	if (super->ujnl_serial==0) {
+		/* no pending transactions */
+		up_write(&super->batch_ctrl_sem);
+	}
+	else {
+		/* transactions present - must wait till pending batch is written */
+		next_batch = super->ujnl_batch + 1;
+
+		set_bit(CACHEFS_SUPER_BATCH_TIMER,&super->flags);
+		wake_up_all(&super->batch_timer_wq);
+
+		up_write(&super->batch_ctrl_sem);
+
+		/* now wait for next batch number to come up */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&super->batch_sync_wq,&myself);
+
+		while (next_batch - super->ujnl_batch > 0) {
+			schedule();
+			set_current_state(TASK_UNINTERRUPTIBLE);
+		}		
+
+		remove_wait_queue(&super->batch_sync_wq,&myself);
+		set_current_state(TASK_RUNNING);
+	}
+
+	/* now we have to wait for any currently active batch write */
+	down(&super->batch_sem);
+	up(&super->batch_sem);
+
+	kleave("");
 } /* end cachefs_trans_sync() */
 
 /*****************************************************************************/

Index: io.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/io.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- io.c	21 Mar 2003 14:01:01 -0000	1.11
+++ io.c	24 Apr 2003 12:02:34 -0000	1.12
@@ -32,6 +32,7 @@
 				    unsigned to);
 static int cachefs_vio_invalidatepage(struct page *page, unsigned long offset);
 static int cachefs_vio_releasepage(struct page *page, int gfp_flags);
+static int cachefs_vio_set_page_dirty(struct page *page);
 
 struct address_space_operations cachefs_vio_addrspace_operations = {
 	.readpage		= cachefs_vio_readpage,
@@ -41,7 +42,7 @@
 	.sync_page		= block_sync_page,
 	.prepare_write		= cachefs_vio_prepare_write,
 	.commit_write		= cachefs_vio_commit_write,
-	.set_page_dirty		= __set_page_dirty_nobuffers,
+	.set_page_dirty		= cachefs_vio_set_page_dirty,
 	.releasepage		= cachefs_vio_releasepage,
 	.invalidatepage		= cachefs_vio_invalidatepage,
 };
@@ -106,6 +107,8 @@
 {
 	struct bio *bio;
 
+	*_bio = NULL;
+
 	_enter("{bits=%u},%llu,%d,%x,",sb->s_blocksize_bits,first_sector,nr_vecs,gfp_flags);
 
 	bio = bio_alloc(gfp_flags,nr_vecs);
@@ -125,7 +128,28 @@
 
 static int cachefs_vio_writepages(struct address_space *mapping, struct writeback_control *wbc)
 {
+	struct page *page;
+
+	write_lock(&mapping->page_lock);
+
+	list_splice_init(&mapping->dirty_pages,&mapping->io_pages);
+
+	if (list_empty(&mapping->dirty_pages) && list_empty(&mapping->io_pages)) {
+		write_unlock(&mapping->page_lock);
+		return 0;
+	}
+
+	/* shouldn't ever get this far */
 	printk("CacheFS: meta-data writepages not supported\n");
+
+	printk("- inode %lx\n",mapping->host->i_ino);
+
+	list_for_each_entry(page,&mapping->io_pages,list) {
+		printk("  - pg %lu\n",page->index);
+	}
+
+	write_unlock(&mapping->page_lock);
+
 	BUG();
 	return -EIO;
 }
@@ -299,7 +323,17 @@
 	ClearPageMappedToDisk(page);
 	pageio->flags = 0;
 
-	if (block) cachefs_block_put(page->mapping->host->i_sb->s_fs_info,block);
+	if (block) {
+		int usage = atomic_read(&block->usage);
+
+		if ((usage&0xffffff00)==0x6b6b6b00) {
+			printk("\nBLOCK PUT ERROR pg=%p{ix=%lu} blk=%p{u=%x}\n",
+			       page,page->index,block,usage);
+			BUG();
+		}
+
+		cachefs_block_put(page->mapping->host->i_sb->s_fs_info,block);
+	}
 
 	/*
 	 * We release buffers only if the entire page is being invalidated.
@@ -319,6 +353,7 @@
  */
 static int cachefs_vio_releasepage(struct page *page, int gfp_flags)
 {
+	struct cachefs_block *block;
 	struct cachefs_page *pageio;
 
 	_enter("{%lu},%x",page->index,gfp_flags);
@@ -330,9 +365,9 @@
 		ClearPageMappedToDisk(page);
 
 		if (pageio) {
-			if (pageio->mapped_block)
-				cachefs_block_put(page->mapping->host->i_sb->s_fs_info,
-						  pageio->mapped_block);
+			block = xchg(&pageio->mapped_block,NULL);
+			if (block)
+				cachefs_block_put(page->mapping->host->i_sb->s_fs_info,block);
 			dbgfree(pageio);
 			kfree(pageio);
 		}
@@ -341,6 +376,20 @@
 	_leave(" = 0");
 	return 0;
 } /* end cachefs_vio_releasepage() */
+
+/*****************************************************************************/
+/*
+ * 
+ */
+static int cachefs_vio_set_page_dirty(struct page *page)
+{
+	kenter("{%lu}",page->index);
+
+	BUG();
+
+	return __set_page_dirty_nobuffers(page);
+
+} /* end cachefs_vio_set_page_dirty() */
 
 /*****************************************************************************/
 /*

Index: interface.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/interface.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- interface.c	17 Apr 2003 11:59:04 -0000	1.1
+++ interface.c	24 Apr 2003 12:02:34 -0000	1.2
@@ -16,10 +16,9 @@
 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 cachefs_match_val_t cachefs_fsdef_index_match(void *target, const void *entry);
 
-static void cachefs_fsdef_index_update(struct cachefs_object *source, void *entry);
+static void cachefs_fsdef_index_update(void *source, void *entry);
 
 static struct cachefs_index_def cachefs_fsdef_index_def = {
 	.name		= ".fsdef",
@@ -28,20 +27,37 @@
 	.update		= cachefs_fsdef_index_update
 };
 
-static struct cachefs_object cachefs_fsdef_index = {
+static struct cachefs_cookie cachefs_fsdef_index = {
+	.usage		= ATOMIC_INIT(1),
 	.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;
+static void __cachefs_cookie_put(struct cachefs_cookie *cookie);
+static inline void cachefs_cookie_put(struct cachefs_cookie *cookie)
+{
+	if (atomic_dec_and_test(&cookie->usage))
+		__cachefs_cookie_put(cookie);
+	else if (atomic_read(&cookie->usage)<0)
+		BUG();
+}
+
+static void __cachefs_put_active_inode(struct cachefs_active_inode *active);
+static inline void cachefs_put_active_inode(struct cachefs_active_inode *active)
+{
+	if (atomic_dec_and_lock(&active->usage,&active->super->ino_tree_lock))
+		__cachefs_put_active_inode(active);
+	else if (atomic_read(&active->usage)<0)
+		BUG();
+}
 
 /*****************************************************************************/
 /*
  * register a network filesystem for caching
  */
-int cachefs_register_netfs(struct cachefs_netfs *netfs)
+int cachefs_register_netfs(struct cachefs_netfs *netfs,
+			   struct cachefs_index_def *primary_idef)
 {
 	struct cachefs_netfs *ptr;
 	int ret;
@@ -50,10 +66,26 @@
 
 	INIT_LIST_HEAD(&netfs->link);
 
-	INIT_LIST_HEAD(&netfs->primary_index.active_inodes);
-	init_rwsem(&netfs->primary_index.sem);
+	netfs->primary_index = kmalloc(sizeof(*netfs->primary_index),GFP_KERNEL);
+	if (!netfs->primary_index) {
+		kleave(" = -ENOMEM");
+		return -ENOMEM;
+	}
+
+	memset(netfs->primary_index,0,sizeof(*netfs->primary_index));
+
+	atomic_set(&netfs->primary_index->usage,1);
+	atomic_set(&netfs->primary_index->children,0);
 
-	netfs->primary_index.iparent = &cachefs_fsdef_index;
+	netfs->primary_index->idef		= primary_idef;
+	netfs->primary_index->iparent		= &cachefs_fsdef_index;
+	netfs->primary_index->netfs_data	= netfs;
+
+	atomic_inc(&netfs->primary_index->iparent->usage);
+	atomic_inc(&netfs->primary_index->iparent->children);
+
+	INIT_LIST_HEAD(&netfs->primary_index->active_inodes);
+	init_rwsem(&netfs->primary_index->sem);
 
 	/* check it's not already present */
 	down_write(&cachefs_addremove_sem);
@@ -79,6 +111,7 @@
 /*****************************************************************************/
 /*
  * unregister a network filesystem from the cache
+ * - all cookies must have been released first
  */
 void cachefs_unregister_netfs(struct cachefs_netfs *netfs)
 {
@@ -88,7 +121,7 @@
 
 	list_del(&netfs->link);
 
-	cachefs_unregister_object(&netfs->primary_index,0);
+	cachefs_relinquish_cookie(netfs->primary_index,0);
 
 	up_write(&cachefs_addremove_sem);
 
@@ -104,21 +137,22 @@
  */
 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 */
+	memset(active,0,sizeof(*active));
+
 	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;
+	active->cookie	= &cachefs_fsdef_index;
 
 	init_waitqueue_head(&active->initwq);
+	init_rwsem(&active->sem);
 
 	/* actually do the stuff */
 	down_write(&cachefs_addremove_sem);
@@ -127,38 +161,54 @@
 
 	up_write(&cachefs_addremove_sem);
 
-	write_lock_irqsave(&super->ino_tree_lock,flags);
+	spin_lock(&super->ino_tree_lock);
 	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);
+	spin_unlock(&super->ino_tree_lock);
 
 	down_write(&cachefs_fsdef_index.sem);
 	list_add_tail(&active->link,&cachefs_fsdef_index.active_inodes);
+	atomic_inc(&cachefs_fsdef_index.usage);
 	up_write(&cachefs_fsdef_index.sem);
 
-	cachefs_num_active_inodes++;
-
 	kleave("");
 } /* end cachefs_add_cache() */
 
 /*****************************************************************************/
 /*
- * remove an unmounted cache from the list
+ * withdraw an unmounted cache from the active service
  */
-void cachefs_del_cache(struct cachefs_super *super)
+void cachefs_withdraw_cache(struct cachefs_super *super)
 {
-	kenter("");
+	struct cachefs_active_inode *active;
+	struct rb_node *n;
 
-	down_write(&cachefs_addremove_sem);
+	kenter("");
 
-	BUG();
+	/* make the cache unavailable for cookie acquisition */
+	set_bit(CACHEFS_SUPER_WITHDRAWN,&super->flags);
 
+	down_write(&cachefs_addremove_sem);
 	list_del_init(&super->mnt_link);
-
 	up_write(&cachefs_addremove_sem);
 
+	/* we now have to destroy all the active inodes pertaining to this superblock */
+	spin_lock(&super->ino_tree_lock);
+	while ((n = rb_first(&super->ino_tree))) {
+		active = rb_entry(n,struct cachefs_active_inode,node);
+		rb_erase(n,&super->ino_tree);
+		spin_unlock(&super->ino_tree_lock);
+
+		/* we've extracted an active inode from the tree */
+		cachefs_withdraw_active_inode(active);
+		cachefs_put_active_inode(active);
+
+		spin_lock(&super->ino_tree_lock);
+	}
+	spin_unlock(&super->ino_tree_lock);
+
 	kleave("");
-} /* end cachefs_del_cache() */
+} /* end cachefs_withdraw_cache() */
 
 /*****************************************************************************/
 /*
@@ -168,24 +218,24 @@
  *   - 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,
+static int cachefs_lookup_object(struct cachefs_cookie *cookie,
 				 struct cachefs_super *super,
 				 int create)
 {
 	struct cachefs_active_inode *ipactive, *active, *xactive;
-	struct cachefs_object *iparent;
+	struct cachefs_cookie *iparent;
 	struct rb_node *parent, **p;
 	unsigned long flags;
 	int ret;
 
-	iparent = object->iparent;
+	iparent = cookie->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>");
+	kenter("{%s/%s},",iparent->idef->name,cookie->idef ? (char*)cookie->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);
+	list_for_each_entry(active,&cookie->active_inodes,link) {
+		kdebug("check entry %p x %p [ino %u]",cookie,super,active->ino);
 
 		if (active->super==super) {
 			kdebug("found entry");
@@ -203,7 +253,7 @@
 	}
 
 	/* allocate an entry for this object */
-	kdebug("alloc entry %p x %p",object,super);
+	kdebug("alloc entry %p x %p",cookie,super);
 
 	active = kmalloc(sizeof(*active),GFP_KERNEL);
 	if (!active) {
@@ -211,21 +261,26 @@
 		return -ENOMEM;
 	}
 
+	memset(active,0,sizeof(*active));
+
 	active->super	= super;
 	active->ino	= 0;
 	active->flags	= 1 << CACHEFS_ACTIVE_INODE_LIVE;
 	active->storage	= NULL;
-	active->object	= object;
+	active->cookie	= cookie;
 
-	if (object->idef)
+	if (cookie->idef)
 		active->flags |= 1 << CACHEFS_ACTIVE_INODE_ISINDEX;
 
 	atomic_set(&active->usage,1);
 	INIT_LIST_HEAD(&active->link);
 	init_waitqueue_head(&active->initwq);
+	init_rwsem(&active->sem);
 
  found_entry:
-	/* we need to insert an entry for this object in the object's parent index, so the first
+	down_write(&active->sem);
+
+	/* we need to insert an entry for this cache 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
 	 */
@@ -235,7 +290,10 @@
 	if (ret<0) {
 		if (ret==-ENODATA) {
 			/* set a negative entry */
-			list_add_tail(&active->link,&object->active_inodes);
+			if (list_empty(&active->link)) {
+				list_add_tail(&active->link,&cookie->active_inodes);
+				atomic_inc(&cookie->usage);
+			}
 		}
 
 		up_write(&iparent->sem);
@@ -259,14 +317,25 @@
 	/* 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;
+	default:
+		goto error;
+
+	case 0:
+		if (list_empty(&active->link)) {
+			list_add_tail(&active->link,&cookie->active_inodes);
+			atomic_inc(&cookie->usage);
+		}
+		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 (list_empty(&active->link)) {
+			list_add_tail(&active->link,&cookie->active_inodes);
+			atomic_inc(&cookie->usage);
+		}
 
 		if (!create) {
+			up_write(&active->sem);
 			up_read(&iparent->sem);
 			goto nodata;
 		}
@@ -286,7 +355,7 @@
 
 	atomic_inc(&active->usage);
 
-	write_lock_irqsave(&super->ino_tree_lock,flags);
+	spin_lock_irqsave(&super->ino_tree_lock,flags);
 
 	p = &super->ino_tree.rb_node;
 	while (*p) {
@@ -304,8 +373,9 @@
 	rb_link_node(&active->node,parent,p);
 	rb_insert_color(&active->node,&super->ino_tree);
 
-	write_unlock_irqrestore(&super->ino_tree_lock,flags);
+	spin_unlock_irqrestore(&super->ino_tree_lock,flags);
 
+	up_write(&active->sem);
 	up_read(&iparent->sem);
 	kleave(" = 0");
 	return 0;
@@ -313,7 +383,9 @@
  error:
 	up_read(&iparent->sem);
  error2:
-	if (list_empty(&active->link)) kfree(active);
+	up_write(&active->sem);
+	if (list_empty(&active->link))
+		kfree(active);
 	kleave(" = %d",ret);
 	return ret;
 
@@ -344,41 +416,89 @@
 
 /*****************************************************************************/
 /*
- * register an object
+ * request a cookie to represent a data file or an index
+ * - iparent specifies the parent index to pin in memory
+ *   - the top level index cookie for each netfs is stored in the cachefs_netfs struct upon
+ *     registration
+ * - idef is NULL for a data file
+ * - idef points to the definition for an index
+ * - the netfs_data will be passed to the functions pointed to in *idef
  * - 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
+ * - we never let on to the netfs about errors
+ *   - we may set a NULL cookie pointer, but that's okay
  */
-int cachefs_register_object(struct cachefs_object *object)
+void cachefs_acquire_cookie(struct cachefs_cookie *iparent,
+			    struct cachefs_index_def *idef,
+			    void *netfs_data,
+			    struct cachefs_cookie **_cookie)
 {
 	struct cachefs_active_inode *active;
+	struct cachefs_cookie *cookie;
 	struct cachefs_super *super;
 	struct list_head *_p, *_n;
 	int ret = 0;
 
-	kenter("{%s}",object->idef?(char*)object->idef->name:"<file>");
+	*_cookie = NULL;
+
+	kenter("{%s},{%s},%p,",
+	       iparent ? (char*)iparent->idef->name : "<no-parent>",
+	       idef ? (char*)idef->name : "<file>",
+	       netfs_data);
+
+	/* if no parent cookie, then don't create one here either */
+	if (!iparent) {
+		*_cookie = NULL;
+		kleave(" [no parent]");
+		return;
+	}
+
+	/* allocate a cookie first and pass it back */
+	cookie = kmalloc(sizeof(*cookie),GFP_KERNEL);
+	if (!cookie) {
+		*_cookie = NULL;
+		kleave(" [ENOMEM]");
+		return;
+	}
+
+	memset(cookie,0,sizeof(*cookie));
+
+	atomic_set(&cookie->usage,1);
+	atomic_set(&cookie->children,0);
 
-	INIT_LIST_HEAD(&object->active_inodes);
-	init_rwsem(&object->sem);
+	atomic_inc(&iparent->usage);
+	atomic_inc(&iparent->children);
 
+	cookie->idef		= idef;
+	cookie->iparent		= iparent;
+	cookie->netfs_data	= netfs_data;
+
+	INIT_LIST_HEAD(&cookie->active_inodes);
+	init_rwsem(&cookie->sem);
+
+	*_cookie = cookie;
+
+	/* now we need to see whether the backing objects for this cookie yet exist */
 	down_read(&cachefs_addremove_sem);
 	if (list_empty(&cachefs_cache_list)) {
 		up_read(&cachefs_addremove_sem);
-		kleave(" = 0 [no caches]");
-		return 0;
+		kleave(" [no caches]");
+		return;
 	}
 
-	down_write(&object->sem);
+	down_write(&cookie->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);
+		ret = cachefs_lookup_object(cookie,super,0);
 		switch (ret) {
 		case 0:
-			if (!object->idef)
+			if (!cookie->idef)
 				break;	/* only want the first file entry */
 		case -ENODATA:
+			ret = 0;
 			continue;
 		default:
 			goto error;
@@ -386,13 +506,13 @@
 	}
 
 	/* if this object is a file, select a cache on which to store it */
-	if (!object->idef) {
+	if (!cookie->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) {
+		list_for_each_safe(_p,_n,&cookie->active_inodes) {
 			active = list_entry(_p,struct cachefs_active_inode,link);
 			if (active->super==super || active->ino==0) {
 				list_del(&active->link);
@@ -405,51 +525,153 @@
 			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;
-		}
+		ret = cachefs_lookup_object(cookie,super,1);
+		if (ret==0)
+			goto done;
+		if (ret==-ENODATA)
+			BUG();
 	}
 
-	/* 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);
+	printk("CacheFS: error from cache fs: %d\n",ret);
+ done:
+	up_write(&cookie->sem);
 	up_read(&cachefs_addremove_sem);
+	kleave("");
+} /* end cachefs_acquire_cookie() */
 
-	kleave(" = %d",ret);
-	return ret;
-} /* end cachefs_register_object() */
-
-EXPORT_SYMBOL(cachefs_register_object);
+EXPORT_SYMBOL(cachefs_acquire_cookie);
 
 /*****************************************************************************/
 /*
- * unregister an object from the cache
+ * release a cookie back to the cache
  * - the object will be marked as recyclable on disc if retire is true
+ * - all dependents of this cookie must have already been unregistered (indexes/files/pages)
  */
-void cachefs_unregister_object(struct cachefs_object *object, int retire)
+void cachefs_relinquish_cookie(struct cachefs_cookie *cookie, int retire)
 {
-	kenter("{%s},%d",object->idef?(char*)object->idef->name:"<file>",retire);
+	struct cachefs_active_inode *active;
 
-	BUG();
+	kenter("{%s},%d",
+	       cookie && cookie->idef ? (char*)cookie->idef->name : "<file>",
+	       retire);
+
+	if (!cookie) {
+		kleave(" [no cookie]");
+		return;
+	}
+
+	if (atomic_read(&cookie->children)!=0) {
+		printk("CacheFS: cookie still has children\n");
+		BUG();
+	}
+
+	/* detach pointers back to netfs */
+	down_write(&cookie->sem);
+
+	cookie->netfs_data	= NULL;
+	cookie->idef		= NULL;
+
+	/* note that all the inodes supporting this object need recycling */
+	if (retire) {
+		list_for_each_entry(active,&cookie->active_inodes,link) {
+			set_bit(CACHEFS_ACTIVE_INODE_RECYCLING,&active->flags);
+		}
+	}
+
+	/* break links with all the active inodes */
+	while (!list_empty(&cookie->active_inodes)) {
+		active = list_entry(&cookie->active_inodes, struct cachefs_active_inode,link);
+
+		/* detach the cache inode from the cached object cookie */
+		set_bit(CACHEFS_ACTIVE_INODE_RELEASING,&active->flags);
+
+		list_del_init(&active->link);
+
+		down_write(&active->sem);
+		active->cookie = NULL;
+		up_write(&active->sem);
+
+		if (atomic_dec_and_test(&cookie->usage))
+			BUG(); /* shouldn't've reduced the cookie usership to 0 yet */
+
+		cachefs_put_active_inode(active);
+	}
+
+	up_write(&cookie->sem);
+
+	cachefs_cookie_put(cookie);
+
+	kleave("");
+} /* end cachefs_relinquish_cookie() */
+
+EXPORT_SYMBOL(cachefs_relinquish_cookie);
+
+/*****************************************************************************/
+/*
+ * withdraw an inode from active service
+ * - need break the links to a cached object cookie
+ * - called under two situations:
+ *   (1) recycler decides to reclaim an in-use inode
+ *   (2) a cache is unmounted
+ * - have to take care as the cookie can be being relinquished by the netfs simultaneously
+ * - the active inode is pinned by the caller holding a refcount on it
+ */
+void cachefs_withdraw_active_inode(struct cachefs_active_inode *active)
+{
+	struct cachefs_cookie *cookie, *xcookie = NULL;
+
+	kenter("%p",active);
+
+	set_bit(CACHEFS_ACTIVE_INODE_WITHDRAWN,&active->flags);
+
+	/* first of all we have to break the links between the active inode and the cookie
+	 * - we have to hold both writelocks BUT we have to get the cookie lock FIRST
+	 */
+		kdebug("%d",__LINE__);
+	down_write(&active->sem);
+
+	cookie = active->cookie;
+	kdebug("cookie: %p",cookie);
+
+	if (cookie) {
+		atomic_inc(&cookie->usage); /* pin the cookie */
+
+		up_write(&active->sem); /* re-order the locks to avoid deadlock */
+		kdebug("%d",__LINE__);
+		down_write(&cookie->sem);
+		kdebug("%d",__LINE__);
+		down_write(&active->sem);
+		kdebug("%d",__LINE__);
+
+		list_del_init(&active->link);
+
+		xcookie = active->cookie;
+		active->cookie = NULL;
+
+		up_write(&cookie->sem);
+	}
 
-} /* end cachefs_unregister_object() */
+	up_write(&active->sem);
 
-EXPORT_SYMBOL(cachefs_unregister_object);
+	cachefs_cookie_put(cookie);
+
+	if (xcookie) {
+		cachefs_cookie_put(xcookie);
+		cachefs_put_active_inode(active);
+	}
+
+	kleave("");
+} /* end cachefs_withdraw_active_inode() */
 
 /*****************************************************************************/
 /*
  * see if the netfs definition matches
  */
-static cachefs_match_val_t cachefs_fsdef_index_match(struct cachefs_object *index,
-						     const void *_entry)
+static cachefs_match_val_t cachefs_fsdef_index_match(void *target, const void *entry)
 {
-	const struct cachefs_ondisc_fsdef *fsdef = _entry;
-	struct cachefs_netfs *netfs = container_of(index,struct cachefs_netfs,primary_index);
+	const struct cachefs_ondisc_fsdef *fsdef = entry;
+	struct cachefs_netfs *netfs = target;
 
 	kenter("{%s.%u},{%s.%u}",
 	       netfs->name,netfs->version,
@@ -473,10 +695,10 @@
 /*
  * update the netfs definition to be stored on disc
  */
-static void cachefs_fsdef_index_update(struct cachefs_object *source, void *entry)
+static void cachefs_fsdef_index_update(void *source, void *entry)
 {
 	struct cachefs_ondisc_fsdef *fsdef = entry;
-	struct cachefs_netfs *netfs = container_of(source,struct cachefs_netfs,primary_index);
+	struct cachefs_netfs *netfs = source;
 
 	kenter("{%s.%u},",netfs->name,netfs->version);
 
@@ -485,3 +707,45 @@
 	fsdef->version = netfs->version;
 
 } /* end cachefs_fsdef_index_update() */
+
+/*****************************************************************************/
+/*
+ * destroy a cookie
+ */
+static void __cachefs_cookie_put(struct cachefs_cookie *cookie)
+{
+	kenter("");
+
+	kfree(cookie);
+
+	kleave("");
+} /* end __cachefs_cookie_put() */
+
+/*****************************************************************************/
+/*
+ * destroy an active inode
+ * - called with super->ino_tree_lock held
+ */
+static void __cachefs_put_active_inode(struct cachefs_active_inode *active)
+{
+	struct cachefs_super *super;
+
+	kenter("");
+
+	/* remove from the cache's inode tree */
+	super = active->super;
+
+	if (!test_bit(CACHEFS_ACTIVE_INODE_WITHDRAWN,&active->flags))
+		rb_erase(&active->node,&super->ino_tree);
+
+	spin_unlock(&super->ino_tree_lock);
+
+	if (active->storage) {
+		BUG();
+		cachefs_block_put(active->super,active->storage);
+	}
+
+	kfree(active);
+
+	kleave("");
+} /* end __cachefs_put_active_inode() */

Index: inode.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/inode.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- inode.c	17 Apr 2003 11:59:04 -0000	1.16
+++ inode.c	24 Apr 2003 12:02:34 -0000	1.17
@@ -252,6 +252,8 @@
 
 	kenter(",%lu,",ino);
 
+	*_inode = NULL;
+
 	/* it does reside in this cache - create an inode for it */
 	vfs_inode = iget_locked(super->sb,ino);
 	if (!vfs_inode) {

Index: index.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/index.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- index.c	17 Apr 2003 11:59:04 -0000	1.14
+++ index.c	24 Apr 2003 12:02:34 -0000	1.15
@@ -29,8 +29,8 @@
 #include "cachefs-int.h"
 
 struct cachefs_index_search_record {
-	struct cachefs_object		*index;
-	struct cachefs_object		*target;
+	struct cachefs_cookie		*index;
+	struct cachefs_cookie		*target;
 	struct cachefs_inode		*iinode;
 	unsigned			entsize;
 	int				entry;
@@ -115,15 +115,15 @@
 	loff_t pos;
 	int ret;
 
-	kenter("{%s,%u}",index->object->idef->name,index->ino);
+	kenter("{%s,%u}",index->cookie->idef->name,index->ino);
 
 	/* get the inode */
 	ret = cachefs_iget(index->super,index->ino,&rec.iinode);
 	if (ret<0)
 		goto error;
 
-	rec.index	= index->object;
-	rec.target	= target->object;
+	rec.index	= index->cookie;
+	rec.target	= target->cookie;
 	rec.entry	= UINT_MAX;
 	rec.entsize	= rec.iinode->index_esize;
 
@@ -220,6 +220,10 @@
 
 	kenter("{%lu},",iinode->vfs_inode.i_ino);
 
+	*_page		= NULL;
+	*_newentry	= 0;
+	*_next		= 0;
+
 	storage = kmap(iinode->storage) + iinode->storage_offset;
 	newentry = storage->freelink;
 	kunmap(iinode->storage);
@@ -292,7 +296,7 @@
 /*****************************************************************************/
 /*
  * allocate an entry in the specified index file and associate an inode with it
- * - target->object->def determines whether the new inode will be a file or an index
+ * - target->cookie->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,
@@ -307,7 +311,7 @@
 	unsigned ino, ixentry, offset, inonext, ixnext, ino_offset;
 	int ret, loop;
 
-	kenter("{%lu},{%s},",iinode->vfs_inode.i_ino,index->object->idef->name);
+	kenter("{%lu},{%s},",iinode->vfs_inode.i_ino,index->cookie->idef->name);
 
 	super = index->super;
 	inopage = NULL;
@@ -334,7 +338,7 @@
 	offset = (ixentry % iinode->index_epp) * iinode->index_esize;
 
 	trans->jentry->mark = CACHEFS_ONDISC_UJNL_INDEX_ALLOCING;
-	if (!target->object->idef)
+	if (!target->cookie->idef)
 		trans->jentry->mark = CACHEFS_ONDISC_UJNL_INODE_ALLOCING;
 
 	trans->jentry->index	= iinode->vfs_inode.i_ino;
@@ -369,10 +373,10 @@
 	xent->ino	= ino;
 	xent->type	= CACHEFS_ONDISC_INDEX_DATAFILE;
 
-	if (target->object->idef)
+	if (target->cookie->idef)
 		xent->type = CACHEFS_ONDISC_INDEX_INDEXFILE;
 
-	index->object->idef->update(target->object,xent->data);
+	index->cookie->idef->update(target->cookie->netfs_data,xent->data);
 
 	kunmap(ixpage);
 
@@ -395,8 +399,8 @@
 	storage->pindex		= iinode->vfs_inode.i_ino;
 	storage->pindex_entry	= ixentry;
 
-	if (target->object->idef) {
-		struct cachefs_index_def *definition = target->object->idef;
+	if (target->cookie->idef) {
+		struct cachefs_index_def *definition = target->cookie->idef;
 
 		storage->index_dsize	= definition->data_size;
 		storage->index_esize	= storage->index_dsize;
@@ -444,7 +448,7 @@
 	struct cachefs_inode *iinode;
 	int ret;
 
-	kenter("{%u,%s},",index->ino,index->object->idef->name);
+	kenter("{%u,%s},",index->ino,index->cookie->idef->name);
 
 	/* get the index inode */
 	ret = cachefs_iget(index->super,index->ino,&iinode);

Index: cachetest-main.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/cachetest-main.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- cachetest-main.c	17 Apr 2003 11:59:04 -0000	1.7
+++ cachetest-main.c	24 Apr 2003 12:02:34 -0000	1.8
@@ -33,7 +33,7 @@
 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 cachefs_cookie	*cache;		/* caching cookie */
 };
 
 struct afs_volume {
@@ -41,22 +41,22 @@
 	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 cachefs_cookie	*cache;		/* caching cookie */
 };
 
 struct afs_inode {
 	u_int32_t		fid;		/* [KEY] file ID */
-	struct cachefs_object	cache;		/* caching cookie */
+	struct cachefs_cookie	*cache;		/* caching cookie */
 };
 
 /* 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 cachefs_match_val_t cell_match(void *target, const void *entry);
+static void cell_update(void *source, void *entry);
 
-static struct cachefs_index_def cachetest_netfs = {
-	.name		= "AFS",
+static struct cachefs_index_def cachetest_cell_index_def = {
+	.name		= "cell_ix",
 	.data_size	= 124,
 	.keys[0]	= { CACHEFS_INDEX_KEYS_ASCIIZ, 64 },
 	.match		= cell_match,
@@ -69,7 +69,6 @@
 static struct cachefs_netfs cachetest = {
 	.name		= "cachetest",
 	.version	= 0,
-	.primary_index	= { .idef = &cachetest_netfs},
 	.ops		= &cachetest_ops,
 };
 
@@ -77,11 +76,11 @@
  * - 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 cachefs_match_val_t vldb_match(void *target, const void *entry);
+static void vldb_update(void *source, void *entry);
 
-static struct cachefs_index_def cachetest_cell = {
-	.name		= "cell",
+static struct cachefs_index_def cachetest_volume_index_def = {
+	.name		= "vol_ix",
 	.data_size	= 124,
 	.keys[0]	= { CACHEFS_INDEX_KEYS_ASCIIZ, 64 },
 	.match		= vldb_match,
@@ -90,21 +89,17 @@
 
 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 cachefs_match_val_t file_match(void *target, const void *entry);
+static void file_update(void *source, void *entry);
 
-static struct cachefs_index_def cachetest_volume = {
-	.name		= "volume",
+static struct cachefs_index_def cachetest_file_index_def = {
+	.name		= "file_ix",
 	.data_size	= 4,
 	.keys[0]	= { CACHEFS_INDEX_KEYS_BIN, 4 },
 	.match		= file_match,
@@ -113,10 +108,6 @@
 
 static struct afs_volume afs_root_volume = {
 	.name		= "#afs.root",
-	.cache		= {
-		.idef		= &cachetest_volume,
-		.iparent	= &afs_mycell.cache,
-	},
 };
 
 /* AFS root dir
@@ -125,10 +116,6 @@
  */
 static struct afs_inode afs_root_dir = {
 	.fid		= 0x1234abcd,
-	.cache		= {
-		.idef		= NULL,
-		.iparent	= &afs_root_volume.cache,
-	},
 };
 
 /*****************************************************************************/
@@ -141,26 +128,29 @@
 
 	printk(KERN_INFO "cachefstest: general fs caching v0.1 tester registering\n");
 
-	ret = cachefs_register_netfs(&cachetest);
+	ret = cachefs_register_netfs(&cachetest,&cachetest_cell_index_def);
 	if (ret<0)
 		goto error;
 
 	printk("\n### Register cell object\n");
-	ret = cachefs_register_object(&afs_mycell.cache);
-	if (ret<0)
-		goto error;
+	cachefs_acquire_cookie(cachetest.primary_index,
+			       &cachetest_volume_index_def,
+			       &afs_mycell,
+			       &afs_mycell.cache);
 
 	printk("\n### Register volume object\n");
-	ret = cachefs_register_object(&afs_root_volume.cache);
-	if (ret<0)
-		goto error;
+	cachefs_acquire_cookie(afs_mycell.cache,
+			       &cachetest_file_index_def,
+			       &afs_root_volume,
+			       &afs_root_volume.cache);
 
 	printk("\n### Register file object\n");
-	ret = cachefs_register_object(&afs_root_dir.cache);
-	if (ret<0)
-		goto error;
+	cachefs_acquire_cookie(afs_root_volume.cache,
+			       NULL,
+			       &afs_root_dir,
+			       &afs_root_dir.cache);
 
-	return ret;
+	return 0;
 
  error:
 	printk(KERN_ERR "cachefstest: failed to register: %d\n",ret);
@@ -175,9 +165,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_relinquish_cookie(afs_root_dir.cache,0);
+	cachefs_relinquish_cookie(afs_root_volume.cache,0);
+	cachefs_relinquish_cookie(afs_mycell.cache,0);
 	cachefs_unregister_netfs(&cachetest);
 
 } /* end cachefstest_exit() */
@@ -186,7 +176,7 @@
 /*
  * 
  */
-static cachefs_match_val_t cell_match(struct cachefs_object *target, const void *entry)
+static cachefs_match_val_t cell_match(void *target, const void *entry)
 {
 	struct afs_cell *cell = container_of(target,struct afs_cell,cache);
 
@@ -202,7 +192,7 @@
 /*
  * update a cell entry from the specified object
  */
-static void cell_update(struct cachefs_object *source, void *entry)
+static void cell_update(void *source, void *entry)
 {
 	struct afs_cell *cell = container_of(source,struct afs_cell,cache);
 
@@ -216,7 +206,7 @@
 /*
  * 
  */
-static cachefs_match_val_t vldb_match(struct cachefs_object *target, const void *entry)
+static cachefs_match_val_t vldb_match(void *target, const void *entry)
 {
 	struct afs_volume *volume = container_of(target,struct afs_volume,cache);
 
@@ -232,7 +222,7 @@
 /*
  * 
  */
-static void vldb_update(struct cachefs_object *source, void *entry)
+static void vldb_update(void *source, void *entry)
 {
 	struct afs_volume *volume = container_of(source,struct afs_volume,cache);
 
@@ -246,7 +236,7 @@
 /*
  * 
  */
-static cachefs_match_val_t file_match(struct cachefs_object *target, const void *entry)
+static cachefs_match_val_t file_match(void *target, const void *entry)
 {
 	struct afs_inode *inode = container_of(target,struct afs_inode,cache);
 	u_int32_t fid = htonl(inode->fid);
@@ -263,7 +253,7 @@
 /*
  * 
  */
-static void file_update(struct cachefs_object *source, void *entry)
+static void file_update(void *source, void *entry)
 {
 	struct afs_inode *inode = container_of(source,struct afs_inode,cache);
 	u_int32_t fid = htonl(inode->fid);

Index: cachefs-int.h
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/cachefs-int.h,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -r1.26 -r1.27
--- cachefs-int.h	17 Apr 2003 11:59:04 -0000	1.26
+++ cachefs-int.h	24 Apr 2003 12:02:34 -0000	1.27
@@ -73,6 +73,7 @@
 #define CACHEFS_SUPER_DO_RECLAIM	2		/* true if should do reclamation */
 #define CACHEFS_SUPER_RCM_IMM_SCAN	3		/* true if should scan for immediately
 							 * reclaimable inodes */
+#define CACHEFS_SUPER_WITHDRAWN		4		/* true if cache has been withdrawn */
 
 	/* block allocation and recycling management */
 	struct rb_root			blk_tree;	/* block mapping tree */
@@ -145,6 +146,7 @@
 	wait_queue_head_t		batch_done_wq;	/* blocks write complete wait queue */
 	struct timer_list		batch_timer;	/* time to next batch write */
 	wait_queue_head_t		batch_timer_wq;	/* batch timer wait queue */
+	wait_queue_head_t		batch_sync_wq;	/* batch sync wait queue */
 
 	struct list_head		jnld_link;	/* journalling daemon list */
 
@@ -156,7 +158,7 @@
 	int				dmn_die;	/* request to die */
 
 	/* event counting */
-	atomic_t			cnt_blk_tree;	/* number of outstanding blk_tree */
+	atomic_t			cnt_blk_tree;	/* number of outstanding blk_tree nodes */
 	atomic_t			cnt_ujnl_mkrq;	/* number of marks requested */
 	atomic_t			cnt_ujnl_mkgr;	/* number of marks granted */
 	atomic_t			cnt_ujnl_mkwr;	/* number of marks written */
@@ -167,14 +169,14 @@
 
 	/* index management */
 	struct rb_root			ino_tree;	/* tree of active inodes */
-	rwlock_t			ino_tree_lock;
+	spinlock_t			ino_tree_lock;
 
 	/* superblock copy */
 	struct cachefs_ondisc_superblock *layout;
 };
 
 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_withdraw_cache(struct cachefs_super *super);
 
 extern void cachefs_recycle_unready_blocks(struct cachefs_super *super);
 extern void cachefs_recycle_transfer_stack(struct cachefs_super *super);
@@ -182,6 +184,25 @@
 
 /*****************************************************************************/
 /*
+ * data file or index object cookie
+ * - a file will only appear in one cache
+ * - a request to cache a file may or may not be honoured, subject to constraints such as disc
+ *   space
+ * - indexes files are created on disc just-in-time
+ */
+struct cachefs_cookie
+{
+	atomic_t			usage;		/* number of users of this cookie */
+	atomic_t			children;	/* number of children of this cookie */
+	struct cachefs_index_def	*idef;		/* index definition */
+	struct cachefs_cookie		*iparent;	/* index holding this entry */
+	struct list_head		active_inodes;	/* inode(s) backing this file/index */
+	struct rw_semaphore		sem;
+	void				*netfs_data;	/* back pointer to netfs */
+};
+
+/*****************************************************************************/
+/*
  * cache file and directory management
  * - negative entry if .ino==0 (and node will be unused)
  */
@@ -195,15 +216,20 @@
 #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 */
+#define CACHEFS_ACTIVE_INODE_RELEASING	3	/* T if inode is being released */
+#define CACHEFS_ACTIVE_INODE_RECYCLING	4	/* T if inode is being retired */
+#define CACHEFS_ACTIVE_INODE_WITHDRAWN	5	/* T if inode has been withdrawn */
 
 	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 */
+	struct cachefs_cookie		*cookie;	/* netfs's file/index object */
+	struct rw_semaphore		sem;		/* guard on object pointer */
 };
 
+extern void cachefs_withdraw_active_inode(struct cachefs_active_inode *active);
+
 extern int cachefs_index_search(struct cachefs_active_inode *index,
 				struct cachefs_active_inode *target);
 
@@ -326,8 +352,15 @@
 
 static inline void cachefs_block_put(struct cachefs_super *super, struct cachefs_block *block)
 {
+	int usage = atomic_read(&block->usage);
 	/*kenter(",{bix=%u u=%d",block->bix,atomic_read(&block->usage));*/
-	BUG_ON(atomic_read(&block->usage)<0);
+
+	if ((usage&0xffffff00)==0x6b6b6b00) {
+		printk("\ncachefs_block_put(%p,%p{u=%d})\n",super,block,usage);
+		BUG();
+	}
+
+	BUG_ON(usage<=0);
 	if (atomic_dec_and_test(&block->usage))
 		__cachefs_block_put(super,block);
 }

Index: block.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/block.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- block.c	17 Apr 2003 11:59:04 -0000	1.2
+++ block.c	24 Apr 2003 12:02:34 -0000	1.3
@@ -125,6 +125,8 @@
 
 	_enter(",%u,,",bix);
 
+	if (_block) *_block = NULL;
+
 	/* get the block definition */
 	ret = cachefs_block_insert(super,bix,&block);
 	if (ret<0)
@@ -167,6 +169,9 @@
 
 	_enter(",%lx,%u,%d,,",inode?inode->vfs_inode.i_ino:CACHEFS_INO_MISC,bix,wipe);
 
+	if (_block) *_block = NULL;
+	if (_page)  *_page = NULL;
+
 	/* get the block definition */
 	ret = cachefs_block_insert(super,bix,&block);
 	if (ret<0) {
@@ -242,10 +247,13 @@
 	clear_bit(CACHEFS_BLOCK_ALLOC,&block->flags);
 	wake_up_all(&block->writewq);
 
-	if (_block)
+	if (_block) {
 		*_block = block;
-	else
+	}
+	else {
 		cachefs_block_put(super,block);
+		block = NULL;
+	}
 
 	if (_page) {
 		*_page = page;
@@ -395,6 +403,8 @@
 
 	_enter(",%u,",bix);
 
+	*_block = NULL;
+
 	/* allocate a block record just in case */
 	newblock = kmalloc(sizeof(*newblock),GFP_KERNEL);
 	if (!newblock)
@@ -460,6 +470,8 @@
 	unsigned long flags;
 
 	_enter(",%d,",bix);
+
+	*_block = NULL;
 
 	read_lock_irqsave(&super->blk_tree_lock,flags);
 	node = super->blk_tree.rb_node;

Index: aops.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/aops.c,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -r1.25 -r1.26
--- aops.c	17 Apr 2003 11:59:04 -0000	1.25
+++ aops.c	24 Apr 2003 12:02:34 -0000	1.26
@@ -73,6 +73,8 @@
 {
 	struct cachefs_page *cookie = (struct cachefs_page*) page->private;
 
+	*_cookie = NULL;
+
 	if (!cookie) {
 		cookie = kmalloc(sizeof(*cookie),gfp_flags);
 		if (!cookie)
@@ -208,6 +210,8 @@
 
 	_enter("{bits=%u},%llu,%d,%x,",sb->s_blocksize_bits,first_sector,nr_vecs,gfp_flags);
 
+	*_bio = NULL;
+
 	bio = bio_alloc(gfp_flags,nr_vecs);
 
 	if (!bio && (current->flags & PF_MEMALLOC)) {
@@ -838,6 +842,7 @@
  */
 static int cachefs_releasepage(struct page *page, int gfp_flags)
 {
+	struct cachefs_block *block;
 	struct cachefs_page *cookie;
 
 	_enter("{%lu},%x",page->index,gfp_flags);
@@ -849,9 +854,9 @@
 		ClearPageMappedToDisk(page);
 
 		if (cookie) {
-			if (cookie->mapped_block)
-				cachefs_block_put(page->mapping->host->i_sb->s_fs_info,
-						  cookie->mapped_block);
+			block = xchg(&cookie->mapped_block,NULL);
+			if (block)
+				cachefs_block_put(page->mapping->host->i_sb->s_fs_info,block);
 			dbgfree(cookie);
 			kfree(cookie);
 		}
@@ -1054,8 +1059,6 @@
 	cachefs_trans_commit(step->transaction);
 	step->transaction = NULL;
 
-	cachefs_block_put(super,block);
-
 	/* synchronise after committing (so our allocation will be sync'd before block reuse) */
 	if ((step->flags & CACHEFS_BLOCK_NEED_SYNC) &&
 	    test_bit(CACHEFS_BLOCK_CRITICAL,&block->flags)
@@ -1063,11 +1066,15 @@
 		cachefs_trans_sync(super,0);
 	}
 
+	cachefs_block_put(super,block);
+	block = NULL;
+
 	_leave(" = 0 [block %u]",step->bix);
 	return 0;
 
  error_block:
 	cachefs_block_put(super,block);
+	block = NULL;
  error_sem:
 	up(&super->alloc_sem);
 	cachefs_trans_put(step->transaction);
@@ -1288,9 +1295,9 @@
 		}
 
 	if (ret<0) {
-		if (cookie->mapped_block)
-			cachefs_block_put(inode->vfs_inode.i_sb->s_fs_info,cookie->mapped_block);
-		cookie->mapped_block = NULL;
+		struct cachefs_block *block = xchg(&cookie->mapped_block,NULL);
+		if (block)
+			cachefs_block_put(inode->vfs_inode.i_sb->s_fs_info,block);
 		_leave(" = %d",ret);
 		return ret;
 	}
@@ -1322,6 +1329,8 @@
 	struct page *page;
 
 	_enter("{%lu},%u",inode->vfs_inode.i_ino,index);
+
+	*_page = NULL;
 
 	page = read_cache_page(mapping,index,(filler_t*)mapping->a_ops->readpage,NULL);
 	dbgpgalloc(page);