* [PATCH 0/5] xfsprogs May 2015 patchbomb
@ 2015-05-26 22:51 Darrick J. Wong
2015-05-26 22:51 ` [PATCH 1/5] xfs_repair: refuse to run if we don't recognize version or feature flags Darrick J. Wong
` (4 more replies)
0 siblings, 5 replies; 25+ messages in thread
From: Darrick J. Wong @ 2015-05-26 22:51 UTC (permalink / raw)
To: david, darrick.wong; +Cc: xfs
Hi all,
This is a rollup of various fixes for xfsprogs 3.2.3-rc1.
The first patch makes repair stop when it encounters v5 feature bits
which it doesn't understand. Without it, an old xfs_repair will
trash a filesystem it doesn't know how to fix.
The second patch adds to repair some missing metadata back pointer
checks.
Patch 3 ensures that the .. link in a dir being rebuilt points
to a sane inode number.
Patch 4 implements blockget for v5 filesystems. This is a second try
at a previous patch which didn't quite catch all the new magic numbers
and had some problems iterating directory index data.
Patch 5 fixes up blocktrash to avoid verifier errors when writing
deliberately corrupted blocks to disk. It also adds the xfsfuzz.sh
script which will create and populate an XFS image, corrupts it,
then tries to modify/repair/re-modify the image. I'm not sure this
is appropriate for xfstests, since runs until the kernel crashes or
repair fails to repair or the user ^Cs it.
I've tested these xfsprogs changes against the -next branch as of
5/11.
Comments and questions are, as always, welcome.
--D
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 25+ messages in thread* [PATCH 1/5] xfs_repair: refuse to run if we don't recognize version or feature flags 2015-05-26 22:51 [PATCH 0/5] xfsprogs May 2015 patchbomb Darrick J. Wong @ 2015-05-26 22:51 ` Darrick J. Wong 2015-05-26 23:49 ` Eric Sandeen ` (2 more replies) 2015-05-26 22:51 ` [PATCH 2/5] xfs_repair: better checking of v5 metadata fields Darrick J. Wong ` (3 subsequent siblings) 4 siblings, 3 replies; 25+ messages in thread From: Darrick J. Wong @ 2015-05-26 22:51 UTC (permalink / raw) To: david, darrick.wong; +Cc: xfs Apparently xfs_repair running on a v5 filesystem doesn't check the compat, rocompat, or incompat feature flags for bits that it doesn't know about, which means that old xfs_repairs can wreak havoc. So, strengthen the checks to prevent repair from "repairing" anything it doesn't understand. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> --- repair/versions.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/repair/versions.c b/repair/versions.c index c1dff72..e60574d 100644 --- a/repair/versions.c +++ b/repair/versions.c @@ -141,6 +141,13 @@ parse_sb_version(xfs_sb_t *sb) } } + /* Look for V5 feature flags we don't know about */ + if (XFS_SB_VERSION_NUM(sb) >= XFS_SB_VERSION_5 && + (xfs_sb_has_ro_compat_feature(sb, XFS_SB_FEAT_RO_COMPAT_UNKNOWN) || + xfs_sb_has_incompat_feature(sb, XFS_SB_FEAT_INCOMPAT_UNKNOWN) || + xfs_sb_has_compat_feature(sb, XFS_SB_FEAT_COMPAT_UNKNOWN))) + issue_warning = 1; + if (issue_warning) { do_warn( _("This filesystem uses feature(s) not yet supported in this release.\n" _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH 1/5] xfs_repair: refuse to run if we don't recognize version or feature flags 2015-05-26 22:51 ` [PATCH 1/5] xfs_repair: refuse to run if we don't recognize version or feature flags Darrick J. Wong @ 2015-05-26 23:49 ` Eric Sandeen 2015-05-27 5:45 ` [PATCH v2 " Darrick J. Wong 2015-05-27 18:15 ` [PATCH v3 " Darrick J. Wong 2 siblings, 0 replies; 25+ messages in thread From: Eric Sandeen @ 2015-05-26 23:49 UTC (permalink / raw) To: Darrick J. Wong, david; +Cc: xfs On 5/26/15 5:51 PM, Darrick J. Wong wrote: > Apparently xfs_repair running on a v5 filesystem doesn't check the > compat, rocompat, or incompat feature flags for bits that it doesn't > know about, which means that old xfs_repairs can wreak havoc. So, > strengthen the checks to prevent repair from "repairing" anything it > doesn't understand. > > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> > --- > repair/versions.c | 7 +++++++ > 1 file changed, 7 insertions(+) > > > diff --git a/repair/versions.c b/repair/versions.c > index c1dff72..e60574d 100644 > --- a/repair/versions.c > +++ b/repair/versions.c > @@ -141,6 +141,13 @@ parse_sb_version(xfs_sb_t *sb) > } > } > > + /* Look for V5 feature flags we don't know about */ > + if (XFS_SB_VERSION_NUM(sb) >= XFS_SB_VERSION_5 && > + (xfs_sb_has_ro_compat_feature(sb, XFS_SB_FEAT_RO_COMPAT_UNKNOWN) || > + xfs_sb_has_incompat_feature(sb, XFS_SB_FEAT_INCOMPAT_UNKNOWN) || > + xfs_sb_has_compat_feature(sb, XFS_SB_FEAT_COMPAT_UNKNOWN))) > + issue_warning = 1; > + should this go after the xfs_sb_good_version() check? Seems like it's more of a fine-grained check on features for a given super version, and should come after that check. i.e. if for some reason XFS_SB_VERSION_NUM == 6, the root problem isn't the feature set, it's the superblock version number. And; would it be worth printing out what the features are? I guess we have no good existing mechanism for that, and could really only print hex values... still, might be useful for bug reports... -Eric > if (issue_warning) { > do_warn( > _("This filesystem uses feature(s) not yet supported in this release.\n" > > _______________________________________________ > xfs mailing list > xfs@oss.sgi.com > http://oss.sgi.com/mailman/listinfo/xfs > _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v2 1/5] xfs_repair: refuse to run if we don't recognize version or feature flags 2015-05-26 22:51 ` [PATCH 1/5] xfs_repair: refuse to run if we don't recognize version or feature flags Darrick J. Wong 2015-05-26 23:49 ` Eric Sandeen @ 2015-05-27 5:45 ` Darrick J. Wong 2015-05-27 14:54 ` Eric Sandeen 2015-05-27 15:19 ` Fanael Linithien 2015-05-27 18:15 ` [PATCH v3 " Darrick J. Wong 2 siblings, 2 replies; 25+ messages in thread From: Darrick J. Wong @ 2015-05-27 5:45 UTC (permalink / raw) To: david; +Cc: xfs Apparently xfs_repair running on a v5 filesystem doesn't check the compat, rocompat, or incompat feature flags for bits that it doesn't know about, which means that old xfs_repairs can wreak havoc. So, strengthen the checks to prevent repair from "repairing" anything it doesn't understand. v2: Move the complaint code after the version number check, and print the actual feature bits that we don't recognize. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> --- repair/versions.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/repair/versions.c b/repair/versions.c index c1dff72..dbe41a4 100644 --- a/repair/versions.c +++ b/repair/versions.c @@ -175,6 +175,39 @@ _("WARNING: you have disallowed superblock-feature-bits-allowed\n" } } + /* Look for V5 feature flags we don't know about */ + if (XFS_SB_VERSION_NUM(sb) >= XFS_SB_VERSION_5) { + if (xfs_sb_has_ro_compat_feature(sb, + XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) { + do_warn( +_("Superblock has unknown read-only compatible features (0x%x) enabled.\n" +"Using a more recent xfs_repair is recommended.\n"), + sb->sb_features_ro_compat & + XFS_SB_FEAT_RO_COMPAT_UNKNOWN); + issue_warning = 1; + } + if (xfs_sb_has_incompat_feature(sb, + XFS_SB_FEAT_INCOMPAT_UNKNOWN)) { + do_warn( +_("Superblock has unknown read-only compatible features (0x%x) enabled.\n" +"Using a more recent xfs_repair is recommended.\n"), + sb->sb_features_ro_compat & + XFS_SB_FEAT_RO_COMPAT_UNKNOWN); + issue_warning = 1; + } + if (xfs_sb_has_compat_feature(sb, + XFS_SB_FEAT_COMPAT_UNKNOWN)) { + do_warn( +_("Superblock has unknown compatible features (0x%x) enabled.\n" +"Using a more recent xfs_repair is recommended.\n"), + sb->sb_features_ro_compat & + XFS_SB_FEAT_RO_COMPAT_UNKNOWN); + issue_warning = 1; + } + if (issue_warning) + return 1; + } + if (xfs_sb_version_hasattr(sb)) { if (!fs_attributes_allowed) { if (!no_modify) { _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH v2 1/5] xfs_repair: refuse to run if we don't recognize version or feature flags 2015-05-27 5:45 ` [PATCH v2 " Darrick J. Wong @ 2015-05-27 14:54 ` Eric Sandeen 2015-05-27 15:16 ` Eric Sandeen 2015-05-27 15:19 ` Fanael Linithien 1 sibling, 1 reply; 25+ messages in thread From: Eric Sandeen @ 2015-05-27 14:54 UTC (permalink / raw) To: Darrick J. Wong, david; +Cc: xfs On 5/27/15 12:45 AM, Darrick J. Wong wrote: > Apparently xfs_repair running on a v5 filesystem doesn't check the > compat, rocompat, or incompat feature flags for bits that it doesn't > know about, which means that old xfs_repairs can wreak havoc. So, > strengthen the checks to prevent repair from "repairing" anything it > doesn't understand. > > v2: Move the complaint code after the version number check, and print > the actual feature bits that we don't recognize. Thanks. That's a bit more wordy, but probably better, in the end. Reviewed-by: Eric Sandeen <sandeen@redhat.com> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> > --- > repair/versions.c | 33 +++++++++++++++++++++++++++++++++ > 1 file changed, 33 insertions(+) > > diff --git a/repair/versions.c b/repair/versions.c > index c1dff72..dbe41a4 100644 > --- a/repair/versions.c > +++ b/repair/versions.c > @@ -175,6 +175,39 @@ _("WARNING: you have disallowed superblock-feature-bits-allowed\n" > } > } > > + /* Look for V5 feature flags we don't know about */ > + if (XFS_SB_VERSION_NUM(sb) >= XFS_SB_VERSION_5) { > + if (xfs_sb_has_ro_compat_feature(sb, > + XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) { > + do_warn( > +_("Superblock has unknown read-only compatible features (0x%x) enabled.\n" > +"Using a more recent xfs_repair is recommended.\n"), > + sb->sb_features_ro_compat & > + XFS_SB_FEAT_RO_COMPAT_UNKNOWN); > + issue_warning = 1; > + } > + if (xfs_sb_has_incompat_feature(sb, > + XFS_SB_FEAT_INCOMPAT_UNKNOWN)) { > + do_warn( > +_("Superblock has unknown read-only compatible features (0x%x) enabled.\n" > +"Using a more recent xfs_repair is recommended.\n"), > + sb->sb_features_ro_compat & > + XFS_SB_FEAT_RO_COMPAT_UNKNOWN); > + issue_warning = 1; > + } > + if (xfs_sb_has_compat_feature(sb, > + XFS_SB_FEAT_COMPAT_UNKNOWN)) { > + do_warn( > +_("Superblock has unknown compatible features (0x%x) enabled.\n" > +"Using a more recent xfs_repair is recommended.\n"), > + sb->sb_features_ro_compat & > + XFS_SB_FEAT_RO_COMPAT_UNKNOWN); > + issue_warning = 1; > + } > + if (issue_warning) > + return 1; > + } > + > if (xfs_sb_version_hasattr(sb)) { > if (!fs_attributes_allowed) { > if (!no_modify) { > > _______________________________________________ > xfs mailing list > xfs@oss.sgi.com > http://oss.sgi.com/mailman/listinfo/xfs > _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v2 1/5] xfs_repair: refuse to run if we don't recognize version or feature flags 2015-05-27 14:54 ` Eric Sandeen @ 2015-05-27 15:16 ` Eric Sandeen 2015-05-27 15:27 ` Eric Sandeen 0 siblings, 1 reply; 25+ messages in thread From: Eric Sandeen @ 2015-05-27 15:16 UTC (permalink / raw) To: Darrick J. Wong, david; +Cc: xfs On 5/27/15 9:54 AM, Eric Sandeen wrote: > On 5/27/15 12:45 AM, Darrick J. Wong wrote: >> Apparently xfs_repair running on a v5 filesystem doesn't check the >> compat, rocompat, or incompat feature flags for bits that it doesn't >> know about, which means that old xfs_repairs can wreak havoc. So, >> strengthen the checks to prevent repair from "repairing" anything it >> doesn't understand. >> >> v2: Move the complaint code after the version number check, and print >> the actual feature bits that we don't recognize. > > Thanks. That's a bit more wordy, but probably better, in the end. > > Reviewed-by: Eric Sandeen <sandeen@redhat.com> Whoops, retract that, thanks for spotting those C&P errors, Fanael! -Eric _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v2 1/5] xfs_repair: refuse to run if we don't recognize version or feature flags 2015-05-27 15:16 ` Eric Sandeen @ 2015-05-27 15:27 ` Eric Sandeen 2015-05-27 16:04 ` Fanael Linithien 0 siblings, 1 reply; 25+ messages in thread From: Eric Sandeen @ 2015-05-27 15:27 UTC (permalink / raw) To: Darrick J. Wong, david; +Cc: xfs On 5/27/15 10:16 AM, Eric Sandeen wrote: > On 5/27/15 9:54 AM, Eric Sandeen wrote: >> On 5/27/15 12:45 AM, Darrick J. Wong wrote: >>> Apparently xfs_repair running on a v5 filesystem doesn't check the >>> compat, rocompat, or incompat feature flags for bits that it doesn't >>> know about, which means that old xfs_repairs can wreak havoc. So, >>> strengthen the checks to prevent repair from "repairing" anything it >>> doesn't understand. >>> >>> v2: Move the complaint code after the version number check, and print >>> the actual feature bits that we don't recognize. >> >> Thanks. That's a bit more wordy, but probably better, in the end. >> >> Reviewed-by: Eric Sandeen <sandeen@redhat.com> > > Whoops, retract that, thanks for spotting those C&P errors, Fanael! I wonder if something like: /* Look for V5 feature flags we don't know about */ if (XFS_SB_VERSION_NUM(sb) >= XFS_SB_VERSION_5 && (xfs_sb_has_ro_compat_feature(sb, XFS_SB_FEAT_RO_COMPAT_UNKNOWN) || xfs_sb_has_incompat_feature(sb, XFS_SB_FEAT_INCOMPAT_UNKNOWN) || xfs_sb_has_compat_feature(sb, XFS_SB_FEAT_COMPAT_UNKNOWN))) { printf("unknown feature flags 0x%x/0x%x/0x%x\n", sb->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_UNKNOWN, sb->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_UNKNOWN, sb->sb_features_compat & XFS_SB_FEAT_COMPAT_UNKNOWN); ... would suffice, given that the user will need to read code to unerstand the hex values, anyway. Hm, and as Fanael also pointed out, "compat" features ... should be ok, right, and can be removed from the exclusions? -Eric _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v2 1/5] xfs_repair: refuse to run if we don't recognize version or feature flags 2015-05-27 15:27 ` Eric Sandeen @ 2015-05-27 16:04 ` Fanael Linithien 2015-05-27 16:26 ` Eric Sandeen 2015-05-27 17:17 ` Darrick J. Wong 0 siblings, 2 replies; 25+ messages in thread From: Fanael Linithien @ 2015-05-27 16:04 UTC (permalink / raw) To: Eric Sandeen, Darrick J. Wong, david; +Cc: xfs On 2015-05-27 17:27, Eric Sandeen wrote: > > I wonder if something like: > > /* Look for V5 feature flags we don't know about */ > if (XFS_SB_VERSION_NUM(sb) >= XFS_SB_VERSION_5 && > (xfs_sb_has_ro_compat_feature(sb, XFS_SB_FEAT_RO_COMPAT_UNKNOWN) || > xfs_sb_has_incompat_feature(sb, XFS_SB_FEAT_INCOMPAT_UNKNOWN) || > xfs_sb_has_compat_feature(sb, XFS_SB_FEAT_COMPAT_UNKNOWN))) { > printf("unknown feature flags 0x%x/0x%x/0x%x\n", > sb->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_UNKNOWN, > sb->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_UNKNOWN, > sb->sb_features_compat & XFS_SB_FEAT_COMPAT_UNKNOWN); > ... > > would suffice, given that the user will need to read code to unerstand the hex > values, anyway. > > Hm, and as Fanael also pointed out, "compat" features ... should be ok, right, > and can be removed from the exclusions? I'm not entirely sure silently ignoring unknown compat features in xfs_repair is a good idea. Consider this ext2 example: xattr support is a compat flag. It's okay to rw mount a FS with xattrs on some ancient (or non-Linux) kernel without xattr support — everything will be fine, even though there's no way to access them — but if the fsck tool doesn't understand them, it wouldn't be able to diagnose xattr corruption. I'd either warn the user about unknown compat features, telling them they're on their own if something in the FS is still broken; or barf outright. _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v2 1/5] xfs_repair: refuse to run if we don't recognize version or feature flags 2015-05-27 16:04 ` Fanael Linithien @ 2015-05-27 16:26 ` Eric Sandeen 2015-05-27 17:17 ` Darrick J. Wong 1 sibling, 0 replies; 25+ messages in thread From: Eric Sandeen @ 2015-05-27 16:26 UTC (permalink / raw) To: Fanael Linithien, Darrick J. Wong, david; +Cc: xfs On 5/27/15 11:04 AM, Fanael Linithien wrote: > I'm not entirely sure silently ignoring unknown compat features in > xfs_repair is a good idea. Consider this ext2 example: xattr support > is a compat flag. It's okay to rw mount a FS with xattrs on some > ancient (or non-Linux) kernel without xattr support — everything will > be fine, even though there's no way to access them — but if the fsck > tool doesn't understand them, it wouldn't be able to diagnose xattr > corruption. Hm, good point. We have no "compat" features atm, so it's not really clear; if nothing else, though, those features will have to go un-checked, if there is any checking to do. So yeah, maybe best to keep it as an exclusion. -Eric _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v2 1/5] xfs_repair: refuse to run if we don't recognize version or feature flags 2015-05-27 16:04 ` Fanael Linithien 2015-05-27 16:26 ` Eric Sandeen @ 2015-05-27 17:17 ` Darrick J. Wong 1 sibling, 0 replies; 25+ messages in thread From: Darrick J. Wong @ 2015-05-27 17:17 UTC (permalink / raw) To: Fanael Linithien; +Cc: Eric Sandeen, xfs On Wed, May 27, 2015 at 06:04:57PM +0200, Fanael Linithien wrote: > On 2015-05-27 17:27, Eric Sandeen wrote: > > > >I wonder if something like: > > > > /* Look for V5 feature flags we don't know about */ > > if (XFS_SB_VERSION_NUM(sb) >= XFS_SB_VERSION_5 && > > (xfs_sb_has_ro_compat_feature(sb, XFS_SB_FEAT_RO_COMPAT_UNKNOWN) || > > xfs_sb_has_incompat_feature(sb, XFS_SB_FEAT_INCOMPAT_UNKNOWN) || > > xfs_sb_has_compat_feature(sb, XFS_SB_FEAT_COMPAT_UNKNOWN))) { > > printf("unknown feature flags 0x%x/0x%x/0x%x\n", > > sb->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_UNKNOWN, > > sb->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_UNKNOWN, > > sb->sb_features_compat & XFS_SB_FEAT_COMPAT_UNKNOWN); > > ... > > > >would suffice, given that the user will need to read code to unerstand the hex > >values, anyway. <shrug> I guess repair could do that. I'd broken things out separately (key word: broken ;)) to avoid complaining about whichever fields aren't broken, but I suppose it doesn't really matter. > > > >Hm, and as Fanael also pointed out, "compat" features ... should be ok, right, > >and can be removed from the exclusions? > > I'm not entirely sure silently ignoring unknown compat features in > xfs_repair is a good idea. Consider this ext2 example: xattr support > is a compat flag. It's okay to rw mount a FS with xattrs on some > ancient (or non-Linux) kernel without xattr support — everything > will be fine, even though there's no way to access them — but if the > fsck tool doesn't understand them, it wouldn't be able to diagnose > xattr corruption. > > I'd either warn the user about unknown compat features, telling them > they're on their own if something in the FS is still broken; or barf > outright. I prefer any repair tool be forthcoming about not knowing what something is. --D > > _______________________________________________ > xfs mailing list > xfs@oss.sgi.com > http://oss.sgi.com/mailman/listinfo/xfs _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v2 1/5] xfs_repair: refuse to run if we don't recognize version or feature flags 2015-05-27 5:45 ` [PATCH v2 " Darrick J. Wong 2015-05-27 14:54 ` Eric Sandeen @ 2015-05-27 15:19 ` Fanael Linithien 2015-05-27 16:42 ` Darrick J. Wong 1 sibling, 1 reply; 25+ messages in thread From: Fanael Linithien @ 2015-05-27 15:19 UTC (permalink / raw) To: xfs > Apparently xfs_repair running on a v5 filesystem doesn't check the > compat, rocompat, or incompat feature flags for bits that it doesn't > know about, which means that old xfs_repairs can wreak havoc. So, > strengthen the checks to prevent repair from "repairing" anything it > doesn't understand. > > v2: Move the complaint code after the version number check, and print > the actual feature bits that we don't recognize. > > Signed-off-by: Darrick J. Wong <darrick.wong at oracle.com> > --- > repair/versions.c | 33 +++++++++++++++++++++++++++++++++ > 1 file changed, 33 insertions(+) > > diff --git a/repair/versions.c b/repair/versions.c > index c1dff72..dbe41a4 100644 > --- a/repair/versions.c > +++ b/repair/versions.c > @@ -175,6 +175,39 @@ _("WARNING: you have disallowed superblock-feature-bits-allowed\n" > } > } > > + /* Look for V5 feature flags we don't know about */ > + if (XFS_SB_VERSION_NUM(sb) >= XFS_SB_VERSION_5) { > + if (xfs_sb_has_ro_compat_feature(sb, > + XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) { > + do_warn( > +_("Superblock has unknown read-only compatible features (0x%x) enabled.\n" > +"Using a more recent xfs_repair is recommended.\n"), > + sb->sb_features_ro_compat & > + XFS_SB_FEAT_RO_COMPAT_UNKNOWN); > + issue_warning = 1; > + } > + if (xfs_sb_has_incompat_feature(sb, > + XFS_SB_FEAT_INCOMPAT_UNKNOWN)) { > + do_warn( > +_("Superblock has unknown read-only compatible features (0x%x) enabled.\n" > +"Using a more recent xfs_repair is recommended.\n"), > + sb->sb_features_ro_compat & > + XFS_SB_FEAT_RO_COMPAT_UNKNOWN); Copy/paste error, do you mean incompat? > + issue_warning = 1; > + } > + if (xfs_sb_has_compat_feature(sb, > + XFS_SB_FEAT_COMPAT_UNKNOWN)) { > + do_warn( > +_("Superblock has unknown compatible features (0x%x) enabled.\n" > +"Using a more recent xfs_repair is recommended.\n"), > + sb->sb_features_ro_compat & > + XFS_SB_FEAT_RO_COMPAT_UNKNOWN); compat here? > + issue_warning = 1; > + } > + if (issue_warning) > + return 1; > + } > + > if (xfs_sb_version_hasattr(sb)) { > if (!fs_attributes_allowed) { > if (!no_modify) { _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v2 1/5] xfs_repair: refuse to run if we don't recognize version or feature flags 2015-05-27 15:19 ` Fanael Linithien @ 2015-05-27 16:42 ` Darrick J. Wong 0 siblings, 0 replies; 25+ messages in thread From: Darrick J. Wong @ 2015-05-27 16:42 UTC (permalink / raw) To: Fanael Linithien; +Cc: xfs On Wed, May 27, 2015 at 05:19:00PM +0200, Fanael Linithien wrote: > > Apparently xfs_repair running on a v5 filesystem doesn't check the > > compat, rocompat, or incompat feature flags for bits that it doesn't > > know about, which means that old xfs_repairs can wreak havoc. So, > > strengthen the checks to prevent repair from "repairing" anything it > > doesn't understand. > > > > v2: Move the complaint code after the version number check, and print > > the actual feature bits that we don't recognize. > > > > Signed-off-by: Darrick J. Wong <darrick.wong at oracle.com> > > --- > > repair/versions.c | 33 +++++++++++++++++++++++++++++++++ > > 1 file changed, 33 insertions(+) > > > > diff --git a/repair/versions.c b/repair/versions.c > > index c1dff72..dbe41a4 100644 > > --- a/repair/versions.c > > +++ b/repair/versions.c > > @@ -175,6 +175,39 @@ _("WARNING: you have disallowed > superblock-feature-bits-allowed\n" > > } > > } > > > > + /* Look for V5 feature flags we don't know about */ > > + if (XFS_SB_VERSION_NUM(sb) >= XFS_SB_VERSION_5) { > > + if (xfs_sb_has_ro_compat_feature(sb, > > + XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) { > > + do_warn( > > +_("Superblock has unknown read-only compatible features (0x%x) > enabled.\n" > > +"Using a more recent xfs_repair is recommended.\n"), > > + sb->sb_features_ro_compat & > > + XFS_SB_FEAT_RO_COMPAT_UNKNOWN); > > + issue_warning = 1; > > + } > > + if (xfs_sb_has_incompat_feature(sb, > > + XFS_SB_FEAT_INCOMPAT_UNKNOWN)) { > > + do_warn( > > +_("Superblock has unknown read-only compatible features (0x%x) > enabled.\n" > > +"Using a more recent xfs_repair is recommended.\n"), > > + sb->sb_features_ro_compat & > > + XFS_SB_FEAT_RO_COMPAT_UNKNOWN); > > Copy/paste error, do you mean incompat? > > > + issue_warning = 1; > > + } > > + if (xfs_sb_has_compat_feature(sb, > > + XFS_SB_FEAT_COMPAT_UNKNOWN)) { > > + do_warn( > > +_("Superblock has unknown compatible features (0x%x) enabled.\n" > > +"Using a more recent xfs_repair is recommended.\n"), > > + sb->sb_features_ro_compat & > > + XFS_SB_FEAT_RO_COMPAT_UNKNOWN); > > compat here? Err, yes. Thank you for catching all these. No more patching past 10pm for me.... :) --D > > > + issue_warning = 1; > > + } > > + if (issue_warning) > > + return 1; > > + } > > + > > if (xfs_sb_version_hasattr(sb)) { > > if (!fs_attributes_allowed) { > > if (!no_modify) { > > _______________________________________________ > xfs mailing list > xfs@oss.sgi.com > http://oss.sgi.com/mailman/listinfo/xfs _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v3 1/5] xfs_repair: refuse to run if we don't recognize version or feature flags 2015-05-26 22:51 ` [PATCH 1/5] xfs_repair: refuse to run if we don't recognize version or feature flags Darrick J. Wong 2015-05-26 23:49 ` Eric Sandeen 2015-05-27 5:45 ` [PATCH v2 " Darrick J. Wong @ 2015-05-27 18:15 ` Darrick J. Wong 2015-05-27 18:42 ` Fanael Linithien 2 siblings, 1 reply; 25+ messages in thread From: Darrick J. Wong @ 2015-05-27 18:15 UTC (permalink / raw) To: david; +Cc: Fanael Linithien, Eric Sandeen, xfs Apparently xfs_repair running on a v5 filesystem doesn't check the compat, rocompat, or incompat feature flags for bits that it doesn't know about, which means that old xfs_repairs can wreak havoc. So, strengthen the checks to prevent repair from "repairing" anything it doesn't understand. v2: Move the complaint code after the version number check, and print the actual feature bits that we don't recognize. v3: Fix some copy-pasta errors, and simpify the warning messages. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> --- repair/versions.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/repair/versions.c b/repair/versions.c index c1dff72..10bcd29 100644 --- a/repair/versions.c +++ b/repair/versions.c @@ -175,6 +175,20 @@ _("WARNING: you have disallowed superblock-feature-bits-allowed\n" } } + /* Look for V5 feature flags we don't know about */ + if (XFS_SB_VERSION_NUM(sb) >= XFS_SB_VERSION_5 && + (xfs_sb_has_compat_feature(sb, XFS_SB_FEAT_COMPAT_UNKNOWN) || + xfs_sb_has_ro_compat_feature(sb, XFS_SB_FEAT_RO_COMPAT_UNKNOWN) || + xfs_sb_has_incompat_feature(sb, XFS_SB_FEAT_INCOMPAT_UNKNOWN))) { + do_warn( +_("Superblock has unknown compat/rocompat/incompat features (0x%x/0x%x/0x%x).\n" + "Using a more recent xfs_repair is recommended.\n"), + sb->sb_features_compat & XFS_SB_FEAT_COMPAT_UNKNOWN, + sb->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_UNKNOWN, + sb->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_UNKNOWN); + return 1; + } + if (xfs_sb_version_hasattr(sb)) { if (!fs_attributes_allowed) { if (!no_modify) { _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH v3 1/5] xfs_repair: refuse to run if we don't recognize version or feature flags 2015-05-27 18:15 ` [PATCH v3 " Darrick J. Wong @ 2015-05-27 18:42 ` Fanael Linithien 0 siblings, 0 replies; 25+ messages in thread From: Fanael Linithien @ 2015-05-27 18:42 UTC (permalink / raw) To: Darrick J. Wong; +Cc: Eric Sandeen, xfs 2015-05-27 20:15 GMT+02:00 Darrick J. Wong <darrick.wong@oracle.com>: > Apparently xfs_repair running on a v5 filesystem doesn't check the > compat, rocompat, or incompat feature flags for bits that it doesn't > know about, which means that old xfs_repairs can wreak havoc. So, > strengthen the checks to prevent repair from "repairing" anything it > doesn't understand. > > v2: Move the complaint code after the version number check, and print > the actual feature bits that we don't recognize. > > v3: Fix some copy-pasta errors, and simpify the warning messages. > > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> > --- Reviewed-by: Fanael Linithien <fanael4@gmail.com> > repair/versions.c | 14 ++++++++++++++ > 1 file changed, 14 insertions(+) > > diff --git a/repair/versions.c b/repair/versions.c > index c1dff72..10bcd29 100644 > --- a/repair/versions.c > +++ b/repair/versions.c > @@ -175,6 +175,20 @@ _("WARNING: you have disallowed superblock-feature-bits-allowed\n" > } > } > > + /* Look for V5 feature flags we don't know about */ > + if (XFS_SB_VERSION_NUM(sb) >= XFS_SB_VERSION_5 && > + (xfs_sb_has_compat_feature(sb, XFS_SB_FEAT_COMPAT_UNKNOWN) || > + xfs_sb_has_ro_compat_feature(sb, XFS_SB_FEAT_RO_COMPAT_UNKNOWN) || > + xfs_sb_has_incompat_feature(sb, XFS_SB_FEAT_INCOMPAT_UNKNOWN))) { > + do_warn( > +_("Superblock has unknown compat/rocompat/incompat features (0x%x/0x%x/0x%x).\n" > + "Using a more recent xfs_repair is recommended.\n"), > + sb->sb_features_compat & XFS_SB_FEAT_COMPAT_UNKNOWN, > + sb->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_UNKNOWN, > + sb->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_UNKNOWN); > + return 1; > + } > + > if (xfs_sb_version_hasattr(sb)) { > if (!fs_attributes_allowed) { > if (!no_modify) { _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 2/5] xfs_repair: better checking of v5 metadata fields 2015-05-26 22:51 [PATCH 0/5] xfsprogs May 2015 patchbomb Darrick J. Wong 2015-05-26 22:51 ` [PATCH 1/5] xfs_repair: refuse to run if we don't recognize version or feature flags Darrick J. Wong @ 2015-05-26 22:51 ` Darrick J. Wong 2015-05-26 23:58 ` Dave Chinner 2015-05-27 5:44 ` [PATCH v2 " Darrick J. Wong 2015-05-26 22:51 ` [PATCH 3/5] xfs_repair: ensure .. is set to a sane ino value when rebuilding dir Darrick J. Wong ` (2 subsequent siblings) 4 siblings, 2 replies; 25+ messages in thread From: Darrick J. Wong @ 2015-05-26 22:51 UTC (permalink / raw) To: david, darrick.wong; +Cc: xfs Check the UUID, owner, and block number fields during repair, looking for blocks that fail either the checksum or the data structure verifiers. For directories we can simply rebuild corrupt/broken index data, though for anything else we have to toss out the broken object. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> --- repair/dir2.c | 7 ++ repair/phase6.c | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- repair/scan.c | 17 ++++++ 3 files changed, 177 insertions(+), 6 deletions(-) diff --git a/repair/dir2.c b/repair/dir2.c index c6d618d..644c214 100644 --- a/repair/dir2.c +++ b/repair/dir2.c @@ -198,6 +198,13 @@ _("bad dir magic number 0x%x in inode %" PRIu64 " bno = %u\n"), da_cursor->ino, bno); goto error_out; } + /* corrupt node; rebuild the dir. */ + if (bp->b_error == EFSBADCRC || bp->b_error == EFSCORRUPTED) { + do_warn( +_("corrupt tree block %u for directory inode %" PRIu64 "\n"), + bno, da_cursor->ino); + goto error_out; + } btree = xfs_da3_node_tree_p(node); if (nodehdr.count > mp->m_dir_node_ents) { libxfs_putbuf(bp); diff --git a/repair/phase6.c b/repair/phase6.c index c09b394..efefb2b 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -1981,6 +1981,41 @@ longform_dir2_check_leaf( libxfs_putbuf(bp); return 1; } + + /* check v5 metadata */ + if (leafhdr.magic == XFS_DIR3_LEAF1_MAGIC) { + struct xfs_dir3_leaf_hdr *block3 = bp->b_addr; + + /* verify owner */ + if (be64_to_cpu(block3->info.owner) != ip->i_ino) { + do_warn( + _("expected owner inode %" PRIu64 ", got %llu, directory block %" PRIu64 "\n"), + ip->i_ino, be64_to_cpu(block3->info.owner), + bp->b_bn); + libxfs_putbuf(bp); + return 1; + } + /* verify block number */ + if (be64_to_cpu(block3->info.blkno) != bp->b_bn) { + do_warn( + _("expected block %" PRIu64 ", got %llu, directory inode %" PRIu64 "\n"), + bp->b_bn, + be64_to_cpu(block3->info.blkno), + ip->i_ino); + libxfs_putbuf(bp); + return 1; + } + /* verify uuid */ + if (platform_uuid_compare(&block3->info.uuid, + &mp->m_sb.sb_uuid) != 0) { + do_warn( + _("wrong FS UUID, directory inode %" PRIu64 " block %" PRIu64 "\n"), + ip->i_ino, bp->b_bn); + libxfs_putbuf(bp); + return 1; + } + } + seeval = dir_hash_see_all(hashtab, ents, leafhdr.count, leafhdr.stale); if (dir_hash_check(hashtab, ip, seeval)) { libxfs_putbuf(bp); @@ -2055,12 +2090,9 @@ longform_dir2_check_node( xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); ents = xfs_dir3_leaf_ents_p(leaf); if (!(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC || - leafhdr.magic == XFS_DIR3_LEAFN_MAGIC)) { - if (leafhdr.magic == XFS_DA_NODE_MAGIC || - leafhdr.magic == XFS_DA3_NODE_MAGIC) { - libxfs_putbuf(bp); - continue; - } + leafhdr.magic == XFS_DIR3_LEAFN_MAGIC || + leafhdr.magic == XFS_DA_NODE_MAGIC || + leafhdr.magic == XFS_DA3_NODE_MAGIC)) { do_warn( _("unknown magic number %#x for block %u in directory inode %" PRIu64 "\n"), leafhdr.magic, da_bno, ip->i_ino); @@ -2068,6 +2100,48 @@ longform_dir2_check_node( return 1; } + /* check v5 metadata */ + if (leafhdr.magic == XFS_DIR3_LEAFN_MAGIC || + leafhdr.magic == XFS_DA3_NODE_MAGIC) { + struct xfs_da3_blkinfo *info = bp->b_addr; + + /* verify owner */ + if (be64_to_cpu(info->owner) != ip->i_ino) { + do_warn( + _("expected owner inode %" PRIu64 ", got %llu, directory block %" PRIu64 "\n"), + ip->i_ino, be64_to_cpu(info->owner), + bp->b_bn); + libxfs_putbuf(bp); + return 1; + } + /* verify block number */ + if (be64_to_cpu(info->blkno) != bp->b_bn) { + do_warn( + _("expected block %" PRIu64 ", got %llu, directory inode %" PRIu64 "\n"), + bp->b_bn, + be64_to_cpu(info->blkno), + ip->i_ino); + libxfs_putbuf(bp); + return 1; + } + /* verify uuid */ + if (platform_uuid_compare(&info->uuid, + &mp->m_sb.sb_uuid) != 0) { + do_warn( + _("wrong FS UUID, directory inode %" PRIu64 " block %" PRIu64 "\n"), + ip->i_ino, bp->b_bn); + libxfs_putbuf(bp); + return 1; + } + } + + /* ignore nodes */ + if (leafhdr.magic == XFS_DA_NODE_MAGIC || + leafhdr.magic == XFS_DA3_NODE_MAGIC) { + libxfs_putbuf(bp); + continue; + } + /* * If there's a validator error, we need to ensure that we got * the right ops on the buffer for when we write it back out. @@ -2121,6 +2195,40 @@ longform_dir2_check_node( libxfs_putbuf(bp); return 1; } + + /* check v5 metadata */ + if (freehdr.magic == XFS_DIR3_FREE_MAGIC) { + struct xfs_dir3_free_hdr *h = bp->b_addr; + + /* verify owner */ + if (be64_to_cpu(h->hdr.owner) != ip->i_ino) { + do_warn( + _("expected owner inode %" PRIu64 ", got %llu, directory block %" PRIu64 "\n"), + ip->i_ino, be64_to_cpu(h->hdr.owner), + bp->b_bn); + libxfs_putbuf(bp); + return 1; + } + /* verify block number */ + if (be64_to_cpu(h->hdr.blkno) != bp->b_bn) { + do_warn( + _("expected block %" PRIu64 ", got %llu, directory inode %" PRIu64 "\n"), + bp->b_bn, + be64_to_cpu(h->hdr.blkno), + ip->i_ino); + libxfs_putbuf(bp); + return 1; + } + /* verify uuid */ + if (platform_uuid_compare(&h->hdr.uuid, + &mp->m_sb.sb_uuid) != 0) { + do_warn( + _("wrong FS UUID, directory inode %" PRIu64 " block %" PRIu64 "\n"), + ip->i_ino, bp->b_bn); + libxfs_putbuf(bp); + return 1; + } + } for (i = used = 0; i < freehdr.nvalid; i++) { if (i + freehdr.firstdb >= freetab->nents || freetab->ents[i + freehdr.firstdb].v != @@ -2212,6 +2320,7 @@ longform_dir2_entry_check(xfs_mount_t *mp, da_bno = (xfs_dablk_t)next_da_bno) { const struct xfs_buf_ops *ops; int error; + struct xfs_dir2_data_hdr *d; next_da_bno = da_bno + mp->m_dirblkfsbs - 1; if (bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK)) { @@ -2260,6 +2369,44 @@ longform_dir2_entry_check(xfs_mount_t *mp, } continue; } + + /* check v5 metadata */ + d = bplist[db]->b_addr; + if (be32_to_cpu(d->magic) == XFS_DIR3_BLOCK_MAGIC || + be32_to_cpu(d->magic) == XFS_DIR3_DATA_MAGIC) { + struct xfs_buf *bp = bplist[db]; + struct xfs_dir3_data_hdr *block3 = bp->b_addr; + + /* verify owner */ + if (be64_to_cpu(block3->hdr.owner) != ino) { + do_warn( + _("expected owner inode %" PRIu64 ", got %llu, directory block %" PRIu64 "\n"), + ino, be64_to_cpu(block3->hdr.owner), + bp->b_bn); + fixit++; + continue; + } + /* verify block number */ + if (be64_to_cpu(block3->hdr.blkno) != bp->b_bn) { + do_warn( + _("expected block %" PRIu64 ", got %llu, directory inode %" PRIu64 "\n"), + bp->b_bn, + be64_to_cpu(block3->hdr.blkno), + ino); + fixit++; + continue; + } + /* verify uuid */ + if (platform_uuid_compare(&block3->hdr.uuid, + &mp->m_sb.sb_uuid) != 0) { + do_warn( + _("wrong FS UUID, directory inode %" PRIu64 " block %" PRIu64 "\n"), + ino, bp->b_bn); + fixit++; + continue; + } + } + longform_dir2_entry_check_data(mp, ip, num_illegal, need_dot, irec, ino_offset, &bplist[db], hashtab, &freetab, da_bno, isblock); diff --git a/repair/scan.c b/repair/scan.c index 12aa782..79fbf83 100644 --- a/repair/scan.c +++ b/repair/scan.c @@ -227,6 +227,23 @@ _("expected owner inode %" PRIu64 ", got %llu, bmbt block %" PRIu64 "\n"), ino, be64_to_cpu(block->bb_u.l.bb_owner), bno); return(1); } + /* verify block number */ + if (be64_to_cpu(block->bb_u.l.bb_blkno) != + XFS_FSB_TO_DADDR(mp, bno)) { + do_warn( +_("expected block %" PRIu64 ", got %llu, bmbt block %" PRIu64 "\n"), + XFS_FSB_TO_DADDR(mp, bno), + be64_to_cpu(block->bb_u.l.bb_blkno), bno); + return(1); + } + /* verify uuid */ + if (platform_uuid_compare(&block->bb_u.l.bb_uuid, + &mp->m_sb.sb_uuid) != 0) { + do_warn( +_("wrong FS UUID, bmbt block %" PRIu64 "\n"), + bno); + return(1); + } } if (check_dups == 0) { _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH 2/5] xfs_repair: better checking of v5 metadata fields 2015-05-26 22:51 ` [PATCH 2/5] xfs_repair: better checking of v5 metadata fields Darrick J. Wong @ 2015-05-26 23:58 ` Dave Chinner 2015-05-27 5:44 ` [PATCH v2 " Darrick J. Wong 1 sibling, 0 replies; 25+ messages in thread From: Dave Chinner @ 2015-05-26 23:58 UTC (permalink / raw) To: Darrick J. Wong; +Cc: xfs On Tue, May 26, 2015 at 03:51:39PM -0700, Darrick J. Wong wrote: > Check the UUID, owner, and block number fields during repair, looking for > blocks that fail either the checksum or the data structure verifiers. For > directories we can simply rebuild corrupt/broken index data, though for > anything else we have to toss out the broken object. helper function needed here for owner/uuid/blkno info checks. i.e the header info being checked is a common structure (xfs_da3_blkinfo) embedded into the different dir header structures, so no need to repeat the same checks just with different dir3 header structures.... Cheers, Dave. -- Dave Chinner david@fromorbit.com _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v2 2/5] xfs_repair: better checking of v5 metadata fields 2015-05-26 22:51 ` [PATCH 2/5] xfs_repair: better checking of v5 metadata fields Darrick J. Wong 2015-05-26 23:58 ` Dave Chinner @ 2015-05-27 5:44 ` Darrick J. Wong 2015-05-31 21:32 ` Dave Chinner 1 sibling, 1 reply; 25+ messages in thread From: Darrick J. Wong @ 2015-05-27 5:44 UTC (permalink / raw) To: david; +Cc: xfs Check the UUID, owner, and block number fields during repair, looking for blocks that fail either the checksum or the data structure verifiers. For directories we can simply rebuild corrupt/broken index data, though for anything else we have to toss out the broken object. v2: Refactor the directory block header checks into a single function. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> --- repair/dir2.c | 7 +++ repair/phase6.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- repair/scan.c | 19 ++++++++- 3 files changed, 140 insertions(+), 7 deletions(-) diff --git a/repair/dir2.c b/repair/dir2.c index c6d618d..644c214 100644 --- a/repair/dir2.c +++ b/repair/dir2.c @@ -198,6 +198,13 @@ _("bad dir magic number 0x%x in inode %" PRIu64 " bno = %u\n"), da_cursor->ino, bno); goto error_out; } + /* corrupt node; rebuild the dir. */ + if (bp->b_error == EFSBADCRC || bp->b_error == EFSCORRUPTED) { + do_warn( +_("corrupt tree block %u for directory inode %" PRIu64 "\n"), + bno, da_cursor->ino); + goto error_out; + } btree = xfs_da3_node_tree_p(node); if (nodehdr.count > mp->m_dir_node_ents) { libxfs_putbuf(bp); diff --git a/repair/phase6.c b/repair/phase6.c index c09b394..7dd868c 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -1925,6 +1925,69 @@ _("entry \"%s\" in dir inode %" PRIu64 " inconsistent with .. value (%" PRIu64 " freetab->ents[db].s = 0; } +/* check v5 metadata */ +static int +__check_dir3_header( + xfs_mount_t *mp, + xfs_buf_t *bp, + xfs_ino_t ino, + __be64 owner, + __be64 blkno, + uuid_t *uuid) +{ + + /* verify owner */ + if (be64_to_cpu(owner) != ino) { + do_warn( +_("expected owner inode %" PRIu64 ", got %llu, directory block %" PRIu64 "\n"), + ino, be64_to_cpu(owner), bp->b_bn); + return 1; + } + /* verify block number */ + if (be64_to_cpu(blkno) != bp->b_bn) { + do_warn( +_("expected block %" PRIu64 ", got %llu, directory inode %" PRIu64 "\n"), + bp->b_bn, be64_to_cpu(blkno), ino); + return 1; + } + /* verify uuid */ + if (platform_uuid_compare(uuid, + &mp->m_sb.sb_uuid) != 0) { + do_warn( +_("wrong FS UUID, directory inode %" PRIu64 " block %" PRIu64 "\n"), + ino, bp->b_bn); + return 1; + } + + return 0; +} + +static int +check_da3_header( + xfs_mount_t *mp, + xfs_buf_t *bp, + xfs_ino_t ino) +{ + struct xfs_da3_blkinfo *info; + + info = bp->b_addr; + return __check_dir3_header(mp, bp, ino, info->owner, info->blkno, + &info->uuid); +} + +static int +check_dir3_header( + xfs_mount_t *mp, + xfs_buf_t *bp, + xfs_ino_t ino) +{ + struct xfs_dir3_blk_hdr *info; + + info = bp->b_addr; + return __check_dir3_header(mp, bp, ino, info->owner, info->blkno, + &info->uuid); +} + /* * Check contents of leaf-form block. */ @@ -1981,6 +2044,15 @@ longform_dir2_check_leaf( libxfs_putbuf(bp); return 1; } + + if (leafhdr.magic == XFS_DIR3_LEAF1_MAGIC) { + error = check_da3_header(mp, bp, ip->i_ino); + if (error) { + libxfs_putbuf(bp); + return error; + } + } + seeval = dir_hash_see_all(hashtab, ents, leafhdr.count, leafhdr.stale); if (dir_hash_check(hashtab, ip, seeval)) { libxfs_putbuf(bp); @@ -2055,12 +2127,9 @@ longform_dir2_check_node( xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); ents = xfs_dir3_leaf_ents_p(leaf); if (!(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC || - leafhdr.magic == XFS_DIR3_LEAFN_MAGIC)) { - if (leafhdr.magic == XFS_DA_NODE_MAGIC || - leafhdr.magic == XFS_DA3_NODE_MAGIC) { - libxfs_putbuf(bp); - continue; - } + leafhdr.magic == XFS_DIR3_LEAFN_MAGIC || + leafhdr.magic == XFS_DA_NODE_MAGIC || + leafhdr.magic == XFS_DA3_NODE_MAGIC)) { do_warn( _("unknown magic number %#x for block %u in directory inode %" PRIu64 "\n"), leafhdr.magic, da_bno, ip->i_ino); @@ -2068,6 +2137,23 @@ longform_dir2_check_node( return 1; } + /* check v5 metadata */ + if (leafhdr.magic == XFS_DIR3_LEAFN_MAGIC || + leafhdr.magic == XFS_DA3_NODE_MAGIC) { + error = check_da3_header(mp, bp, ip->i_ino); + if (error) { + libxfs_putbuf(bp); + return error; + } + } + + /* ignore nodes */ + if (leafhdr.magic == XFS_DA_NODE_MAGIC || + leafhdr.magic == XFS_DA3_NODE_MAGIC) { + libxfs_putbuf(bp); + continue; + } + /* * If there's a validator error, we need to ensure that we got * the right ops on the buffer for when we write it back out. @@ -2121,6 +2207,14 @@ longform_dir2_check_node( libxfs_putbuf(bp); return 1; } + + if (freehdr.magic == XFS_DIR3_FREE_MAGIC) { + error = check_dir3_header(mp, bp, ip->i_ino); + if (error) { + libxfs_putbuf(bp); + return error; + } + } for (i = used = 0; i < freehdr.nvalid; i++) { if (i + freehdr.firstdb >= freetab->nents || freetab->ents[i + freehdr.firstdb].v != @@ -2212,6 +2306,7 @@ longform_dir2_entry_check(xfs_mount_t *mp, da_bno = (xfs_dablk_t)next_da_bno) { const struct xfs_buf_ops *ops; int error; + struct xfs_dir2_data_hdr *d; next_da_bno = da_bno + mp->m_dirblkfsbs - 1; if (bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK)) { @@ -2260,6 +2355,20 @@ longform_dir2_entry_check(xfs_mount_t *mp, } continue; } + + /* check v5 metadata */ + d = bplist[db]->b_addr; + if (be32_to_cpu(d->magic) == XFS_DIR3_BLOCK_MAGIC || + be32_to_cpu(d->magic) == XFS_DIR3_DATA_MAGIC) { + struct xfs_buf *bp = bplist[db]; + + error = check_dir3_header(mp, bp, ino); + if (error) { + fixit++; + continue; + } + } + longform_dir2_entry_check_data(mp, ip, num_illegal, need_dot, irec, ino_offset, &bplist[db], hashtab, &freetab, da_bno, isblock); diff --git a/repair/scan.c b/repair/scan.c index 12aa782..6508a47 100644 --- a/repair/scan.c +++ b/repair/scan.c @@ -225,7 +225,24 @@ _("expected level %d got %d in inode %" PRIu64 ", (%s fork) bmbt block %" PRIu64 do_warn( _("expected owner inode %" PRIu64 ", got %llu, bmbt block %" PRIu64 "\n"), ino, be64_to_cpu(block->bb_u.l.bb_owner), bno); - return(1); + return 1; + } + /* verify block number */ + if (be64_to_cpu(block->bb_u.l.bb_blkno) != + XFS_FSB_TO_DADDR(mp, bno)) { + do_warn( +_("expected block %" PRIu64 ", got %llu, bmbt block %" PRIu64 "\n"), + XFS_FSB_TO_DADDR(mp, bno), + be64_to_cpu(block->bb_u.l.bb_blkno), bno); + return 1; + } + /* verify uuid */ + if (platform_uuid_compare(&block->bb_u.l.bb_uuid, + &mp->m_sb.sb_uuid) != 0) { + do_warn( +_("wrong FS UUID, bmbt block %" PRIu64 "\n"), + bno); + return 1; } } _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH v2 2/5] xfs_repair: better checking of v5 metadata fields 2015-05-27 5:44 ` [PATCH v2 " Darrick J. Wong @ 2015-05-31 21:32 ` Dave Chinner 0 siblings, 0 replies; 25+ messages in thread From: Dave Chinner @ 2015-05-31 21:32 UTC (permalink / raw) To: Darrick J. Wong; +Cc: xfs On Tue, May 26, 2015 at 10:44:50PM -0700, Darrick J. Wong wrote: > Check the UUID, owner, and block number fields during repair, looking for > blocks that fail either the checksum or the data structure verifiers. For > directories we can simply rebuild corrupt/broken index data, though for > anything else we have to toss out the broken object. > > v2: Refactor the directory block header checks into a single function. > > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> FYI, just a couple of quick whitespacy things, which I've fixed on commit. > diff --git a/repair/phase6.c b/repair/phase6.c > index c09b394..7dd868c 100644 > --- a/repair/phase6.c > +++ b/repair/phase6.c > @@ -1925,6 +1925,69 @@ _("entry \"%s\" in dir inode %" PRIu64 " inconsistent with .. value (%" PRIu64 " > freetab->ents[db].s = 0; > } > > +/* check v5 metadata */ > +static int > +__check_dir3_header( > + xfs_mount_t *mp, > + xfs_buf_t *bp, Don't use the typedef versions - struct xfs_mount. No need for quite so much whitespace, either - this sort of thing is fine if there's no need for larger alignment steps: struct xfs_mount *mp, struct xfs_buf *bp, .... > + /* verify uuid */ > + if (platform_uuid_compare(uuid, > + &mp->m_sb.sb_uuid) != 0) { No need to split that line. > +static int > +check_da3_header( > + xfs_mount_t *mp, > + xfs_buf_t *bp, > + xfs_ino_t ino) > +{ > + struct xfs_da3_blkinfo *info; > + > + info = bp->b_addr; struct xfs_da3_blkinfo *info = bp->b_addr; Cheers, Dave. -- Dave Chinner david@fromorbit.com _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 3/5] xfs_repair: ensure .. is set to a sane ino value when rebuilding dir 2015-05-26 22:51 [PATCH 0/5] xfsprogs May 2015 patchbomb Darrick J. Wong 2015-05-26 22:51 ` [PATCH 1/5] xfs_repair: refuse to run if we don't recognize version or feature flags Darrick J. Wong 2015-05-26 22:51 ` [PATCH 2/5] xfs_repair: better checking of v5 metadata fields Darrick J. Wong @ 2015-05-26 22:51 ` Darrick J. Wong 2015-05-26 22:51 ` [PATCH 4/5] xfs_db: enable blockget for v5 filesystems Darrick J. Wong 2015-05-26 22:51 ` [PATCH 5/5] xfs_db: enable blocktrash for checksummed filesystems Darrick J. Wong 4 siblings, 0 replies; 25+ messages in thread From: Darrick J. Wong @ 2015-05-26 22:51 UTC (permalink / raw) To: david, darrick.wong; +Cc: xfs When we're rebuilding a directory, ensure that we reinitialize the directory with a sane parent ('..') inode value. If we don't, the error return from xfs_dir_init() is ignored, and the rebuild process becomes confused and leaves the directory corrupt. If repair later discovers that the rebuilt directory is an orphan, it'll try to attach it to lost+found and abort on the corrupted directory. Also fix ignoring the return value of xfs_dir_init(). Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> --- include/xfs_dir2.h | 2 ++ libxfs/xfs_dir2_priv.h | 1 - repair/phase6.c | 9 +++++++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/include/xfs_dir2.h b/include/xfs_dir2.h index 3900130..2d41c5f 100644 --- a/include/xfs_dir2.h +++ b/include/xfs_dir2.h @@ -100,6 +100,8 @@ extern void xfs_dir2_data_use_free(struct xfs_trans *tp, struct xfs_buf *bp, extern struct xfs_dir2_data_free *xfs_dir2_data_freefind( struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_data_unused *dup); +extern int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino); + extern const struct xfs_buf_ops xfs_dir3_block_buf_ops; extern const struct xfs_buf_ops xfs_dir3_leafn_buf_ops; extern const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops; diff --git a/libxfs/xfs_dir2_priv.h b/libxfs/xfs_dir2_priv.h index 1bad84c..926715f 100644 --- a/libxfs/xfs_dir2_priv.h +++ b/libxfs/xfs_dir2_priv.h @@ -21,7 +21,6 @@ struct dir_context; /* xfs_dir2.c */ -extern int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino); extern int xfs_dir2_grow_inode(struct xfs_da_args *args, int space, xfs_dir2_db_t *dbp); extern int xfs_dir_cilookup_result(struct xfs_da_args *args, diff --git a/repair/phase6.c b/repair/phase6.c index efefb2b..145e497 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -1321,7 +1321,8 @@ longform_dir2_rebuild( * for the libxfs_dir_init() call). */ pip.i_ino = get_inode_parent(irec, ino_offset); - if (pip.i_ino == NULLFSINO) + if (pip.i_ino == NULLFSINO || + xfs_dir_ino_validate(mp, pip.i_ino)) pip.i_ino = mp->m_sb.sb_rootino; xfs_bmap_init(&flist, &firstblock); @@ -1348,7 +1349,11 @@ longform_dir2_rebuild( ASSERT(done); - libxfs_dir_init(tp, ip, &pip); + error = libxfs_dir_init(tp, ip, &pip); + if (error) { + do_warn(_("xfs_dir_init failed -- error - %d\n"), error); + goto out_bmap_cancel; + } error = libxfs_bmap_finish(&tp, &flist, &committed); _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 4/5] xfs_db: enable blockget for v5 filesystems 2015-05-26 22:51 [PATCH 0/5] xfsprogs May 2015 patchbomb Darrick J. Wong ` (2 preceding siblings ...) 2015-05-26 22:51 ` [PATCH 3/5] xfs_repair: ensure .. is set to a sane ino value when rebuilding dir Darrick J. Wong @ 2015-05-26 22:51 ` Darrick J. Wong 2015-05-26 23:07 ` Eric Sandeen 2015-05-26 23:14 ` [PATCH v2 " Darrick J. Wong 2015-05-26 22:51 ` [PATCH 5/5] xfs_db: enable blocktrash for checksummed filesystems Darrick J. Wong 4 siblings, 2 replies; 25+ messages in thread From: Darrick J. Wong @ 2015-05-26 22:51 UTC (permalink / raw) To: david, darrick.wong; +Cc: xfs Plumb in the necessary magic number checks and other fixups required to handle v5 filesystems. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> --- db/check.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- db/type.c | 3 + db/type.h | 2 - 3 files changed, 214 insertions(+), 16 deletions(-) diff --git a/db/check.c b/db/check.c index c4c972f..8f8096d 100644 --- a/db/check.c +++ b/db/check.c @@ -44,7 +44,7 @@ typedef enum { DBM_FREE1, DBM_FREE2, DBM_FREELIST, DBM_INODE, DBM_LOG, DBM_MISSING, DBM_QUOTA, DBM_RTBITMAP, DBM_RTDATA, DBM_RTFREE, DBM_RTSUM, DBM_SB, - DBM_SYMLINK, + DBM_SYMLINK, DBM_BTFINO, DBM_NDBM } dbm_t; @@ -170,6 +170,7 @@ static const char *typename[] = { "rtsum", "sb", "symlink", + "btfino", NULL }; static int verbose; @@ -345,6 +346,9 @@ static void scanfunc_cnt(struct xfs_btree_block *block, int level, static void scanfunc_ino(struct xfs_btree_block *block, int level, xfs_agf_t *agf, xfs_agblock_t bno, int isroot); +static void scanfunc_fino(struct xfs_btree_block *block, int level, + xfs_agf_t *agf, xfs_agblock_t bno, + int isroot); static void set_dbmap(xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len, dbm_t type, xfs_agnumber_t c_agno, xfs_agblock_t c_agbno); @@ -799,8 +803,6 @@ blockget_f( * filters out, or we need to actually do the work to make check support * crc enabled filesystems. */ - if (xfs_sb_version_hascrc(&mp->m_sb)) - return 0; if (!init(argc, argv)) { if (serious_error) @@ -2223,7 +2225,9 @@ process_data_dir_v2( data = iocur_top->data; block = iocur_top->data; if (be32_to_cpu(block->magic) != XFS_DIR2_BLOCK_MAGIC && - be32_to_cpu(data->magic) != XFS_DIR2_DATA_MAGIC) { + be32_to_cpu(data->magic) != XFS_DIR2_DATA_MAGIC && + be32_to_cpu(block->magic) != XFS_DIR3_BLOCK_MAGIC && + be32_to_cpu(data->magic) != XFS_DIR3_DATA_MAGIC) { if (!sflag || v) dbprintf(_("bad directory data magic # %#x for dir ino " "%lld block %d\n"), @@ -2234,7 +2238,8 @@ process_data_dir_v2( db = xfs_dir2_da_to_db(mp, dabno); bf = xfs_dir3_data_bestfree_p(data); ptr = (char *)xfs_dir3_data_unused_p(data); - if (be32_to_cpu(block->magic) == XFS_DIR2_BLOCK_MAGIC) { + if (be32_to_cpu(block->magic) == XFS_DIR2_BLOCK_MAGIC || + be32_to_cpu(block->magic) == XFS_DIR3_BLOCK_MAGIC) { btp = xfs_dir2_block_tail_p(mp, block); lep = xfs_dir2_block_leaf_p(btp); endptr = (char *)lep; @@ -2380,7 +2385,8 @@ process_data_dir_v2( (*dot)++; } } - if (be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC) { + if (be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC || + be32_to_cpu(data->magic) == XFS_DIR3_BLOCK_MAGIC) { endptr = (char *)data + mp->m_dirblksize; for (i = stale = 0; lep && i < be32_to_cpu(btp->count); i++) { if ((char *)&lep[i] >= endptr) { @@ -2412,7 +2418,8 @@ process_data_dir_v2( id->ino, dabno); error++; } - if (be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC && + if ((be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC || + be32_to_cpu(data->magic) == XFS_DIR3_BLOCK_MAGIC) && count != be32_to_cpu(btp->count) - be32_to_cpu(btp->stale)) { if (!sflag || v) dbprintf(_("dir %lld block %d bad block tail count %d " @@ -2421,7 +2428,8 @@ process_data_dir_v2( be32_to_cpu(btp->stale)); error++; } - if (be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC && + if ((be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC || + be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC) && stale != be32_to_cpu(btp->stale)) { if (!sflag || v) dbprintf(_("dir %lld block %d bad stale tail count %d\n"), @@ -3007,6 +3015,73 @@ process_leaf_node_dir_v2( } static void +process_leaf_node_dir_v3_free( + inodata_t *id, + int v, + xfs_dablk_t dabno, + freetab_t *freetab) +{ + xfs_dir2_data_off_t ent; + struct xfs_dir3_free *free; + int i; + int maxent; + int used; + + free = iocur_top->data; + maxent = xfs_dir3_free_max_bests(mp); + if (be32_to_cpu(free->hdr.firstdb) != xfs_dir2_da_to_db(mp, + dabno - mp->m_dirfreeblk) * maxent) { + if (!sflag || v) + dbprintf(_("bad free block firstdb %d for dir ino %lld " + "block %d\n"), + be32_to_cpu(free->hdr.firstdb), id->ino, dabno); + error++; + return; + } + if (be32_to_cpu(free->hdr.nvalid) > maxent || + be32_to_cpu(free->hdr.nvalid) < 0 || + be32_to_cpu(free->hdr.nused) > maxent || + be32_to_cpu(free->hdr.nused) < 0 || + be32_to_cpu(free->hdr.nused) > + be32_to_cpu(free->hdr.nvalid)) { + if (!sflag || v) + dbprintf(_("bad free block nvalid/nused %d/%d for dir " + "ino %lld block %d\n"), + be32_to_cpu(free->hdr.nvalid), + be32_to_cpu(free->hdr.nused), id->ino, dabno); + error++; + return; + } + for (used = i = 0; i < be32_to_cpu(free->hdr.nvalid); i++) { + if (freetab->nents <= be32_to_cpu(free->hdr.firstdb) + i) + ent = NULLDATAOFF; + else + ent = freetab->ents[be32_to_cpu(free->hdr.firstdb) + i]; + if (ent != be16_to_cpu(free->bests[i])) { + if (!sflag || v) + dbprintf(_("bad free block ent %d is %d should " + "be %d for dir ino %lld block %d\n"), + i, be16_to_cpu(free->bests[i]), ent, + id->ino, dabno); + error++; + } + if (be16_to_cpu(free->bests[i]) != NULLDATAOFF) + used++; + if (ent != NULLDATAOFF) + freetab->ents[be32_to_cpu(free->hdr.firstdb) + i] = + NULLDATAOFF; + } + if (used != be32_to_cpu(free->hdr.nused)) { + if (!sflag || v) + dbprintf(_("bad free block nused %d should be %d for dir " + "ino %lld block %d\n"), + be32_to_cpu(free->hdr.nused), used, id->ino, + dabno); + error++; + } +} + +static void process_leaf_node_dir_v2_free( inodata_t *id, int v, @@ -3020,7 +3095,8 @@ process_leaf_node_dir_v2_free( int used; free = iocur_top->data; - if (be32_to_cpu(free->hdr.magic) != XFS_DIR2_FREE_MAGIC) { + if (be32_to_cpu(free->hdr.magic) != XFS_DIR2_FREE_MAGIC && + be32_to_cpu(free->hdr.magic) != XFS_DIR3_FREE_MAGIC) { if (!sflag || v) dbprintf(_("bad free block magic # %#x for dir ino %lld " "block %d\n"), @@ -3028,6 +3104,10 @@ process_leaf_node_dir_v2_free( error++; return; } + if (be32_to_cpu(free->hdr.magic) == XFS_DIR3_FREE_MAGIC) { + process_leaf_node_dir_v3_free(id, v, dabno, freetab); + return; + } maxent = xfs_dir3_free_max_bests(mp); if (be32_to_cpu(free->hdr.firstdb) != xfs_dir2_da_to_db(mp, dabno - mp->m_dirfreeblk) * maxent) { @@ -3081,6 +3161,20 @@ process_leaf_node_dir_v2_free( } } +/* + * Get address of the bestcount field in the single-leaf block. + */ +static inline int +xfs_dir3_leaf_ents_count(struct xfs_dir2_leaf *lp) +{ + if (lp->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) || + lp->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) { + struct xfs_dir3_leaf *lp3 = (struct xfs_dir3_leaf *)lp; + return be16_to_cpu(lp3->hdr.count); + } + return be16_to_cpu(lp->hdr.count); +} + static void process_leaf_node_dir_v2_int( inodata_t *id, @@ -3091,6 +3185,7 @@ process_leaf_node_dir_v2_int( int i; __be16 *lbp; xfs_dir2_leaf_t *leaf; + struct xfs_dir3_leaf *leaf3 = NULL; xfs_dir2_leaf_entry_t *lep; xfs_dir2_leaf_tail_t *ltp; xfs_da_intnode_t *node; @@ -3099,7 +3194,15 @@ process_leaf_node_dir_v2_int( leaf = iocur_top->data; switch (be16_to_cpu(leaf->hdr.info.magic)) { + case XFS_DIR3_LEAF1_MAGIC: + case XFS_DIR3_LEAFN_MAGIC: + case XFS_DA3_NODE_MAGIC: + leaf3 = iocur_top->data; + break; + } + switch (be16_to_cpu(leaf->hdr.info.magic)) { case XFS_DIR2_LEAF1_MAGIC: + case XFS_DIR3_LEAF1_MAGIC: if (be32_to_cpu(leaf->hdr.info.forw) || be32_to_cpu(leaf->hdr.info.back)) { if (!sflag || v) @@ -3139,10 +3242,12 @@ process_leaf_node_dir_v2_int( } break; case XFS_DIR2_LEAFN_MAGIC: + case XFS_DIR3_LEAFN_MAGIC: /* if it's at the root location then we can check the * pointers are null XXX */ break; case XFS_DA_NODE_MAGIC: + case XFS_DA3_NODE_MAGIC: node = iocur_top->data; xfs_da3_node_hdr_from_disk(&nodehdr, node); if (nodehdr.level < 1 || nodehdr.level > XFS_DA_NODE_MAXDEPTH) { @@ -3164,7 +3269,7 @@ process_leaf_node_dir_v2_int( return; } lep = xfs_dir3_leaf_ents_p(leaf); - for (i = stale = 0; i < be16_to_cpu(leaf->hdr.count); i++) { + for (i = stale = 0; i < xfs_dir3_leaf_ents_count(leaf); i++) { if (be32_to_cpu(lep[i].address) == XFS_DIR2_NULL_DATAPTR) stale++; else if (dir_hash_see(be32_to_cpu(lep[i].hashval), @@ -3177,7 +3282,14 @@ process_leaf_node_dir_v2_int( error++; } } - if (stale != be16_to_cpu(leaf->hdr.stale)) { + if (leaf3 && stale != be16_to_cpu(leaf3->hdr.stale)) { + if (!sflag || v) + dbprintf(_("dir3 %lld block %d stale mismatch " + "%d/%d\n"), + id->ino, dabno, stale, + be16_to_cpu(leaf3->hdr.stale)); + error++; + } else if (!leaf && stale != be16_to_cpu(leaf->hdr.stale)) { if (!sflag || v) dbprintf(_("dir %lld block %d stale mismatch " "%d/%d\n"), @@ -3764,6 +3876,12 @@ scan_ag( be32_to_cpu(agi->agi_root), be32_to_cpu(agi->agi_level), 1, scanfunc_ino, TYP_INOBT); + if (agi->agi_free_root) { + scan_sbtree(agf, + be32_to_cpu(agi->agi_free_root), + be32_to_cpu(agi->agi_free_level), + 1, scanfunc_fino, TYP_FINOBT); + } if (be32_to_cpu(agf->agf_freeblks) != agffreeblks) { if (!sflag) dbprintf(_("agf_freeblks %u, counted %u in ag %u\n"), @@ -3963,7 +4081,8 @@ scanfunc_bmap( agno = XFS_FSB_TO_AGNO(mp, bno); agbno = XFS_FSB_TO_AGBNO(mp, bno); - if (be32_to_cpu(block->bb_magic) != XFS_BMAP_MAGIC) { + if (be32_to_cpu(block->bb_magic) != XFS_BMAP_MAGIC && + be32_to_cpu(block->bb_magic) != XFS_BMAP_CRC_MAGIC) { if (!sflag || id->ilist || CHECK_BLIST(bno)) dbprintf(_("bad magic # %#x in inode %lld bmbt block " "%u/%u\n"), @@ -4028,7 +4147,8 @@ scanfunc_bno( xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); xfs_agblock_t lastblock; - if (be32_to_cpu(block->bb_magic) != XFS_ABTB_MAGIC) { + if (be32_to_cpu(block->bb_magic) != XFS_ABTB_MAGIC && + be32_to_cpu(block->bb_magic) != XFS_ABTB_CRC_MAGIC) { dbprintf(_("bad magic # %#x in btbno block %u/%u\n"), be32_to_cpu(block->bb_magic), seqno, bno); serious_error++; @@ -4101,7 +4221,8 @@ scanfunc_cnt( xfs_alloc_rec_t *rp; xfs_extlen_t lastcount; - if (be32_to_cpu(block->bb_magic) != XFS_ABTC_MAGIC) { + if (be32_to_cpu(block->bb_magic) != XFS_ABTC_MAGIC && + be32_to_cpu(block->bb_magic) != XFS_ABTC_CRC_MAGIC) { dbprintf(_("bad magic # %#x in btcnt block %u/%u\n"), be32_to_cpu(block->bb_magic), seqno, bno); serious_error++; @@ -4181,7 +4302,8 @@ scanfunc_ino( xfs_inobt_ptr_t *pp; xfs_inobt_rec_t *rp; - if (be32_to_cpu(block->bb_magic) != XFS_IBT_MAGIC) { + if (be32_to_cpu(block->bb_magic) != XFS_IBT_MAGIC && + be32_to_cpu(block->bb_magic) != XFS_IBT_CRC_MAGIC) { dbprintf(_("bad magic # %#x in inobt block %u/%u\n"), be32_to_cpu(block->bb_magic), seqno, bno); serious_error++; @@ -4277,6 +4399,79 @@ scanfunc_ino( } static void +scanfunc_fino( + struct xfs_btree_block *block, + int level, + xfs_agf_t *agf, + xfs_agblock_t bno, + int isroot) +{ + xfs_agino_t agino; + xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); + int i; + int off; + xfs_inobt_ptr_t *pp; + xfs_inobt_rec_t *rp; + + if (be32_to_cpu(block->bb_magic) != XFS_FIBT_MAGIC && + be32_to_cpu(block->bb_magic) != XFS_FIBT_CRC_MAGIC) { + dbprintf(_("bad magic # %#x in finobt block %u/%u\n"), + be32_to_cpu(block->bb_magic), seqno, bno); + serious_error++; + return; + } + if (be16_to_cpu(block->bb_level) != level) { + if (!sflag) + dbprintf(_("expected level %d got %d in finobt block " + "%u/%u\n"), + level, be16_to_cpu(block->bb_level), seqno, bno); + error++; + } + set_dbmap(seqno, bno, 1, DBM_BTFINO, seqno, bno); + if (level == 0) { + if (be16_to_cpu(block->bb_numrecs) > mp->m_inobt_mxr[0] || + (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_inobt_mnr[0])) { + dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in " + "finobt block %u/%u\n"), + be16_to_cpu(block->bb_numrecs), mp->m_inobt_mnr[0], + mp->m_inobt_mxr[0], seqno, bno); + serious_error++; + return; + } + rp = XFS_INOBT_REC_ADDR(mp, block, 1); + for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) { + agino = be32_to_cpu(rp[i].ir_startino); + off = XFS_INO_TO_OFFSET(mp, agino); + if (off == 0) { + if ((sbversion & XFS_SB_VERSION_ALIGNBIT) && + mp->m_sb.sb_inoalignmt && + (XFS_INO_TO_AGBNO(mp, agino) % + mp->m_sb.sb_inoalignmt)) + sbversion &= ~XFS_SB_VERSION_ALIGNBIT; + check_set_dbmap(seqno, XFS_AGINO_TO_AGBNO(mp, agino), + (xfs_extlen_t)MAX(1, + XFS_INODES_PER_CHUNK >> + mp->m_sb.sb_inopblog), + DBM_INODE, DBM_INODE, seqno, bno); + } + } + return; + } + if (be16_to_cpu(block->bb_numrecs) > mp->m_inobt_mxr[1] || + (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_inobt_mnr[1])) { + dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in finobt block " + "%u/%u\n"), + be16_to_cpu(block->bb_numrecs), mp->m_inobt_mnr[1], + mp->m_inobt_mxr[1], seqno, bno); + serious_error++; + return; + } + pp = XFS_INOBT_PTR_ADDR(mp, block, 1, mp->m_inobt_mxr[1]); + for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) + scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_ino, TYP_FINOBT); +} + +static void set_dbmap( xfs_agnumber_t agno, xfs_agblock_t agbno, diff --git a/db/type.c b/db/type.c index b29f2a4..0aa3137 100644 --- a/db/type.c +++ b/db/type.c @@ -70,6 +70,7 @@ static const typ_t __typtab[] = { { 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_NONE, NULL } }; @@ -104,6 +105,8 @@ static const typ_t __typtab_crc[] = { { TYP_SYMLINK, "symlink", handle_struct, symlink_crc_hfld, &xfs_symlink_buf_ops }, { TYP_TEXT, "text", handle_text, NULL, NULL }, + { TYP_FINOBT, "finobt", handle_struct, inobt_crc_hfld, + &xfs_inobt_buf_ops }, { TYP_NONE, NULL } }; diff --git a/db/type.h b/db/type.h index 3bb26f1..e8d8df7 100644 --- a/db/type.h +++ b/db/type.h @@ -27,7 +27,7 @@ typedef enum typnm TYP_BMAPBTD, TYP_BNOBT, TYP_CNTBT, TYP_DATA, TYP_DIR2, TYP_DQBLK, TYP_INOBT, TYP_INODATA, TYP_INODE, TYP_LOG, TYP_RTBITMAP, TYP_RTSUMMARY, TYP_SB, TYP_SYMLINK, - TYP_TEXT, TYP_NONE + TYP_TEXT, TYP_FINOBT, TYP_NONE } typnm_t; #define DB_WRITE 1 _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH 4/5] xfs_db: enable blockget for v5 filesystems 2015-05-26 22:51 ` [PATCH 4/5] xfs_db: enable blockget for v5 filesystems Darrick J. Wong @ 2015-05-26 23:07 ` Eric Sandeen 2015-05-26 23:13 ` Darrick J. Wong 2015-05-26 23:14 ` [PATCH v2 " Darrick J. Wong 1 sibling, 1 reply; 25+ messages in thread From: Eric Sandeen @ 2015-05-26 23:07 UTC (permalink / raw) To: Darrick J. Wong, david; +Cc: xfs On 5/26/15 5:51 PM, Darrick J. Wong wrote: > Plumb in the necessary magic number checks and other fixups required > to handle v5 filesystems. > > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> > @@ -799,8 +803,6 @@ blockget_f( > * filters out, or we need to actually do the work to make check support > * crc enabled filesystems. > */ > - if (xfs_sb_version_hascrc(&mp->m_sb)) > - return 0; Hm, the comment above these lines says: /* * XXX: check does not support CRC enabled filesystems. Return * immediately, silently, with success but without doing anything here * initially so that xfstests can run without modification on metadata * enabled filesystems. * * XXX: ultimately we need to dump an error message here that xfstests * filters out, or we need to actually do the work to make check support * crc enabled filesystems. */ but now we don't. So I guess the comment should go too? I guess check is deprecated now, so the comment is stale anyway... -Eric _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 4/5] xfs_db: enable blockget for v5 filesystems 2015-05-26 23:07 ` Eric Sandeen @ 2015-05-26 23:13 ` Darrick J. Wong 0 siblings, 0 replies; 25+ messages in thread From: Darrick J. Wong @ 2015-05-26 23:13 UTC (permalink / raw) To: Eric Sandeen; +Cc: xfs On Tue, May 26, 2015 at 06:07:32PM -0500, Eric Sandeen wrote: > On 5/26/15 5:51 PM, Darrick J. Wong wrote: > > Plumb in the necessary magic number checks and other fixups required > > to handle v5 filesystems. > > > > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> > > > @@ -799,8 +803,6 @@ blockget_f( > > * filters out, or we need to actually do the work to make check support > > * crc enabled filesystems. > > */ > > - if (xfs_sb_version_hascrc(&mp->m_sb)) > > - return 0; > > Hm, the comment above these lines says: > > /* > * XXX: check does not support CRC enabled filesystems. Return > * immediately, silently, with success but without doing anything here > * initially so that xfstests can run without modification on metadata > * enabled filesystems. > * > * XXX: ultimately we need to dump an error message here that xfstests > * filters out, or we need to actually do the work to make check support > * crc enabled filesystems. > */ > > but now we don't. So I guess the comment should go too? > > I guess check is deprecated now, so the comment is stale anyway... Doh. Forgot to remove that. Will resend. --D > > -Eric > _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v2 4/5] xfs_db: enable blockget for v5 filesystems 2015-05-26 22:51 ` [PATCH 4/5] xfs_db: enable blockget for v5 filesystems Darrick J. Wong 2015-05-26 23:07 ` Eric Sandeen @ 2015-05-26 23:14 ` Darrick J. Wong 1 sibling, 0 replies; 25+ messages in thread From: Darrick J. Wong @ 2015-05-26 23:14 UTC (permalink / raw) To: david; +Cc: sandeen, xfs Plumb in the necessary magic number checks and other fixups required to handle v5 filesystems. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> --- db/check.c | 236 +++++++++++++++++++++++++++++++++++++++++++++++++++++------- db/type.c | 3 + db/type.h | 2 - 3 files changed, 214 insertions(+), 27 deletions(-) diff --git a/db/check.c b/db/check.c index c4c972f..48eeaa8 100644 --- a/db/check.c +++ b/db/check.c @@ -44,7 +44,7 @@ typedef enum { DBM_FREE1, DBM_FREE2, DBM_FREELIST, DBM_INODE, DBM_LOG, DBM_MISSING, DBM_QUOTA, DBM_RTBITMAP, DBM_RTDATA, DBM_RTFREE, DBM_RTSUM, DBM_SB, - DBM_SYMLINK, + DBM_SYMLINK, DBM_BTFINO, DBM_NDBM } dbm_t; @@ -170,6 +170,7 @@ static const char *typename[] = { "rtsum", "sb", "symlink", + "btfino", NULL }; static int verbose; @@ -345,6 +346,9 @@ static void scanfunc_cnt(struct xfs_btree_block *block, int level, static void scanfunc_ino(struct xfs_btree_block *block, int level, xfs_agf_t *agf, xfs_agblock_t bno, int isroot); +static void scanfunc_fino(struct xfs_btree_block *block, int level, + xfs_agf_t *agf, xfs_agblock_t bno, + int isroot); static void set_dbmap(xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len, dbm_t type, xfs_agnumber_t c_agno, xfs_agblock_t c_agbno); @@ -789,19 +793,6 @@ blockget_f( return 0; } - /* - * XXX: check does not support CRC enabled filesystems. Return - * immediately, silently, with success but without doing anything here - * initially so that xfstests can run without modification on metadata - * enabled filesystems. - * - * XXX: ultimately we need to dump an error message here that xfstests - * filters out, or we need to actually do the work to make check support - * crc enabled filesystems. - */ - if (xfs_sb_version_hascrc(&mp->m_sb)) - return 0; - if (!init(argc, argv)) { if (serious_error) exitcode = 3; @@ -2223,7 +2214,9 @@ process_data_dir_v2( data = iocur_top->data; block = iocur_top->data; if (be32_to_cpu(block->magic) != XFS_DIR2_BLOCK_MAGIC && - be32_to_cpu(data->magic) != XFS_DIR2_DATA_MAGIC) { + be32_to_cpu(data->magic) != XFS_DIR2_DATA_MAGIC && + be32_to_cpu(block->magic) != XFS_DIR3_BLOCK_MAGIC && + be32_to_cpu(data->magic) != XFS_DIR3_DATA_MAGIC) { if (!sflag || v) dbprintf(_("bad directory data magic # %#x for dir ino " "%lld block %d\n"), @@ -2234,7 +2227,8 @@ process_data_dir_v2( db = xfs_dir2_da_to_db(mp, dabno); bf = xfs_dir3_data_bestfree_p(data); ptr = (char *)xfs_dir3_data_unused_p(data); - if (be32_to_cpu(block->magic) == XFS_DIR2_BLOCK_MAGIC) { + if (be32_to_cpu(block->magic) == XFS_DIR2_BLOCK_MAGIC || + be32_to_cpu(block->magic) == XFS_DIR3_BLOCK_MAGIC) { btp = xfs_dir2_block_tail_p(mp, block); lep = xfs_dir2_block_leaf_p(btp); endptr = (char *)lep; @@ -2380,7 +2374,8 @@ process_data_dir_v2( (*dot)++; } } - if (be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC) { + if (be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC || + be32_to_cpu(data->magic) == XFS_DIR3_BLOCK_MAGIC) { endptr = (char *)data + mp->m_dirblksize; for (i = stale = 0; lep && i < be32_to_cpu(btp->count); i++) { if ((char *)&lep[i] >= endptr) { @@ -2412,7 +2407,8 @@ process_data_dir_v2( id->ino, dabno); error++; } - if (be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC && + if ((be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC || + be32_to_cpu(data->magic) == XFS_DIR3_BLOCK_MAGIC) && count != be32_to_cpu(btp->count) - be32_to_cpu(btp->stale)) { if (!sflag || v) dbprintf(_("dir %lld block %d bad block tail count %d " @@ -2421,7 +2417,8 @@ process_data_dir_v2( be32_to_cpu(btp->stale)); error++; } - if (be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC && + if ((be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC || + be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC) && stale != be32_to_cpu(btp->stale)) { if (!sflag || v) dbprintf(_("dir %lld block %d bad stale tail count %d\n"), @@ -3007,6 +3004,73 @@ process_leaf_node_dir_v2( } static void +process_leaf_node_dir_v3_free( + inodata_t *id, + int v, + xfs_dablk_t dabno, + freetab_t *freetab) +{ + xfs_dir2_data_off_t ent; + struct xfs_dir3_free *free; + int i; + int maxent; + int used; + + free = iocur_top->data; + maxent = xfs_dir3_free_max_bests(mp); + if (be32_to_cpu(free->hdr.firstdb) != xfs_dir2_da_to_db(mp, + dabno - mp->m_dirfreeblk) * maxent) { + if (!sflag || v) + dbprintf(_("bad free block firstdb %d for dir ino %lld " + "block %d\n"), + be32_to_cpu(free->hdr.firstdb), id->ino, dabno); + error++; + return; + } + if (be32_to_cpu(free->hdr.nvalid) > maxent || + be32_to_cpu(free->hdr.nvalid) < 0 || + be32_to_cpu(free->hdr.nused) > maxent || + be32_to_cpu(free->hdr.nused) < 0 || + be32_to_cpu(free->hdr.nused) > + be32_to_cpu(free->hdr.nvalid)) { + if (!sflag || v) + dbprintf(_("bad free block nvalid/nused %d/%d for dir " + "ino %lld block %d\n"), + be32_to_cpu(free->hdr.nvalid), + be32_to_cpu(free->hdr.nused), id->ino, dabno); + error++; + return; + } + for (used = i = 0; i < be32_to_cpu(free->hdr.nvalid); i++) { + if (freetab->nents <= be32_to_cpu(free->hdr.firstdb) + i) + ent = NULLDATAOFF; + else + ent = freetab->ents[be32_to_cpu(free->hdr.firstdb) + i]; + if (ent != be16_to_cpu(free->bests[i])) { + if (!sflag || v) + dbprintf(_("bad free block ent %d is %d should " + "be %d for dir ino %lld block %d\n"), + i, be16_to_cpu(free->bests[i]), ent, + id->ino, dabno); + error++; + } + if (be16_to_cpu(free->bests[i]) != NULLDATAOFF) + used++; + if (ent != NULLDATAOFF) + freetab->ents[be32_to_cpu(free->hdr.firstdb) + i] = + NULLDATAOFF; + } + if (used != be32_to_cpu(free->hdr.nused)) { + if (!sflag || v) + dbprintf(_("bad free block nused %d should be %d for dir " + "ino %lld block %d\n"), + be32_to_cpu(free->hdr.nused), used, id->ino, + dabno); + error++; + } +} + +static void process_leaf_node_dir_v2_free( inodata_t *id, int v, @@ -3020,7 +3084,8 @@ process_leaf_node_dir_v2_free( int used; free = iocur_top->data; - if (be32_to_cpu(free->hdr.magic) != XFS_DIR2_FREE_MAGIC) { + if (be32_to_cpu(free->hdr.magic) != XFS_DIR2_FREE_MAGIC && + be32_to_cpu(free->hdr.magic) != XFS_DIR3_FREE_MAGIC) { if (!sflag || v) dbprintf(_("bad free block magic # %#x for dir ino %lld " "block %d\n"), @@ -3028,6 +3093,10 @@ process_leaf_node_dir_v2_free( error++; return; } + if (be32_to_cpu(free->hdr.magic) == XFS_DIR3_FREE_MAGIC) { + process_leaf_node_dir_v3_free(id, v, dabno, freetab); + return; + } maxent = xfs_dir3_free_max_bests(mp); if (be32_to_cpu(free->hdr.firstdb) != xfs_dir2_da_to_db(mp, dabno - mp->m_dirfreeblk) * maxent) { @@ -3081,6 +3150,20 @@ process_leaf_node_dir_v2_free( } } +/* + * Get address of the bestcount field in the single-leaf block. + */ +static inline int +xfs_dir3_leaf_ents_count(struct xfs_dir2_leaf *lp) +{ + if (lp->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) || + lp->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) { + struct xfs_dir3_leaf *lp3 = (struct xfs_dir3_leaf *)lp; + return be16_to_cpu(lp3->hdr.count); + } + return be16_to_cpu(lp->hdr.count); +} + static void process_leaf_node_dir_v2_int( inodata_t *id, @@ -3091,6 +3174,7 @@ process_leaf_node_dir_v2_int( int i; __be16 *lbp; xfs_dir2_leaf_t *leaf; + struct xfs_dir3_leaf *leaf3 = NULL; xfs_dir2_leaf_entry_t *lep; xfs_dir2_leaf_tail_t *ltp; xfs_da_intnode_t *node; @@ -3099,7 +3183,15 @@ process_leaf_node_dir_v2_int( leaf = iocur_top->data; switch (be16_to_cpu(leaf->hdr.info.magic)) { + case XFS_DIR3_LEAF1_MAGIC: + case XFS_DIR3_LEAFN_MAGIC: + case XFS_DA3_NODE_MAGIC: + leaf3 = iocur_top->data; + break; + } + switch (be16_to_cpu(leaf->hdr.info.magic)) { case XFS_DIR2_LEAF1_MAGIC: + case XFS_DIR3_LEAF1_MAGIC: if (be32_to_cpu(leaf->hdr.info.forw) || be32_to_cpu(leaf->hdr.info.back)) { if (!sflag || v) @@ -3139,10 +3231,12 @@ process_leaf_node_dir_v2_int( } break; case XFS_DIR2_LEAFN_MAGIC: + case XFS_DIR3_LEAFN_MAGIC: /* if it's at the root location then we can check the * pointers are null XXX */ break; case XFS_DA_NODE_MAGIC: + case XFS_DA3_NODE_MAGIC: node = iocur_top->data; xfs_da3_node_hdr_from_disk(&nodehdr, node); if (nodehdr.level < 1 || nodehdr.level > XFS_DA_NODE_MAXDEPTH) { @@ -3164,7 +3258,7 @@ process_leaf_node_dir_v2_int( return; } lep = xfs_dir3_leaf_ents_p(leaf); - for (i = stale = 0; i < be16_to_cpu(leaf->hdr.count); i++) { + for (i = stale = 0; i < xfs_dir3_leaf_ents_count(leaf); i++) { if (be32_to_cpu(lep[i].address) == XFS_DIR2_NULL_DATAPTR) stale++; else if (dir_hash_see(be32_to_cpu(lep[i].hashval), @@ -3177,7 +3271,14 @@ process_leaf_node_dir_v2_int( error++; } } - if (stale != be16_to_cpu(leaf->hdr.stale)) { + if (leaf3 && stale != be16_to_cpu(leaf3->hdr.stale)) { + if (!sflag || v) + dbprintf(_("dir3 %lld block %d stale mismatch " + "%d/%d\n"), + id->ino, dabno, stale, + be16_to_cpu(leaf3->hdr.stale)); + error++; + } else if (!leaf && stale != be16_to_cpu(leaf->hdr.stale)) { if (!sflag || v) dbprintf(_("dir %lld block %d stale mismatch " "%d/%d\n"), @@ -3764,6 +3865,12 @@ scan_ag( be32_to_cpu(agi->agi_root), be32_to_cpu(agi->agi_level), 1, scanfunc_ino, TYP_INOBT); + if (agi->agi_free_root) { + scan_sbtree(agf, + be32_to_cpu(agi->agi_free_root), + be32_to_cpu(agi->agi_free_level), + 1, scanfunc_fino, TYP_FINOBT); + } if (be32_to_cpu(agf->agf_freeblks) != agffreeblks) { if (!sflag) dbprintf(_("agf_freeblks %u, counted %u in ag %u\n"), @@ -3963,7 +4070,8 @@ scanfunc_bmap( agno = XFS_FSB_TO_AGNO(mp, bno); agbno = XFS_FSB_TO_AGBNO(mp, bno); - if (be32_to_cpu(block->bb_magic) != XFS_BMAP_MAGIC) { + if (be32_to_cpu(block->bb_magic) != XFS_BMAP_MAGIC && + be32_to_cpu(block->bb_magic) != XFS_BMAP_CRC_MAGIC) { if (!sflag || id->ilist || CHECK_BLIST(bno)) dbprintf(_("bad magic # %#x in inode %lld bmbt block " "%u/%u\n"), @@ -4028,7 +4136,8 @@ scanfunc_bno( xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); xfs_agblock_t lastblock; - if (be32_to_cpu(block->bb_magic) != XFS_ABTB_MAGIC) { + if (be32_to_cpu(block->bb_magic) != XFS_ABTB_MAGIC && + be32_to_cpu(block->bb_magic) != XFS_ABTB_CRC_MAGIC) { dbprintf(_("bad magic # %#x in btbno block %u/%u\n"), be32_to_cpu(block->bb_magic), seqno, bno); serious_error++; @@ -4101,7 +4210,8 @@ scanfunc_cnt( xfs_alloc_rec_t *rp; xfs_extlen_t lastcount; - if (be32_to_cpu(block->bb_magic) != XFS_ABTC_MAGIC) { + if (be32_to_cpu(block->bb_magic) != XFS_ABTC_MAGIC && + be32_to_cpu(block->bb_magic) != XFS_ABTC_CRC_MAGIC) { dbprintf(_("bad magic # %#x in btcnt block %u/%u\n"), be32_to_cpu(block->bb_magic), seqno, bno); serious_error++; @@ -4181,7 +4291,8 @@ scanfunc_ino( xfs_inobt_ptr_t *pp; xfs_inobt_rec_t *rp; - if (be32_to_cpu(block->bb_magic) != XFS_IBT_MAGIC) { + if (be32_to_cpu(block->bb_magic) != XFS_IBT_MAGIC && + be32_to_cpu(block->bb_magic) != XFS_IBT_CRC_MAGIC) { dbprintf(_("bad magic # %#x in inobt block %u/%u\n"), be32_to_cpu(block->bb_magic), seqno, bno); serious_error++; @@ -4277,6 +4388,79 @@ scanfunc_ino( } static void +scanfunc_fino( + struct xfs_btree_block *block, + int level, + xfs_agf_t *agf, + xfs_agblock_t bno, + int isroot) +{ + xfs_agino_t agino; + xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); + int i; + int off; + xfs_inobt_ptr_t *pp; + xfs_inobt_rec_t *rp; + + if (be32_to_cpu(block->bb_magic) != XFS_FIBT_MAGIC && + be32_to_cpu(block->bb_magic) != XFS_FIBT_CRC_MAGIC) { + dbprintf(_("bad magic # %#x in finobt block %u/%u\n"), + be32_to_cpu(block->bb_magic), seqno, bno); + serious_error++; + return; + } + if (be16_to_cpu(block->bb_level) != level) { + if (!sflag) + dbprintf(_("expected level %d got %d in finobt block " + "%u/%u\n"), + level, be16_to_cpu(block->bb_level), seqno, bno); + error++; + } + set_dbmap(seqno, bno, 1, DBM_BTFINO, seqno, bno); + if (level == 0) { + if (be16_to_cpu(block->bb_numrecs) > mp->m_inobt_mxr[0] || + (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_inobt_mnr[0])) { + dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in " + "finobt block %u/%u\n"), + be16_to_cpu(block->bb_numrecs), mp->m_inobt_mnr[0], + mp->m_inobt_mxr[0], seqno, bno); + serious_error++; + return; + } + rp = XFS_INOBT_REC_ADDR(mp, block, 1); + for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) { + agino = be32_to_cpu(rp[i].ir_startino); + off = XFS_INO_TO_OFFSET(mp, agino); + if (off == 0) { + if ((sbversion & XFS_SB_VERSION_ALIGNBIT) && + mp->m_sb.sb_inoalignmt && + (XFS_INO_TO_AGBNO(mp, agino) % + mp->m_sb.sb_inoalignmt)) + sbversion &= ~XFS_SB_VERSION_ALIGNBIT; + check_set_dbmap(seqno, XFS_AGINO_TO_AGBNO(mp, agino), + (xfs_extlen_t)MAX(1, + XFS_INODES_PER_CHUNK >> + mp->m_sb.sb_inopblog), + DBM_INODE, DBM_INODE, seqno, bno); + } + } + return; + } + if (be16_to_cpu(block->bb_numrecs) > mp->m_inobt_mxr[1] || + (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_inobt_mnr[1])) { + dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in finobt block " + "%u/%u\n"), + be16_to_cpu(block->bb_numrecs), mp->m_inobt_mnr[1], + mp->m_inobt_mxr[1], seqno, bno); + serious_error++; + return; + } + pp = XFS_INOBT_PTR_ADDR(mp, block, 1, mp->m_inobt_mxr[1]); + for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) + scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_ino, TYP_FINOBT); +} + +static void set_dbmap( xfs_agnumber_t agno, xfs_agblock_t agbno, diff --git a/db/type.c b/db/type.c index b29f2a4..0aa3137 100644 --- a/db/type.c +++ b/db/type.c @@ -70,6 +70,7 @@ static const typ_t __typtab[] = { { 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_NONE, NULL } }; @@ -104,6 +105,8 @@ static const typ_t __typtab_crc[] = { { TYP_SYMLINK, "symlink", handle_struct, symlink_crc_hfld, &xfs_symlink_buf_ops }, { TYP_TEXT, "text", handle_text, NULL, NULL }, + { TYP_FINOBT, "finobt", handle_struct, inobt_crc_hfld, + &xfs_inobt_buf_ops }, { TYP_NONE, NULL } }; diff --git a/db/type.h b/db/type.h index 3bb26f1..e8d8df7 100644 --- a/db/type.h +++ b/db/type.h @@ -27,7 +27,7 @@ typedef enum typnm TYP_BMAPBTD, TYP_BNOBT, TYP_CNTBT, TYP_DATA, TYP_DIR2, TYP_DQBLK, TYP_INOBT, TYP_INODATA, TYP_INODE, TYP_LOG, TYP_RTBITMAP, TYP_RTSUMMARY, TYP_SB, TYP_SYMLINK, - TYP_TEXT, TYP_NONE + TYP_TEXT, TYP_FINOBT, TYP_NONE } typnm_t; #define DB_WRITE 1 _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 5/5] xfs_db: enable blocktrash for checksummed filesystems 2015-05-26 22:51 [PATCH 0/5] xfsprogs May 2015 patchbomb Darrick J. Wong ` (3 preceding siblings ...) 2015-05-26 22:51 ` [PATCH 4/5] xfs_db: enable blockget for v5 filesystems Darrick J. Wong @ 2015-05-26 22:51 ` Darrick J. Wong 2015-05-28 5:08 ` Darrick J. Wong 4 siblings, 1 reply; 25+ messages in thread From: Darrick J. Wong @ 2015-05-26 22:51 UTC (permalink / raw) To: david, darrick.wong; +Cc: xfs Disable the write verifiers when we're trashing a block. With this in place, create a xfs fuzzer script that formats, populates, corrupts, tries to use, repairs, and tries again to use a crash test xfs image. Hopefully this will shake out some v5 filesystem bugs. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> --- db/check.c | 7 + db/xfsfuzz.sh | 305 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 312 insertions(+) create mode 100755 db/xfsfuzz.sh diff --git a/db/check.c b/db/check.c index 8f8096d..2c2a02e 100644 --- a/db/check.c +++ b/db/check.c @@ -953,6 +953,7 @@ blocktrash_b( int mask; int newbit; int offset; + const struct xfs_buf_ops *stashed_ops; static char *modestr[] = { N_("zeroed"), N_("set"), N_("flipped"), N_("randomized") }; @@ -963,6 +964,8 @@ blocktrash_b( push_cur(); set_cur(&typtab[DBM_UNKNOWN], XFS_AGB_TO_DADDR(mp, agno, agbno), blkbb, DB_RING_IGN, NULL); + stashed_ops = iocur_top->bp->b_ops; + iocur_top->bp->b_ops = NULL; if ((buf = iocur_top->data) == NULL) { dbprintf(_("can't read block %u/%u for trashing\n"), agno, agbno); pop_cur(); @@ -993,6 +996,7 @@ blocktrash_b( buf[byte] &= ~mask; } write_cur(); + iocur_top->bp->b_ops = stashed_ops; pop_cur(); printf(_("blocktrash: %u/%u %s block %d bit%s starting %d:%d %s\n"), agno, agbno, typename[type], len, len == 1 ? "" : "s", @@ -1049,9 +1053,12 @@ blocktrash_f( (1 << DBM_BTINO) | (1 << DBM_DIR) | (1 << DBM_INODE) | + (1 << DBM_LOG) | (1 << DBM_QUOTA) | (1 << DBM_RTBITMAP) | (1 << DBM_RTSUM) | + (1 << DBM_SYMLINK) | + (1 << DBM_BTFINO) | (1 << DBM_SB); while ((c = getopt(argc, argv, "0123n:s:t:x:y:")) != EOF) { switch (c) { diff --git a/db/xfsfuzz.sh b/db/xfsfuzz.sh new file mode 100755 index 0000000..fc40e97 --- /dev/null +++ b/db/xfsfuzz.sh @@ -0,0 +1,305 @@ +#!/bin/bash + +# Test harness to fuzz a filesystem over and over... +# Copyright (C) 2014 Oracle. + +DIR=/tmp +PASSES=10000 +SZ=32m +SCRIPT_DIR="$(dirname "$0")" +FEATURES="-m crc=1,finobt=1" +xEATURES="-m crc=0" +BLK_SZ=4096 +INODE_SZ=512 +RUN_FSCK=1 +OVERRIDE_PATH=1 +MAX_FSCK=10 +SRCDIR=/etc +FUZZ_ARGS="-3 -n 32" +XFS_REPAIR_OPTS="-P" + +print_help() { + echo "Usage: $0 OPTIONS" + echo "-b: FS block size is this. (${BLK_SZ})" + echo "-B: Corrupt this many bytes per run." + echo "-d: Create test files in this directory. (${DIR})" + echo "-f: Do not run xfs_repair after each pass." + echo "-I: Create inodes of this size. (${INODE_SZ})" + echo "-n: Run this many passes. (${PASSES})" + echo "-O: Pass this to mkfs.xfs." + echo "-p: Use system's xfsprogs tools." + echo "-s: Create FS images of this size. (${SZ})" + echo "-S: Copy files from this dir. (${SRCDIR})" + echo "-x: Run xfs_repair at most this many times. (${MAX_FSCK})" + exit 0 +} + +GETOPT="d:n:s:O:I:b:B:fpx:S:" + +while getopts "${GETOPT}" opt; do + case "${opt}" in + "B") + FUZZ_ARGS="-3 -n ${OPTARG}" + ;; + "d") + DIR="${OPTARG}" + ;; + "n") + PASSES="${OPTARG}" + ;; + "s") + SZ="${OPTARG}" + ;; + "O") + FEATURES="${OPTARG}" + ;; + "I") + INODE_SZ="${OPTARG}" + ;; + "b") + BLK_SZ="${OPTARG}" + ;; + "f") + RUN_FSCK=0 + ;; + "p") + OVERRIDE_PATH=0 + ;; + "x") + MAX_FSCK="${OPTARG}" + ;; + "S") + SRCDIR="${OPTARG}" + ;; + *) + print_help + ;; + esac +done + +if [ "${OVERRIDE_PATH}" -gt 0 ]; then + PATH="${SCRIPT_DIR}:${SCRIPT_DIR}/../repair/:${SCRIPT_DIR}/../db/:${SCRIPT_DIR}/../mkfs/:${PATH}" + export PATH +fi + +TESTDIR="${DIR}/tests/" +TESTMNT="${DIR}/mnt/" +BASE_IMG="${DIR}/xfsfuzz.img" + +# Set up FS image +echo "+ create fs image" +umount "${TESTDIR}" +umount "${TESTMNT}" +rm -rf "${TESTDIR}" +rm -rf "${TESTMNT}" +mkdir -p "${TESTDIR}" +mkdir -p "${TESTMNT}" +rm -rf "${BASE_IMG}" +truncate -s "${SZ}" "${BASE_IMG}" +mkfs.xfs -f ${FEATURES} -b "size=${BLK_SZ}" -i "size=${INODE_SZ}" "${BASE_IMG}" +if [ $? -ne 0 ]; then + exit $? +fi + +# Populate FS image +echo "+ populate fs image" +modprobe loop +mount "${BASE_IMG}" "${TESTMNT}" -o loop +if [ $? -ne 0 ]; then + exit $? +fi +SRC_SZ="$(du -ks "${SRCDIR}" | awk '{print $1}')" +FS_SZ="$(( $(stat -f "${TESTMNT}" -c '%a * %S') / 1024 ))" +NR="$(( (FS_SZ * 6 / 10) / SRC_SZ ))" +if [ "${NR}" -lt 1 ]; then + NR=1 +fi +echo "+ make ${NR} copies" +seq 1 "${NR}" | while read nr; do + cp -pRdu "${SRCDIR}" "${TESTMNT}/test.${nr}" 2> /dev/null +done +umount "${TESTMNT}" +xfs_repair ${XFS_REPAIR_OPTS} -vn "${BASE_IMG}" +if [ $? -ne 0 ]; then + echo "fsck failed??" + exit 1 +fi + +# Run tests +echo "+ run test" +ret=0 +seq 1 "${PASSES}" | while read pass; do + echo "+ pass ${pass}" + PASS_IMG="${TESTDIR}/xfsfuzz-${pass}.img" + FSCK_IMG="${TESTDIR}/xfsfuzz-${pass}.fsck" + FUZZ_LOG="${TESTDIR}/xfsfuzz-${pass}.fuzz.log" + OPS_LOG="${TESTDIR}/xfsfuzz-${pass}.ops.log" + + echo "++ copy image" + cp "${BASE_IMG}" "${PASS_IMG}" + if [ $? -ne 0 ]; then + exit $? + fi + xfs_db -x -c "label xfsfuzz-${pass}" "${PASS_IMG}" + + echo "++ corrupt image" + xfs_db -x -c blockget -c "blocktrash ${FUZZ_ARGS}" "${PASS_IMG}" > "${FUZZ_LOG}" +# res=$? +# if [ "${res}" -ne 0 ]; then +# echo "blocktrash returns ${res}" +# exit "${res}" +# fi + + echo "++ mount image" + mount "${PASS_IMG}" "${TESTMNT}" -o loop + res=$? + + if [ "${res}" -eq 0 ]; then + echo "+++ ls -laR" + ls -laR "${TESTMNT}/test.1/" > /dev/null 2> "${OPS_LOG}" + + echo "+++ cat files" + find "${TESTMNT}/test.1/" -type f -size -1048576k -print0 | xargs -0 cat > /dev/null 2>> "${OPS_LOG}" + + echo "+++ expand" + find "${TESTMNT}/" -type f 2> /dev/null | head -n 50000 | while read f; do + attr -l "$f" > /dev/null 2>> "${OPS_LOG}" + if [ -f "$f" -a -w "$f" ]; then + dd if=/dev/zero bs="${BLK_SZ}" count=1 >> "$f" 2>> "${OPS_LOG}" + fi + mv "$f" "$f.longer" > /dev/null 2>> "${OPS_LOG}" + done + sync + + echo "+++ create files" + cp -pRdu "${SRCDIR}" "${TESTMNT}/test.moo" 2>> "${OPS_LOG}" + sync + + echo "+++ remove files" + rm -rf "${TESTMNT}/test.moo" 2>> "${OPS_LOG}" + + umount "${TESTMNT}" + res=$? + if [ "${res}" -ne 0 ]; then + ret=1 + break + fi + sync + fi + if [ "${RUN_FSCK}" -gt 0 ]; then + cp "${PASS_IMG}" "${FSCK_IMG}" + pass_img_sz="$(stat -c '%s' "${PASS_IMG}")" + + seq 1 "${MAX_FSCK}" | while read fsck_pass; do + echo "++ fsck pass ${fsck_pass}: $(which xfs_repair) -v ${FSCK_IMG}" + FSCK_LOG="${TESTDIR}/xfsfuzz-${pass}-${fsck_pass}.log" + echo "repairing" > "${FSCK_LOG}" + xfs_repair ${XFS_REPAIR_OPTS} -v "${FSCK_IMG}" >> "${FSCK_LOG}" 2>&1 + res=$? + if [ "${res}" -eq 0 ]; then + echo "reverify" >> "${FSCK_LOG}" + xfs_repair ${XFS_REPAIR_OPTS} -v -n "${FSCK_IMG}" >> "${FSCK_LOG}" 2>&1 + res=$? + fi + echo "++ fsck returns ${res}" + if [ "${res}" -eq 0 ]; then + exit 0 + elif [ "${res}" -eq 2 ]; then + # replay log? + echo "replaying log" >> "${FSCK_LOG}" + dmesg > /tmp/a + mount "${FSCK_IMG}" "${TESTMNT}" -o loop + res=$? + if [ "${res}" -gt 0 ]; then + echo "+++ zeroing log" + echo "zeroing log" >> "${FSCK_LOG}" + xfs_repair ${XFS_REPAIR_OPTS} -L -v "${FSCK_IMG}" >> "${FSCK_LOG}" 2>&1 + else + umount "${TESTMNT}" + fi + dmesg > /tmp/b + diff -u /tmp/a /tmp/b >> "${FSCK_LOG}" + elif [ "${fsck_pass}" -eq "${MAX_FSCK}" ]; then + echo "++ fsck did not fix in ${MAX_FSCK} passes." + exit 1 + fi + if [ "${fsck_pass}" -gt 1 ]; then + diff -u "${TESTDIR}/xfsfuzz-${pass}-$((fsck_pass - 1)).log" "${FSCK_LOG}" + if [ $? -eq 0 ]; then + echo "++ fsck makes no progress" + exit 2 + fi + fi + + fsck_img_sz="$(stat -c '%s' "${FSCK_IMG}")" + if [ "${fsck_img_sz}" -ne "${pass_img_sz}" ]; then + echo "++ fsck image size changed" + exit 3 + fi + done + fsck_loop_ret=$? + if [ "${fsck_loop_ret}" -gt 0 ]; then + break; + fi + fi + + echo "+++ check fs for round 2" + FSCK_LOG="${TESTDIR}/xfsfuzz-${pass}-round2.log" + xfs_repair ${XFS_REPAIR_OPTS} -v -n "${FSCK_IMG}" > "${FSCK_LOG}" 2>&1 + res=$? + if [ "${res}" -ne 0 ]; then + echo "++++ fsck failed." + exit 1 + fi + + echo "++ mount image (2)" + mount "${FSCK_IMG}" "${TESTMNT}" -o loop + res=$? + + if [ "${res}" -eq 0 ]; then + echo "+++ ls -laR (2)" + ls -laR "${TESTMNT}/test.1/" > /dev/null 2> "${OPS_LOG}" + + echo "+++ cat files (2)" + find "${TESTMNT}/test.1/" -type f -size -1048576k -print0 | xargs -0 cat > /dev/null 2>> "${OPS_LOG}" + + echo "+++ expand (2)" + find "${TESTMNT}/" -type f 2> /dev/null | head -n 50000 | while read f; do + attr -l "$f" > /dev/null 2>> "${OPS_LOG}" + if [ -f "$f" -a -w "$f" ]; then + dd if=/dev/zero bs="${BLK_SZ}" count=1 >> "$f" 2>> "${OPS_LOG}" + fi + mv "$f" "$f.longer" > /dev/null 2>> "${OPS_LOG}" + done + sync + + echo "+++ create files (2)" + cp -pRdu "${SRCDIR}" "${TESTMNT}/test.moo" 2>> "${OPS_LOG}" + sync + + echo "+++ remove files (2)" + rm -rf "${TESTMNT}/test.moo" 2>> "${OPS_LOG}" + + umount "${TESTMNT}" + res=$? + if [ "${res}" -ne 0 ]; then + ret=1 + break + fi + sync + + echo "+++ check fs (2)" + xfs_repair ${XFS_REPAIR_OPTS} -v -n "${FSCK_IMG}" >> "${FSCK_LOG}" 2>&1 + res=$? + if [ "${res}" -ne 0 ]; then + echo "++++ fsck failed." + exit 1 + fi + else + echo "++ mount(2) failed with ${res}" + exit 1 + fi + rm -rf "${FSCK_IMG}" "${PASS_IMG}" "${FUZZ_LOG}" "${TESTDIR}"/xfsfuzz*.log +done + +exit $ret _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH 5/5] xfs_db: enable blocktrash for checksummed filesystems 2015-05-26 22:51 ` [PATCH 5/5] xfs_db: enable blocktrash for checksummed filesystems Darrick J. Wong @ 2015-05-28 5:08 ` Darrick J. Wong 0 siblings, 0 replies; 25+ messages in thread From: Darrick J. Wong @ 2015-05-28 5:08 UTC (permalink / raw) To: david; +Cc: xfs On Tue, May 26, 2015 at 03:51:59PM -0700, Darrick J. Wong wrote: > Disable the write verifiers when we're trashing a block. With this > in place, create a xfs fuzzer script that formats, populates, corrupts, > tries to use, repairs, and tries again to use a crash test xfs image. > Hopefully this will shake out some v5 filesystem bugs. > > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> > --- > db/check.c | 7 + > db/xfsfuzz.sh | 305 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 312 insertions(+) > create mode 100755 db/xfsfuzz.sh > > > diff --git a/db/check.c b/db/check.c > index 8f8096d..2c2a02e 100644 > --- a/db/check.c > +++ b/db/check.c > @@ -953,6 +953,7 @@ blocktrash_b( > int mask; > int newbit; > int offset; > + const struct xfs_buf_ops *stashed_ops; > static char *modestr[] = { > N_("zeroed"), N_("set"), N_("flipped"), N_("randomized") > }; > @@ -963,6 +964,8 @@ blocktrash_b( > push_cur(); > set_cur(&typtab[DBM_UNKNOWN], So... seeing as the the TYP_* and DBM_* values don't correspond and every other user of typtab uses the TYP_ values for array index, what's the point of unconditionally using the AGF verifier on this block? Passing NULL as the first argument doesn't seem to hurt anything. (DBM_UNKNOWN == TYP_AGF) Seeing as we're going to trash the block anyway, why bother? > XFS_AGB_TO_DADDR(mp, agno, agbno), blkbb, DB_RING_IGN, NULL); > + stashed_ops = iocur_top->bp->b_ops; > + iocur_top->bp->b_ops = NULL; > if ((buf = iocur_top->data) == NULL) { > dbprintf(_("can't read block %u/%u for trashing\n"), agno, agbno); > pop_cur(); > @@ -993,6 +996,7 @@ blocktrash_b( > buf[byte] &= ~mask; > } > write_cur(); > + iocur_top->bp->b_ops = stashed_ops; > pop_cur(); > printf(_("blocktrash: %u/%u %s block %d bit%s starting %d:%d %s\n"), > agno, agbno, typename[type], len, len == 1 ? "" : "s", > @@ -1049,9 +1053,12 @@ blocktrash_f( > (1 << DBM_BTINO) | > (1 << DBM_DIR) | > (1 << DBM_INODE) | > + (1 << DBM_LOG) | It's useful to be able to fuzz the log, but that'll bias the block selection towards the log. Maybe it should be masked off by default in tmask = goodmask below? > (1 << DBM_QUOTA) | > (1 << DBM_RTBITMAP) | > (1 << DBM_RTSUM) | > + (1 << DBM_SYMLINK) | > + (1 << DBM_BTFINO) | > (1 << DBM_SB); > while ((c = getopt(argc, argv, "0123n:s:t:x:y:")) != EOF) { > switch (c) { > diff --git a/db/xfsfuzz.sh b/db/xfsfuzz.sh > new file mode 100755 > index 0000000..fc40e97 > --- /dev/null > +++ b/db/xfsfuzz.sh [working on stuffing this into xfstests] [maybe I'll see about doing likewise for the ext4 fuzzer] --D > @@ -0,0 +1,305 @@ > +#!/bin/bash > + > +# Test harness to fuzz a filesystem over and over... > +# Copyright (C) 2014 Oracle. > + > +DIR=/tmp > +PASSES=10000 > +SZ=32m > +SCRIPT_DIR="$(dirname "$0")" > +FEATURES="-m crc=1,finobt=1" > +xEATURES="-m crc=0" > +BLK_SZ=4096 > +INODE_SZ=512 > +RUN_FSCK=1 > +OVERRIDE_PATH=1 > +MAX_FSCK=10 > +SRCDIR=/etc > +FUZZ_ARGS="-3 -n 32" > +XFS_REPAIR_OPTS="-P" > + > +print_help() { > + echo "Usage: $0 OPTIONS" > + echo "-b: FS block size is this. (${BLK_SZ})" > + echo "-B: Corrupt this many bytes per run." > + echo "-d: Create test files in this directory. (${DIR})" > + echo "-f: Do not run xfs_repair after each pass." > + echo "-I: Create inodes of this size. (${INODE_SZ})" > + echo "-n: Run this many passes. (${PASSES})" > + echo "-O: Pass this to mkfs.xfs." > + echo "-p: Use system's xfsprogs tools." > + echo "-s: Create FS images of this size. (${SZ})" > + echo "-S: Copy files from this dir. (${SRCDIR})" > + echo "-x: Run xfs_repair at most this many times. (${MAX_FSCK})" > + exit 0 > +} > + > +GETOPT="d:n:s:O:I:b:B:fpx:S:" > + > +while getopts "${GETOPT}" opt; do > + case "${opt}" in > + "B") > + FUZZ_ARGS="-3 -n ${OPTARG}" > + ;; > + "d") > + DIR="${OPTARG}" > + ;; > + "n") > + PASSES="${OPTARG}" > + ;; > + "s") > + SZ="${OPTARG}" > + ;; > + "O") > + FEATURES="${OPTARG}" > + ;; > + "I") > + INODE_SZ="${OPTARG}" > + ;; > + "b") > + BLK_SZ="${OPTARG}" > + ;; > + "f") > + RUN_FSCK=0 > + ;; > + "p") > + OVERRIDE_PATH=0 > + ;; > + "x") > + MAX_FSCK="${OPTARG}" > + ;; > + "S") > + SRCDIR="${OPTARG}" > + ;; > + *) > + print_help > + ;; > + esac > +done > + > +if [ "${OVERRIDE_PATH}" -gt 0 ]; then > + PATH="${SCRIPT_DIR}:${SCRIPT_DIR}/../repair/:${SCRIPT_DIR}/../db/:${SCRIPT_DIR}/../mkfs/:${PATH}" > + export PATH > +fi > + > +TESTDIR="${DIR}/tests/" > +TESTMNT="${DIR}/mnt/" > +BASE_IMG="${DIR}/xfsfuzz.img" > + > +# Set up FS image > +echo "+ create fs image" > +umount "${TESTDIR}" > +umount "${TESTMNT}" > +rm -rf "${TESTDIR}" > +rm -rf "${TESTMNT}" > +mkdir -p "${TESTDIR}" > +mkdir -p "${TESTMNT}" > +rm -rf "${BASE_IMG}" > +truncate -s "${SZ}" "${BASE_IMG}" > +mkfs.xfs -f ${FEATURES} -b "size=${BLK_SZ}" -i "size=${INODE_SZ}" "${BASE_IMG}" > +if [ $? -ne 0 ]; then > + exit $? > +fi > + > +# Populate FS image > +echo "+ populate fs image" > +modprobe loop > +mount "${BASE_IMG}" "${TESTMNT}" -o loop > +if [ $? -ne 0 ]; then > + exit $? > +fi > +SRC_SZ="$(du -ks "${SRCDIR}" | awk '{print $1}')" > +FS_SZ="$(( $(stat -f "${TESTMNT}" -c '%a * %S') / 1024 ))" > +NR="$(( (FS_SZ * 6 / 10) / SRC_SZ ))" > +if [ "${NR}" -lt 1 ]; then > + NR=1 > +fi > +echo "+ make ${NR} copies" > +seq 1 "${NR}" | while read nr; do > + cp -pRdu "${SRCDIR}" "${TESTMNT}/test.${nr}" 2> /dev/null > +done > +umount "${TESTMNT}" > +xfs_repair ${XFS_REPAIR_OPTS} -vn "${BASE_IMG}" > +if [ $? -ne 0 ]; then > + echo "fsck failed??" > + exit 1 > +fi > + > +# Run tests > +echo "+ run test" > +ret=0 > +seq 1 "${PASSES}" | while read pass; do > + echo "+ pass ${pass}" > + PASS_IMG="${TESTDIR}/xfsfuzz-${pass}.img" > + FSCK_IMG="${TESTDIR}/xfsfuzz-${pass}.fsck" > + FUZZ_LOG="${TESTDIR}/xfsfuzz-${pass}.fuzz.log" > + OPS_LOG="${TESTDIR}/xfsfuzz-${pass}.ops.log" > + > + echo "++ copy image" > + cp "${BASE_IMG}" "${PASS_IMG}" > + if [ $? -ne 0 ]; then > + exit $? > + fi > + xfs_db -x -c "label xfsfuzz-${pass}" "${PASS_IMG}" > + > + echo "++ corrupt image" > + xfs_db -x -c blockget -c "blocktrash ${FUZZ_ARGS}" "${PASS_IMG}" > "${FUZZ_LOG}" > +# res=$? > +# if [ "${res}" -ne 0 ]; then > +# echo "blocktrash returns ${res}" > +# exit "${res}" > +# fi > + > + echo "++ mount image" > + mount "${PASS_IMG}" "${TESTMNT}" -o loop > + res=$? > + > + if [ "${res}" -eq 0 ]; then > + echo "+++ ls -laR" > + ls -laR "${TESTMNT}/test.1/" > /dev/null 2> "${OPS_LOG}" > + > + echo "+++ cat files" > + find "${TESTMNT}/test.1/" -type f -size -1048576k -print0 | xargs -0 cat > /dev/null 2>> "${OPS_LOG}" > + > + echo "+++ expand" > + find "${TESTMNT}/" -type f 2> /dev/null | head -n 50000 | while read f; do > + attr -l "$f" > /dev/null 2>> "${OPS_LOG}" > + if [ -f "$f" -a -w "$f" ]; then > + dd if=/dev/zero bs="${BLK_SZ}" count=1 >> "$f" 2>> "${OPS_LOG}" > + fi > + mv "$f" "$f.longer" > /dev/null 2>> "${OPS_LOG}" > + done > + sync > + > + echo "+++ create files" > + cp -pRdu "${SRCDIR}" "${TESTMNT}/test.moo" 2>> "${OPS_LOG}" > + sync > + > + echo "+++ remove files" > + rm -rf "${TESTMNT}/test.moo" 2>> "${OPS_LOG}" > + > + umount "${TESTMNT}" > + res=$? > + if [ "${res}" -ne 0 ]; then > + ret=1 > + break > + fi > + sync > + fi > + if [ "${RUN_FSCK}" -gt 0 ]; then > + cp "${PASS_IMG}" "${FSCK_IMG}" > + pass_img_sz="$(stat -c '%s' "${PASS_IMG}")" > + > + seq 1 "${MAX_FSCK}" | while read fsck_pass; do > + echo "++ fsck pass ${fsck_pass}: $(which xfs_repair) -v ${FSCK_IMG}" > + FSCK_LOG="${TESTDIR}/xfsfuzz-${pass}-${fsck_pass}.log" > + echo "repairing" > "${FSCK_LOG}" > + xfs_repair ${XFS_REPAIR_OPTS} -v "${FSCK_IMG}" >> "${FSCK_LOG}" 2>&1 > + res=$? > + if [ "${res}" -eq 0 ]; then > + echo "reverify" >> "${FSCK_LOG}" > + xfs_repair ${XFS_REPAIR_OPTS} -v -n "${FSCK_IMG}" >> "${FSCK_LOG}" 2>&1 > + res=$? > + fi > + echo "++ fsck returns ${res}" > + if [ "${res}" -eq 0 ]; then > + exit 0 > + elif [ "${res}" -eq 2 ]; then > + # replay log? > + echo "replaying log" >> "${FSCK_LOG}" > + dmesg > /tmp/a > + mount "${FSCK_IMG}" "${TESTMNT}" -o loop > + res=$? > + if [ "${res}" -gt 0 ]; then > + echo "+++ zeroing log" > + echo "zeroing log" >> "${FSCK_LOG}" > + xfs_repair ${XFS_REPAIR_OPTS} -L -v "${FSCK_IMG}" >> "${FSCK_LOG}" 2>&1 > + else > + umount "${TESTMNT}" > + fi > + dmesg > /tmp/b > + diff -u /tmp/a /tmp/b >> "${FSCK_LOG}" > + elif [ "${fsck_pass}" -eq "${MAX_FSCK}" ]; then > + echo "++ fsck did not fix in ${MAX_FSCK} passes." > + exit 1 > + fi > + if [ "${fsck_pass}" -gt 1 ]; then > + diff -u "${TESTDIR}/xfsfuzz-${pass}-$((fsck_pass - 1)).log" "${FSCK_LOG}" > + if [ $? -eq 0 ]; then > + echo "++ fsck makes no progress" > + exit 2 > + fi > + fi > + > + fsck_img_sz="$(stat -c '%s' "${FSCK_IMG}")" > + if [ "${fsck_img_sz}" -ne "${pass_img_sz}" ]; then > + echo "++ fsck image size changed" > + exit 3 > + fi > + done > + fsck_loop_ret=$? > + if [ "${fsck_loop_ret}" -gt 0 ]; then > + break; > + fi > + fi > + > + echo "+++ check fs for round 2" > + FSCK_LOG="${TESTDIR}/xfsfuzz-${pass}-round2.log" > + xfs_repair ${XFS_REPAIR_OPTS} -v -n "${FSCK_IMG}" > "${FSCK_LOG}" 2>&1 > + res=$? > + if [ "${res}" -ne 0 ]; then > + echo "++++ fsck failed." > + exit 1 > + fi > + > + echo "++ mount image (2)" > + mount "${FSCK_IMG}" "${TESTMNT}" -o loop > + res=$? > + > + if [ "${res}" -eq 0 ]; then > + echo "+++ ls -laR (2)" > + ls -laR "${TESTMNT}/test.1/" > /dev/null 2> "${OPS_LOG}" > + > + echo "+++ cat files (2)" > + find "${TESTMNT}/test.1/" -type f -size -1048576k -print0 | xargs -0 cat > /dev/null 2>> "${OPS_LOG}" > + > + echo "+++ expand (2)" > + find "${TESTMNT}/" -type f 2> /dev/null | head -n 50000 | while read f; do > + attr -l "$f" > /dev/null 2>> "${OPS_LOG}" > + if [ -f "$f" -a -w "$f" ]; then > + dd if=/dev/zero bs="${BLK_SZ}" count=1 >> "$f" 2>> "${OPS_LOG}" > + fi > + mv "$f" "$f.longer" > /dev/null 2>> "${OPS_LOG}" > + done > + sync > + > + echo "+++ create files (2)" > + cp -pRdu "${SRCDIR}" "${TESTMNT}/test.moo" 2>> "${OPS_LOG}" > + sync > + > + echo "+++ remove files (2)" > + rm -rf "${TESTMNT}/test.moo" 2>> "${OPS_LOG}" > + > + umount "${TESTMNT}" > + res=$? > + if [ "${res}" -ne 0 ]; then > + ret=1 > + break > + fi > + sync > + > + echo "+++ check fs (2)" > + xfs_repair ${XFS_REPAIR_OPTS} -v -n "${FSCK_IMG}" >> "${FSCK_LOG}" 2>&1 > + res=$? > + if [ "${res}" -ne 0 ]; then > + echo "++++ fsck failed." > + exit 1 > + fi > + else > + echo "++ mount(2) failed with ${res}" > + exit 1 > + fi > + rm -rf "${FSCK_IMG}" "${PASS_IMG}" "${FUZZ_LOG}" "${TESTDIR}"/xfsfuzz*.log > +done > + > +exit $ret > > _______________________________________________ > xfs mailing list > xfs@oss.sgi.com > http://oss.sgi.com/mailman/listinfo/xfs _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2015-05-31 21:32 UTC | newest] Thread overview: 25+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2015-05-26 22:51 [PATCH 0/5] xfsprogs May 2015 patchbomb Darrick J. Wong 2015-05-26 22:51 ` [PATCH 1/5] xfs_repair: refuse to run if we don't recognize version or feature flags Darrick J. Wong 2015-05-26 23:49 ` Eric Sandeen 2015-05-27 5:45 ` [PATCH v2 " Darrick J. Wong 2015-05-27 14:54 ` Eric Sandeen 2015-05-27 15:16 ` Eric Sandeen 2015-05-27 15:27 ` Eric Sandeen 2015-05-27 16:04 ` Fanael Linithien 2015-05-27 16:26 ` Eric Sandeen 2015-05-27 17:17 ` Darrick J. Wong 2015-05-27 15:19 ` Fanael Linithien 2015-05-27 16:42 ` Darrick J. Wong 2015-05-27 18:15 ` [PATCH v3 " Darrick J. Wong 2015-05-27 18:42 ` Fanael Linithien 2015-05-26 22:51 ` [PATCH 2/5] xfs_repair: better checking of v5 metadata fields Darrick J. Wong 2015-05-26 23:58 ` Dave Chinner 2015-05-27 5:44 ` [PATCH v2 " Darrick J. Wong 2015-05-31 21:32 ` Dave Chinner 2015-05-26 22:51 ` [PATCH 3/5] xfs_repair: ensure .. is set to a sane ino value when rebuilding dir Darrick J. Wong 2015-05-26 22:51 ` [PATCH 4/5] xfs_db: enable blockget for v5 filesystems Darrick J. Wong 2015-05-26 23:07 ` Eric Sandeen 2015-05-26 23:13 ` Darrick J. Wong 2015-05-26 23:14 ` [PATCH v2 " Darrick J. Wong 2015-05-26 22:51 ` [PATCH 5/5] xfs_db: enable blocktrash for checksummed filesystems Darrick J. Wong 2015-05-28 5:08 ` Darrick J. Wong
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox