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

svn-commits at oss.oracle.com svn-commits at oss.oracle.com
Wed Sep 29 18:57:01 CDT 2004


Author: zab
Date: 2004-09-29 18:56:59 -0500 (Wed, 29 Sep 2004)
New Revision: 289

Added:
   trunk/fsck.ocfs2/dirparents.c
   trunk/fsck.ocfs2/include/dirparents.h
Modified:
   trunk/fsck.ocfs2/Makefile
   trunk/fsck.ocfs2/dirblocks.c
   trunk/fsck.ocfs2/fsck.c
   trunk/fsck.ocfs2/include/fsck.h
   trunk/fsck.ocfs2/pass1.c
   trunk/fsck.ocfs2/pass2.c
   trunk/libocfs2/ocfs2_err.et.in
Log:
o add tracking of directory linkage to pass 1 and 2
o detect and fix multiple dirs thinking they are the parent of a dir inode
o get rid of the unused ABORT handling
o add an INTERNAL_FAILURE et error for when our logic goes south


Modified: trunk/fsck.ocfs2/Makefile
===================================================================
--- trunk/fsck.ocfs2/Makefile	2004-09-29 23:55:02 UTC (rev 288)
+++ trunk/fsck.ocfs2/Makefile	2004-09-29 23:56:59 UTC (rev 289)
@@ -22,10 +22,24 @@
   DEFINES += -D__ILP32__
 endif
 
-CFILES = fsck.c dirblocks.c icount.c pass1.c pass2.c problem.c util.c
-HFILES = include/fsck.h include/dirblocks.h include/icount.h include/pass1.h \
-		include/pass2.h include/problem.h include/util.h
+CFILES =	fsck.c		\
+		dirblocks.c 	\
+		dirparents.c 	\
+		icount.c 	\
+		pass1.c 	\
+		pass2.c 	\
+		problem.c 	\
+		util.c
 
+HFILES = 	include/fsck.h		\
+		include/dirblocks.h	\
+		include/dirparents.h	\
+		include/icount.h	\
+		include/pass1.h		\
+		include/pass2.h		\
+		include/problem.h	\
+		include/util.h
+
 OBJS = $(subst .c,.o,$(CFILES))
 
 VERSION_FILES = $(CFILES) $(HFILES)

