[Ocfs2-tools-devel] [PATCH 1/1] Ocfs2-tools: Add quota corruption codes to fswreck.

Tristan tristan.ye at oracle.com
Thu Oct 8 20:15:32 PDT 2009


Jan Kara wrote:
>   Hi Tristan,
>
> On Wed 30-09-09 10:25:58, Tristan wrote:
>   
>> Patch below sent days ago may need your review:-)
>>     
>   Thanks for a reminder.
>
>   
>> Tristan Ye wrote:
>>     
>>> As the quota supports on ocfs2-tools got finished, we therefore
>>> have to support such quota corruptions in fswreck to make it compatible
>>> with corresponding codes in fsck.ocfs2. Following five fsck codes will be
>>> added in fswreck to support new quota corruptions.
>>>
>>> 	QMAGIC_INVALID,
>>> 	QTREE_BLK_INVALID,
>>> 	DQBLK_INVALID,
>>> 	DUP_DQBLK_INVALID,
>>> 	DUP_DQBLK_VALID
>>>
>>> Signed-off-by: Tristan Ye <tristan.ye at oracle.com>
>>>
>>> ---
>>>  fswreck/Makefile            |    5 +-
>>>  fswreck/corrupt.c           |    7 +
>>>  fswreck/include/fsck_type.h |   13 ++-
>>>  fswreck/include/main.h      |    1 +
>>>  fswreck/include/quota.h     |   23 ++++
>>>  fswreck/main.c              |   16 ++-
>>>  fswreck/quota.c             |  278 +++++++++++++++++++++++++++++++++++++++++++
>>>  7 files changed, 336 insertions(+), 7 deletions(-)
>>>  create mode 100644 fswreck/include/quota.h
>>>  create mode 100644 fswreck/quota.c
>>>
>>> diff --git a/fswreck/Makefile b/fswreck/Makefile
>>> index d5b4e6c..7e688f9 100644
>>> --- a/fswreck/Makefile
>>> +++ b/fswreck/Makefile
>>> @@ -10,7 +10,7 @@ INCLUDES += $(GLIB_CFLAGS)
>>>   UNINST_PROGRAMS = fswreck
>>>  -CFILES = main.c corrupt.c chain.c extent.c group.c inode.c local_alloc.c 
>>> truncate_log.c special.c symlink.c dir.c journal.c
>>> +CFILES = main.c corrupt.c chain.c extent.c group.c inode.c local_alloc.c truncate_log.c special.c symlink.c dir.c journal.c quota.c
>>>   HFILES = 			\
>>>  	include/chain.h		\
>>> @@ -25,7 +25,8 @@ HFILES = 			\
>>>  	include/group.h		\
>>>  	include/journal.h	\
>>>  	include/main.h		\
>>> -	include/symlink.h
>>> +	include/symlink.h	\
>>> +	include/quota.h
>>>   DIST_FILES = $(CFILES) $(HFILES)
>>>  DIST_RULES = dist-subdircreate
>>> diff --git a/fswreck/corrupt.c b/fswreck/corrupt.c
>>> index e6f2bf3..f0c89cf 100644
>>> --- a/fswreck/corrupt.c
>>> +++ b/fswreck/corrupt.c
>>> @@ -332,6 +332,13 @@ void corrupt_sys_file(ocfs2_filesys *fs, enum fsck_type type, uint16_t slotnum)
>>>  	case JOURNAL_TOO_SMALL:
>>>  		func = mess_up_journal;
>>>  		break;
>>> +	case QMAGIC_INVALID:
>>> +	case QTREE_BLK_INVALID:
>>> +	case DQBLK_INVALID:
>>> +	case DUP_DQBLK_INVALID:
>>> +	case DUP_DQBLK_VALID:
>>> +		func = mess_up_quota;
>>> +		break;
>>>  	default:
>>>  		FSWRK_FATAL("Invalid code=%d", type);
>>>  	}
>>> diff --git a/fswreck/include/fsck_type.h b/fswreck/include/fsck_type.h
>>> index c385383..7f3430f 100644
>>> --- a/fswreck/include/fsck_type.h
>>> +++ b/fswreck/include/fsck_type.h
>>> @@ -129,6 +129,11 @@ enum fsck_type
>>>  	JOURNAL_UNKNOWN_FEATURE,
>>>  	JOURNAL_MISSING_FEATURE,
>>>  	JOURNAL_TOO_SMALL,
>>> +	QMAGIC_INVALID,
>>> +	QTREE_BLK_INVALID,
>>> +	DQBLK_INVALID,
>>> +	DUP_DQBLK_INVALID,
>>> +	DUP_DQBLK_VALID,
>>>  	NUM_FSCK_TYPE
>>>  };
>>>  @@ -186,9 +191,13 @@ enum fsck_type
>>>   *
>>>   * Special files error: ROOT_NOTDIR, ROOT_DIR_MISSING, LOSTFOUND_MISSING,
>>>   *			DIR_DOTDOT
>>> + *
>>>   * Journal file error:	JOURNAL_FILE_INVALID, JOURNAL_UNKNOWN_FEATURE,
>>> -			JOURNAL_MISSING_FEATURE, JOURNAL_TOO_SMALL.
>>> - * 	
>>> + *			JOURNAL_MISSING_FEATURE, JOURNAL_TOO_SMALL.
>>> + *
>>> + * Quota file error:	QMAGIC_INVALID, QTREE_BLK_INVALID, DQBLK_INVALID
>>> + *			DUP_DQBLK_INVALID, DUP_DQBLK_VALID
>>> + *   * Link file error: LINK_FAST_DATA, LINK_NULLTERM, LINK_SIZE, 
>>> LINK_BLOCKS
>>>   *
>>>   * Directory inode error: DIR_ZERO
>>> diff --git a/fswreck/include/main.h b/fswreck/include/main.h
>>> index daedc0a..a5f69ea 100644
>>> --- a/fswreck/include/main.h
>>> +++ b/fswreck/include/main.h
>>> @@ -89,5 +89,6 @@
>>>  #include "special.h"
>>>  #include "dir.h"
>>>  #include "journal.h"
>>> +#include "quota.h"
>>>   #endif		/* __MAIN_H__ */
>>> diff --git a/fswreck/include/quota.h b/fswreck/include/quota.h
>>> new file mode 100644
>>> index 0000000..e50621b
>>> --- /dev/null
>>> +++ b/fswreck/include/quota.h
>>> @@ -0,0 +1,23 @@
>>> +/* -*- mode: c; c-basic-offset: 8; -*-
>>> + * vim: noexpandtab sw=8 ts=8 sts=0:
>>> + *
>>> + * quota.h
>>> + *
>>> + * 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 __QUOTA_H
>>> +#define __QUOTA_H
>>> +
>>> +void mess_up_quota(ocfs2_filesys *fs, enum fsck_type type, uint16_t slotnum);
>>> +
>>> +#endif		/* __QUOTA_H */
>>> diff --git a/fswreck/main.c b/fswreck/main.c
>>> index 85b0472..0910188 100644
>>> --- a/fswreck/main.c
>>> +++ b/fswreck/main.c
>>> @@ -9,12 +9,12 @@
>>>   * modify it under the terms of the GNU General Public
>>>   * License as published by the Free Software Foundation; either
>>>   * version 2 of the License, or (at your option) any later version.
>>> - * + *
>>>   * 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,
>>> @@ -249,6 +249,16 @@ static struct prompt_code prompt_codes[NUM_FSCK_TYPE] = {
>>>  			   "Corrupt journal file by missing features."),
>>>  	define_prompt_code(JOURNAL_TOO_SMALL, corrupt_sys_file,
>>>  			   "Corrupt journal file as a too small one."),
>>> +	define_prompt_code(QMAGIC_INVALID, corrupt_sys_file,
>>> +			   "Corrupt quota system file's header."),
>>> +	define_prompt_code(QTREE_BLK_INVALID, corrupt_sys_file,
>>> +			   "Corrupt quota tree block."),
>>> +	define_prompt_code(DQBLK_INVALID, corrupt_sys_file,
>>> +			   "Corrupt quota data blok."),
>>> +	define_prompt_code(DUP_DQBLK_INVALID, corrupt_sys_file,
>>> +			   "Duplicate a invalid quota limits."),
>>> +	define_prompt_code(DUP_DQBLK_VALID, corrupt_sys_file,
>>> +			   "Duplicate a valid quota limits."),
>>>  };
>>>   #undef define_prompt_code
>>> @@ -373,7 +383,7 @@ static int read_options(int argc, char **argv)
>>>  		return 1;
>>>  	}
>>>  -	while(1) {
>>> +	while (1) {
>>>  		c = getopt(argc, argv, "c:n:");
>>>  		if (c == -1)
>>>  			break;
>>> diff --git a/fswreck/quota.c b/fswreck/quota.c
>>> new file mode 100644
>>> index 0000000..cee1f26
>>> --- /dev/null
>>> +++ b/fswreck/quota.c
>>> @@ -0,0 +1,278 @@
>>> +/* -*- mode: c; c-basic-offset: 8; -*-
>>> + * vim: noexpandtab sw=8 ts=8 sts=0:
>>> + *
>>> + * quota.c
>>> + *
>>> + * Copyright (C) 2004, 2008 Oracle.  All rights reserved.
>>> + *
>>> + * Corruptions for quota system file.
>>> + *
>>> + * 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.
>>> + */
>>> +
>>> +#include "main.h"
>>> +
>>> +extern char *progname;
>>> +static int g_actref;
>>> +
>>> +/* This file will corrupt quota system file.
>>> + *
>>> + * Quota Error: QMAGIC_INVALID, QTREE_BLK_INVALID, DQBLK_INVALID
>>> + *		DUP_DQBLK_INVALID, DUP_DQBLK_VALID
>>> + *
>>> + */
>>> +
>>> +static char *type2name(int type)
>>> +{
>>> +	if (type == USRQUOTA)
>>> +		return "user";
>>> +
>>> +	return "group";
>>> +}
>>> +
>>> +static errcode_t o2fswreck_read_blk(ocfs2_filesys *fs, int type, char *buf,
>>> +				    uint32_t blk)
>>> +{
>>> +	uint32_t got;
>>> +	errcode_t ret;
>>> +
>>> +	ret = ocfs2_file_read(fs->qinfo[type].qi_inode, buf, fs->fs_blocksize,
>>> +			      blk * fs->fs_blocksize, &got);
>>> +	if (ret)
>>> +		return ret;
>>> +	if (got != fs->fs_blocksize)
>>> +		return OCFS2_ET_SHORT_READ;
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static errcode_t o2fswreck_write_blk(ocfs2_filesys *fs, int type, char *buf,
>>> +				     uint32_t blk)
>>> +{
>>> +	errcode_t err;
>>> +	uint32_t written;
>>> +
>>> +	err = ocfs2_file_write(fs->qinfo[type].qi_inode, buf, fs->fs_blocksize,
>>> +			       blk * fs->fs_blocksize, &written);
>>> +	if (err)
>>> +		return err;
>>> +	if (written != fs->fs_blocksize)
>>> +		return OCFS2_ET_SHORT_WRITE;
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +
>>> +static errcode_t o2fswreck_get_data_blk(ocfs2_filesys *fs, int type,
>>> +					uint32_t blk, int depth,
>>> +					char *buf)
>>> +{
>>> +	errcode_t ret;
>>> +	int epb = (fs->fs_blocksize - OCFS2_QBLK_RESERVED_SPACE) >> 2;
>>> +	int tree_depth = ocfs2_qtree_depth(fs->fs_blocksize);
>>> +	uint32_t *refs = (uint32_t *)buf, actref;
>>> +	int i;
>>> +
>>> +	ret = o2fswreck_read_blk(fs, type, buf, blk);
>>> +	if (ret)
>>> +		FSWRK_COM_FATAL(progname, ret);
>>> +
>>> +	for (i = 0; i < epb; i++) {
>>> +
>>> +		actref = le32_to_cpu(refs[i]);
>>> +		if (!actref)
>>> +			continue;
>>> +
>>> +		if (depth + 1 < tree_depth) {
>>> +			ret = o2fswreck_get_data_blk(fs, type, actref,
>>> +						     depth + 1,
>>> +						     buf + fs->fs_blocksize);
>>> +		} else {
>>> +
>>> +			ret = o2fswreck_read_blk(fs, type,
>>> +						 buf + fs->fs_blocksize,
>>> +						 actref);
>>> +			if (ret)
>>> +				FSWRK_COM_FATAL(progname, ret);
>>> +
>>> +			g_actref = actref;
>>> +
>>> +			return 0;
>>> +		}
>>> +
>>> +		if (ret)
>>> +			goto out;
>>> +	}
>>> +
>>> +out:
>>> +	return ret;
>>> +}
>>> +
>>> +
>>> +void mess_up_quota(ocfs2_filesys *fs, enum fsck_type type, uint16_t slotnum)
>>> +{
>>> +	errcode_t ret;
>>> +	int qtype;
>>> +	char *buf;
>>> +	int tree_depth = ocfs2_qtree_depth(fs->fs_blocksize);
>>> +
>>> +	struct ocfs2_disk_dqheader *header;
>>> +	struct ocfs2_global_disk_dqblk *ddquot;
>>> +
>>> +	ret = ocfs2_init_fs_quota_info(fs, USRQUOTA);
>>> +	if (ret)
>>> +		FSWRK_COM_FATAL(progname, ret);
>>> +
>>> +	ret = ocfs2_init_fs_quota_info(fs, GRPQUOTA);
>>> +	if (ret)
>>> +		FSWRK_COM_FATAL(progname, ret);
>>> +
>>> +	ret = ocfs2_malloc_blocks(fs->fs_io,
>>> +				  tree_depth + 1,
>>> +				  &buf);
>>> +	if (ret)
>>> +		FSWRK_COM_FATAL(progname, ret);
>>> +
>>> +	switch (type) {
>>> +	case  QMAGIC_INVALID:
>>> +		qtype = USRQUOTA;
>>> +
>>> +		ret = o2fswreck_read_blk(fs, qtype, buf, 0);
>>> +		if (ret)
>>> +			FSWRK_COM_FATAL(progname, ret);
>>> +
>>> +		header = (struct ocfs2_disk_dqheader *)buf;
>>> +
>>> +		ocfs2_swap_quota_header(header);
>>> +
>>> +		header->dqh_magic = ~header->dqh_magic;
>>> +
>>> +		ocfs2_swap_quota_header(header);
>>> +
>>> +		ret = o2fswreck_write_blk(fs, qtype, buf, 0);
>>> +		if (ret)
>>> +			FSWRK_COM_FATAL(progname, ret);
>>> +
>>> +		fprintf(stdout, "QMAGIC_INVALID: "
>>> +			"Corrupt global %s quota file's magic number "
>>> +			"in its header.\n", type2name(qtype));
>>> +		break;
>>> +	case QTREE_BLK_INVALID:
>>> +		qtype = GRPQUOTA;
>>> +
>>> +		ret = o2fswreck_read_blk(fs, qtype, buf, QT_TREEOFF);
>>> +		if (ret)
>>> +			FSWRK_COM_FATAL(progname, ret);
>>> +
>>> +		struct ocfs2_disk_dqtrailer *dqt =
>>> +				ocfs2_block_dqtrailer(fs->fs_blocksize, buf);
>>> +
>>> +		dqt->dq_check.bc_crc32e = ~dqt->dq_check.bc_crc32e;
>>> +		dqt->dq_check.bc_ecc = ~dqt->dq_check.bc_ecc;
>>> +
>>> +		ret = o2fswreck_write_blk(fs, qtype, buf, QT_TREEOFF);
>>> +		if (ret)
>>> +			FSWRK_COM_FATAL(progname, ret);
>>> +
>>> +		fprintf(stdout, "QTREE_BLK_INVALID: "
>>> +			"Corrupt global %s quota tree block.\n",
>>> +			type2name(qtype));
>>> +		break;
>>> +	case DQBLK_INVALID:
>>> +		qtype = USRQUOTA;
>>> +
>>> +		ret = o2fswreck_get_data_blk(fs, qtype, QT_TREEOFF, 0, buf);
>>> +
>>> +		ddquot = (struct ocfs2_global_disk_dqblk *)(buf +
>>> +					fs->fs_blocksize * tree_depth +
>>> +					sizeof(struct qt_disk_dqdbheader));
>>> +
>>> +		ocfs2_swap_quota_global_dqblk(ddquot);
>>> +
>>> +		ddquot->dqb_id = getuid();
>>>       
>   I suppose you want to use some random UID here. Maybe using 0xffffffff
> might be better because it's most probably invalid.
>   Also it might be useful to have another test which would corrupt a header
> of data block (qt_disk_dqdbheader).
>   
Good point!

I'll use -10 for a invalid UID as joel suggested.
>   
>>> +
>>> +		ddquot->dqb_isoftlimit += 1;
>>> +		ddquot->dqb_ihardlimit += 2;
>>> +		ddquot->dqb_bsoftlimit += 3;
>>> +		ddquot->dqb_bhardlimit += 4;
>>> +
>>> +		ocfs2_swap_quota_global_dqblk(ddquot);
>>> +
>>> +		ret = o2fswreck_write_blk(fs, qtype,
>>> +					  buf + fs->fs_blocksize * tree_depth,
>>> +					  g_actref);
>>> +		if (ret)
>>> +			FSWRK_COM_FATAL(progname, ret);
>>> +
>>> +		fprintf(stdout, "DQBLK_INVALID: "
>>> +			"Corrupt global %s quota data block.\n",
>>> +			type2name(qtype));
>>> +
>>> +		break;
>>> +	case DUP_DQBLK_INVALID:
>>> +		qtype = GRPQUOTA;
>>> +
>>> +		ret = o2fswreck_get_data_blk(fs, qtype, QT_TREEOFF, 0, buf);
>>> +
>>> +		ddquot = (struct ocfs2_global_disk_dqblk *)(buf +
>>> +					fs->fs_blocksize * tree_depth +
>>> +					sizeof(struct qt_disk_dqdbheader));
>>> +
>>> +		ddquot[1].dqb_id = ddquot[0].dqb_id;
>>> +
>>> +		ddquot[1].dqb_isoftlimit += 1;
>>> +		ddquot[1].dqb_ihardlimit += 2;
>>> +		ddquot[1].dqb_bsoftlimit += 3;
>>> +		ddquot[1].dqb_bhardlimit += 4;
>>>       
>   DQBLK_INVALID error of fsck happens when there is a duplicate dquot in an
> invalid block - i.e. you have to also corrupt header of the block or so.
>
>   
Thank you for pointing this out:-)

>>> +
>>> +		ret = o2fswreck_write_blk(fs, qtype,
>>> +					  buf + fs->fs_blocksize * tree_depth,
>>> +					  g_actref);
>>> +		if (ret)
>>> +			FSWRK_COM_FATAL(progname, ret);
>>> +
>>> +		fprintf(stdout, "DUP_DQBLK_INVALID: "
>>> +			"Duplicate %s quota data block with a invalid entry.\n",
>>> +			type2name(qtype));
>>> +
>>> +		break;
>>> +	case DUP_DQBLK_VALID:
>>> +		qtype = GRPQUOTA;
>>> +
>>> +		ret = o2fswreck_get_data_blk(fs, qtype, QT_TREEOFF, 0, buf);
>>> +
>>> +		ddquot = (struct ocfs2_global_disk_dqblk *)(buf +
>>> +					fs->fs_blocksize * tree_depth +
>>> +					sizeof(struct qt_disk_dqdbheader));
>>> +
>>> +		ddquot[1].dqb_id = ddquot[0].dqb_id;
>>> +		ddquot[1].dqb_isoftlimit = ddquot[0].dqb_isoftlimit;
>>> +		ddquot[1].dqb_ihardlimit = ddquot[0].dqb_isoftlimit;
>>> +		ddquot[1].dqb_bsoftlimit = ddquot[0].dqb_isoftlimit;
>>> +		ddquot[1].dqb_bhardlimit = ddquot[0].dqb_isoftlimit;
>>> +
>>> +		ret = o2fswreck_write_blk(fs, qtype,
>>> +					  buf + fs->fs_blocksize * tree_depth,
>>> +					  g_actref);
>>> +		if (ret)
>>> +			FSWRK_COM_FATAL(progname, ret);
>>> +
>>> +		fprintf(stdout, "DUP_DQBLK_INVALID: "
>>> +			"Duplicate %s quota data block with a valid entry.\n",
>>> +			type2name(qtype));
>>> +
>>> +		break;
>>> +	default:
>>> +		FSWRK_FATAL("Invalid type[%d]\n", type);
>>> +	}
>>> +
>>> +	if (buf)
>>> +		ocfs2_free(&buf);
>>> +}
>>>   
>>>       
> 								Honza
>   




More information about the Ocfs2-tools-devel mailing list