[Ocfs2-commits] zab commits r2603 - in branches/locking-changes: . fs/configfs fs/ocfs2 fs/ocfs2/cluster fs/ocfs2/dlm vendor/redhat

svn-commits at oss.oracle.com svn-commits at oss.oracle.com
Thu Sep 22 12:40:13 CDT 2005


Author: zab
Date: 2005-09-22 12:39:57 -0500 (Thu, 22 Sep 2005)
New Revision: 2603

Added:
   branches/locking-changes/fs/ocfs2/export.c
   branches/locking-changes/fs/ocfs2/export.h
Modified:
   branches/locking-changes/Config.make.in
   branches/locking-changes/README
   branches/locking-changes/configure.in
   branches/locking-changes/fs/configfs/Makefile
   branches/locking-changes/fs/configfs/symlink.c
   branches/locking-changes/fs/ocfs2/Makefile
   branches/locking-changes/fs/ocfs2/alloc.c
   branches/locking-changes/fs/ocfs2/buffer_head_io.c
   branches/locking-changes/fs/ocfs2/buffer_head_io.h
   branches/locking-changes/fs/ocfs2/cluster/heartbeat.c
   branches/locking-changes/fs/ocfs2/cluster/masklog.c
   branches/locking-changes/fs/ocfs2/cluster/masklog.h
   branches/locking-changes/fs/ocfs2/cluster/ocfs2_nodemanager.h
   branches/locking-changes/fs/ocfs2/cluster/tcp.c
   branches/locking-changes/fs/ocfs2/cluster/tcp_internal.h
   branches/locking-changes/fs/ocfs2/dir.c
   branches/locking-changes/fs/ocfs2/dlm/dlmmaster.c
   branches/locking-changes/fs/ocfs2/dlmglue.c
   branches/locking-changes/fs/ocfs2/dlmglue.h
   branches/locking-changes/fs/ocfs2/extent_map.c
   branches/locking-changes/fs/ocfs2/file.c
   branches/locking-changes/fs/ocfs2/inode.c
   branches/locking-changes/fs/ocfs2/journal.c
   branches/locking-changes/fs/ocfs2/journal.h
   branches/locking-changes/fs/ocfs2/localalloc.c
   branches/locking-changes/fs/ocfs2/namei.c
   branches/locking-changes/fs/ocfs2/ocfs2.h
   branches/locking-changes/fs/ocfs2/ocfs2_fs.h
   branches/locking-changes/fs/ocfs2/slot_map.c
   branches/locking-changes/fs/ocfs2/suballoc.c
   branches/locking-changes/fs/ocfs2/super.c
   branches/locking-changes/fs/ocfs2/super.h
   branches/locking-changes/fs/ocfs2/symlink.c
   branches/locking-changes/fs/ocfs2/sysfile.c
   branches/locking-changes/fs/ocfs2/vote.c
   branches/locking-changes/vendor/redhat/ocfs2-2.6.9-EL.spec-generic.in
Log:
o merge revs 2543:2601 from trunk into locking-changes



Modified: branches/locking-changes/Config.make.in
===================================================================
--- branches/locking-changes/Config.make.in	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/Config.make.in	2005-09-22 17:39:57 UTC (rev 2603)
@@ -57,6 +57,7 @@
 INET_SK_RETURNS_INET_OPT = @INET_SK_RETURNS_INET_OPT@
 HAVE_SPARSE_ENDIAN_TYPES = @HAVE_SPARSE_ENDIAN_TYPES@
 HAVE_GENERIC_READLINK = @HAVE_GENERIC_READLINK@
+NEW_FOLLOW_LINK_API = @NEW_FOLLOW_LINK_API@
 
 OCFS_DEBUG = @OCFS_DEBUG@
 

Modified: branches/locking-changes/README
===================================================================
--- branches/locking-changes/README	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/README	2005-09-22 17:39:57 UTC (rev 2603)
@@ -48,3 +48,5 @@
 
 barrier=1		This enables/disables barriers. barrier=0 disables it,
 			barrier=1 enables it.
+errors=remount-ro(*)	Remount the filesystem read-only on an error.
+errors=panic		Panic and halt the machine if an error occurs.

Modified: branches/locking-changes/configure.in
===================================================================
--- branches/locking-changes/configure.in	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/configure.in	2005-09-22 17:39:57 UTC (rev 2603)
@@ -9,8 +9,8 @@
 # Adjust these for the software version.
 MAJOR_VERSION=1
 MINOR_VERSION=1
-MICRO_VERSION=1
-EXTRA_VERSION=ALPHA
+MICRO_VERSION=4
+EXTRA_VERSION=
 
 # Adjust this only to bump the RPM packaging version
 RPM_VERSION=1
@@ -19,7 +19,11 @@
 TOOLS_REQUIRED_VERSION=1.1.1
 
 DIST_VERSION=$MAJOR_VERSION.$MINOR_VERSION.$MICRO_VERSION
-VERSION=$DIST_VERSION-$EXTRA_VERSION
+if test -z "$EXTRA_VERSION"; then
+    VERSION=$DIST_VERSION
+else
+    VERSION=$DIST_VERSION-$EXTRA_VERSION
+fi
 
 AC_SUBST(MAJOR_VERSION)
 AC_SUBST(MINOR_VERSION)
@@ -258,6 +262,11 @@
   HAVE_GENERIC_READLINK=yes, , [generic_readlink(])
 AC_SUBST(HAVE_GENERIC_READLINK)
 
+NEW_FOLLOW_LINK_API=
+OCFS2_CHECK_KERNEL([for follow_link inode operation returning void *], fs.h,
+  NEW_FOLLOW_LINK_API=yes, , [void \* (\*follow_link)])
+AC_SUBST(NEW_FOLLOW_LINK_API)
+
 # using -include has two advantages:
 #  the source doesn't need to know to include compat headers
 #  the compat header file names don't go through the search path

Modified: branches/locking-changes/fs/configfs/Makefile
===================================================================
--- branches/locking-changes/fs/configfs/Makefile	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/configfs/Makefile	2005-09-22 17:39:57 UTC (rev 2603)
@@ -21,6 +21,10 @@
 EXTRA_CFLAGS += -DHAVE_GENERIC_READLINK
 endif
 
+ifdef NEW_FOLLOW_LINK_API
+EXTRA_CFLAGS += -DNEW_FOLLOW_LINK_API
+endif
+
 INSTALL_MOD_DIR := fs/configfs
 
 obj-m		:= configfs.o configfs_example.o bobtest.o

Modified: branches/locking-changes/fs/configfs/symlink.c
===================================================================
--- branches/locking-changes/fs/configfs/symlink.c	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/configfs/symlink.c	2005-09-22 17:39:57 UTC (rev 2603)
@@ -281,13 +281,13 @@
 
 	return error;
 }
-#else
+#elif !defined(NEW_FOLLOW_LINK_API)
 static int configfs_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	int error = -ENOMEM;
 	unsigned long page = get_zeroed_page(GFP_KERNEL);
 	if (page)
-		error = configfs_getlink(dentry, (char *) page);
+		error = configfs_getlink(dentry, (char *)page);
 	nd_set_link(nd, error ? ERR_PTR(error) : (char *)page);
 	return 0;
 }
@@ -298,6 +298,32 @@
 	if (!IS_ERR(page))
 		free_page((unsigned long)page);
 }
+#else
+static void *configfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+	int error = -ENOMEM;
+	unsigned long page = get_zeroed_page(GFP_KERNEL);
+
+	if (page) {
+		error = configfs_getlink(dentry, (char *)page);
+		if (!error) {
+			nd_set_link(nd, (char *)page);
+			return (void *)page;
+		}
+	}
+
+	nd_set_link(nd, ERR_PTR(error));
+	return NULL;
+}
+
+static void configfs_put_link(struct dentry *dentry, struct nameidata *nd,
+			      void *cookie)
+{
+	if (cookie) {
+		unsigned long page = (unsigned long)cookie;
+		free_page(page);
+	}
+}
 #endif
 
 struct inode_operations configfs_symlink_inode_operations = {

Modified: branches/locking-changes/fs/ocfs2/Makefile
===================================================================
--- branches/locking-changes/fs/ocfs2/Makefile	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/Makefile	2005-09-22 17:39:57 UTC (rev 2603)
@@ -26,6 +26,10 @@
 EXTRA_CFLAGS += -DJOURNAL_ACCESS_WITH_CREDITS
 endif
 
+ifdef NEW_FOLLOW_LINK_API
+EXTRA_CFLAGS += -DNEW_FOLLOW_LINK_API
+endif
+
 EXTRA_CFLAGS += -DOCFS2_DELETE_INODE_WORKAROUND
 EXTRA_CFLAGS += -DOCFS2_CDSL
 
@@ -42,6 +46,7 @@
 	dcache.c 		\
 	dir.c 			\
 	dlmglue.c 		\
+	export.c		\
 	extent_map.c 		\
 	file.c 			\
 	heartbeat.c 		\
@@ -72,6 +77,7 @@
 	dir.h			\
 	dlmglue.h		\
 	endian.h		\
+	export.h		\
 	extent_map.h		\
 	file.h			\
 	heartbeat.h		\

Modified: branches/locking-changes/fs/ocfs2/alloc.c
===================================================================
--- branches/locking-changes/fs/ocfs2/alloc.c	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/alloc.c	2005-09-22 17:39:57 UTC (rev 2603)
@@ -115,7 +115,11 @@
 
 	mlog_entry_void();
 
-	OCFS2_BUG_ON_INVALID_DINODE(fe);
+	if (!OCFS2_IS_VALID_DINODE(fe)) {
+		OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, fe);
+		retval = -EIO;
+		goto bail;
+	}
 
 	if (fe->i_last_eb_blk) {
 		retval = ocfs2_read_block(osb, le64_to_cpu(fe->i_last_eb_blk),
@@ -307,7 +311,11 @@
 	for(i = 0; i < new_blocks; i++) {
 		bh = new_eb_bhs[i];
 		eb = (ocfs2_extent_block *) bh->b_data;
-		OCFS2_BUG_ON_INVALID_EXTENT_BLOCK(eb);
+		if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+			OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
+			status = -EIO;
+			goto bail;
+		}
 		eb_el = &eb->h_list;
 
 		status = ocfs2_journal_access(handle, inode, bh,
@@ -431,7 +439,12 @@
 	}
 
 	eb = (ocfs2_extent_block *) new_eb_bh->b_data;
-	OCFS2_BUG_ON_INVALID_EXTENT_BLOCK(eb);
+	if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+		OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
+		status = -EIO;
+		goto bail;
+	}
+
 	eb_el = &eb->h_list;
 	fe = (ocfs2_dinode *) fe_bh->b_data;
 	fe_el = &fe->id2.i_list;
@@ -549,7 +562,14 @@
 		i = 0;
 		while(el->l_tree_depth) {
 			next_free = le16_to_cpu(el->l_next_free_rec);
-			OCFS2_BUG_ON_RO(next_free == 0);
+			if (next_free == 0) {
+				ocfs2_error(inode->i_sb,
+					    "Dinode %"MLFu64" has a bad "
+					    "extent list",
+					    OCFS2_I(inode)->ip_blkno);
+				status = -EIO;
+				goto bail;
+			}
 			next_blkno = le64_to_cpu(el->l_recs[next_free - 1].e_blkno);
 
 			BUG_ON(i >= num_bhs);
@@ -560,7 +580,12 @@
 				goto bail;
 			}
 			eb = (ocfs2_extent_block *) eb_bhs[i]->b_data;
-			OCFS2_BUG_ON_INVALID_EXTENT_BLOCK(eb);
+			if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+				OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb,
+								 eb);
+				status = -EIO;
+				goto bail;
+			}
 
 			status = ocfs2_journal_access(handle, inode, eb_bhs[i],
 						      OCFS2_JOURNAL_ACCESS_WRITE);
@@ -582,7 +607,14 @@
 		 * bottom-most leaf in order to update it with the
 		 * actual extent data below. */
 		next_free = le16_to_cpu(el->l_next_free_rec);
-		OCFS2_BUG_ON_RO(next_free == 0);
+		if (next_free == 0) {
+			ocfs2_error(inode->i_sb,
+				    "Dinode %"MLFu64" has a bad "
+				    "extent list",
+				    OCFS2_I(inode)->ip_blkno);
+			status = -EIO;
+			goto bail;
+		}
 		le32_add_cpu(&el->l_recs[next_free - 1].e_clusters,
 			     new_clusters);
 		/* (num_bhs - 1) to avoid the leaf */
@@ -616,7 +648,15 @@
 	} else if (le16_to_cpu(el->l_next_free_rec) &&
 		   (le32_to_cpu(el->l_recs[i].e_clusters) == 0)) {
 		/* having an empty extent at eof is legal. */
-		OCFS2_BUG_ON_RO(el->l_recs[i].e_cpos != fe->i_clusters);
+		if (el->l_recs[i].e_cpos != fe->i_clusters) {
+			ocfs2_error(inode->i_sb,
+				    "Dinode %"MLFu64" trailing extent is bad: "
+				    "cpos (%u) != number of clusters (%u)",
+				    le32_to_cpu(el->l_recs[i].e_cpos),
+				    le32_to_cpu(fe->i_clusters));
+			status = -EIO;
+			goto bail;
+		}
 		el->l_recs[i].e_blkno = cpu_to_le64(start_blk);
 		el->l_recs[i].e_clusters = cpu_to_le32(new_clusters);
 	} else {
@@ -704,10 +744,23 @@
 	el = &fe->id2.i_list;
 
 	while(le16_to_cpu(el->l_tree_depth) > 1) {
-		OCFS2_BUG_ON_RO(le16_to_cpu(el->l_next_free_rec) == 0);
+		if (le16_to_cpu(el->l_next_free_rec) == 0) {
+			ocfs2_error(inode->i_sb, "Dinode %"MLFu64" has empty "
+				    "extent list (next_free_rec == 0)",
+				    OCFS2_I(inode)->ip_blkno);
+			status = -EIO;
+			goto bail;
+		}
 		i = le16_to_cpu(el->l_next_free_rec) - 1;
 		blkno = le64_to_cpu(el->l_recs[i].e_blkno);
-		OCFS2_BUG_ON_RO(!blkno);
+		if (!blkno) {
+			ocfs2_error(inode->i_sb, "Dinode %"MLFu64" has extent "
+				    "list where extent # %d has no physical "
+				    "block start",
+				    OCFS2_I(inode)->ip_blkno, i);
+			status = -EIO;
+			goto bail;
+		}
 
 		if (bh) {
 			brelse(bh);
@@ -722,7 +775,11 @@
 		}
 
 		eb = (ocfs2_extent_block *) bh->b_data;
-		OCFS2_BUG_ON_INVALID_EXTENT_BLOCK(eb);
+		if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+			OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
+			status = -EIO;
+			goto bail;
+		}
 		el = &eb->h_list;
 
 		if (le16_to_cpu(el->l_next_free_rec) <
@@ -913,7 +970,12 @@
 
 	di = (ocfs2_dinode *) tl_bh->b_data;
 	tl = &di->id2.i_dealloc;
-	OCFS2_BUG_ON_INVALID_DINODE(di);
+	if (!OCFS2_IS_VALID_DINODE(di)) {
+		OCFS2_RO_ON_INVALID_DINODE(osb->sb, di);
+		status = -EIO;
+		goto bail;
+	}
+
 	tl_count = le16_to_cpu(tl->tl_count);
 	mlog_bug_on_msg(tl_count > ocfs2_truncate_recs_per_inode(osb->sb) ||
 			tl_count == 0,
@@ -1063,7 +1125,11 @@
 
 	di = (ocfs2_dinode *) tl_bh->b_data;
 	tl = &di->id2.i_dealloc;
-	OCFS2_BUG_ON_INVALID_DINODE(di);
+	if (!OCFS2_IS_VALID_DINODE(di)) {
+		OCFS2_RO_ON_INVALID_DINODE(osb->sb, di);
+		status = -EIO;
+		goto bail;
+	}
 
 	num_to_flush = le16_to_cpu(tl->tl_used);
 	mlog(0, "Flush %u records from truncate log #%"MLFu64"\n",
@@ -1097,8 +1163,9 @@
 	}
 
 	handle = ocfs2_start_trans(osb, handle, OCFS2_TRUNCATE_LOG_UPDATE);
-	if (!handle) {
-		status = -ENOMEM;
+	if (IS_ERR(handle)) {
+		status = PTR_ERR(handle);
+		handle = NULL;
 		mlog_errno(status);
 		goto bail;
 	}
@@ -1224,7 +1291,11 @@
 
 	di = (ocfs2_dinode *) tl_bh->b_data;
 	tl = &di->id2.i_dealloc;
-	OCFS2_BUG_ON_INVALID_DINODE(di);
+	if (!OCFS2_IS_VALID_DINODE(di)) {
+		OCFS2_RO_ON_INVALID_DINODE(tl_inode->i_sb, di);
+		status = -EIO;
+		goto bail;
+	}
 
 	if (le16_to_cpu(tl->tl_used)) {
 		mlog(0, "We'll have %u logs to recover\n",
@@ -1302,8 +1373,8 @@
 
 		handle = ocfs2_start_trans(osb, NULL,
 					   OCFS2_TRUNCATE_LOG_UPDATE);
-		if (!handle) {
-			status = -ENOMEM;
+		if (IS_ERR(handle)) {
+			status = PTR_ERR(handle);
 			mlog_errno(status);
 			goto bail_up;
 		}
@@ -1393,10 +1464,14 @@
 	ocfs2_extent_list *el;
 	struct buffer_head *bh = NULL;
 
-	OCFS2_BUG_ON_INVALID_DINODE(fe);
-
 	*new_last_eb = NULL;
 
+	if (!OCFS2_IS_VALID_DINODE(fe)) {
+		OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, fe);
+		status = -EIO;
+		goto bail;
+	}
+
 	/* we have no tree, so of course, no last_eb. */
 	if (!fe->id2.i_list.l_tree_depth)
 		goto bail;
@@ -1443,7 +1518,11 @@
 		}
 		eb = (ocfs2_extent_block *) bh->b_data;
 		el = &eb->h_list;
-		OCFS2_BUG_ON_INVALID_EXTENT_BLOCK(eb);
+		if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+			OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
+			status = -EIO;
+			goto bail;
+		}
 	} while (el->l_tree_depth);
 
 	*new_last_eb = bh;
@@ -1574,7 +1653,11 @@
 			goto bail;
 		}
 		eb = (ocfs2_extent_block *)eb_bh->b_data;
-		OCFS2_BUG_ON_INVALID_EXTENT_BLOCK(eb);
+		if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+			OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
+			status = -EIO;
+			goto bail;
+		}
 		el = &(eb->h_list);
 
 		status = ocfs2_journal_access(handle, inode, eb_bh,
@@ -1738,7 +1821,11 @@
 			goto bail;
 		}
 		eb = (ocfs2_extent_block *) last_eb_bh->b_data;
-		OCFS2_BUG_ON_INVALID_EXTENT_BLOCK(eb);
+		if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+			OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
+			status = -EIO;
+			goto bail;
+		}
 		el = &(eb->h_list);
 	}
 
