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

Sunil Mushran sunil.mushran at oracle.com
Tue May 18 10:55:08 PDT 2010


I have added some comments that should be easy to implement.

But I am wondering whether we should extend this tool a bit and
make it work without using ocfs2_open(). fake_fs, maybe. Because
it won't work if superblock has the problem. Other option is to teach
it to use backup superblocks.

Having said that, I am ok with this tool. Something is always better
than nothing.

Sunil

On 05/18/2010 10:06 AM, 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 |  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.
> + *
>    

Please remove this para. "You should... USA". FSF is recommending
the para be dropped from the copyright header.

> + * 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)
>    

Please align the params.

+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");
>    

Instead say "Unknown: 0x3556789056789045"

> +			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);
>    

This tool will be useful when we have a problem. And when we do, we'd like
to know the "correct" and "bad" checksums. Please can you print both.

> +
> +	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;
> +}
> +
>    




More information about the Ocfs2-tools-devel mailing list