Subject: afs/fs/cachefs super.c,1.23,1.24 status.c,1.4,1.5 rootdir.c,1.7,1.8 recycling.c,1.15,1.16 kcachefsd.c,1.8,1.9 journal.c,1.28,1.29 index.c,1.12,1.13 dump-journal.c,1.7,1.8 cachefs-layout.h,1.19,1.20 cachefs-int.h,1.24,1.25 aops.c,1.23,1.24 Makefile,1.13,1.14

From: [email-masked]
Date: Wed, 02 Apr 2003 10:12:34 +0100

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

Modified Files:
	super.c status.c rootdir.c recycling.c kcachefsd.c journal.c 
	index.c dump-journal.c cachefs-layout.h cachefs-int.h aops.c 
	Makefile 
Log Message:
can now recycle index trees

Index: super.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/super.c,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -r1.23 -r1.24
--- super.c	29 Mar 2003 11:13:47 -0000	1.23
+++ super.c	2 Apr 2003 09:12:31 -0000	1.24
@@ -244,6 +244,14 @@
 
 	memset(super,0,sizeof(*super));
 
+	super->rcm_imm_buf = (unsigned*) get_zeroed_page(GFP_KERNEL);
+	if (!super->rcm_imm_buf)
+		goto error;
+
+	super->rcm_atm_list = (struct cachefs_reclaimable *) get_zeroed_page(GFP_KERNEL);
+	if (!super->rcm_atm_list)
+		goto error;
+
 	/* fill in the superblock */
 	sb->s_magic		= CACHEFS_FS_MAGIC;
 	sb->s_op		= &cachefs_super_ops;
@@ -256,6 +264,8 @@
 
 	rwlock_init(&super->blk_tree_lock);
 
+	spin_lock_init(&super->rcm_lock);
+
 	init_MUTEX(&super->ujnl_alloc_sem);
 	init_waitqueue_head(&super->ujnl_alloc_wq);
 	init_waitqueue_head(&super->ujnl_sync_wq);
@@ -282,7 +292,6 @@
 
 	init_MUTEX(&super->alloc_sem);
 	init_waitqueue_head(&super->alloc_wq);
-	INIT_LIST_HEAD(&super->recycleq);
 
 	init_completion(&super->dmn_alive);
 	init_completion(&super->dmn_dead);
@@ -392,17 +401,21 @@
 	return 0;
 
  error:
