[Ocfs2-tools-commits] zab commits r368 - in trunk: fsck.ocfs2 fsck.ocfs2/include libocfs2 libocfs2/include

svn-commits at oss.oracle.com svn-commits at oss.oracle.com
Fri Nov 5 22:54:14 CST 2004


Author: zab
Date: 2004-11-05 22:54:12 -0600 (Fri, 05 Nov 2004)
New Revision: 368

Modified:
   trunk/fsck.ocfs2/Makefile
   trunk/fsck.ocfs2/fsck.c
   trunk/fsck.ocfs2/include/fsck.h
   trunk/fsck.ocfs2/include/pass2.h
   trunk/fsck.ocfs2/pass0.c
   trunk/fsck.ocfs2/pass1.c
   trunk/fsck.ocfs2/pass2.c
   trunk/fsck.ocfs2/pass3.c
   trunk/fsck.ocfs2/pass4.c
   trunk/libocfs2/Makefile
   trunk/libocfs2/alloc.c
   trunk/libocfs2/bitmap.c
   trunk/libocfs2/chainalloc.c
   trunk/libocfs2/include/bitmap.h
   trunk/libocfs2/include/ocfs2.h
   trunk/libocfs2/openfs.c
Log:
o add a lib helper to test the lib's in-memory allocators for a given inode
o read each node's allocator into memory late in pass0 after checking it
o sync each inode's bit in the allocators as it is iterated over in pass 1
o ask to write back chain allocators if we change them during pass 1
o after pass1 trust the lib to manage the chain allocators
o do pass4 with iteration and the allocators instead of fsck's redundant bitmap
o only use -O when building with debugging to make life suck less
o bring each node's allocator into ocfs2_filesys when needed
o add ocfs2_bitmap_foreach_region so chainalloc can iterate when writing
o add a bit_change_notify bitmap callback so chainalloc can keep counts in sync
o free the group descs when we free chain alloc's region private
o track dirty groups and inodes in chainalloc and write them when asked


Modified: trunk/fsck.ocfs2/Makefile
===================================================================
--- trunk/fsck.ocfs2/Makefile	2004-11-05 20:50:15 UTC (rev 367)
+++ trunk/fsck.ocfs2/Makefile	2004-11-06 04:54:12 UTC (rev 368)
@@ -7,8 +7,13 @@
 INCLUDES = -Iinclude -I$(TOPDIR)/libocfs2/include
 LIBOCFS2_LIBS = -L$(TOPDIR)/libocfs2 -locfs2
 
-# -O2 to get uninitialized warnings from gcc.
-CFLAGS := -O2 -g -Wall -Wstrict-prototypes -Wmissing-prototypes \
+ifdef OCFS_DEBUG
+OPTS += -O -g
+else
+OPTS += -O2
+endif
+
+CFLAGS := $(OPTS) -Wall -Wstrict-prototypes -Wmissing-prototypes \
            -Wmissing-declarations
 
 DEFINES = -DOCFS2_FLAT_INCLUDES

Modified: trunk/fsck.ocfs2/fsck.c
===================================================================
--- trunk/fsck.ocfs2/fsck.c	2004-11-05 20:50:15 UTC (rev 367)
+++ trunk/fsck.ocfs2/fsck.c	2004-11-06 04:54:12 UTC (rev 368)
@@ -114,13 +114,6 @@
 		return ret;
 	}
 
-	ret = ocfs2_block_bitmap_new(fs, "inodes in use", 
-				     &ost->ost_used_inodes);
-	if (ret) {
-		com_err(whoami, ret, "while allocating used inodes bitmap");
-		return ret;
-	}
-
 	ret = ocfs2_block_bitmap_new(fs, "inodes with bad fields", 
 				     &ost->ost_bad_inodes);
 	if (ret) {

Modified: trunk/fsck.ocfs2/include/fsck.h
===================================================================
--- trunk/fsck.ocfs2/include/fsck.h	2004-11-05 20:50:15 UTC (rev 367)
+++ trunk/fsck.ocfs2/include/fsck.h	2004-11-06 04:54:12 UTC (rev 368)
@@ -30,7 +30,9 @@
 typedef struct _o2fsck_state {
 	ocfs2_filesys 	*ost_fs;
 
-	ocfs2_bitmap	*ost_used_inodes;
+	ocfs2_cached_inode	*ost_global_inode_alloc;
+	ocfs2_cached_inode	**ost_inode_allocs;
+
 	ocfs2_bitmap	*ost_bad_inodes;
 	ocfs2_bitmap	*ost_dir_inodes;
 	ocfs2_bitmap	*ost_reg_inodes;
@@ -52,10 +54,11 @@
 
 	struct rb_root	ost_dir_parents;
 
-	/* flags */
 	unsigned	ost_ask:1,	/* confirm with the user */
 			ost_answer:1,	/* answer if we don't ask the user */
-			ost_force:1;	/* -f supplied; force check */
+			ost_force:1,	/* -f supplied; force check */
+			ost_write_inode_alloc_asked:1,
+			ost_write_inode_alloc:1;
 } o2fsck_state;
 
 /* The idea is to let someone off-site run fsck and have it give us 

Modified: trunk/fsck.ocfs2/include/pass2.h
===================================================================
--- trunk/fsck.ocfs2/include/pass2.h	2004-11-05 20:50:15 UTC (rev 367)
+++ trunk/fsck.ocfs2/include/pass2.h	2004-11-06 04:54:12 UTC (rev 368)
@@ -27,6 +27,7 @@
 #include "fsck.h"
 
 errcode_t o2fsck_pass2(o2fsck_state *ost);
+int o2fsck_test_inode_allocated(o2fsck_state *ost, uint64_t blkno);
 
 #endif /* __O2FSCK_PASS2_H__ */
 

Modified: trunk/fsck.ocfs2/pass0.c
===================================================================
--- trunk/fsck.ocfs2/pass0.c	2004-11-05 20:50:15 UTC (rev 367)
+++ trunk/fsck.ocfs2/pass0.c	2004-11-06 04:54:12 UTC (rev 368)
@@ -34,6 +34,7 @@
  * 	track used blocks that iteration won't see?
  * 	verify more inode fields?
  * 	use prompt to mark soft errors
+ * 	make sure blocks don't overlap as part of cluster tracking
  */
 
 #include <string.h>
@@ -396,6 +397,8 @@
 	char *blocks = NULL;
 	ocfs2_dinode *di = NULL;
 	ocfs2_filesys *fs = ost->ost_fs;
+	ocfs2_cached_inode **ci;
+	int max_nodes = OCFS2_RAW_SB(fs->fs_super)->s_max_nodes;
 	int i, type;
 
 	printf("Pass 0: Checking allocation structures\n");
@@ -407,12 +410,18 @@
 	}
 	di = (ocfs2_dinode *)blocks;
 
