forked from pool/ocfs2-tools
c8700c5230
OBS-URL: https://build.opensuse.org/package/show/network:ha-clustering:Factory/ocfs2-tools?expand=0&rev=8
416 lines
11 KiB
Diff
416 lines
11 KiB
Diff
From 2bbbdef8534534b12cf3dd3ad9db6a1ebd74d0a3 Mon Sep 17 00:00:00 2001
|
|
From: Coly Li <coly.li@suse.de>
|
|
Date: Sun, 11 Apr 2010 16:10:05 +0800
|
|
Subject: [PATCH 08/30] dx_dirs: fsck.ocfs2 support
|
|
|
|
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@suse.de>
|
|
Signed-off-by: Mark Fasheh <mfasheh@suse.com>
|
|
---
|
|
fsck.ocfs2/dirblocks.c | 125 ++++++++++++++++++++++++++++++++++++++-
|
|
fsck.ocfs2/include/dirblocks.h | 4 +
|
|
fsck.ocfs2/pass1.c | 54 +++++++++++++++++
|
|
fsck.ocfs2/pass1b.c | 4 +-
|
|
fsck.ocfs2/pass2.c | 48 +++++++++++++++-
|
|
fsck.ocfs2/pass3.c | 1 +
|
|
fsck.ocfs2/pass4.c | 1 +
|
|
7 files changed, 229 insertions(+), 8 deletions(-)
|
|
|
|
diff --git a/fsck.ocfs2/dirblocks.c b/fsck.ocfs2/dirblocks.c
|
|
index 1fd5560..085dd1f 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;
|
|
+ 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 = 0;
|
|
+
|
|
+ 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 00f3d54..b53b908 100644
|
|
--- a/fsck.ocfs2/pass1.c
|
|
+++ b/fsck.ocfs2/pass1.c
|
|
@@ -781,6 +781,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->i_blkno, &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.
|
|
@@ -836,6 +883,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 0ea87b4..3ca1d7d 100644
|
|
--- a/fsck.ocfs2/pass1b.c
|
|
+++ b/fsck.ocfs2/pass1b.c
|
|
@@ -902,8 +902,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..58efcd4 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,15 +854,47 @@ 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) &&
|
|
+ (di->i_dyn_features & OCFS2_INDEXED_DIR_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);
|
|
+ goto out;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+ /* truncate invalid indexed tree */
|
|
+ if ((!ocfs2_supports_indexed_dirs(OCFS2_RAW_SB(dd->fs->fs_super)))&&
|
|
+ di->i_dyn_features & OCFS2_INDEXED_DIR_FL ) {
|
|
+ /* ignore the return value */
|
|
+ ocfs2_dx_dir_truncate(dd->fs, dbe->e_ino);
|
|
+ }
|
|
+
|
|
out:
|
|
if (ret)
|
|
dd->ret = ret;
|
|
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 +903,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 +941,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,
|
|
--
|
|
1.7.0.2
|
|
|