-	if (super->dmn_task) {
-		super->dmn_die = 1;
-		wake_up(&super->dmn_sleepq);
-		wait_for_completion(&super->dmn_dead);
-	}
+	if (super) {
+		if (super->dmn_task) {
+			super->dmn_die = 1;
+			wake_up(&super->dmn_sleepq);
+			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->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);
+		if (super->rcm_imm_buf)		free_page((unsigned long)super->rcm_imm_buf);
 
-	kcachefs_jnld_remove_super(super);
+		kcachefs_jnld_remove_super(super);
+	}
 
 	if (page) {
 		wait_on_page_locked(page);
@@ -413,8 +426,8 @@
 	if (inode)	iput(&inode->vfs_inode);
 
 	if (super) {
-		if (super->istorage)	cachefs_iput(super->istorage);
-		if (super->imisc)	iput(super->imisc);
+		if (super->istorage)		cachefs_iput(super->istorage);
+		if (super->imisc)		iput(super->imisc);
 		dbgfree(super);
 		kfree(super);
 	}
@@ -710,6 +723,9 @@
 
 	if (super->recycle_block)
 		cachefs_block_put(super,super->recycle_block);
+
+	if (super->rcm_atm_list)	free_page((unsigned long)super->rcm_atm_list);
+	if (super->rcm_imm_buf)		free_page((unsigned long)super->rcm_imm_buf);
 
 	kcachefs_jnld_remove_super(super);

Index: status.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/status.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- status.c	21 Mar 2003 14:01:00 -0000	1.4
+++ status.c	2 Apr 2003 09:12:31 -0000	1.5
@@ -129,7 +129,9 @@
 	seq_printf(m,"Recyc Stk : TOS={%u} #%u NUM=%u\n",
 		   super->recycle_cur,super->recycle_room,super->recycle_cur_n);
 
-	seq_printf(m,"Recycler  : {%u} %u-%u\n",super->rcyblock,super->rcynext,super->rcystop);
+	seq_printf(m,"Reclaimer : ino=%u indir=%u blk=%u:%hu-%hu\n",
+		   super->rcm_ino,super->rcm_indirect,super->rcm_block,
+		   super->rcm_ptrnext,super->rcm_ptrstop);
 
 	seq_printf(m,"uj disc   : NEXT=%u ACK=%u\n",super->ujnl_head,super->ujnl_tail);

Index: rootdir.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/rootdir.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- rootdir.c	29 Mar 2003 11:13:47 -0000	1.7
+++ rootdir.c	2 Apr 2003 09:12:31 -0000	1.8
@@ -18,6 +18,7 @@
 #include <linux/file.h>
 #include <linux/pagemap.h>
 #include <linux/ctype.h>
+#include <linux/circ_buf.h>
 #include <asm/uaccess.h>
 #include "cachefs-int.h"
 
@@ -604,6 +605,9 @@
 	struct cachefs_ondisc_storage *storage;
 	struct cachefs_transaction *trans;
 	struct cachefs_inode *inode;
+	struct cachefs_super *super = dir->i_sb->s_fs_info;
+	unsigned long flags;
+	int ret;
 
 	kenter("{%lx},{%s,%p}",dir->i_ino,dentry->d_name.name,dentry->d_inode);
 
@@ -616,17 +620,23 @@
 	inode = CACHEFS_FS_I(dentry->d_inode);
 
 	/* mark for reclamation under journalling */
-	trans = cachefs_trans_alloc(dir->i_sb->s_fs_info,GFP_KERNEL);
+	trans = cachefs_trans_alloc(super,GFP_KERNEL);
 	if (!trans) {
 		kleave(" = -ENOMEM");
 		return -ENOMEM;
 	}
 
-	trans->jentry->mark	= CACHEFS_ONDISC_UJNL_INODE_RECLAIMING;
+	trans->jentry->mark	= CACHEFS_ONDISC_UJNL_INODE_MARK_RECLAIM;
 	trans->jentry->ino	= inode->vfs_inode.i_ino;
 
 	cachefs_trans_affects_inode(trans,inode);
-	cachefs_trans_mark(trans);
+
+	ret = cachefs_trans_mark(trans);
+	if (ret<0) {
+		cachefs_trans_put(trans);
+		kleave(" = %d",ret);
+		return ret;
+	}
 
 	/* modify the inode storage entry */
 	storage = kmap(inode->storage) + inode->storage_offset;
@@ -634,6 +644,22 @@
 	kunmap(inode->storage);
 
 	cachefs_trans_commit(trans);
+
+	/* add to the immediate-reclaim table if possible */
+	spin_lock_irqsave(&super->rcm_lock,flags);
+
+	if (CIRC_SPACE(super->rcm_imm_head,super->rcm_imm_tail,CACHEFS_RCM_IMM_BUFSIZE)>0) {
+		super->rcm_imm_buf[super->rcm_imm_head] = inode->vfs_inode.i_ino;
+		super->rcm_imm_head = (super->rcm_imm_head+1) & (CACHEFS_RCM_IMM_BUFSIZE-1);
+	}
+	else {
+		set_bit(CACHEFS_SUPER_RCM_IMM_SCAN,&super->flags);
+	}
+
+	spin_unlock_irqrestore(&super->rcm_lock,flags);
+
+	set_bit(CACHEFS_SUPER_DO_RECLAIM,&super->flags);
+	wake_up(&super->dmn_sleepq);
 
 	kleave(" = 0");
 	return 0;

Index: recycling.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/recycling.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- recycling.c	21 Mar 2003 14:01:00 -0000	1.15
+++ recycling.c	2 Apr 2003 09:12:31 -0000	1.16
@@ -25,28 +25,15 @@
 #include <linux/buffer_head.h>
 #include "cachefs-int.h"
 
-static void cachefs_recycle_manage_advance_rcynext(struct cachefs_super *super)
-{
-	super->rcynext++;
-}
-
-static void cachefs_recycle_manage_clear_rcyblock(struct cachefs_super *super)
-{
-	super->rcyblock	= 0;
-	super->rcynext	= 0;
-	super->rcystop	= 0;
-}
-
 /*****************************************************************************/
 /*
  * begin a new recycling node
  * - a block may be suggested as the target page
  */
-int cachefs_recycle_begin_new_node(struct cachefs_super *super,
-				   cachefs_blockix_t bix,
-				   cachefs_blockix_t upblock,
-				   unsigned short upentry,
-				   void (*manage)(struct cachefs_super *super))
+static int cachefs_recycle_begin_new_node(struct cachefs_super *super,
+					  cachefs_blockix_t bix,
+					  cachefs_blockix_t upblock,
+					  unsigned short upentry)
 {
 	struct cachefs_ondisc_free_node *node;
 	struct cachefs_transaction *trans;
@@ -114,8 +101,6 @@
 	page	= xchg(&super->recycle_node,page);
 	block	= xchg(&super->recycle_block,block);
 
-	if (manage) manage(super);
-
 	if (used_unready_node)
 		super->layout->bix_unready++;
 
@@ -157,7 +142,7 @@
 	 * block to set up a new one
 	 */
 	if (super->recycle_room==0)
-		cachefs_recycle_begin_new_node(super,0,0,0,NULL);
+		cachefs_recycle_begin_new_node(super,0,0,0);
 
 	qty = super->layout->bix_end - super->layout->bix_unready;
 	if (qty==0) {
@@ -222,233 +207,6 @@
 
 /*****************************************************************************/
 /*
- * recycle the dependents of the block currently in the recycling bin and then recycle the block
- * itself
- */
-static int cachefs_recycle_pointer_array(struct cachefs_super *super)
-{
-	struct cachefs_ondisc_free_node *node;
-	struct cachefs_transaction *trans;
-	cachefs_blockix_t *indirect, *jeptr;
-	struct page *page;
-	unsigned limit, count, src, dst, max;
-	int ret;
-
-	_enter("{room=%u block=%u:%hu-%hu},",
-	       super->recycle_room,super->rcyblock,super->rcynext,super->rcystop);
-
-	max = super->sb->s_blocksize - sizeof(struct cachefs_ondisc_update_journal);
-	max /= sizeof(cachefs_blockix_t);
-
-	/* load the pointer block page */
-	ret = cachefs_block_read(super,NULL,super->rcyblock,0,NULL,&page);
-	if (ret<0) {
-		_leave(" = %d",ret);
-		return ret;
-	}
-
-	wait_on_page_locked(page);
-
-	indirect = (cachefs_blockix_t*) kmap(page);
-
-	ret = 0;
-	for (;;) {
-		/* find an occupied pointer */
-		for (src=super->rcynext; src<super->rcystop; src++)
-			if (indirect[src])
-				goto found;
-		break;
-	found:
-
-		/* make sure there's a recycling block with space available */
-		if (super->recycle_room==0) {
-			/* recycle the first dependent page as the new recycling node */
-			super->rcynext = src;
-			cachefs_recycle_begin_new_node(super,indirect[src],super->rcyblock,src,
-						       cachefs_recycle_manage_advance_rcynext);
-			continue;
-		}
-
-		/* journal what we're going to do */
-		trans = cachefs_trans_alloc(super,GFP_KERNEL);
-		if (!trans)
-			goto out;
-
-		cachefs_trans_affects_block(trans,super->recycle_block,0,PAGE_SIZE);
-
-		limit = min(super->recycle_room,max);
-		dst = CACHEFS_ONDISC_LEAVES_PER_FREE_NODE - super->recycle_room;
-
-		trans->jentry->mark	= CACHEFS_ONDISC_UJNL_RECYC_SCAVENGE;
-		trans->jentry->block	= super->rcyblock;
-		trans->jentry->entry	= src;
-		trans->jentry->auxblock	= super->recycle_cur;
-		trans->jentry->auxentry	= dst;
-
-		/* transfer the pointers into the journal entry first */
-		jeptr = trans->jentry->rcyptrs;
-		count = 0;
-		while (count<limit && src<super->rcystop) {
-			if (indirect[src]) {
-				jeptr[count] = indirect[src];
-				count++;
-			}
-
-			src++;
-		}
-
-		trans->jentry->count	= count;
-
-		ret = cachefs_trans_mark(trans);
-		if (ret<0) {
-			printk("kcachefsd: Failed to mark journal: %d\n",ret);
-			cachefs_trans_put(trans);
-			break;
-		}
-
-		super->recycle_room -= count;
-		super->recycle_cur_n += count;
-		if (super->recycle_room==0) super->recycle_cur_n++;
-
-		/* transfer from the jentry to the recycling block */
-		cachefs_block_modify(super,super->recycle_block,&super->recycle_node);
-
-		node = (struct cachefs_ondisc_free_node*) kmap(super->recycle_node);
-
-		memcpy(&node->leaves[dst],trans->jentry->rcyptrs,count*sizeof(cachefs_blockix_t));
-
-		kunmap(node);
-
-		super->rcynext = src;
-		cachefs_trans_commit(trans);
-		trans = NULL;
-	}
-
-	kunmap(page);
-	dbgpgfree(page);
-	page_cache_release(page);
-
-	/* finally, the pointer block itself must be recycled */
-	if (super->recycle_room==0) {
-		/* reuse as new recycling node */
-		super->rcyblock = 0;
-		cachefs_recycle_begin_new_node(super,indirect[src],super->rcyblock,src,
-					       cachefs_recycle_manage_clear_rcyblock);
-	}
-	else {
-		/* add to current recycling node */
-		unsigned short slot = CACHEFS_ONDISC_LEAVES_PER_FREE_NODE - super->recycle_room;
-
-		trans = cachefs_trans_alloc(super,GFP_KERNEL);
-		if (!trans)
-			goto out;
-
-		cachefs_trans_affects_block(trans,super->recycle_block,0,PAGE_SIZE);
-
-		trans->jentry->mark	= CACHEFS_ONDISC_UJNL_RECYC_PTRBLK;
-		trans->jentry->block	= super->rcyblock;
-		trans->jentry->auxblock	= super->recycle_cur;
-		trans->jentry->auxentry	= slot;
-
-		ret = cachefs_trans_mark(trans);
-		if (ret<0) {
-			printk("kcachefsd: Failed to mark journal: %d\n",ret);
-			cachefs_trans_put(trans);
-			goto out2;
-		}
-
-		node = (struct cachefs_ondisc_free_node*) kmap(super->recycle_node);
-		node->leaves[slot] = super->rcyblock;
-		kunmap(node);
-
-		super->recycle_room--;
-		super->recycle_cur_n++;
-		if (super->recycle_room==0) super->recycle_cur_n++;
-
-		super->rcyblock	= 0;
-		super->rcynext	= 0;
-		super->rcystop	= 0;
-		cachefs_trans_commit(trans);
-	out2:
-		trans = NULL;
-	out:
-		;
-	}
-
-	_leave(" = %d",ret);
-	return ret;
-} /* end cachefs_recycle_pointer_array() */
-
-/*****************************************************************************/
-/*
- * recycle an indirection block
- */
-static int cachefs_recycle_indirect_block(struct cachefs_super *super,
-					  ino_t ino,
-					  struct page **_parent,
-					  unsigned poffset,
-					  cachefs_blockix_t bix,
-					  unsigned short first,
-					  unsigned short count)
-{
-	struct cachefs_transaction *trans;
-	struct cachefs_block *pblock;
-	int ret;
-
-	_enter(",%lu,{bix=%u},%u,%u,%hu,%hu",
-	       ino,__cachefs_get_page_block(*_parent)->bix,poffset,
-	       bix,first,count);
-
-	pblock = cachefs_block_get(__cachefs_get_page_block(*_parent));
-
-	/* mark the journal to indicate the intended breaking of the pointer */
-	ret = -ENOMEM;
-	trans = cachefs_trans_alloc(super,GFP_KERNEL);
-	if (!trans)
-		goto error_rel_block;
-
-	cachefs_trans_affects_block(trans,pblock,poffset,sizeof(cachefs_blockix_t));
-
-	trans->jentry->ino	= ino;
-	trans->jentry->mark   	= CACHEFS_ONDISC_UJNL_INDIRECT_FREEING;
-	trans->jentry->block	= bix;
-	trans->jentry->entry  	= first;
-	trans->jentry->count  	= count;
-	trans->jentry->upblock	= pblock->bix;
-	trans->jentry->upentry	= poffset;
-
-	ret = cachefs_trans_mark(trans);
-	if (ret<0)
-		goto error_rel_trans;
-
-	super->rcyblock		= bix;
-	super->rcynext		= first;
-	super->rcystop		= first + count;
-
-	cachefs_block_modify(super,pblock,_parent);
-	*(cachefs_blockix_t*) (kmap(*_parent) + poffset) = 0;
-	kunmap(*_parent);
-
-	cachefs_trans_commit(trans);
-	cachefs_block_put(super,pblock);
-
-	/* zap the contents */
-	ret = cachefs_recycle_pointer_array(super);
-
-	_leave(" = %d",ret);
-	return ret;
-
- error_rel_trans:
-	printk("kcachefsd: Failed to mark journal: %d\n",ret);
-	cachefs_trans_put(trans);
- error_rel_block:
-	cachefs_block_put(super,pblock);
-	_leave(" = %d",ret);
-	return ret;
-} /* end cachefs_recycle_indirect_block() */
-
-/*****************************************************************************/
-/*
  * transfer the recycling stack to the allocation stack
  */
 void cachefs_recycle_transfer_stack(struct cachefs_super *super)
@@ -569,111 +327,486 @@
 	_leave("");
 } /* end cachefs_recycle_transfer_stack() */
 
-#if 1
 /*****************************************************************************/
 /*
- *
+ * recycle the dependents of the block currently in the recycling bin and then recycle the block
+ * itself
  */
-static int cachefs_recycle_test_write(struct bio *bio, unsigned int bytes_done, int err)
+static void cachefs_recycle_pointer_array(struct cachefs_super *super)
 {
-	_enter("{sz=%u rw=%lu},%u,%d",bio->bi_size,bio->bi_rw,bytes_done,err);
+	struct cachefs_ondisc_free_node *node;
+	struct cachefs_transaction *trans;
+	cachefs_blockix_t *indirect, *jeptr;
+	struct page *page;
+	unsigned limit, count, src, dst, max;
+	int ret;
+
+	kenter("{room=%u block=%u:%hu-%hu},",
+	       super->recycle_room,super->rcm_block,super->rcm_ptrnext,super->rcm_ptrstop);
+
+	max = super->sb->s_blocksize - sizeof(struct cachefs_ondisc_update_journal);
+	max /= sizeof(cachefs_blockix_t);
 
-	if (bio->bi_size)
-		return 1;
+	/* load the pointer block page */
+	ret = cachefs_block_read(super,NULL,super->rcm_block,0,NULL,&page);
+	if (ret<0) {
+		kleave(" [error %d]",ret);
+		return;
+	}
 
-	if (err<0)
-		panic("test write failed: %d\n",err);
+	wait_on_page_locked(page);
+
+	indirect = (cachefs_blockix_t*) kmap(page);
 
-	end_page_writeback(bio->bi_io_vec[0].bv_page);
+	/* find an occupied pointer */
+	for (src=super->rcm_ptrnext; src<super->rcm_ptrstop; src++)
+		if (indirect[src])
+			goto found;
 
-	bio_put(bio);
-	return 0;
-}
+	super->rcm_ptrnext = src;
+	goto out;
+
+ found:
+	/* make sure there's a recycling block with space available */
+	if (super->recycle_room==0) {
+		/* recycle the first dependent page as the new recycling node */
+		super->rcm_ptrnext = src;
+		ret = cachefs_recycle_begin_new_node(super,indirect[src],super->rcm_block,src);
+		goto out;
+	}
+
+	/* journal what we're going to do */
+	trans = cachefs_trans_alloc(super,GFP_KERNEL);
+	if (!trans)
+		goto out;
+
+	cachefs_trans_affects_block(trans,super->recycle_block,0,PAGE_SIZE);
+
+	limit = min(super->recycle_room,max);
+	dst = CACHEFS_ONDISC_LEAVES_PER_FREE_NODE - super->recycle_room;
+
+	trans->jentry->mark	= CACHEFS_ONDISC_UJNL_RECYC_SCAVENGE;
+	trans->jentry->block	= super->rcm_block;
+	trans->jentry->entry	= src;
+	trans->jentry->auxblock	= super->recycle_cur;
+	trans->jentry->auxentry	= dst;
+
+	/* transfer the pointers into the journal entry first */
+	jeptr = trans->jentry->rcyptrs;
+	count = 0;
+	while (count<limit && src<super->rcm_ptrstop) {
+		if (indirect[src]) {
+			jeptr[count] = indirect[src];
+			count++;
+		}
+
+		src++;
+	}
+
+	trans->jentry->count	= count;
+
+	ret = cachefs_trans_mark(trans);
+	if (ret<0) {
+		printk("kcachefsd: Failed to mark journal: %d\n",ret);
+		cachefs_trans_put(trans);
+		goto out;
+	}
+
+	super->recycle_room -= count;
+	super->recycle_cur_n += count;
+	if (super->recycle_room==0) super->recycle_cur_n++;
+
+	/* transfer from the jentry to the recycling block */
+	cachefs_block_modify(super,super->recycle_block,&super->recycle_node);
+
+	node = (struct cachefs_ondisc_free_node*) kmap(super->recycle_node);
+
+	memcpy(&node->leaves[dst],trans->jentry->rcyptrs,count*sizeof(cachefs_blockix_t));
+
+	kunmap(node);
 
-void cachefs_recycle_test(struct cachefs_super *super)
+	super->rcm_ptrnext = src;
+
+	cachefs_trans_commit(trans);
+	trans = NULL;
+
+ out:
+	kunmap(page);
+	dbgpgfree(page);
+	page_cache_release(page);
+
+	kleave(" [error %d]",ret);
+} /* end cachefs_recycle_pointer_array() */
+
+/*****************************************************************************/
+/*
+ * reclaim an inode storage entry
+ * - need to change four entities:
+ *   - storage record of inode being reclaimed
+ *   - storage record of storage inode (we've got a new free inode)
+ *   - index entry pointing to inode being reclaimed
+ *   - storage record of index (we've got a new free index entry)
+ */
+static int cachefs_recycle_reclaim_inode_storage(struct cachefs_super *super)
 {
-	struct cachefs_block *iblock, *pblock;
-	cachefs_blockix_t block, *indirect;
-	struct page *ipage, *ppage;
-	struct bio *bio;
-	ino_t ino;
-	int loop, ret;
-
-	printk("\n");
-	_debug("________________________________________\n");
-	_enter("{%u}",super->layout->bix_unready);
+	struct cachefs_ondisc_index_entry *xent;
+	struct cachefs_ondisc_storage *storage;
+	struct cachefs_transaction *trans = NULL;
+	struct cachefs_inode *iinode = NULL;
+	struct page *ixpage = NULL;
+	unsigned iino, ixentry, offset;
+	int ret;
 
-	ino	= 40000;
-	block	= super->layout->bix_unready++;
+	kenter("{%u}",super->rcm_ino);
 
-	/* prepare a block with a full list of pointers to other blocks */
-	ret = cachefs_block_read(super,NULL,block,1,&iblock,&ipage);
-	if (ret<0)
-		BUG();
+	/* find the parent index entry */
+	storage = kmap(super->rcm_inode->storage) + super->rcm_inode->storage_offset;
+	iino	= storage->pindex;
+	ixentry	= storage->pindex_entry;
+	kunmap(super->rcm_inode->storage);
+
+	if (iino) {
+		ret = cachefs_iget(super,iino,&iinode);
+		if (ret<0)
+			goto error;
+
+		ret = cachefs_get_page(iinode,ixentry/iinode->index_epp,&ixpage);
+		if (ret<0)
+			goto error;
+
+		offset = (ixentry % iinode->index_epp) * iinode->index_esize;
+	}
+	else {
+		ixentry	= 0;
+		offset	= 0;
+	}
+
+	/* do the release under journalling */
+	ret = -ENOMEM;
+	trans = cachefs_trans_alloc(super,GFP_KERNEL);
+	if (!trans)
+		goto error;
 
-	indirect = (cachefs_blockix_t *) kmap(ipage);
+	trans->jentry->mark	= CACHEFS_ONDISC_UJNL_INODE_DELETING;
+	trans->jentry->index	= iino;
+	trans->jentry->ixentry	= ixentry;
+	trans->jentry->ino	= super->rcm_ino;
+	trans->jentry->size	= iinode ? iinode->vfs_inode.i_size : 0;
+	trans->jentry->pgnum	= ixpage ? ixpage->index : 0;
+	trans->jentry->block	= ixpage ? __cachefs_get_page_block(ixpage)->bix : 0;
+	trans->jentry->entry	= offset;
+	trans->jentry->count	= iinode ? iinode->index_esize : 0;
+
+	storage = kmap(super->istorage->storage) + super->istorage->storage_offset;
+	trans->jentry->auxblock	= storage->freelink;
+	kunmap(super->istorage->storage);
+
+	if (iinode) {
+		storage = kmap(iinode->storage) + iinode->storage_offset;
+		trans->jentry->upblock	= storage->freelink;
+		kunmap(iinode->storage);
 
-	for (loop=0; loop<PAGE_SIZE/sizeof(cachefs_blockix_t); loop++)
-		indirect[loop] = super->layout->bix_unready++;
+		cachefs_trans_affects_page(trans,ixpage,offset,iinode->index_esize);
+		cachefs_trans_affects_inode(trans,iinode);
+	}
 
-	kunmap(ipage);
-	flush_dcache_page(ipage);
-	SetPageWriteback(ipage);
-
-	bio = bio_alloc(GFP_KERNEL,1);
-	if (!bio) BUG();
-	bio->bi_sector	= __cachefs_get_page_block(ipage)->bix;
-	bio->bi_sector	<<= (PAGE_SHIFT - super->sb->s_blocksize_bits);
-	bio->bi_bdev	= super->sb->s_bdev;
-	bio->bi_end_io	= cachefs_recycle_test_write;
-	if (!bio_add_page(bio,ipage,super->sb->s_blocksize,0))
-		BUG();
-	submit_bio(WRITE,bio);
-	wait_on_page_writeback(ipage);
-
-	cachefs_block_put(super,iblock);
-	page_cache_release(ipage);
-	dbgpgfree(ipage);
+	cachefs_trans_affects_inode(trans,super->rcm_inode);
+	cachefs_trans_affects_inode(trans,super->istorage);
 
-	/* create a parent page for the indirection block */
-	ret = cachefs_block_read(super,NULL,super->layout->bix_unready++,1,&pblock,&ppage);
+	ret = cachefs_trans_mark(trans);
 	if (ret<0)
-		BUG();
+		goto error;
+
+	if (iinode)
+		cachefs_page_modify(super,&ixpage);
+
+	/* free up the parent index entry */
+	if (iinode) {
+		xent = kmap(ixpage) + offset;
+		xent->state		= CACHEFS_ONDISC_INDEX_FREE;
+		xent->ino		= 0;
+		xent->freelink[0]	= trans->jentry->upblock;
+		memset(xent->data,0,iinode->index_dsize);
+		kunmap(ixpage);
+
+		/* modify the index inode storage entry */
+		storage = kmap(iinode->storage) + iinode->storage_offset;
+		storage->freelink	= ixentry;
+		kunmap(iinode->storage);
+	}
+
+	/* clear the inode definition */
+	storage = kmap(super->rcm_inode->storage) + super->rcm_inode->storage_offset;
+	memset(storage,0,sizeof(super->istorage->index_esize));
+
+	storage->header.state	= CACHEFS_ONDISC_INDEX_FREE;
+	storage->freelink	= trans->jentry->auxblock;
+	storage->mtime		= CURRENT_TIME.tv_sec;
+	storage->atime		= CURRENT_TIME.tv_sec;
+	kunmap(super->rcm_inode->storage);
+
+	/* modify the storage inode storage entry */
+	storage = kmap(super->istorage->storage) + super->istorage->storage_offset;
+	storage->freelink	= super->rcm_ino;
+	kunmap(super->istorage->storage);
+
+	/* do the writing */
+	cachefs_trans_commit(trans);
+	trans = NULL;
+
+ error:
+	if (trans)	cachefs_trans_put(trans);
+	if (ixpage)	put_page(ixpage);
+	if (iinode)	cachefs_iput(iinode);
+
+	kleave(" = %d",ret);
+	return ret;
+} /* end cachefs_recycle_reclaim_inode_storage() */
+
+/*****************************************************************************/
+/*
+ * do next step in reclamation of a file
+ * - need to dispose of:
+ *   (1) index entries in file content (if it's an index file)
+ *   (2) data blocks and indirection blocks
+ *   (3) parent index entry
+ *   (4) inode storage entry
+ * - update journal keeps track of recycling point
+ *   - rcm_ino, rcm_indirect, rcm_block, rcm_ptrnext & rcm_ptrstop
+ * - work out which block we're actually dealing with from rcm_indirect:
+ *	FROM		TO		WHAT
+ *	0		-		not started yet
+ *	1		-		reclaiming index entries
+ *	2		-		pointers in single indirect block
+ *	3		3+N-1		pointers in dblindirect subblocks 0...N-1
+ *	3+N		-		pointers in dblindirect block
+ *	3+N+1		-		all pointers in inode struct
+ *	3+N+2		-		inode itself
+ */
+static void cachefs_recycle_reclaim_inode(struct cachefs_super *super)
+{
+	struct cachefs_ondisc_storage *storage;
+	cachefs_blockix_t bix, *pbix;
+	struct page *page, *dpage;
+	unsigned indirect;
+	unsigned short next, stop;
+	int ret, loop;
+
+	const unsigned N = PAGE_SIZE / sizeof(cachefs_blockix_t);
+
+	kenter("{%u,%u,%u:%hu-%hu}",
+	       super->rcm_ino,super->rcm_indirect,super->rcm_block,
+	       super->rcm_ptrnext,super->rcm_ptrstop);
+
+	BUG_ON(!super->rcm_ino);
+
+	if (super->rcm_ptrnext==super->rcm_ptrstop && super->rcm_curpage) {
+		put_page(super->rcm_curpage);
+		super->rcm_curpage = NULL;
+	}
+
+	indirect = super->rcm_indirect;
+	bix = 0;
+	next = 0;
+	stop = PAGE_SIZE / sizeof(cachefs_blockix_t);
+
+	ret = 0;
+
+ again:
+	indirect++;
+
+	/* clear out then entries in an index */
+	if (indirect == 1) {
+		if (super->rcm_inode->index_dsize==0)
+			goto again;
+
+		if (cachefs_index_zap(super)<0)
+			goto error2;
+		goto again;
+	}
+
+	/* process the single indirect block */
+	if (indirect == 2) {
+		storage = kmap(super->rcm_inode->storage) + super->rcm_inode->storage_offset;
+		bix = storage->single_indirect;
+		kunmap(super->rcm_inode->storage);
+
+		if (!bix)
+			goto again;
+		goto pointer_array;
+	}
+
+	/* deal with double indirection */
+	if (indirect <= 3+N) {
+		storage = kmap(super->rcm_inode->storage) + super->rcm_inode->storage_offset;
+		bix = storage->double_indirect;
+		kunmap(super->rcm_inode->storage);
+
+		if (!bix) {
+			indirect = 3+N;
+			goto again;
+		}
+
+		ret = cachefs_block_read(super,NULL,bix,0,NULL,&dpage);
+		if (ret<0)
+			goto error;
+
+		/* start processing a double indirect subblock */
+		if (indirect <= 3+N-1) {
+			wait_on_page_locked(dpage);
+
+			bix = 0;
+			pbix = kmap(dpage);
+			for (loop=indirect-2; loop<N; loop++) {
+				bix = pbix[loop];
+				if (bix)
+					break;
+			}
+			kunmap(pbix);
+
+			indirect = loop + 3;
+			if (bix) {
+				put_page(dpage);
+				goto pointer_array;
+			}
+		}
 
-	*(cachefs_blockix_t *) kmap(ppage) = block;
-	kunmap(ppage);
-	flush_dcache_page(ppage);
-	SetPageWriteback(ppage);
-
-	bio = bio_alloc(GFP_KERNEL,1);
-	if (!bio) BUG();
-	bio->bi_sector	= __cachefs_get_page_block(ipage)->bix;
-	bio->bi_sector	<<= (PAGE_SHIFT - super->sb->s_blocksize_bits);
-	bio->bi_bdev	= super->sb->s_bdev;
-	bio->bi_end_io	= cachefs_recycle_test_write;
-	if (!bio_add_page(bio,ppage,super->sb->s_blocksize,0))
-		BUG();
-	submit_bio(WRITE,bio);
-	wait_on_page_writeback(ppage);
-
-	/* now recycle it */
-	_debug("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
-	ret = cachefs_recycle_indirect_block(super,ino,&ppage,0,block,0,PAGE_SIZE/4);
-	_debug("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+		/* start processing the double indirect block */
+		page = dpage;
+		bix = __cachefs_get_page_block(dpage)->bix;
+		goto pointer_array2;
+	}
+
+	/* reclaim all the block pointers in the inode storage record */
+	if (indirect == 3+N+1) {
+		bix	= __cachefs_get_page_block(super->rcm_inode->storage)->bix;
+		next	= super->rcm_inode->storage_offset;
+		next	+= offsetof(struct cachefs_ondisc_storage,triple_indirect);
+		next	/= sizeof(cachefs_blockix_t);
+
+		stop	= super->rcm_inode->storage_offset + super->layout->storage_size;
+		stop	/= sizeof(cachefs_blockix_t);
+
+		page = super->rcm_inode->storage;
+		get_page(page);
+		goto pointer_array2;
+	}
+
+	/* reclaim the inode itself */
+	if (cachefs_recycle_reclaim_inode_storage(super)<0) {
+		indirect--;
+		bix	= 0;
+		next	= 0;
+		stop	= 0;
+		page	= NULL;
+		goto set;
+	}
+
+	/* finished this inode */
+	cachefs_iput(super->rcm_inode);
+	super->rcm_inode	= NULL;
+	super->rcm_ino		= 0;
+	super->rcm_indirect	= 0;
+	super->rcm_block	= 0;
+	super->rcm_ptrnext	= 0;
+	super->rcm_ptrstop	= 0;
+	kleave("");
+	return;
+
+ pointer_array:
+	ret = cachefs_block_read(super,NULL,bix,0,NULL,&page);
 	if (ret<0)
-		panic("recycle indirect failed: %d\n",ret);
+		goto error;
 
-	cachefs_block_put(super,pblock);
-	dbgpgfree(ppage);
-	page_cache_release(ppage);
+ pointer_array2:
+	cachefs_recycle_pointer_array(super);
 
-	_debug("________________________________________\n");
-	printk("\n");
-	_leave("");
-} /* end cachefs_recycle_test() */
-#endif
+ set:
+	super->rcm_indirect	= indirect;
+	super->rcm_block	= bix;
+	super->rcm_ptrnext	= next;
+	super->rcm_ptrstop	= stop;
+	super->rcm_curpage	= page;
+	kleave("");
+	return;
+
+ error:
+	if (ret==-EIO) {
+		/* just sweep any buggy block under the rug */
+		printk("CacheFS: discarding block %u due to I/O error\n",bix);
+		goto again;
+	}
+ error2:
+	kleave(" [error %d]",ret);
+	goto set;
+} /* end cachefs_recycle_reclaim_inode() */
 
-void cachefs_recycle_nodes(struct cachefs_super *super)
+/*****************************************************************************/
+/*
+ * do inode reclamation
+ */
+void cachefs_recycle_reclaim(struct cachefs_super *super)
 {
-	_enter("");
-}
+	struct cachefs_transaction *trans;
+	int ret;
+
+	kenter("{%u,%u,%u:%hu-%hu}",
+	       super->rcm_ino,super->rcm_indirect,super->rcm_block,
+	       super->rcm_ptrnext,super->rcm_ptrstop);
+
+	/* recycle the next chunk of an inode we're busy reclaiming */
+	if (super->rcm_ino) {
+		kdebug("do reclaim");
+		if (!super->rcm_inode) {
+			ret = cachefs_iget(super,super->rcm_ino,&super->rcm_inode);
+			if (ret<0) {
+				kleave(" [error %d]",ret);
+				return;
+			}
+		}
+
+		cachefs_recycle_reclaim_inode(super);
+
+		goto done;
+	}
+
+	/* see if there's an inode we can start reclaiming */
+	if (super->rcm_imm_head != super->rcm_imm_tail) {
+		kdebug("begin reclaim {%u-%u}",super->rcm_imm_tail,super->rcm_imm_head);
+		trans = cachefs_trans_alloc(super,GFP_KERNEL);
+		if (!trans) {
+			kdebug("[ENOMEM]");
+			goto done;
+		}
+
+		trans->jentry->ino	= super->rcm_imm_buf[super->rcm_imm_tail];
+		trans->jentry->mark   	= CACHEFS_ONDISC_UJNL_INODE_RECLAIMING;
+
+		ret = cachefs_trans_mark(trans);
+		if (ret<0) {
+			kdebug("[error %d]",ret);
+			cachefs_trans_put(trans);
+			goto done;
+		}
+
+		super->rcm_ino		= trans->jentry->ino;
+		super->rcm_indirect	= 0;
+		super->rcm_block	= 0;
+		super->rcm_ptrnext	= 0;
+		super->rcm_ptrstop	= 0;
+
+		cachefs_trans_commit(trans);
+
+		super->rcm_imm_tail = (super->rcm_imm_tail+1) & (CACHEFS_RCM_IMM_BUFSIZE-1);
+		goto done;
+	}
+
+
+ done:
+	if (super->rcm_ino ||
+	    super->rcm_imm_head != super->rcm_imm_tail
+	    )
+		set_bit(CACHEFS_SUPER_DO_RECLAIM,&super->flags);
+	kleave("");
+	return;
+} /* end cachefs_recycle_immediate_reclaim() */

Index: kcachefsd.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/kcachefsd.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- kcachefsd.c	21 Mar 2003 14:01:00 -0000	1.8
+++ kcachefsd.c	2 Apr 2003 09:12:31 -0000	1.9
@@ -79,9 +79,9 @@
 
 			/* see if there's work to be done */
 			if (!super->alloc_node ||
-			    !list_empty(&super->recycleq) ||
 			    super->layout->bix_unready < super->layout->bix_end ||
-			    test_bit(CACHEFS_SUPER_BATCH_TIMER,&super->flags)
+			    test_bit(CACHEFS_SUPER_BATCH_TIMER,&super->flags) ||
+			    test_bit(CACHEFS_SUPER_DO_RECLAIM,&super->flags)
 			    )
 				break;
 
@@ -101,8 +101,8 @@
 		_debug("@@@ Begin Cache Management");
 
 		/* decant the recycling queue */
-		if (!list_empty(&super->recycleq))
-			cachefs_recycle_nodes(super);
+		if (test_and_clear_bit(CACHEFS_SUPER_DO_RECLAIM,&super->flags))
+			cachefs_recycle_reclaim(super);
 
 		/* transfer blocks from the unready data if possible */
 		if (super->layout->bix_unready<super->layout->bix_end) {
@@ -115,13 +115,6 @@
 				yield();
 			}
 		}
