Subject: afs/fs/cachefs super.c,1.32,1.33 recycling.c,1.21,1.22 journal.c,1.35,1.36 index.c,1.22,1.23 cachefs-int.h,1.35,1.36 aops.c,1.36,1.37

From: [email-masked]
Date: Wed, 11 Jun 2003 12:59:55 +0100

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

Modified Files:
	super.c recycling.c journal.c index.c cachefs-int.h aops.c 
Log Message:
fix some data integrity problems

Index: super.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/super.c,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -r1.32 -r1.33
--- super.c	10 Jun 2003 17:49:49 -0000	1.32
+++ super.c	11 Jun 2003 11:59:52 -0000	1.33
@@ -299,6 +299,7 @@
 	INIT_LIST_HEAD(&super->jnld_link);
 
 	init_MUTEX(&super->batch_sem);
+	init_MUTEX(&super->batch_uj_sem);
 	init_rwsem(&super->batch_ctrl_sem);
 	spin_lock_init(&super->batch_qlock);
 	INIT_LIST_HEAD(&super->batch_writeq);
@@ -737,7 +738,7 @@
 	}
 
 	super->dmn_die = 1;
-	cachefs_trans_sync(super,1);
+	cachefs_trans_sync(super,CACHEFS_TRANS_SYNC_WAIT_FOR_ACK);
 
 	super->dmn_die = 2;
 	wake_up(&super->dmn_sleepq);

Index: recycling.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/recycling.c,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -r1.21 -r1.22
--- recycling.c	2 Jun 2003 09:17:42 -0000	1.21
+++ recycling.c	11 Jun 2003 11:59:52 -0000	1.22
@@ -340,6 +340,7 @@
 {
 	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;
@@ -402,12 +403,17 @@
 		if (indirect[src]) {
 			jeptr[count] = indirect[src];
 			count++;
+
+			if (cachefs_block_find(super,jeptr[count],&block) == 0) {
+				clear_bit(CACHEFS_BLOCK_NETFSDATA,&block->flags);
+				cachefs_block_put(block);
+			}
 		}
 
 		src++;
 	}
 
