Re: [PATCH 2/2] xfs_repair: new secondary superblock search method

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

 



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@xxxxxxxxxx>
> ---
>  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.

> +	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@xxxxxxxxxxx
http://oss.sgi.com/mailman/listinfo/xfs



[Index of Archives]     [Linux XFS Devel]     [Linux Filesystem Development]     [Filesystem Testing]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux