[Ocfs2-tools-devel] [PATCH] extras/check_metaecc: A tool to check metaecc of a metadata block, v3
Coly Li
coly.li at suse.de
Thu May 20 13:32:28 PDT 2010
Headache ... I use an openSUSE factory build on my development laptop, update to latest every day.
Today, I tried dozens times, the code can not pass ecc checking on an ecc-correct metadata block. I don't see coding
error in the patch, not sure whether there is something wrong in my development system environment. (When I tried to
test the code on my workstation, the harddisk of the workstation crashed, what a luck!)
Can anyone help me to test this patch on an ecc-correct meta data block ? The result will be very helpful, no matter
it's PASS or FAIL.
Thanks.
On 05/21/2010 04:08 AM, Sunil Mushran Wrote:
> 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
>>
>
--
Coly Li
SuSE Labs
More information about the Ocfs2-tools-devel
mailing list