[PATCH] xfs_db: allow recalculating CRCs on invalid metadata

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Dave Chinner <dchinner@xxxxxxxxxx>

Currently we can't write corrupt structures with valid CRCs on v5
filesystems via xfs_db. TO emulate certain types of corruption
result from software bugs in the kernel code, we need this
capability to set up the corrupted state. i.e. corrupt state with a
valid CRC needs to appear on disk.

This requires us to avoid running the verifier that would otherwise
prevent writing corrupt state to disk. To enable this, add the CRC
offset to the type table for different buffers and add a new flag to
the write command to trigger running a CRC calculation base don this
type table. We can then insert the calculated value into the correct
location in the buffer...

Because some objects are not directly buffer based, we can't easily
do this CRC trick. Those object types will be marked as
TYP_NO_CRC_OFF, and as a result will emit an error such as:

# xfs_db -x -c "inode 96" -c "write -d magic 0x4949" /dev/ram0
Cannot recalculate CRCs on this type of object
#

All v4 superblock types are configured this way, as are inode,
dquots and other v5 metadata types that either don't have CRCs or
don't have a fixed offset into a buffer to store their CRC.

Signed-off-by: Dave Chinner <dchinner@xxxxxxxxxx>
---
 db/io.c    |   7 ++++
 db/io.h    |   1 +
 db/type.c  | 137 +++++++++++++++++++++++++++++++++----------------------------
 db/type.h  |   2 +
 db/write.c |  52 +++++++++++++++++------
 5 files changed, 124 insertions(+), 75 deletions(-)

diff --git a/db/io.c b/db/io.c
index 9452e07..91cab12 100644
--- a/db/io.c
+++ b/db/io.c
@@ -464,6 +464,13 @@ xfs_dummy_verify(
 }
 
 void
