[Ocfs2-tools-devel] [PATCH 08/12] dx_dirs v7: fsck.ocfs2 support

Coly Li coly.li at suse.de
Fri Jan 29 10:18:40 PST 2010


This patch does a basic indexed dirs support in fsck.ocfs2.

During pass2, if a directory block is changed, and indexed dirs in
enabled, the indexed tree of this directory will be
truncate, then rebuild with the modified directory data. All the
modified directories' inode numbers are recored in a
rb-tree, when all directories get scanned, truncate and rebuild the
directories whose inode recorded in the rb-tree.

Signed-off-by: Coly Li <coly.li at suse.de>
Cc: Mark Fasheh <mfasheh at suse.com>
---
 fsck.ocfs2/dirblocks.c         |  127 ++++++++++++++++++++++++++++++++++++++--
 fsck.ocfs2/include/dirblocks.h |    4 +
 fsck.ocfs2/pass1.c             |   54 +++++++++++++++++
 fsck.ocfs2/pass1b.c            |    4 +-
 fsck.ocfs2/pass2.c             |   38 +++++++++++-
 fsck.ocfs2/pass3.c             |    1 +
 fsck.ocfs2/pass4.c             |    1 +
 7 files changed, 220 insertions(+), 9 deletions(-)

diff --git a/fsck.ocfs2/dirblocks.c b/fsck.ocfs2/dirblocks.c
index 1fd5560..79a3617 100644
--- a/fsck.ocfs2/dirblocks.c
+++ b/fsck.ocfs2/dirblocks.c
@@ -34,6 +34,7 @@
 #include "fsck.h"
 #include "dirblocks.h"
 #include "util.h"
+#include "extent.h"

 errcode_t o2fsck_add_dir_block(o2fsck_dirblocks *db, uint64_t ino,
 			       uint64_t blkno, uint64_t blkcount)
