[PATCH 2/2] xfs_repair: new secondary superblock search method
Darrick J. Wong
darrick.wong at oracle.com
Tue Feb 9 13:14:09 CST 2016
On Tue, Feb 09, 2016 at 01:05:12PM -0600, Eric Sandeen wrote:
> On 2/9/16 11:13 AM, Bill O'Donnell wrote:
> > Optimize secondary sb search, using similar method to find
> > fs geometry as that of xfs_mkfs. If this faster method fails
> > in finding a secondary sb, fall back to original brute force
> > slower search.
> >
> > Signed-off-by: Bill O'Donnell <billodo at redhat.com>
> > ---
> > Makefile | 2 +-
> > include/libxcmd.h | 4 +++-
> > libxcmd/topology.c | 28 +++++++++++++++++++++++++++-
> > repair/Makefile | 4 ++--
> > repair/phase1.c | 25 +++++++++++++++++++++++--
> > repair/protos.h | 2 +-
> > repair/sb.c | 27 +++++++++++++++++++++------
> > 7 files changed, 78 insertions(+), 14 deletions(-)
> >
> > diff --git a/Makefile b/Makefile
> > index fca0a42..1d60d9c 100644
> > --- a/Makefile
> > +++ b/Makefile
> > @@ -80,7 +80,7 @@ fsr: libhandle
> > growfs: libxcmd
> > io: libxcmd libhandle
> > quota: libxcmd
> > -repair: libxlog
> > +repair: libxlog libxcmd
> > copy: libxlog
> >
> > ifeq ($(HAVE_BUILDDEFS), yes)
> > diff --git a/include/libxcmd.h b/include/libxcmd.h
> > index df7046e..b140adb 100644
> > --- a/include/libxcmd.h
> > +++ b/include/libxcmd.h
> > @@ -50,6 +50,8 @@ extern int
> > check_overwrite(
> > char *device);
> >
> > -
> > +extern int guess_default_geometry(__uint64_t *agsize,
> > + __uint64_t *agcount,
> > + libxfs_init_t x);
> >
> > #endif /* __LIBXCMD_H__ */
> > diff --git a/libxcmd/topology.c b/libxcmd/topology.c
> > index 0eeea28..4a8ab8b 100644
> > --- a/libxcmd/topology.c
> > +++ b/libxcmd/topology.c
> > @@ -302,7 +302,6 @@ static void blkid_get_topology(
> >
> > #endif /* ENABLE_BLKID */
> >
> > -
> > void get_topology(
> > libxfs_init_t *xi,
> > struct fs_topology *ft,
> > @@ -346,3 +345,30 @@ void get_topology(
> > &lsectorsize, &psectorsize, force_overwrite);
> > }
> > }
> > +
> > +/*
> > + * Use this macro before we have superblock and mount structure
> > + */
> > +#define DTOBT(d) ((xfs_rfsblock_t)((d) >> (blocklog - BBSHIFT)))
>
> Hm, I hate this macro. ;) I know it lives in xfs_mkfs.c too... depending
> on a local variable is ick. Since you only use it once below, it might be best
> to just open-code it, see below.
>
> > +
> > +int guess_default_geometry(__uint64_t *agsize, __uint64_t *agcount, libxfs_init_t x) {
>
> Move the "{" down to this line, please, and wrap the args so it doesn't go
> over 80 chars.
Also, please put the function name at the start of a line like most of the
other XFS code:
int
guess_default_geometry(
__uint64_t *agsize,
__uint64_t *agcount,
libxfs_init_t x)
{
/* ... */
}
This makes it wayyyy easier to grep-hunt for function definitions.
(Try wading through the mishmash of ext4/e2fsprogs until your brain fades...)
--D
>
> > + struct fs_topology ft;
> > + int blocklog;
> > + __uint64_t dblocks;
> ^tab here please
> > + int multidisk;
> ^tabs here please
>
> ... and a newline here to separate variable declarations...
>
> > + memset(&ft, 0, sizeof(ft));
>
> ... from this call. Tab this call in...
>
>
> > + get_topology(&x, &ft, 1);
> ^^^^ as well as this one.
>
> > +
> > + /*
> ^ tab here too
> > + * get geometry from get_topology result.
> > + * Use default block size (2^12)
> > + */
> > + blocklog = 12;
> > + multidisk = ft.dswidth | ft.dsunit;
> > + printf("x.dsize = %lu\n",(long unsigned int)x.dsize);
>
> drop the debug printf
>
> > + dblocks = DTOBT(x.dsize);
>
> maybe best to just:
>
> dblocks = x.dsize >> (blocklog - BBSHIFT);
>
> > + calc_default_ag_geometry(blocklog, dblocks, multidisk,
> > + agsize, agcount);
>
> general whitespace problems above; use tabs not spaces please,
> as appropriate.
>
> > +
> > + return(blocklog);
>
> while we're at it it'd be nice to make return not a function;
> just "return blocklog;"
>
> > +}
> > diff --git a/repair/Makefile b/repair/Makefile
> > index 251722b..d24ab1f 100644
> > --- a/repair/Makefile
> > +++ b/repair/Makefile
> > @@ -20,8 +20,8 @@ CFILES = agheader.c attr_repair.c avl.c avl64.c bmap.c btree.c \
> > progress.c prefetch.c rt.c sb.c scan.c threads.c \
> > versions.c xfs_repair.c
> >
> > -LLDLIBS = $(LIBXFS) $(LIBXLOG) $(LIBUUID) $(LIBRT) $(LIBPTHREAD)
> > -LTDEPENDENCIES = $(LIBXFS) $(LIBXLOG)
> > +LLDLIBS = $(LIBBLKID) $(LIBXFS) $(LIBXLOG) $(LIBUUID) $(LIBRT) $(LIBPTHREAD) $(LIBXCMD)
> > +LTDEPENDENCIES = $(LIBXFS) $(LIBXLOG) $(LIBXCMD)
> > LLDFLAGS = -static-libtool-libs
> >
> > default: depend $(LTCOMMAND)
> > diff --git a/repair/phase1.c b/repair/phase1.c
> > index 126d0b3..c27033d 100644
> > --- a/repair/phase1.c
> > +++ b/repair/phase1.c
> > @@ -21,6 +21,7 @@
> > #include "agheader.h"
> > #include "protos.h"
> > #include "err_protos.h"
> > +#include "libxcmd.h"
> >
> > static void
> > no_sb(void)
> > @@ -47,6 +48,9 @@ alloc_ag_buf(int size)
> > */
> > #define MAX_SECTSIZE (512 * 1024)
> >
> > +extern libxfs_init_t x;
>
> It would be better to
>
> #include "libxlog.h"
>
> after the inclusion of libxfs.h at the top of this file, and you won't
> need this extern. That's how the main file/function gets "x" for
> xfs_repair. but actually, see more below.
>
> > +
> > +
> > /* ARGSUSED */
> > void
> > phase1(xfs_mount_t *mp)
> > @@ -54,6 +58,10 @@ phase1(xfs_mount_t *mp)
> > xfs_sb_t *sb;
> > char *ag_bp;
> > int rval;
> > + int blocklog;
> > + __uint64_t agcount;
> > + __uint64_t agsize;
> > + __uint64_t skipsize;
> >
> > do_log(_("Phase 1 - find and verify superblock...\n"));
> >
> > @@ -65,6 +73,18 @@ phase1(xfs_mount_t *mp)
> > lost_quotas = 0;
> >
> > /*
> > + * divine the geometry
> > + */
> > + blocklog = guess_default_geometry(&agsize, &agcount, x);
> > +
> > + /*
> > + * use found ag geometry to quickly find secondary sb
> > + */
> > + skipsize = agsize << blocklog;
> > + do_log("agsize = %d agcount = %d skipsize = %d\n",
> > + (int)agsize, (int)agcount, (int)skipsize);
>
> Since this is just a guess, I wouldn't log. It may well
> print out geometry that is not correct, and that would be confusing.
>
> And actually - looking at how you have refactored find_secondary_sb(),
> you can move the above 12 or so lines into find_secondary_sb(),
> and you don't need to pre-compute skipsize etc here. You can do it
> all in find_secondary_sb() when it gets called.
>
> Then this file (phase1.c) can be completely unchanged, and all the
> magic happens in repair/sb.c.
>
> > +
> > + /*
> > * get AG 0 into ag header buf
> > */
> > ag_bp = alloc_ag_buf(MAX_SECTSIZE);
> > @@ -80,14 +100,15 @@ phase1(xfs_mount_t *mp)
> > if (rval != XR_OK) {
> > do_warn(_("bad primary superblock - %s !!!\n"),
> > err_string(rval));
> > - if (!find_secondary_sb(sb))
> > +
> > + if (!find_secondary_sb(sb, skipsize))
> > no_sb();
> > primary_sb_modified = 1;
> > } else if ((rval = verify_set_primary_sb(sb, 0,
> > &primary_sb_modified)) != XR_OK) {
> > do_warn(_("couldn't verify primary superblock - %s !!!\n"),
> > err_string(rval));
> > - if (!find_secondary_sb(sb))
> > + if (!find_secondary_sb(sb, skipsize))
> > no_sb();
> > primary_sb_modified = 1;
> > }
> > diff --git a/repair/protos.h b/repair/protos.h
> > index 9d5a2a6..d96373e 100644
> > --- a/repair/protos.h
> > +++ b/repair/protos.h
> > @@ -31,7 +31,7 @@ int get_sb(xfs_sb_t *sbp,
> > void write_primary_sb(xfs_sb_t *sbp,
> > int size);
> >
> > -int find_secondary_sb(xfs_sb_t *sb);
> > +int find_secondary_sb(xfs_sb_t *sb, __uint64_t skipsize);
>
> this would be unchanged as well.
>
> >
> > struct fs_geometry;
> > void get_sb_geometry(struct fs_geometry *geo,
> > diff --git a/repair/sb.c b/repair/sb.c
> > index 4eef14a..4386479 100644
> > --- a/repair/sb.c/d
> > +++ b/repair/sb.c
> > @@ -87,8 +87,7 @@ copy_sb(xfs_sb_t *source, xfs_sb_t *dest)
> > /*
> > * find a secondary superblock, copy it into the sb buffer
>
> It'd be good to document "skipsize" here - units, and purpose.
>
> > */
> > -int
> > -find_secondary_sb(xfs_sb_t *rsb)
> > +static int __find_secondary_sb(xfs_sb_t *rsb, __uint64_t skipsize )
>
> no space between skipsize and ")" please.
>
> > {
> > xfs_off_t off;
> > xfs_sb_t *sb;
> > @@ -101,7 +100,6 @@ find_secondary_sb(xfs_sb_t *rsb)
> > int bsize;
> >
> > do_warn(_("\nattempting to find secondary superblock...\n"));
> > -
> > sb = (xfs_sb_t *)memalign(libxfs_device_alignment(), BSIZE);
> > if (!sb) {
> > do_error(
> > @@ -117,7 +115,7 @@ find_secondary_sb(xfs_sb_t *rsb)
> > /*
> > * skip first sector since we know that's bad
> > */
> > - for (done = 0, off = XFS_AG_MIN_BYTES; !done ; off += bsize) {
> > + for (done = 0, off = skipsize; !done ; off += bsize) {
>
> Ok, so you jump out "skipsize" for the first read, but after that you
> only move the offset by bsize, which is BSIZE (or 1MB).
>
> That works OK if the 2nd superblock (at skipsize) is OK, but if it's
> not, you'll start from there doing smaller reads like before, and
> then this loop isn't really any more efficient than it was.
>
> If skipsize is set, you need to start out 1x skipsize, then read
> at 2x skipsize, 3x skipsize, etc. So you need to change the
> loop increment as well.
>
> i.e. fast path: start at skipsize, advance by skipsize each loop
>
> slow path: start at XFS_AG_MIN_BYTES, advance by BSIZE each loop
>
> If you make a 4t sparse file, mkfs it, and corrupt the first *2*
> superblocks, then point repair at it you'll see what I mean.
>
> > /*
> > * read disk 1 MByte at a time.
> > */
> > @@ -130,7 +128,6 @@ find_secondary_sb(xfs_sb_t *rsb)
> > }
> >
> > do_warn(".");
> > -
> > /*
> > * check the buffer 512 bytes at a time since
> > * we don't know how big the sectors really are.
> > @@ -164,11 +161,29 @@ find_secondary_sb(xfs_sb_t *rsb)
> > }
> > }
> > }
> > -
> > free(sb);
> > return(retval);
> > }
> >
> > +int
> > +find_secondary_sb(xfs_sb_t *rsb, __uint64_t skipsize)
> > +{
> > + int retval;
> > +
> > + /*
> > + * Attempt to find secondary sb with a coarse approach,
> > + * using a large skipsize (agsize in bytes). Failing that,
> > + * fallback to the fine-grained approach using min agsize.
> > + */
> > + retval = __find_secondary_sb(rsb, skipsize);
> > + if (!retval)
>
> With the comment below, it's safest to wrap these multiple lines after
> the conditional in { .... }
>
> > + /*
> > + * fallback: use minimum agsize for skipsize
> > + */
> > + retval = __find_secondary_sb(rsb, XFS_AG_MIN_BYTES);
> > + return(retval);
>
> again drop the () on the return, please.
>
> > +}
> > +
> > /*
> > * Calculate what the inode alignment field ought to be based on internal
> > * superblock info and determine if it is valid.
> >
>
> _______________________________________________
> xfs mailing list
> xfs at oss.sgi.com
> http://oss.sgi.com/mailman/listinfo/xfs
More information about the xfs
mailing list