[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