@@ -1770,20 +1857,13 @@
 	credits = ocfs2_calc_tree_trunc_credits(osb->sb, clusters_to_del,
 						fe, el);
 	handle = ocfs2_start_trans(osb, NULL, credits);
-	if (!handle) {
-		status = -ENOMEM;
+	if (IS_ERR(handle)) {
+		status = PTR_ERR(handle);
+		handle = NULL;
 		mlog_errno(status);
 		goto bail;
 	}
 
-	/* None of the cluster locks for a truncate are added
-	 * to the handle, so we update the last transaction
-	 * info manually. */
-	if (tc->tc_ext_alloc_inode)
-		ocfs2_set_inode_lock_trans(osb->journal,
-					   tc->tc_ext_alloc_inode);
-	ocfs2_set_inode_lock_trans(osb->journal, inode);
-
 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 	status = ocfs2_mark_inode_dirty(handle, inode, fe_bh);
 	if (status < 0)
@@ -1857,7 +1937,20 @@
 	mlog(0, "fe->i_clusters = %u, new_i_clusters = %u, fe->i_size ="
 	     "%"MLFu64"\n", fe->i_clusters, new_i_clusters, fe->i_size);
 
-	BUG_ON(le32_to_cpu(fe->i_clusters) <= new_i_clusters);
+	if (le32_to_cpu(fe->i_clusters) <= new_i_clusters) {
+		ocfs2_error(inode->i_sb, "Dinode %"MLFu64" has cluster count "
+			    "%u and size %"MLFu64" whereas struct inode has "
+			    "cluster count %u and size %llu which caused an "
+			    "invalid truncate to %u clusters.",
+			    le64_to_cpu(fe->i_blkno),
+			    le32_to_cpu(fe->i_clusters),
+			    le64_to_cpu(fe->i_size),
+			    OCFS2_I(inode)->ip_clusters, i_size_read(inode),
+			    new_i_clusters);
+		mlog_meta_lvb(ML_ERROR, &OCFS2_I(inode)->ip_meta_lockres);
+		status = -EIO;
+		goto bail;
+	}
 
 	*tc = kcalloc(1, sizeof(struct ocfs2_truncate_context), GFP_KERNEL);
 	if (!(*tc)) {
@@ -1878,7 +1971,13 @@
 			goto bail;
 		}
 		eb = (ocfs2_extent_block *) last_eb_bh->b_data;
-		OCFS2_BUG_ON_INVALID_EXTENT_BLOCK(eb);
+		if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+			OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
+
+			brelse(last_eb_bh);
+			status = -EIO;
+			goto bail;
+		}
 		el = &(eb->h_list);
 		if (le32_to_cpu(el->l_recs[0].e_cpos) >= new_i_clusters)
 			metadata_delete = 1;

Modified: branches/locking-changes/fs/ocfs2/buffer_head_io.c
===================================================================
--- branches/locking-changes/fs/ocfs2/buffer_head_io.c	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/buffer_head_io.c	2005-09-22 17:39:57 UTC (rev 2603)
@@ -39,104 +39,53 @@
 
 #include "buffer_head_io.h"
 
-void ocfs2_end_buffer_io_sync(struct buffer_head *bh,
-			      int uptodate)
+int ocfs2_write_block(ocfs2_super *osb, struct buffer_head *bh,
+		      struct inode *inode)
 {
-	if (!uptodate)
-		mlog_errno(-EIO);
+	int ret = 0;
 
-	if (uptodate)
-		set_buffer_uptodate(bh);
-	else
-		clear_buffer_uptodate(bh);
-	unlock_buffer(bh);
-}
+	mlog_entry("(bh->b_blocknr = %llu, inode=%p)\n",
+		   (unsigned long long)bh->b_blocknr, inode);
 