+xfs_verify_recalc_crc(
+	struct xfs_buf *bp)
+{
+	xfs_buf_update_cksum(bp, iocur_top->typ->crc_off);
+}
+
+void
 write_cur(void)
 {
 	if (iocur_sp < 0) {
diff --git a/db/io.h b/db/io.h
index 6201d7b..c69e9ce 100644
--- a/db/io.h
+++ b/db/io.h
@@ -64,6 +64,7 @@ extern void	set_cur(const struct typ *t, __int64_t d, int c, int ring_add,
 extern void     ring_add(void);
 extern void	set_iocur_type(const struct typ *t);
 extern void	xfs_dummy_verify(struct xfs_buf *bp);
+extern void	xfs_verify_recalc_crc(struct xfs_buf *bp);
 
 /*
  * returns -1 for unchecked, 0 for bad and 1 for good
diff --git a/db/type.c b/db/type.c
index 1da7ee1..d061bc1 100644
--- a/db/type.c
+++ b/db/type.c
@@ -50,99 +50,110 @@ static const cmdinfo_t	type_cmd =
 	  N_("set/show current data type"), NULL };
 
 static const typ_t	__typtab[] = {
-	{ TYP_AGF, "agf", handle_struct, agf_hfld, NULL },
-	{ TYP_AGFL, "agfl", handle_struct, agfl_hfld, NULL },
-	{ TYP_AGI, "agi", handle_struct, agi_hfld, NULL },
-	{ TYP_ATTR, "attr", handle_struct, attr_hfld, NULL },
-	{ TYP_BMAPBTA, "bmapbta", handle_struct, bmapbta_hfld, NULL },
-	{ TYP_BMAPBTD, "bmapbtd", handle_struct, bmapbtd_hfld, NULL },
-	{ TYP_BNOBT, "bnobt", handle_struct, bnobt_hfld, NULL },
-	{ TYP_CNTBT, "cntbt", handle_struct, cntbt_hfld, NULL },
-	{ TYP_DATA, "data", handle_block, NULL, NULL },
-	{ TYP_DIR2, "dir2", handle_struct, dir2_hfld, NULL },
-	{ TYP_DQBLK, "dqblk", handle_struct, dqblk_hfld, NULL },
-	{ TYP_INOBT, "inobt", handle_struct, inobt_hfld, NULL },
-	{ TYP_INODATA, "inodata", NULL, NULL, NULL },
-	{ TYP_INODE, "inode", handle_struct, inode_hfld, NULL },
-	{ TYP_LOG, "log", NULL, NULL, NULL },
-	{ TYP_RTBITMAP, "rtbitmap", NULL, NULL, NULL },
-	{ TYP_RTSUMMARY, "rtsummary", NULL, NULL, NULL },
-	{ TYP_SB, "sb", handle_struct, sb_hfld, NULL },
-	{ TYP_SYMLINK, "symlink", handle_string, NULL, NULL },
-	{ TYP_TEXT, "text", handle_text, NULL, NULL },
-	{ TYP_FINOBT, "finobt", handle_struct, inobt_hfld, NULL },
+	{ TYP_AGF, "agf", handle_struct, agf_hfld, NULL, TYP_NO_CRC_OFF },
+	{ TYP_AGFL, "agfl", handle_struct, agfl_hfld, NULL, TYP_NO_CRC_OFF },
+	{ TYP_AGI, "agi", handle_struct, agi_hfld, NULL, TYP_NO_CRC_OFF },
+	{ TYP_ATTR, "attr", handle_struct, attr_hfld, NULL, TYP_NO_CRC_OFF },
+	{ TYP_BMAPBTA, "bmapbta", handle_struct, bmapbta_hfld, NULL,
+		TYP_NO_CRC_OFF },
+	{ TYP_BMAPBTD, "bmapbtd", handle_struct, bmapbtd_hfld, NULL,
+		TYP_NO_CRC_OFF },
+	{ TYP_BNOBT, "bnobt", handle_struct, bnobt_hfld, NULL, TYP_NO_CRC_OFF },
+	{ TYP_CNTBT, "cntbt", handle_struct, cntbt_hfld, NULL, TYP_NO_CRC_OFF },
+	{ TYP_DATA, "data", handle_block, NULL, NULL, TYP_NO_CRC_OFF },
+	{ TYP_DIR2, "dir2", handle_struct, dir2_hfld, NULL, TYP_NO_CRC_OFF },
+	{ TYP_DQBLK, "dqblk", handle_struct, dqblk_hfld, NULL, TYP_NO_CRC_OFF },
+	{ TYP_INOBT, "inobt", handle_struct, inobt_hfld, NULL, TYP_NO_CRC_OFF },
+	{ TYP_INODATA, "inodata", NULL, NULL, NULL, TYP_NO_CRC_OFF },
+	{ TYP_INODE, "inode", handle_struct, inode_hfld, NULL, TYP_NO_CRC_OFF },
+	{ TYP_LOG, "log", NULL, NULL, NULL, TYP_NO_CRC_OFF },
+	{ TYP_RTBITMAP, "rtbitmap", NULL, NULL, NULL, TYP_NO_CRC_OFF },
+	{ TYP_RTSUMMARY, "rtsummary", NULL, NULL, NULL, TYP_NO_CRC_OFF },
+	{ TYP_SB, "sb", handle_struct, sb_hfld, NULL, TYP_NO_CRC_OFF },
+	{ TYP_SYMLINK, "symlink", handle_string, NULL, NULL, TYP_NO_CRC_OFF },
+	{ TYP_TEXT, "text", handle_text, NULL, NULL, TYP_NO_CRC_OFF },
+	{ TYP_FINOBT, "finobt", handle_struct, inobt_hfld, NULL,
+		TYP_NO_CRC_OFF },
 	{ TYP_NONE, NULL }
 };
 
 static const typ_t	__typtab_crc[] = {
-	{ TYP_AGF, "agf", handle_struct, agf_hfld, &xfs_agf_buf_ops },
-	{ TYP_AGFL, "agfl", handle_struct, agfl_crc_hfld, &xfs_agfl_buf_ops },
-	{ TYP_AGI, "agi", handle_struct, agi_hfld, &xfs_agi_buf_ops },
+	{ TYP_AGF, "agf", handle_struct, agf_hfld, &xfs_agf_buf_ops,
+		XFS_AGF_CRC_OFF },
+	{ TYP_AGFL, "agfl", handle_struct, agfl_crc_hfld, &xfs_agfl_buf_ops,
+		XFS_AGFL_CRC_OFF },
+	{ TYP_AGI, "agi", handle_struct, agi_hfld, &xfs_agi_buf_ops,
+		XFS_AGI_CRC_OFF },
 	{ TYP_ATTR, "attr3", handle_struct, attr3_hfld,
-		&xfs_attr3_db_buf_ops },
+		&xfs_attr3_db_buf_ops, TYP_NO_CRC_OFF },
 	{ TYP_BMAPBTA, "bmapbta", handle_struct, bmapbta_crc_hfld,
-		&xfs_bmbt_buf_ops },
+		&xfs_bmbt_buf_ops, XFS_BTREE_LBLOCK_CRC_OFF },
 	{ TYP_BMAPBTD, "bmapbtd", handle_struct, bmapbtd_crc_hfld,
-		&xfs_bmbt_buf_ops },
+		&xfs_bmbt_buf_ops, XFS_BTREE_LBLOCK_CRC_OFF },
 	{ TYP_BNOBT, "bnobt", handle_struct, bnobt_crc_hfld,
-		&xfs_allocbt_buf_ops },
+		&xfs_allocbt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF },
 	{ TYP_CNTBT, "cntbt", handle_struct, cntbt_crc_hfld,
-		&xfs_allocbt_buf_ops },
-	{ TYP_DATA, "data", handle_block, NULL, NULL },
+		&xfs_allocbt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF },
+	{ TYP_DATA, "data", handle_block, NULL, NULL, TYP_NO_CRC_OFF },
 	{ TYP_DIR2, "dir3", handle_struct, dir3_hfld,
-		&xfs_dir3_db_buf_ops },
+		&xfs_dir3_db_buf_ops, TYP_NO_CRC_OFF },
 	{ TYP_DQBLK, "dqblk", handle_struct, dqblk_hfld,
-		&xfs_dquot_buf_ops },
+		&xfs_dquot_buf_ops, TYP_NO_CRC_OFF },
 	{ TYP_INOBT, "inobt", handle_struct, inobt_crc_hfld,
-		&xfs_inobt_buf_ops },
-	{ TYP_INODATA, "inodata", NULL, NULL, NULL },
+		&xfs_inobt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF },
+	{ TYP_INODATA, "inodata", NULL, NULL, NULL, TYP_NO_CRC_OFF },
 	{ TYP_INODE, "inode", handle_struct, inode_crc_hfld,
-		&xfs_inode_buf_ops },
-	{ TYP_LOG, "log", NULL, NULL, NULL },
-	{ TYP_RTBITMAP, "rtbitmap", NULL, NULL, NULL },
-	{ TYP_RTSUMMARY, "rtsummary", NULL, NULL, NULL },
-	{ TYP_SB, "sb", handle_struct, sb_hfld, &xfs_sb_buf_ops },
+		&xfs_inode_buf_ops, TYP_NO_CRC_OFF },
+	{ TYP_LOG, "log", NULL, NULL, NULL, TYP_NO_CRC_OFF },
+	{ TYP_RTBITMAP, "rtbitmap", NULL, NULL, NULL, TYP_NO_CRC_OFF },
+	{ TYP_RTSUMMARY, "rtsummary", NULL, NULL, NULL, TYP_NO_CRC_OFF },
+	{ TYP_SB, "sb", handle_struct, sb_hfld, &xfs_sb_buf_ops,
+		XFS_SB_CRC_OFF },
 	{ TYP_SYMLINK, "symlink", handle_struct, symlink_crc_hfld,
-		&xfs_symlink_buf_ops },
-	{ TYP_TEXT, "text", handle_text, NULL, NULL },
+		&xfs_symlink_buf_ops, XFS_SYMLINK_CRC_OFF },
+	{ TYP_TEXT, "text", handle_text, NULL, NULL, TYP_NO_CRC_OFF },
 	{ TYP_FINOBT, "finobt", handle_struct, inobt_crc_hfld,
-		&xfs_inobt_buf_ops },
+		&xfs_inobt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF },
 	{ TYP_NONE, NULL }
 };
 
 static const typ_t	__typtab_spcrc[] = {
-	{ TYP_AGF, "agf", handle_struct, agf_hfld, &xfs_agf_buf_ops },
-	{ TYP_AGFL, "agfl", handle_struct, agfl_crc_hfld, &xfs_agfl_buf_ops },
-	{ TYP_AGI, "agi", handle_struct, agi_hfld, &xfs_agi_buf_ops },
+	{ TYP_AGF, "agf", handle_struct, agf_hfld, &xfs_agf_buf_ops,
+		XFS_AGF_CRC_OFF },
+	{ TYP_AGFL, "agfl", handle_struct, agfl_crc_hfld, &xfs_agfl_buf_ops ,
+		XFS_AGFL_CRC_OFF },
+	{ TYP_AGI, "agi", handle_struct, agi_hfld, &xfs_agi_buf_ops ,
+		XFS_AGI_CRC_OFF },
 	{ TYP_ATTR, "attr3", handle_struct, attr3_hfld,
-		&xfs_attr3_db_buf_ops },
+		&xfs_attr3_db_buf_ops, TYP_NO_CRC_OFF },
 	{ TYP_BMAPBTA, "bmapbta", handle_struct, bmapbta_crc_hfld,
-		&xfs_bmbt_buf_ops },
+		&xfs_bmbt_buf_ops, XFS_BTREE_LBLOCK_CRC_OFF },
 	{ TYP_BMAPBTD, "bmapbtd", handle_struct, bmapbtd_crc_hfld,
-		&xfs_bmbt_buf_ops },
+		&xfs_bmbt_buf_ops, XFS_BTREE_LBLOCK_CRC_OFF },
 	{ TYP_BNOBT, "bnobt", handle_struct, bnobt_crc_hfld,
-		&xfs_allocbt_buf_ops },
+		&xfs_allocbt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF },
 	{ TYP_CNTBT, "cntbt", handle_struct, cntbt_crc_hfld,
-		&xfs_allocbt_buf_ops },
-	{ TYP_DATA, "data", handle_block, NULL, NULL },
+		&xfs_allocbt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF },
+	{ TYP_DATA, "data", handle_block, NULL, NULL, TYP_NO_CRC_OFF },
 	{ TYP_DIR2, "dir3", handle_struct, dir3_hfld,
-		&xfs_dir3_db_buf_ops },
+		&xfs_dir3_db_buf_ops, TYP_NO_CRC_OFF },
 	{ TYP_DQBLK, "dqblk", handle_struct, dqblk_hfld,
-		&xfs_dquot_buf_ops },
+		&xfs_dquot_buf_ops, TYP_NO_CRC_OFF },
 	{ TYP_INOBT, "inobt", handle_struct, inobt_spcrc_hfld,
-		&xfs_inobt_buf_ops },
-	{ TYP_INODATA, "inodata", NULL, NULL, NULL },
+		&xfs_inobt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF },
+	{ TYP_INODATA, "inodata", NULL, NULL, NULL, TYP_NO_CRC_OFF },
 	{ TYP_INODE, "inode", handle_struct, inode_crc_hfld,
-		&xfs_inode_buf_ops },
-	{ TYP_LOG, "log", NULL, NULL, NULL },
-	{ TYP_RTBITMAP, "rtbitmap", NULL, NULL, NULL },
-	{ TYP_RTSUMMARY, "rtsummary", NULL, NULL, NULL },
-	{ TYP_SB, "sb", handle_struct, sb_hfld, &xfs_sb_buf_ops },
+		&xfs_inode_buf_ops, TYP_NO_CRC_OFF },
+	{ TYP_LOG, "log", NULL, NULL, NULL, TYP_NO_CRC_OFF },
+	{ TYP_RTBITMAP, "rtbitmap", NULL, NULL, NULL, TYP_NO_CRC_OFF },
+	{ TYP_RTSUMMARY, "rtsummary", NULL, NULL, NULL, TYP_NO_CRC_OFF },
+	{ TYP_SB, "sb", handle_struct, sb_hfld, &xfs_sb_buf_ops,
+		XFS_SB_CRC_OFF },
 	{ TYP_SYMLINK, "symlink", handle_struct, symlink_crc_hfld,
-		&xfs_symlink_buf_ops },
-	{ TYP_TEXT, "text", handle_text, NULL, NULL },
+		&xfs_symlink_buf_ops, XFS_SYMLINK_CRC_OFF },
+	{ TYP_TEXT, "text", handle_text, NULL, NULL, TYP_NO_CRC_OFF },
 	{ TYP_FINOBT, "finobt", handle_struct, inobt_crc_hfld,
-		&xfs_inobt_buf_ops },
+		&xfs_inobt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF },
 	{ TYP_NONE, NULL }
 };
 
diff --git a/db/type.h b/db/type.h
index d9583e5..e954a68 100644
--- a/db/type.h
+++ b/db/type.h
@@ -43,6 +43,8 @@ typedef struct typ
 	pfunc_t			pfunc;
 	const struct field	*fields;
 	const struct xfs_buf_ops *bops;
+	unsigned long		crc_off;
+#define TYP_NO_CRC_OFF	(-1UL)
 } typ_t;
 extern const typ_t	*typtab, *cur_typ;
 
diff --git a/db/write.c b/db/write.c
index 9f5b423..a922e16 100644
--- a/db/write.c
+++ b/db/write.c
@@ -79,7 +79,10 @@ write_help(void)
 "  String mode: 'write \"This_is_a_filename\" - write null terminated string.\n"
 "\n"
 " In data mode type 'write' by itself for a list of specific commands.\n\n"
-" Specifying the -c option will allow writes of invalid (corrupt) data.\n\n"
+" Specifying the -c option will allow writes of invalid (corrupt) data with\n"
+" an invalid CRC. Specifying the -d option will allow writes of invalid data,\n"
+" but still recalculate the CRC so we are forced to check and detect the\n"
+" invalid data appropriately.\n\n"
 ));
 
 }
@@ -92,7 +95,8 @@ write_f(
 	pfunc_t	pf;
 	extern char *progname;
 	int c;
-	int corrupt = 0;		/* Allow write of corrupt data; skip verification */
+	bool corrupt = false;	/* Allow write of bad data w/ invalid CRC */
+	bool invalid_data = false; /* Allow write of bad data w/ valid CRC */
 	struct xfs_buf_ops nowrite_ops;
 	const struct xfs_buf_ops *stashed_ops = NULL;
 
@@ -114,10 +118,13 @@ write_f(
 		return 0;
 	}
 
-	while ((c = getopt(argc, argv, "c")) != EOF) {
+	while ((c = getopt(argc, argv, "cd")) != EOF) {
 		switch (c) {
 		case 'c':
-			corrupt = 1;
+			corrupt = true;
+			break;
+		case 'd':
+			invalid_data = true;
 			break;
 		default:
 			dbprintf(_("bad option for write command\n"));
@@ -125,22 +132,43 @@ write_f(
 		}
 	}
 
+	if (corrupt && invalid_data) {
+		dbprintf(_("Cannot specify both -c and -d options\n"));
+		return 0;
+	}
+
+	if (invalid_data && iocur_top->typ->crc_off == TYP_NO_CRC_OFF) {
+		dbprintf(_("Cannot recalculate CRCs on this type of object\n"));
+		return 0;
+	}
+
 	argc -= optind;
 	argv += optind;
 
-	if (iocur_top->bp->b_ops && corrupt) {
-		/* Temporarily remove write verifier to write bad data */
-		stashed_ops = iocur_top->bp->b_ops;
-		nowrite_ops.verify_read = stashed_ops->verify_read;
+	/* If we don't have to juggle verifiers, then just issue the write */
+	if (!iocur_top->bp->b_ops ||
+	    !(corrupt || invalid_data)) {
+		(*pf)(DB_WRITE, cur_typ->fields, argc, argv);
+		return 0;
+	}
+
+
+	/* Temporarily remove write verifier to write bad data */
+	stashed_ops = iocur_top->bp->b_ops;
+	nowrite_ops.verify_read = stashed_ops->verify_read;
+	iocur_top->bp->b_ops = &nowrite_ops;
+
+	if (corrupt) {
 		nowrite_ops.verify_write = xfs_dummy_verify;
-		iocur_top->bp->b_ops = &nowrite_ops;
-		dbprintf(_("Allowing write of corrupted data\n"));
+		dbprintf(_("Allowing write of corrupted data and bad CRC\n"));
+	} else {
+		nowrite_ops.verify_write = xfs_verify_recalc_crc;
+		dbprintf(_("Allowing write of corrupted data with good CRC\n"));
 	}
 
 	(*pf)(DB_WRITE, cur_typ->fields, argc, argv);
 
-	if (stashed_ops)
-		iocur_top->bp->b_ops = stashed_ops;
+	iocur_top->bp->b_ops = stashed_ops;
 
 	return 0;
 }
-- 
2.8.0.rc3

_______________________________________________
xfs mailing list
xfs@xxxxxxxxxxx
http://oss.sgi.com/mailman/listinfo/xfs



[Index of Archives]     [Linux XFS Devel]     [Linux Filesystem Development]     [Filesystem Testing]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux