]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_repair: further improvement on secondary superblock search method
authorBill O'Donnell <billodo@redhat.com>
Fri, 3 Jun 2016 01:04:03 +0000 (11:04 +1000)
committerDave Chinner <david@fromorbit.com>
Fri, 3 Jun 2016 01:04:03 +0000 (11:04 +1000)
This patch is a further optimization of secondary sb search, in
order to handle non-default geometries. Once again, use a similar
method to find fs geometry as that of xfs_mkfs. Refactor
verify_sb(), creating new sub-function that checks sanity of
agblocks and agcount: verify_sb_blocksize().

If verify_sb_blocksize verifies sane paramters, use found values for
the sb search. Otherwise, try search with default values. If these
faster methods both fail, fall back to original brute force slower
search.

Signed-off-by: Bill O'Donnell <billodo@redhat.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
repair/sb.c

index 7e4708c164462296494ad733632cb09683fc7992..39659532d57c67b3da7573f79ee04b04d781c42a 100644 (file)
 #include "globals.h"
 #include "protos.h"
 #include "err_protos.h"
+#include "xfs_multidisk.h"
 
 #define BSIZE  (1024 * 1024)
 
-#define XFS_AG_BYTES(bblog)    ((long long)BBSIZE << (bblog))
-#define        XFS_AG_MIN_BYTES        ((XFS_AG_BYTES(15)))    /* 16 MB */
-
 /*
  * copy the fields of a superblock that are present in primary and
  * secondaries -- preserve fields that are different in the primary.
@@ -85,6 +83,21 @@ copy_sb(xfs_sb_t *source, xfs_sb_t *dest)
        memset(source->sb_fname, 0, 12);
 }
 
+int
+verify_sb_blocksize(xfs_sb_t *sb)
+{
+       /* check to make sure blocksize is legal 2^N, 9 <= N <= 16 */
+       if (sb->sb_blocksize == 0)
+               return XR_BAD_BLOCKSIZE;
+       if (sb->sb_blocksize != (1 << sb->sb_blocklog))
+               return XR_BAD_BLOCKLOG;
+       if (sb->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG ||
+           sb->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG)
+               return XR_BAD_BLOCKLOG;
+
+       return 0;
+}
+
 /*
  * find a secondary superblock, copy it into the sb buffer.
  * start is the point to begin reading BSIZE bytes.
@@ -106,8 +119,6 @@ __find_secondary_sb(
        int             retval;
        int             bsize;
 
-       do_warn(_("\nattempting to find secondary superblock...\n"));
-
        sb = (xfs_sb_t *)memalign(libxfs_device_alignment(), BSIZE);
        if (!sb) {
                do_error(
@@ -205,29 +216,36 @@ guess_default_geometry(
 int
 find_secondary_sb(xfs_sb_t *rsb)
 {
-       int             retval;
+       int             retval = 0;
        __uint64_t      agcount;
        __uint64_t      agsize;
        __uint64_t      skip;
        int             blocklog;
 
        /*
-        * Attempt to find secondary sb with a coarse approach.
-        * Failing that, fallback to a fine-grained approach.
+        * Attempt to find secondary sb with a coarse approach,
+        * first trying agblocks and blocksize read from sb, providing
+        * they're sane.
         */
-       blocklog = guess_default_geometry(&agsize, &agcount, &x);
+       do_warn(_("\nattempting to find secondary superblock...\n"));
 
-       /*
-        * use found ag geometry to quickly find secondary sb
-        */
-       skip = agsize << blocklog;
-       retval = __find_secondary_sb(rsb, skip, skip);
-       if (!retval)  {
-               /*
-                * fallback: Start at min agsize and scan all blocks
-                */
-               retval = __find_secondary_sb(rsb, XFS_AG_MIN_BYTES, BSIZE);
+       if (verify_sb_blocksize(rsb) == 0) {
+               skip = rsb->sb_agblocks * rsb->sb_blocksize;
+               if (skip >= XFS_AG_MIN_BYTES && skip <= XFS_AG_MAX_BYTES)
+                       retval = __find_secondary_sb(rsb, skip, skip);
        }
+
+        /* If that failed, retry coarse approach, using default geometry */
+        if (!retval) {
+                blocklog = guess_default_geometry(&agsize, &agcount, &x);
+                skip = agsize << blocklog;
+                retval = __find_secondary_sb(rsb, skip, skip);
+        }
+
+        /* If that failed, fall back to the brute force method */
+        if (!retval)
+                retval = __find_secondary_sb(rsb, XFS_AG_MIN_BYTES, BSIZE);
+
        return retval;
 }
 
@@ -328,6 +346,7 @@ verify_sb(char *sb_buf, xfs_sb_t *sb, int is_primary_sb)
 {
        __uint32_t      bsize;
        int             i;
+       int             ret;
 
        /* check magic number and version number */
 
@@ -369,23 +388,10 @@ verify_sb(char *sb_buf, xfs_sb_t *sb, int is_primary_sb)
            !xfs_verify_cksum(sb_buf, sb->sb_sectsize, XFS_SB_CRC_OFF))
                return XR_BAD_CRC;
 
-       /* check to make sure blocksize is legal 2^N, 9 <= N <= 16 */
-       if (sb->sb_blocksize == 0)
-               return(XR_BAD_BLOCKSIZE);
-
-       bsize = 1;
-
-       for (i = 0; bsize < sb->sb_blocksize &&
-               i < sizeof(sb->sb_blocksize) * NBBY; i++)
-               bsize <<= 1;
-
-       if (i < XFS_MIN_BLOCKSIZE_LOG || i > XFS_MAX_BLOCKSIZE_LOG)
-               return(XR_BAD_BLOCKSIZE);
-
-       /* check sb blocksize field against sb blocklog field */
-
-       if (i != sb->sb_blocklog)
-               return(XR_BAD_BLOCKLOG);
+       /* check to ensure blocksize and blocklog are legal */
+       ret = verify_sb_blocksize(sb);
+       if (ret != 0)
+               return ret;
 
        /* sanity check ag count, size fields against data size field */