+	ret = ocfs2_malloc0(max_nodes * sizeof(ocfs2_cached_inode *), 
+			    &ost->ost_inode_allocs);
+	if (ret)
+		fatal_error(ret, "while allocating pointers for each nodes' "
+			    "inode allocator bitmaps");
+
 	/* first the global inode alloc and then each of the node's
 	 * inode allocators */
 	type = GLOBAL_INODE_ALLOC_SYSTEM_INODE;
 	i = -1;
 
-	do {
+	for ( ; i < max_nodes; i++, type = INODE_ALLOC_SYSTEM_INODE) {
 		ret = ocfs2_lookup_system_inode(fs, type, i, &blkno);
 		if (ret) {
 			com_err(whoami, ret, "while looking up the inode "
@@ -439,9 +448,28 @@
 		if (ret)
 			goto out;
 
-		type = INODE_ALLOC_SYSTEM_INODE;
-	} while (++i < OCFS2_RAW_SB(fs->fs_super)->s_max_nodes);
+		if (i == -1)
+			ci = &ost->ost_global_inode_alloc;
+		else
+			ci = &ost->ost_inode_allocs[i];
 
+		ret = ocfs2_read_cached_inode(ost->ost_fs, blkno, ci);
+		if (ret) {
+			com_err(whoami, ret, "while reading node %d's inode "
+				"allocator inode %"PRIu64, i, blkno);	
+			continue;
+		}
+
+		ret = ocfs2_load_chain_allocator(ost->ost_fs, *ci);
+		if (ret) {
+			com_err(whoami, ret, "while loading inode %"PRIu64" "
+				"as a chain allocator", blkno);
+			ocfs2_free_cached_inode(ost->ost_fs, *ci);
+			*ci = NULL;
+			continue;
+		}
+	}
+
 out:
 	/* errors are only returned to this guy if they're fatal -- memory
 	 * alloc or IO errors.  the.. returnee had the responsibility of 

Modified: trunk/fsck.ocfs2/pass1.c
===================================================================
--- trunk/fsck.ocfs2/pass1.c	2004-11-05 20:50:15 UTC (rev 367)
+++ trunk/fsck.ocfs2/pass1.c	2004-11-06 04:54:12 UTC (rev 368)
@@ -1,10 +1,6 @@
 /* -*- mode: c; c-basic-offset: 8; -*-
  * vim: noexpandtab sw=8 ts=8 sts=0:
  *
- * pass1.c
- *
- * file system checker for OCFS2
- *
  * Copyright (C) 2004 Oracle.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -21,7 +17,8 @@
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 021110-1307, USA.
  *
- * Authors: Zach Brown
+ * XXX
+ * 	make sure the inode's dtime/count/valid match in update_inode_alloc
  */
 #include <string.h>
 #include <inttypes.h>
@@ -52,13 +49,112 @@
 	return was_set;
 }
 
-/* XXX should walk down all the i_fields to make sure we're veryfying
+/* update our in memory images of the inode chain alloc bitmaps.  these
+ * will be written out at the end of pass1 and the library will read
+ * them off disk for use from then on.
+ *
+ * XXX this returns errors because inode iteration can return inode numbers
+ * that cause errors when given to the chain alloc bitmaps.  I'm sure its
+ * easy to fix. */
+static void update_inode_alloc(o2fsck_state *ost, ocfs2_dinode *di, 
+			       uint64_t blkno, int val)
+{
+	uint16_t node, max_nodes, yn;
+	errcode_t ret = OCFS2_ET_INTERNAL_FAILURE;
+	ocfs2_cached_inode *cinode;
+	int oldval;
+
+	val = !!val;
+
+	/* XXX we could skip all this if we're not going to write it out
+	 * anyway */
+
+	max_nodes = OCFS2_RAW_SB(ost->ost_fs->fs_super)->s_max_nodes;
+
+	verbosef("updating inode %"PRIu64" alloc to %d\n", blkno, val);
+
+	for (node = ~0; node != max_nodes; node++, 
+					   ret = OCFS2_ET_INTERNAL_FAILURE) {
+
+		if (node == (uint16_t)~0)
+			cinode = ost->ost_global_inode_alloc;
+		else
+			cinode = ost->ost_inode_allocs[node];
+
+		/* we might have had trouble reading the chains in pass 0 */
+		if (cinode == NULL)
+			continue;
+
+		if (val)
+			ret = ocfs2_bitmap_set(cinode->ci_chains, blkno,
+					       &oldval);
+		else
+			ret = ocfs2_bitmap_clear(cinode->ci_chains, blkno,
+						 &oldval);
+
+		com_err(whoami, ret, "node %"PRIu16, node);
+
+		if (ret) {
+		       	if (ret != OCFS2_ET_INVALID_BIT)
+				com_err(whoami, ret, "while trying to set "
+					"inode %"PRIu64"'s allocation to '%d' "
+					"in node %u's chain", blkno, val,
+					node);
+			continue;
+		}
+
+		/* this node covers the inode.  see if we've changed the 
+		 * bitmap and if the user wants us to keep tracking it and
+		 * write back the new map */
+		if (oldval != val && !ost->ost_write_inode_alloc_asked) {
+			yn = prompt(ost, PY, "fsck found an inode whose "
+				    "allocation does not match the chain "
+				    "allocators.  Fix the allocation of this "
+				    "and all future inodes?");
+			ost->ost_write_inode_alloc_asked = 1;
+			ost->ost_write_inode_alloc = !!yn;
+		}
+		break;
+	}
+
+	if (ret) {
+		com_err(whoami, ret, "while trying to set inode %"PRIu64"'s "
+			"allocation to '%d'.  None of the nodes chain "
+			"allocator's had a group covering the inode.",
+			blkno, val);
+		goto out;
+	}
+
+	verbosef("updated inode %"PRIu64" alloc to %d in node %"PRIu16"\n",
+		 blkno, val, node);
+
+	/* make sure the inode's fields are consistent if it's allocated */
+	if (val == 1 && node != (uint16_t)di->i_suballoc_node &&
+	    prompt(ost, PY, "Inode %"PRIu64" indicates that it was allocated "
+		   "from node %"PRIu16" but node %"PRIu16"'s chain allocator "
+		   "covers the inode.  Fix the inode's record of where it is "
+		   "allocated?",
+		   blkno, di->i_suballoc_node, node)) {
+		di->i_suballoc_node = node;
+		o2fsck_write_inode(ost->ost_fs, di->i_blkno, di);
+	}
+out:
+	return;
+}
+
+/* Check the basics of the ocfs2_dinode itself.  If we find problems
+ * we clear the VALID flag and the caller will see that and update
+ * inode allocations and write the inode to disk.
+ *
+ * XXX should walk down all the i_fields to make sure we're veryfying
  * those that we can this early */
 static void o2fsck_verify_inode_fields(ocfs2_filesys *fs, o2fsck_state *ost, 
 				       uint64_t blkno, ocfs2_dinode *di)
 {
-	int was_set;
+	int clear = 0;
 
+	verbosef("checking inode %"PRIu64"'s fields\n", blkno);
+
 	/* do we want to detect and delete corrupt system dir/files here
 	 * so we can recreate them later ? */
 
@@ -70,11 +166,12 @@
 	 * in use?  orphaned?  deleted?  garbage?) to understand what
 	 * fsck can do to fix it up */
 	if (memcmp(di->i_signature, OCFS2_INODE_SIGNATURE,
-		   strlen(OCFS2_INODE_SIGNATURE))) {
-		goto bad;
+		   strlen(OCFS2_INODE_SIGNATURE)) &&
+	    prompt(ost, PY, "Inode %"PRIu64" doesn't have a valid signature. "
+		   "Clear it?", blkno)) {
+		clear = 1;
+		goto out;
 	}