-
-#if 0
-		cachefs_recycle_test(super);
-#endif
-#if 0
-		super->layout->bix_unready = super->layout->bix_end;
-#endif
 
 		/* if there's no next node, then get one */
 		if (!super->alloc_node)

Index: journal.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/journal.c,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -r1.28 -r1.29
--- journal.c	29 Mar 2003 11:13:47 -0000	1.28
+++ journal.c	2 Apr 2003 09:12:31 -0000	1.29
@@ -25,12 +25,12 @@
 	"RcycBegin",
 	"RcycXfer ",
 	"RcycScvng",
-	"RcycPtrBk",
 	"RcycMkRdy",
 	"InoAlloc ",
 	"InoUpdate",
 	"InoDelete",
-	"InoReclm ",
+	"InoMkRcm ",
+	"InoRcming",
 	"DataAlloc",
 	"DataWrite",
 	"IndrAlloc",
@@ -330,9 +330,11 @@
 	trans->jentry->alloc_leaf	= super->alloc_leaf;
 	trans->jentry->alloc_cur	= super->alloc_cur;
 	trans->jentry->recycle_cur	= super->recycle_cur;
-	trans->jentry->rcyblock		= super->rcyblock;
-	trans->jentry->rcynext		= super->rcynext;
-	trans->jentry->rcystop		= super->rcystop;
+	trans->jentry->rcm_ino		= super->rcm_ino;
+	trans->jentry->rcm_indirect	= super->rcm_indirect;
+	trans->jentry->rcm_block	= super->rcm_block;
+	trans->jentry->rcm_ptrnext	= super->rcm_ptrnext;
+	trans->jentry->rcm_ptrstop	= super->rcm_ptrstop;
 
 	/* transfer the journal entry to the page it's going to be written from */
 	offset = (trans->index << super->sb->s_blocksize_bits) & ~PAGE_MASK;
