This adds a new "crc" command to xfs_db for CRC-enabled filesystems. If a structure has a CRC field, we can validate it, invalidate/corrupt it, or revalidate/rewrite it: xfs_db> sb 0 xfs_db> crc -v crc = 0x796c814f (correct) xfs_db> crc -i Metadata CRC error detected at block 0x0/0x200 crc = 0x796c8150 (bad) xfs_db> crc -r crc = 0x796c814f (correct) (-i and -r require "expert" write-capable mode) This requires temporarily replacing the write verifier with a dummy which won't recalculate the CRC on the way to disk. It also required me to write a new flist function, which is totally foreign to me, so hopefully done right - but it seems to work here. Signed-off-by: Eric Sandeen <sandeen@xxxxxxxxxx> --- I found this very useful when working with a filesystem image which was consistent except for a corrupt CRC; the ability to rewrite the correct CRCs and run repair to validate the fs was very handy... V2: Fix whitespace damage, clarify write_cur() changes a bit w/ code & comments. V3: Be a bit more verbose with command output V4: Rebase patch to current tree diff --git a/db/Makefile b/db/Makefile index 8260da3..ba4b1a8 100644 --- a/db/Makefile +++ b/db/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/include/builddefs LTCOMMAND = xfs_db HFILES = addr.h agf.h agfl.h agi.h attr.h attrshort.h bit.h block.h bmap.h \ - btblock.h bmroot.h check.h command.h convert.h debug.h \ + btblock.h bmroot.h check.h command.h convert.h crc.h debug.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 \ diff --git a/db/command.c b/db/command.c index 3c17a1e..1848d64 100644 --- a/db/command.c +++ b/db/command.c @@ -49,6 +49,7 @@ #include "write.h" #include "malloc.h" #include "dquot.h" +#include "crc.h" cmdinfo_t *cmdtab; int ncmds; @@ -124,6 +125,7 @@ init_commands(void) bmap_init(); check_init(); convert_init(); + crc_init(); debug_init(); echo_init(); frag_init(); diff --git a/db/flist.c b/db/flist.c index 84065a2..2530baf 100644 --- a/db/flist.c +++ b/db/flist.c @@ -411,6 +411,40 @@ flist_split( return v; } +/* + * Given a set of fields, scan for a field of the given type. + * Return an flist leading to the first found field + * of that type. + * Return NULL if no field of the given type is found. + */ +flist_t * +flist_find_ftyp( + const field_t *fields, + fldt_t type) +{ + flist_t *fl; + const field_t *f; + const ftattr_t *fa; + + for (f = fields; f->name; f++) { + fl = flist_make(f->name); + fl->fld = f; + if (f->ftyp == type) + return fl; + fa = &ftattrtab[f->ftyp]; + if (fa->subfld) { + flist_t *nfl; + nfl = flist_find_ftyp(fa->subfld, type); + if (nfl) { + fl->child = nfl; + return fl; + } + } + flist_free(fl); + } + return NULL; +} + static void ftok_free( ftok_t *ft) diff --git a/db/flist.h b/db/flist.h index 5c9fba0..3f4b312 100644 --- a/db/flist.h +++ b/db/flist.h @@ -37,3 +37,4 @@ extern int flist_parse(const struct field *fields, flist_t *fl, void *obj, int startoff); extern void flist_print(flist_t *fl); extern flist_t *flist_scan(char *name); +extern flist_t *flist_find_ftyp(const field_t *fields, fldt_t type); diff --git a/db/io.c b/db/io.c index 91cab12..56b4414 100644 --- a/db/io.c +++ b/db/io.c @@ -27,6 +27,7 @@ #include "output.h" #include "init.h" #include "malloc.h" +#include "crc.h" static int pop_f(int argc, char **argv); static void pop_help(void); @@ -473,12 +474,14 @@ xfs_verify_recalc_crc( void write_cur(void) { + int skip_crc = (iocur_top->bp->b_ops->verify_write == xfs_dummy_verify); + if (iocur_sp < 0) { dbprintf(_("nothing to write\n")); return; } - if (xfs_sb_version_hascrc(&mp->m_sb) && iocur_top->ino_buf) { + if (xfs_sb_version_hascrc(&mp->m_sb) && iocur_top->ino_buf && !skip_crc) { libxfs_dinode_calc_crc(mp, iocur_top->data); iocur_top->ino_crc_ok = 1; } @@ -489,6 +492,19 @@ write_cur(void) write_cur_bbs(); else write_cur_buf(); + + /* If we didn't write the crc automatically, re-check validity */ + if (iocur_top->ino_buf && skip_crc) { + xfs_dinode_t *dip; + xfs_ino_t ino; + + dip = iocur_top->data; + ino = iocur_top->ino; + iocur_top->ino_crc_ok = xfs_verify_cksum((char *)dip, + mp->m_sb.sb_inodesize, + XFS_DINODE_CRC_OFF); + } + } void diff --git a/db/write.h b/db/write.h index 31e2665..664ddcc 100644 --- a/db/write.h +++ b/db/write.h @@ -20,5 +20,5 @@ struct field; extern void write_init(void); extern void write_block(const field_t *fields, int argc, char **argv); -extern void write_string(const field_t *fields, int argc, char **argv); extern void write_struct(const field_t *fields, int argc, char **argv); +extern void write_string(const field_t *fields, int argc, char **argv); diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8 index ff8f862..894a94e 100644 --- a/man/man8/xfs_db.8 +++ b/man/man8/xfs_db.8 @@ -87,16 +87,14 @@ or .I filename read-only. This option is required if the filesystem is mounted. It is only necessary to omit this flag if a command that changes data -.RB ( write ", " blocktrash ) +.RB ( write ", " blocktrash ", " crc ) is to be used. .TP .B \-x Specifies expert mode. This enables the -.B write -and -.B blocktrash -commands. +.RB ( write ", " blocktrash ", " crc +invalidate/revalidate) commands. .TP .B \-V Prints the version number and exits. @@ -422,6 +420,25 @@ conversions such as .I agb .BR fsblock . .TP +.B crc [\-i|\-r|\-v] +Invalidates, revalidates, or validates the CRC (checksum) +field of the current structure, if it has one. +This command is available only on CRC-enabled filesystems. +With no argument, validation is performed. +Each command will display the resulting CRC value and state. +.RS 1.0i +.TP 0.4i +.B \-i +Invalidate the structure's CRC value (incrementing it by one), +and write it to disk. +.TP +.B \-r +Recalculate the current structure's correct CRC value, and write it to disk. +.TP +.B \-v +Validate and display the current value and state of the structure's CRC. +.RE +.TP .BI "daddr [" d ] Set current address to the daddr (512 byte block) given by .IR d . _______________________________________________ xfs mailing list xfs@xxxxxxxxxxx http://oss.sgi.com/mailman/listinfo/xfs