-int ocfs2_write_blocks(ocfs2_super *osb, struct buffer_head *bhs[],
-		       int nr, struct inode *inode)
-{
-	int status = 0;
-	int i;
-	struct super_block *sb;
-	struct buffer_head *bh;
+	BUG_ON(bh->b_blocknr < OCFS2_SUPER_BLOCK_BLKNO);
+	BUG_ON(buffer_jbd(bh));
 
-	mlog_entry("(bh[0]->b_blocknr = %llu, nr=%d, inode=%p)\n",
-		   (unsigned long long)bhs[0]->b_blocknr, nr, inode);
-
-	if (osb == NULL || osb->sb == NULL || bhs == NULL) {
-		status = -EINVAL;
-		mlog_errno(status);
-		goto bail;
+	/* No need to check for a soft readonly file system here. non
+	 * journalled writes are only ever done on system files which
+	 * can get modified during recovery even if read-only. */
+	if (ocfs2_is_hard_readonly(osb)) {
+		ret = -EROFS;
+		goto out;
 	}
 
-	sb = osb->sb;
+	down(&OCFS2_I(inode)->ip_io_sem);
 
-	if (inode)
-		down(&OCFS2_I(inode)->ip_io_sem);
-	for (i = 0 ; i < nr ; i++) {
-		bh = bhs[i];
-		if (bh == NULL) {
-			if (inode)
-				up(&OCFS2_I(inode)->ip_io_sem);
-			status = -EIO;
-			mlog_errno(status);
-			goto bail;
-		}
+	lock_buffer(bh);
+	set_buffer_uptodate(bh);
 
-		if (unlikely(bh->b_blocknr < OCFS2_SUPER_BLOCK_BLKNO)) {
-			BUG();
-			status = -EIO;
-			mlog_errno(status);
-			goto bail;
-		}
+	/* remove from dirty list before I/O. */
+	clear_buffer_dirty(bh);
 
-		if (unlikely(buffer_jbd(bh))) {
-			/* What are you thinking?! */
-			mlog(ML_ERROR, "trying to write a jbd managed bh "
-				       "(blocknr = %llu), nr=%d\n",
-			     (unsigned long long)bh->b_blocknr, nr);
-			BUG();
-		}
+	get_bh(bh); /* for end_buffer_write_sync() */                   
+	bh->b_end_io = end_buffer_write_sync;
+	submit_bh(WRITE, bh);
 
-		lock_buffer(bh);
+	wait_on_buffer(bh);
 
-		set_buffer_uptodate(bh);
-
-		/* remove from dirty list before I/O. */
-		clear_buffer_dirty(bh);
-
-		bh->b_end_io = ocfs2_end_buffer_io_sync;
-		submit_bh(WRITE, bh);
+	if (buffer_uptodate(bh)) {
+		ocfs2_set_buffer_uptodate(inode, bh);
+	} else {
+		/* We don't need to remove the clustered uptodate
+		 * information for this bh as it's not marked locally
+		 * uptodate. */
+		ret = -EIO;
+		brelse(bh);
 	}
 
-	for (i = (nr - 1) ; i >= 0; i--) {
-		bh = bhs[i];
-
-		wait_on_buffer(bh);
-
-		if (!buffer_uptodate(bh)) {
-			/* Status won't be cleared from here on out,
-			 * so we can safely record this and loop back
-			 * to cleanup the other buffers. Don't need to
-			 * remove the clustered uptodate information
-			 * for this bh as it's not marked locally
-			 * uptodate. */
-			status = -EIO;
-			brelse(bh);
-			bhs[i] = NULL;
-			continue;
-		}
-
-		if (inode)
-			ocfs2_set_buffer_uptodate(inode, bh);
-	}
-	if (inode)
-		up(&OCFS2_I(inode)->ip_io_sem);
-
-bail:
-
-	mlog_exit(status);
-	return status;
+	up(&OCFS2_I(inode)->ip_io_sem);
+out:
+	mlog_exit(ret);
+	return ret;
 }
 
 int ocfs2_read_blocks(ocfs2_super *osb, u64 block, int nr,
@@ -233,7 +182,8 @@
 #endif
 			}
 			clear_buffer_uptodate(bh);
-			bh->b_end_io = ocfs2_end_buffer_io_sync;
+			get_bh(bh); /* for end_buffer_read_sync() */
+			bh->b_end_io = end_buffer_read_sync;
 			if (flags & OCFS2_BH_READAHEAD)
 				submit_bh(READA, bh);
 			else

Modified: branches/locking-changes/fs/ocfs2/buffer_head_io.h
===================================================================
--- branches/locking-changes/fs/ocfs2/buffer_head_io.h	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/buffer_head_io.h	2005-09-22 17:39:57 UTC (rev 2603)
@@ -31,20 +31,15 @@
 void ocfs2_end_buffer_io_sync(struct buffer_head *bh,
 			     int uptodate);
 
-/* Yosh made me do it. */
-static inline int ocfs2_write_block(ocfs2_super         *osb,
-				    struct buffer_head  *bh,
-				    struct inode        *inode);
 static inline int ocfs2_read_block(ocfs2_super          *osb,
 				   u64                  off,
 				   struct buffer_head **bh,
 				   int                  flags,
 				   struct inode        *inode);
 
-int ocfs2_write_blocks(ocfs2_super          *osb,
-		       struct buffer_head  *bh[],
-		       int                  nr,
-		       struct inode        *inode);
+int ocfs2_write_block(ocfs2_super          *osb,
+		      struct buffer_head  *bh,
+		      struct inode        *inode);
 int ocfs2_read_blocks(ocfs2_super          *osb,
 		      u64                  block,
 		      int                  nr,
@@ -56,16 +51,6 @@
 #define OCFS2_BH_CACHED            1
 #define OCFS2_BH_READAHEAD         8	/* use this to pass READA down to submit_bh */
 
-static inline int ocfs2_write_block(ocfs2_super * osb, struct buffer_head *bh,
-				    struct inode *inode)
-{
-	int status;
-
-	status = ocfs2_write_blocks(osb, &bh, 1, inode);
-
-	return status;
-}
-
 static inline int ocfs2_read_block(ocfs2_super * osb, u64 off,
 				   struct buffer_head **bh, int flags,
 				   struct inode *inode)

Modified: branches/locking-changes/fs/ocfs2/cluster/heartbeat.c
===================================================================
--- branches/locking-changes/fs/ocfs2/cluster/heartbeat.c	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/cluster/heartbeat.c	2005-09-22 17:39:57 UTC (rev 2603)
@@ -97,7 +97,7 @@
 struct o2hb_disk_slot {
 	struct o2hb_disk_heartbeat_block *ds_raw_block;
 	u8			ds_node_num;
-	unsigned long		ds_last_time;
+	u64			ds_last_time;
 	u64			ds_last_generation;
 	u16			ds_equal_samples;
 	u16			ds_changed_samples;
@@ -244,7 +244,11 @@
 
 	nr_vecs = (num_slots + spp - 1) / spp;
 
-	bio = bio_alloc(GFP_KERNEL, nr_vecs);
+	/* Testing has shown this allocation to take long enough under
+	 * GFP_KERNEL that the local node can get fenced. It would be
+	 * nicest if we could pre-allocate these bios and avoid this
+	 * all together. */
+	bio = bio_alloc(GFP_ATOMIC, nr_vecs);
 	if (!bio) {
 		mlog(ML_ERROR, "Could not alloc slots BIO!\n");
 		bio = ERR_PTR(-ENOMEM);
@@ -692,10 +696,11 @@
 
 	slot->ds_last_generation = le64_to_cpu(hb_block->hb_generation);
 
-	mlog(ML_HEARTBEAT, "Slot %d has generation 0x%"MLFx64", cksum 0x%x "
-	     "changed samples %u, equal samples %u\n",
+	mlog(ML_HEARTBEAT, "Slot %d gen 0x%"MLFx64" cksum 0x%x "
+	     "seq %"MLFu64" last %"MLFu64" changed %u equal %u\n",
 	     slot->ds_node_num, slot->ds_last_generation,
-	     le32_to_cpu(hb_block->hb_cksum), slot->ds_changed_samples,
+	     le32_to_cpu(hb_block->hb_cksum), le64_to_cpu(hb_block->hb_seq), 
+	     slot->ds_last_time, slot->ds_changed_samples,
 	     slot->ds_equal_samples);
 
 	spin_lock(&o2hb_live_lock);

Modified: branches/locking-changes/fs/ocfs2/cluster/masklog.c
===================================================================
--- branches/locking-changes/fs/ocfs2/cluster/masklog.c	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/cluster/masklog.c	2005-09-22 17:39:57 UTC (rev 2603)
@@ -211,6 +211,7 @@
 	set_a_string(DCACHE);
 	set_a_string(CONN);
 	set_a_string(QUORUM);
+	set_a_string(EXPORT);
 	set_a_string(ERROR);
 	set_a_string(NOTICE);
 	set_a_string(KTHREAD);

Modified: branches/locking-changes/fs/ocfs2/cluster/masklog.h
===================================================================
--- branches/locking-changes/fs/ocfs2/cluster/masklog.h	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/cluster/masklog.h	2005-09-22 17:39:57 UTC (rev 2603)
@@ -111,6 +111,7 @@
 #define ML_DCACHE	0x0000000002000000ULL /* ocfs2 dcache operations */
 #define ML_CONN		0x0000000004000000ULL /* net connection management */
 #define ML_QUORUM	0x0000000008000000ULL /* net connection quorum */
+#define ML_EXPORT	0x0000000010000000ULL /* ocfs2 export operations */
 /* bits that are infrequently given and frequently matched in the high word */
 #define ML_ERROR	0x0000000100000000ULL /* sent to KERN_ERR */
 #define ML_NOTICE	0x0000000200000000ULL /* setn to KERN_NOTICE */

Modified: branches/locking-changes/fs/ocfs2/cluster/ocfs2_nodemanager.h
===================================================================
--- branches/locking-changes/fs/ocfs2/cluster/ocfs2_nodemanager.h	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/cluster/ocfs2_nodemanager.h	2005-09-22 17:39:57 UTC (rev 2603)
@@ -28,7 +28,7 @@
 #ifndef _OCFS2_NODEMANAGER_H
 #define _OCFS2_NODEMANAGER_H
 
-#define O2NM_API_VERSION	4
+#define O2NM_API_VERSION	5
 
 #define O2NM_MAX_NODES		255
 #define O2NM_INVALID_NODE_NUM	255

Modified: branches/locking-changes/fs/ocfs2/cluster/tcp.c
===================================================================
--- branches/locking-changes/fs/ocfs2/cluster/tcp.c	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/cluster/tcp.c	2005-09-22 17:39:57 UTC (rev 2603)
@@ -178,7 +178,7 @@
 	int ret = 0;
 
 	do {
-		if (!idr_pre_get(&nn->nn_status_idr, GFP_NOFS)) {
+		if (!idr_pre_get(&nn->nn_status_idr, GFP_ATOMIC)) {
 			ret = -EAGAIN;
 			break;
 		}
@@ -461,6 +461,7 @@
 	if (sk->sk_user_data) {
 		struct o2net_sock_container *sc = sk->sk_user_data;
 		sclog(sc, "data_ready hit\n");
+		do_gettimeofday(&sc->sc_tv_data_ready);
 		o2net_sc_queue_work(sc, &sc->sc_rx_work);
 		ready = sc->sc_data_ready;
 	} else {
@@ -686,7 +687,7 @@
 		goto out;
 	}
 
-       	nmh = kcalloc(1, sizeof(struct o2net_msg_handler), GFP_KERNEL);
+       	nmh = kcalloc(1, sizeof(struct o2net_msg_handler), GFP_NOFS);
 	if (nmh == NULL) {
 		ret = -ENOMEM;
 		goto out;
@@ -930,14 +931,14 @@
 	nst.st_sc = sc;
 
 	veclen = caller_veclen + 1;
-	vec = kmalloc(sizeof(struct kvec) * veclen, GFP_KERNEL);
+	vec = kmalloc(sizeof(struct kvec) * veclen, GFP_ATOMIC);
 	if (vec == NULL) {
 		mlog(0, "failed to %zu element kvec!\n", veclen);
 		ret = -ENOMEM;
 		goto out;
 	}
 
-	msg = kmalloc(sizeof(o2net_msg), GFP_KERNEL);
+	msg = kmalloc(sizeof(o2net_msg), GFP_ATOMIC);
 	if (!msg) {
 		mlog(0, "failed to allocate a o2net_msg!\n");
 		ret = -ENOMEM;
@@ -1083,9 +1084,13 @@
 	if (syserr != O2NET_ERR_NONE)
 		goto out_respond;
 
+	do_gettimeofday(&sc->sc_tv_func_start);
+	sc->sc_msg_key = be32_to_cpu(hdr->key);
+	sc->sc_msg_type = be16_to_cpu(hdr->msg_type);
 	handler_status = (nmh->nh_func)(hdr, sizeof(o2net_msg) +
 					     be16_to_cpu(hdr->data_len),
 					nmh->nh_func_data);
+	do_gettimeofday(&sc->sc_tv_func_stop);
 
 out_respond:
 	/* this destroys the hdr, so don't use it after this */
@@ -1148,6 +1153,7 @@
 	size_t datalen;
 
 	sclog(sc, "receiving\n");
+	do_gettimeofday(&sc->sc_tv_advance_start);
 
 	/* do we need more header? */
 	if (sc->sc_page_off < sizeof(o2net_msg)) {
@@ -1214,6 +1220,7 @@
 
 out:
 	sclog(sc, "ret = %d\n", ret);
+	do_gettimeofday(&sc->sc_tv_advance_stop);
 	return ret;
 }
 
@@ -1295,9 +1302,23 @@
 static void o2net_idle_timer(unsigned long data)
 {
 	struct o2net_sock_container *sc = (struct o2net_sock_container *)data;
+	struct timeval now;
 
+	do_gettimeofday(&now);
+
 	mlog(ML_NOTICE, "connection to " SC_NODEF_FMT " has been idle for 10 "
 	     "seconds, shutting it down.\n", SC_NODEF_ARGS(sc));
+	mlog(ML_NOTICE, "here are some times that might help debug the "
+	     "situation: (tmr %ld.%ld now %ld.%ld dr %ld.%ld adv "
+	     "%ld.%ld:%ld.%ld func (%08x:%u) %ld.%ld:%ld.%ld)\n",
+	     sc->sc_tv_timer.tv_sec, sc->sc_tv_timer.tv_usec, 
+	     now.tv_sec, now.tv_usec,
+	     sc->sc_tv_data_ready.tv_sec, sc->sc_tv_data_ready.tv_usec, 
+	     sc->sc_tv_advance_start.tv_sec, sc->sc_tv_advance_start.tv_usec, 
+	     sc->sc_tv_advance_stop.tv_sec, sc->sc_tv_advance_stop.tv_usec, 
+	     sc->sc_msg_key, sc->sc_msg_type,
+	     sc->sc_tv_func_start.tv_sec, sc->sc_tv_func_start.tv_usec,
+	     sc->sc_tv_func_stop.tv_sec, sc->sc_tv_func_stop.tv_usec);
 
 	o2net_sc_queue_work(sc, &sc->sc_shutdown_work);
 }
@@ -1307,6 +1328,7 @@
 	o2net_sc_cancel_delayed_work(sc, &sc->sc_keepalive_work);
 	o2net_sc_queue_delayed_work(sc, &sc->sc_keepalive_work,
 				    O2NET_KEEPALIVE_DELAY_SECS * HZ);
+	do_gettimeofday(&sc->sc_tv_timer);
 	mod_timer(&sc->sc_idle_timeout,
 		  jiffies + (O2NET_IDLE_TIMEOUT_SECS * HZ));
 }
@@ -1360,6 +1382,8 @@
 	}
 	sc->sc_sock = sock; /* freed by sc_kref_release */
 
+	sock->sk->sk_allocation = GFP_ATOMIC;
+
 	myaddr.sin_family = AF_INET;
 	myaddr.sin_port = (__force u16)htons(0); /* any port */
 
@@ -1563,6 +1587,8 @@
 	if (ret < 0)
 		goto out;
 
+	new_sock->sk->sk_allocation = GFP_ATOMIC;
+
 	ret = o2net_set_nodelay(new_sock);
 	if (ret) {
 		mlog(ML_ERROR, "setting TCP_NODELAY failed with %d\n", ret);
@@ -1696,6 +1722,8 @@
 		goto out;
 	}
 
+	sock->sk->sk_allocation = GFP_ATOMIC;
+
 	write_lock_bh(&sock->sk->sk_callback_lock);
 	sock->sk->sk_user_data = sock->sk->sk_data_ready;
 	sock->sk->sk_data_ready = o2net_listen_data_ready;

Modified: branches/locking-changes/fs/ocfs2/cluster/tcp_internal.h
===================================================================
--- branches/locking-changes/fs/ocfs2/cluster/tcp_internal.h	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/cluster/tcp_internal.h	2005-09-22 17:39:57 UTC (rev 2603)
@@ -127,6 +127,15 @@
 	void			(*sc_data_ready)(struct sock *sk, int bytes);
 
 	struct list_head	sc_net_proc_item;
+
+	struct timeval 		sc_tv_timer;
+	struct timeval 		sc_tv_data_ready;
+	struct timeval 		sc_tv_advance_start;
+	struct timeval 		sc_tv_advance_stop;
+	struct timeval 		sc_tv_func_start;
+	struct timeval 		sc_tv_func_stop;
+	u32			sc_msg_key;
+	u16			sc_msg_type;
 };
 
 struct o2net_msg_handler {

Modified: branches/locking-changes/fs/ocfs2/dir.c
===================================================================
--- branches/locking-changes/fs/ocfs2/dir.c	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/dir.c	2005-09-22 17:39:57 UTC (rev 2603)
@@ -451,8 +451,9 @@
 	}
 
 	handle = ocfs2_start_trans(osb, handle, credits);
-	if (handle == NULL) {
-		status = -ENOMEM;
+	if (IS_ERR(handle)) {
+		status = PTR_ERR(handle);
+		handle = NULL;
 		mlog_errno(status);
 		goto bail;
 	}

Modified: branches/locking-changes/fs/ocfs2/dlm/dlmmaster.c
===================================================================
--- branches/locking-changes/fs/ocfs2/dlm/dlmmaster.c	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/dlm/dlmmaster.c	2005-09-22 17:39:57 UTC (rev 2603)
@@ -753,7 +753,6 @@
 		dlm_init_mle(mle, DLM_MLE_MASTER, dlm, res, NULL, 0);
 		list_add(&mle->list, &dlm->master_list);
 	}
-	spin_unlock(&dlm->master_lock);
 
 	/* at this point there is either a DLM_MLE_BLOCK or a
 	 * DLM_MLE_MASTER on the master list, so it's safe to add the
@@ -762,6 +761,7 @@
 
 	/* finally add the lockres to its hash bucket */
 	__dlm_insert_lockres(dlm, res);
+	spin_unlock(&dlm->master_lock);
 	spin_unlock(&dlm->spinlock);
 
 	if (blocked) {
@@ -1888,7 +1888,9 @@
 	/* get an extra reference on the mle.
 	 * otherwise the assert_master from the new
 	 * master will destroy this. */
+	spin_lock(&dlm->master_lock);
 	dlm_get_mle(mle);
+	spin_unlock(&dlm->master_lock);
 
 	/* notify new node and send all lock state */
 	/* call send_one_lockres with migration flag.

Modified: branches/locking-changes/fs/ocfs2/dlmglue.c
===================================================================
--- branches/locking-changes/fs/ocfs2/dlmglue.c	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/dlmglue.c	2005-09-22 17:39:57 UTC (rev 2603)
@@ -49,6 +49,7 @@
 #include "inode.h"
 #include "journal.h"
 #include "slot_map.h"
+#include "super.h"
 #include "uptodate.h"
 #include "vote.h"
 
@@ -943,7 +944,7 @@
 {
 	struct ocfs2_mask_waiter mw;
 	enum dlm_status status;
-	int wait, catch_signals = 1;
+	int wait, catch_signals = !(osb->s_mount_opt & OCFS2_MOUNT_NOINTR);
 	int ret = 0; /* gcc doesn't realize wait = 1 guarantees ret is set */
 
 	mlog_entry_void();
@@ -1184,7 +1185,7 @@
 int ocfs2_data_lock(struct inode *inode,
 		    int write)
 {
-	int status, level;
+	int status = 0, level;
 	struct ocfs2_lock_res *lockres;
 
 	BUG_ON(!inode);
@@ -1195,6 +1196,16 @@
 	     OCFS2_I(inode)->ip_blkno,
 	     write ? "EXMODE" : "PRMODE");
 
+	/* We'll allow faking a readonly data lock for
+	 * rodevices. */
+	if (ocfs2_is_hard_readonly(OCFS2_SB(inode->i_sb))) {
+		if (write) {
+			status = -EROFS;
+			mlog_errno(status);
+		}
+		goto out;
+	}
+
 	lockres = &OCFS2_I(inode)->ip_data_lockres;
 
 	level = write ? LKM_EXMODE : LKM_PRMODE;
@@ -1203,6 +1214,7 @@
 	if (status < 0)
 		mlog_errno(status);
 
+out:
 	mlog_exit(status);
 	return status;
 }
@@ -1250,7 +1262,8 @@
 	     OCFS2_I(inode)->ip_blkno,
 	     write ? "EXMODE" : "PRMODE");
 
-	ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres, level);
+	if (!ocfs2_is_hard_readonly(OCFS2_SB(inode->i_sb)))
+		ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres, level);
 
 	mlog_exit_void();
 }
@@ -1306,6 +1319,8 @@
 	lvb->lvb_imtime_packed =
 		cpu_to_be64(ocfs2_pack_timespec(&inode->i_mtime));
 
+	mlog_meta_lvb(0, lockres);
+
 	mlog_exit_void();
 }
 
@@ -1325,21 +1340,10 @@
 
 	mlog_entry_void();
 
+	mlog_meta_lvb(0, lockres);
+
 	lvb = (struct ocfs2_meta_lvb *) lockres->l_lksb.lvb;
 
-	mlog(0, "seq %u, trunc clusters %u, iclusters %u\n",
-	     be32_to_cpu(lvb->lvb.lvb_seq),
-	     be32_to_cpu(lvb->lvb_trunc_clusters),
-	     be32_to_cpu(lvb->lvb_iclusters));
-	mlog(0, "uid %u, gid %u, isize offset %u, mode 0x%x\n",
-	     be32_to_cpu(lvb->lvb_iuid), be32_to_cpu(lvb->lvb_igid),
-	     be32_to_cpu(lvb->lvb_isize_off), be16_to_cpu(lvb->lvb_imode));
-	mlog(0, "nlink %u, atime_packed %"MLFu64", ctime_packed %"MLFx64", "
-	     "mtime_packed %"MLFx64"\n",
-	     be16_to_cpu(lvb->lvb_inlink), be64_to_cpu(lvb->lvb_iatime_packed),
-	     be64_to_cpu(lvb->lvb_ictime_packed),
-	     be64_to_cpu(lvb->lvb_imtime_packed));
-
 	/* We're safe here without the lockres lock... */
 	spin_lock(&oi->ip_lock);
 	oi->ip_clusters = be32_to_cpu(lvb->lvb_iclusters);
@@ -1528,7 +1532,11 @@
 		 * node provides a guarantee that we receive that
 		 * message and can mark the inode before dropping any
 		 * locks associated with it. */
-		OCFS2_BUG_ON_INVALID_DINODE(fe);
+		if (!OCFS2_IS_VALID_DINODE(fe)) {
+			OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, fe);
+			status = -EIO;
+			goto bail_refresh;
+		}
 		mlog_bug_on_msg(inode->i_generation !=
 				le32_to_cpu(fe->i_generation),
 				"Invalid dinode %"MLFu64" disk generation: %u "
@@ -1629,16 +1637,19 @@
 
 	status = 0;
 	acquired = 0;
+	/* We'll allow faking a readonly metadata lock for
+	 * rodevices. */
+	if (ocfs2_is_hard_readonly(osb)) {
+		if (ex)
+			status = -EROFS;
+		goto bail;
+	}
 
 	if (!(flags & OCFS2_META_LOCK_RECOVERY))
-		status = wait_event_interruptible(osb->recovery_event,
-						  ocfs2_node_map_is_empty(osb,
-									  &osb->recovery_map));
-	if (status < 0) {
-		mlog_errno(status);
-		return status;
-	}
+		wait_event(osb->recovery_event,
+			   ocfs2_node_map_is_empty(osb, &osb->recovery_map));
 
+	acquired = 0;
 	lockres = &OCFS2_I(inode)->ip_meta_lockres;
 	level = ex ? LKM_EXMODE : LKM_PRMODE;
 	dlm_flags = 0;
@@ -1661,8 +1672,7 @@
 	 * abort the operation. */
 	if (!(flags & OCFS2_META_LOCK_RECOVERY))
 		wait_event(osb->recovery_event,
-			   ocfs2_node_map_is_empty(osb,
-						   &osb->recovery_map));
+			   ocfs2_node_map_is_empty(osb, &osb->recovery_map));
 
 	/* This is fun. The caller may want a bh back, or it may
 	 * not. ocfs2_meta_lock_update definitely wants one in, but
@@ -1719,7 +1729,8 @@
 	     OCFS2_I(inode)->ip_blkno,
 	     ex ? "EXMODE" : "PRMODE");
 
-	ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres, level);
+	if (!ocfs2_is_hard_readonly(OCFS2_SB(inode->i_sb)))
+		ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres, level);
 
 	mlog_exit_void();
 }
@@ -1735,6 +1746,9 @@
 
 	mlog_entry_void();
 
+	if (ocfs2_is_hard_readonly(osb))
+		return -EROFS;
+
 	status = ocfs2_cluster_lock(osb, lockres, level, 0);
 	if (status < 0) {
 		mlog_errno(status);
@@ -1781,6 +1795,9 @@
 	int status;
 	struct ocfs2_lock_res *lockres = &osb->osb_rename_lockres;
 
+	if (ocfs2_is_hard_readonly(osb))
+		return -EROFS;
+
 	status = ocfs2_cluster_lock(osb, lockres, LKM_EXMODE, 0);
 	if (status < 0)
 		mlog_errno(status);
@@ -2617,3 +2634,27 @@
 		lvb->lvb_trunc_clusters = cpu_to_be32(trunc_clusters);
 	spin_unlock(&lockres->l_lock);
 }
+
+/* This aids in debugging situations where a bad LVB might be involved. */
+void ocfs2_dump_meta_lvb_info(u64 level,
+			      const char *function,
+			      unsigned int line,
+			      struct ocfs2_lock_res *lockres)
+{
+	struct ocfs2_meta_lvb *lvb = (struct ocfs2_meta_lvb *) lockres->l_lksb.lvb;
+
+	mlog(level, "LVB information for %s (called from %s:%u):\n",
+	     lockres->l_name, function, line);
+	mlog(level, "trustable: %s, seq: %u, size_off: %u, clusters: %u\n",
+	     ocfs2_lvb_is_trustable(lockres) ? "yes" : "no",
+	     be32_to_cpu(lvb->lvb.lvb_seq), be32_to_cpu(lvb->lvb_isize_off),
+	     be32_to_cpu(lvb->lvb_iclusters));
+	mlog(level, "trunc clusters %u, uid %u, gid %u, mode 0x%x\n",
+	     be32_to_cpu(lvb->lvb_trunc_clusters), be32_to_cpu(lvb->lvb_iuid),
+	     be32_to_cpu(lvb->lvb_igid), be16_to_cpu(lvb->lvb_imode));
+	mlog(level, "nlink %u, atime_packed 0x%"MLFx64", "
+	     "ctime_packed 0x%"MLFx64", mtime_packed 0x%"MLFx64"\n",
+	     be16_to_cpu(lvb->lvb_inlink), be64_to_cpu(lvb->lvb_iatime_packed),
+	     be64_to_cpu(lvb->lvb_ictime_packed),
+	     be64_to_cpu(lvb->lvb_imtime_packed));
+}

Modified: branches/locking-changes/fs/ocfs2/dlmglue.h
===================================================================
--- branches/locking-changes/fs/ocfs2/dlmglue.h	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/dlmglue.h	2005-09-22 17:39:57 UTC (rev 2603)
@@ -121,5 +121,11 @@
 
 void ocfs2_meta_lvb_set_trunc_clusters(struct inode *inode,
 				       unsigned int trunc_clusters);
+/* aids in debugging and tracking lvbs */
+void ocfs2_dump_meta_lvb_info(u64 level,
+			      const char *function,
+			      unsigned int line,
+			      struct ocfs2_lock_res *lockres);
+#define mlog_meta_lvb(__level, __lockres) ocfs2_dump_meta_lvb_info(__level, __PRETTY_FUNCTION__, __LINE__, __lockres)
 
 #endif	/* DLMGLUE_H */

Copied: branches/locking-changes/fs/ocfs2/export.c (from rev 2601, trunk/fs/ocfs2/export.c)

Copied: branches/locking-changes/fs/ocfs2/export.h (from rev 2601, trunk/fs/ocfs2/export.h)

Modified: branches/locking-changes/fs/ocfs2/extent_map.c
===================================================================
--- branches/locking-changes/fs/ocfs2/extent_map.c	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/extent_map.c	2005-09-22 17:39:57 UTC (rev 2603)
@@ -36,6 +36,7 @@
 
 #include "extent_map.h"
 #include "inode.h"
+#include "super.h"
 
 #include "buffer_head_io.h"
 
@@ -236,7 +237,11 @@
 		if (ret)
 			goto out_free;
 		eb = (ocfs2_extent_block *)eb_bh->b_data;
-		OCFS2_BUG_ON_INVALID_EXTENT_BLOCK(eb);
+		if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+			OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
+			ret = -EIO;
+			goto out_free;
+		}
 		el = &eb->h_list;
 	}
 