@@ -516,9 +518,11 @@
 	ajentry->alloc_leaf	= super->alloc_leaf;
 	ajentry->alloc_cur	= super->alloc_cur;
 	ajentry->recycle_cur	= super->recycle_cur;
-	ajentry->rcyblock	= super->rcyblock;
-	ajentry->rcynext	= super->rcynext;
-	ajentry->rcystop	= super->rcystop;
+	ajentry->rcm_ino	= super->rcm_ino;
+	ajentry->rcm_indirect	= super->rcm_indirect;
+	ajentry->rcm_block	= super->rcm_block;
+	ajentry->rcm_ptrnext	= super->rcm_ptrnext;
+	ajentry->rcm_ptrstop	= super->rcm_ptrstop;
 
 	up_write(&super->batch_ctrl_sem);

Index: index.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/index.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- index.c	29 Mar 2003 11:13:47 -0000	1.12
+++ index.c	2 Apr 2003 09:12:31 -0000	1.13
@@ -25,6 +25,7 @@
 #include <linux/completion.h>
 #include <linux/slab.h>
 #include <linux/bio.h>
+#include <linux/circ_buf.h>
 #include "cachefs-int.h"
 
 struct cachefs_index_search_record {
@@ -356,7 +357,13 @@
 	cachefs_trans_affects_inode(trans,iinode);
 	cachefs_trans_affects_page(trans,inopage,ino_offset,super->layout->storage_size);
 	cachefs_trans_affects_inode(trans,super->istorage);
-	cachefs_trans_mark(trans);
+
+	ret = cachefs_trans_mark(trans);
+	if (ret<0)
+		goto error;
+
+	cachefs_page_modify(super,&ixpage);
+	cachefs_page_modify(super,&inopage);
 
 	/* fill the index entry */
 	xent = kmap(ixpage) + offset;
@@ -446,4 +453,103 @@
  error:
 	kleave(" = %d",ret);
 	return ret;
+} /* end cachefs_index_add() */
+
+/*****************************************************************************/
+/*
+ * mark the next inode pinned by an entry in the index currently being reclaimed as being obsolete
+ */
+int cachefs_index_zap(struct cachefs_super *super)
+{
+	struct cachefs_ondisc_index_entry *xent;
+	struct cachefs_ondisc_storage *storage;
+	struct cachefs_transaction *trans = NULL;
+	struct cachefs_inode *inode = NULL;
+	unsigned long flags;
+	struct page *page = NULL;
+	unsigned pgnum, offset, ino;
+	int ret;
+
+	kenter("{%u,%u}",super->rcm_ino,super->rcm_block);
+
+	pgnum	= super->rcm_block / super->rcm_inode->index_epp;
+	offset	= super->rcm_block % super->rcm_inode->index_epp;
+
+	if (pgnum >= (super->rcm_inode->vfs_inode.i_size >> PAGE_SHIFT)) {
+		kleave(" = 0");
+		return 0; /* done them all */
+	}
+
+	/* get the page holding the next index entry and extract the inode number from it */
+	ret = cachefs_get_page(super->rcm_inode,pgnum,&page);
+	if (ret<0) {
+		if (ret==-EIO) {
+			super->rcm_block = (pgnum+1) * super->rcm_inode->index_epp;
+		}
+		kleave(" = %d",ret);
+		return ret;
+	}
+
+	offset *= super->rcm_inode->index_esize;
+	xent = kmap(page) + offset;
+	ino = xent->ino;
+	kunmap(page);
+
+	/* open the inode */
+	ret = cachefs_iget(super,ino,&inode);
+	if (ret<0)
+		goto error_skip;
+
+	/* journal what we're going to do */
+	trans = cachefs_trans_alloc(super,GFP_KERNEL);
+	if (!trans) {
+		kleave(" = -ENOMEM");
+		return -ENOMEM;
+	}
+
+	trans->jentry->mark	= CACHEFS_ONDISC_UJNL_INODE_MARK_RECLAIM;
+	trans->jentry->ino	= inode->vfs_inode.i_ino;
+	trans->jentry->index	= super->rcm_ino;
+	trans->jentry->ixentry	= super->rcm_block;
+
+	cachefs_trans_affects_inode(trans,inode);
+
+	ret = cachefs_trans_mark(trans);
+	if (ret<0)
+		goto error_skip;
+
+	/* modify the inode storage entry */
+	storage = kmap(inode->storage) + inode->storage_offset;
+	storage->header.state	= CACHEFS_ONDISC_INDEX_RECYCLE;
+	storage->pindex		= 0;
+	storage->pindex_entry	= 0;
+	kunmap(inode->storage);
+
+	cachefs_trans_commit(trans);
+	trans = NULL;
+
+	/* add to the immediate-reclaim table if possible */
+	spin_lock_irqsave(&super->rcm_lock,flags);
+
+	if (CIRC_SPACE(super->rcm_imm_head,super->rcm_imm_tail,CACHEFS_RCM_IMM_BUFSIZE)>0) {
+		super->rcm_imm_buf[super->rcm_imm_head] = inode->vfs_inode.i_ino;
+		super->rcm_imm_head = (super->rcm_imm_head+1) & (CACHEFS_RCM_IMM_BUFSIZE-1);
+	}
+	else {
+		set_bit(CACHEFS_SUPER_RCM_IMM_SCAN,&super->flags);
+	}
+
+	spin_unlock_irqrestore(&super->rcm_lock,flags);
+
+	super->rcm_block++;
+	ret = -EAGAIN;
+
+ error_skip:
+	if (inode)	cachefs_iput(inode);
+	if (trans)	cachefs_trans_put(trans);
+	if (page)	put_page(page);
+	if (ret==-EIO)	super->rcm_block++;
+	kleave(" = %d",ret);
+	return ret;
+
 } /* end cachefs_index_add() */

