[Ocfs2-tools-devel] [PATCH] extras/check_metaecc: A tool to check metaecc of a metadata block
Sunil Mushran
sunil.mushran at oracle.com
Thu May 20 12:58:41 PDT 2010
One small comment. Else looks good.
On 05/20/2010 12:53 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>
> ---
> 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, "PASS\n");
> + fprintf(stderr, outbuf);
> + goto do_check_end;
> + }
>
We should differentiate between a clean PASS and PASS after ECC fixups.
Maybe call it "ECC Fixup" and call it a day.
> +
> + 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
>
> _______________________________________________
> Ocfs2-tools-devel mailing list
> Ocfs2-tools-devel at oss.oracle.com
> http://oss.oracle.com/mailman/listinfo/ocfs2-tools-devel
>
More information about the Ocfs2-tools-devel
mailing list