@@ -298,7 +303,11 @@
 			return ret;
 		}
 		eb = (ocfs2_extent_block *)bh->b_data;
-		OCFS2_BUG_ON_INVALID_EXTENT_BLOCK(eb);
+		if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+			OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
+			brelse(bh);
+			return -EIO;
+		}
 		el = &eb->h_list;
 	} else {
 		spin_unlock(&OCFS2_I(inode)->ip_lock);
@@ -312,7 +321,11 @@
 			return ret;
 		}
 		di = (ocfs2_dinode *)bh->b_data;
-		OCFS2_BUG_ON_INVALID_DINODE(di);
+		if (!OCFS2_IS_VALID_DINODE(di)) {
+			brelse(bh);
+			OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, di);
+			return -EIO;
+		}
 		el = &di->id2.i_list;
 	}
 

Modified: branches/locking-changes/fs/ocfs2/file.c
===================================================================
--- branches/locking-changes/fs/ocfs2/file.c	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/file.c	2005-09-22 17:39:57 UTC (rev 2603)
@@ -46,6 +46,7 @@
 #include "journal.h"
 #include "mmap.h"
 #include "suballoc.h"
+#include "super.h"
 
 #include "buffer_head_io.h"
 
@@ -201,30 +202,26 @@
 				     u64 new_i_size)
 {
 	int status;
-	ocfs2_journal_handle *handle = NULL;
+	ocfs2_journal_handle *handle;
 
 	mlog_entry_void();
 
-	/* TODO: This needs to actually orphen the inode in this
+	/* TODO: This needs to actually orphan the inode in this
 	 * transaction. */
 
-	handle = ocfs2_start_trans(osb, handle, OCFS2_INODE_UPDATE_CREDITS);
-	if (handle == NULL) {
-		status = -ENOMEM;
+	handle = ocfs2_start_trans(osb, NULL, OCFS2_INODE_UPDATE_CREDITS);
+	if (IS_ERR(handle)) {
+		status = PTR_ERR(handle);
 		mlog_errno(status);
-		goto bail;
+		goto out;
 	}
 
-	ocfs2_set_inode_lock_trans(osb->journal, inode);
-
 	status = ocfs2_set_inode_size(handle, inode, fe_bh, new_i_size);
-	if (status < 0) {
+	if (status < 0)
 		mlog_errno(status);
-		goto bail;
-	}
-bail:
-	if (handle)
-		ocfs2_commit_trans(handle);
+
+	ocfs2_commit_trans(handle);
+out:
 	mlog_exit(status);
 	return status;
 }
@@ -244,7 +241,11 @@
 	truncate_inode_pages(inode->i_mapping, new_i_size);
 
 	fe = (ocfs2_dinode *) di_bh->b_data;
-	OCFS2_BUG_ON_INVALID_DINODE(fe);
+	if (!OCFS2_IS_VALID_DINODE(fe)) {
+		OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, fe);
+		status = -EIO;
+		goto bail;
+	}
 	mlog_bug_on_msg(le64_to_cpu(fe->i_size) != i_size_read(inode),
 			"Inode %"MLFu64", inode i_size = %lld != di "
 			"i_size = %"MLFu64", i_flags = 0x%x\n",
@@ -457,7 +458,11 @@
 	}
 
 	fe = (ocfs2_dinode *) bh->b_data;
-	OCFS2_BUG_ON_INVALID_DINODE(fe);
+	if (!OCFS2_IS_VALID_DINODE(fe)) {
+		OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, fe);
+		status = -EIO;
+		goto leave;
+	}
 
 restart_all:
 	BUG_ON(le32_to_cpu(fe->i_clusters) != OCFS2_I(inode)->ip_clusters);
@@ -514,15 +519,13 @@
 
 	credits = ocfs2_calc_extend_credits(osb->sb, fe, clusters_to_add);
 	handle = ocfs2_start_trans(osb, handle, credits);
-	if (handle == NULL) {
-		status = -ENOMEM;
+	if (IS_ERR(handle)) {
+		status = PTR_ERR(handle);
+		handle = NULL;
 		mlog_errno(status);
 		goto leave;
 	}
 
-	/* Since we got our cluster lock from caller and we don't add
-	 * it to the handle: */
-	ocfs2_set_inode_lock_trans(osb->journal, inode);
 restarted_transaction:
 	/* reserve a write to the file entry early on - that we if we
 	 * run out of credits in the allocation path, we can still
@@ -746,7 +749,6 @@
 int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
 {
 	int status = 0;
-	int unlock = 0;
 	u64 newsize;
 	struct inode *inode = dentry->d_inode;
 	struct super_block *sb = inode->i_sb;
@@ -787,7 +789,6 @@
 			mlog_errno(status);
 		goto bail;
 	}
-	unlock = 1;
 
 	if (S_ISREG(inode->i_mode) &&
 	    attr->ia_valid & ATTR_SIZE &&
@@ -800,41 +801,32 @@
 			if (status != -ENOSPC)
 				mlog_errno(status);
 			status = -ENOSPC;
-			goto bail;
+			goto bail_unlock;
 		}
 	}
 
 	handle = ocfs2_start_trans(osb, NULL, OCFS2_INODE_UPDATE_CREDITS);
-	if (handle == NULL) {
+	if (IS_ERR(handle)) {
+		status = PTR_ERR(handle);
 		mlog_errno(status);
-		goto bail;
+		goto bail_unlock;
 	}
 
-	/* Ok, this is the last transaction we'll do for a setattr so
-	 * just add our lock to the handle and let commit_trans deal
-	 * with it. */
-	status = ocfs2_handle_add_lock(handle, inode);
-	if (status < 0)
-		mlog_errno(status);
-	unlock = 0;
-
 	status = inode_setattr(inode, attr);
 	if (status < 0) {
 		mlog_errno(status);
-		goto bail;
+		goto bail_commit;
 	}
 
 	status = ocfs2_mark_inode_dirty(handle, inode, bh);
-	if (status < 0) {
+	if (status < 0)
 		mlog_errno(status);
-		goto bail;
-	}
 
+bail_commit:
+	ocfs2_commit_trans(handle);
+bail_unlock:
+	ocfs2_meta_unlock(inode, 1);
 bail:
-	if (handle)
-		ocfs2_commit_trans(handle);
-	if (unlock)
-		ocfs2_meta_unlock(inode, 1);
 	if (bh)
 		brelse(bh);
 

Modified: branches/locking-changes/fs/ocfs2/inode.c
===================================================================
--- branches/locking-changes/fs/ocfs2/inode.c	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/inode.c	2005-09-22 17:39:57 UTC (rev 2603)
@@ -100,7 +100,8 @@
 	 * caller, or we just pulled them off the bh. Lets do some
 	 * sanity checks to make sure they're OK. */
 	if (blkno == 0) {
-		mlog_errno(-EINVAL);
+		inode = ERR_PTR(-EINVAL);
+		mlog_errno(PTR_ERR(inode));
 		goto bail;
 	}
 
@@ -119,24 +120,25 @@
 		unlock_new_inode(inode);
 	}
 	if (inode == NULL) {
-		mlog(ML_ERROR, "access error\n");
-		inode = NULL;
+		inode = ERR_PTR(-ENOMEM);
+		mlog_errno(PTR_ERR(inode));
 		goto bail;
 	}
 	if (is_bad_inode(inode)) {
-		mlog(ML_ERROR, "access error (bad inode)\n");
 		iput(inode);
-		inode = NULL;
+		inode = ERR_PTR(-ESTALE);
+		mlog_errno(PTR_ERR(inode));
 		goto bail;
 	}
 
 bail:
-	if (inode)
+	if (!IS_ERR(inode)) {
 		mlog(0, "returning inode with number %"MLFu64"\n",
 		     OCFS2_I(inode)->ip_blkno);
+		mlog_exit_ptr(inode);
+	} else
+		mlog_errno(PTR_ERR(inode));
 
-	mlog_exit_ptr(inode);
-
 	return inode;
 }
 
@@ -427,14 +429,13 @@
 		goto bail;
 
 	handle = ocfs2_start_trans(osb, handle, OCFS2_INODE_UPDATE_CREDITS);
-	if (handle == NULL) {
-		status = -ENOMEM;
+	if (IS_ERR(handle)) {
+		status = PTR_ERR(handle);
+		handle = NULL;
 		mlog_errno(status);
 		goto bail;
 	}
 
-	ocfs2_set_inode_lock_trans(osb->journal, inode);
-
 	status = ocfs2_set_inode_size(handle, inode, fe_bh, 0ULL);
 	if (status < 0) {
 		mlog_errno(status);
@@ -494,20 +495,12 @@
 	}
 
 	handle = ocfs2_start_trans(osb, NULL, OCFS2_DELETE_INODE_CREDITS);
-	if (handle == NULL) {
-		status = -ENOMEM;
+	if (IS_ERR(handle)) {
+		status = PTR_ERR(handle);
 		mlog_errno(status);
 		goto bail_unlock;
 	}
 
-	ocfs2_set_inode_lock_trans(osb->journal, inode_alloc_inode);
-	ocfs2_set_inode_lock_trans(osb->journal, orphan_dir_inode);
-	/* Set the inode locking information, even though we're wiping
-	 * the inode - if we error before completing the wipe, we'll
-	 * want to checkpoint our progress so other nodes get an
-	 * up-to-date picture. */
-	ocfs2_set_inode_lock_trans(osb->journal, inode);
-
 	status = ocfs2_orphan_del(osb, handle, orphan_dir_inode, inode,
 				  orphan_dir_bh);
 	if (status < 0) {

Modified: branches/locking-changes/fs/ocfs2/journal.c
===================================================================
--- branches/locking-changes/fs/ocfs2/journal.c	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/journal.c	2005-09-22 17:39:57 UTC (rev 2603)
@@ -58,8 +58,7 @@
 static int ocfs2_commit_cache(ocfs2_super *osb);
 static int ocfs2_wait_on_mount(ocfs2_super *osb);
 static void ocfs2_handle_cleanup_locks(ocfs2_journal *journal,
-				      ocfs2_journal_handle *handle,
-				      int set_id);
+				       ocfs2_journal_handle *handle);
 static void ocfs2_commit_unstarted_handle(ocfs2_journal_handle *handle);
 static int ocfs2_journal_toggle_dirty(ocfs2_super *osb,
 				     int dirty);
@@ -137,12 +136,13 @@
 }
 
 /* pass it NULL and it will allocate a new handle object for you.  If
- * you pass it a handle however, it may still return NULL, in which
+ * you pass it a handle however, it may still return error, in which
  * case it has free'd the passed handle for you. */
 ocfs2_journal_handle *ocfs2_start_trans(ocfs2_super *osb,
 					ocfs2_journal_handle *handle,
 					int max_buffs)
 {
+	int ret;
 	journal_t *journal = osb->journal->j_journal;
 
 	mlog_entry("(max_buffs = %d)\n", max_buffs);
@@ -150,6 +150,11 @@
 	if (!osb || !osb->journal->j_journal)
 		BUG();
 
+	if (ocfs2_is_hard_readonly(osb)) {
+		ret = -EROFS;
+		goto done_free;
+	}
+
 	BUG_ON(osb->journal->j_state == OCFS2_JOURNAL_FREE);
 	BUG_ON(max_buffs <= 0);
 
@@ -162,6 +167,7 @@
 	if (!handle)
 		handle = ocfs2_alloc_handle(osb);
 	if (!handle) {
+		ret = -ENOMEM;
 		mlog(ML_ERROR, "Failed to allocate memory for journal "
 		     "handle!\n");
 		goto done_free;
@@ -176,9 +182,14 @@
 	if (IS_ERR(handle->k_handle)) {
 		up_read(&osb->journal->j_trans_barrier);
 
-		mlog(ML_ERROR, "journal_start() failed!\n");
-		mlog_errno((int)PTR_ERR(handle->k_handle));
+		ret = PTR_ERR(handle->k_handle);
 		handle->k_handle = NULL;
+		mlog_errno(ret);
+
+		if (is_journal_aborted(journal)) {
+			ocfs2_abort(osb->sb, "Detected aborted journal");
+			ret = -EROFS;
+		}
 		goto done_free;
 	}
 
@@ -189,12 +200,11 @@
 	return handle;
 
 done_free:
-
 	if (handle)
 		ocfs2_commit_unstarted_handle(handle); /* will kfree handle */
 
-	mlog_exit(NULL);
-	return NULL;
+	mlog_exit(ret);
+	return ERR_PTR(ret);
 }
 
 void ocfs2_handle_add_inode(ocfs2_journal_handle *handle,
@@ -247,7 +257,7 @@
 	ocfs2_handle_unlock_inodes(handle);
 	/* You are allowed to add journal locks before the transaction
 	 * has started. */
-	ocfs2_handle_cleanup_locks(handle->journal, handle, 0);
+	ocfs2_handle_cleanup_locks(handle->journal, handle);
 
 	kfree(handle);
 
@@ -297,7 +307,7 @@
 		handle->k_handle = NULL; /* it's been free'd in journal_stop */
 	}
 
-	ocfs2_handle_cleanup_locks(journal, handle, 1);
+	ocfs2_handle_cleanup_locks(journal, handle);
 
 	up_read(&journal->j_trans_barrier);
 
@@ -383,6 +393,14 @@
 		BUG();
 	}
 
+	/* Set the current transaction information on the inode so
+	 * that the locking code knows whether it can drop it's locks
+	 * on this inode or not. We're protected from the commit
+	 * thread updating the current transaction id until
+	 * ocfs2_commit_trans() because ocfs2_start_trans() took
+	 * j_trans_barrier for us. */
+	ocfs2_set_inode_lock_trans(OCFS2_SB(inode->i_sb)->journal, inode);
+
 	down(&OCFS2_I(inode)->ip_io_sem);
 	switch (type) {
 	case OCFS2_JOURNAL_ACCESS_CREATE:
@@ -470,8 +488,7 @@
 }
 
 static void ocfs2_handle_cleanup_locks(ocfs2_journal *journal,
-				       ocfs2_journal_handle *handle,
-				       int set_id)
+				       ocfs2_journal_handle *handle)
 {
 	struct list_head *p, *n;
 	ocfs2_journal_lock *lock;
@@ -483,8 +500,6 @@
 		handle->num_locks--;
 
 		inode = lock->jl_inode;
-		if (set_id)
-			ocfs2_set_inode_lock_trans(journal, inode);
 		ocfs2_meta_unlock(inode, 1);
 		if (atomic_read(&inode->i_count) == 1)
 			mlog(ML_ERROR,
@@ -497,6 +512,19 @@
 
 #define OCFS2_DEFAULT_COMMIT_INTERVAL 	(HZ * 5)
 
+void ocfs2_set_journal_params(ocfs2_super *osb)
+{
+	journal_t *journal = osb->journal->j_journal;
+
+	spin_lock(&journal->j_state_lock);
+	journal->j_commit_interval = OCFS2_DEFAULT_COMMIT_INTERVAL;
+	if (osb->s_mount_opt & OCFS2_MOUNT_BARRIER)
+		journal->j_flags |= JFS_BARRIER;
+	else
+		journal->j_flags &= ~JFS_BARRIER;
+	spin_unlock(&journal->j_state_lock);
+}
+
 int ocfs2_journal_init(ocfs2_journal *journal, int *dirty)
 {
 	int status = -1;
@@ -563,15 +591,7 @@
 
 	mlog(0, "Returned from journal_init_inode\n");
 	mlog(0, "j_journal->j_maxlen = %u\n", j_journal->j_maxlen);
-	j_journal->j_commit_interval = OCFS2_DEFAULT_COMMIT_INTERVAL;
 
-	spin_lock(&j_journal->j_state_lock);
-	if (osb->s_mount_opt & OCFS2_MOUNT_BARRIER)
-		j_journal->j_flags |= JFS_BARRIER;
-	else
-		j_journal->j_flags &= ~JFS_BARRIER;
-	spin_unlock(&j_journal->j_state_lock);
-
 	*dirty = (le32_to_cpu(di->id1.journal1.ij_flags) &
 		  OCFS2_JOURNAL_DIRTY_FL);
 
@@ -579,6 +599,8 @@
 	journal->j_inode = inode;
 	journal->j_bh = bh;
 
+	ocfs2_set_journal_params(osb);
+
 	journal->j_state = OCFS2_JOURNAL_LOADED;
 
 	status = 0;
@@ -610,7 +632,15 @@
 	mlog_entry_void();
 
 	fe = (ocfs2_dinode *)bh->b_data;
-	OCFS2_BUG_ON_INVALID_DINODE(fe);
+	if (!OCFS2_IS_VALID_DINODE(fe)) {
+		/* This is called from startup/shutdown which will
+		 * handle the errors in a specific manner, so no need
+		 * to call ocfs2_error() here. */
+		mlog(ML_ERROR, "Journal dinode %"MLFu64"  has invalid "
+		     "signature: %.*s", fe->i_blkno, 7, fe->i_signature);
+		status = -EIO;
+		goto out;
+	}
 
 	flags = le32_to_cpu(fe->id1.journal1.ij_flags);
 	if (dirty)
@@ -623,6 +653,7 @@
 	if (status < 0)
 		mlog_errno(status);
 
+out:
 	mlog_exit(status);
 	return status;
 }
@@ -704,10 +735,27 @@
 	mlog_exit_void();
 }
 
+static void ocfs2_clear_journal_error(struct super_block *sb,
+				      journal_t *journal,
+				      int slot)
+{
+	int olderr;
+
+	olderr = journal_errno(journal);
+	if (olderr) {
+		mlog(ML_ERROR, "File system error %d recorded in "
+		     "journal %u.\n", olderr, slot);
+		mlog(ML_ERROR, "File system on device %s needs checking.\n",
+		     sb->s_id);
+
+		journal_ack_err(journal);
+		journal_clear_err(journal);
+	}
+}
+
 int ocfs2_journal_load(ocfs2_journal *journal)
 {
 	int status = 0;
-	int olderr = 0;
 	ocfs2_super *osb;
 
 	mlog_entry_void();
@@ -723,12 +771,7 @@
 		goto done;
 	}
 
-	olderr = journal_errno(journal->j_journal);
-	if (olderr) {
-		mlog(ML_ERROR, "last journal left error code %d\n", olderr);
-		journal_ack_err(journal->j_journal);
-		journal_clear_err(journal->j_journal);
-	}
+	ocfs2_clear_journal_error(osb->sb, journal->j_journal, osb->slot_num);
 
 	status = ocfs2_journal_toggle_dirty(osb, 1);
 	if (status < 0) {
@@ -921,7 +964,6 @@
 	}
 
 	mlog(0, "Recovery completion\n");
-
 	mlog_exit_void();
 }
 