Index: dump-journal.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/dump-journal.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- dump-journal.c	29 Mar 2003 11:13:47 -0000	1.7
+++ dump-journal.c	2 Apr 2003 09:12:31 -0000	1.8
@@ -48,12 +48,12 @@
 	BRIGHT	"RcycBegin"	NORMAL,
 	BRIGHT	"RcycXfer "	NORMAL,
 	BRIGHT	"RcycScvng"	NORMAL,
-	BRIGHT	"RcycPtrBk"	NORMAL,
 	BRIGHT	"RcycMkRdy"	NORMAL,
 	BRIGHT	"InoAlloc "	NORMAL,
 	BRIGHT	"InoUpdate"	NORMAL,
 	BRIGHT	"InoDelete"	NORMAL,
-	BRIGHT	"InoReclm "	NORMAL,
+	BRIGHT	"InoMkRcm "	NORMAL,
+	BRIGHT	"InoRcming"	NORMAL,
 	BRIGHT	"DataAlloc"	NORMAL,
 	BRIGHT	"DataWrite"	NORMAL,
 	BRIGHT	"IndrAlloc"	NORMAL,
@@ -184,7 +184,7 @@
 		       jentry->count,
 		       jentry->alloc_cur,	jentry->alloc_leaf,
 		       jentry->recycle_cur,
