On Mar 1, 2013, at 7:18 PM, Dave Chinner <david@xxxxxxxxxxxxx> wrote: > On Fri, Mar 01, 2013 at 05:46:48PM -0600, Eric Sandeen wrote: >> In no-modify mode (-n), verify_set_agf doesn't fix up bad >> freelist blocks that it finds. When we get to scan_freelist, >> this can wreak havoc if, for example, first > last and the loop >> never exits; we index agfl->agfl_bno[i] off into the weeds. >> >> To fix this, re-check the values in no-modify mode, and if >> they're off, warn about it and skip the scan. >> >> In addition, add a check to verify_set_agf() to ensure that >> first <= last. >> >> Reported-by: Ole Tange <tange@xxxxxxxxxx> >> Signed-off-by: Eric Sandeen <sandeen@xxxxxxxxxx> >> --- >> >> diff --git a/repair/agheader.c b/repair/agheader.c >> index 769022d..68789fe 100644 >> --- a/repair/agheader.c >> +++ b/repair/agheader.c >> @@ -86,6 +86,14 @@ verify_set_agf(xfs_mount_t *mp, xfs_agf_t *agf, xfs_agnumber_t i) >> * check first/last AGF fields. if need be, lose the free >> * space in the AGFL, we'll reclaim it later. >> */ >> + if (be32_to_cpu(agf->agf_flfirst) > be32_to_cpu(agf->agf_fllast)) { >> + do_warn(_("flfirst %d in agf %d > fllast %d\n"), >> + be32_to_cpu(agf->agf_flfirst), >> + i, be32_to_cpu(agf->agf_fllast)); >> + if (!no_modify) >> + agf->agf_fllast = agf->agf_flfirst = cpu_to_be32(0); >> + } > > I don't think that test is correct. The free list is circular and is > indexed as a pair of head/tail pointers. Hence flfirst > fllast can > be actually valid. e.g. flcount = 4, flfirst=126, fllast = 2 is a > valid free list. > Doh, ok. Will fix. >> + >> if (be32_to_cpu(agf->agf_flfirst) >= XFS_AGFL_SIZE(mp)) { >> do_warn(_("flfirst %d in agf %d too large (max = %zu)\n"), >> be32_to_cpu(agf->agf_flfirst), >> diff --git a/repair/scan.c b/repair/scan.c >> index 5345094..0f83fb4 100644 >> --- a/repair/scan.c >> +++ b/repair/scan.c >> @@ -1067,6 +1067,17 @@ scan_freelist( >> } >> agfl = XFS_BUF_TO_AGFL(agflbuf); >> i = be32_to_cpu(agf->agf_flfirst); >> + if (no_modify) { >> + /* agf values not sanitized, so double check */ >> + if (i >= XFS_AGFL_SIZE(mp) || >> + be32_to_cpu(agf->agf_fllast) >= XFS_AGFL_SIZE(mp) || >> + i > be32_to_cpu(agf->agf_fllast)) >> + do_warn(_("agf %d freelist blocks bad, skipping scan\n"), > > "skipping freelist scan" > >> + i); >> + return; > > Also, you might be missing a set of {} there - that will always > return immediately if no_modify is set.... > Cripes. 1 demerit for me, sorry. Will fix and resend. Thanks for the embarrassing review. :) -Eric > Cheers, > > Dave. > -- > Dave Chinner > david@xxxxxxxxxxxxx > _______________________________________________ xfs mailing list xfs@xxxxxxxxxxx http://oss.sgi.com/mailman/listinfo/xfs