Re: [PATCH 7/7] xfs_db: introduce fuzz command

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

 



On Mon, Jul 31, 2017 at 02:07:32PM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@xxxxxxxxxx>
> 
> Introduce a new 'fuzz' command to write creative values into
> disk structure fields.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx>
> ---
>  db/Makefile       |    3 
>  db/bit.c          |   17 +-
>  db/bit.h          |    5 -
>  db/command.c      |    2 
>  db/fuzz.c         |  467 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  db/fuzz.h         |   21 ++
>  db/type.c         |   44 ++++-
>  db/type.h         |    1 
>  man/man8/xfs_db.8 |   49 ++++++
>  9 files changed, 589 insertions(+), 20 deletions(-)
>  create mode 100644 db/fuzz.c
>  create mode 100644 db/fuzz.h
> 

Code looks good and tested here.

Reviewed-by: Carlos Maiolino <cmaiolino@xxxxxxxxxx>


> 
> diff --git a/db/Makefile b/db/Makefile
> index 6618bff..8111bf1 100644
> --- a/db/Makefile
> +++ b/db/Makefile
> @@ -12,7 +12,8 @@ HFILES = addr.h agf.h agfl.h agi.h attr.h attrshort.h bit.h block.h bmap.h \
>  	dir2.h dir2sf.h dquot.h echo.h faddr.h field.h \
>  	flist.h fprint.h frag.h freesp.h hash.h help.h init.h inode.h input.h \
>  	io.h logformat.h malloc.h metadump.h output.h print.h quit.h sb.h \
> -	 sig.h strvec.h text.h type.h write.h attrset.h symlink.h fsmap.h
> +	sig.h strvec.h text.h type.h write.h attrset.h symlink.h fsmap.h \
> +	fuzz.h
>  CFILES = $(HFILES:.h=.c) btdump.c
>  LSRCFILES = xfs_admin.sh xfs_ncheck.sh xfs_metadump.sh
>  
> diff --git a/db/bit.c b/db/bit.c
> index f5ebf68..a20b6ba 100644
> --- a/db/bit.c
> +++ b/db/bit.c
> @@ -19,13 +19,8 @@
>  #include "libxfs.h"
>  #include "bit.h"
>  
> -#undef setbit	/* defined in param.h on Linux */
> -
> -static int	getbit(char *ptr, int bit);
> -static void	setbit(char *ptr, int bit, int val);
> -
> -static int
> -getbit(
> +int
> +getbit_l(
>  	char	*ptr,
>  	int	bit)
>  {
> @@ -39,8 +34,8 @@ getbit(
>  	return (*ptr & mask) >> shift;
>  }
>  
> -static void
> -setbit(
> +void
> +setbit_l(
>  	char *ptr,
>  	int  bit,
>  	int  val)
> @@ -106,7 +101,7 @@ getbitval(
>  
>  
>  	for (i = 0, rval = 0LL; i < nbits; i++) {
> -		if (getbit(p, bit + i)) {
> +		if (getbit_l(p, bit + i)) {
>  			/* If the last bit is on and we care about sign
>  			 * bits and we don't have a full 64 bit
>  			 * container, turn all bits on between the
> @@ -162,7 +157,7 @@ setbitval(
>  
>  	if (bitoff % NBBY || nbits % NBBY) {
>  		for (bit = 0; bit < nbits; bit++)
> -			setbit(out, bit + bitoff, getbit(in, bit));
> +			setbit_l(out, bit + bitoff, getbit_l(in, bit));
>  	} else
>  		memcpy(out + byteize(bitoff), in, byteize(nbits));
>  }
> diff --git a/db/bit.h b/db/bit.h
> index 9fd71f4..78fcd05 100644
> --- a/db/bit.h
> +++ b/db/bit.h
> @@ -21,9 +21,12 @@
>  #define	bitszof(x,y)	bitize(szof(x,y))
>  #define	byteize(s)	((s) / NBBY)
>  #define	bitoffs(s)	((s) % NBBY)
> +#define	byteize_up(s)	(((s) + NBBY - 1) / NBBY)
>  
>  #define	BVUNSIGNED	0
>  #define	BVSIGNED	1
>  
>  extern int64_t		getbitval(void *obj, int bitoff, int nbits, int flags);
> -extern void             setbitval(void *obuf, int bitoff, int nbits, void *ibuf);
> +extern void		setbitval(void *obuf, int bitoff, int nbits, void *ibuf);
> +extern int		getbit_l(char *ptr, int bit);
> +extern void		setbit_l(char *ptr, int bit, int val);
> diff --git a/db/command.c b/db/command.c
> index c90c85c..5ff3c4f 100644
> --- a/db/command.c
> +++ b/db/command.c
> @@ -51,6 +51,7 @@
>  #include "dquot.h"
>  #include "fsmap.h"
>  #include "crc.h"
> +#include "fuzz.h"
>  
>  cmdinfo_t	*cmdtab;
>  int		ncmds;
> @@ -147,4 +148,5 @@ init_commands(void)
>  	type_init();
>  	write_init();
>  	dquot_init();
> +	fuzz_init();
>  }
> diff --git a/db/fuzz.c b/db/fuzz.c
> new file mode 100644
> index 0000000..b4c62ca
> --- /dev/null
> +++ b/db/fuzz.c
> @@ -0,0 +1,467 @@
> +/*
> + * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
> + * 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 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it would 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 the Free Software Foundation,
> + * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
> + */
> +
> +#include "libxfs.h"
> +#include <ctype.h>
> +#include <time.h>
> +#include "bit.h"
> +#include "block.h"
> +#include "command.h"
> +#include "type.h"
> +#include "faddr.h"
> +#include "fprint.h"
> +#include "field.h"
> +#include "flist.h"
> +#include "io.h"
> +#include "init.h"
> +#include "output.h"
> +#include "print.h"
> +#include "write.h"
> +#include "malloc.h"
> +
> +static int	fuzz_f(int argc, char **argv);
> +static void     fuzz_help(void);
> +
> +static const cmdinfo_t	fuzz_cmd =
> +	{ "fuzz", NULL, fuzz_f, 0, -1, 0, N_("[-c] [-d] field fuzzcmd..."),
> +	  N_("fuzz values on disk"), fuzz_help };
> +
> +void
> +fuzz_init(void)
> +{
> +	if (!expert_mode)
> +		return;
> +
> +	add_command(&fuzz_cmd);
> +	srand48(clock());
> +}
> +
> +static void
> +fuzz_help(void)
> +{
> +	dbprintf(_(
> +"\n"
> +" The 'fuzz' command fuzzes fields in any on-disk data structure.  For\n"
> +" block fuzzing, see the 'blocktrash' or 'write' commands."
> +"\n"
> +" Examples:\n"
> +"  Struct mode: 'fuzz core.uid zeroes'    - set an inode uid field to 0.\n"
> +"               'fuzz crc ones'           - set a crc filed to all ones.\n"
> +"               'fuzz bno[11] firstbit'   - set the high bit of a block array.\n"
> +"               'fuzz keys[5].startblock add'    - increase a btree key value.\n"
> +"               'fuzz uuid random'        - randomize the superblock uuid.\n"
> +"\n"
> +" In data mode type 'fuzz' by itself for a list of specific commands.\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"
> +));
> +
> +}
> +
> +static int
> +fuzz_f(
> +	int		argc,
> +	char		**argv)
> +{
> +	pfunc_t	pf;
> +	extern char *progname;
> +	int c;
> +	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 local_ops;
> +	const struct xfs_buf_ops *stashed_ops = NULL;
> +
> +	if (x.isreadonly & LIBXFS_ISREADONLY) {
> +		dbprintf(_("%s started in read only mode, fuzzing disabled\n"),
> +			progname);
> +		return 0;
> +	}
> +
> +	if (cur_typ == NULL) {
> +		dbprintf(_("no current type\n"));
> +		return 0;
> +	}
> +
> +	pf = cur_typ->pfunc;
> +	if (pf == NULL) {
> +		dbprintf(_("no handler function for type %s, fuzz unsupported.\n"),
> +			 cur_typ->name);
> +		return 0;
> +	}
> +
> +	while ((c = getopt(argc, argv, "cd")) != EOF) {
> +		switch (c) {
> +		case 'c':
> +			corrupt = true;
> +			break;
> +		case 'd':
> +			invalid_data = true;
> +			break;
> +		default:
> +			dbprintf(_("bad option for fuzz command\n"));
> +			return 0;
> +		}
> +	}
> +
> +	if (corrupt && invalid_data) {
> +		dbprintf(_("Cannot specify both -c and -d options\n"));
> +		return 0;
> +	}
> +
> +	if (invalid_data && iocur_top->typ->crc_off == TYP_F_NO_CRC_OFF &&
> +			!iocur_top->ino_buf && !iocur_top->dquot_buf) {
> +		dbprintf(_("Cannot recalculate CRCs on this type of object\n"));
> +		return 0;
> +	}
> +
> +	argc -= optind;
> +	argv += optind;
> +
> +	/*
> +	 * If the buffer has no verifier or we are using standard verifier
> +	 * paths, then just fuzz it and return
> +	 */
> +	if (!iocur_top->bp->b_ops ||
> +	    !(corrupt || invalid_data)) {
> +		(*pf)(DB_FUZZ, cur_typ->fields, argc, argv);
> +		return 0;
> +	}
> +
> +
> +	/* Temporarily remove write verifier to write bad data */
> +	stashed_ops = iocur_top->bp->b_ops;
> +	local_ops.verify_read = stashed_ops->verify_read;
> +	iocur_top->bp->b_ops = &local_ops;
> +
> +	if (corrupt) {
> +		local_ops.verify_write = xfs_dummy_verify;
> +		dbprintf(_("Allowing fuzz of corrupted data and bad CRC\n"));
> +	} else if (iocur_top->ino_buf) {
> +		local_ops.verify_write = xfs_verify_recalc_inode_crc;
> +		dbprintf(_("Allowing fuzz of corrupted inode with good CRC\n"));
> +	} else if (iocur_top->dquot_buf) {
> +		local_ops.verify_write = xfs_verify_recalc_dquot_crc;
> +		dbprintf(_("Allowing fuzz of corrupted dquot with good CRC\n"));
> +	} else if (iocur_top->typ->crc_off == TYP_F_CRC_FUNC) {
> +		local_ops.verify_write = iocur_top->typ->set_crc;
> +		dbprintf(_("Allowing fuzz of corrupted data with good CRC\n"));
> +	} else { /* invalid data */
> +		local_ops.verify_write = xfs_verify_recalc_crc;
> +		dbprintf(_("Allowing fuzz of corrupted data with good CRC\n"));
> +	}
> +
> +	(*pf)(DB_FUZZ, cur_typ->fields, argc, argv);
> +
> +	iocur_top->bp->b_ops = stashed_ops;
> +
> +	return 0;
> +}
> +
> +/* Write zeroes to the field */
> +static bool
> +fuzz_zeroes(
> +	void		*buf,
> +	int		bitoff,
> +	int		nbits)
> +{
> +	char		*out = buf;
> +	int		bit;
> +
> +	if (bitoff % NBBY || nbits % NBBY) {
> +		for (bit = 0; bit < nbits; bit++)
> +			setbit_l(out, bit + bitoff, 0);
> +	} else
> +		memset(out + byteize(bitoff), 0, byteize(nbits));
> +	return true;
> +}
> +
> +/* Write ones to the field */
> +static bool
> +fuzz_ones(
> +	void		*buf,
> +	int		bitoff,
> +	int		nbits)
> +{
> +	char		*out = buf;
> +	int		bit;
> +
> +	if (bitoff % NBBY || nbits % NBBY) {
> +		for (bit = 0; bit < nbits; bit++)
> +			setbit_l(out, bit + bitoff, 1);
> +	} else
> +		memset(out + byteize(bitoff), 0xFF, byteize(nbits));
> +	return true;
> +}
> +
> +/* Flip the high bit in the (presumably big-endian) field */
> +static bool
> +fuzz_firstbit(
> +	void		*buf,
> +	int		bitoff,
> +	int		nbits)
> +{
> +	setbit_l((char *)buf, bitoff, !getbit_l((char *)buf, bitoff));
> +	return true;
> +}
> +
> +/* Flip the low bit in the (presumably big-endian) field */
> +static bool
> +fuzz_lastbit(
> +	void		*buf,
> +	int		bitoff,
> +	int		nbits)
> +{
> +	setbit_l((char *)buf, bitoff + nbits - 1,
> +			!getbit_l((char *)buf, bitoff));
> +	return true;
> +}
> +
> +/* Flip the middle bit in the (presumably big-endian) field */
> +static bool
> +fuzz_middlebit(
> +	void		*buf,
> +	int		bitoff,
> +	int		nbits)
> +{
> +	setbit_l((char *)buf, bitoff + nbits / 2,
> +			!getbit_l((char *)buf, bitoff));
> +	return true;
> +}
> +
> +/* Format and shift a number into a buffer for setbitval. */
> +static char *
> +format_number(
> +	uint64_t	val,
> +	__be64		*out,
> +	int		bit_length)
> +{
> +	int		offset;
> +	char		*rbuf = (char *)out;
> +
> +	/*
> +	 * If the length of the field is not a multiple of a byte, push
> +	 * the bits up in the field, so the most signicant field bit is
> +	 * the most significant bit in the byte:
> +	 *
> +	 * before:
> +	 * val  |----|----|----|----|----|--MM|mmmm|llll|
> +	 * after
> +	 * val  |----|----|----|----|----|MMmm|mmll|ll00|
> +	 */
> +	offset = bit_length % NBBY;
> +	if (offset)
> +		val <<= (NBBY - offset);
> +
> +	/*
> +	 * convert to big endian and copy into the array
> +	 * rbuf |----|----|----|----|----|MMmm|mmll|ll00|
> +	 */
> +	*out = cpu_to_be64(val);
> +
> +	/*
> +	 * Align the array to point to the field in the array.
> +	 *  rbuf  = |MMmm|mmll|ll00|
> +	 */
> +	offset = sizeof(__be64) - 1 - ((bit_length - 1) / sizeof(__be64));
> +	return rbuf + offset;
> +}
> +
> +/* Increase the value by some small prime number. */
> +static bool
> +fuzz_add(
> +	void		*buf,
> +	int		bitoff,
> +	int		nbits)
> +{
> +	uint64_t	val;
> +	__be64		out;
> +	char		*b;
> +
> +	if (nbits > 64)
> +		return false;
> +
> +	val = getbitval(buf, bitoff, nbits, BVUNSIGNED);
> +	val += (nbits > 8 ? 2017 : 137);
> +	b = format_number(val, &out, nbits);
> +	setbitval(buf, bitoff, nbits, b);
> +
> +	return true;
> +}
> +
> +/* Decrease the value by some small prime number. */
> +static bool
> +fuzz_sub(
> +	void		*buf,
> +	int		bitoff,
> +	int		nbits)
> +{
> +	uint64_t	val;
> +	__be64		out;
> +	char		*b;
> +
> +	if (nbits > 64)
> +		return false;
> +
> +	val = getbitval(buf, bitoff, nbits, BVUNSIGNED);
> +	val -= (nbits > 8 ? 2017 : 137);
> +	b = format_number(val, &out, nbits);
> +	setbitval(buf, bitoff, nbits, b);
> +
> +	return true;
> +}
> +
> +/* Randomize the field. */
> +static bool
> +fuzz_random(
> +	void		*buf,
> +	int		bitoff,
> +	int		nbits)
> +{
> +	int		i, bytes;
> +	char		*b, *rbuf;
> +
> +	bytes = byteize_up(nbits);
> +	rbuf = b = malloc(bytes);
> +	if (!b) {
> +		perror("fuzz_random");
> +		return false;
> +	}
> +
> +	for (i = 0; i < bytes; i++)
> +		*b++ = (char)lrand48();
> +
> +	setbitval(buf, bitoff, nbits, rbuf);
> +	free(rbuf);
> +
> +	return true;
> +}
> +
> +struct fuzzcmd {
> +	const char	*verb;
> +	bool		(*fn)(void *buf, int bitoff, int nbits);
> +};
> +
> +/* Keep these verbs in sync with enum fuzzcmds. */
> +static struct fuzzcmd fuzzverbs[] = {
> +	{"zeroes",		fuzz_zeroes},
> +	{"ones",		fuzz_ones},
> +	{"firstbit",		fuzz_firstbit},
> +	{"middlebit",		fuzz_middlebit},
> +	{"lastbit",		fuzz_lastbit},
> +	{"add",			fuzz_add},
> +	{"sub",			fuzz_sub},
> +	{"random",		fuzz_random},
> +	{NULL,			NULL},
> +};
> +
> +/* ARGSUSED */
> +void
> +fuzz_struct(
> +	const field_t	*fields,
> +	int		argc,
> +	char		**argv)
> +{
> +	const ftattr_t	*fa;
> +	flist_t		*fl;
> +	flist_t		*sfl;
> +	int		bit_length;
> +	struct fuzzcmd	*fc;
> +	bool		success;
> +	int		parentoffset;
> +
> +	if (argc != 2) {
> +		dbprintf(_("Usage: fuzz fieldname verb\n"));
> +		dbprintf("Verbs: %s", fuzzverbs->verb);
> +		for (fc = fuzzverbs + 1; fc->verb != NULL; fc++)
> +			dbprintf(", %s", fc->verb);
> +		dbprintf(".\n");
> +		return;
> +	}
> +
> +	fl = flist_scan(argv[0]);
> +	if (!fl) {
> +		dbprintf(_("unable to parse '%s'.\n"), argv[0]);
> +		return;
> +	}
> +
> +	/* Find our fuzz verb */
> +	for (fc = fuzzverbs; fc->verb != NULL; fc++)
> +		if (!strcmp(fc->verb, argv[1]))
> +			break;
> +	if (fc->fn == NULL) {
> +		dbprintf(_("Unknown fuzz command '%s'.\n"), argv[1]);
> +		return;
> +	}
> +
> +	/* if we're a root field type, go down 1 layer to get field list */
> +	if (fields->name[0] == '\0') {
> +		fa = &ftattrtab[fields->ftyp];
> +		ASSERT(fa->ftyp == fields->ftyp);
> +		fields = fa->subfld;
> +	}
> +
> +	/* run down the field list and set offsets into the data */
> +	if (!flist_parse(fields, fl, iocur_top->data, 0)) {
> +		flist_free(fl);
> +		dbprintf(_("parsing error\n"));
> +		return;
> +	}
> +
> +	sfl = fl;
> +	parentoffset = 0;
> +	while (sfl->child) {
> +		parentoffset = sfl->offset;
> +		sfl = sfl->child;
> +	}
> +
> +	/*
> +	 * For structures, fsize * fcount tells us the size of the region we are
> +	 * modifying, which is usually a single structure member and is pointed
> +	 * to by the last child in the list.
> +	 *
> +	 * However, if the base structure is an array and we have a direct index
> +	 * into the array (e.g. write bno[5]) then we are returned a single
> +	 * flist object with the offset pointing directly at the location we
> +	 * need to modify. The length of the object we are modifying is then
> +	 * determined by the size of the individual array entry (fsize) and the
> +	 * indexes defined in the object, not the overall size of the array
> +	 * (which is what fcount returns).
> +	 */
> +	bit_length = fsize(sfl->fld, iocur_top->data, parentoffset, 0);
> +	if (sfl->fld->flags & FLD_ARRAY)
> +		bit_length *= sfl->high - sfl->low + 1;
> +	else
> +		bit_length *= fcount(sfl->fld, iocur_top->data, parentoffset);
> +
> +	/* Fuzz the value */
> +	success = fc->fn(iocur_top->data, sfl->offset, bit_length);
> +	if (!success) {
> +		dbprintf(_("unable to fuzz field '%s'\n"), argv[0]);
> +		flist_free(fl);
> +		return;
> +	}
> +
> +	/* Write the fuzzed value back */
> +	write_cur();
> +
> +	flist_print(fl);
> +	print_flist(fl);
> +	flist_free(fl);
> +}
> diff --git a/db/fuzz.h b/db/fuzz.h
> new file mode 100644
> index 0000000..c203eb5
> --- /dev/null
> +++ b/db/fuzz.h
> @@ -0,0 +1,21 @@
> +/*
> + * Copyright (C) 2017 Oracle.  All Rights Reserved.
> + *
> + * Author: Darrick J. Wong <darrick.wong@xxxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or
> + * 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 would 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 the Free Software Foundation,
> + * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
> + */
> +extern void	fuzz_init(void);
> +extern void	fuzz_struct(const field_t *fields, int argc, char **argv);
> diff --git a/db/type.c b/db/type.c
> index bf31e04..740adc0 100644
> --- a/db/type.c
> +++ b/db/type.c
> @@ -39,6 +39,7 @@
>  #include "dir2.h"
>  #include "text.h"
>  #include "symlink.h"
> +#include "fuzz.h"
>  
>  static const typ_t	*findtyp(char *name);
>  static int		type_f(int argc, char **argv);
> @@ -254,10 +255,17 @@ handle_struct(
>  	int           argc,
>  	char          **argv)
>  {
> -	if (action == DB_WRITE)
> +	switch (action) {
> +	case DB_FUZZ:
> +		fuzz_struct(fields, argc, argv);
> +		break;
> +	case DB_WRITE:
>  		write_struct(fields, argc, argv);
> -	else
> +		break;
> +	case DB_READ:
>  		print_struct(fields, argc, argv);
> +		break;
> +	}
>  }
>  
>  void
> @@ -267,10 +275,17 @@ handle_string(
>  	int           argc,
>  	char          **argv)
>  {
> -	if (action == DB_WRITE)
> +	switch (action) {
> +	case DB_WRITE:
>  		write_string(fields, argc, argv);
> -	else
> +		break;
> +	case DB_READ:
>  		print_string(fields, argc, argv);
> +		break;
> +	case DB_FUZZ:
> +		dbprintf(_("string fuzzing not supported.\n"));
> +		break;
> +	}
>  }
>  
>  void
> @@ -280,10 +295,17 @@ handle_block(
>  	int           argc,
>  	char          **argv)
>  {
> -	if (action == DB_WRITE)
> +	switch (action) {
> +	case DB_WRITE:
>  		write_block(fields, argc, argv);
> -	else
> +		break;
> +	case DB_READ:
>  		print_block(fields, argc, argv);
> +		break;
> +	case DB_FUZZ:
> +		dbprintf(_("use 'blocktrash' or 'write' to fuzz a block.\n"));
> +		break;
> +	}
>  }
>  
>  void
> @@ -293,6 +315,14 @@ handle_text(
>  	int           argc,
>  	char          **argv)
>  {
> -	if (action != DB_WRITE)
> +	switch (action) {
> +	case DB_FUZZ:
> +		/* fall through */
> +	case DB_WRITE:
> +		dbprintf(_("text writing/fuzzing not supported.\n"));
> +		break;
> +	case DB_READ:
>  		print_text(fields, argc, argv);
> +		break;
> +	}
>  }
> diff --git a/db/type.h b/db/type.h
> index 85d89c7..3971975 100644
> --- a/db/type.h
> +++ b/db/type.h
> @@ -30,6 +30,7 @@ typedef enum typnm
>  	TYP_TEXT, TYP_FINOBT, TYP_NONE
>  } typnm_t;
>  
> +#define DB_FUZZ  2
>  #define DB_WRITE 1
>  #define DB_READ  0
>  
> diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
> index b3129f7..49e665a 100644
> --- a/man/man8/xfs_db.8
> +++ b/man/man8/xfs_db.8
> @@ -613,6 +613,55 @@ in units of 512-byte blocks, no matter what the filesystem's block size is.
>  .BI "The optional " start " and " end " arguments can be used to constrain
>  the output to a particular range of disk blocks.
>  .TP
> +.BI "fuzz [\-c] [\-d] " "field action"
> +Write garbage into a specific structure field on disk.
> +Expert mode must be enabled to use this command.
> +The operation happens immediately; there is no buffering.
> +.IP
> +The fuzz command can take the following
> +.IR action "s"
> +against a field:
> +.RS 1.0i
> +.TP 0.4i
> +.B zeroes
> +Clears all bits in the field.
> +.TP 0.4i
> +.B ones
> +Sets all bits in the field.
> +.TP 0.4i
> +.B firstbit
> +Flips the first bit in the field.
> +For a scalar value, this is the highest bit.
> +.TP 0.4i
> +.B middlebit
> +Flips the middle bit in the field.
> +.TP 0.4i
> +.B lastbit
> +Flips the last bit in the field.
> +For a scalar value, this is the lowest bit.
> +.TP 0.4i
> +.B add
> +Adds a small value to a scalar field.
> +.TP 0.4i
> +.B sub
> +Subtracts a small value from a scalar field.
> +.TP 0.4i
> +.B random
> +Randomizes the contents of the field.
> +.RE
> +.IP
> +The following switches affect the write behavior:
> +.RS 1.0i
> +.TP 0.4i
> +.B \-c
> +Skip write verifiers and CRC recalculation; allows invalid data to be written
> +to disk.
> +.TP 0.4i
> +.B \-d
> +Skip write verifiers but perform CRC recalculation; allows invalid data to be
> +written to disk to test detection of invalid data.
> +.RE
> +.TP
>  .BI hash " string
>  Prints the hash value of
>  .I string
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 
Carlos
--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [XFS Filesystem Development (older mail)]     [Linux Filesystem Development]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux RAID]     [Linux SCSI]


  Powered by Linux