[Ocfs2-tools-commits] zab commits r318 - in trunk/fsck.ocfs2: .
include
svn-commits at oss.oracle.com
svn-commits at oss.oracle.com
Wed Oct 6 19:44:26 CDT 2004
Author: zab
Date: 2004-10-06 19:44:24 -0500 (Wed, 06 Oct 2004)
New Revision: 318
Added:
trunk/fsck.ocfs2/include/pass3.h
trunk/fsck.ocfs2/pass3.c
Modified:
trunk/fsck.ocfs2/Makefile
trunk/fsck.ocfs2/dirparents.c
trunk/fsck.ocfs2/fsck.c
trunk/fsck.ocfs2/icount.c
trunk/fsck.ocfs2/include/dirparents.h
trunk/fsck.ocfs2/include/icount.h
trunk/fsck.ocfs2/pass1.c
trunk/fsck.ocfs2/pass2.c
trunk/fsck.ocfs2/problem.c
Log:
o add pass3 where we walk our directory inode parent tracking structure to
make sure that all the directory inodes we have are connected to our
top level directories
o add dir_parent_{first,next} so pass3 can walk them
o use {read,write}_dir_block when walking directory entry blocks
o record the system dir's parent as itself, like we do root
o rename icount update to set, fix bug where it missed icount 2
o add icount_delta to make relative icount tracking changes
Modified: trunk/fsck.ocfs2/Makefile
===================================================================
--- trunk/fsck.ocfs2/Makefile 2004-10-06 22:26:51 UTC (rev 317)
+++ trunk/fsck.ocfs2/Makefile 2004-10-07 00:44:24 UTC (rev 318)
@@ -18,6 +18,7 @@
icount.c \
pass1.c \
pass2.c \
+ pass3.c \
problem.c \
strings.c \
util.c
@@ -28,6 +29,7 @@
include/icount.h \
include/pass1.h \
include/pass2.h \
+ include/pass3.h \
include/problem.h \
include/strings.h \
include/util.h
Modified: trunk/fsck.ocfs2/dirparents.c
===================================================================
--- trunk/fsck.ocfs2/dirparents.c 2004-10-06 22:26:51 UTC (rev 317)
+++ trunk/fsck.ocfs2/dirparents.c 2004-10-07 00:44:24 UTC (rev 318)
@@ -53,6 +53,8 @@
dp->dp_ino = ino;
dp->dp_dot_dot = dot_dot;
dp->dp_dirent = dirent;
+ dp->dp_connected = 0;
+ dp->dp_loop_no = 0;
while (*p)
{
@@ -91,3 +93,24 @@
return NULL;
}
+o2fsck_dir_parent *o2fsck_dir_parent_first(struct rb_root *root)
+{
+ struct rb_node *node = rb_first(root);
+ o2fsck_dir_parent *dp = NULL;
+
+ if (node)
+ dp = rb_entry(node, o2fsck_dir_parent, dp_node);
+
+ return dp;
+}
+
+o2fsck_dir_parent *o2fsck_dir_parent_next(o2fsck_dir_parent *from)
+{
+ struct rb_node *node = rb_next(&from->dp_node);
+ o2fsck_dir_parent *dp = NULL;
+
+ if (node)
+ dp = rb_entry(node, o2fsck_dir_parent, dp_node);
+
+ return dp;
+}
Modified: trunk/fsck.ocfs2/fsck.c
===================================================================
--- trunk/fsck.ocfs2/fsck.c 2004-10-06 22:26:51 UTC (rev 317)
+++ trunk/fsck.ocfs2/fsck.c 2004-10-07 00:44:24 UTC (rev 318)
@@ -36,6 +36,7 @@
#include "icount.h"
#include "pass1.h"
#include "pass2.h"
+#include "pass3.h"
#include "util.h"
int verbose = 0;
@@ -266,6 +267,11 @@
if (ret)
com_err(argv[0], ret, "pass2 failed");
+ ret = o2fsck_pass3(ost);
+ if (ret)
+ com_err(argv[0], ret, "pass3 failed");
+
+
ret = ocfs2_close(ost->ost_fs);
if (ret) {
com_err(argv[0], ret,
Modified: trunk/fsck.ocfs2/icount.c
===================================================================
--- trunk/fsck.ocfs2/icount.c 2004-10-06 22:26:51 UTC (rev 317)
+++ trunk/fsck.ocfs2/icount.c 2004-10-07 00:44:24 UTC (rev 318)
@@ -29,6 +29,7 @@
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
+#include <inttypes.h>
#include "ocfs2.h"
@@ -84,12 +85,12 @@
return NULL;
}
-void o2fsck_icount_update(o2fsck_icount *icount, uint64_t blkno,
- uint16_t count)
+/* keep it simple for now by always updating both data structures */
+void o2fsck_icount_set(o2fsck_icount *icount, uint64_t blkno,
+ uint16_t count)
{
icount_node *in;
- /* keep it simple for now by always clearing/setting */
if (count == 1)
ocfs2_bitmap_set(icount->ic_single_bm, blkno, NULL);
else
@@ -103,7 +104,7 @@
} else {
in->in_icount = count;
}
- } else if (count > 2){
+ } else if (count > 1) {
in = calloc(1, sizeof(*in));
if (in == NULL)
fatal_error(OCFS2_ET_NO_MEMORY,
@@ -115,6 +116,38 @@
}
}
+/* again, simple before efficient. We just find the old value and
+ * use _set to make sure that the new value updates both the bitmap
+ * and the tree */
+void o2fsck_icount_delta(o2fsck_icount *icount, uint64_t blkno,
+ int delta)
+{
+ int was_set;
+ uint16_t prev_count;
+ icount_node *in;
+
+ if (delta == 0)
+ return;
+
+ ocfs2_bitmap_test(icount->ic_single_bm, blkno, &was_set);
+ if (was_set) {
+ prev_count = 1;
+ } else {
+ in = icount_search(icount, blkno);
+ if (in == NULL)
+ prev_count = 0;
+ else
+ prev_count = in->in_icount;
+ }
+
+ if (prev_count + delta < 0)
+ fatal_error(OCFS2_ET_INTERNAL_FAILURE, "while droping icount "
+ "from %"PRIu16" bt %d for inode %"PRIu64,
+ prev_count, delta, blkno);
+
+ o2fsck_icount_set(icount, blkno, prev_count + delta);
+}
+
errcode_t o2fsck_icount_new(ocfs2_filesys *fs, o2fsck_icount **ret)
{
o2fsck_icount *icount;
Modified: trunk/fsck.ocfs2/include/dirparents.h
===================================================================
--- trunk/fsck.ocfs2/include/dirparents.h 2004-10-06 22:26:51 UTC (rev 317)
+++ trunk/fsck.ocfs2/include/dirparents.h 2004-10-07 00:44:24 UTC (rev 318)
@@ -33,6 +33,11 @@
uint64_t dp_dirent; /* The inode that has a dirent which points
* to this directory. */
+
+ /* used by pass3 to walk the dir_parent structs and ensure
+ * connectivity */
+ uint64_t dp_loop_no;
+ int dp_connected;
} o2fsck_dir_parent;
void o2fsck_add_dir_parent(struct rb_root *root, uint64_t ino,
@@ -40,5 +45,7 @@
o2fsck_dir_parent *o2fsck_dir_parent_lookup(struct rb_root *root,
uint64_t ino);
+o2fsck_dir_parent *o2fsck_dir_parent_first(struct rb_root *root);
+o2fsck_dir_parent *o2fsck_dir_parent_next(o2fsck_dir_parent *from);
#endif /* __O2FSCK_DIRPARENTS_H__ */
Modified: trunk/fsck.ocfs2/include/icount.h
===================================================================
--- trunk/fsck.ocfs2/include/icount.h 2004-10-06 22:26:51 UTC (rev 317)
+++ trunk/fsck.ocfs2/include/icount.h 2004-10-07 00:44:24 UTC (rev 318)
@@ -31,10 +31,12 @@
struct rb_root ic_multiple_tree;
} o2fsck_icount;
-void o2fsck_icount_update(o2fsck_icount *icount, uint64_t blkno,
- uint16_t count);
+void o2fsck_icount_set(o2fsck_icount *icount, uint64_t blkno,
+ uint16_t count);
errcode_t o2fsck_icount_new(ocfs2_filesys *fs, o2fsck_icount **ret);
void o2fsck_icount_free(o2fsck_icount *icount);
+void o2fsck_icount_delta(o2fsck_icount *icount, uint64_t blkno,
+ int delta);
#endif /* __O2FSCK_ICOUNT_H__ */
Added: trunk/fsck.ocfs2/include/pass3.h
===================================================================
--- trunk/fsck.ocfs2/include/pass3.h 2004-10-06 22:26:51 UTC (rev 317)
+++ trunk/fsck.ocfs2/include/pass3.h 2004-10-07 00:44:24 UTC (rev 318)
@@ -0,0 +1,32 @@
+/*
+ * pass3.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_PASS3_H__
+#define __O2FSCK_PASS3_H__
+
+#include "fsck.h"
+
+errcode_t o2fsck_pass3(o2fsck_state *ost);
+
+#endif /* __O2FSCK_PASS3_H__ */
+
Modified: trunk/fsck.ocfs2/pass1.c
===================================================================
--- trunk/fsck.ocfs2/pass1.c 2004-10-06 22:26:51 UTC (rev 317)
+++ trunk/fsck.ocfs2/pass1.c 2004-10-07 00:44:24 UTC (rev 318)
@@ -74,7 +74,7 @@
goto bad;
if (di->i_links_count)
- o2fsck_icount_update(ost->ost_icount_in_inodes, di->i_blkno,
+ o2fsck_icount_set(ost->ost_icount_in_inodes, di->i_blkno,
di->i_links_count);
/* offer to clear a non-directory root inode so that
@@ -83,8 +83,8 @@
should_fix(ost, FIX_DEFYES, "Root inode isn't a directory.")) {
di->i_dtime = 0ULL;
di->i_links_count = 0ULL;
- o2fsck_icount_update(ost->ost_icount_in_inodes,
- di->i_blkno, di->i_links_count);
+ o2fsck_icount_set(ost->ost_icount_in_inodes, di->i_blkno,
+ di->i_links_count);
o2fsck_write_inode(fs, blkno, di);
}
@@ -273,8 +273,8 @@
*/
if (vb.vb_clear) {
di->i_links_count = 0;
- o2fsck_icount_update(ost->ost_icount_in_inodes,
- di->i_blkno, di->i_links_count);
+ o2fsck_icount_set(ost->ost_icount_in_inodes, di->i_blkno,
+ di->i_links_count);
di->i_dtime = time(0);
o2fsck_write_inode(fs, di->i_blkno, di);
/* XXX clear valid flag and stuff? */
Modified: trunk/fsck.ocfs2/pass2.c
===================================================================
--- trunk/fsck.ocfs2/pass2.c 2004-10-06 22:26:51 UTC (rev 317)
+++ trunk/fsck.ocfs2/pass2.c 2004-10-07 00:44:24 UTC (rev 318)
@@ -438,15 +438,16 @@
if (!was_set)
return 0;
- /* XXX there is no byte swapping story here, which is wrong. we might
- * be able to salvage more than read_dir_block() if we did our own
- * swabing, so maybe that's what's needed. */
- retval = io_read_block(dd->fs->fs_io, dbe->e_blkno, 1, dd->buf);
- if (retval)
- return OCFS2_DIRENT_ABORT;
-
o2fsck_strings_init(&strings);
+ retval = ocfs2_read_dir_block(dd->fs, dbe->e_blkno, dd->buf);
+ if (retval && retval != OCFS2_ET_DIR_CORRUPTED) {
+ /* XXX hum, ask to continue here. more a prompt than a
+ * fix. need to expand problem.c's vocabulary. */
+ fatal_error(retval, "while reading dir block %"PRIu64,
+ dbe->e_blkno);
+ }
+
while (offset < dd->fs->fs_blocksize) {
dirent = (struct ocfs2_dir_entry *)(dd->buf + offset);
@@ -460,8 +461,15 @@
/* first verify that we can trust the dirent's lengths
- * to navigate to the next in the block. doing so can
- * modify the one we're checking in place */
+ * to navigate to the next in the block. This can try to
+ * get rid of a broken dirent by trying to shift remaining
+ * dirents into its place. The 'contiune' attempts to let
+ * us recheck the current dirent.
+ *
+ * XXX this will have to do some swabbing as it tries
+ * to salvage as read_dir_block stops swabbing
+ * when it sees bad entries.
+ */
this_flags = fix_dirent_lengths(dd->ost, dbe, dirent, offset,
dd->fs->fs_blocksize - offset,
prev);
@@ -506,6 +514,16 @@
prev = dirent;
}
+ if (ret_flags & OCFS2_DIRENT_CHANGED) {
+ retval = ocfs2_write_dir_block(dd->fs, dbe->e_blkno, dd->buf);
+ if (retval) {
+ /* XXX hum, ask to continue here. more a prompt than a
+ * fix. need to expand problem.c's vocabulary. */
+ fatal_error(retval, "while writing dir block %"PRIu64,
+ dbe->e_blkno);
+ }
+ }
+
o2fsck_strings_free(&strings);
return ret_flags;
}
@@ -526,7 +544,7 @@
/*
* 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
+ * if it didn't exist already. XXX we should do this for all our other
* magical directories.
*/
dp = o2fsck_dir_parent_lookup(&ost->ost_dir_parents,
@@ -534,6 +552,11 @@
if (dp)
dp->dp_dirent = ost->ost_fs->fs_root_blkno;
+ dp = o2fsck_dir_parent_lookup(&ost->ost_dir_parents,
+ ost->ost_fs->fs_sysdir_blkno);
+ if (dp)
+ dp->dp_dirent = ost->ost_fs->fs_sysdir_blkno;
+
o2fsck_dir_block_iterate(&ost->ost_dirblocks, pass2_dir_block_iterate,
&dd);
ocfs2_free(&dd.buf);
Added: trunk/fsck.ocfs2/pass3.c
===================================================================
--- trunk/fsck.ocfs2/pass3.c 2004-10-06 22:26:51 UTC (rev 317)
+++ trunk/fsck.ocfs2/pass3.c 2004-10-07 00:44:24 UTC (rev 318)
@@ -0,0 +1,234 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * pass3.c
+ *
+ * file system checker for OCFS2
+ *
+ * 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 <inttypes.h>
+#include <string.h>
+
+#include <ocfs2.h>
+
+#include "dirparents.h"
+#include "fsck.h"
+#include "pass3.h"
+#include "problem.h"
+#include "util.h"
+
+static void check_root(o2fsck_state *ost)
+{
+ int was_set;
+
+ ocfs2_bitmap_test(ost->ost_used_inodes, ost->ost_fs->fs_root_blkno,
+ &was_set);
+ if (was_set) {
+ ocfs2_bitmap_test(ost->ost_dir_inodes,
+ ost->ost_fs->fs_root_blkno, &was_set);
+ if (!was_set) {
+ printf("The root inode exists but isn't a directory. "
+ "fsck should have cleaned this up in "
+ "a previous pass. Exiting.\n");
+ exit(FSCK_ERROR);
+ }
+ return;
+ }
+
+ if (!should_fix(ost, FIX_DEFYES, "The root inode doesn't exist. "
+ "Should it be created? If not, fsck will exit.")) {
+ printf("Aborting.\n");
+ exit(FSCK_ERROR);
+ }
+
+ /* XXX */
+ printf("I don't actually create anything yet..\n");
+ exit(FSCK_ERROR);
+}
+
+struct fix_dot_dot_args {
+ o2fsck_state *ost;
+ uint64_t parent;
+ int fixed;
+};
+
+static int fix_dot_dot_dirent(struct ocfs2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data)
+{
+ struct fix_dot_dot_args *args = priv_data;
+
+ if (dirent->name_len != 2 || strncmp(dirent->name, "..", 2))
+ return 0;
+
+ verbosef("fixing '..' entry to point to %"PRIu64"\n", args->parent);
+
+ if (dirent->inode != 0)
+ o2fsck_icount_delta(args->ost->ost_icount_refs, dirent->inode,
+ -1);
+ o2fsck_icount_delta(args->ost->ost_icount_refs, args->parent, 1);
+
+ dirent->inode = args->parent;
+ args->fixed = 1;
+
+ return OCFS2_DIRENT_ABORT | OCFS2_DIRENT_CHANGED;
+}
+
+static void fix_dot_dot(o2fsck_state *ost, o2fsck_dir_parent *dir)
+{
+ errcode_t ret;
+
+ struct fix_dot_dot_args args = {
+ .ost = ost,
+ .parent = dir->dp_dirent,
+ .fixed = 0,
+ };
+
+ ret = ocfs2_dir_iterate(ost->ost_fs, dir->dp_ino,
+ OCFS2_DIRENT_FLAG_INCLUDE_EMPTY, NULL,
+ fix_dot_dot_dirent, &args);
+ if (ret) {
+ com_err("fix_dot_dot", ret, "while iterating through dir "
+ "inode %"PRIu64"'s directory entries.", dir->dp_dirent);
+ /* XXX mark fs invalid */
+ return;
+ }
+
+ if (!args.fixed) {
+ fprintf(stderr, "Didn't find a '..' entry to fix.\n");
+ /* XXX mark fs invalid */
+ return;
+ }
+
+ dir->dp_dot_dot = dir->dp_dirent;
+}
+
+static int reconnect_file(o2fsck_state *ost, uint64_t inode)
+{
+ fatal_error(OCFS2_ET_INTERNAL_FAILURE, "not implemented yet");
+ return 0;
+}
+
+static uint64_t loop_no = 0;
+
+static void connect_directory(o2fsck_state *ost, o2fsck_dir_parent *dir)
+{
+ o2fsck_dir_parent *dp = dir, *par;
+ int fix;
+
+ verbosef("checking dir inode %"PRIu64" parent %"PRIu64" dot_dot "
+ "%"PRIu64"\n", dir->dp_ino, dp->dp_dirent, dp->dp_dot_dot);
+
+ loop_no++;
+
+ while(!dp->dp_connected) {
+
+ /* we either will ascend to a parent that is connected or
+ * we'll graft the subtree with this directory on to lost
+ * and found. */
+ dp->dp_connected = 1;
+
+ /* move on to the parent dir only if it exists and we haven't
+ * already traversed it in this instance of parent walking */
+ if (dp->dp_dirent) {
+ par = o2fsck_dir_parent_lookup(&ost->ost_dir_parents,
+ dp->dp_dirent);
+ if (par == NULL)
+ fatal_error(OCFS2_ET_INTERNAL_FAILURE,
+ "no dir info for parent "
+ "%"PRIu64, dp->dp_dirent);
+ if (par->dp_loop_no != loop_no) {
+ par->dp_loop_no = loop_no;
+ dp = par;
+ continue;
+ }
+ }
+
+ /* ok, we hit an orphan subtree with no parent or are at
+ * the dir in a subtree that is the first to try to reference
+ * a dir in its children */
+ fix = should_fix(ost, FIX_DEFYES, "directory inode %"PRIu64" "
+ "isn't connected to the filesystem. Move it "
+ "to lost+found?", dp->dp_ino);
+ if (!fix)
+ break;
+ if (reconnect_file(ost, dp->dp_ino)) {
+ /* XXX mark invalid */
+ break;
+ }
+ dp = o2fsck_dir_parent_lookup(&ost->ost_dir_parents,
+ dp->dp_ino);
+ if (dp == NULL)
+ fatal_error(OCFS2_ET_INTERNAL_FAILURE,
+ "no dir parents for reconnected inode "
+ "%"PRIu64, dp->dp_ino);
+ dp->dp_dirent = 1/* XXX lost and found */;
+ fix_dot_dot(ost, dp);
+ break;
+ }
+
+ if (dir->dp_dirent != dir->dp_dot_dot) {
+ fix = should_fix(ost, FIX_DEFYES, "directory inode %"PRIu64" "
+ "is referenced by a dirent in directory "
+ "%"PRIu64" but its '..' entry points to "
+ "inode %"PRIu64". Fix the '..' entry to "
+ "reference %"PRIu64"?", dir->dp_ino,
+ dir->dp_dirent, dir->dp_dot_dot,
+ dir->dp_dirent);
+ if (fix)
+ fix_dot_dot(ost, dir);
+ }
+}
+
+errcode_t o2fsck_pass3(o2fsck_state *ost)
+{
+ o2fsck_dir_parent *dp;
+
+ /* these could probably share more code. We might need to treat the
+ * other required directories like root here */
+
+ check_root(ost);
+
+ dp = o2fsck_dir_parent_lookup(&ost->ost_dir_parents,
+ ost->ost_fs->fs_root_blkno);
+ if (dp == NULL)
+ fatal_error(OCFS2_ET_INTERNAL_FAILURE, "root inode %"PRIu64" "
+ "wasn't marked as a directory in pass1",
+ ost->ost_fs->fs_root_blkno);
+ dp->dp_connected = 1;
+
+ dp = o2fsck_dir_parent_lookup(&ost->ost_dir_parents,
+ ost->ost_fs->fs_sysdir_blkno);
+ if (dp == NULL)
+ fatal_error(OCFS2_ET_INTERNAL_FAILURE, "system dir inode "
+ "%"PRIu64" wasn't marked as a directory in "
+ "pass1", ost->ost_fs->fs_sysdir_blkno);
+ dp->dp_connected = 1;
+
+ for(dp = o2fsck_dir_parent_first(&ost->ost_dir_parents) ;
+ dp; dp = o2fsck_dir_parent_next(dp)) {
+ /* XXX hmm, make sure dir->ino is in the dir map? */
+ connect_directory(ost, dp);
+ }
+
+ return 0;
+}
Modified: trunk/fsck.ocfs2/problem.c
===================================================================
--- trunk/fsck.ocfs2/problem.c 2004-10-06 22:26:51 UTC (rev 317)
+++ trunk/fsck.ocfs2/problem.c 2004-10-07 00:44:24 UTC (rev 318)
@@ -103,8 +103,6 @@
/* no curses, no nothin. overly regressive? */
while ((c = read_a_char(fileno(stdin))) != EOF) {
- printf("read '%c'\n", c);
-
/* XXX control-c, we're done? */
if (c == 3) {
printf("cancelled!\n");
More information about the Ocfs2-tools-commits
mailing list