Modified: trunk/fsck.ocfs2/dirblocks.c
===================================================================
--- trunk/fsck.ocfs2/dirblocks.c	2004-09-29 23:55:02 UTC (rev 288)
+++ trunk/fsck.ocfs2/dirblocks.c	2004-09-29 23:56:59 UTC (rev 289)
@@ -42,7 +42,7 @@
 {
 	struct rb_node ** p = &db->db_root.rb_node;
 	struct rb_node * parent = NULL;
-	o2fsck_dirblock_entry *dbe, *tmp_dbe;;
+	o2fsck_dirblock_entry *dbe, *tmp_dbe;
 
 	dbe = calloc(1, sizeof(*dbe));
 	if (dbe == NULL)

Added: trunk/fsck.ocfs2/dirparents.c
===================================================================
--- trunk/fsck.ocfs2/dirparents.c	2004-09-29 23:55:02 UTC (rev 288)
+++ trunk/fsck.ocfs2/dirparents.c	2004-09-29 23:56:59 UTC (rev 289)
@@ -0,0 +1,93 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * dirparents.c
+ *
+ * As always, we let e2fsck lead the way.  A bitmap for
+ * inodes with a single i_count (the vast majority), and a
+ * tree of inode numbers with a greater count. 
+ *
+ * Copyright (C) 2004 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License, version 2,  as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ * Authors: Zach Brown
+ */
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "ocfs2.h"
+
+#include "fsck.h"
+#include "dirparents.h"
+#include "util.h"
+
+/* XXX callers are supposed to make sure they don't call with dup inodes.
+ * we'll see. */
+void o2fsck_add_dir_parent(struct rb_root *root, uint64_t ino, uint64_t dot_dot,
+			   uint64_t dirent)
+{
+	struct rb_node ** p = &root->rb_node;
+	struct rb_node * parent = NULL;
+	o2fsck_dir_parent *dp, *tmp_dp;
+
+	dp = calloc(1, sizeof(*dp));
+	if (dp == NULL)
+		fatal_error(OCFS2_ET_NO_MEMORY, 
+				"while allocating directory entries");
+
+	dp->dp_ino = ino;
+	dp->dp_dot_dot = dot_dot;
+	dp->dp_dirent = dirent;
+
+	while (*p)
+	{
+		parent = *p;
+		tmp_dp = rb_entry(parent, o2fsck_dir_parent, dp_node);
+
+		if (dp->dp_ino < tmp_dp->dp_ino)
+			p = &(*p)->rb_left;
+		else if (dp->dp_ino > tmp_dp->dp_ino)
+			p = &(*p)->rb_right;
+		else
+			fatal_error(OCFS2_ET_INTERNAL_FAILURE, "while adding "
+				    "unique dir parent tracking for dir inode "
+				    "%"PRIu64, ino);
+	}
+
+	rb_link_node(&dp->dp_node, parent, p);
+	rb_insert_color(&dp->dp_node, root);
+}
+
+o2fsck_dir_parent *o2fsck_dir_parent_lookup(struct rb_root *root, uint64_t ino)
+{
+	struct rb_node *node = root->rb_node;
+	o2fsck_dir_parent *dp;
+
+	while (node) {
+		dp = rb_entry(node, o2fsck_dir_parent, dp_node);
+
+		if (ino < dp->dp_ino)
+			node = node->rb_left;
+		else if (ino > dp->dp_ino)
+			node = node->rb_right;
+		else
+			return dp;
+	}
+	return NULL;
+}
+

Modified: trunk/fsck.ocfs2/fsck.c
===================================================================
--- trunk/fsck.ocfs2/fsck.c	2004-09-29 23:55:02 UTC (rev 288)
+++ trunk/fsck.ocfs2/fsck.c	2004-09-29 23:56:59 UTC (rev 289)
@@ -142,6 +142,7 @@
 	memset(ost, 0, sizeof(o2fsck_state));
 	ost->ost_ask = 1;
 	ost->ost_dirblocks.db_root = RB_ROOT;
+	ost->ost_dir_parents = RB_ROOT;
 
 	/* These mean "autodetect" */
 	blksize = 0;

Added: trunk/fsck.ocfs2/include/dirparents.h
===================================================================
--- trunk/fsck.ocfs2/include/dirparents.h	2004-09-29 23:55:02 UTC (rev 288)
+++ trunk/fsck.ocfs2/include/dirparents.h	2004-09-29 23:56:59 UTC (rev 289)
@@ -0,0 +1,44 @@
+/*
+ * dirparents.h
+ *
+ * Copyright (C) 2002 Oracle Corporation.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ * Author: Zach Brown
+ */
+
+#ifndef __O2FSCK_DIRPARENTS_H__
+#define __O2FSCK_DIRPARENTS_H__
+
+typedef struct _o2fsck_dir_parent {
+	struct rb_node	dp_node;
+	uint64_t 	dp_ino; /* The dir inode in question. */
+
+	uint64_t 	dp_dot_dot; /* The parent according to the dir's own 
+				     * '..' entry */
+
+	uint64_t 	dp_dirent; /* The inode that has a dirent which points
+				    * to this directory.  */
+} o2fsck_dir_parent;
+
+void o2fsck_add_dir_parent(struct rb_root *root, uint64_t ino, 
+			uint64_t dot_dot, uint64_t dirent);
+
+o2fsck_dir_parent *o2fsck_dir_parent_lookup(struct rb_root *root, 
+						uint64_t ino);
+#endif /* __O2FSCK_DIRPARENTS_H__ */
+

Modified: trunk/fsck.ocfs2/include/fsck.h
===================================================================
--- trunk/fsck.ocfs2/include/fsck.h	2004-09-29 23:55:02 UTC (rev 288)
+++ trunk/fsck.ocfs2/include/fsck.h	2004-09-29 23:56:59 UTC (rev 289)
@@ -43,6 +43,8 @@
 
 	o2fsck_dirblocks	ost_dirblocks;
 
+	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 */

Modified: trunk/fsck.ocfs2/pass1.c
===================================================================
--- trunk/fsck.ocfs2/pass1.c	2004-09-29 23:55:02 UTC (rev 288)
+++ trunk/fsck.ocfs2/pass1.c	2004-09-29 23:56:59 UTC (rev 289)
@@ -30,6 +30,7 @@
 #include "ocfs2.h"
 
 #include "dirblocks.h"
+#include "dirparents.h"
 #include "icount.h"
 #include "fsck.h"
 #include "pass1.h"
@@ -108,6 +109,7 @@
 	if (S_ISDIR(di->i_mode)) {
 		/* XXX record dir for dir block walk */
 		ocfs2_bitmap_set(ost->ost_dir_inodes, blkno, NULL);
+		o2fsck_add_dir_parent(&ost->ost_dir_parents, blkno, 0, 0);
 	} else if (S_ISREG(di->i_mode)) {
 		ocfs2_bitmap_set(ost->ost_reg_inodes, blkno, NULL);
 	} else if (S_ISLNK(di->i_mode)) {

Modified: trunk/fsck.ocfs2/pass2.c
===================================================================
--- trunk/fsck.ocfs2/pass2.c	2004-09-29 23:55:02 UTC (rev 288)
+++ trunk/fsck.ocfs2/pass2.c	2004-09-29 23:56:59 UTC (rev 289)
@@ -29,6 +29,7 @@
 
 #include "ocfs2.h"
 
+#include "dirparents.h"
 #include "icount.h"
 #include "fsck.h"
 #include "pass2.h"
@@ -52,23 +53,28 @@
 	return dirent->name[0] == '.';
 }
 
+static int expected_dots(o2fsck_dirblock_entry *dbe, int offset)
+{
+	if (dbe->e_blkcount == 0) {
+		if (offset == 0)
+			return 1;
+		if (offset == OCFS2_DIR_REC_LEN(1))
+			return 2;
+	}
+
+	return 0;
+}
+
 /* XXX this needs much stronger messages */
 static int fix_dirent_dots(o2fsck_state *ost, o2fsck_dirblock_entry *dbe,
 			   struct ocfs2_dir_entry *dirent, int offset, 
 			   int left)
 {
-	int expect_dots = 0;
+	int expect_dots = expected_dots(dbe, offset);
 	int ret_flags = 0, changed_len = 0;
 	struct ocfs2_dir_entry *next;
 	uint16_t new_len;
 
-	if (dbe->e_blkcount == 0) {
-		if (offset == 0)
-			expect_dots = 1;
-		if (offset == OCFS2_DIR_REC_LEN(1))
-			expect_dots = 2;
-	}
-
 	if (!expect_dots) {
 	       	if (!dirent_has_dots(dirent, 1) && !dirent_has_dots(dirent, 2))
 			return 0;
@@ -90,13 +96,21 @@
 		ret_flags = OCFS2_DIRENT_CHANGED;
 	}
 
-	/* 
-	 * We don't have the parent inode for .. so we don't check it yet.
-	 * It is reasonable for ..'s rec_len to go to the end of the
-	 * block for an empty directory, .'s can't because .. is next.
-	 */
-	if (expect_dots == 2)
+	/* we only record where .. points for now and that ends the
+	 * checks for .. */
+	if (expect_dots == 2) {
+		o2fsck_dir_parent *dp;
+		dp = o2fsck_dir_parent_lookup(&ost->ost_dir_parents,
+						dbe->e_ino);
+		if (dp == NULL)
+			fatal_error(OCFS2_ET_INTERNAL_FAILURE,
+				    "no dir parents for '..' entry for "
+				    "inode %"PRIu64, dbe->e_ino);
+
+		dp->dp_dot_dot = dirent->inode;
+					
 		return ret_flags;
+	}
 
 	if ((dirent->inode != dbe->e_ino) &&
             should_fix(ost, FIX_DEFYES, "invalid . directory, replace?")) {
@@ -201,6 +215,52 @@
 	return ret_flags;
 }
 
+static int fix_dirent_linkage(o2fsck_state *ost, o2fsck_dirblock_entry *dbe,
+			      struct ocfs2_dir_entry *dirent, int offset)
+{
+	int expect_dots = expected_dots(dbe, offset);
+	o2fsck_dir_parent *dp;
+	errcode_t err;
+	int is_dir;
+
+	/* we already took care of special-casing the dots */
+	if (expect_dots)
+		return 0;
+
+	/* we're only checking the linkage if we already found the dir 
+	 * this inode claims to be pointing to */
+	err = ocfs2_bitmap_test(ost->ost_dir_inodes, dirent->inode, &is_dir);
+	if (err)
+		fatal_error(err, "while checking for inode %"PRIu64" in the "
+				"dir bitmap", dirent->inode);
+	if (!is_dir)
+		return 0;
+
+	dp = o2fsck_dir_parent_lookup(&ost->ost_dir_parents, dirent->inode);
+	if (dp == NULL)
+		fatal_error(OCFS2_ET_INTERNAL_FAILURE, "no dir parents for "
+				"'..' entry for inode %"PRIu64, dbe->e_ino);
+
+	/* if no dirents have pointed to this inode yet we record ours
+	 * as the first and move on */
+	if (dp->dp_dirent == 0) {
+		dp->dp_dirent = dbe->e_ino;
+		return 0;
+	}
+
+	if (should_fix(ost, 0, "directory inode %"PRIu64" is not the first to "
+		"claim to be the parent of subdir '%*s' (%"PRIu64").  Forget "
+		"this linkage and leave the previous parent of '%*s' intact?",
+		dbe->e_ino, dirent->name_len, dirent->name, dirent->inode,
+		dirent->name_len, dirent->name)) {
+
+		dirent->inode = 0;
+		return OCFS2_DIRENT_CHANGED;
+	}
+
+	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) 
@@ -240,18 +300,13 @@
 		if (this_flags & OCFS2_DIRENT_CHANGED)
 			continue;
 
-		if (ret_flags & OCFS2_DIRENT_ABORT)
-			break;
-
 		ret_flags |= fix_dirent_dots(dd->ost, dbe, dirent, offset, 
 					     dd->fs->fs_blocksize - offset);
-		if (ret_flags & OCFS2_DIRENT_ABORT)
-			break;
 
 		ret_flags |= fix_dirent_name(dd->ost, dbe, dirent, offset);
-		if (ret_flags & OCFS2_DIRENT_ABORT)
-			break;
 
+		ret_flags |= fix_dirent_linkage(dd->ost, dbe, dirent, offset);
+
 		offset += dirent->rec_len;
 		prev = dirent;
 	}
@@ -262,6 +317,7 @@
 errcode_t o2fsck_pass2(o2fsck_state *ost)
 {
 	errcode_t retval;
+	o2fsck_dir_parent *dp;
 	struct dirblock_data dd = {
 		.ost = ost,
 		.fs = ost->ost_fs,
@@ -271,6 +327,17 @@
 	if (retval)
 		return retval;
 
+	/* 
+	 * Mark the root directory's dirent parent as itself if we found the
+	 * inode during inode scanning.  The dir will be created in pass3
+	 * if it didn't exist already.  XXX we should do this for our other
+	 * magical directories.
+	 */
+	dp = o2fsck_dir_parent_lookup(&ost->ost_dir_parents, 
+					ost->ost_fs->fs_root_blkno);
+	if (dp)
+		dp->dp_dirent = ost->ost_fs->fs_root_blkno;
+
 	o2fsck_dir_block_iterate(&ost->ost_dirblocks, pass2_dir_block_iterate, 
 			 	 &dd);
 	ocfs2_free(&dd.buf);

Modified: trunk/libocfs2/ocfs2_err.et.in
===================================================================
--- trunk/libocfs2/ocfs2_err.et.in	2004-09-29 23:55:02 UTC (rev 288)
+++ trunk/libocfs2/ocfs2_err.et.in	2004-09-29 23:56:59 UTC (rev 289)
@@ -83,4 +83,7 @@
 ec	OCFS2_ET_INVALID_BIT,
 	"Bit does not exist in bitmap range"
 
+ec	OCFS2_ET_INTERNAL_FAILURE,
+	"Internal logic faliure"
+
 	end



More information about the Ocfs2-tools-commits mailing list