@@ -974,6 +1016,8 @@
 						osb->slot_num,
 						osb->local_alloc_copy,
 						NULL);
+		ocfs2_schedule_truncate_log_flush(osb, 0);
+
 		osb->local_alloc_copy = NULL;
 		osb->dirty = 0;
 	}
@@ -1159,6 +1203,8 @@
 		goto done;
 	}
 
+	ocfs2_clear_journal_error(osb->sb, journal, slot_num);
+
 	/* wipe the journal */
 	mlog(0, "flushing the journal.\n");
 	journal_lock_updates(journal);
@@ -1194,7 +1240,6 @@
 
 	mlog_exit(status);
 	return status;
-
 }
 
 /*
@@ -1384,7 +1429,7 @@
 	if  (!orphan_dir_inode) {
 		status = -ENOENT;
 		mlog_errno(status);
-		goto bail;
+		goto out;
 	}
 
 	down(&orphan_dir_inode->i_sem);
@@ -1392,7 +1437,7 @@
 	if (status < 0) {
 		up(&orphan_dir_inode->i_sem);
 		mlog_errno(status);
-		goto bail;
+		goto out;
 	}
 	have_disk_lock = 1;
 
@@ -1409,7 +1454,7 @@
 			if (bh)
 				brelse(bh);
 			mlog_errno(status);
-			goto bail;
+			goto out;
 		}
 
 		local = 0;
@@ -1423,7 +1468,7 @@
 				status = -EINVAL;
 				mlog_errno(status);
 				brelse(bh);
-				goto bail;
+				goto out;
 			}
 
 			local += le16_to_cpu(de->rec_len);
@@ -1453,7 +1498,7 @@
 				continue;
 
 			iter = ocfs2_iget(osb, le64_to_cpu(de->inode));
-			if (!iter)
+			if (IS_ERR(iter))
 				continue;
 
 			mlog(0, "queue orphan %"MLFu64"\n",
@@ -1495,7 +1540,7 @@
 		inode = iter;
 	}
 
-bail:
+out:
 	if (have_disk_lock)
 		ocfs2_meta_unlock(orphan_dir_inode, 0);
 
@@ -1557,3 +1602,50 @@
 
 	return 0;
 }
+
+/* Look for a dirty journal without taking any cluster locks. Used for
+ * hard readonly access to determine whether the file system journals
+ * require recovery. */
+int ocfs2_check_journals_nolocks(ocfs2_super *osb)
+{
+	int ret = 0;
+	unsigned int slot;
+	struct buffer_head *di_bh;
+	ocfs2_dinode *di;
+	struct inode *journal = NULL;
+
+	for(slot = 0; slot < osb->max_slots; slot++) {
+		journal = ocfs2_get_system_file_inode(osb,
+						      JOURNAL_SYSTEM_INODE,
+						      slot);
+		if (!journal || is_bad_inode(journal)) {
+			ret = -EACCES;
+			mlog_errno(ret);
+			goto out;
+		}
+
+		di_bh = NULL;
+		ret = ocfs2_read_block(osb, OCFS2_I(journal)->ip_blkno, &di_bh,
+				       0, journal);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		di = (ocfs2_dinode *) di_bh->b_data;
+
+		if (le32_to_cpu(di->id1.journal1.ij_flags) &
+		    OCFS2_JOURNAL_DIRTY_FL)
+			ret = -EROFS;
+
+		brelse(di_bh);
+		if (ret)
+			break;
+	}
+
+out:
+	if (journal)
+		iput(journal);
+
+	return ret;
+}

Modified: branches/locking-changes/fs/ocfs2/journal.h
===================================================================
--- branches/locking-changes/fs/ocfs2/journal.h	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/journal.h	2005-09-22 17:39:57 UTC (rev 2603)
@@ -77,7 +77,7 @@
 	unsigned long old_id;
 	spin_lock(&trans_inc_lock);
 	old_id = j->j_trans_id++;
-	if (!j->j_trans_id)
+	if (unlikely(!j->j_trans_id))
 		j->j_trans_id = 1;
 	spin_unlock(&trans_inc_lock);
 	return old_id;
@@ -194,12 +194,14 @@
  *                          event on.
  *  ocfs2_start_checkpoint - Kick the commit thread to do a checkpoint.
  */
+void   ocfs2_set_journal_params(ocfs2_super *osb);
 int    ocfs2_journal_init(ocfs2_journal *journal,
 			  int *dirty);
 void   ocfs2_journal_shutdown(struct _ocfs2_super *osb);
 int    ocfs2_journal_wipe(ocfs2_journal *journal,
 			  int full);
 int    ocfs2_journal_load(ocfs2_journal *journal);
+int    ocfs2_check_journals_nolocks(ocfs2_super *osb);
 void   ocfs2_recovery_thread(struct _ocfs2_super *osb,
 			     int node_num);
 int    ocfs2_mark_dead_nodes(ocfs2_super *osb);

Modified: branches/locking-changes/fs/ocfs2/localalloc.c
===================================================================
--- branches/locking-changes/fs/ocfs2/localalloc.c	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/localalloc.c	2005-09-22 17:39:57 UTC (rev 2603)
@@ -40,6 +40,7 @@
 #include "journal.h"
 #include "localalloc.h"
 #include "suballoc.h"
+#include "super.h"
 #include "sysfile.h"
 
 #include "buffer_head_io.h"
@@ -245,8 +246,9 @@
 
 	/* WINDOW_MOVE_CREDITS is a bit heavy... */
 	handle = ocfs2_start_trans(osb, handle, OCFS2_WINDOW_MOVE_CREDITS);
-	if (!handle) {
-		mlog_errno(-ENOMEM);
+	if (IS_ERR(handle)) {
+		mlog_errno(PTR_ERR(handle));
+		handle = NULL;
 		goto bail;
 	}
 
@@ -413,8 +415,9 @@
 	}
 
 	handle = ocfs2_start_trans(osb, handle, OCFS2_WINDOW_MOVE_CREDITS);
-	if (!handle) {
-		status = -ENOMEM;
+	if (IS_ERR(handle)) {
+		status = PTR_ERR(handle);
+		handle = NULL;
 		mlog_errno(status);
 		goto bail;
 	}
@@ -488,8 +491,16 @@
 
 	alloc = (ocfs2_dinode *) osb->local_alloc_bh->b_data;
 
-	OCFS2_BUG_ON_RO(le32_to_cpu(alloc->id1.bitmap1.i_used) !=
-			ocfs2_local_alloc_count_bits(alloc));
+	if (le32_to_cpu(alloc->id1.bitmap1.i_used) !=
+	    ocfs2_local_alloc_count_bits(alloc)) {
+		ocfs2_error(osb->sb, "local alloc inode %"MLFu64" says it has "
+			    "%u free bits, but a count shows %u",
+			    le64_to_cpu(alloc->i_blkno),
+			    le32_to_cpu(alloc->id1.bitmap1.i_used),
+			    ocfs2_local_alloc_count_bits(alloc));
+		status = -EIO;
+		goto bail;
+	}
 
 	free_bits = le32_to_cpu(alloc->id1.bitmap1.i_total) -
 		le32_to_cpu(alloc->id1.bitmap1.i_used);
@@ -895,8 +906,9 @@
 	}
 
 	handle = ocfs2_start_trans(osb, handle, OCFS2_WINDOW_MOVE_CREDITS);
-	if (!handle) {
-		status = -ENOMEM;
+	if (IS_ERR(handle)) {
+		status = PTR_ERR(handle);
+		handle = NULL;
 		mlog_errno(status);
 		goto bail;
 	}

Modified: branches/locking-changes/fs/ocfs2/namei.c
===================================================================
--- branches/locking-changes/fs/ocfs2/namei.c	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/namei.c	2005-09-22 17:39:57 UTC (rev 2603)
@@ -177,7 +177,7 @@
 		goto bail_add;
 
 	inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno);
-	if (!inode) {
+	if (IS_ERR(inode)) {
 		mlog(ML_ERROR, "Unable to create inode %"MLFu64"\n", blkno);
 		ret = ERR_PTR(-EACCES);
 		goto bail_unlock;
@@ -197,8 +197,7 @@
 bail_add:
 
 	dentry->d_op = &ocfs2_dentry_ops;
-	d_add(dentry, inode);
-	ret = NULL;
+	ret = d_splice_alias(inode, dentry);
 
 bail_unlock:
 	/* Don't drop the cluster lock until *after* the d_add --
@@ -216,62 +215,6 @@
 	return ret;
 }
 
-struct dentry *ocfs2_get_parent(struct dentry *child)
-{
-	int status;
-	u64 blkno;
-	struct dentry *parent;
-	struct inode *inode;
-	struct inode *dir = child->d_inode;
-	struct buffer_head *dirent_bh = NULL;
-	struct ocfs2_dir_entry *dirent;
-
-	mlog_entry("(0x%p, '%.*s')\n", child,
-		   child->d_name.len, child->d_name.name);
-
-	mlog(0, "find parent of directory %"MLFu64"\n",
-	     OCFS2_I(dir)->ip_blkno);
-
-	status = ocfs2_meta_lock(dir, NULL, NULL, 0);
-	if (status < 0) {
-		if (status != -ENOENT)
-			mlog_errno(status);
-		parent = ERR_PTR(status);
-		goto bail;
-	}
-
-	status = ocfs2_find_files_on_disk("..", 2, &blkno, dir, &dirent_bh,
-					  &dirent);
-	if (status < 0) {
-		parent = ERR_PTR(-ENOENT);
-		goto bail_unlock;
-	}
-
-	inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno);
-	if (!inode) {
-		mlog(ML_ERROR, "Unable to create inode %"MLFu64"\n", blkno);
-		parent = ERR_PTR(-EACCES);
-		goto bail_unlock;
-	}
-
-	parent = d_alloc_anon(inode);
-	if (!parent) {
-		iput(inode);
-		parent = ERR_PTR(-ENOMEM);
-	}
-
-bail_unlock:
-	ocfs2_meta_unlock(dir, 0);
-
-	if (dirent_bh)
-		brelse(dirent_bh);
-
-bail:
-	mlog_exit_ptr(parent);
-
-	return parent;
-}
-
 static int ocfs2_fill_new_dir(ocfs2_super *osb,
 			      ocfs2_journal_handle *handle,
 			      struct inode *parent,
@@ -426,8 +369,9 @@
 	}
 
 	handle = ocfs2_start_trans(osb, handle, OCFS2_MKNOD_CREDITS);
-	if (handle == NULL) {
-		status = -ENOMEM;
+	if (IS_ERR(handle)) {
+		status = PTR_ERR(handle);
+		handle = NULL;
 		mlog_errno(status);
 		goto leave;
 	}
@@ -553,9 +497,9 @@
 	else
 		inode->i_nlink = 1;
 	inode->i_mode = mode;
-	spin_lock(&osb->s_next_gen_lock);
+	spin_lock(&osb->osb_lock);
 	inode->i_generation = osb->s_next_generation++;
-	spin_unlock(&osb->s_next_gen_lock);
+	spin_unlock(&osb->osb_lock);
 
 	*new_fe_bh = sb_getblk(osb->sb, fe_blkno);
 	if (!*new_fe_bh) {
@@ -740,8 +684,10 @@
 	}
 
 	handle = ocfs2_start_trans(osb, handle, OCFS2_LINK_CREDITS);
-	if (handle == NULL) {
-		err = -ENOMEM;
+	if (IS_ERR(handle)) {
+		err = PTR_ERR(handle);
+		handle = NULL;
+		mlog_errno(err);
 		goto bail;
 	}
 
@@ -903,8 +849,9 @@
 	}
 
 	handle = ocfs2_start_trans(osb, handle, OCFS2_UNLINK_CREDITS);
-	if (handle == NULL) {
-		status = -ENOMEM;
+	if (IS_ERR(handle)) {
+		status = PTR_ERR(handle);
+		handle = NULL;
 		mlog_errno(status);
 		goto leave;
 	}
@@ -1300,8 +1247,9 @@
 	}
 
 	handle = ocfs2_start_trans(osb, handle, OCFS2_RENAME_CREDITS);
-	if (handle == NULL) {
-		status = -ENOMEM;
+	if (IS_ERR(handle)) {
+		status = PTR_ERR(handle);
+		handle = NULL;
 		mlog_errno(status);
 		goto bail;
 	}
@@ -1657,8 +1605,9 @@
 	}
 
 	handle = ocfs2_start_trans(osb, handle, credits);
-	if (handle == NULL) {
-		status = -ENOMEM;
+	if (IS_ERR(handle)) {
+		status = PTR_ERR(handle);
+		handle = NULL;
 		mlog_errno(status);
 		goto bail;
 	}

Modified: branches/locking-changes/fs/ocfs2/ocfs2.h
===================================================================
--- branches/locking-changes/fs/ocfs2/ocfs2.h	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/ocfs2.h	2005-09-22 17:39:57 UTC (rev 2603)
@@ -160,13 +160,19 @@
 
 enum ocfs2_mount_options
 {
-	OCFS2_MOUNT_HB_OK   = 1 << 0,	/* Heartbeat started */
+	OCFS2_MOUNT_HB_LOCAL   = 1 << 0, /* Heartbeat started in local mode */
 	OCFS2_MOUNT_BARRIER = 1 << 1,	/* Use block barriers */
+	OCFS2_MOUNT_NOINTR  = 1 << 2,   /* Don't catch signals */
+	OCFS2_MOUNT_ERRORS_PANIC = 1 << 3, /* Panic on errors */
 #ifdef OCFS2_ORACORE_WORKAROUNDS
 	OCFS2_MOUNT_COMPAT_OCFS = 1 << 30, /* ocfs1 compatibility mode */
 #endif
 };
 
+#define OCFS2_OSB_SOFT_RO	0x0001
+#define OCFS2_OSB_HARD_RO	0x0002
+#define OCFS2_OSB_ERROR_FS	0x0004
+
 struct _ocfs2_journal;
 typedef struct _ocfs2_journal_handle ocfs2_journal_handle;
 
@@ -201,8 +207,11 @@
 	u32 s_feature_incompat;
 	u32 s_feature_ro_compat;
 
-	spinlock_t s_next_gen_lock;
+	/* Protects s_next_generaion, osb_flags. Could protect more on
+	 * osb as it's very short lived. */
+	spinlock_t osb_lock;
 	u32 s_next_generation;
+	unsigned long osb_flags;
 
 	unsigned long s_mount_opt;
 
@@ -282,38 +291,83 @@
 #define OCFS2_SB(sb)	    ((ocfs2_super *)(sb)->s_fs_info)
 #define OCFS2_MAX_OSB_ID             65536
 
-/* Helps document which BUG's should really just force the file system
- * to go readonly */
-#define OCFS2_BUG_ON_RO(x) BUG_ON((x))
+/* set / clear functions because cluster events can make these happen
+ * in parallel so we want the transitions to be atomic. this also
+ * means that any future flags osb_flags must be protected by spinlock
+ * too! */
+static inline void ocfs2_set_osb_flag(ocfs2_super *osb,
+				      unsigned long flag)
+{
+	spin_lock(&osb->osb_lock);
+	osb->osb_flags |= flag;
+	spin_unlock(&osb->osb_lock);
+}
 
+static inline void ocfs2_set_ro_flag(ocfs2_super *osb,
+				     int hard)
+{
+	spin_lock(&osb->osb_lock);
+	osb->osb_flags &= ~(OCFS2_OSB_SOFT_RO|OCFS2_OSB_HARD_RO);
+	if (hard)
+		osb->osb_flags |= OCFS2_OSB_HARD_RO;
+	else
+		osb->osb_flags |= OCFS2_OSB_SOFT_RO;
+	spin_unlock(&osb->osb_lock);
+}
+
+static inline int ocfs2_is_hard_readonly(ocfs2_super *osb)
+{
+	int ret;
+
+	spin_lock(&osb->osb_lock);
+	ret = osb->osb_flags & OCFS2_OSB_HARD_RO;
+	spin_unlock(&osb->osb_lock);
+
+	return ret;
+}
+
+static inline int ocfs2_is_soft_readonly(ocfs2_super *osb)
+{
+	int ret;
+
+	spin_lock(&osb->osb_lock);
+	ret = osb->osb_flags & OCFS2_OSB_SOFT_RO;
+	spin_unlock(&osb->osb_lock);
+
+	return ret;
+}
+
 #define OCFS2_IS_VALID_DINODE(ptr)					\
 	(!strcmp((ptr)->i_signature, OCFS2_INODE_SIGNATURE))
 
-#define OCFS2_BUG_ON_INVALID_DINODE(__di)	do {			\
-	mlog_bug_on_msg(!OCFS2_IS_VALID_DINODE((__di)),			\
-		"Dinode # %"MLFu64" has bad signature %.*s\n",		\
-		(__di)->i_blkno, 7,					\
-		(__di)->i_signature);					\
+#define OCFS2_RO_ON_INVALID_DINODE(__sb, __di)	do {			\
+	typeof(__di) ____di = (__di);					\
+	ocfs2_error((__sb), 						\
+		"Dinode # %"MLFu64" has bad signature %.*s",		\
+		(____di)->i_blkno, 7,					\
+		(____di)->i_signature);					\
 } while (0);
 
 #define OCFS2_IS_VALID_EXTENT_BLOCK(ptr)				\
 	(!strcmp((ptr)->h_signature, OCFS2_EXTENT_BLOCK_SIGNATURE))
 
