Subject: afs/fs/cachefs vjournal.c,1.4,1.5 rootdir.c,1.15,1.16 recycling.c,1.28,1.29 journal.c,1.40,1.41 index.c,1.28,1.29 dump-journal.c,1.14,1.15 cachefs-layout.h,1.31,1.32aops.c,1.43,1.44

From: [email-masked]
Date: Thu, 17 Jul 2003 13:02:15 +0100

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

Modified Files:
	vjournal.c rootdir.c recycling.c journal.c index.c 
	dump-journal.c cachefs-layout.h aops.c 
Log Message:
improve/debug reclaimation and recycling and allocation stack tracking

Index: vjournal.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/vjournal.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- vjournal.c	4 Jul 2003 09:04:43 -0000	1.4
+++ vjournal.c	17 Jul 2003 12:02:13 -0000	1.5
@@ -225,6 +225,7 @@
 	if (ret < 0)
 		goto error_free;
 
+	wait_on_page_locked(vjentry->vpage);
 	cachefs_block_modify(super, vjentry->vblock, &vjentry->vpage);
 	memset(kmap(vjentry->vpage) + vjentry->ventry, 0,
 	       sizeof(struct cachefs_ondisc_validity_journal));

Index: rootdir.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/rootdir.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- rootdir.c	17 Jul 2003 08:49:39 -0000	1.15
+++ rootdir.c	17 Jul 2003 12:02:13 -0000	1.16
@@ -681,9 +681,10 @@
 
 	BUG_ON(trans->jentry->index != dir->i_ino);
 
-	trans->jentry->pgnum = trans->jentry->index / index->index_epp;
+	trans->jentry->pgnum = trans->jentry->ixentry / index->index_epp;
 	trans->jentry->entry =
-		(trans->jentry->index % index->index_epp) * index->index_esize;
+		(trans->jentry->ixentry % index->index_epp) *
+		index->index_esize;
 
 	ret = cachefs_get_page(index, trans->jentry->pgnum, &ixpage);
 	if (ret < 0) {

Index: recycling.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/recycling.c,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -r1.28 -r1.29
--- recycling.c	16 Jul 2003 11:19:39 -0000	1.28
+++ recycling.c	17 Jul 2003 12:02:13 -0000	1.29
@@ -78,14 +78,23 @@
 	}
 
 	trans->jentry->mark	= CACHEFS_ONDISC_UJNL_RECYC_BEGIN_NEW;
+	trans->jentry->index	= super->recycle_cur;
+	trans->jentry->ixentry	= super->recycle_cur_n;
 	trans->jentry->block	= bix;
-	trans->jentry->auxblock	= super->recycle_cur;
 	trans->jentry->upblock	= upblock;
 	trans->jentry->upentry	= upentry;
 
 	trans->jentry->pgnum =
 		super->layout->bix_unready + used_unready_node;
 
+	trans->changed |= CACHEFS_TRANS_CHANGED_RECYCLE;
+	trans->jentry->recycle_cur = bix;
+
+	if (upblock) {
+		trans->changed |= CACHEFS_TRANS_CHANGED_RCMPTR;
+		trans->jentry->rcm_ptrnext = upentry;
+	}
+
 	/* mark the beginning of the operation */
 	ret = cachefs_trans_mark(trans);
 	if (ret<0)
@@ -95,12 +104,11 @@
 	cachefs_block_modify(super, block, &page);
 
 	node = (struct cachefs_ondisc_free_node *) kmap(page);
-	node->next = super->recycle_cur;
-	node->count = super->recycle_cur_n;
+	node->next  = trans->jentry->index;
+	node->count = trans->jentry->ixentry;
 	kunmap(page);
 
-	super->recycle_cur	= bix;
-	super->recycle_room	= CACHEFS_ONDISC_LEAVES_PER_FREE_NODE;
+	super->recycle_room = CACHEFS_ONDISC_LEAVES_PER_FREE_NODE;
 	page	= xchg(&super->recycle_node, page);
 	block	= xchg(&super->recycle_block, block);
 
@@ -250,15 +258,17 @@
 
 		trans->jentry->mark	= CACHEFS_ONDISC_UJNL_RECYC_TRANSFER;
 		trans->jentry->block	= allocTOS;
