[Ocfs2-tools-devel] [PATCH] extras/check_metaecc: A tool to check metaecc of a metadata block

Coly Li coly.li at suse.de
Tue May 18 10:06:34 PDT 2010


check_metaecc can be used to check whether a specific block is
ecc-broken or not. When kernel reports an metaecc validation failure,
this tool can help us to check whether it's ecc broken block on disk, or
some error happens in memory.

Signed-off-by: Coly Li <coly.li at suse.de>
Cc: Mark Fasheh <mfasheh at suse.com>
---
 extras/Makefile        |    8 ++-
 extras/check_metaecc.c |  236 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 242 insertions(+), 2 deletions(-)
 create mode 100644 extras/check_metaecc.c

diff --git a/extras/Makefile b/extras/Makefile
index a7a1946..1203688 100644
--- a/extras/Makefile
+++ b/extras/Makefile
@@ -2,7 +2,7 @@ TOPDIR = ..
 
 include $(TOPDIR)/Preamble.make
 
-UNINST_PROGRAMS = find_hardlinks find_dup_extents find_inode_paths set_random_bits decode_lockres encode_lockres mark_journal_dirty find_allocation_fragments compute_groups
+UNINST_PROGRAMS = find_hardlinks find_dup_extents find_inode_paths set_random_bits decode_lockres encode_lockres mark_journal_dirty find_allocation_fragments compute_groups check_metaecc
 
 INCLUDES = -I$(TOPDIR)/include
 
@@ -15,8 +15,9 @@ ENCODE_LOCKRES_CFILES = encode_lockres.c
 MARK_JOURNAL_DIRTY_CFILES = mark_journal_dirty.c
 FIND_ALLOC_FRAG_CFILES = find_allocation_fragments.c
 COMPUTE_GROUPS_CFILES = compute_groups.c
+CHECK_METAECC_CFILES = check_metaecc.c
 
-DIST_FILES = $(FIND_HARDLINKS_CFILES) $(FIND_DUP_EXTENTS_CFILES) $(FIND_INODE_PATHS_CFILES) $(SET_RANDOM_BITS_CFILES) $(DECODE_LOCKRES_CFILES) $(ENCODE_LOCKRES_CFILES) $(MARK_JOURNAL_DIRTY_CFILES) $(FIND_ALLOC_FRAG_CFILES) $(COMPUTE_GROUPS_CFILES)
+DIST_FILES = $(FIND_HARDLINKS_CFILES) $(FIND_DUP_EXTENTS_CFILES) $(FIND_INODE_PATHS_CFILES) $(SET_RANDOM_BITS_CFILES) $(DECODE_LOCKRES_CFILES) $(ENCODE_LOCKRES_CFILES) $(MARK_JOURNAL_DIRTY_CFILES) $(FIND_ALLOC_FRAG_CFILES) $(COMPUTE_GROUPS_CFILES) $(CHECK_METAECC_CFILES)
 
 FIND_HARDLINKS_OBJS = $(subst .c,.o,$(FIND_HARDLINKS_CFILES))
 FIND_DUP_EXTENTS_OBJS = $(subst .c,.o,$(FIND_DUP_EXTENTS_CFILES))
@@ -27,6 +28,7 @@ ENCODE_LOCKRES_OBJS  = $(subst .c,.o,$(ENCODE_LOCKRES_CFILES))
 MARK_JOURNAL_DIRTY_OBJS = $(subst .c,.o,$(MARK_JOURNAL_DIRTY_CFILES))
 FIND_ALLOC_FRAG_OBJS = $(subst .c,.o,$(FIND_ALLOC_FRAG_CFILES))
 COMPUTE_GROUPS_OBJS = $(subst .c,.o,$(COMPUTE_GROUPS_CFILES))
+CHECK_METAECC_OBJS = $(subst .c,.o,$(CHECK_METAECC_CFILES))
 
 LIBOCFS2 = ../libocfs2/libocfs2.a
 EXTRAS_LIBS = $(LIBOCFS2) $(COM_ERR_LIBS)
@@ -58,4 +60,6 @@ find_allocation_fragments: $(FIND_ALLOC_FRAG_OBJS) $(LIBOCFS2)
 compute_groups: $(COMPUTE_GROUPS_OBJS) $(LIBOCFS2)
 	$(LINK) $(EXTRAS_LIBS)
 
+check_metaecc: $(CHECK_METAECC_OBJS) $(LIBOCFS2)
+	$(LINK) $(EXTRAS_LIBS)
 include $(TOPDIR)/Postamble.make