-#define OCFS2_BUG_ON_INVALID_EXTENT_BLOCK(__eb)	do {			\
-	mlog_bug_on_msg(!OCFS2_IS_VALID_EXTENT_BLOCK((__eb)),		\
-		"Extent Block # %"MLFu64" has bad signature %.*s\n",	\
-		(__eb)->h_blkno, 7,					\
-		(__eb)->h_signature);					\
+#define OCFS2_RO_ON_INVALID_EXTENT_BLOCK(__sb, __eb)	do {		\
+	typeof(__eb) ____eb = (__eb);					\
+	ocfs2_error((__sb), 						\
+		"Extent Block # %"MLFu64" has bad signature %.*s",	\
+		(____eb)->h_blkno, 7,					\
+		(____eb)->h_signature);					\
 } while (0);
 
 #define OCFS2_IS_VALID_GROUP_DESC(ptr)					\
 	(!strcmp((ptr)->bg_signature, OCFS2_GROUP_DESC_SIGNATURE))
 
-#define OCFS2_BUG_ON_INVALID_GROUP_DESC(__gd)	do {			\
-	mlog_bug_on_msg(!OCFS2_IS_VALID_GROUP_DESC((__gd)),		\
-		"Group Descriptor # %"MLFu64" has bad signature %.*s\n",\
-		(__gd)->bg_blkno, 7,					\
-		(__gd)->bg_signature);					\
+#define OCFS2_RO_ON_INVALID_GROUP_DESC(__sb, __gd)	do {		\
+	typeof(__gd) ____gd = (__gd);					\
+		ocfs2_error((__sb),					\
+		"Group Descriptor # %"MLFu64" has bad signature %.*s",	\
+		(____gd)->bg_blkno, 7,					\
+		(____gd)->bg_signature);				\
 } while (0);
 
 static inline unsigned long ino_from_blkno(struct super_block *sb,

Modified: branches/locking-changes/fs/ocfs2/ocfs2_fs.h
===================================================================
--- branches/locking-changes/fs/ocfs2/ocfs2_fs.h	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/ocfs2_fs.h	2005-09-22 17:39:57 UTC (rev 2603)
@@ -185,7 +185,8 @@
 };
 
 /* Parameter passed from mount.ocfs2 to module */
-#define OCFS2_HB_OK		"hbok"
+#define OCFS2_HB_NONE			"heartbeat=none"
+#define OCFS2_HB_LOCAL			"heartbeat=local"
 
 /*
  * OCFS2 directory file types.  Only the low 3 bits are used.  The

Modified: branches/locking-changes/fs/ocfs2/slot_map.c
===================================================================
--- branches/locking-changes/fs/ocfs2/slot_map.c	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/slot_map.c	2005-09-22 17:39:57 UTC (rev 2603)
@@ -38,6 +38,7 @@
 #include "heartbeat.h"
 #include "inode.h"
 #include "slot_map.h"
+#include "super.h"
 #include "sysfile.h"
 
 #include "buffer_head_io.h"

Modified: branches/locking-changes/fs/ocfs2/suballoc.c
===================================================================
--- branches/locking-changes/fs/ocfs2/suballoc.c	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/suballoc.c	2005-09-22 17:39:57 UTC (rev 2603)
@@ -40,6 +40,7 @@
 #include "journal.h"
 #include "localalloc.h"
 #include "suballoc.h"
+#include "super.h"
 #include "sysfile.h"
 #include "uptodate.h"
 
@@ -155,7 +156,13 @@
 
 	mlog_entry_void();
 
-	OCFS2_BUG_ON_RO(((unsigned long long) bg_bh->b_blocknr) != group_blkno);
+	if (((unsigned long long) bg_bh->b_blocknr) != group_blkno) {
+		ocfs2_error(alloc_inode->i_sb, "group block (%"MLFu64") "
+			    "!= b_blocknr (%llu)", group_blkno,
+			    (unsigned long long) bg_bh->b_blocknr);
+		status = -EIO;
+		goto bail;
+	}
 
 	status = ocfs2_journal_access(handle,
 				      alloc_inode,
@@ -250,8 +257,9 @@
 	credits = ocfs2_calc_group_alloc_credits(osb->sb,
 						 le16_to_cpu(cl->cl_cpg));
 	handle = ocfs2_start_trans(osb, handle, credits);
-	if (!handle) {
-		status = -ENOMEM;
+	if (IS_ERR(handle)) {
+		status = PTR_ERR(handle);
+		handle = NULL;
 		mlog_errno(status);
 		goto bail;
 	}
@@ -368,8 +376,17 @@
 	}
 
 	fe = (ocfs2_dinode *) bh->b_data;
-	OCFS2_BUG_ON_INVALID_DINODE(fe);
-	OCFS2_BUG_ON_RO(!(fe->i_flags & cpu_to_le32(OCFS2_CHAIN_FL)));
+	if (!OCFS2_IS_VALID_DINODE(fe)) {
+		OCFS2_RO_ON_INVALID_DINODE(alloc_inode->i_sb, fe);
+		status = -EIO;
+		goto bail;
+	}
+	if (!(fe->i_flags & cpu_to_le32(OCFS2_CHAIN_FL))) {
+		ocfs2_error(alloc_inode->i_sb, "Invalid chain allocator "
+			    "# %"MLFu64, le64_to_cpu(fe->i_blkno));
+		status = -EIO;
+		goto bail;
+	}
 
 	free_bits = le32_to_cpu(fe->id1.bitmap1.i_total) -
 		le32_to_cpu(fe->id1.bitmap1.i_used);
@@ -493,7 +510,7 @@
 	}
 
 	(*ac)->ac_inode = igrab(alloc_inode);
-	(*ac)->ac_group_search = &ocfs2_block_group_search;
+	(*ac)->ac_group_search = ocfs2_block_group_search;
 
 	status = ocfs2_reserve_suballoc_bits(osb, *ac);
 	if (status < 0) {
@@ -532,7 +549,7 @@
 		goto bail;
 	}
 	ac->ac_which = OCFS2_AC_USE_MAIN;
-	ac->ac_group_search = &ocfs2_cluster_group_search;
+	ac->ac_group_search = ocfs2_cluster_group_search;
 
 	status = ocfs2_reserve_suballoc_bits(osb, ac);
 	if (status < 0 && status != -ENOSPC)
@@ -653,7 +670,10 @@
 	int offset, start, found, status = 0;
 	ocfs2_group_desc *bg = (ocfs2_group_desc *) bg_bh->b_data;
 
-	OCFS2_BUG_ON_INVALID_GROUP_DESC(bg);
+	if (!OCFS2_IS_VALID_GROUP_DESC(bg)) {
+		OCFS2_RO_ON_INVALID_GROUP_DESC(osb->sb, bg);
+		return -EIO;
+	}
 
 	found = start = best_offset = best_size = 0;
 	bitmap = bg->bg_bitmap;
@@ -720,7 +740,11 @@
 
 	mlog_entry_void();
 
-	OCFS2_BUG_ON_INVALID_GROUP_DESC(bg);
+	if (!OCFS2_IS_VALID_GROUP_DESC(bg)) {
+		OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, bg);
+		status = -EIO;
+		goto bail;
+	}
 	BUG_ON(le16_to_cpu(bg->bg_free_bits_count) < num_bits);
 
 	mlog(0, "block_group_set_bits: off = %u, num = %u\n", bit_off,
@@ -789,9 +813,21 @@
 	ocfs2_group_desc *bg = (ocfs2_group_desc *) bg_bh->b_data;
 	ocfs2_group_desc *prev_bg = (ocfs2_group_desc *) prev_bg_bh->b_data;
 
-	OCFS2_BUG_ON_INVALID_DINODE(fe);
-	OCFS2_BUG_ON_INVALID_GROUP_DESC(bg);
-	OCFS2_BUG_ON_INVALID_GROUP_DESC(prev_bg);
+	if (!OCFS2_IS_VALID_DINODE(fe)) {
+		OCFS2_RO_ON_INVALID_DINODE(alloc_inode->i_sb, fe);
+		status = -EIO;
+		goto out;
+	}
+	if (!OCFS2_IS_VALID_GROUP_DESC(bg)) {
+		OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, bg);
+		status = -EIO;
+		goto out;
+	}
+	if (!OCFS2_IS_VALID_GROUP_DESC(prev_bg)) {
+		OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, prev_bg);
+		status = -EIO;
+		goto out;
+	}
 
 	mlog(0, "In suballoc %"MLFu64", chain %u, move group %"MLFu64" to "
 	     "top, prev = %"MLFu64"\n",
@@ -805,7 +841,7 @@
 				      OCFS2_JOURNAL_ACCESS_WRITE);
 	if (status < 0) {
 		mlog_errno(status);
-		goto bail;
+		goto out_rollback;
 	}
 
 	prev_bg->bg_next_group = bg->bg_next_group;
@@ -813,14 +849,14 @@
 	status = ocfs2_journal_dirty(handle, prev_bg_bh);
 	if (status < 0) {
 		mlog_errno(status);
-		goto bail;
+		goto out_rollback;
 	}
 
 	status = ocfs2_journal_access(handle, alloc_inode, bg_bh,
 				      OCFS2_JOURNAL_ACCESS_WRITE);
 	if (status < 0) {
 		mlog_errno(status);
-		goto bail;
+		goto out_rollback;
 	}
 
 	bg->bg_next_group = fe->id2.i_chain.cl_recs[chain].c_blkno;
@@ -828,14 +864,14 @@
 	status = ocfs2_journal_dirty(handle, bg_bh);
 	if (status < 0) {
 		mlog_errno(status);
-		goto bail;
+		goto out_rollback;
 	}
 
 	status = ocfs2_journal_access(handle, alloc_inode, fe_bh,
 				      OCFS2_JOURNAL_ACCESS_WRITE);
 	if (status < 0) {
 		mlog_errno(status);
-		goto bail;
+		goto out_rollback;
 	}
 
 	fe->id2.i_chain.cl_recs[chain].c_blkno = bg->bg_blkno;
@@ -843,17 +879,17 @@
 	status = ocfs2_journal_dirty(handle, fe_bh);
 	if (status < 0) {
 		mlog_errno(status);
-		goto bail;
+		goto out_rollback;
 	}
 
 	status = 0;
-bail:
+out_rollback:
 	if (status < 0) {
 		fe->id2.i_chain.cl_recs[chain].c_blkno = cpu_to_le64(fe_ptr);
 		bg->bg_next_group = cpu_to_le64(bg_ptr);
 		prev_bg->bg_next_group = cpu_to_le64(prev_bg_ptr);
 	}
-
+out:
 	mlog_exit(status);
 	return status;
 }
@@ -882,12 +918,17 @@
 		ret = ocfs2_block_group_find_clear_bits(OCFS2_SB(inode->i_sb),
 							group_bh, bits_wanted,
 							&tmp_off, &tmp_found);
-		if (!ret) {
-			if (min_bits <= tmp_found) {
-				*bit_off = tmp_off;
-				*bits_found = tmp_found;
-				search = 0; /* success */
-			}
+		if (ret)
+			return ret;
+
+		/* ocfs2_block_group_find_clear_bits() might
+		 * return success, but we still want to return
+		 * -ENOSPC unless it found the minimum number
+		 * of bits. */
+		if (min_bits <= tmp_found) {
+			*bit_off = tmp_off;
+			*bits_found = tmp_found;
+			search = 0; /* success */
 		}
 	}
 
@@ -944,7 +985,11 @@
 		goto bail;
 	}
 	bg = (ocfs2_group_desc *) group_bh->b_data;
