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

Tristan Ye tristan.ye at oracle.com
Thu Oct 8 20:04:14 PDT 2009


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             |  297 +++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 355 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..1faa538 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..4d49cec
--- /dev/null
+++ b/fswreck/quota.c
@@ -0,0 +1,297 @@
+/* -*- 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;
+	struct qt_disk_dqdbheader *dh;
+
+	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 = 0xFFFFFFF6;
+
+		ddquot->dqb_isoftlimit += 1;
+		ddquot->dqb_ihardlimit += 2;
+		ddquot->dqb_bsoftlimit += 3;
+		ddquot->dqb_bhardlimit += 4;
+
+		ocfs2_swap_quota_global_dqblk(ddquot);
+
+		dh = (struct qt_disk_dqdbheader *)(buf +
+				fs->fs_blocksize * tree_depth);
+
+		ocfs2_swap_quota_leaf_block_header(dh);
+		dh->dqdh_next_free = 0xFFFFFFFF;
+		dh->dqdh_prev_free = 0xFFFFFFFF;
+		dh->dqdh_entries = 0xFFFFFFFF;
+		ocfs2_swap_quota_leaf_block_header(dh);
+
+		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;
+
+		dh = (struct qt_disk_dqdbheader *)(buf +
+				fs->fs_blocksize * tree_depth);
+
+		ocfs2_swap_quota_leaf_block_header(dh);
+		dh->dqdh_next_free = 0xFFFFFFFF;
+		dh->dqdh_prev_free = 0xFFFFFFFF;
+		dh->dqdh_entries = 0xFFFFFFFF;
+		ocfs2_swap_quota_leaf_block_header(dh);
+
+		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_VALID: "
+			"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);
+}
-- 
1.5.5




More information about the Ocfs2-tools-devel mailing list