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

Bill O'Donnell
2016-02-10T01:35:02Z

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@redhat.com>
---
Makefile | 2 +-
include/libxcmd.h | 4 +++-
libxcmd/topology.c | 35 ++++++++++++++++++++++++++++----
repair/Makefile | 4 ++--
repair/sb.c | 58 ++++++++++++++++++++++++++++++++++++++++++++----------
5 files changed, 85 insertions(+), 18 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..b98d9b9 100644
--- a/libxcmd/topology.c
+++ b/libxcmd/topology.c
@@ -192,7 +192,8 @@ out:
return ret;
}

-static void blkid_get_topology(
+static void
+blkid_get_topology(
const char *device,
int *sunit,
int *swidth,
@@ -284,7 +285,8 @@ check_overwrite(
return 1;
}

-static void blkid_get_topology(
+static void
+blkid_get_topology(
const char *device,
int *sunit,
int *swidth,
@@ -302,8 +304,8 @@ static void blkid_get_topology(

#endif /* ENABLE_BLKID */

-
-void get_topology(
+void
+get_topology(
libxfs_init_t *xi,
struct fs_topology *ft,
int force_overwrite)
@@ -346,3 +348,28 @@ void get_topology(
&lsectorsize, &psectorsize, force_overwrite);
}
}
+
+int
+guess_default_geometry(__uint64_t *agsize, __uint64_t *agcount,
+ libxfs_init_t x)
+{
+ struct fs_topology ft;
+ int blocklog;
+ __uint64_t dblocks;
+ int multidisk;
+
+ memset(&ft, 0, sizeof(ft));
+ get_topology(&x, &ft, 1);
+
+ /*
+ * get geometry from get_topology result.
+ * Use default block size (2^12)
+ */
+ blocklog = 12;
+ multidisk = ft.dswidth | ft.dsunit;
+ dblocks = x.dsize >> (blocklog - BBSHIFT);
+ calc_default_ag_geometry(blocklog, dblocks, multidisk,
+ agsize, agcount);
+
+ 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/sb.c b/repair/sb.c
index 4eef14a..8bc246e 100644
--- a/repair/sb.c
+++ b/repair/sb.c
@@ -22,6 +22,7 @@
#include "globals.h"
#include "protos.h"
#include "err_protos.h"
+#include "libxcmd.h"

#define BSIZE (1024 * 1024)

@@ -85,10 +86,11 @@ copy_sb(xfs_sb_t *source, xfs_sb_t *dest)
}

/*
- * find a secondary superblock, copy it into the sb buffer
+ * find a secondary superblock, copy it into the sb buffer.
+ * skipsize units is bytes, it contains either the agsize in bytes
+ * (if known), or the minimum agsize in bytes if agsize unknown.
*/
-int
-find_secondary_sb(xfs_sb_t *rsb)
+static int __find_secondary_sb(xfs_sb_t *rsb, __uint64_t skipsize)
{
xfs_off_t off;
xfs_sb_t *sb;
@@ -99,9 +101,9 @@ find_secondary_sb(xfs_sb_t *rsb)
int dirty;
int retval;
int bsize;
+ int readsize;

do_warn(_("\nattempting to find secondary superblock...\n"));
-
sb = (xfs_sb_t *)memalign(libxfs_device_alignment(), BSIZE);
if (!sb) {
do_error(
@@ -113,13 +115,16 @@ find_secondary_sb(xfs_sb_t *rsb)
retval = 0;
dirty = 0;
bsize = 0;
+ readsize = 0;

/*
* 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 += readsize) {
/*
- * read disk 1 MByte at a time.
+ * read disk using readsize interval
+ * (either the bytecount of actual agsize or bsize if
+ * agsize undetermined.)
*/
if (lseek64(x.dfd, off, SEEK_SET) != off) {
done = 1;
@@ -128,9 +133,13 @@ find_secondary_sb(xfs_sb_t *rsb)
if (!done && (bsize = read(x.dfd, sb, BSIZE)) <= 0) {
done = 1;
}
-
+ if (skipsize == XFS_AG_MIN_BYTES) {
+ readsize = bsize;
+ }
+ else {
+ readsize = skipsize;
+ }
do_warn(".");
-
/*
* check the buffer 512 bytes at a time since
* we don't know how big the sectors really are.
@@ -164,9 +173,38 @@ find_secondary_sb(xfs_sb_t *rsb)
}
}
}
-
free(sb);
- return(retval);
+ return retval;
+}
+
+int
+find_secondary_sb(xfs_sb_t *rsb)
+{
+ int retval;
+ __uint64_t skipsize;
+ __uint64_t agcount;
+ __uint64_t agsize;
+ int blocklog;
+
+ /*
+ * 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.
+ */
+ blocklog = guess_default_geometry(&agsize, &agcount, x);
+
+ /*
+ * use found ag geometry to quickly find secondary sb
+ */
+ skipsize = agsize << blocklog;
+ retval = __find_secondary_sb(rsb, skipsize);
+ if (!retval) {
+ /*
+ * fallback: use minimum agsize for skipsize
+ */
+ retval = __find_secondary_sb(rsb, XFS_AG_MIN_BYTES);
+ }
+ return retval;
}

/*
--
2.5.0