-	OCFS2_BUG_ON_INVALID_GROUP_DESC(bg);
+	if (!OCFS2_IS_VALID_GROUP_DESC(bg)) {
+		OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, bg);
+		status = -EIO;
+		goto bail;
+	}
 
 	status = -ENOSPC;
 	/* for now, the chain search is a bit simplistic. We just use
@@ -970,7 +1015,11 @@
 			goto bail;
 		}
 		bg = (ocfs2_group_desc *) group_bh->b_data;
-		OCFS2_BUG_ON_INVALID_GROUP_DESC(bg);
+		if (!OCFS2_IS_VALID_GROUP_DESC(bg)) {
+			OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, bg);
+			status = -EIO;
+			goto bail;
+		}
 	}
 	if (status < 0) {
 		if (status != -ENOSPC)
@@ -1078,9 +1127,21 @@
 	BUG_ON(!ac->ac_bh);
 
 	fe = (ocfs2_dinode *) ac->ac_bh->b_data;
-	OCFS2_BUG_ON_INVALID_DINODE(fe);
-	OCFS2_BUG_ON_RO(le32_to_cpu(fe->id1.bitmap1.i_used) >=
-			le32_to_cpu(fe->id1.bitmap1.i_total));
+	if (!OCFS2_IS_VALID_DINODE(fe)) {
+		OCFS2_RO_ON_INVALID_DINODE(osb->sb, fe);
+		status = -EIO;
+		goto bail;
+	}
+	if (le32_to_cpu(fe->id1.bitmap1.i_used) >=
+	    le32_to_cpu(fe->id1.bitmap1.i_total)) {
+		ocfs2_error(osb->sb, "Chain allocator dinode %"MLFu64" has %u"
+			    "used bits but only %u total.",
+			    le64_to_cpu(fe->i_blkno),
+			    le32_to_cpu(fe->id1.bitmap1.i_used),
+			    le32_to_cpu(fe->id1.bitmap1.i_total));
+		status = -EIO;
+		goto bail;
+	}
 
 	cl = (ocfs2_chain_list *) &fe->id2.i_chain;
 
@@ -1353,7 +1414,11 @@
 
 	mlog_entry_void();
 
-	OCFS2_BUG_ON_INVALID_GROUP_DESC(bg);
+	if (!OCFS2_IS_VALID_GROUP_DESC(bg)) {
+		OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, bg);
+		status = -EIO;
+		goto bail;
+	}
 
 	mlog(0, "off = %u, num = %u\n", bit_off, num_bits);
 
@@ -1407,11 +1472,15 @@
 
 	mlog_entry_void();
 
-	OCFS2_BUG_ON_INVALID_DINODE(fe);
+	if (!OCFS2_IS_VALID_DINODE(fe)) {
+		OCFS2_RO_ON_INVALID_DINODE(alloc_inode->i_sb, fe);
+		status = -EIO;
+		goto bail;
+	}
 	BUG_ON((count + start_bit) > ocfs2_bits_per_group(cl));
 
 	mlog(0, "suballocator %"MLFu64": freeing %u bits from group %"MLFu64
-	        ", starting at %u\n",
+	     ", starting at %u\n",
 	     OCFS2_I(alloc_inode)->ip_blkno, count, bg_blkno,
 	     start_bit);
 
@@ -1423,7 +1492,11 @@
 	}
 
 	group = (ocfs2_group_desc *) group_bh->b_data;
-	OCFS2_BUG_ON_INVALID_GROUP_DESC(group);
+	if (!OCFS2_IS_VALID_GROUP_DESC(group)) {
+		OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, group);
+		status = -EIO;
+		goto bail;
+	}
 	BUG_ON((count + start_bit) > le16_to_cpu(group->bg_bits));
 
 	status = ocfs2_block_group_clear_bits(handle, alloc_inode,

Modified: branches/locking-changes/fs/ocfs2/super.c
===================================================================
--- branches/locking-changes/fs/ocfs2/super.c	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/super.c	2005-09-22 17:39:57 UTC (rev 2603)
@@ -51,6 +51,7 @@
 
 #include "alloc.h"
 #include "dlmglue.h"
+#include "export.h"
 #include "extent_map.h"
 #include "heartbeat.h"
 #include "inode.h"
@@ -87,9 +88,11 @@
 MODULE_AUTHOR("Oracle");
 MODULE_LICENSE("GPL");
 
-static int ocfs2_parse_options(char *options, unsigned long *mount_opt);
+static int ocfs2_parse_options(struct super_block *sb, char *options,
+			       unsigned long *mount_opt, int is_remount);
 static void ocfs2_put_super(struct super_block *sb);
-static int ocfs2_mount_volume(struct super_block *sb, unsigned long mount_opt);
+static int ocfs2_mount_volume(struct super_block *sb);
+static int ocfs2_remount(struct super_block *sb, int *flags, char *data);
 static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err);
 static int ocfs2_initialize_mem_caches(void);
 static void ocfs2_free_mem_caches(void);
@@ -107,7 +110,9 @@
 static int ocfs2_verify_volume(ocfs2_dinode *di,
 			       struct buffer_head *bh,
 			       u32 sectsize);
-static int ocfs2_initialize_osb(ocfs2_super *osb, struct buffer_head *bh);
+static int ocfs2_initialize_super(struct super_block *sb,
+				  struct buffer_head *bh,
+				  int sector_size);
 static int ocfs2_get_sector(struct super_block *sb,
 			    struct buffer_head **bh,
 			    int block,
@@ -128,31 +133,38 @@
 	.sync_fs	= ocfs2_sync_fs,
 	.write_super	= ocfs2_write_super,
 	.put_super	= ocfs2_put_super,
+	.remount_fs	= ocfs2_remount,
 };
 
-static struct export_operations ocfs2_export_ops = {
-	.get_parent	= ocfs2_get_parent,
-};
-
 #ifdef OCFS2_ORACORE_WORKAROUNDS
 #define OCFS_SUPER_MAGIC		0xa156f7eb
 #endif
 
 enum {
-	Opt_hbok,
 	Opt_barrier,
+	Opt_err_panic,
+	Opt_err_ro,
 #ifdef OCFS2_ORACORE_WORKAROUNDS
 	Opt_datavolume,
 #endif
+	Opt_intr,
+	Opt_nointr,
+	Opt_hb_none,
+	Opt_hb_local,
 	Opt_err,
 };
 
 static match_table_t tokens = {
-	{Opt_hbok, OCFS2_HB_OK},
 	{Opt_barrier, "barrier=%u"},
+	{Opt_err_panic, "errors=panic"},
+	{Opt_err_ro, "errors=remount-ro"},
 #ifdef OCFS2_ORACORE_WORKAROUNDS
 	{Opt_datavolume, "datavolume"},
 #endif
+	{Opt_intr, "intr"},
+	{Opt_nointr, "nointr"},
+	{Opt_hb_none, OCFS2_HB_NONE},
+	{Opt_hb_local, OCFS2_HB_LOCAL},
 	{Opt_err, NULL}
 };
 
@@ -174,6 +186,9 @@
 
 	sb->s_dirt = 0;
 
+	if (ocfs2_is_hard_readonly(osb))
+		return -EROFS;
+
 	if (wait) {
 		status = ocfs2_flush_truncate_log(osb);
 		if (status < 0)
@@ -199,16 +214,16 @@
 	mlog_entry_void();
 
 	new = ocfs2_iget(osb, osb->root_blkno);
-	if (!new) {
-		status = -EINVAL;
+	if (IS_ERR(new)) {
+		status = PTR_ERR(new);
 		mlog_errno(status);
 		goto bail;
 	}
 	osb->root_inode = new;
 
 	new = ocfs2_iget(osb, osb->system_dir_blkno);
-	if (!new) {
-		status = -EINVAL;
+	if (IS_ERR(new)) {
+		status = PTR_ERR(new);
 		mlog_errno(status);
 		goto bail;
 	}
@@ -346,13 +361,158 @@
 	return (((unsigned long long)pagefactor) << bitshift) - 1;
 }
 
+static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
+{
+	int incompat_features;
+	int ret = 0;
+	unsigned long parsed_options;
+	ocfs2_super *osb = OCFS2_SB(sb);
+
+	if (!ocfs2_parse_options(sb, data, &parsed_options, 1)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* We're going to/from readonly mode. */
+	if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) {
+		/* Lock here so the check of HARD_RO and the potential
+		 * setting of SOFT_RO is atomic. */
+		spin_lock(&osb->osb_lock);
+		if (osb->osb_flags & OCFS2_OSB_HARD_RO) {
+			mlog(ML_ERROR, "Remount on readonly device is forbidden.\n");
+			ret = -EROFS;
+			goto unlock_osb;
+		}
+
+		if (*flags & MS_RDONLY) {
+			mlog(0, "Going to ro mode.\n");
+			sb->s_flags |= MS_RDONLY;
+			osb->osb_flags |= OCFS2_OSB_SOFT_RO;
+		} else {
+			mlog(0, "Making ro filesystem writeable.\n");
+
+			if (osb->osb_flags & OCFS2_OSB_ERROR_FS) {
+				mlog(ML_ERROR, "Cannot remount RDWR "
+				     "filesystem due to previous errors.\n");
+				ret = -EROFS;
+				goto unlock_osb;
+			}
+			incompat_features = OCFS2_HAS_RO_COMPAT_FEATURE(sb, ~OCFS2_FEATURE_RO_COMPAT_SUPP);
+			if (incompat_features) {
+				mlog(ML_ERROR, "Cannot remount RDWR because "
+				     "of unsupported optional features "
+				     "(%x).\n", incompat_features);
+				ret = -EINVAL;
+				goto unlock_osb;
+			}
+			sb->s_flags &= ~MS_RDONLY;
+			osb->osb_flags &= ~OCFS2_OSB_SOFT_RO;
+		}
+unlock_osb:
+		spin_unlock(&osb->osb_lock);
+	}
+
+	if (!ret) {
+		if (!ocfs2_is_hard_readonly(osb))
+			ocfs2_set_journal_params(osb);
+
+		/* Only save off the new mount options in case of a successful
+		 * remount. */
+		osb->s_mount_opt = parsed_options;
+	}
+out:
+	return ret;
+}
+
+static int ocfs2_sb_probe(struct super_block *sb,
+			  struct buffer_head **bh,
+			  int *sector_size)
+{
+	int status = 0, tmpstat;
+	ocfs1_vol_disk_hdr *hdr;
+	ocfs2_dinode *di;
+	int blksize;
+
+	*bh = NULL;
+
+	/* may be > 512 */
+	*sector_size = bdev_hardsect_size(sb->s_bdev);
+	if (*sector_size > OCFS2_MAX_BLOCKSIZE) {
+		mlog(ML_ERROR, "Hardware sector size too large: %d (max=%d)\n",
+		     *sector_size, OCFS2_MAX_BLOCKSIZE);
+		status = -EINVAL;
+		goto bail;
+	}
+
+	/* Can this really happen? */
+	if (*sector_size < OCFS2_MIN_BLOCKSIZE)
+		*sector_size = OCFS2_MIN_BLOCKSIZE;
+
+	/* check block zero for old format */
+	status = ocfs2_get_sector(sb, bh, 0, *sector_size);
+	if (status < 0) {
+		mlog_errno(status);
+		goto bail;
+	}
+	hdr = (ocfs1_vol_disk_hdr *) (*bh)->b_data;
+	if (hdr->major_version == OCFS1_MAJOR_VERSION) {
+		mlog(ML_ERROR, "incompatible version: %u.%u\n",
+		     hdr->major_version, hdr->minor_version);
+		status = -EINVAL;
+	}
+	if (memcmp(hdr->signature, OCFS1_VOLUME_SIGNATURE,
+		   strlen(OCFS1_VOLUME_SIGNATURE)) == 0) {
+		mlog(ML_ERROR, "incompatible volume signature: %8s\n",
+		     hdr->signature);
+		status = -EINVAL;
+	}
+	brelse(*bh);
+	*bh = NULL;
+	if (status < 0) {
+		mlog(ML_ERROR, "This is an ocfs v1 filesystem which must be "
+		     "upgraded before mounting with ocfs v2\n");
+		goto bail;
+	}
+
+	/*
+	 * Now check at magic offset for 512, 1024, 2048, 4096
+	 * blocksizes.  4096 is the maximum blocksize because it is
+	 * the minimum clustersize.
+	 */
+	status = -EINVAL;
+	for (blksize = *sector_size;
+	     blksize <= OCFS2_MAX_BLOCKSIZE;
+	     blksize <<= 1) {
+		tmpstat = ocfs2_get_sector(sb, bh,
+					   OCFS2_SUPER_BLOCK_BLKNO,
+					   blksize);
+		if (tmpstat < 0) {
+			status = tmpstat;
+			mlog_errno(status);
+			goto bail;
+		}
+		di = (ocfs2_dinode *) (*bh)->b_data;
+		status = ocfs2_verify_volume(di, *bh, blksize);
+		if (status >= 0)
+			goto bail;
+		brelse(*bh);
+		*bh = NULL;
+		if (status != -EAGAIN)
+			break;
+	}
+
+bail:
+	return status;
+}
+
 static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct dentry *root;
-	int status;
+	int status, sector_size;
+	unsigned long parsed_opt;
 	struct inode *inode = NULL;
 	ocfs2_super *osb = NULL;
-	unsigned long mount_opt = 0;
+	struct buffer_head *bh = NULL;
 
 	mlog_entry("%p, %p, %i", sb, data, silent);
 
@@ -363,47 +523,95 @@
 		goto read_super_error;
 	}
 