@@ -43,11 +44,9 @@ errcode_t o2fsck_add_dir_block(o2fsck_dirblocks *db, uint64_t ino,
 	o2fsck_dirblock_entry *dbe, *tmp_dbe;
 	errcode_t ret = 0;

-	dbe = calloc(1, sizeof(*dbe));
-	if (dbe == NULL) {
-		ret = OCFS2_ET_NO_MEMORY;
-		goto out;
-	}
+	ret = ocfs2_malloc0(sizeof(o2fsck_dirblock_entry), &dbe);
+	if (ret)
+       		goto out;

 	dbe->e_ino = ino;
 	dbe->e_blkno = blkno;
@@ -134,6 +133,73 @@ static int try_to_cache(ocfs2_filesys *fs, struct rb_node *node,
 	return cached_blocks;
 }

+uint64_t o2fsck_search_reidx_dir(struct rb_root *root, uint64_t dino)
+{
+	struct rb_node *node = root->rb_node;
+	o2fsck_dirblock_entry *dbe;
+
+	while (node) {
+		dbe = rb_entry(node, o2fsck_dirblock_entry, e_node);
+
+		if (dino < dbe->e_ino)
+			node = node->rb_left;
+		else if (dino > dbe->e_ino)
+			node = node->rb_right;
+		else
+			return dbe->e_ino;
+	}
+	return 0;
+}
+
+static errcode_t o2fsck_add_reidx_dir_ino(struct rb_root *root, uint64_t dino)
+{
+	struct rb_node **p = &root->rb_node;
+	struct rb_node *parent = NULL;
+	o2fsck_dirblock_entry *dp, *tmp_dp;
+	errcode_t ret = 0;
+
+	ret = ocfs2_malloc0(sizeof (o2fsck_dirblock_entry), &dp);
+	if (ret)
+		goto out;
+
+	dp->e_ino = dino;
+
+	while(*p)
+	{
+		parent = *p;
+		tmp_dp = rb_entry(parent, o2fsck_dirblock_entry, e_node);
+
+		if (dp->e_ino < tmp_dp->e_ino)
+			p = &(*p)->rb_left;
+		else if (dp->e_ino > tmp_dp->e_ino)
+			p = &(*p)->rb_right;
+		else {
+			ret = OCFS2_ET_INTERNAL_FAILURE;
+			ocfs2_free(&dp);
+			goto out;
+		}
+	}
+
+	rb_link_node(&dp->e_node, parent, p);
+	rb_insert_color(&dp->e_node, root);
+
+out:
+	return ret;
+}
+
+errcode_t o2fsck_try_add_reidx_dir(struct rb_root *root, uint64_t dino)
+{
+	errcode_t ret = 0;
+	uint64_t ino;
+	ino = o2fsck_search_reidx_dir(root, dino);
+	if (ino)
+		goto out;
+	ret = o2fsck_add_reidx_dir_ino(root, dino);
+
+out:
+	return ret;
+}
+
 void o2fsck_dir_block_iterate(o2fsck_state *ost, dirblock_iterator func,
 			      void *priv_data)
 {
@@ -174,3 +240,54 @@ void o2fsck_dir_block_iterate(o2fsck_state *ost, dirblock_iterator func,
 	if (pre_cache_buf)
 		ocfs2_free(&pre_cache_buf);
 }
+
+static errcode_t ocfs2_rebuild_indexed_dir(ocfs2_filesys *fs, uint64_t ino)
+{
+	errcode_t ret = 0;
+	char *di_buf = NULL;
+	struct ocfs2_dinode *di;
+
+
+	ret = ocfs2_malloc_block(fs->fs_io, &di_buf);
+	if (ret)
+		goto out;
+	
+	ret = ocfs2_read_inode(fs, ino, di_buf);
+	if (ret)
+		goto out;
+	di = (struct ocfs2_dinode *)di_buf;
+
+	/* do not rebuild indexed tree for inline directory */
+	if (di->i_dyn_features & OCFS2_INLINE_DATA_FL)
+		goto out;
+
+	ret = ocfs2_dx_dir_truncate(fs, ino);
+	if (ret)
+		goto out;
+
+	ret = ocfs2_dx_dir_build(fs, ino);
+out:
+	if (di_buf)
+		ocfs2_free(&di_buf);
+	return ret;
+}
+
+
+errcode_t o2fsck_rebuild_indexed_dirs(ocfs2_filesys *fs, struct rb_root *root)
+{
+	struct rb_node *node;
+	o2fsck_dirblock_entry *dbe;
+	uint64_t ino;
+	errcode_t ret;
+
+	for (node = rb_first(root); node; node = rb_next(node)) {
+		dbe = rb_entry(node, o2fsck_dirblock_entry, e_node);
+		ino = dbe->e_ino;
+		ret = ocfs2_rebuild_indexed_dir(fs, ino);
+		if (ret)
+			goto out;
+	}
+out:
+	return ret;
+}
+
diff --git a/fsck.ocfs2/include/dirblocks.h b/fsck.ocfs2/include/dirblocks.h
index 7b3a2e9..f85974f 100644
--- a/fsck.ocfs2/include/dirblocks.h
+++ b/fsck.ocfs2/include/dirblocks.h
@@ -48,6 +48,10 @@ struct _o2fsck_state;
 void o2fsck_dir_block_iterate(struct _o2fsck_state *ost, dirblock_iterator func,
                               void *priv_data);
 		
+uint64_t o2fsck_search_reidx_dir(struct rb_root *root, uint64_t dino);
+errcode_t o2fsck_try_add_reidx_dir(struct rb_root *root, uint64_t dino);
+errcode_t o2fsck_rebuild_indexed_dirs(ocfs2_filesys *fs, struct rb_root *root);
+errcode_t o2fsck_check_dir_index(struct _o2fsck_state *ost, struct ocfs2_dinode *di);

 #endif /* __O2FSCK_DIRBLOCKS_H__ */

diff --git a/fsck.ocfs2/pass1.c b/fsck.ocfs2/pass1.c
index 4f0ad8c..e8e3471 100644
--- a/fsck.ocfs2/pass1.c
+++ b/fsck.ocfs2/pass1.c
@@ -760,6 +760,53 @@ static int clear_block(ocfs2_filesys *fs,
 	return 0;
 }

+
+static errcode_t o2fsck_check_dx_dir(o2fsck_state *ost, struct ocfs2_dinode *di)
+{
+	errcode_t ret = 0;
+	char *buf = NULL;
+	struct ocfs2_dx_root_block *dx_root;
+	ocfs2_filesys *fs = ost->ost_fs;
+	struct extent_info ei = {0,};
+	int changed = 0;
+
+	if (!ocfs2_supports_indexed_dirs(OCFS2_RAW_SB(fs->fs_super)))
+		goto out;
+
+	if (!ocfs2_dir_indexed(di))
+		goto out;
+
+	ret = ocfs2_malloc_block(fs->fs_io, &buf);
+	if (ret)
+		goto out;
+
+	ret = ocfs2_read_dx_root(fs, (uint64_t)di->i_dx_root, buf);
+	if (ret)
+		goto out;
+
+	dx_root = (struct ocfs2_dx_root_block *)buf;
+	if (dx_root->dr_flags & OCFS2_DX_FLAG_INLINE)
+		goto out;
+
+	ret = check_el(ost, &ei, di, &dx_root->dr_list,
+			ocfs2_extent_recs_per_dx_root(fs->fs_blocksize),
+			&changed);
+	if (ret)
+		goto out;
+
+	if (changed) {
+		ret = ocfs2_write_dx_root(fs, (uint64_t)di->i_dx_root, (char *)dx_root);
+		if (ret)
+			com_err(whoami, ret, "while writing an updated "
+				"dx_root block at %"PRIu64" for inode %"PRIu64,
+				(uint64_t)di->i_dx_root, (uint64_t)di->i_blkno);
+	}
+out:
+	if (buf)
+		ocfs2_free(&buf);
+	return ret;
+}
+
 /*
  * this verifies i_size and i_clusters for inodes that use i_list to
  * reference extents of data.
@@ -815,6 +862,13 @@ static errcode_t o2fsck_check_blocks(ocfs2_filesys *fs, o2fsck_state *ost,
 		goto out;
 	}

+	ret = o2fsck_check_dx_dir(ost, di);
+	if (ret) {
+		com_err(whoami, ret, "while iterating over the dir indexed "
+			"tree for directory inode %"PRIu64, (uint64_t)di->i_blkno);
+		goto out;
+	}
+
 	if (S_ISLNK(di->i_mode))
 		check_link_data(&vb);

diff --git a/fsck.ocfs2/pass1b.c b/fsck.ocfs2/pass1b.c
index 7e9ca3b..4900fe0 100644
--- a/fsck.ocfs2/pass1b.c
+++ b/fsck.ocfs2/pass1b.c
@@ -889,8 +889,8 @@ static void name_inode(struct dir_scan_context *scan,
 		pass1c_warn(OCFS2_ET_NO_MEMORY);
 }

-static int walk_iterate(struct ocfs2_dir_entry *de, int offset,
-			int blocksize, char *buf, void *priv_data)
+static int walk_iterate(struct ocfs2_dir_entry *de, uint64_t blocknr,
+			int offset, int blocksize, char *buf, void *priv_data)
 {
 	struct dir_scan_context *scan = priv_data;

diff --git a/fsck.ocfs2/pass2.c b/fsck.ocfs2/pass2.c
index d61c501..80409ff 100644
--- a/fsck.ocfs2/pass2.c
+++ b/fsck.ocfs2/pass2.c
@@ -36,6 +36,7 @@
 #include <time.h>

 #include "ocfs2/ocfs2.h"
+#include "ocfs2/kernel-rbtree.h"

 #include "dirparents.h"
 #include "icount.h"
@@ -70,6 +71,7 @@ struct dirblock_data {
 	errcode_t	ret;
 	o2fsck_strings	strings;
 	uint64_t	last_ino;
+	struct rb_root	re_idx_dirs;
 };

 static int dirent_has_dots(struct ocfs2_dir_entry *dirent, int num_dots)
@@ -833,10 +835,11 @@ next:
 	}

 	if (ocfs2_dir_has_trailer(dd->fs, di))
-		fix_dir_trailer(dd->ost, dbe,
+		fix_dir_trailer(dd->ost,
+				dbe,
 				ocfs2_dir_trailer_from_block(dd->fs,
 							     dd->dirblock_buf),
-				&ret_flags);
+							     &ret_flags);

 	if (ret_flags & OCFS2_DIRENT_CHANGED) {
 		if (di->i_dyn_features & OCFS2_INLINE_DATA_FL) {
@@ -851,6 +854,16 @@ next:
 			com_err(whoami, ret, "while writing dir block %"PRIu64,
 				dbe->e_blkno);
 			dd->ost->ost_write_error = 1;
+			goto out;
+		}
+
+		if (ocfs2_supports_indexed_dirs(OCFS2_RAW_SB(dd->fs->fs_super)) &&
+		    !(di->i_dyn_features & OCFS2_INLINE_DATA_FL)) {
+			ret = o2fsck_try_add_reidx_dir(&dd->re_idx_dirs, dbe->e_ino);
+			if (ret)
+				com_err(whoami, ret, "while adding block for "
+					"directory inode %"PRIu64" to rebuild "
+					"dir index", dbe->e_ino);
 		}
 	}

@@ -860,6 +873,18 @@ out:
 	return ret_flags;
 }

+static void release_re_idx_dirs_rbtree(struct rb_root * root)
+{
+	struct rb_node *node;
+	o2fsck_dirblock_entry *dp;
+
+	while ((node = rb_first(root)) != NULL) {
+		dp = rb_entry(node, o2fsck_dirblock_entry, e_node);
+		rb_erase(&dp->e_node, root);
+		ocfs2_free(&dp);
+	}
+}
+
 errcode_t o2fsck_pass2(o2fsck_state *ost)
 {
 	o2fsck_dir_parent *dp;
@@ -868,6 +893,7 @@ errcode_t o2fsck_pass2(o2fsck_state *ost)
 		.ost = ost,
 		.fs = ost->ost_fs,
 		.last_ino = 0,
+		.re_idx_dirs = RB_ROOT,
 	};

 	printf("Pass 2: Checking directory entries.\n");
@@ -905,6 +931,14 @@ errcode_t o2fsck_pass2(o2fsck_state *ost)
 		dp->dp_dirent = ost->ost_fs->fs_sysdir_blkno;

 	o2fsck_dir_block_iterate(ost, pass2_dir_block_iterate, &dd);
+
+	if (dd.re_idx_dirs.rb_node) {
+		ret = o2fsck_rebuild_indexed_dirs(ost->ost_fs, &dd.re_idx_dirs);
+		if (ret)
+			com_err(whoami, ret, "while rebuild indexed dirs.");
+	}
+	release_re_idx_dirs_rbtree(&dd.re_idx_dirs);
+
 	o2fsck_strings_free(&dd.strings);
 out:
 	if (dd.dirblock_buf)
diff --git a/fsck.ocfs2/pass3.c b/fsck.ocfs2/pass3.c
index 457f312..94d9fbd 100644
--- a/fsck.ocfs2/pass3.c
+++ b/fsck.ocfs2/pass3.c
@@ -193,6 +193,7 @@ struct fix_dot_dot_args {
 };

 static int fix_dot_dot_dirent(struct ocfs2_dir_entry *dirent,
+			      uint64_t blocknr,
 			      int	offset,
 			      int	blocksize,
 			      char	*buf,
diff --git a/fsck.ocfs2/pass4.c b/fsck.ocfs2/pass4.c
index d713d13..5ca4f17 100644
--- a/fsck.ocfs2/pass4.c
+++ b/fsck.ocfs2/pass4.c
@@ -101,6 +101,7 @@ out:
 }

 static int replay_orphan_iterate(struct ocfs2_dir_entry *dirent,
+				 uint64_t blocknr,
 				 int	offset,
 				 int	blocksize,
 				 char	*buf,
-- 
Coly Li
SuSE Labs



More information about the Ocfs2-tools-devel mailing list