diff --git a/extras/check_metaecc.c b/extras/check_metaecc.c
new file mode 100644
index 0000000..ea6d687
--- /dev/null
+++ b/extras/check_metaecc.c
@@ -0,0 +1,236 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * check_metaecc.c
+ *
+ * Simple tool to check ecc of a metadata block.
+ *
+ * Copyright (C) 2010 Novell.  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: Coly Li <coly.li at suse.de>
+ *
+ */
+
+#define _XOPEN_SOURCE 600 /* Triggers magic in features.h */
+#define _LARGEFILE64_SOURCE
+
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <inttypes.h>
+
+#include "ocfs2/ocfs2.h"
+
+static void print_usage(void)
+{
+	fprintf(stderr,
+		"Usage: check_metaecc <device> <block #>\n");
+	exit(1);
+}
+
+/* copied from find_inode_paths.c */
+static uint64_t read_number(const char *num)
+{
+	uint64_t val;
+	char *ptr;
+
+	val = strtoull(num, &ptr, 0);
+	if (!ptr || *ptr)
+		return 0;
+
+	return val;
+}
+
+static errcode_t check_metaecc(ocfs2_filesys *fs,
+			uint64_t blk,
+			char *dev,
+			char *block)
+{
+	char signature[8];
+	char name[256] = {0, };
+	struct ocfs2_block_check check;
+	int do_check = 1;
+	errcode_t err = OCFS2_ET_INVALID_ARGUMENT;
+
+	memcpy(signature, block, sizeof(signature));
+
+	if (!strncmp(signature, OCFS2_SUPER_BLOCK_SIGNATURE,
+			sizeof(OCFS2_SUPER_BLOCK_SIGNATURE))) {
+		struct ocfs2_dinode *di = (struct ocfs2_dinode *)block;
+		check = di->i_check;
+		snprintf(name, sizeof(name), OCFS2_SUPER_BLOCK_SIGNATURE);
+	} else if (!strncmp(signature, OCFS2_INODE_SIGNATURE,
+			sizeof(OCFS2_INODE_SIGNATURE))) {
+		struct ocfs2_dinode *di;
+		di = (struct ocfs2_dinode *)block;
+		check = di->i_check;
+		snprintf(name, sizeof(name), OCFS2_INODE_SIGNATURE);
+	} else if (!strncmp(signature, OCFS2_EXTENT_BLOCK_SIGNATURE,
+			sizeof(OCFS2_EXTENT_BLOCK_SIGNATURE))) {
+		struct ocfs2_extent_block *eb;
+		eb = (struct ocfs2_extent_block *)block;
+		check = eb->h_check;
+		snprintf(name, sizeof(name), OCFS2_EXTENT_BLOCK_SIGNATURE);
+	} else if (!strncmp(signature, OCFS2_GROUP_DESC_SIGNATURE,
+			sizeof(OCFS2_GROUP_DESC_SIGNATURE))) {
+		struct ocfs2_group_desc *gd;
+		gd = (struct ocfs2_group_desc *)block;
+		check = gd->bg_check;
+		snprintf(name, sizeof(name), OCFS2_GROUP_DESC_SIGNATURE);
+	} else if (!strncmp(signature, OCFS2_XATTR_BLOCK_SIGNATURE,
+			sizeof(OCFS2_XATTR_BLOCK_SIGNATURE))) {
+		struct ocfs2_xattr_block *xb;
+		xb = (struct ocfs2_xattr_block *)block;
+		check = xb->xb_check;
+		snprintf(name, sizeof(name), OCFS2_XATTR_BLOCK_SIGNATURE);
+	} else if (!strncmp(signature, OCFS2_REFCOUNT_BLOCK_SIGNATURE,
+			sizeof(OCFS2_REFCOUNT_BLOCK_SIGNATURE))) {
+		struct ocfs2_refcount_block *rb;
+		rb = (struct ocfs2_refcount_block *)block;
+		check = rb->rf_check;
+		snprintf(name, sizeof(name), OCFS2_REFCOUNT_BLOCK_SIGNATURE);
+	} else if (!strncmp(signature, OCFS2_DX_ROOT_SIGNATURE,
+			sizeof(OCFS2_DX_ROOT_SIGNATURE))) {
+		struct ocfs2_dx_root_block *dx_root;
+		dx_root = (struct ocfs2_dx_root_block *)block;
+		check = dx_root->dr_check;
+		snprintf(name, sizeof(name), OCFS2_DX_ROOT_SIGNATURE);
+	} else if (!strncmp(signature, OCFS2_DX_LEAF_SIGNATURE,
+			sizeof(OCFS2_DX_LEAF_SIGNATURE))) {
+		struct ocfs2_dx_leaf *dx_leaf;
+		dx_leaf = (struct ocfs2_dx_leaf *)block;
+		check = dx_leaf->dl_check;
+		snprintf(name, sizeof(name), OCFS2_DX_LEAF_SIGNATURE);
+	} else {
+		if (ocfs2_supports_dir_trailer(fs)) {
+			struct ocfs2_dir_block_trailer *trailer;
+			trailer = ocfs2_dir_trailer_from_block(fs, block);
+			if (!strncmp((char *)trailer->db_signature, OCFS2_DIR_TRAILER_SIGNATURE,
+					sizeof(OCFS2_DIR_TRAILER_SIGNATURE))) {
+				check = trailer->db_check;
+				snprintf(name, sizeof(name), OCFS2_DIR_TRAILER_SIGNATURE);
+			}
+		} else {
+			snprintf(name, sizeof(name), "No signature found");
+			do_check = 0;
+		}
+	}
+
+	fprintf(stderr, "Signature of block #%"PRIu64" on device %s : \"%s\"\n", blk, dev, name);
+
+	if (do_check)
+		err = ocfs2_block_check_validate(block, fs->fs_blocksize, &check);
+
+	return err;
+}
+
+extern int opterr, optind;
+extern char *optarg;
+
+int main(int argc, char *argv[])
+{
+	errcode_t err;
+	int ret = 1;
+	int force = 0;
+	ocfs2_filesys *fs;
+	char *dev, *block;
+	uint64_t blkno;
+	char c;
+
+	static struct option long_options[] = {
+		{"force", 0, 0, 'F'},
+		{0, 0, 0, 0}
+	};
+
+	while(1) {
+		c = getopt_long(argc, argv, "F", long_options, NULL);
+		if (c == -1)
+			break;
+
+		switch (c) {
+			case 'F':
+				force = 1;
+				break;
+			default:
+				print_usage();
+				break;
+		}
+	}
+	if (optind != (argc - 2))
+		print_usage();
+
+	initialize_ocfs_error_table();
+
+	dev = argv[optind];
+	blkno = read_number(argv[optind + 1]);
+	if (blkno == 0) {
+		fprintf(stderr, "invalid block number\n");
+		print_usage();
+	}
+
+	err = ocfs2_open(dev, OCFS2_FLAG_RO, 0, 0, &fs);
+	if (err) {
+		com_err(argv[0], err,
+			"while opening device \"%s\"", dev);
+		goto out;
+	}
+
+	if (!ocfs2_meta_ecc(OCFS2_RAW_SB(fs->fs_super))) {
+		fprintf(stderr, "metaecc feature is not enabled on volume %s, "
+			"validation might be invalid.\n", dev);
+		if (!force) {
+			fprintf(stderr, "To skip this check, use --force or -F\n");
+			goto out;
+		}
+	}
+
+	err = ocfs2_malloc_block(fs->fs_io, &block);
+	if (err) {
+		com_err(argv[0], err,
+			"while reading block #%"PRIu64" on \"%s\"\n",
+			blkno, dev);
+		goto out_close;
+	}
+
+	err = ocfs2_read_blocks(fs, blkno, 1, block);
+	if (err) {
+		com_err(argv[0], err,
+			"while reading block #%"PRIu64" on \"%s\"\n",
+			blkno, dev);
+		goto out_free;
+	}
+
+	err = check_metaecc(fs, blkno, dev, block);
+	if (err == 0) {
+		fprintf(stderr, "Metadata block %"PRIu64" ecc check OK.\n", blkno);
+		ret = 0;
+	} else if (err != OCFS2_ET_INVALID_ARGUMENT)
+		fprintf(stderr, "Metadata block %"PRIu64" ecc check failed.\n", blkno);
+
+out_free:
+	ocfs2_free(&block);
+out_close:
+	err = ocfs2_close(fs);
+	if (err) {
+		com_err(argv[0], err,
+			"while closing device \"%s\"", dev);
+		ret = 1;
+	}
+out:
+	return ret;
+}
+
-- 
1.7.0.3




More information about the Ocfs2-tools-devel mailing list