-	if (!ocfs2_parse_options(data, &mount_opt)) {
-		status = -EINVAL;
+	/* probe for superblock */
+	status = ocfs2_sb_probe(sb, &bh, &sector_size);
+	if (status < 0) {
+		mlog(ML_ERROR, "superblock probe failed!\n");
 		goto read_super_error;
 	}
 
-	/* Stopgap check to ensure that mount.ocfs2 mounted the volume */
-	if (!(mount_opt & OCFS2_MOUNT_HB_OK)) {
-		  mlog(ML_ERROR, "No heartbeat for device (%s)\n", sb->s_id);
-		  status = -EINVAL;
-		  goto read_super_error;
+	status = ocfs2_initialize_super(sb, bh, sector_size);
+	osb = OCFS2_SB(sb);
+	if (status < 0) {
+		mlog_errno(status);
+		goto read_super_error;
 	}
+	brelse(bh);
+	bh = NULL;
 
+	if (!ocfs2_parse_options(sb, data, &parsed_opt, 0)) {
+		status = -EINVAL;
+		goto read_super_error;
+	}
+	osb->s_mount_opt = parsed_opt;
+
 #ifdef OCFS2_ORACORE_WORKAROUNDS
-	if (mount_opt & OCFS2_MOUNT_COMPAT_OCFS)
+	if (osb->s_mount_opt & OCFS2_MOUNT_COMPAT_OCFS)
 		sb->s_magic = OCFS_SUPER_MAGIC;
 	else
 #endif
 		sb->s_magic = OCFS2_SUPER_MAGIC;
-	sb->s_op = &ocfs2_sops;
-	sb->s_export_op = &ocfs2_export_ops;
-	sb->s_flags |= MS_NOATIME;
-	sb->s_fs_info = NULL;
 
-	status = ocfs2_mount_volume(sb, mount_opt);
-	/* ocfs2_mount_volume may set osb even on error so we want to
-	 * pull it off for proper cleanup. */
-	osb = OCFS2_SB(sb);
-	if (osb && osb->root_inode)
+	/* Hard readonly mode only if: bdev_read_only, MS_RDONLY,
+	 * heartbeat=none */
+	if (bdev_read_only(sb->s_bdev)) {
+		if (!(sb->s_flags & MS_RDONLY)) {
+			status = -EACCES;
+			mlog(ML_ERROR, "Readonly device detected but readonly "
+			     "mount was not specified.\n");
+			goto read_super_error;
+		}
+
+		/* You should not be able to start a local heartbeat
+		 * on a readonly device. */
+		if (osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL) {
+			status = -EROFS;
+			mlog(ML_ERROR, "Local heartbeat specified on readonly "
+			     "device.\n");
+			goto read_super_error;
+		}
+
+		status = ocfs2_check_journals_nolocks(osb);
+		if (status < 0) {
+			if (status == -EROFS)
+				mlog(ML_ERROR, "Recovery required on readonly "
+				     "file system, but write access is "
+				     "unavailable.\n");
+			else
+				mlog_errno(status);			
+			goto read_super_error;
+		}
+
+		ocfs2_set_ro_flag(osb, 1);
+
+		printk(KERN_NOTICE "Readonly device detected. No cluster "
+		       "services will be utilized for this mount. Recovery "
+		       "will be skipped.\n");
+	}
+
+	if (!ocfs2_is_hard_readonly(osb)) {
+		/* If this isn't a hard readonly mount, then we need
+		 * to make sure that heartbeat is in a valid state,
+		 * and that we mark ourselves soft readonly is -oro
+		 * was specified. */
+		if (!(osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL)) {
+			mlog(ML_ERROR, "No heartbeat for device (%s)\n",
+			     sb->s_id);
+			status = -EINVAL;
+			goto read_super_error;
+		}
+
+		if (sb->s_flags & MS_RDONLY)
+			ocfs2_set_ro_flag(osb, 0);
+	}
+
+	status = ocfs2_mount_volume(sb);
+	if (osb->root_inode)
 		inode = igrab(osb->root_inode);
 
 	if (status < 0)
 		goto read_super_error;
 
-	/* this is needed to support O_LARGEFILE */
-	sb->s_maxbytes = ocfs2_max_file_offset(sb->s_blocksize_bits);
-
-	if (!osb) {
-		status = -EINVAL;
-		goto read_super_error;
-	}
-
 	if (!inode) {
 		status = -EIO;
 		mlog_errno(status);
@@ -432,6 +640,9 @@
 	return status;
 
 read_super_error:
+	if (bh != NULL)
+		brelse(bh);
+
 	if (inode)
 		iput(inode);
 
@@ -465,13 +676,19 @@
 	.next           = NULL
 };
 
-static int ocfs2_parse_options(char *options, unsigned long *mount_opt)
+static int ocfs2_parse_options(struct super_block *sb,
+			       char *options,
+			       unsigned long *mount_opt,
+			       int is_remount)
 {
 	int status;
 	char *p;
 
-	mlog_entry("options: \"%s\"\n", options ? options : "(none)");
+	mlog_entry("remount: %d, options: \"%s\"\n", is_remount,
+		   options ? options : "(none)");
 
+	*mount_opt = 0;
+
 	if (!options) {
 		status = 1;
 		goto bail;
@@ -486,9 +703,12 @@
 
 		token = match_token(p, tokens, args);
 		switch (token) {
-		case Opt_hbok:
-			*mount_opt |= OCFS2_MOUNT_HB_OK;
+		case Opt_hb_local:
+			*mount_opt |= OCFS2_MOUNT_HB_LOCAL;
 			break;
+		case Opt_hb_none:
+			*mount_opt &= ~OCFS2_MOUNT_HB_LOCAL;
+			break;
 		case Opt_barrier:
 			if (match_int(&args[0], &option)) {
 				status = 0;
@@ -499,8 +719,26 @@
 			else
 				*mount_opt &= ~OCFS2_MOUNT_BARRIER;
 			break;
+		case Opt_intr:
+			*mount_opt &= ~OCFS2_MOUNT_NOINTR;
+			break;
+		case Opt_nointr:
+			*mount_opt |= OCFS2_MOUNT_NOINTR;
+			break;
+		case Opt_err_panic:
+			*mount_opt |= OCFS2_MOUNT_ERRORS_PANIC;
+			break;
+		case Opt_err_ro:
+			*mount_opt &= ~OCFS2_MOUNT_ERRORS_PANIC;
+			break;
 #ifdef OCFS2_ORACORE_WORKAROUNDS
 		case Opt_datavolume:
+			if (is_remount) {
+				mlog(ML_ERROR, "Cannot specifiy datavolume "
+				     "on remount.\n");
+				status = 0;
+				goto bail;
+			}
 			*mount_opt |= OCFS2_MOUNT_COMPAT_OCFS;
 			break;
 #endif
@@ -731,87 +969,6 @@
 	ocfs2_lock_cache = NULL;
 }
 
-static int ocfs2_sb_probe(struct super_block *sb,
-			  struct buffer_head **bh,
-			  int *sector_size)
-{
-	int status = 0, tmpstat;
-	ocfs1_vol_disk_hdr *hdr;
-	ocfs2_dinode *di;
-	int blksize;
-
-	*bh = NULL;
-
-	/* may be > 512 */
-	*sector_size = bdev_hardsect_size(sb->s_bdev);
-	if (*sector_size > OCFS2_MAX_BLOCKSIZE) {
-		mlog(ML_ERROR, "Hardware sector size too large: %d (max=%d)\n",
-		     *sector_size, OCFS2_MAX_BLOCKSIZE);
-		status = -EINVAL;
-		goto bail;
-	}
-
-	/* Can this really happen? */
-	if (*sector_size < OCFS2_MIN_BLOCKSIZE)
-		*sector_size = OCFS2_MIN_BLOCKSIZE;
-
-	/* check block zero for old format */
-	status = ocfs2_get_sector(sb, bh, 0, *sector_size);
-	if (status < 0) {
-		mlog_errno(status);
-		goto bail;
-	}
-	hdr = (ocfs1_vol_disk_hdr *) (*bh)->b_data;
-	if (hdr->major_version == OCFS1_MAJOR_VERSION) {
-		mlog(ML_ERROR, "incompatible version: %u.%u\n",
-		     hdr->major_version, hdr->minor_version);
-		status = -EINVAL;
-	}
-	if (memcmp(hdr->signature, OCFS1_VOLUME_SIGNATURE,
-		   strlen(OCFS1_VOLUME_SIGNATURE)) == 0) {
-		mlog(ML_ERROR, "incompatible volume signature: %8s\n",
-		     hdr->signature);
-		status = -EINVAL;
-	}
-	brelse(*bh);
-	*bh = NULL;
-	if (status < 0) {
-		mlog(ML_ERROR, "This is an ocfs v1 filesystem which must be "
-		     "upgraded before mounting with ocfs v2\n");
-		goto bail;
-	}
-
-	/*
-	 * Now check at magic offset for 512, 1024, 2048, 4096
-	 * blocksizes.  4096 is the maximum blocksize because it is
-	 * the minimum clustersize.
-	 */
-	status = -EINVAL;
-	for (blksize = *sector_size;
-	     blksize <= OCFS2_MAX_BLOCKSIZE;
-	     blksize <<= 1) {
-		tmpstat = ocfs2_get_sector(sb, bh,
-					   OCFS2_SUPER_BLOCK_BLKNO,
-					   blksize);
-		if (tmpstat < 0) {
-			status = tmpstat;
-			mlog_errno(status);
-			goto bail;
-		}
-		di = (ocfs2_dinode *) (*bh)->b_data;
-		status = ocfs2_verify_volume(di, *bh, blksize);
-		if (status >= 0)
-			goto bail;
-		brelse(*bh);
-		*bh = NULL;
-		if (status != -EAGAIN)
-			break;
-	}
-
-bail:
-	return status;
-}
-
 static int ocfs2_get_sector(struct super_block *sb,
 			    struct buffer_head **bh,
 			    int block,
@@ -857,46 +1014,17 @@
 	return status;
 }
 
-static int ocfs2_mount_volume(struct super_block *sb, unsigned long mount_opt)
+static int ocfs2_mount_volume(struct super_block *sb)
 {
-	int status, sector_size;
+	int status = 0;
 	int unlock_super = 0;
-	ocfs2_super *osb = NULL;
-	struct buffer_head *bh = NULL;
+	ocfs2_super *osb = OCFS2_SB(sb);
 
 	mlog_entry_void();
 
-	/* probe for superblock */
-	status = ocfs2_sb_probe(sb, &bh, &sector_size);
-	if (status < 0) {
-		mlog(ML_ERROR, "superblock probe failed!\n");
-		goto leave;
-	}
+	if (ocfs2_is_hard_readonly(osb))
+		goto out_add_proc;
 
-	osb = kcalloc(1, sizeof(ocfs2_super), GFP_KERNEL);
-	if (!osb) {
-		status = -ENOMEM;
-		mlog_errno(status);
-		goto leave;
-	}
-
-	sb->s_fs_info = osb;
-	osb->sb = sb;
-
-	osb->s_mount_opt = mount_opt;
-
-	/* Save off for ocfs2_rw_direct */
-	osb->s_sectsize_bits = blksize_bits(sector_size);
-	if (!osb->s_sectsize_bits)
-		BUG();
-
-	/* s_blocksize was set in the probe */
-	status = ocfs2_initialize_osb(osb, bh);
-	if (status < 0) {
-		mlog_errno(status);
-		goto leave;
-	}
-
 	status = ocfs2_fill_local_node_info(osb);
 	if (status < 0) {
 		mlog_errno(status);
@@ -945,10 +1073,6 @@
 		goto leave;
 	}
 
-	/* Add proc entry for this volume */
-	ocfs2_proc_add_volume(osb);
-
-	mlog(0, "ocfs2_check_volume...\n");
 	status = ocfs2_check_volume(osb);
 	if (status < 0) {
 		mlog_errno(status);
@@ -970,12 +1094,14 @@
 	if (status < 0)
 		mlog_errno(status);
 
+out_add_proc:
+	/* Add proc entry for this volume */
+	ocfs2_proc_add_volume(osb);
+
 leave:
 	if (unlock_super)
 		ocfs2_super_unlock(osb, 1);
 
-	if (bh != NULL)
-		brelse(bh);
 	mlog_exit(status);
 	return status;
 }
@@ -1092,7 +1218,9 @@
 	return 0;
 }
 
-static int ocfs2_initialize_osb(ocfs2_super *osb, struct buffer_head *bh)
+static int ocfs2_initialize_super(struct super_block *sb,
+				  struct buffer_head *bh,
+				  int sector_size)
 {
 	int status = 0;
 	int i;
@@ -1101,9 +1229,30 @@
 	struct buffer_head *bitmap_bh = NULL;
 	ocfs2_journal *journal;
 	__le32 uuid_net_key;
+	ocfs2_super *osb;
 
 	mlog_entry_void();
 
+	osb = kcalloc(1, sizeof(ocfs2_super), GFP_KERNEL);
+	if (!osb) {
+		status = -ENOMEM;
+		mlog_errno(status);
+		goto bail;
+	}
+
+	sb->s_fs_info = osb;
+	sb->s_op = &ocfs2_sops;
+	sb->s_export_op = &ocfs2_export_ops;
+	sb->s_flags |= MS_NOATIME;
+	/* this is needed to support O_LARGEFILE */
+	sb->s_maxbytes = ocfs2_max_file_offset(sb->s_blocksize_bits);
+
+	osb->sb = sb;
+	/* Save off for ocfs2_rw_direct */
+	osb->s_sectsize_bits = blksize_bits(sector_size);
+	if (!osb->s_sectsize_bits)
+		BUG();
+
 	osb->net_response_ids = 0;
 	spin_lock_init(&osb->net_response_lock);
 	INIT_LIST_HEAD(&osb->net_response_list);
@@ -1117,7 +1266,7 @@
 	INIT_LIST_HEAD(&osb->blocked_lock_list);
 	osb->blocked_lock_count = 0;
 	INIT_LIST_HEAD(&osb->vote_list);
-	spin_lock_init(&osb->s_next_gen_lock);
+	spin_lock_init(&osb->osb_lock);
 
 	atomic_set(&osb->alloc_stats.moves, 0);
 	atomic_set(&osb->alloc_stats.local_data, 0);
@@ -1463,7 +1612,6 @@
 	return status;
 }
 
-
 /*
  * The routine gets called from dismount or close whenever a dismount on
  * volume is requested and the osb open count becomes 1.
@@ -1493,5 +1641,80 @@
 	mlog_exit_void();
 }
 
+/* Put OCFS2 into a readonly state, or (if the user specifies it),
+ * panic(). We do not support continue-on-error operation. */
+static void ocfs2_handle_error(struct super_block *sb)
+{
+	ocfs2_super *osb = OCFS2_SB(sb);
+
+	if (osb->s_mount_opt & OCFS2_MOUNT_ERRORS_PANIC)
+		panic("OCFS2: (device %s): panic forced after error\n",
+		      sb->s_id);
+
+	ocfs2_set_osb_flag(osb, OCFS2_OSB_ERROR_FS);
+
+	if (sb->s_flags & MS_RDONLY &&
+	    (ocfs2_is_soft_readonly(osb) ||
+	     ocfs2_is_hard_readonly(osb)))
+		return;
+
+	printk(KERN_CRIT "File system is now read-only due to the potential "
+	       "of on-disk corruption. Please run fsck.ocfs2 once the file "
+	       "system is unmounted.\n");
+	sb->s_flags |= MS_RDONLY;
+	ocfs2_set_ro_flag(osb, 0);
+}
+
+static char error_buf[1024];
+
+void __ocfs2_error(struct super_block *sb,
+		   const char *function,
+		   const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	vsprintf(error_buf, fmt, args);
+	va_end(args);
+
+	/* Not using mlog here because we want to show the actual
+	 * function the error came from. */
+	printk(KERN_CRIT "OCFS2: ERROR (device %s): %s: %s\n",
+	       sb->s_id, function, error_buf);
+
+	ocfs2_handle_error(sb);
+}
+
+/* Handle critical errors. This is intentionally more drastic than
+ * ocfs2_handle_error, so we only use for things like journal errors,
+ * etc. */
+void __ocfs2_abort(struct super_block* sb,
+		   const char *function,
+		   const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	vsprintf(error_buf, fmt, args);
+	va_end(args);
+
+	printk(KERN_CRIT "OCFS2: abort (device %s): %s: %s\n",
+	       sb->s_id, function, error_buf);
+
+	/* We don't have the cluster support yet to go straight to
+	 * hard readonly in here. Until then, we want to keep
+	 * ocfs2_abort() so that we can at least mark critical
+	 * errors.
+	 *
+	 * TODO: This should abort the journal and alert other nodes
+	 * that our slot needs recovery. */
+
+	/* Force a panic(). This stinks, but it's better than letting
+	 * things continue without having a proper hard readonly
+	 * here. */
+	OCFS2_SB(sb)->s_mount_opt |= OCFS2_MOUNT_ERRORS_PANIC;
+	ocfs2_handle_error(sb);
+}
+
 module_init(ocfs2_init);
 module_exit(ocfs2_exit);

Modified: branches/locking-changes/fs/ocfs2/super.h
===================================================================
--- branches/locking-changes/fs/ocfs2/super.h	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/super.h	2005-09-22 17:39:57 UTC (rev 2603)
@@ -31,4 +31,14 @@
 int ocfs2_publish_get_mount_state(ocfs2_super *osb,
 				  int node_num);
 
+void __ocfs2_error(struct super_block *sb,
+		   const char *function,
+		   const char *fmt, ...);
+#define ocfs2_error(sb, fmt, args...) __ocfs2_error(sb, __PRETTY_FUNCTION__, fmt, ##args)
+
+void __ocfs2_abort(struct super_block *sb,
+		   const char *function,
+		   const char *fmt, ...);
+#define ocfs2_abort(sb, fmt, args...) __ocfs2_abort(sb, __PRETTY_FUNCTION__, fmt, ##args)
+
 #endif /* OCFS2_SUPER_H */

Modified: branches/locking-changes/fs/ocfs2/symlink.c
===================================================================
--- branches/locking-changes/fs/ocfs2/symlink.c	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/symlink.c	2005-09-22 17:39:57 UTC (rev 2603)
@@ -377,8 +377,13 @@
 }
 #endif
 
+#ifndef NEW_FOLLOW_LINK_API
 static int ocfs2_follow_link(struct dentry *dentry,
 			     struct nameidata *nd)
+#else
+static void *ocfs2_follow_link(struct dentry *dentry,
+			       struct nameidata *nd)
+#endif
 {
 	int status;
 	char *link;
@@ -411,7 +416,11 @@
 	if (bh)
 		brelse(bh);
 
+#ifndef NEW_FOLLOW_LINK_API
 	return status;
+#else
+	return ERR_PTR(status);
+#endif
 }
 
 struct inode_operations ocfs2_symlink_inode_operations = {

Modified: branches/locking-changes/fs/ocfs2/sysfile.c
===================================================================
--- branches/locking-changes/fs/ocfs2/sysfile.c	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/sysfile.c	2005-09-22 17:39:57 UTC (rev 2603)
@@ -118,8 +118,9 @@
 	}
 
 	inode = ocfs2_iget(osb, blkno);
-	if (!inode) {
-		mlog(ML_ERROR, "Could not create inode!\n");
+	if (IS_ERR(inode)) {
+		mlog_errno(PTR_ERR(inode));
+		inode = NULL;
 		goto bail;
 	}
 bail:

Modified: branches/locking-changes/fs/ocfs2/vote.c
===================================================================
--- branches/locking-changes/fs/ocfs2/vote.c	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/fs/ocfs2/vote.c	2005-09-22 17:39:57 UTC (rev 2603)
@@ -817,7 +817,8 @@
 
 	status = -EAGAIN;
 	while (status == -EAGAIN) {
-		if (signal_pending(current))
+		if (!(osb->s_mount_opt & OCFS2_MOUNT_NOINTR) &&
+		    signal_pending(current))
 			return -ERESTARTSYS;
 
 		status = ocfs2_super_lock(osb, 0);
@@ -982,7 +983,8 @@
 
 	status = -EAGAIN;
 	while (status == -EAGAIN) {
-		if (signal_pending(current)) {
+		if (!(osb->s_mount_opt & OCFS2_MOUNT_NOINTR) &&
+		    signal_pending(current)) {
 			status = -ERESTARTSYS;
 			goto bail;
 		}

Modified: branches/locking-changes/vendor/redhat/ocfs2-2.6.9-EL.spec-generic.in
===================================================================
--- branches/locking-changes/vendor/redhat/ocfs2-2.6.9-EL.spec-generic.in	2005-09-22 16:45:24 UTC (rev 2602)
+++ branches/locking-changes/vendor/redhat/ocfs2-2.6.9-EL.spec-generic.in	2005-09-22 17:39:57 UTC (rev 2603)
@@ -28,6 +28,12 @@
 %define buildhugemem	0
 %endif
 
+%ifarch s390x
+%define karch s390x
+%define buildsmp	0
+%define buildhugemem	0
+%endif
+
 %define base		2.6.9
 %define sver		%{generic}
 %define kver		%{base}-%{sver}.EL



More information about the Ocfs2-commits mailing list