[Ocfs2-tools-devel] [PATCH 46/50] fswreck: Add refcount block corruption.
Tao Ma
tao.ma at oracle.com
Mon Jan 11 07:31:32 PST 2010
Add some basic corruptions for a refcount block:
RB_BLKNO, RB_GEN, RB_GEN_FIX, RB_PARENT.
Signed-off-by: Tao Ma <tao.ma at oracle.com>
---
fswreck/Makefile | 5 +-
fswreck/corrupt.c | 27 +++++
fswreck/include/corrupt.h | 1 +
fswreck/include/fsck_type.h | 10 ++-
fswreck/include/main.h | 1 +
fswreck/include/refcount.h | 23 ++++
fswreck/main.c | 12 ++
fswreck/refcount.c | 259 +++++++++++++++++++++++++++++++++++++++++++
8 files changed, 335 insertions(+), 3 deletions(-)
create mode 100644 fswreck/include/refcount.h
create mode 100644 fswreck/refcount.c
diff --git a/fswreck/Makefile b/fswreck/Makefile
index 7e688f9..65dffd6 100644
--- a/fswreck/Makefile
+++ b/fswreck/Makefile
@@ -10,7 +10,7 @@ INCLUDES += $(GLIB_CFLAGS)
UNINST_PROGRAMS = fswreck
-CFILES = main.c corrupt.c chain.c extent.c group.c inode.c local_alloc.c truncate_log.c special.c symlink.c dir.c journal.c quota.c
+CFILES = main.c corrupt.c chain.c extent.c group.c inode.c local_alloc.c truncate_log.c special.c symlink.c dir.c journal.c quota.c refcount.c
HFILES = \
include/chain.h \
@@ -26,7 +26,8 @@ HFILES = \
include/journal.h \
include/main.h \
include/symlink.h \
- include/quota.h
+ include/quota.h \
+ include/refcount.h
DIST_FILES = $(CFILES) $(HFILES)
DIST_RULES = dist-subdircreate
diff --git a/fswreck/corrupt.c b/fswreck/corrupt.c
index a69ae20..951e4f5 100644
--- a/fswreck/corrupt.c
+++ b/fswreck/corrupt.c
@@ -466,3 +466,30 @@ void corrupt_truncate_log(ocfs2_filesys *fs, enum fsck_type type,
return;
}
+
+void corrupt_refcount(ocfs2_filesys *fs, enum fsck_type type, uint16_t slotnum)
+{
+ uint64_t blkno;
+ void (*func)(ocfs2_filesys *fs,
+ enum fsck_type type, uint64_t blkno) = NULL;
+
+ switch (type) {
+ case RB_BLKNO:
+ case RB_GEN:
+ case RB_GEN_FIX:
+ case RB_PARENT:
+ case REFCOUNT_BLOCK_INVALID:
+ case REFCOUNT_ROOT_BLOCK_INVALID:
+ func = mess_up_refcount_tree_block;
+ break;
+ default:
+ FSWRK_FATAL("Invalid code = %d", type);
+ }
+
+ create_named_directory(fs, "tmp", &blkno);
+
+ if (func)
+ func(fs, type, blkno);
+
+ return;
+}
diff --git a/fswreck/include/corrupt.h b/fswreck/include/corrupt.h
index 393e495..3aebb28 100644
--- a/fswreck/include/corrupt.h
+++ b/fswreck/include/corrupt.h
@@ -35,5 +35,6 @@ void corrupt_local_alloc(ocfs2_filesys *fs, enum fsck_type type,
uint16_t slotnum);
void corrupt_truncate_log(ocfs2_filesys *fs, enum fsck_type type,
uint16_t slotnum);
+void corrupt_refcount(ocfs2_filesys *fs, enum fsck_type type, uint16_t slotnum);
#endif /* __CORRUPT_H */
diff --git a/fswreck/include/fsck_type.h b/fswreck/include/fsck_type.h
index 5721817..d34d2a9 100644
--- a/fswreck/include/fsck_type.h
+++ b/fswreck/include/fsck_type.h
@@ -137,6 +137,12 @@ enum fsck_type
DUP_DQBLK_VALID,
REFCOUNT_FLAG_INVALID,
REFCOUNT_LOC_INVALID,
+ RB_BLKNO,
+ RB_GEN,
+ RB_GEN_FIX,
+ RB_PARENT,
+ REFCOUNT_BLOCK_INVALID,
+ REFCOUNT_ROOT_BLOCK_INVALID,
NUM_FSCK_TYPE
};
@@ -223,6 +229,8 @@ enum fsck_type
* DUP_CLUSTERS_SYSFILE_CLONE
*
* refcount tree error: EXTENT_MARKED_REFCOUNTED, REFCOUNT_FLAG_INVALID,
- * REFCOUNT_LOC_INVALID
+ * REFCOUNT_LOC_INVALID, RB_BLKNO, RB_GEN, RB_GEN_FIX,
+ * RB_PARENT, REFCOUNT_BLOCK_INVALID,
+ * REFCOUNT_ROOT_BLOCK_INVALID
*/
#endif
diff --git a/fswreck/include/main.h b/fswreck/include/main.h
index a5f69ea..94682f4 100644
--- a/fswreck/include/main.h
+++ b/fswreck/include/main.h
@@ -90,5 +90,6 @@
#include "dir.h"
#include "journal.h"
#include "quota.h"
+#include "refcount.h"
#endif /* __MAIN_H__ */
diff --git a/fswreck/include/refcount.h b/fswreck/include/refcount.h
new file mode 100644
index 0000000..ab4967e
--- /dev/null
+++ b/fswreck/include/refcount.h
@@ -0,0 +1,23 @@
+/*
+ * refcount.h
+ *
+ * Function prototypes, macros, etc. for related 'C' files
+ *
+ * Copyright (C) 2009 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.
+ */
+
+#ifndef _FSWRECK_REFCOUNT_H_
+#define _FSWRECK_REFCOUNT_H_
+
+void mess_up_refcount_tree_block(ocfs2_filesys *fs, enum fsck_type type,
+ uint64_t blkno);
+#endif /* _FSWRECK_REFCOUNT_H_ */
diff --git a/fswreck/main.c b/fswreck/main.c
index bcd4469..00285a2 100644
--- a/fswreck/main.c
+++ b/fswreck/main.c
@@ -266,6 +266,18 @@ static struct prompt_code prompt_codes[NUM_FSCK_TYPE] = {
"Create a refcounted inode on a unsupported volume"),
define_prompt_code(REFCOUNT_LOC_INVALID, corrupt_file,
"Corrupt a refcounted file's refcount location"),
+ define_prompt_code(RB_BLKNO, corrupt_refcount,
+ "Corrupt a refcount block's rf_blkno"),
+ define_prompt_code(RB_GEN, corrupt_refcount,
+ "Corrupt a refcount block's generation"),
+ define_prompt_code(RB_GEN_FIX, corrupt_refcount,
+ "Corrupt a refcount block's generation"),
+ define_prompt_code(RB_PARENT, corrupt_refcount,
+ "Corrupt a refcount block's rf_parent"),
+ define_prompt_code(REFCOUNT_BLOCK_INVALID, corrupt_refcount,
+ "Corrupt a refcount block's rf_parent"),
+ define_prompt_code(REFCOUNT_ROOT_BLOCK_INVALID, corrupt_refcount,
+ "Corrupt a refcount block's rf_parent"),
};
#undef define_prompt_code
diff --git a/fswreck/refcount.c b/fswreck/refcount.c
new file mode 100644
index 0000000..a955f44
--- /dev/null
+++ b/fswreck/refcount.c
@@ -0,0 +1,259 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * refcount.c
+ *
+ * Copyright (C) 2009 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.
+ */
+
+#include <assert.h>
+#include "main.h"
+
+extern char *progname;
+
+/*
+ * Create a refcount tree.
+ *
+ * If tree = 0, the root is just a refcount block with refcount recs.
+ * Otherwise, we will create a refcount extent tree.
+ *
+ */
+static void create_refcount_tree(ocfs2_filesys *fs, uint64_t blkno,
+ uint64_t *rf_blkno, int tree_depth)
+{
+ errcode_t ret;
+ uint64_t file1, file2, file3, root_blkno, new_clusters, tmpblk;
+ int i, recs_num = ocfs2_refcount_recs_per_rb(fs->fs_blocksize);
+ int bpc = ocfs2_clusters_to_blocks(fs, 1), offset = 0;
+ uint32_t n_clusters;
+ uint64_t file_size;
+
+ /*
+ * Create 3 files.
+ * file1 and file2 are used to sharing a refcount tree.
+ * file2 is used to waste some clusters so that the refcount
+ * tree won't be increased easily.
+ */
+ create_file(fs, blkno, &file1);
+ create_file(fs, blkno, &file2);
+ create_file(fs, blkno, &file3);
+
+ ret = ocfs2_new_refcount_block(fs, &root_blkno, 0, 0);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
+
+ /* attach the create refcount tree in these 2 files. */
+ ret = ocfs2_attach_refcount_tree(fs, file1, root_blkno);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
+ ret = ocfs2_attach_refcount_tree(fs, file2, root_blkno);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
+
+ /*
+ * Calculate how much clusters we need in order to create
+ * the required extent tree.
+ */
+ new_clusters = 1;
+ while (tree_depth-- > 0)
+ new_clusters *= recs_num;
+ new_clusters += recs_num / 2;
+
+ /*
+ * We double the new_clusters so that half of them will be inserted
+ * into tree, while another half is inserted into file3.
+ */
+ new_clusters *= 2;
+ while (new_clusters) {
+ ret = ocfs2_new_clusters(fs, 1, new_clusters, &blkno,
+ &n_clusters);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
+ if (!n_clusters)
+ FSWRK_FATAL("ENOSPC");
+
+ /*
+ * In order to ensure the extent records are not coalesced,
+ * we insert each cluster in reverse.
+ */
+ for (i = n_clusters; i > 1; i -= 2, offset++) {
+ tmpblk = blkno + ocfs2_clusters_to_blocks(fs, i - 2);
+ ret = ocfs2_inode_insert_extent(fs, file1, offset,
+ tmpblk, 1,
+ OCFS2_EXT_REFCOUNTED);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
+ ret = ocfs2_inode_insert_extent(fs, file2, offset,
+ tmpblk, 1,
+ OCFS2_EXT_REFCOUNTED);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
+
+ ret = ocfs2_change_refcount(fs, root_blkno,
+ ocfs2_blocks_to_clusters(fs, tmpblk),
+ 1, 2);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
+
+ ret = ocfs2_inode_insert_extent(fs, file3, offset,
+ tmpblk + bpc, 1, 0);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
+
+ }
+ new_clusters -= n_clusters;
+ }
+
+ file_size = (offset + 1) * fs->fs_clustersize;
+ ret = ocfs2_extend_file(fs, file1, file_size);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
+ ret = ocfs2_extend_file(fs, file2, file_size);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
+ ret = ocfs2_extend_file(fs, file3, file_size);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
+
+
+ *rf_blkno = root_blkno;
+
+ return;
+}
+
+static void damage_refcount_block(ocfs2_filesys *fs, enum fsck_type type,
+ struct ocfs2_refcount_block *rb)
+{
+ uint32_t oldno;
+ uint64_t oldblkno;
+
+ switch (type) {
+ case RB_BLKNO:
+ oldblkno = rb->rf_blkno;
+ rb->rf_blkno += 1;
+ fprintf(stdout, "RB_BLKNO: "
+ "change refcount block's number from %"PRIu64" to "
+ "%"PRIu64"\n", oldblkno, (uint64_t)rb->rf_blkno);
+ break;
+ case RB_GEN:
+ case RB_GEN_FIX:
+ oldno = rb->rf_fs_generation;
+ rb->rf_fs_generation = 0x1234;
+ if (type == RB_GEN)
+ fprintf(stdout, "RB_GEN: ");
+ else if (type == RB_GEN_FIX)
+ fprintf(stdout, "RB_GEN_FIX: ");
+ fprintf(stdout, "change refcount block %"PRIu64
+ " generation number from 0x%x to 0x%x\n",
+ (uint64_t)rb->rf_blkno, oldno, rb->rf_fs_generation);
+ break;
+ case RB_PARENT:
+ oldblkno = rb->rf_parent;
+ rb->rf_parent += 1;
+ fprintf(stdout, "RB_PARENT: "
+ "change refcount block's parent from %"PRIu64" to "
+ "%"PRIu64"\n", oldblkno, (uint64_t)rb->rf_parent);
+ break;
+ case REFCOUNT_BLOCK_INVALID:
+ case REFCOUNT_ROOT_BLOCK_INVALID:
+ memset(rb->rf_signature, 'a', sizeof(rb->rf_signature));
+ fprintf(stdout, "Corrupt the signature of refcount block "
+ "%"PRIu64"\n", (uint64_t)rb->rf_blkno);
+ break;
+ default:
+ FSWRK_FATAL("Invalid type=%d", type);
+ }
+}
+
+void mess_up_refcount_tree_block(ocfs2_filesys *fs, enum fsck_type type,
+ uint64_t blkno)
+{
+ errcode_t ret;
+ char *buf1 = NULL, *buf2 = NULL, *buf2_leaf = NULL;
+ uint64_t rf_blkno1, rf_blkno2, rf_leaf_blkno;
+ struct ocfs2_refcount_block *rb1, *rb2, *rb2_leaf;
+
+ if (!ocfs2_refcount_tree(OCFS2_RAW_SB(fs->fs_super)))
+ FSWRK_FATAL("Should specify a refcount supported "
+ "volume to do this corruption\n");
+
+ ret = ocfs2_malloc_block(fs->fs_io, &buf1);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
+ ret = ocfs2_malloc_block(fs->fs_io, &buf2);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
+ ret = ocfs2_malloc_block(fs->fs_io, &buf2_leaf);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
+
+ /*
+ * We create 2 refcount trees. One only has a root refcount block,
+ * and the other has a tree with depth = 1. So we can corrupt both
+ * of them and verify whether fsck works for different block types.
+ */
+ create_refcount_tree(fs, blkno, &rf_blkno1, 0);
+ create_refcount_tree(fs, blkno, &rf_blkno2, 1);
+
+ ret = ocfs2_read_refcount_block(fs, rf_blkno1, buf1);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
+ rb1 = (struct ocfs2_refcount_block *)buf1;
+
+ /* tree 2 is an extent tree, so find the 1st leaf refcount block. */
+ ret = ocfs2_read_refcount_block(fs, rf_blkno2, buf2);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
+ rb2 = (struct ocfs2_refcount_block *)buf2;
+ assert(rb2->rf_flags & OCFS2_REFCOUNT_TREE_FL);
+ rf_leaf_blkno = rb2->rf_list.l_recs[0].e_blkno;
+ ret = ocfs2_read_refcount_block(fs, rf_leaf_blkno, buf2_leaf);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
+ rb2_leaf = (struct ocfs2_refcount_block *)buf2_leaf;
+
+ switch (type) {
+ case RB_BLKNO:
+ case RB_GEN:
+ case RB_GEN_FIX:
+ damage_refcount_block(fs, type, rb1);
+ damage_refcount_block(fs, type, rb2_leaf);
+ break;
+ case RB_PARENT:
+ damage_refcount_block(fs, type, rb2_leaf);
+ break;
+ case REFCOUNT_BLOCK_INVALID:
+ damage_refcount_block(fs, type, rb2_leaf);
+ break;
+ case REFCOUNT_ROOT_BLOCK_INVALID:
+ damage_refcount_block(fs, type, rb1);
+ damage_refcount_block(fs, type, rb2);
+ break;
+ default:
+ FSWRK_FATAL("Invalid type[%d]\n", type);
+ }
+
+ ret = ocfs2_write_refcount_block(fs, rf_blkno1, buf1);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
+ ret = ocfs2_write_refcount_block(fs, rf_blkno2, buf2);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
+ ret = ocfs2_write_refcount_block(fs, rf_leaf_blkno, buf2_leaf);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
+ ocfs2_free(&buf1);
+ ocfs2_free(&buf2);
+ ocfs2_free(&buf2_leaf);
+
+ return;
+}
--
1.5.5
More information about the Ocfs2-tools-devel
mailing list