-	trans->jentry->count	= count;
+	trans->jentry->count = count;
 
 	ret = cachefs_trans_mark(trans);
 	if (ret<0) {
@@ -829,7 +835,7 @@
 	struct cachefs_ondisc_free_node *node;
 	struct cachefs_transaction *trans;
 	struct cachefs_vj_entry *vjentry;
-	struct cachefs_block *rcyblock = NULL, *upblock = NULL;
+	struct cachefs_block *rcyblock = NULL, *upblock = NULL, *block;
 	struct page *rcypage = NULL, *uppage = NULL;
 	int ret;
 
@@ -863,6 +869,11 @@
 
 	cachefs_trans_affects_block(trans,vjentry->vblock,vjentry->ventry,
 				    sizeof(struct cachefs_ondisc_validity_journal));
+
+	if (cachefs_block_find(super,vjentry->bix,&block) == 0) {
+		clear_bit(CACHEFS_BLOCK_NETFSDATA,&block->flags);
+		cachefs_block_put(block);
+	}
 
 	if (super->recycle_room==0) {
 		/* we have to generate a new recycling node */

Index: journal.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/journal.c,v
retrieving revision 1.35
retrieving revision 1.36
diff -u -r1.35 -r1.36
--- journal.c	10 Jun 2003 17:49:49 -0000	1.35
+++ journal.c	11 Jun 2003 11:59:52 -0000	1.36
@@ -23,7 +23,7 @@
 	unsigned short		batch_end;	/* batch mark sector for ujnl_batch */
 	unsigned short		batch_ack;	/* batch ACK sector for ujnl_batch */
 	unsigned short		batch_count;	/* number of marks in batch */
-	unsigned		ack_hi;		/* highest batch with ACK number */
+	int16_t			ack_hi;		/* highest batch with ACK number */
 };
 
 const char *cachefs_ondisc_ujnl_marks[] = {
@@ -489,6 +489,7 @@
 	_enter("");
 
 	down(&super->batch_sem);
+	down(&super->batch_uj_sem);
 
 	spin_lock_irqsave(&super->ujnl_mk_lock,flags);
 	del_timer_sync(&super->batch_timer);
@@ -525,10 +526,18 @@
 				BUG_ON(!block->page->private);
 
 				if (!test_bit(CACHEFS_BLOCK_WRITEBACK,&block->flags)) {
+					struct list_head *plist;
+
 					set_bit(CACHEFS_BLOCK_COW	,&block->flags);
 					set_bit(CACHEFS_BLOCK_WRITEBACK	,&block->flags);
 
-					list_add_tail(&block->batch_link,&super->batch_writeq);
+					plist = &super->batch_writeq;
+					if (test_bit(CACHEFS_BLOCK_NETFSDATA,&block->flags)) {
+						plist = &super->batch_doneq;
+						kdebug("skip meta block %u",block->bix);
+					}
+
+					list_add_tail(&block->batch_link,plist);
 					block->writeback = block->page;
 					get_page(block->writeback);
 					flush_dcache_page(block->writeback);
@@ -773,6 +782,7 @@
 
 	bfirst = rb_entry(_n,struct cachefs_block,lookup_node);
 	if (!test_bit(CACHEFS_BLOCK_WRITEBACK,&bfirst->flags) ||
+	    test_bit(CACHEFS_BLOCK_NETFSDATA,&bfirst->flags) ||
 	    test_bit(CACHEFS_BLOCK_UJOURNAL,&bfirst->flags))
 		goto next_first;
 
@@ -1187,6 +1197,7 @@
  */
 static int cachefs_trans_marker_written(struct bio *bio, unsigned int bytes_done, int error)
 {
+	struct cachefs_super *super;
 	struct cachefs_block *block;
 
 	_enter("%p{%u},%u,%d",bio,bio->bi_size,bytes_done,error);
@@ -1198,12 +1209,16 @@
 
 	block = bio->bi_private;
 
-	/* mark the block appropriately */
+	/* let critical blocks be reused for netfs data caching */
+	super = block->super;
+	up(&super->batch_uj_sem);
+
 	if (!test_bit(BIO_UPTODATE,&bio->bi_flags))
 		set_bit(CACHEFS_BLOCK_ERROR,&block->flags);
 
 	page_cache_release(bio->bi_io_vec[0].bv_page);
 	bio_put(bio);
+
 	_leave(" = 0");
 	return 0;
 } /* end cachefs_trans_marker_written() */
@@ -1242,16 +1257,16 @@
 /*
  * synchronise by forcing a batch write to occur and then maybe waiting for it to be ACK'd on disc
  */
-void cachefs_trans_sync(struct cachefs_super *super, int wait)
+void cachefs_trans_sync(struct cachefs_super *super, cachefs_trans_syncwt_t wait)
 {
 	int16_t next_batch;
 
 	DECLARE_WAITQUEUE(myself,current);
 
-	kenter("{batch=%hd}",super->ujnl_batch);
+	kenter("{batch=%hd},%d",super->ujnl_batch,wait);
 
 	/* if we're not supposed to wait, just induce consideration of a batch write */
-	if (!wait) {
+	if (wait == CACHEFS_TRANS_SYNC_NOWAIT) {
 		set_bit(CACHEFS_SUPER_BATCH_TIMER,&super->flags);
 		wake_up_all(&super->batch_timer_wq);
 		kleave("");
@@ -1267,7 +1282,7 @@
 	}
 	else {
 		/* transactions present - must wait till pending batch is written */
-		next_batch = super->ujnl_batch + 1;
+		next_batch   = super->ujnl_batch + 1;
 
 		set_bit(CACHEFS_SUPER_BATCH_TIMER,&super->flags);
 		wake_up_all(&super->batch_timer_wq);
@@ -1288,8 +1303,14 @@
 	}
 
 	/* now we have to wait for any currently active batch write */
-	down(&super->batch_sem);
-	up(&super->batch_sem);
+	if (wait==CACHEFS_TRANS_SYNC_WAIT_FOR_MARK) {
+		down(&super->batch_uj_sem);
+		up(&super->batch_uj_sem);
+	}
+	else {
+		down(&super->batch_sem);
+		up(&super->batch_sem);
+	}
 
 	kleave("");
 } /* end cachefs_trans_sync() */
@@ -1410,13 +1431,14 @@
 				super->rcm_indirect	= jentry->rcm_indirect;
 				super->rcm_ino		= jentry->rcm_ino;
 
-				desc->ack_hi = jentry->batch;
-
-				kdebug("UJNL[%u] ACK %u { a=%u[%u] r=%u R=%u:%u:%u[%u-%u]",
-				       slot,desc->ack_hi,
+				kdebug("UJNL[%u] ACK %u { a=%u[%u] r=%u R=%u:%u:%u[%u-%u] } hi=%u",
+				       slot,jentry->batch,
 				       super->alloc_leaf,super->alloc_cur,super->recycle_cur,
 				       super->rcm_ino,super->rcm_indirect,super->rcm_block,
-				       super->rcm_ptrnext,super->rcm_ptrstop);
+				       super->rcm_ptrnext,super->rcm_ptrstop,
+				       desc->ack_hi);
+
+				desc->ack_hi = jentry->batch;
 			}
 			else {
 				kdebug("UJNL[%u] ACK %u { hi=%u }",
@@ -1656,6 +1678,8 @@
 		}
 
 		dbgpgalloc(super->alloc_node);
+
+		set_bit(CACHEFS_BLOCK_CRITICAL,&super->alloc_block->flags);
 		wait_on_page_locked(super->alloc_node);
 
 		node = kmap(super->alloc_node);

Index: index.c
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/index.c,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -r1.22 -r1.23
--- index.c	10 Jun 2003 17:49:49 -0000	1.22
+++ index.c	11 Jun 2003 11:59:52 -0000	1.23
@@ -277,7 +277,8 @@
 		BUG_ON(newentry==UINT_MAX);
 
 //		_debug("syncing");
-//		cachefs_trans_sync(iinode->vfs_inode.i_sb->s_fs_info,1);
+//		cachefs_trans_sync(iinode->vfs_inode.i_sb->s_fs_info,
+//				   CACHEFS_TRANS_SYNC_WAIT_FOR_ACK);
 		_debug("done");
 	}
 	/* get the page holding the next free entry */

Index: cachefs-int.h
===================================================================
RCS file: /home/cvs/afs/fs/cachefs/cachefs-int.h,v
retrieving revision 1.35
retrieving revision 1.36
diff -u -r1.35 -r1.36
--- cachefs-int.h	3 Jun 2003 17:45:27 -0000	1.35
+++ cachefs-int.h	11 Jun 2003 11:59:52 -0000	1.36
@@ -71,12 +71,12 @@
 	struct inode			*imisc;		/* an inode covering the whole blkdev */
 
 	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
+#define CACHEFS_SUPER_INIT_BLKDEV	0		/* T if initialising blockdev */
+#define CACHEFS_SUPER_BATCH_TIMER	1		/* T if batch timer expired */
+#define CACHEFS_SUPER_DO_RECLAIM	2		/* T if should do reclamation */
+#define CACHEFS_SUPER_RCM_IMM_SCAN	3		/* T if should scan for immediately
 							 * reclaimable inodes */
-#define CACHEFS_SUPER_WITHDRAWN		4		/* true if cache has been withdrawn */
+#define CACHEFS_SUPER_WITHDRAWN		4		/* T if cache has been withdrawn */
 
 	/* index management */
 	struct list_head		ino_list;	/* list of data/index inodes */
@@ -145,6 +145,7 @@
 	struct list_head		ujnl_ackwq;	/* marks awaiting on-disc ACK */
 
 	struct semaphore		batch_sem;	/* batching mutex */
+	struct semaphore		batch_uj_sem;	/* ujnl written sync mutex */
 	struct rw_semaphore		batch_ctrl_sem;	/* marking/batching interleave control */
 	spinlock_t			batch_qlock;
 	struct list_head		batch_writeq;	/* blocks awaiting writing */
@@ -230,9 +231,10 @@
 #define CACHEFS_BLOCK_ERROR	4	/* [bit] block has disc error */
 #define CACHEFS_BLOCK_UJOURNAL	5	/* [bit] block holds update journal entries */
 #define CACHEFS_BLOCK_CRITICAL	6	/* [bit] block holds critical data that mustn't be
-					 *       zapped until sync'd */
+					 *       zapped until u-journal sync'd */
 #define CACHEFS_BLOCK_WITHDRAWN	7	/* [bit] backing cache withdrawn from service */
-#define CACHEFS_BLOCK_NETFSBUSY	8	/* [bit] netfs is accessing the block */
+#define CACHEFS_BLOCK_NETFSDATA	8	/* [bit] netfs data block (discard metadata) */
+#define CACHEFS_BLOCK_NETFSBUSY	9	/* [bit] netfs is accessing the block */
 
 #define _CACHEFS_BLOCK_ALLOC		(1 << CACHEFS_BLOCK_ALLOC)
 #define _CACHEFS_BLOCK_COW		(1 << CACHEFS_BLOCK_COW)
@@ -595,7 +597,14 @@
 extern void cachefs_trans_cancel(struct cachefs_transaction *trans);
 extern void cachefs_trans_batch_write(struct cachefs_super *super);
 extern void cachefs_trans_batch_timer(unsigned long data);
-extern void cachefs_trans_sync(struct cachefs_super *super, int wait);
+
+typedef enum {
+	CACHEFS_TRANS_SYNC_NOWAIT,		/* don't wait - just begin write */
+	CACHEFS_TRANS_SYNC_WAIT_FOR_MARK,	/* wait until ujnl BATCH mark is written */
+	CACHEFS_TRANS_SYNC_WAIT_FOR_ACK,	/* wait until ujnl ACK mark is written */
+} cachefs_trans_syncwt_t;
+
+extern void cachefs_trans_sync(struct cachefs_super *super, cachefs_trans_syncwt_t 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.36
retrieving revision 1.37
diff -u -r1.36 -r1.37
--- aops.c	10 Jun 2003 17:49:49 -0000	1.36
+++ aops.c	11 Jun 2003 11:59:52 -0000	1.37
@@ -39,8 +39,7 @@
 #define CACHEFS_BLOCK_WRITTEN		0x00000004
 #define CACHEFS_BLOCK_INIT_INDIRECT	0x00000008
 #define CACHEFS_BLOCK_INIT_INDEX	0x00000010
-#define CACHEFS_BLOCK_INIT_DATA		0x00000020
-#define CACHEFS_BLOCK_NEED_SYNC		0x00000040
+#define CACHEFS_BLOCK_INIT_NETFSDATA	0x00000020
 
 	/* ujournal marks for allocation journalling entries */
 	enum cachefs_ondisc_ujnl_mark	mktype : 8;
@@ -921,7 +920,7 @@
 	}
 
 	/* freshly allocated data blocks must be recorded in the v-journal */
-	if (step->flags & CACHEFS_BLOCK_INIT_DATA) {
+	if (step->flags & CACHEFS_BLOCK_INIT_NETFSDATA) {
 		_debug("init data");
 
 		ret = cachefs_vj_alloc(step->transaction,inode);
@@ -1035,7 +1034,8 @@
 	if (cachefs_trans_mark(step->transaction)<0)
 		goto error_block;
 
-	if (step->flags & CACHEFS_BLOCK_INIT_DATA) {
+	if (step->flags & CACHEFS_BLOCK_INIT_NETFSDATA) {
+		set_bit(CACHEFS_BLOCK_NETFSDATA,&block->flags);
 		block->vjentry = step->transaction->vjentry;
 		block->vjentry->bix = block->bix;
 	}
@@ -1101,12 +1101,15 @@
 	cachefs_trans_commit(step->transaction);
 	step->transaction = NULL;
 
-	/* synchronise after committing (so our allocation will be sync'd before block reuse) */
-	if ((step->flags & CACHEFS_BLOCK_NEED_SYNC) &&
+	/* the allocation must be journalled before journalling-independent
+	 * writes are permitted to modify a reused metadata block that had
+	 * critical data on it
+	 */
+	if ((step->flags & CACHEFS_BLOCK_INIT_NETFSDATA) &&
 	    test_bit(CACHEFS_BLOCK_CRITICAL,&block->flags)
 	    ) {
-		cachefs_trans_sync(super,0);
-		// TODO: wait for CRITICAL to be unset
+		cachefs_trans_sync(super,CACHEFS_TRANS_SYNC_WAIT_FOR_MARK);
+		clear_bit(CACHEFS_BLOCK_CRITICAL,&block->flags);
 	}
 
 	cachefs_block_put(block);
@@ -1167,7 +1170,7 @@
 	path[2].mktype	= CACHEFS_ONDISC_UJNL_INDIRECT_ALLOCING;
 	path[1].mktype	= CACHEFS_ONDISC_UJNL_INDIRECT_ALLOCING;
 	path[0].mktype	= CACHEFS_ONDISC_UJNL_DATA_ALLOCING;
-	path[0].flags	= CACHEFS_BLOCK_INIT_DATA;
+	path[0].flags	= CACHEFS_BLOCK_INIT_NETFSDATA;
 
 	if (inode->index_esize) {
 		path[0].mktype	= CACHEFS_ONDISC_UJNL_INDEX_EXTENDING;
@@ -1343,6 +1346,9 @@
 			cachefs_block_put(block);
 		_leave(" = %d",ret);
 		return ret;
+	}
+	else if (path[0].flags & CACHEFS_BLOCK_INIT_NETFSDATA) {
+		set_bit(CACHEFS_BLOCK_NETFSDATA,&pageio->mapped_block->flags);
 	}
 
 	/* got the block - set the block offset in the page mapping record */