-	if (di->i_flags & OCFS2_SUPER_BLOCK_FL)
-		goto bad;
 
 	if (di->i_links_count)
 		o2fsck_icount_set(ost->ost_icount_in_inodes, di->i_blkno,
@@ -100,12 +197,6 @@
 		o2fsck_write_inode(fs, blkno, di);
 	}
 
-	ocfs2_bitmap_set(ost->ost_used_inodes, blkno, &was_set);
-	if (was_set) {
-		fprintf(stderr, "duplicate inode %"PRIu64"?\n", blkno);
-		goto bad;
-	}
-
 	if (S_ISDIR(di->i_mode)) {
 		ocfs2_bitmap_set(ost->ost_dir_inodes, blkno, NULL);
 		o2fsck_add_dir_parent(&ost->ost_dir_parents, blkno, 0, 0);
@@ -117,16 +208,19 @@
 		 * we walk the inode's blocks */
 	} else {
 		if (!S_ISCHR(di->i_mode) && !S_ISBLK(di->i_mode) &&
-			!S_ISFIFO(di->i_mode) && !S_ISSOCK(di->i_mode))
-			goto bad;
+		    !S_ISFIFO(di->i_mode) && !S_ISSOCK(di->i_mode)) {
+			clear = 1;
+			goto out;
+		}
 
 		/* i_size?  what other sanity testing for devices? */
 	}
 
-	return;
-bad:
-	/* XXX we don't actually do anything with this bitmap */
-	ocfs2_bitmap_set(ost->ost_bad_inodes, blkno, NULL);
+out:
+	if (clear) {
+		di->i_flags &= ~OCFS2_SUPER_BLOCK_FL;
+		o2fsck_write_inode(fs, blkno, di);
+	}
 }
 
 struct verifying_blocks {
@@ -389,6 +483,41 @@
 	}
 }
 