-		       jentry->rcyblock,	jentry->rcynext,	jentry->rcystop
+		       jentry->rcm_block,	jentry->rcm_ptrnext,	jentry->rcm_ptrstop
 		       );
 	}

Index: cachefs-layout.h
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/cachefs-layout.h,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -r1.19 -r1.20
--- cachefs-layout.h	29 Mar 2003 11:13:47 -0000	1.19
+++ cachefs-layout.h	2 Apr 2003 09:12:31 -0000	1.20
@@ -122,7 +122,7 @@
 	u_int64_t			version;	/* current data version */
 	u_int64_t			size;		/* size of file */
 
-	/* file contents */
+	/* file contents - recycling depends on triple_indirect being first */
 	cachefs_blockix_t		triple_indirect; /* triple indirect block index */
 	cachefs_blockix_t		double_indirect; /* double indirect block index */
 	cachefs_blockix_t		single_indirect; /* single indirect block index */
@@ -250,13 +250,6 @@
 	 */
 	CACHEFS_ONDISC_UJNL_RECYC_SCAVENGE,
 
-	/* scavenge the picked over corpse of a pointer block (super->rcyblock)
-	 * - block	= block being scavenged
-	 * - auxblock	= recycling node transferred to
-	 * - auxentry	= index into auxblock[] of leaf attached to
-	 */
-	CACHEFS_ONDISC_UJNL_RECYC_PTRBLK,
-
 	/* transfer bix_unready to recycle_stk
 	 * - block	= recycling node that blocks were pasted into
 	 * - auxblock	= first unready block transferred
@@ -273,8 +266,15 @@
 	/* inode being deleted */
 	CACHEFS_ONDISC_UJNL_INODE_DELETING,
 
