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

Sunil Mushran sunil.mushran at oracle.com
Thu May 20 13:08:54 PDT 2010


Signed-off-by: Sunil Mushran<sunil.mushran at oracle.com>


On 05/20/2010 01:19 PM, Coly Li wrote:
> 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>
> Cc: Sunil Mushran<sunil.mushran at oracle.com>
> Cc: Joel Becker<Joel.Becker at oracle.com>
> ---
>   extras/Makefile        |    8 +-
>   extras/check_metaecc.c |  292 ++++++++++++++++++++++++++++++++++++++++++++++++
>   include/ocfs2/ocfs2.h  |    8 ++
>   libocfs2/blockcheck.c  |    1 -
>   libocfs2/blockcheck.h  |   31 -----
>   5 files changed, 306 insertions(+), 34 deletions(-)
>
> 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..45e6386
> --- /dev/null
> +++ b/extras/check_metaecc.c
> @@ -0,0 +1,292 @@
> +/* -*- 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.
> + *
> + * 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<stdio.h>
> +
> +#include "ocfs2/ocfs2.h"
> +#include "ocfs2/byteorder.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 = 0;
> +
> +	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),
> +				"Unknow: 0x%x%x%x%x%x%x%x%x\n",
> +				signature[0], signature[1],
> +				signature[2], signature[3],
> +				signature[4], signature[5],
> +				signature[6], signature[7]);
> +			do_check = 0;
> +		}
> +	}
> +
> +	fprintf(stderr, "Signature of block #%"PRIu64" on "
> +		"device %s : \"%s\"\n", blk, dev, name);
> +
> +	/* modified from ocfs2_block_check_validate(),
> +	 * rested code is only display format related  */
> +	if (do_check) {
> +		struct ocfs2_block_check new_check;
> +		uint32_t crc, ecc;
> +		int crc_offset, result_offset, offset;
> +		char outbuf[256] = {0,};
> +
> +		new_check.bc_crc32e = le32_to_cpu(check.bc_crc32e);
> +		new_check.bc_ecc = le16_to_cpu(check.bc_ecc);
> +		memset(&check, 0, sizeof(struct ocfs2_block_check));
> +
> +		crc_offset = snprintf(outbuf, sizeof(outbuf),
> +				"Block %4"PRIu64"    ", blk);
> +		result_offset = snprintf(outbuf + crc_offset,
> +					sizeof(outbuf) - crc_offset,
> +					"CRC32: %.8"PRIx32"    "
> +					"ECC: %.4"PRIx16"    ",
> +					new_check.bc_crc32e, new_check.bc_ecc);
> +		result_offset += crc_offset;
> +
> +		/* Fast path - if the crc32 validates, we're good to go */
> +		crc = crc32_le(~0, (void *)block, fs->fs_blocksize);
> +		if (crc == new_check.bc_crc32e) {
> +			snprintf(outbuf + result_offset,
> +				sizeof(outbuf) - result_offset, "PASS\n");
> +			fprintf(stderr, outbuf);
> +			goto do_check_end;
> +		}
> +
> +		/* OK, try ECC fixups */
> +		ecc = ocfs2_hamming_encode_block(block, fs->fs_blocksize);
> +		ocfs2_hamming_fix_block(block, fs->fs_blocksize,
> +					ecc ^ new_check.bc_ecc);
> +
> +		crc = crc32_le(~0, (void *)block, fs->fs_blocksize);
> +		if (crc == new_check.bc_crc32e) {
> +			snprintf(outbuf + result_offset,
> +				sizeof(outbuf) - result_offset, "ECC Fixup\n");
> +			fprintf(stderr, outbuf);
> +			goto do_check_end;
> +		}
> +
> +		snprintf(outbuf + result_offset,
> +			sizeof(outbuf) - result_offset, "FAIL\n");
> +		fprintf(stderr, outbuf);
> +
> +		offset = snprintf(outbuf, sizeof(outbuf), "Calculated");
> +		while (offset<  crc_offset)
> +			outbuf[offset++] = ' ';
> +		snprintf(outbuf + crc_offset, sizeof(outbuf) - crc_offset,
> +			"CRC32: %.8"PRIx32"    ECC: %.4"PRIx16"\n",
> +			crc, ecc);
> +		fprintf(stderr, outbuf);
> +		err = -1;
> +do_check_end:
> +		check.bc_crc32e = cpu_to_le32(new_check.bc_crc32e);
> +		check.bc_ecc = cpu_to_le16(new_check.bc_ecc);
> +	}
> +
> +	return err;
> +}
> +
> +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);
> +
> +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;
> +}
> +
> diff --git a/include/ocfs2/ocfs2.h b/include/ocfs2/ocfs2.h
> index 2931207..e452960 100644
> --- a/include/ocfs2/ocfs2.h
> +++ b/include/ocfs2/ocfs2.h
> @@ -1539,6 +1539,14 @@ void release_lookup_res(struct ocfs2_dir_lookup_result *res);
>   int ocfs2_find_max_rec_len(ocfs2_filesys *fs, char *buf);
>   void ocfs2_dx_list_remove_entry(struct ocfs2_dx_entry_list *entry_list, int index);
>   int ocfs2_is_dir_trailer(ocfs2_filesys *fs, struct ocfs2_dinode *di, unsigned long de_off);
> +/* routines for block check */
> +uint32_t ocfs2_hamming_encode(uint32_t parity, void *data,
> +				unsigned int d, unsigned int nr);
> +uint32_t ocfs2_hamming_encode_block(void *data, unsigned int d);
> +void ocfs2_hamming_fix(void *data, unsigned int d,
> +			unsigned int nr, unsigned int fix);
> +void ocfs2_hamming_fix_block(void *data, unsigned int d, unsigned int fix);
> +uint32_t crc32_le(uint32_t crc, unsigned char const *p, size_t len);
>
>
>
> diff --git a/libocfs2/blockcheck.c b/libocfs2/blockcheck.c
> index 8263af7..adc2d8b 100644
> --- a/libocfs2/blockcheck.c
> +++ b/libocfs2/blockcheck.c
> @@ -34,7 +34,6 @@
>   #include "ocfs2/bitops.h"
>   #include "ocfs2/byteorder.h"
>
> -#include "blockcheck.h"
>   #include "crc32table.h"
>
>
> diff --git a/libocfs2/blockcheck.h b/libocfs2/blockcheck.h
> deleted file mode 100644
> index 253d936..0000000
> --- a/libocfs2/blockcheck.h
> +++ /dev/null
> @@ -1,31 +0,0 @@
> -/* -*- mode: c; c-basic-offset: 8; -*-
> - * vim: noexpandtab sw=8 ts=8 sts=0:
> - *
> - * blockcheck.h
> - *
> - * Checksum and ECC codes for the OCFS2 userspace library.
> - *
> - * Copyright (C) 2004, 2008 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 _BLOCKCHECK_H
> -#define _BLOCKCHECK_H
> -
> -extern uint32_t ocfs2_hamming_encode(uint32_t parity, void *data,
> -				     unsigned int d, unsigned int nr);
> -extern uint32_t ocfs2_hamming_encode_block(void *data, unsigned int d);
> -extern void ocfs2_hamming_fix(void *data, unsigned int d, unsigned int nr,
> -			      unsigned int fix);
> -extern void ocfs2_hamming_fix_block(void *data, unsigned int d,
> -				    unsigned int fix);
> -extern uint32_t crc32_le(uint32_t crc, unsigned char const *p, size_t len);
> -#endif
>    




More information about the Ocfs2-tools-devel mailing list