+static void write_inode_alloc(o2fsck_state *ost)
+{
+	int max_nodes = OCFS2_RAW_SB(ost->ost_fs->fs_super)->s_max_nodes;
+	ocfs2_cached_inode **ci;
+	errcode_t ret;
+	int i = -1;
+
+	if (!ost->ost_write_inode_alloc)
+		return;
+
+	for ( ; i < max_nodes; i++) {
+		if (i == -1)
+			ci = &ost->ost_global_inode_alloc;
+		else
+			ci = &ost->ost_inode_allocs[i];
+
+		if (*ci == NULL)
+			continue;
+
+		verbosef("writing node %d's allocator\n", i);
+
+		ret = ocfs2_write_chain_allocator(ost->ost_fs, *ci);
+		if (ret)
+			com_err(whoami, ret, "while trying to write back node "
+				"%d's inode allocator", i);
+
+		ret = ocfs2_free_cached_inode(ost->ost_fs, *ci);
+		if (ret)
+			com_err(whoami, ret, "while trying to free node %d's "
+				"inode allocator", i);
+
+		*ci = NULL;
+	}
+}
+
 errcode_t o2fsck_pass1(o2fsck_state *ost)
 {
 	errcode_t ret;
@@ -431,23 +560,26 @@
 			break;
 
 		/* scanners have to skip over uninitialized inodes */
-		if (!(di->i_flags & OCFS2_VALID_FL))
-			continue;
+		if (di->i_flags & OCFS2_VALID_FL) {
+			o2fsck_verify_inode_fields(fs, ost, blkno, di);
 
-		verbosef("found inode %"PRIu64"\n", blkno);
+			/* XXX be able to mark the blocks in the inode as 
+			 * bad if the inode was bad */
+			o2fsck_check_blocks(fs, ost, blkno, di);
+		}
 
-		o2fsck_verify_inode_fields(fs, ost, blkno, di);
-
-		/* XXX be able to mark the blocks in the inode as 
-		 * bad if the inode was bad */
-
-		o2fsck_check_blocks(fs, ost, blkno, di);
+		verbosef("blkno %"PRIu64" ino %"PRIu64"\n", blkno,
+				di->i_blkno);
+		update_inode_alloc(ost, di, blkno, 
+				   di->i_flags & OCFS2_VALID_FL);
 	}
 
 	if (ocfs2_bitmap_get_set_bits(ost->ost_dup_blocks))
 		fatal_error(OCFS2_ET_INTERNAL_FAILURE, "duplicate blocks "
 				"found, need to learn to fix.");
 
+	write_inode_alloc(ost);
+
 out_close_scan:
 	ocfs2_close_inode_scan(scan);
 out_free:

Modified: trunk/fsck.ocfs2/pass2.c
===================================================================
--- trunk/fsck.ocfs2/pass2.c	2004-11-05 20:50:15 UTC (rev 367)
+++ trunk/fsck.ocfs2/pass2.c	2004-11-06 04:54:12 UTC (rev 368)
@@ -37,6 +37,23 @@
 #include "strings.h"
 #include "util.h"
 