-		super->recycle_cur	= 0;
-		super->alloc_cur	= allocTOS;
-		super->alloc_leaf	= 0;
+
+		trans->jentry->recycle_cur	= 0;
+		trans->jentry->alloc_cur	= allocTOS;
+		trans->jentry->alloc_leaf	= 0;
+
+		trans->changed |=
+			CACHEFS_TRANS_CHANGED_RECYCLE |
+			CACHEFS_TRANS_CHANGED_ALLOC;
 
 		ret = cachefs_trans_mark(trans);
 		if (ret < 0) {
-			super->recycle_cur	= allocTOS;
-			super->alloc_cur	= 0;
-			super->alloc_leaf	= 0;
 			printk("CacheFS: failed to mark ujnl: %d\n", ret);
 			_leave(" [error %d]", ret);
 			return;
@@ -307,15 +317,12 @@
 		trans->jentry->block	= allocTOS;
 		trans->jentry->upblock	= super->recycle_cur;
 
-		super->recycle_cur	= 0;
-		super->alloc_cur	= allocTOS;
-		super->alloc_leaf	= 0;
+		trans->jentry->alloc_cur  = allocTOS;
+		trans->jentry->alloc_leaf = 0;
+		trans->changed |= CACHEFS_TRANS_CHANGED_ALLOC;
 
 		ret = cachefs_trans_mark(trans);
 		if (ret < 0) {
-			super->recycle_cur	= allocTOS;
-			super->alloc_cur	= 0;
-			super->alloc_leaf	= 0;
 			printk("CacheFS: failed to mark ujnl: %d\n", ret);
 			dbgpgfree(page);
 			page_cache_release(page);
@@ -351,21 +358,21 @@
 
 /*****************************************************************************/
 /*
- * recycle the dependents of the block currently in the recycling bin and then
- * recycle the block itself
+ * recycle the dependents of the page currently being reclaimed
  */
-static void cachefs_recycle_pointer_array(struct cachefs_super *super)
+static void cachefs_recycle_pointer_array(struct cachefs_super *super,
+					  struct cachefs_transaction **_trans)
 {
 	struct cachefs_ondisc_free_node *node;
 	struct cachefs_transaction *trans;
 	struct cachefs_block *block;
 	cachefs_blockix_t *indirect, *jeptr;
-	struct page *page;
 	unsigned limit, count, src, dst, max;
 	int ret;
 
-	kenter("{room=%u block=%u:%hu-%hu},",
+	kenter("{room=%u page=%lx block=%x:%hu-%hu},",
 	       super->recycle_room,
+	       super->rcm_curpage->index,
 	       super->rcm_block,
 	       super->rcm_ptrnext,
 	       super->rcm_ptrstop);
@@ -374,17 +381,9 @@
 	max -= sizeof(struct cachefs_ondisc_update_journal);
 	max /= sizeof(cachefs_blockix_t);
 
-	/* 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;
-	}
-
-	wait_on_page_locked(page);
-
-	indirect = (cachefs_blockix_t*) kmap(page);
+	ret = 0;
+	wait_on_page_locked(super->rcm_curpage);
+	indirect = (cachefs_blockix_t *) kmap(super->rcm_curpage);
 
 	/* find an occupied pointer */
 	for (src = super->rcm_ptrnext; src < super->rcm_ptrstop; src++)
@@ -397,17 +396,12 @@
  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;
 	}
 
-	trans = cachefs_trans_alloc(super, GFP_KERNEL);
-	if (!trans)
-		goto out;
+	trans = *_trans;
 
 	cachefs_trans_affects_block(trans, super->recycle_block, 0, PAGE_SIZE);
 
@@ -440,14 +434,16 @@
 	}
 
 	trans->jentry->count = count;
+	trans->jentry->rcm_ptrnext = src;
 
 	ret = cachefs_trans_mark(trans);
 	if (ret < 0) {
 		printk("kcachefsd: Failed to mark journal: %d\n", ret);
-		cachefs_trans_put(trans);
 		goto out;
 	}
 
+	*_trans = NULL;
+
 	super->recycle_room -= count;
 	super->recycle_cur_n += count;
 	if (super->recycle_room == 0)
@@ -465,16 +461,10 @@
 
 	kunmap(super->recycle_node);
 
-	super->rcm_ptrnext = src;
-
 	cachefs_trans_commit(trans);
-	trans = NULL;
 
  out:
-	kunmap(page);
-	dbgpgfree(page);
-	page_cache_release(page);
-
+	kunmap(super->rcm_curpage);
 	kleave(" [error %d]", ret);
 } /* end cachefs_recycle_pointer_array() */
 
@@ -487,18 +477,19 @@
  *   - index entry pointing to inode being reclaimed
  *   - metadata record of index (we've got a new free index entry)
  */
-static int cachefs_recycle_reclaim_inode_metadata(struct cachefs_super *super)
+static int cachefs_recycle_reclaim_inode_metadata(struct cachefs_super *super,
+						  struct cachefs_transaction **_trans)
 {
 	struct cachefs_ondisc_index_entry *xent;
 	struct cachefs_ondisc_ujnl_index *jindex;
 	struct cachefs_ondisc_metadata *metadata;
-	struct cachefs_transaction *trans = NULL;
+	struct cachefs_transaction *trans;
 	struct cachefs_inode *iinode = NULL;
 	struct page *ixpage = NULL;
 	unsigned iino, ixentry, offset;
 	int ret;
 
-	kenter("{%u}", super->rcm_ino);
+	kenter("{%x}", super->rcm_ino);
 
 	/* find the parent index entry */
 	metadata = cachefs_metadata_preread(super->rcm_inode);
@@ -524,17 +515,13 @@
 	}
 
 	/* do the release under journalling */
-	ret = -ENOMEM;
-	trans = cachefs_trans_alloc(super, GFP_KERNEL);
-	if (!trans)
-		goto error;
+	trans = *_trans;
 
 	jindex = &trans->jentry->ixdata[0];
 	jindex->next_ino	= UINT_MAX;
 	jindex->next_index	= UINT_MAX;
 
 	trans->jentry->mark	= CACHEFS_ONDISC_UJNL_INODE_DELETING;
-	trans->jentry->ino	= super->rcm_ino;
 
 	if (iinode) {
 		trans->jentry->index	= iino;
@@ -570,10 +557,18 @@
 	cachefs_trans_affects_inode(trans, super->rcm_inode);
 	cachefs_trans_affects_inode(trans, super->imetadata);
 
+	trans->jentry->rcm_ino		= 0;
+	trans->jentry->rcm_indirect	= 0;
+	trans->jentry->rcm_block	= 0;
+	trans->jentry->rcm_ptrnext	= 0;
+	trans->jentry->rcm_ptrstop	= 0;
+
 	ret = cachefs_trans_mark(trans);
 	if (ret < 0)
 		goto error;
 
+	*_trans = NULL;
+
 	/* free up the parent index entry */
 	if (iinode) {
 		cachefs_page_modify(super, &ixpage);
@@ -604,15 +599,13 @@
 
 	/* modify the metadata inode metadata entry */
 	metadata = cachefs_metadata_prewrite(super->imetadata);
-	metadata->freelink	= super->rcm_ino;
+	metadata->freelink	= trans->jentry->ino;
 	cachefs_metadata_postwrite(super->imetadata);
 
 	/* do the writing */
 	cachefs_trans_commit(trans);
-	trans = NULL;
 
  error:
-	cachefs_trans_put(trans);
 	cachefs_put_page(ixpage);
 	cachefs_iput(iinode);
 
@@ -631,175 +624,197 @@
  * - 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
+ *	FROM	TO	WHAT
+ *	0	-	reclaiming index entries
+ *	1	-	pointers in single indirect block
+ *	2	2+N-1	pointers in dblindirect subblocks 0...N-1
+ *	2+N	-	pointers in dblindirect block
+ *	2+N+1	-	all pointers in inode struct
+ *	2+N+2	-	inode itself
  */
 static void cachefs_recycle_reclaim_inode(struct cachefs_super *super)
 {
 	struct cachefs_ondisc_metadata *metadata;
-	cachefs_blockix_t bix, *pbix;
-	struct page *page, *dpage;
-	unsigned indirect;
-	unsigned short next, stop;
-	int ret, loop;
+	struct cachefs_transaction *trans;
+	struct page *dpage;
+	int ret = 0, loop;
 
 	const unsigned N = PAGE_SIZE / sizeof(cachefs_blockix_t);
 
-	kenter("{%u,%u,%u:%hu-%hu}",
+	kenter("{%x,%u,%x:%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);
+	if (super->rcm_ptrnext == super->rcm_ptrstop) {
+		cachefs_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;
+	trans = cachefs_trans_alloc(super, GFP_KERNEL);
+	if (!trans) {
+		kleave(" [ENOMEM");
+		return;
+	}
 
- again:
-	indirect++;
+	trans->jentry->ino		= super->rcm_ino;
+	trans->jentry->rcm_ino		= super->rcm_ino;
+	trans->jentry->rcm_indirect	= super->rcm_indirect;
+	trans->jentry->rcm_block	= super->rcm_block;
+	trans->jentry->rcm_ptrstop	= super->rcm_ptrstop;
+	trans->jentry->rcm_ptrnext	= super->rcm_ptrnext;
+
+	trans->changed |=
+		CACHEFS_TRANS_CHANGED_RCMBLOCK |
+		CACHEFS_TRANS_CHANGED_RCMPTR;
 
 	/* iterate through an index clearing out the entries it contains */
-	if (indirect == 1) {
-		if (super->rcm_inode->index_dsize == 0)
-			goto again;
-
-		if (cachefs_index_reclaim_one_entry(super) < 0)
-			goto error2;
-		goto again;
-	}
+	if (trans->jentry->rcm_indirect == 0) {
+		kdebug("-- step 0.%u", trans->jentry->rcm_block);
+
+		if (super->rcm_inode->index_dsize != 0)
+			if (cachefs_index_reclaim_one_entry(super, &trans) < 0)
+				goto error2;
+		goto advance;
+	}
+
+	/* continue a partially complete pointer array */
+	if (trans->jentry->rcm_ptrstop > 0 &&
+	    super->rcm_ptrnext < super->rcm_ptrstop)
+		goto process_pointer_array;
+
+ advance:
+	trans->jentry->rcm_indirect++;
+	kdebug("-- step %u", trans->jentry->rcm_indirect);
 
 	/* process the single indirect block */
-	if (indirect == 2) {
+	if (trans->jentry->rcm_indirect == 1) {
 		metadata = cachefs_metadata_preread(super->rcm_inode);
-		bix = metadata->single_indirect;
+		trans->jentry->rcm_block = metadata->single_indirect;
 		cachefs_metadata_postread(super->rcm_inode);
 
-		if (!bix)
-			goto again;
-		goto pointer_array;
+		if (!trans->jentry->rcm_block)
+			goto advance;
+		goto start_pointer_array;
 	}
 
 	/* deal with double indirection */
-	if (indirect <= 3 + N) {
+	if (trans->jentry->rcm_indirect <= 2 + N) {
+		cachefs_blockix_t *pbix, dblbix;
+
 		metadata = cachefs_metadata_preread(super->rcm_inode);
-		bix = metadata->double_indirect;
+		dblbix = metadata->double_indirect;
 		cachefs_metadata_postread(super->rcm_inode);
 
-		if (!bix) {
-			indirect = 3 + N;
-			goto again;
+		if (!dblbix) {
+			trans->jentry->rcm_indirect = 2 + N;
+			goto advance;
 		}
 
-		ret = cachefs_block_read(super, NULL, bix, 0, NULL, &dpage);
+		ret = cachefs_block_read(super, NULL, dblbix, 0, NULL, &dpage);
 		if (ret < 0)
 			goto error;
 
 		/* start processing a double indirect subblock */
-		if (indirect <= 3 + N - 1) {
+		if (trans->jentry->rcm_indirect <= 2 + N - 1) {
 			wait_on_page_locked(dpage);
 
-			bix = 0;
+			trans->jentry->rcm_block = 0;
 			pbix = kmap(dpage);
-			for (loop = indirect - 2; loop < N; loop++) {
-				bix = pbix[loop];
-				if (bix)
+			for (loop = trans->jentry->rcm_indirect - 2;
+			     loop < N;
+			     loop++) {
+				trans->jentry->rcm_block = pbix[loop];
+				if (trans->jentry->rcm_block)
 					break;
 			}
 			kunmap(dpage);
 
-			indirect = loop + 3;
-			if (bix) {
+			trans->jentry->rcm_indirect = loop + 3;
+			if (trans->jentry->rcm_block) {
 				put_page(dpage);
-				goto pointer_array;
+				goto start_pointer_array;
 			}
 		}
 
 		/* start processing the double indirect block */
-		page = dpage;
-		bix = __cachefs_get_page_block(dpage)->bix;
-		goto pointer_array2;
+		super->rcm_curpage = dpage;
+		super->rcm_block = __cachefs_get_page_block(dpage)->bix;
+		goto process_pointer_array;
 	}
 
 	/* reclaim all the block pointers in the inode metadata record */
-	if (indirect == 3 + N + 1) {
-		bix	= super->rcm_inode->metadata->bix;
-		next	= super->rcm_inode->metadata_offset;
-		next	+= offsetof(struct cachefs_ondisc_metadata,
-				    triple_indirect);
-		next	/= sizeof(cachefs_blockix_t);
-
-		stop	= super->rcm_inode->metadata_offset;
-		stop	+= super->layout->metadata_size;
-		stop	/= sizeof(cachefs_blockix_t);
+	if (trans->jentry->rcm_indirect == 2 + N + 1) {
+		trans->jentry->rcm_block = super->rcm_inode->metadata->bix;
+		trans->jentry->rcm_ptrnext = super->rcm_inode->metadata_offset;
+		trans->jentry->rcm_ptrnext +=
+			offsetof(struct cachefs_ondisc_metadata,
+				 triple_indirect);
+		trans->jentry->rcm_ptrnext /= sizeof(cachefs_blockix_t);
+
+		trans->jentry->rcm_ptrstop = super->rcm_inode->metadata_offset;
+		trans->jentry->rcm_ptrstop += super->layout->metadata_size;
+		trans->jentry->rcm_ptrstop /= sizeof(cachefs_blockix_t);
 
 		down_read(&super->rcm_inode->metadata_sem);
-		page = super->rcm_inode->metadata_page;
-		get_page(page);
+		super->rcm_curpage = super->rcm_inode->metadata_page;
+		get_page(super->rcm_curpage);
 		up_read(&super->rcm_inode->metadata_sem);
-		goto pointer_array2;
+		goto process_pointer_array;
 	}
 
 	/* reclaim the inode itself */
-	if (cachefs_recycle_reclaim_inode_metadata(super) < 0) {
-		indirect--;
-		bix	= 0;
-		next	= 0;
-		stop	= 0;
-		page	= NULL;
-		goto set;
-	}
+	ret = cachefs_recycle_reclaim_inode_metadata(super, &trans);
+	if (ret < 0)
+		goto error;
 
-	/* 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;
+	super->rcm_inode = NULL;
+
+	cachefs_trans_put(trans);
 	kleave("");
 	return;
 
- pointer_array:
-	ret = cachefs_block_read(super, NULL, bix, 0, NULL, &page);
+ start_pointer_array:
+	ret = cachefs_block_read(super, NULL, trans->jentry->rcm_block, 0,
+				 NULL, &super->rcm_curpage);
 	if (ret < 0)
 		goto error;
 
- pointer_array2:
-	cachefs_recycle_pointer_array(super);
+ process_pointer_array:
+	down(&super->ujnl_alloc_sem);
+	super->rcm_ino		= trans->jentry->rcm_ino;
+	super->rcm_indirect	= trans->jentry->rcm_indirect;
+	super->rcm_block	= trans->jentry->rcm_block;
+	super->rcm_ptrstop	= trans->jentry->rcm_ptrstop;
+	super->rcm_ptrnext	= trans->jentry->rcm_ptrnext;
+	up(&super->ujnl_alloc_sem);
 
- set:
-	super->rcm_indirect	= indirect;
-	super->rcm_block	= bix;
-	super->rcm_ptrnext	= next;
-	super->rcm_ptrstop	= stop;
-	super->rcm_curpage	= page;
+	cachefs_recycle_pointer_array(super, &trans);
+	cachefs_trans_put(trans);
 	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;
+		printk("CacheFS: discarding block %u due to I/O error\n",
+		       trans ? trans->jentry->rcm_block : super->rcm_block);
+		goto advance;
 	}
  error2:
-	kdebug("[error %d]", ret);
-	goto set;
+	if (trans) {
+		down(&super->ujnl_alloc_sem);
+		super->rcm_ino		= trans->jentry->rcm_ino;
+		super->rcm_indirect	= trans->jentry->rcm_indirect;
+		super->rcm_block	= trans->jentry->rcm_block;
+		super->rcm_ptrstop	= trans->jentry->rcm_ptrstop;
+		super->rcm_ptrnext	= trans->jentry->rcm_ptrnext;
+		up(&super->ujnl_alloc_sem);
+		cachefs_trans_put(trans);
+	}
+	kleave("[error %d]", ret);
 } /* end cachefs_recycle_reclaim_inode() */
 
 /*****************************************************************************/
@@ -811,13 +826,13 @@
 	struct cachefs_transaction *trans;
 	int ret;
 
-	kenter("{%u,%u,%u:%hu-%hu}",
+	kenter("{%x,%u,%x:%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");
+		kdebug("do reclaim: %x", super->rcm_ino);
 		if (!super->rcm_inode) {
 			ret = cachefs_iget(super, super->rcm_ino,
 					   &super->rcm_inode);
@@ -845,6 +860,16 @@
 		trans->jentry->ino  = super->rcm_imm_buf[super->rcm_imm_tail];
 		trans->jentry->mark = CACHEFS_ONDISC_UJNL_INODE_RECLAIMING;
 
+		trans->jentry->rcm_ino		= trans->jentry->ino;
+		trans->jentry->rcm_indirect	= 0;
+		trans->jentry->rcm_block	= 0;
+		trans->jentry->rcm_ptrnext	= 0;
+		trans->jentry->rcm_ptrstop	= 0;
+
+		trans->changed |=
+			CACHEFS_TRANS_CHANGED_RCMBLOCK |
+			CACHEFS_TRANS_CHANGED_RCMPTR;
+
 		ret = cachefs_trans_mark(trans);
 		if (ret < 0) {
 			kdebug("[error %d]", ret);
@@ -852,12 +877,6 @@
 			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 =
@@ -866,7 +885,6 @@
 		goto done;
 	}
 
-
  done:
 	if (super->rcm_ino ||
 	    super->rcm_imm_head != super->rcm_imm_tail
@@ -906,6 +924,8 @@
 		goto error;
 
 	trans->jentry->mark   	= CACHEFS_ONDISC_UJNL_DATA_UNALLOCING;
+	trans->jentry->index	= super->recycle_cur;
+	trans->jentry->ixentry	= super->recycle_cur_n;
 	trans->jentry->ino	= vjentry->ino;
 	trans->jentry->auxmark	= vjentry->vslot;
 	trans->jentry->block	= vjentry->bix;
@@ -939,6 +959,9 @@
 			goto error_free;
 
 		cachefs_trans_affects_block(trans, rcyblock, 0, PAGE_SIZE);
+
+		trans->jentry->recycle_cur = vjentry->bix;
+		trans->changed |= CACHEFS_TRANS_CHANGED_RECYCLE;
 	}
 	else {
 		/* we can add into an existing recycling node */
@@ -964,15 +987,14 @@
 	memset(kmap(uppage) + vjentry->upentry, 0, sizeof(cachefs_blockix_t));
 	kunmap(uppage);
 
-	if (trans->jentry->auxentry == UINT_MAX) {
+	if (trans->changed & CACHEFS_TRANS_CHANGED_RECYCLE) {
 		/* new recycling node */
 		node = kmap(rcypage);
-		node->next  = super->recycle_cur;
-		node->count = super->recycle_cur_n;
+		node->next  = trans->jentry->index;
+		node->count = trans->jentry->ixentry;
 		kunmap(rcypage);
 
-		super->recycle_cur	= vjentry->bix;
-		super->recycle_room	= CACHEFS_ONDISC_LEAVES_PER_FREE_NODE;
+		super->recycle_room = CACHEFS_ONDISC_LEAVES_PER_FREE_NODE;
 		rcypage	 = xchg(&super->recycle_node, rcypage);
 		rcyblock = xchg(&super->recycle_block, rcyblock);
 	}

Index: journal.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/journal.c,v
retrieving revision 1.40
retrieving revision 1.41
diff -u -r1.40 -r1.41
--- journal.c	10 Jul 2003 14:21:24 -0000	1.40
+++ journal.c	17 Jul 2003 12:02:13 -0000	1.41
@@ -381,19 +381,45 @@
 	trans->serial		= super->ujnl_serial++;
 	super->ujnl_head	= next;
 
+	/* some recorded values in the superblock should only be updated with
+	 * the lock held */
+	if (trans->changed & CACHEFS_TRANS_CHANGED_ALLOC) {
+		super->alloc_leaf = trans->jentry->alloc_leaf;
+		super->alloc_cur  = trans->jentry->alloc_cur;
+	} else {
+		trans->jentry->alloc_leaf = super->alloc_leaf;
+		trans->jentry->alloc_cur  = super->alloc_cur;
+	}
+
+	if (trans->changed & CACHEFS_TRANS_CHANGED_RECYCLE) {
+		super->recycle_cur = trans->jentry->recycle_cur;
+	} else {
+		trans->jentry->recycle_cur = super->recycle_cur;
+	}
+
+	if (trans->changed & CACHEFS_TRANS_CHANGED_RCMBLOCK) {
+		super->rcm_ino		= trans->jentry->rcm_ino;
+		super->rcm_indirect	= trans->jentry->rcm_indirect;
+		super->rcm_block	= trans->jentry->rcm_block;
+		super->rcm_ptrstop	= trans->jentry->rcm_ptrstop;
+	} else {
+		trans->jentry->rcm_ino		= super->rcm_ino;
+		trans->jentry->rcm_indirect	= super->rcm_indirect;
+		trans->jentry->rcm_block	= super->rcm_block;
+		trans->jentry->rcm_ptrstop	= super->rcm_ptrstop;
+	}
+
+	if (trans->changed & CACHEFS_TRANS_CHANGED_RCMPTR) {
+		super->rcm_ptrnext	= trans->jentry->rcm_ptrnext;
+	} else {
+		trans->jentry->rcm_ptrnext	= super->rcm_ptrnext;
+	}
+
 	up(&super->ujnl_alloc_sem);
 
 	trans->index			= index;
 	trans->jentry->batch		= trans->batch;
 	trans->jentry->serial		= trans->serial;
-	trans->jentry->alloc_leaf	= super->alloc_leaf;
-	trans->jentry->alloc_cur	= super->alloc_cur;
-	trans->jentry->recycle_cur	= super->recycle_cur;
-	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 */
@@ -433,6 +459,7 @@
 
 	/* record a mark in the validity journal */
 	if (trans->vjentry) {
+		wait_on_page_locked(trans->vjentry->vpage);
 		cachefs_block_modify(super, trans->vjentry->vblock,
 				     &trans->vjentry->vpage);
 		vjentry = kmap(trans->vjentry->vpage) + trans->vjentry->ventry;

Index: index.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/index.c,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -r1.28 -r1.29
--- index.c	16 Jul 2003 10:44:21 -0000	1.28
+++ index.c	17 Jul 2003 12:02:13 -0000	1.29
@@ -640,7 +640,7 @@
 
 	/* fill the inode definition */
 	metadata = kmap(inopage) + ino_offset;
-	memset(metadata, 0, sizeof(super->imetadata->index_esize));
+	memset(metadata, 0, super->imetadata->index_esize);
 
 	metadata->header.state	= CACHEFS_ONDISC_INDEX_ACTIVE;
 	metadata->header.ino	= 0xfefefe;
@@ -689,24 +689,27 @@
  * mark the next inode pinned by an entry in the index currently being
  * reclaimed as being obsolete
  */
-int cachefs_index_reclaim_one_entry(struct cachefs_super *super)
+int cachefs_index_reclaim_one_entry(struct cachefs_super *super,
+				    struct cachefs_transaction **_trans)
 {
 	struct cachefs_ondisc_index_entry *xent;
 	struct cachefs_ondisc_metadata *metadata;
-	struct cachefs_transaction *trans = NULL;
+	struct cachefs_transaction *trans;
 	struct cachefs_inode *inode = NULL;
 	unsigned long flags;
 	struct page *page = NULL;
 	unsigned pgnum, offset, ino;
 	int ret;
 
-	_enter("{%u,%u}", super->rcm_ino, super->rcm_block);
+	kenter("{%x,%x}", super->rcm_ino, super->rcm_block);
 
+ try_next_block:
 	pgnum	= super->rcm_block / super->rcm_inode->index_epp;
 	offset	= super->rcm_block % super->rcm_inode->index_epp;
+	offset *= super->rcm_inode->index_esize;
 
 	if (pgnum >= (super->rcm_inode->vfs_inode.i_size >> PAGE_SHIFT)) {
-		_leave(" = 0");
+		kleave(" = 0");
 		return 0; /* done them all */
 	}
 
@@ -718,25 +721,39 @@
 			super->rcm_block =
 				(pgnum + 1) * super->rcm_inode->index_epp;
 		}
-		_leave(" = %d", ret);
+		kleave(" = %d", ret);
 		return ret;
 	}
 
-	offset *= super->rcm_inode->index_esize;
+ try_next_entry:
 	xent = kmap(page) + offset;
 	ino = xent->ino;
+	BUG_ON(ino == 0 && xent->state != CACHEFS_ONDISC_INDEX_FREE);
+	BUG_ON(ino != 0 && xent->state == CACHEFS_ONDISC_INDEX_FREE);
 	kunmap(page);
 
+	if (!ino) {
+		kdebug("skip slot %u", super->rcm_block);
+		super->rcm_block++;
+
+		offset += super->rcm_inode->index_esize;
+		if (offset + super->rcm_inode->index_esize <= PAGE_SIZE)
+			goto try_next_entry;
+
+		cachefs_put_page(page);
+		page = NULL;
+		goto try_next_block;
+	}
+
 	ret = cachefs_iget(super, ino, &inode);
-	if (ret < 0)
-		goto error_skip;
+	if (ret < 0) {
+		if (ret == -EIO)
+			super->rcm_block++;
+		goto error;
+	}
 
 	/* journal what we're going to do */
-	trans = cachefs_trans_alloc(super, GFP_KERNEL);
-	if (!trans) {
-		_leave(" = -ENOMEM");
-		return -ENOMEM;
-	}
+	trans = *_trans;
 
 	trans->jentry->mark	= CACHEFS_ONDISC_UJNL_INODE_MARK_RECLAIM;
 	trans->jentry->ino	= inode->vfs_inode.i_ino;
@@ -750,9 +767,13 @@
 
 	cachefs_trans_affects_inode(trans, inode);
 
+	trans->jentry->rcm_block = super->rcm_block + 1;
+
 	ret = cachefs_trans_mark(trans);
 	if (ret < 0)
-		goto error_skip;
+		goto error;
+
+	*_trans = NULL;
 
 	/* modify the inode metadata entry */
 	metadata = cachefs_metadata_prewrite(inode);
@@ -762,14 +783,14 @@
 	cachefs_metadata_postwrite(inode);
 
 	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) {
+		       CACHEFS_RCM_IMM_BUFSIZE) > 0
+	    ) {
 		super->rcm_imm_buf[super->rcm_imm_head] =
 			inode->vfs_inode.i_ino;
 		super->rcm_imm_head =
@@ -782,16 +803,12 @@
 
 	spin_unlock_irqrestore(&super->rcm_lock, flags);
 
-	super->rcm_block++;
 	ret = -EAGAIN;
 
- error_skip:
+ error:
 	cachefs_iput(inode);
-	cachefs_trans_put(trans);
 	cachefs_put_page(page);
-	if (ret == -EIO)
-		super->rcm_block++;
 
-	_leave(" = %d", ret);
+	kleave(" = %d [%u]", ret, super->rcm_block);
 	return ret;
 } /* end cachefs_index_reclaim_one_entry() */

Index: dump-journal.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/dump-journal.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- dump-journal.c	10 Jul 2003 14:21:24 -0000	1.14
+++ dump-journal.c	17 Jul 2003 12:02:13 -0000	1.15
@@ -141,13 +141,13 @@
 	       "  CNT"
 	       "    ALLOC[LEAF]"
 	       " RECYCLE "
-	       " RCYBLOCK:NEXT-STOP\n");
+	       " RCMBLOCK:NEXT-STOP\n");
 
 	printf("===="
 	       " ==========="
 	       " ========= ===="
 	       " ======== ========"
-	       " ============="
+	       " =============="
 	       " ============="
 	       " ============="
 	       " ============="
@@ -168,15 +168,15 @@
 		printf("%s%4u" NORMAL
 		       " " CYAN		"%5u"	GREY	"."	NORMAL	"%-5u"	NORMAL
 		       " "		"%s"		" %4d"
-		       " " YELLOW	"%8x"	NORMAL	" %8u"
-		       " " YELLOW	"%8x"	GREY	":"	NORMAL	"%-4hu"
-		       " " YELLOW	"%8d"	GREY	"+"	NORMAL	"%-4hu"
-		       " " YELLOW	"%8d"	GREY	"+"	NORMAL	"%-4hu"
-		       " " YELLOW	"%8d"	GREY	"+"	NORMAL	"%-4hu"
+		       " " YELLOW	"%8x"	NORMAL	" %8x"
+		       " " YELLOW	"%8x"	GREY	":"	NORMAL	"%-5hu"
+		       " " YELLOW	"%8x"	GREY	"+"	NORMAL	"%-4hu"
+		       " " YELLOW	"%8x"	GREY	"+"	NORMAL	"%-4hu"
+		       " " YELLOW	"%8x"	GREY	"+"	NORMAL	"%-4hu"
 		       " " YELLOW	"%4hu"	NORMAL	""
-		       " " GREEN	"%8u"	NORMAL	"[%-4hu]"
-		       " " CYAN		"%8u"	NORMAL	""
-		       " " RED		"%8u"	GREY	":"	NORMAL
+		       " " GREEN	"%8x"	NORMAL	"[%-4hu]"
+		       " " CYAN		"%8x"	NORMAL	""
+		       " " RED		"%8x"	GREY	":"	NORMAL
 		       "%4hu" GREY"-"NORMAL "%-4hu"
 		       "\n",
 		       loop&7 ? NORMAL : GREEN,

Index: cachefs-layout.h
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/cachefs-layout.h,v
retrieving revision 1.31
retrieving revision 1.32
diff -u -r1.31 -r1.32
--- cachefs-layout.h	16 Jul 2003 10:44:21 -0000	1.31
+++ cachefs-layout.h	17 Jul 2003 12:02:13 -0000	1.32
@@ -210,7 +210,8 @@
 
 	/* beginning new recycle_stk front node
 	 * - block	= block being begun
-	 * - auxblock	= old front recycling node
+	 * - index	= old front recycling node
+	 * - ixentry	= old front recycling node's count
 	 * - upblock	= block from which transferred (or 0 if from unready list)
 	 * - upentry	= entry in upblock[]
 	 * - pgnum	= new super->layout.bix_unready
@@ -325,6 +326,8 @@
 	CACHEFS_ONDISC_UJNL_DATA_WRITTEN,
 
 	/* data block being unallocated
+	 * - index	= old front recycling node
+	 * - ixentry	= old front recycling node's count
 	 * - ino	= inode to which block belongs
 	 * - pgnum	= which page of inode being unallocated
 	 * - block	= block being recycled

Index: aops.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/aops.c,v
retrieving revision 1.43
retrieving revision 1.44
diff -u -r1.43 -r1.44
--- aops.c	16 Jul 2003 11:19:39 -0000	1.43
+++ aops.c	17 Jul 2003 12:02:13 -0000	1.44
@@ -923,8 +923,8 @@
 	struct cachefs_ondisc_metadata *metadata;
 	struct cachefs_super *super = sb->s_fs_info;
 	struct cachefs_block *block;
-	cachefs_blockix_t alloc2os = 0, old_alloc_cur;
-	u_int32_t next_count = 0, old_alloc_leaf;
+	cachefs_blockix_t alloc2os = 0;
+	u_int32_t next_count = 0;
 	int ret;
 	u8 *data;
 
@@ -1005,10 +1005,9 @@
 
 	BUG_ON(super->alloc_leaf > CACHEFS_ONDISC_LEAVES_PER_FREE_NODE);
 
-	/* choose either a dependent block or the now empty node */
-	old_alloc_cur  = super->alloc_cur;
-	old_alloc_leaf = super->alloc_leaf;
+	step->transaction->changed |= CACHEFS_TRANS_CHANGED_ALLOC;
 
+	/* choose either a dependent block or the now empty node */
 	if (super->alloc_leaf == CACHEFS_ONDISC_LEAVES_PER_FREE_NODE) {
 		/* no dependent blocks left - take the alloc node itself */
 		block = super->alloc_block;
@@ -1018,12 +1017,12 @@
 		BUG_ON(!jentry->block);
 
 		node = kmap(super->alloc_node);
-		super->alloc_cur	= node->next;
-		super->alloc_leaf	= 0;
+		jentry->alloc_cur	= node->next;
+		jentry->alloc_leaf	= 0;
 		next_count		= node->count;
 		kunmap(node);
 
-		alloc2os = super->alloc_cur;
+		alloc2os = jentry->alloc_cur;
 
 		if (step->page)
 			cachefs_block_set(super,
@@ -1034,11 +1033,14 @@
 	else {
 		/* take the next dependent page */
 		node = kmap(super->alloc_node);
-		jentry->block	= node->leaves[super->alloc_leaf++];
+		jentry->block	= node->leaves[super->alloc_leaf];
 		alloc2os	= node->next;
 		kunmap(node);
 		BUG_ON(!jentry->block);
 
+		jentry->alloc_cur	= super->alloc_cur;
+		jentry->alloc_leaf	= super->alloc_leaf + 1;
+
 		if (!step->page) {
 			ret = cachefs_block_read(super, NULL, jentry->block, 1,
 						 &block, &step->page);
@@ -1085,11 +1087,8 @@
 	}
 
 	/* make sure the journal is marked on disc before doing anything else */
-	if (cachefs_trans_mark(step->transaction) < 0) {
-		super->alloc_cur  = old_alloc_cur;
-		super->alloc_leaf = old_alloc_leaf;
+	if (cachefs_trans_mark(step->transaction) < 0)
 		goto error_block;
-	}
 
 	if (step->flags & CACHEFS_BLOCK_INIT_NETFSDATA) {
 		set_bit(CACHEFS_BLOCK_NETFSDATA, &block->flags);
@@ -1133,7 +1132,7 @@
 	}
 
 	/* clean up the alloc stack tracking */
-	if (old_alloc_leaf == CACHEFS_ONDISC_LEAVES_PER_FREE_NODE) {
+	if (super->alloc_leaf == 0) {
 		struct page *dead;
 
 		/* move the allocation stack to the 2OS */