+	/* inode being marked for reclamation
+	 * - ino	= target inode
+	 */
+	CACHEFS_ONDISC_UJNL_INODE_MARK_RECLAIM,
+
 	/* inode being reclaimed
 	 * - ino	= target inode
+	 * - index	= inode's parent index
+	 * - ixentry	= inode's parent index entry
 	 */
 	CACHEFS_ONDISC_UJNL_INODE_RECLAIMING,
 
@@ -350,14 +350,16 @@
 	u_int16_t			entry;
 	u_int16_t			auxentry;
 	u_int16_t			upentry;
-	u_int16_t			rcynext;	/* next ptr in rcyblock to be recycled */
-	u_int16_t			rcystop;	/* last ptr in rcyblock + 1 */
+	u_int16_t			rcm_ptrnext;	/* next ptr in rcm_block to be reclaimed */
+	u_int16_t			rcm_ptrstop;	/* last ptr in rcm_block + 1 */
 	u_int16_t			count;
 	u_int16_t			alloc_leaf;	/* current alloc point in alloc_cur */
+	u_int16_t			rcm_indirect;	/* indirect block being reclaimed */
+	u_int32_t			rcm_ino;	/* number of inode being reclaimed */
 	cachefs_blockix_t		block;
 	cachefs_blockix_t		auxblock;
 	cachefs_blockix_t		upblock;