+static const char *whoami = "pass2";
+
+int o2fsck_test_inode_allocated(o2fsck_state *ost, uint64_t blkno)
+{
+	errcode_t ret;
+	int was_set;
+
+	ret = ocfs2_test_inode_allocated(ost->ost_fs, blkno, &was_set);
+	/* XXX this should stop fsck from marking the fs clean */
+	if (ret) {
+		com_err(whoami, ret, "while testing if inode %"PRIu64" is "
+			"allocated.  Continuing as though it is.", blkno);
+		was_set = 1;
+	}
+	return was_set;
+}
+
 struct dirblock_data {
 	o2fsck_state *ost;
 	ocfs2_filesys *fs;
@@ -232,8 +249,6 @@
 static int fix_dirent_inode(o2fsck_state *ost, o2fsck_dirblock_entry *dbe,
 				struct ocfs2_dir_entry *dirent, int offset)
 {
-	int was_set;
-
 	if (ocfs2_block_out_of_range(ost->ost_fs, dirent->inode)) {
 		if (prompt(ost, PY, "Directory entry '%.*s' refers to inode "
 			   "number %"PRIu64" which is out of range, "
@@ -244,16 +259,12 @@
 		}
 	}
 
-	/* XXX Do I care about possible bitmap_test errors here? */
-	ocfs2_bitmap_test(ost->ost_used_inodes, dirent->inode, &was_set);
-	if (!was_set) {
-		if (prompt(ost, PY, "Directory entry '%.*s' refers to inode "
-			   "number %"PRIu64" which is unused, clear the "
-			   "entry?", dirent->name_len, dirent->name, 
-			   dirent->inode)) {
-			dirent->inode = 0;
-			return OCFS2_DIRENT_CHANGED;
-		}
+	if (!o2fsck_test_inode_allocated(ost, dbe->e_ino) &&
+	    prompt(ost, PY, "Directory entry '%.*s' refers to inode number "
+		   "%"PRIu64" which isn't allocated, clear the entry?", 
+		   dirent->name_len, dirent->name, dirent->inode)) {
+		dirent->inode = 0;
+		return OCFS2_DIRENT_CHANGED;
 	}
 	return 0;
 }
@@ -421,8 +432,6 @@
 	return 0;
 }
 
-
-
 /* this could certainly be more clever to issue reads in groups */
 static unsigned pass2_dir_block_iterate(o2fsck_dirblock_entry *dbe, 
 					void *priv_data) 
@@ -431,16 +440,15 @@
 	struct ocfs2_dir_entry *dirent, *prev = NULL;
 	unsigned int offset = 0, this_flags, ret_flags = 0;
 	o2fsck_strings strings;
-	int was_set, dups_in_block = 0;
+	int dups_in_block = 0;
 	errcode_t retval;
 
-	retval = ocfs2_bitmap_test(dd->ost->ost_used_inodes, dbe->e_ino, 
-				  &was_set);
-	if (retval)
-		fatal_error(retval, "while checking for inode %"PRIu64" in "
-				"the used bitmap", dbe->e_ino);
-	if (!was_set)
+	if (!o2fsck_test_inode_allocated(dd->ost, dbe->e_ino)) {
+		printf("Directory block %"PRIu64" belongs to directory inode "
+		       "%"PRIu64" which isn't allocated.  Ignoring this "
+		       "block.", dbe->e_blkno, dbe->e_ino);
 		return 0;
+	}
 
 	o2fsck_strings_init(&strings);
 

Modified: trunk/fsck.ocfs2/pass3.c
===================================================================
--- trunk/fsck.ocfs2/pass3.c	2004-11-05 20:50:15 UTC (rev 367)
+++ trunk/fsck.ocfs2/pass3.c	2004-11-06 04:54:12 UTC (rev 368)
@@ -30,6 +30,7 @@
 
 #include "dirparents.h"
 #include "fsck.h"
+#include "pass2.h"
 #include "pass3.h"
 #include "problem.h"
 #include "util.h"
@@ -38,9 +39,7 @@
 {
 	int was_set;
 
-	ocfs2_bitmap_test(ost->ost_used_inodes, ost->ost_fs->fs_root_blkno, 
-			  &was_set);
-	if (was_set) {
+	if (o2fsck_test_inode_allocated(ost, ost->ost_fs->fs_root_blkno)) {
 		ocfs2_bitmap_test(ost->ost_dir_inodes, 
 				ost->ost_fs->fs_root_blkno, &was_set);
 		if (!was_set) {

Modified: trunk/fsck.ocfs2/pass4.c
===================================================================
--- trunk/fsck.ocfs2/pass4.c	2004-11-05 20:50:15 UTC (rev 367)
+++ trunk/fsck.ocfs2/pass4.c	2004-11-06 04:54:12 UTC (rev 368)
@@ -1,10 +1,6 @@
 /* -*- mode: c; c-basic-offset: 8; -*-
  * vim: noexpandtab sw=8 ts=8 sts=0:
  *
- * pass4.c
- *
- * file system checker for OCFS2
- *
  * Copyright (C) 2004 Oracle.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -21,7 +17,6 @@
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 021110-1307, USA.
  *
- * Authors: Zach Brown
  */
 #include <inttypes.h>
 
@@ -34,78 +29,100 @@
 #include "problem.h"
 #include "util.h"
 
+static const char *whoami = "pass4";
+
+static errcode_t check_link_counts(o2fsck_state *ost, ocfs2_dinode *di)
+{
+	uint16_t refs, in_inode;
+
+	refs = o2fsck_icount_get(ost->ost_icount_refs, di->i_blkno);
+	in_inode = o2fsck_icount_get(ost->ost_icount_in_inodes, di->i_blkno);
+
+	verbosef("ino %"PRIu64", refs %u in %u\n", di->i_blkno, refs, 
+		 in_inode);
+
+	/* XXX offer to remove files/dirs with no data? */
+	if (refs == 0 &&
+	    prompt(ost, PY, "Inode %"PRIu64" isn't referenced by any "
+		   "directory entries.  Move it to lost+found?", 
+		   di->i_blkno)) {
+		o2fsck_reconnect_file(ost, di->i_blkno);
+		refs = o2fsck_icount_get(ost->ost_icount_refs, di->i_blkno);
+	}
+
+	if (refs == in_inode)
+		goto out;
+
+	if (in_inode != di->i_links_count)
+		com_err(whoami, OCFS2_ET_INTERNAL_FAILURE, "fsck's thinks "
+			"inode %"PRIu64" has a link count of %"PRIu16" but on "
+			"disk it is %"PRIu16, di->i_blkno, in_inode, 
+			di->i_links_count);
+
+	if (prompt(ost, PY, "Inode %"PRIu64" has a link count of %"PRIu16" on "
+		   "disk but directory entry references come to %"PRIu16". "
+		   "Update the count on disk to match?", di->i_blkno, in_inode, 
+		   refs)) {
+		di->i_links_count = refs;
+		o2fsck_icount_set(ost->ost_icount_in_inodes, di->i_blkno,
+				  refs);
+		o2fsck_write_inode(ost->ost_fs, di->i_blkno, di);
+	}
+
+out:
+	return 0;
+}
+
 errcode_t o2fsck_pass4(o2fsck_state *ost)
 {
-	uint64_t ino = 0;
-	uint16_t refs, in_inode;
 	ocfs2_dinode *di;
 	char *buf = NULL;
-	errcode_t err;
+	errcode_t ret;
+	ocfs2_inode_scan *scan;
+	uint64_t blkno;
 
 	printf("Pass 4: Checking inodes link counts.\n");
 
-	for (ino = 0;
-	     ocfs2_bitmap_find_next_set(ost->ost_used_inodes, ino, &ino) == 0;
-	     ino++) {
-		/*
-		 * XXX e2fsck skips some inodes by their presence in other
-		 * bitmaps.  I think we should use this loop to verify their
-		 * i_links_count as well and just make sure that we update refs
-		 * to match our expectations in previous passes.
-		 */
+	ret = ocfs2_malloc_block(ost->ost_fs->fs_io, &buf);
+	if (ret) {
+		com_err(whoami, ret, "while allocating space to read inodes");
+		goto out;
+	}
 
-		refs = o2fsck_icount_get(ost->ost_icount_refs, ino);
-		in_inode = o2fsck_icount_get(ost->ost_icount_in_inodes, ino);
+	di = (ocfs2_dinode *)buf;
 
-		verbosef("ino %"PRIu64", refs %u in %u\n", ino, refs, 
-				in_inode);
+	ret = ocfs2_open_inode_scan(ost->ost_fs, &scan);
+	if (ret) {
+		com_err(whoami, ret,
+			"while opening inode scan");
+		goto out_free;
+	}
 
-		if (refs == 0) {
-			/* XXX offer to remove files/dirs with no data? */
-			if (prompt(ost, PY, "Inode %"PRIu64" isn't referenced "
-				   "by any directory entries.  Move it to "
-				   "lost+found?", ino)) {
-				o2fsck_reconnect_file(ost, ino);
-				refs = o2fsck_icount_get(ost->ost_icount_refs,
-						ino);
-			}
+	for(;;) {
+		ret = ocfs2_get_next_inode(scan, &blkno, buf);
+		if (ret) {
+			com_err(whoami, ret, "while reading next inode");
+			break;
 		}
+		if (blkno == 0)
+			break;
 
-		if (refs == in_inode)
+		if (!(di->i_flags & OCFS2_VALID_FL))
 			continue;
 
-		if (buf == NULL) {
-			err = ocfs2_malloc_block(ost->ost_fs->fs_io, &buf);
-			if (err)
-				fatal_error(err, "while allocating inode "
-						"buffer to verify an inode's "
-						"link count");
-		}
+		/*
+		 * XXX e2fsck skips some inodes by their presence in other
+		 * bitmaps.  I think we should use this loop to verify their
+		 * i_links_count as well and just make sure that we update refs
+		 * to match our expectations in previous passes.
+		 */
 
-		err = ocfs2_read_inode(ost->ost_fs, ino, buf);
-		if (err)
-			fatal_error(err, "while reading inode %"PRIu64" to "
-					"verify its link count", ino);
-
-		di = (ocfs2_dinode *)buf; 
-
-		if (in_inode != di->i_links_count)
-			fatal_error(OCFS2_ET_INTERNAL_FAILURE,
-				    "fsck's thinks inode %"PRIu64" has a link "
-				    "count of %"PRIu16" but on disk it is "
-				    "%"PRIu16, ino, in_inode, 
-				    di->i_links_count);
-
-		if (prompt(ost, PY, "Inode %"PRIu64" has a link count of "
-			   "%"PRIu16" on disk but directory entry references "
-			   "come to %"PRIu16". Update the count on disk to "
-			   "match?", ino, in_inode, refs)) {
-			di->i_links_count = refs;
-			o2fsck_icount_set(ost->ost_icount_in_inodes, ino, 
-					refs);
-			o2fsck_write_inode(ost->ost_fs, ino, di);
-		}
+		check_link_counts(ost, di);
 	}
 
-	return 0;
+	ocfs2_close_inode_scan(scan);
+out_free:
+	ocfs2_free(&buf);
+out:
+	return ret;
 }

Modified: trunk/libocfs2/Makefile
===================================================================
--- trunk/libocfs2/Makefile	2004-11-05 20:50:15 UTC (rev 367)
+++ trunk/libocfs2/Makefile	2004-11-06 04:54:12 UTC (rev 368)
@@ -6,7 +6,9 @@
 	-Wmissing-declarations
 
 ifdef OCFS_DEBUG
-OPTS += -g
+OPTS += -O -g
+else
+OPTS += -O2
 endif
 
 INCLUDES = -Iinclude
@@ -16,10 +18,6 @@
 CFLAGS = $(OPTS) $(WARNINGS) -fPIC
 CPPFLAGS += -DOCFS2_FLAT_INCLUDES
 
-OPTIMIZE = -O2
-
-CFLAGS += $(OPTIMIZE)
-
 ifneq ($(OCFS2_DEBUG_EXE),)
 DEBUG_EXE_FILES = $(shell awk '/DEBUG_EXE/{if (k[FILENAME] == 0) {print FILENAME; k[FILENAME] = 1;}}' $(CFILES))
 DEBUG_EXE_PROGRAMS = $(addprefix debug_,$(subst .c,,$(DEBUG_EXE_FILES)))

Modified: trunk/libocfs2/alloc.c
===================================================================
--- trunk/libocfs2/alloc.c	2004-11-05 20:50:15 UTC (rev 367)
+++ trunk/libocfs2/alloc.c	2004-11-06 04:54:12 UTC (rev 368)
@@ -94,11 +94,11 @@
 	errcode_t ret;
 
 	ret = ocfs2_load_allocator(fs, INODE_ALLOC_SYSTEM_INODE,
-			   	   0, &fs->fs_inode_alloc);
+			   	   0, &fs->fs_inode_allocs[0]);
 	if (ret)
 		return ret;
 
-	return ocfs2_chain_alloc_with_io(fs, fs->fs_inode_alloc, blkno);
+	return ocfs2_chain_alloc_with_io(fs, fs->fs_inode_allocs[0], blkno);
 }
 
 errcode_t ocfs2_new_system_inode(ocfs2_filesys *fs, uint64_t *blkno)
@@ -118,14 +118,53 @@
 {
 	errcode_t ret;
 
+	/* XXX needs to delete from the allocator that has the inode */
+
 	ret = ocfs2_load_allocator(fs, INODE_ALLOC_SYSTEM_INODE,
-			   	   0, &fs->fs_inode_alloc);
+			   	   0, &fs->fs_inode_allocs[0]);
 	if (ret)
 		return ret;
 
-	return ocfs2_chain_free_with_io(fs, fs->fs_inode_alloc, blkno);
+	return ocfs2_chain_free_with_io(fs, fs->fs_inode_allocs[0], blkno);
 }
 
+errcode_t ocfs2_test_inode_allocated(ocfs2_filesys *fs, uint64_t blkno,
+				     int *is_allocated)
+{
+	uint16_t node, max_nodes = OCFS2_RAW_SB(fs->fs_super)->s_max_nodes;
+	ocfs2_cached_inode **ci;
+	int type;
+	errcode_t ret = OCFS2_ET_INTERNAL_FAILURE;
+
+	for (node = ~0; node != max_nodes; node++) {
+		if (node == (uint16_t)~0) {
+			type = GLOBAL_INODE_ALLOC_SYSTEM_INODE;
+			ci = &fs->fs_system_inode_alloc;
+		} else {
+			type = INODE_ALLOC_SYSTEM_INODE;
+			ci = &fs->fs_inode_allocs[node];
+		}
+
+		ret = ocfs2_load_allocator(fs, type, node, ci);
+		if (ret)
+			break;
+
+		/* XXX I don't understand why this isn't in
+		 * ocfs2_load_allocator.. the _with_io guys in this file about
+		 * chain_allocator */
+		if ((*ci)->ci_chains == NULL) {
+			ret = ocfs2_load_chain_allocator(fs, *ci);
+			if (ret)
+				break;
+		}
+
+		ret = ocfs2_chain_test(fs, *ci, blkno, is_allocated);
+		if (ret != OCFS2_ET_INVALID_BIT)
+			break;
+	}
+	return ret;
+}
+
 void ocfs2_init_inode(ocfs2_filesys *fs, ocfs2_dinode *di,
 		      uint64_t blkno)
 {

Modified: trunk/libocfs2/bitmap.c
===================================================================
--- trunk/libocfs2/bitmap.c	2004-11-05 20:50:15 UTC (rev 367)
+++ trunk/libocfs2/bitmap.c	2004-11-06 04:54:12 UTC (rev 368)
@@ -287,6 +287,25 @@
 	return 0;
 }
 
+errcode_t ocfs2_bitmap_foreach_region(ocfs2_bitmap *bitmap,
+				      ocfs2_bitmap_foreach_func func,
+				      void *private_data)
+{
+	struct ocfs2_bitmap_region *br;
+	struct rb_node *node;
+	errcode_t ret = 0;
+
+	for (node = rb_first(&bitmap->b_regions); node; node = rb_next(node)) {
+		br = rb_entry(node, struct ocfs2_bitmap_region, br_node);
+
+		ret = func(br, private_data);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
 /*
  * Attempt to merge two regions.  If the merge is successful, 0 will
  * be returned and prev will be the only valid region.  Next will
@@ -432,8 +451,12 @@
 	if (oldval)
 		*oldval = old_tmp;
 
-	if (!old_tmp)
+	if (!old_tmp) {
 		br->br_set_bits++;
+		if (bitmap->b_ops->bit_change_notify)
+			(*bitmap->b_ops->bit_change_notify)(bitmap, br, bitno,
+							    1);
+	}
 
 	return 0;
 }
@@ -453,8 +476,12 @@
 	if (oldval)
 		*oldval = old_tmp;
 
-	if (old_tmp)
+	if (old_tmp) {
 		br->br_set_bits--;
+		if (bitmap->b_ops->bit_change_notify)
+			(*bitmap->b_ops->bit_change_notify)(bitmap, br, bitno,
+							    0);
+	}
 
 	return 0;
 }

Modified: trunk/libocfs2/chainalloc.c
===================================================================
--- trunk/libocfs2/chainalloc.c	2004-11-05 20:50:15 UTC (rev 367)
+++ trunk/libocfs2/chainalloc.c	2004-11-06 04:54:12 UTC (rev 368)
@@ -38,6 +38,7 @@
 struct chainalloc_bitmap_private {
 	ocfs2_cached_inode	*cb_cinode;
 	errcode_t		cb_errcode;
+	int			cb_dirty;
 };
 
 struct chainalloc_region_private {
@@ -51,9 +52,14 @@
 {
 	struct rb_node *node = NULL;
 	struct ocfs2_bitmap_region *br;
+	struct chainalloc_region_private *cr;
 
 	for (node = rb_first(&bitmap->b_regions); node; node = rb_next(node)) {
 		br = rb_entry(node, struct ocfs2_bitmap_region, br_node);
+
+		cr = br->br_private;
+		if (cr->cr_ag)
+			ocfs2_free(&cr->cr_ag);
 		ocfs2_free(&br->br_private);
 	}
 
@@ -139,6 +145,54 @@
 	return ret;
 }
 
+static errcode_t chainalloc_write_group(struct ocfs2_bitmap_region *br,
+					void *private_data)
+{
+	struct chainalloc_region_private *cr = br->br_private;
+	ocfs2_filesys *fs = private_data;
+	errcode_t ret = 0;
+
+	printf("want to write desc %"PRIu64"\n", cr->cr_ag->bg_blkno);
+
+	if (!cr->cr_dirty)
+		return 0;
+
+	memcpy(cr->cr_ag->bg_bitmap, br->br_bitmap, cr->cr_ag->bg_bits / 8);
+
+	ret = ocfs2_write_group_desc(fs, cr->cr_ag->bg_blkno, 
+				     (char *)cr->cr_ag);
+	if (ret == 0)
+		cr->cr_dirty = 0;
+
+	return ret;
+}
+
+static errcode_t chainalloc_write_bitmap(ocfs2_bitmap *bitmap)
+{
+	struct chainalloc_bitmap_private *cb = bitmap->b_private;
+	ocfs2_filesys *fs;
+	errcode_t ret;
+
+	if (!cb->cb_cinode)
+		return OCFS2_ET_INVALID_ARGUMENT;
+
+	if (!cb->cb_dirty)
+		return 0;
+
+	fs = cb->cb_cinode->ci_fs;
+
+	ret = ocfs2_bitmap_foreach_region(bitmap, chainalloc_write_group, fs);
+	if (ret)
+		goto out;
+
+	ret = ocfs2_write_cached_inode(fs, cb->cb_cinode);
+	if (ret == 0)
+		cb->cb_dirty = 0;
+
+out:
+	return ret;
+}
+
 static int chainalloc_merge_region(ocfs2_bitmap *bitmap,
 				   struct ocfs2_bitmap_region *prev,
 				   struct ocfs2_bitmap_region *next)
@@ -147,6 +201,33 @@
 	return 0;
 }
 
+/* update the free bit counts in the alloc group, chain rec, and inode so
+ * that they are valid if we're asked to write in the future */
+static void chainalloc_bit_change_notify(ocfs2_bitmap *bitmap,
+					 struct ocfs2_bitmap_region *br,
+					 uint64_t bitno,
+					 int new_val)
+{
+	struct chainalloc_bitmap_private *cb = bitmap->b_private;
+	struct chainalloc_region_private *cr = br->br_private;
+	ocfs2_dinode *di = cb->cb_cinode->ci_inode;
+	ocfs2_group_desc *ag = cr->cr_ag;
+	ocfs2_chain_rec *rec = &di->id2.i_chain.cl_recs[ag->bg_chain];
+
+	if (new_val) {
+		ag->bg_free_bits_count--;
+		rec->c_free--;
+		di->id1.bitmap1.i_used++;
+	} else {
+		ag->bg_free_bits_count++;
+		rec->c_free++;
+		di->id1.bitmap1.i_used--;
+	}
+
+	cr->cr_dirty = 1;
+	cb->cb_dirty = 1;
+}
+
 static struct ocfs2_bitmap_operations chainalloc_bitmap_ops = {
 	.set_bit		= ocfs2_bitmap_set_generic,
 	.clear_bit		= ocfs2_bitmap_clear_generic,
@@ -155,7 +236,9 @@
 	.find_next_clear	= ocfs2_bitmap_find_next_clear_generic,
 	.merge_region		= chainalloc_merge_region,
 	.read_bitmap		= chainalloc_read_bitmap,
+	.write_bitmap		= chainalloc_write_bitmap,
 	.destroy_notify		= chainalloc_destroy_notify,
+	.bit_change_notify	= chainalloc_bit_change_notify,
 };
 
 static errcode_t ocfs2_chainalloc_bitmap_new(ocfs2_filesys *fs,
@@ -273,7 +356,18 @@
 	return 0;
 }
 
+errcode_t ocfs2_chain_test(ocfs2_filesys *fs,
+			   ocfs2_cached_inode *cinode,
+			   uint64_t blkno,
+			   int *oldval)
+{
+	if (!cinode->ci_chains)
+		return OCFS2_ET_INVALID_ARGUMENT;
 
+	return ocfs2_bitmap_test(cinode->ci_chains, blkno, oldval);
+}
+
+
 #ifdef DEBUG_EXE
 #include <stdlib.h>
 #include <getopt.h>

Modified: trunk/libocfs2/include/bitmap.h
===================================================================
--- trunk/libocfs2/include/bitmap.h	2004-11-05 20:50:15 UTC (rev 367)
+++ trunk/libocfs2/include/bitmap.h	2004-11-06 04:54:12 UTC (rev 368)
@@ -61,6 +61,10 @@
 	errcode_t (*read_bitmap)(ocfs2_bitmap *bitmap);
 	errcode_t (*write_bitmap)(ocfs2_bitmap *bitmap);
 	void (*destroy_notify)(ocfs2_bitmap *bitmap);
+	void (*bit_change_notify)(ocfs2_bitmap *bitmap,
+				  struct ocfs2_bitmap_region *br,
+				  uint64_t bitno,
+				  int new_val);
 };
 
 struct _ocfs2_bitmap {
@@ -90,6 +94,11 @@
 				      int total_bits);
 errcode_t ocfs2_bitmap_insert_region(ocfs2_bitmap *bitmap,
 				     struct ocfs2_bitmap_region *br);
+typedef errcode_t (*ocfs2_bitmap_foreach_func)(struct ocfs2_bitmap_region *br,
+					       void *private_data);
+errcode_t ocfs2_bitmap_foreach_region(ocfs2_bitmap *bitmap,
+				      ocfs2_bitmap_foreach_func func,
+				      void *private_data);
 errcode_t ocfs2_bitmap_set_generic(ocfs2_bitmap *bitmap,
 				   uint64_t bitno, int *oldval);
 errcode_t ocfs2_bitmap_clear_generic(ocfs2_bitmap *bitmap,

Modified: trunk/libocfs2/include/ocfs2.h
===================================================================
--- trunk/libocfs2/include/ocfs2.h	2004-11-05 20:50:15 UTC (rev 367)
+++ trunk/libocfs2/include/ocfs2.h	2004-11-06 04:54:12 UTC (rev 368)
@@ -180,7 +180,7 @@
 
 	/* Allocators */
 	ocfs2_cached_inode *fs_cluster_alloc;
-	ocfs2_cached_inode *fs_inode_alloc;
+	ocfs2_cached_inode **fs_inode_allocs;
 	ocfs2_cached_inode *fs_system_inode_alloc;
 	ocfs2_cached_inode *fs_eb_alloc;
 	ocfs2_cached_inode *fs_system_eb_alloc;
@@ -425,7 +425,14 @@
 errcode_t ocfs2_chain_free(ocfs2_filesys *fs,
 			   ocfs2_cached_inode *cinode,
 			   uint64_t blkno);
+errcode_t ocfs2_chain_test(ocfs2_filesys *fs,
+			   ocfs2_cached_inode *cinode,
+			   uint64_t blkno,
+			   int *oldval);
 
+errcode_t ocfs2_test_inode_allocated(ocfs2_filesys *fs, uint64_t blkno,
+				     int *is_allocated);
+
 /* 
  * ${foo}_to_${bar} is a floor function.  blocks_to_clusters will
  * returns the cluster that contains a block, not the number of clusters

Modified: trunk/libocfs2/openfs.c
===================================================================
--- trunk/libocfs2/openfs.c	2004-11-05 20:50:15 UTC (rev 367)
+++ trunk/libocfs2/openfs.c	2004-11-06 04:54:12 UTC (rev 368)
@@ -234,6 +234,12 @@
 	if (OCFS2_RAW_SB(fs->fs_super)->s_max_nodes > OCFS2_MAX_NODES)
 		goto out;
 
+	ret = ocfs2_malloc0(OCFS2_RAW_SB(fs->fs_super)->s_max_nodes *
+			    sizeof(ocfs2_cached_inode *), 
+			    &fs->fs_inode_allocs);
+	if (ret)
+		goto out;
+
 	ret = OCFS2_ET_UNEXPECTED_BLOCK_SIZE;
 	if (block_size !=
 	    (1U << OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits))
@@ -258,6 +264,9 @@
 	return 0;
 
 out:
+	if (fs->fs_inode_allocs)
+		ocfs2_free(&fs->fs_inode_allocs);
+
 	ocfs2_freefs(fs);
 
 	return ret;



More information about the Ocfs2-tools-commits mailing list