-	cachefs_blockix_t		rcyblock;	/* block currently being recycled */
+	cachefs_blockix_t		rcm_block;	/* block currently being reclaimed */
 	cachefs_blockix_t		alloc_cur;	/* current block allocation node */
 	cachefs_blockix_t		recycle_cur;	/* current block recycling node */

Index: cachefs-int.h
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/cachefs-int.h,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -r1.24 -r1.25
--- cachefs-int.h	29 Mar 2003 11:13:47 -0000	1.24
+++ cachefs-int.h	2 Apr 2003 09:12:31 -0000	1.25
@@ -48,6 +48,11 @@
 
 extern int cachefs_get_block(struct inode *inode, struct page *page, int create);
 
+struct cachefs_reclaimable {
+	unsigned	ino;
+	time_t		atime;
+};
+
 /*****************************************************************************/
 /*
  * cachefs superblock private information
@@ -62,6 +67,9 @@
 	unsigned long			flags;
 #define CACHEFS_SUPER_INIT_BLKDEV	0		/* true if initialising blockdev */
 #define CACHEFS_SUPER_BATCH_TIMER	1		/* true if batch timer expired */
+#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 */
 
 	/* block allocation and recycling management */
 	struct rb_root			blk_tree;	/* block mapping tree */
@@ -83,11 +91,28 @@
 	cachefs_blockix_t		recycle_cur;	/* current node in recycle stack */
 	unsigned			recycle_cur_n;	/* current occupancy of reserve stack */
 
-	struct list_head		recycleq;	/* inodes to be deleted */
+	/* inode reclamation */
+	spinlock_t			rcm_lock;
+
+	unsigned			*rcm_imm_buf;	/* circular immediate-reclaim buffer */
+	unsigned short			rcm_imm_head;
+	unsigned short			rcm_imm_tail;
+
+#define CACHEFS_RCM_IMM_BUFSIZE (PAGE_SIZE/sizeof(unsigned))
+
+	struct cachefs_reclaimable	*rcm_atm_list;	/* atime-based reclaimable inode list */
+	unsigned short			rcm_atm_end;	/* end of buffer contents */
+
+#define CACHEFS_RCM_ATM_LISTSIZE (PAGE_SIZE/sizeof(struct cachefs_reclaimable))
+
+	unsigned			rcm_ino;	/* inode being reclaimed */
+	unsigned			rcm_indirect;	/* current indirect block index */
+	cachefs_blockix_t		rcm_block;	/* current block being recycled */
+	unsigned short			rcm_ptrnext;	/* next entry in rcyblock to process */
+	unsigned short			rcm_ptrstop;	/* entry in rcyblock to stop at */
 
-	cachefs_blockix_t		rcyblock;	/* current block being recycled */
-	unsigned short			rcynext;	/* next entry in rcyblock to process */
-	unsigned short			rcystop;	/* entry in rcyblock to stop at */
+	struct cachefs_inode		*rcm_inode;	/* inode being reclaimed */
+	struct page			*rcm_curpage;	/* page holding rcm_block */
 
 	/* update journal tracking */
 	unsigned short			ujnl_step;	/* journal block size */
@@ -147,15 +172,9 @@
 extern void cachefs_add_cache(struct cachefs_super *super);
 extern void cachefs_del_cache(struct cachefs_super *super);
 
-extern int cachefs_recycle_begin_new_node(struct cachefs_super *super,
-					  cachefs_blockix_t bix,
-					  cachefs_blockix_t upblock,
-					  unsigned short upentry,
-					  void (*manage)(struct cachefs_super *super));
-
-extern void cachefs_recycle_nodes(struct cachefs_super *super);
 extern void cachefs_recycle_unready_blocks(struct cachefs_super *super);
 extern void cachefs_recycle_transfer_stack(struct cachefs_super *super);
+extern void cachefs_recycle_reclaim(struct cachefs_super *super);
 
 /*****************************************************************************/
 /*
@@ -184,6 +203,8 @@
 			     const struct cachefs_index *definition,
 			     const void *data);
 
+extern int cachefs_index_zap(struct cachefs_super *super);
+
 /*****************************************************************************/
 /*
  * on-disc per-cache inode record
@@ -310,6 +331,11 @@
 	return ((struct cachefs_page *) page->private)->mapped_block;
 }
 
+static inline void cachefs_page_modify(struct cachefs_super *super, struct page **page)
+{
+	cachefs_block_modify(super,__cachefs_get_page_block(*page),page);
+}
+
 /*****************************************************************************/
 /*
  * transaction record and tracking structure
@@ -407,7 +433,6 @@
 extern void cachefs_trans_sync(struct cachefs_super *super, int wait);
 
 extern int  cachefs_ujnl_replay(struct cachefs_super *super);
-
 
 /*****************************************************************************/
 /*

Index: aops.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/aops.c,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -r1.23 -r1.24
--- aops.c	21 Mar 2003 14:01:01 -0000	1.23
+++ aops.c	2 Apr 2003 09:12:31 -0000	1.24
@@ -1029,13 +1029,12 @@
 	up(&super->alloc_sem);
 
 	/* change the appropriate pointer on disc to point to this block */
-	cachefs_block_modify(super,__cachefs_get_page_block(step[1].page),&step[1].page);
+	cachefs_page_modify(super,&step[1].page);
 
 	step->bix = jentry->block;
 	data = kmap(step[1].page);
 	*(cachefs_blockix_t *)(data + step->offset) = step->bix;
 	kunmap(data);
-	flush_dcache_page(step[1].page);
 
 	unlock_page(step[1].page);
 
@@ -1044,7 +1043,6 @@
 	storage->size	= inode->vfs_inode.i_size;
 	storage->mtime	= CURRENT_TIME.tv_sec;
 	kunmap(inode->storage);
-	flush_dcache_page(inode->storage);
 
 	/* okay... done that */
 	cachefs_trans_commit(step->transaction);

Index: Makefile
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/Makefile,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- Makefile	21 Mar 2003 14:01:01 -0000	1.13
+++ Makefile	2 Apr 2003 09:12:31 -0000	1.14
@@ -2,7 +2,7 @@
 # Makefile for general caching filesystem
 #
 
-CFLAGS += -finstrument-functions
+#CFLAGS += -finstrument-functions
 
 cachefs-objs := \
 	block.o \