Blob Blame History Raw
diff --git a/copy/Makefile b/copy/Makefile
index 54f6dfb..beabbd4 100644
--- a/copy/Makefile
+++ b/copy/Makefile
@@ -11,7 +11,7 @@ HFILES = xfs_copy.h
 
 LLDLIBS = $(LIBXFS) $(LIBUUID) $(LIBPTHREAD) $(LIBRT)
 LTDEPENDENCIES = $(LIBXFS)
-LLDFLAGS = -static
+LLDFLAGS = -static-libtool-libs
 
 default: depend $(LTCOMMAND)
 
diff --git a/db/Makefile b/db/Makefile
index bae6154..fb01bdd 100644
--- a/db/Makefile
+++ b/db/Makefile
@@ -18,7 +18,7 @@ LSRCFILES = xfs_admin.sh xfs_ncheck.sh xfs_metadump.sh
 
 LLDLIBS	= $(LIBXFS) $(LIBXLOG) $(LIBUUID) $(LIBRT) $(LIBPTHREAD)
 LTDEPENDENCIES = $(LIBXFS) $(LIBXLOG)
-LLDFLAGS += -static
+LLDFLAGS += -static-libtool-libs
 
 ifeq ($(ENABLE_READLINE),yes)
 LLDLIBS += $(LIBREADLINE) $(LIBTERMCAP)
diff --git a/db/check.c b/db/check.c
index 4fd9fd0..c4c972f 100644
--- a/db/check.c
+++ b/db/check.c
@@ -1832,7 +1832,13 @@ init(
 	error = sbver_err = serious_error = 0;
 	fdblocks = frextents = icount = ifree = 0;
 	sbversion = XFS_SB_VERSION_4;
-	if (mp->m_sb.sb_inoalignmt)
+	/*
+	 * Note that inoalignmt == 0 is valid when fsb size is large enough for
+	 * at least one full inode record per block. Check this case explicitly.
+	 */
+	if (mp->m_sb.sb_inoalignmt ||
+	    (xfs_sb_version_hasalign(&mp->m_sb) &&
+	     mp->m_sb.sb_inopblock >= XFS_INODES_PER_CHUNK))
 		sbversion |= XFS_SB_VERSION_ALIGNBIT;
 	if ((mp->m_sb.sb_uquotino && mp->m_sb.sb_uquotino != NULLFSINO) ||
 	    (mp->m_sb.sb_gquotino && mp->m_sb.sb_gquotino != NULLFSINO) ||
diff --git a/db/inode.c b/db/inode.c
index 24170ba..dfefbf5 100644
--- a/db/inode.c
+++ b/db/inode.c
@@ -369,7 +369,7 @@ inode_core_nlinkv2_count(
 	ASSERT(startoff == 0);
 	ASSERT(obj == iocur_top->data);
 	dic = obj;
-	return dic->di_version == 2;
+	return dic->di_version >= 2;
 }
 
 static int
@@ -382,7 +382,7 @@ inode_core_onlink_count(
 	ASSERT(startoff == 0);
 	ASSERT(obj == iocur_top->data);
 	dic = obj;
-	return dic->di_version == 2;
+	return dic->di_version >= 2;
 }
 
 static int
@@ -395,7 +395,7 @@ inode_core_projid_count(
 	ASSERT(startoff == 0);
 	ASSERT(obj == iocur_top->data);
 	dic = obj;
-	return dic->di_version == 2;
+	return dic->di_version >= 2;
 }
 
 static int
@@ -684,13 +684,22 @@ set_cur_inode(
 		numblks, DB_RING_IGN, NULL);
 	off_cur(offset << mp->m_sb.sb_inodelog, mp->m_sb.sb_inodesize);
 	dip = iocur_top->data;
-	iocur_top->ino_crc_ok = libxfs_dinode_verify(mp, ino, dip);
 	iocur_top->ino_buf = 1;
 	iocur_top->ino = ino;
 	iocur_top->mode = be16_to_cpu(dip->di_mode);
 	if ((iocur_top->mode & S_IFMT) == S_IFDIR)
 		iocur_top->dirino = ino;
 
+	if (xfs_sb_version_hascrc(&mp->m_sb)) {
+		iocur_top->ino_crc_ok = libxfs_verify_cksum((char *)dip,
+						    mp->m_sb.sb_inodesize,
+						    XFS_DINODE_CRC_OFF);
+		if (!iocur_top->ino_crc_ok)
+			dbprintf(
+_("Metadata CRC error detected for ino %lld\n"),
+				ino);
+	}
+
 	/* track updated info in ring */
 	ring_add();
 }
diff --git a/db/io.c b/db/io.c
index 7f1b76a..d906123 100644
--- a/db/io.c
+++ b/db/io.c
@@ -457,6 +457,13 @@ write_cur_bbs(void)
 }
 
 void
+xfs_dummy_verify(
+	struct xfs_buf *bp)
+{
+	return;
+}
+
+void
 write_cur(void)
 {
 	if (iocur_sp < 0) {
@@ -464,8 +471,10 @@ write_cur(void)
 		return;
 	}
 
-	if (iocur_top->ino_buf)
+	if (xfs_sb_version_hascrc(&mp->m_sb) && iocur_top->ino_buf) {
 		libxfs_dinode_calc_crc(mp, iocur_top->data);
+		iocur_top->ino_crc_ok = 1;
+	}
 	if (iocur_top->dquot_buf)
 		xfs_update_cksum(iocur_top->data, sizeof(struct xfs_dqblk),
 				 XFS_DQUOT_CRC_OFF);
diff --git a/db/io.h b/db/io.h
index 71082e6..31d96b4 100644
--- a/db/io.h
+++ b/db/io.h
@@ -63,6 +63,7 @@ extern void	set_cur(const struct typ *t, __int64_t d, int c, int ring_add,
 			bbmap_t *bbmap);
 extern void     ring_add(void);
 extern void	set_iocur_type(const struct typ *t);
+extern void	xfs_dummy_verify(struct xfs_buf *bp);
 
 /*
  * returns -1 for unchecked, 0 for bad and 1 for good
diff --git a/db/metadump.c b/db/metadump.c
index 38cd441..a599571 100644
--- a/db/metadump.c
+++ b/db/metadump.c
@@ -1865,6 +1865,7 @@ copy_inode_chunk(
 			(mp->m_sb.sb_inopblock > XFS_INODES_PER_CHUNK &&
 					off % XFS_INODES_PER_CHUNK != 0) ||
 			(xfs_sb_version_hasalign(&mp->m_sb) &&
+					mp->m_sb.sb_inoalignmt != 0 &&
 					agbno % mp->m_sb.sb_inoalignmt != 0)) {
 		if (show_warnings)
 			print_warning("badly aligned inode (start = %llu)",
@@ -2112,7 +2113,7 @@ copy_ino(
 	int			offset;
 	int			rval = 0;
 
-	if (ino == 0)
+	if (ino == 0 || ino == NULLFSINO)
 		return 1;
 
 	agno = XFS_INO_TO_AGNO(mp, ino);
diff --git a/db/sb.c b/db/sb.c
index 6cb665d..974abd2 100644
--- a/db/sb.c
+++ b/db/sb.c
@@ -363,6 +363,18 @@ uuid_f(
 			return 0;
 		}
 
+		/*
+		 * For now, changing the UUID of V5 superblock filesystems is
+		 * not supported; we do not have the infrastructure to fix all
+		 * other metadata when a new superblock UUID is generated.
+		 */
+		if (xfs_sb_version_hascrc(&mp->m_sb) &&
+		    strcasecmp(argv[1], "rewrite")) {
+			dbprintf(_("%s: only 'rewrite' supported on V5 fs\n"),
+				progname);
+			return 0;
+		}
+
 		if (!strcasecmp(argv[1], "generate")) {
 			platform_uuid_generate(&uu);
 		} else if (!strcasecmp(argv[1], "nil")) {
@@ -646,6 +658,8 @@ version_string(
 		strcat(s, ",CRC");
 	if (xfs_sb_version_hasftype(sbp))
 		strcat(s, ",FTYPE");
+	if (xfs_sb_version_hasfinobt(sbp))
+		strcat(s, ",FINOBT");
 	return s;
 }
 
diff --git a/db/write.c b/db/write.c
index a0f14f4..655b618 100644
--- a/db/write.c
+++ b/db/write.c
@@ -38,7 +38,7 @@ static int	write_f(int argc, char **argv);
 static void     write_help(void);
 
 static const cmdinfo_t	write_cmd =
-	{ "write", NULL, write_f, 0, -1, 0, N_("[field or value]..."),
+	{ "write", NULL, write_f, 0, -1, 0, N_("[-c] [field or value]..."),
 	  N_("write value to disk"), write_help };
 
 void
@@ -79,6 +79,7 @@ write_help(void)
 "  String mode: 'write \"This_is_a_filename\" - write null terminated string.\n"
 "\n"
 " In data mode type 'write' by itself for a list of specific commands.\n\n"
+" Specifying the -c option will allow writes of invalid (corrupt) data.\n\n"
 ));
 
 }
@@ -90,6 +91,10 @@ write_f(
 {
 	pfunc_t	pf;
 	extern char *progname;
+	int c;
+	int corrupt = 0;		/* Allow write of corrupt data; skip verification */
+	struct xfs_buf_ops nowrite_ops;
+	const struct xfs_buf_ops *stashed_ops = NULL;
 
 	if (x.isreadonly & LIBXFS_ISREADONLY) {
 		dbprintf(_("%s started in read only mode, writing disabled\n"),
@@ -109,12 +114,34 @@ write_f(
 		return 0;
 	}
 
-	/* move past the "write" command */
-	argc--;
-	argv++;
+	while ((c = getopt(argc, argv, "c")) != EOF) {
+		switch (c) {
+		case 'c':
+			corrupt = 1;
+			break;
+		default:
+			dbprintf(_("bad option for write command\n"));
+			return 0;
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	if (iocur_top->bp->b_ops && corrupt) {
+		/* Temporarily remove write verifier to write bad data */
+		stashed_ops = iocur_top->bp->b_ops;
+		nowrite_ops.verify_read = stashed_ops->verify_read;
+		nowrite_ops.verify_write = xfs_dummy_verify;
+		iocur_top->bp->b_ops = &nowrite_ops;
+		dbprintf(_("Allowing write of corrupted data\n"));
+	}
 
 	(*pf)(DB_WRITE, cur_typ->fields, argc, argv);
 
+	if (stashed_ops)
+		iocur_top->bp->b_ops = stashed_ops;
+
 	return 0;
 }
 
diff --git a/growfs/Makefile b/growfs/Makefile
index 88cbf4f..19616de 100644
--- a/growfs/Makefile
+++ b/growfs/Makefile
@@ -19,7 +19,7 @@ LLDLIBS += $(LIBEDITLINE) $(LIBTERMCAP)
 endif
 
 LTDEPENDENCIES = $(LIBXFS) $(LIBXCMD)
-LLDFLAGS = -static
+LLDFLAGS = -static-libtool-libs
 LSRCFILES = xfs_info.sh
 
 default: depend $(LTCOMMAND)
diff --git a/include/builddefs.in b/include/builddefs.in
index 944bcf6..7e9f53d 100644
--- a/include/builddefs.in
+++ b/include/builddefs.in
@@ -109,7 +109,7 @@ GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall
 #	   -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-decl
 
 ifeq ($(PKG_PLATFORM),linux)
-PCFLAGS = -D_GNU_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=500 -D_FILE_OFFSET_BITS=64 $(GCCFLAGS)
+PCFLAGS = -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 $(GCCFLAGS)
 ifeq ($(HAVE_UMODE_T),yes)
 PCFLAGS += -DHAVE_UMODE_T
 endif
diff --git a/include/handle.h b/include/handle.h
index b211a2f..ee69a11 100644
--- a/include/handle.h
+++ b/include/handle.h
@@ -28,6 +28,7 @@ struct parent;
 
 extern int  path_to_handle (char *__path, void **__hanp, size_t *__hlen);
 extern int  path_to_fshandle (char *__path, void **__fshanp, size_t *__fshlen);
+extern int  fd_to_handle (int fd, void **hanp, size_t *hlen);
 extern int  handle_to_fshandle (void *__hanp, size_t __hlen, void **__fshanp,
 				size_t *__fshlen);
 extern void free_handle (void *__hanp, size_t __hlen);
diff --git a/include/libxfs.h b/include/libxfs.h
index 45a924f..962e319 100644
--- a/include/libxfs.h
+++ b/include/libxfs.h
@@ -782,6 +782,8 @@ extern uint32_t crc32c_le(uint32_t crc, unsigned char const *p, size_t len);
 
 #include <xfs/xfs_cksum.h>
 
+#define libxfs_verify_cksum	xfs_verify_cksum
+
 static inline int
 xfs_buf_verify_cksum(struct xfs_buf *bp, unsigned long cksum_offset)
 {
diff --git a/include/xfs_da_format.h b/include/xfs_da_format.h
index 89a1a21..11f1420 100644
--- a/include/xfs_da_format.h
+++ b/include/xfs_da_format.h
@@ -561,7 +561,6 @@ xfs_dir3_dirent_get_ftype(
 	if (xfs_sb_version_hasftype(&mp->m_sb)) {
 		__uint8_t	type = dep->name[dep->namelen];
 
-		ASSERT(type < XFS_DIR3_FT_MAX);
 		if (type < XFS_DIR3_FT_MAX)
 			return type;
 
diff --git a/include/xfs_dir2.h b/include/xfs_dir2.h
index 3900130..2d41c5f 100644
--- a/include/xfs_dir2.h
+++ b/include/xfs_dir2.h
@@ -100,6 +100,8 @@ extern void xfs_dir2_data_use_free(struct xfs_trans *tp, struct xfs_buf *bp,
 extern struct xfs_dir2_data_free *xfs_dir2_data_freefind(
 		struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_data_unused *dup);
 
+extern int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino);
+
 extern const struct xfs_buf_ops xfs_dir3_block_buf_ops;
 extern const struct xfs_buf_ops xfs_dir3_leafn_buf_ops;
 extern const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops;
diff --git a/include/xfs_types.h b/include/xfs_types.h
index 65c6e66..accb95d 100644
--- a/include/xfs_types.h
+++ b/include/xfs_types.h
@@ -100,11 +100,14 @@ typedef __uint64_t	xfs_filblks_t;	/* number of blocks in a file */
  * Minimum and maximum blocksize and sectorsize.
  * The blocksize upper limit is pretty much arbitrary.
  * The sectorsize upper limit is due to sizeof(sb_sectsize).
+ * CRC enable filesystems use 512 byte inodes, meaning 512 byte block sizes
+ * cannot be used.
  */
 #define XFS_MIN_BLOCKSIZE_LOG	9	/* i.e. 512 bytes */
 #define XFS_MAX_BLOCKSIZE_LOG	16	/* i.e. 65536 bytes */
 #define XFS_MIN_BLOCKSIZE	(1 << XFS_MIN_BLOCKSIZE_LOG)
 #define XFS_MAX_BLOCKSIZE	(1 << XFS_MAX_BLOCKSIZE_LOG)
+#define XFS_MIN_CRC_BLOCKSIZE	(1 << (XFS_MIN_BLOCKSIZE_LOG + 1))
 #define XFS_MIN_SECTORSIZE_LOG	9	/* i.e. 512 bytes */
 #define XFS_MAX_SECTORSIZE_LOG	15	/* i.e. 32768 bytes */
 #define XFS_MIN_SECTORSIZE	(1 << XFS_MIN_SECTORSIZE_LOG)
diff --git a/io/Makefile b/io/Makefile
index 82593a6..a08a782 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -15,7 +15,7 @@ CFILES = init.c \
 
 LLDLIBS = $(LIBXCMD) $(LIBHANDLE)
 LTDEPENDENCIES = $(LIBXCMD) $(LIBHANDLE)
-LLDFLAGS = -static
+LLDFLAGS = -static-libtool-libs
 
 ifeq ($(HAVE_FADVISE),yes)
 CFILES += fadvise.c
diff --git a/io/prealloc.c b/io/prealloc.c
index aba6b44..4ab3d8c 100644
--- a/io/prealloc.c
+++ b/io/prealloc.c
@@ -37,6 +37,10 @@
 #define FALLOC_FL_ZERO_RANGE 0x10
 #endif
 
+#ifndef FALLOC_FL_INSERT_RANGE
+#define FALLOC_FL_INSERT_RANGE 0x20
+#endif
+
 static cmdinfo_t allocsp_cmd;
 static cmdinfo_t freesp_cmd;
 static cmdinfo_t resvsp_cmd;
@@ -46,6 +50,7 @@ static cmdinfo_t zero_cmd;
 static cmdinfo_t falloc_cmd;
 static cmdinfo_t fpunch_cmd;
 static cmdinfo_t fcollapse_cmd;
+static cmdinfo_t finsert_cmd;
 static cmdinfo_t fzero_cmd;
 #endif
 
@@ -169,11 +174,14 @@ fallocate_f(
 	int		mode = 0;
 	int		c;
 
-	while ((c = getopt(argc, argv, "ckp")) != EOF) {
+	while ((c = getopt(argc, argv, "cikp")) != EOF) {
 		switch (c) {
 		case 'c':
 			mode = FALLOC_FL_COLLAPSE_RANGE;
 			break;
+		case 'i':
+			mode = FALLOC_FL_INSERT_RANGE;
+			break;
 		case 'k':
 			mode = FALLOC_FL_KEEP_SIZE;
 			break;
@@ -237,6 +245,25 @@ fcollapse_f(
 }
 
 static int
+finsert_f(
+	int		argc,
+	char		**argv)
+{
+	xfs_flock64_t	segment;
+	int		mode = FALLOC_FL_INSERT_RANGE;
+
+	if (!offset_length(argv[1], argv[2], &segment))
+		return 0;
+
+	if (fallocate(file->fd, mode,
+			segment.l_start, segment.l_len)) {
+		perror("fallocate");
+		return 0;
+	}
+	return 0;
+}
+
+static int
 fzero_f(
 	int		argc,
 	char		**argv)
@@ -345,6 +372,16 @@ prealloc_init(void)
 	_("de-allocates space and eliminates the hole by shifting extents");
 	add_command(&fcollapse_cmd);
 
+	finsert_cmd.name = "finsert";
+	finsert_cmd.cfunc = finsert_f;
+	finsert_cmd.argmin = 2;
+	finsert_cmd.argmax = 2;
+	finsert_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
+	finsert_cmd.args = _("off len");
+	finsert_cmd.oneline =
+	_("creates new space for writing within file by shifting extents");
+	add_command(&finsert_cmd);
+
 	fzero_cmd.name = "fzero";
 	fzero_cmd.cfunc = fzero_f;
 	fzero_cmd.argmin = 2;
diff --git a/libxfs/rdwr.c b/libxfs/rdwr.c
index 7d73477..35fb366 100644
--- a/libxfs/rdwr.c
+++ b/libxfs/rdwr.c
@@ -411,6 +411,7 @@ __initbuf(xfs_buf_t *bp, struct xfs_buftarg *btp, xfs_daddr_t bno,
 			strerror(errno));
 		exit(1);
 	}
+	memset(bp->b_addr, 0, bytes);
 #ifdef XFS_BUF_TRACING
 	list_head_init(&bp->b_lock_list);
 #endif
diff --git a/libxfs/util.c b/libxfs/util.c
index 9504e33..49eb76d 100644
--- a/libxfs/util.c
+++ b/libxfs/util.c
@@ -700,8 +700,6 @@ libxfs_inode_alloc(
 		if (error)
 			return error;
 	}
-	if (!ip)
-		error = ENOSPC;
 
 	*ipp = ip;
 	return error;
@@ -718,6 +716,7 @@ libxfs_fs_repair_cmn_err(int level, xfs_mount_t *mp, char *fmt, ...)
 	va_start(ap, fmt);
 	vfprintf(stderr, fmt, ap);
 	fprintf(stderr, "  This is a bug.\n");
+	fprintf(stderr, "%s version %s\n", progname, VERSION);
 	fprintf(stderr, "Please capture the filesystem metadata with "
 			"xfs_metadump and\nreport it to xfs@oss.sgi.com.\n");
 	va_end(ap);
diff --git a/libxfs/xfs_dir2_priv.h b/libxfs/xfs_dir2_priv.h
index 1bad84c..926715f 100644
--- a/libxfs/xfs_dir2_priv.h
+++ b/libxfs/xfs_dir2_priv.h
@@ -21,7 +21,6 @@
 struct dir_context;
 
 /* xfs_dir2.c */
-extern int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino);
 extern int xfs_dir2_grow_inode(struct xfs_da_args *args, int space,
 				xfs_dir2_db_t *dbp);
 extern int xfs_dir_cilookup_result(struct xfs_da_args *args,
diff --git a/logprint/Makefile b/logprint/Makefile
index 2d656a4..7bcf27f 100644
--- a/logprint/Makefile
+++ b/logprint/Makefile
@@ -14,7 +14,7 @@ CFILES = logprint.c \
 
 LLDLIBS	= $(LIBXFS) $(LIBXLOG) $(LIBUUID) $(LIBRT) $(LIBPTHREAD)
 LTDEPENDENCIES = $(LIBXFS) $(LIBXLOG)
-LLDFLAGS = -static
+LLDFLAGS = -static-libtool-libs
 
 default: depend $(LTCOMMAND)
 
diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
index 4d8d4ff..d527230 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -711,7 +711,7 @@ and
 bits respectively, and their string equivalent reported
 (but no modifications are made).
 .TP
-.BI "write [" "field value" "] ..."
+.BI "write [\-c] [" "field value" "] ..."
 Write a value to disk.
 Specific fields can be set in structures (struct mode),
 or a block can be set to data values (data mode),
@@ -729,6 +729,12 @@ contents of the block can be shifted or rotated left or right, or filled
 with a sequence, a constant value, or a random value. In this mode
 .B write
 with no arguments gives more information on the allowed commands.
+.RS 1.0i
+.TP 0.4i
+.B \-c
+Skip write verifiers and CRC recalculation; allows invalid data to be written
+to disk.
+.RE
 .SH TYPES
 This section gives the fields in each structure type and their meanings.
 Note that some types of block cover multiple actual structures,
diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8
index cf27b99..416206f 100644
--- a/man/man8/xfs_io.8
+++ b/man/man8/xfs_io.8
@@ -404,6 +404,11 @@ Call fallocate with FALLOC_FL_COLLAPSE_RANGE flag as described in the
 manual page to de-allocates blocks and eliminates the hole created in this process
 by shifting data blocks into the hole.
 .TP
+.BI finsert " offset length"
+Call fallocate with FALLOC_FL_INSERT_RANGE flag as described in the
+.BR fallocate (2)
+manual page to create the hole by shifting data blocks.
+.TP
 .BI fpunch " offset length"
 Punches (de-allocates) blocks in the file by calling fallocate with 
 the FALLOC_FL_PUNCH_HOLE flag as described in the
diff --git a/man/man8/xfs_quota.8 b/man/man8/xfs_quota.8
index 8cc8ab7..9b555e9 100644
--- a/man/man8/xfs_quota.8
+++ b/man/man8/xfs_quota.8
@@ -324,7 +324,7 @@ path to the
 list entry (the current path is used by many
 of the commands described here, it identifies the filesystem toward
 which a command is directed).
-The patch list can come from several places \- the command line,
+The path list can come from several places \- the command line,
 the mount table, and the
 .I /etc/projects
 file.
@@ -565,12 +565,7 @@ instead of stdout.
 .I name
 ]
 .br
-Without arguments, this command lists known project names and identifiers
-(based on entries in the
-.I /etc/projects
-and
-.I /etc/projid
-files). The
+The
 .BR \-c ,
 .BR \-C ,
 and
diff --git a/mkfs/Makefile b/mkfs/Makefile
index 75da633..fd1f615 100644
--- a/mkfs/Makefile
+++ b/mkfs/Makefile
@@ -21,7 +21,7 @@ endif
 
 LLDLIBS += $(LIBXFS) $(LIBUUID) $(LIBRT) $(LIBPTHREAD)
 LTDEPENDENCIES += $(LIBXFS)
-LLDFLAGS = -static
+LLDFLAGS = -static-libtool-libs
 
 LSRCFILES = $(FSTYP).c
 LDIRT = $(FSTYP)
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 66711cb..8e756d1 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -817,6 +817,13 @@ zero_old_xfs_structures(
 	__uint32_t		bsize;
 	int			i;
 	xfs_off_t		off;
+	int			tmp;
+
+	/*
+	 * We open regular files with O_TRUNC|O_CREAT. Nothing to do here...
+	 */
+	if (xi->disfile && xi->dcreat)
+		return;
 
 	/*
 	 * read in existing filesystem superblock, use its geometry
@@ -830,11 +837,16 @@ zero_old_xfs_structures(
 	}
 	memset(buf, 0, new_sb->sb_sectsize);
 
-	if (pread(xi->dfd, buf, new_sb->sb_sectsize, 0) != new_sb->sb_sectsize) {
+	tmp = pread(xi->dfd, buf, new_sb->sb_sectsize, 0);
+	if (tmp < 0) {
 		fprintf(stderr, _("existing superblock read failed: %s\n"),
 			strerror(errno));
-		free(buf);
-		return;
+		goto done;
+	}
+	if (tmp != new_sb->sb_sectsize) {
+		fprintf(stderr,
+	_("warning: could not read existing superblock, skip zeroing\n"));
+		goto done;
 	}
 	libxfs_sb_from_disk(&sb, buf);
 
@@ -1743,6 +1755,12 @@ _("cannot specify both crc and ftype\n"));
 		fprintf(stderr, _("illegal block size %d\n"), blocksize);
 		usage();
 	}
+	if (crcs_enabled && blocksize < XFS_MIN_CRC_BLOCKSIZE) {
+		fprintf(stderr,
+_("Minimum block size for CRC enabled filesystems is %d bytes.\n"),
+			XFS_MIN_CRC_BLOCKSIZE);
+		usage();
+	}
 
 	memset(&ft, 0, sizeof(ft));
 	get_topology(&xi, &ft, force_overwrite);
@@ -2441,9 +2459,11 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
 			 */
 			logblocks = (dblocks << blocklog) / 2048;
 			logblocks = logblocks >> blocklog;
-			logblocks = MAX(min_logblocks, logblocks);
 		}
 
+		/* Ensure the chosen size meets minimum log size requirements */
+		logblocks = MAX(min_logblocks, logblocks);
+
 		/* make sure the log fits wholly within an AG */
 		if (logblocks >= agsize)
 			logblocks = min_logblocks;
diff --git a/repair/Makefile b/repair/Makefile
index 17a30fd..6d84ade 100644
--- a/repair/Makefile
+++ b/repair/Makefile
@@ -22,7 +22,7 @@ CFILES = agheader.c attr_repair.c avl.c avl64.c bmap.c btree.c \
 
 LLDLIBS = $(LIBXFS) $(LIBXLOG) $(LIBUUID) $(LIBRT) $(LIBPTHREAD)
 LTDEPENDENCIES = $(LIBXFS) $(LIBXLOG)
-LLDFLAGS = -static
+LLDFLAGS = -static-libtool-libs
 
 default: depend $(LTCOMMAND)
 
diff --git a/repair/agheader.c b/repair/agheader.c
index 416dbd8..5dbf992 100644
--- a/repair/agheader.c
+++ b/repair/agheader.c
@@ -377,7 +377,13 @@ secondary_sb_wack(
 			rval |= XR_AG_SB_SEC;
 	}
 
-	if (sb->sb_inprogress == 1 && sb->sb_pquotino != NULLFSINO)  {
+	/*
+	 * Note that sb_pquotino is not considered a valid sb field for pre-v5
+	 * superblocks. If it is anything other than 0 it is considered garbage
+	 * data beyond the valid sb and explicitly zeroed above.
+	 */
+	if (xfs_sb_version_has_pquotino(&mp->m_sb) &&
+	    sb->sb_inprogress == 1 && sb->sb_pquotino != NULLFSINO)  {
 		if (!no_modify) {
 			sb->sb_pquotino = 0;
 			dsb->sb_pquotino = 0;
diff --git a/repair/attr_repair.c b/repair/attr_repair.c
index d60b664..5ce7bb6 100644
--- a/repair/attr_repair.c
+++ b/repair/attr_repair.c
@@ -746,9 +746,10 @@ valuecheck(
 	void *valuep;
 	int clearit = 0;
 
-	if ((strncmp(namevalue, SGI_ACL_FILE, SGI_ACL_FILE_SIZE) == 0) ||
-			(strncmp(namevalue, SGI_ACL_DEFAULT,
-				SGI_ACL_DEFAULT_SIZE) == 0)) {
+	if ((namelen == SGI_ACL_FILE_SIZE &&
+	     strncmp(namevalue, SGI_ACL_FILE, SGI_ACL_FILE_SIZE) == 0) ||
+	    (namelen == SGI_ACL_DEFAULT_SIZE &&
+	     strncmp(namevalue, SGI_ACL_DEFAULT, SGI_ACL_DEFAULT_SIZE) == 0)) {
 		if (value == NULL) {
 			valuep = malloc(valuelen);
 			if (!valuep)
diff --git a/repair/dinode.c b/repair/dinode.c
index 38a6562..035212c 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -667,12 +667,14 @@ _("inode %" PRIu64 " - bad extent overflows - start %" PRIu64 ", "
 					irec.br_startoff);
 				goto done;
 		}
-		if (irec.br_startoff >= fs_max_file_offset)  {
+		/* Ensure this extent does not extend beyond the max offset */
+		if (irec.br_startoff + irec.br_blockcount - 1 >
+							fs_max_file_offset) {
 			do_warn(
-_("inode %" PRIu64 " - extent offset too large - start %" PRIu64 ", "
-  "count %" PRIu64 ", offset %" PRIu64 "\n"),
-				ino, irec.br_startblock, irec.br_blockcount,
-				irec.br_startoff);
+_("inode %" PRIu64 " - extent exceeds max offset - start %" PRIu64 ", "
+  "count %" PRIu64 ", physical block %" PRIu64 "\n"),
+				ino, irec.br_startoff, irec.br_blockcount,
+				irec.br_startblock);
 			goto done;
 		}
 
@@ -1333,7 +1335,7 @@ process_symlink(
 	xfs_dinode_t	*dino,
 	blkmap_t 	*blkmap)
 {
-	char			*symlink, *cptr;
+	char			*symlink;
 	char			data[MAXPATHLEN];
 
 	/*
@@ -1380,31 +1382,6 @@ _("found illegal null character in symlink inode %" PRIu64 "\n"),
 		return(1);
 	}
 
-	/*
-	 * check for any component being too long
-	 */
-	if (be64_to_cpu(dino->di_size) >= MAXNAMELEN)  {
-		cptr = strchr(symlink, '/');
-
-		while (cptr != NULL)  {
-			if (cptr - symlink >= MAXNAMELEN)  {
-				do_warn(
-_("component of symlink in inode %" PRIu64 " too long\n"),
-					lino);
-				return(1);
-			}
-			symlink = cptr + 1;
-			cptr = strchr(symlink, '/');
-		}
-
-		if (strlen(symlink) >= MAXNAMELEN)  {
-			do_warn(
-_("component of symlink in inode %" PRIu64 " too long\n"),
-				lino);
-			return(1);
-		}
-	}
-
 	return(0);
 }
 
@@ -2314,6 +2291,30 @@ process_dinode_int(xfs_mount_t *mp,
 	 */
 	ASSERT(uncertain == 0 || verify_mode != 0);
 
+	/*
+	 * This is the only valid point to check the CRC; after this we may have
+	 * made changes which invalidate it, and the CRC is only updated again
+	 * when it gets written out.
+	 *
+	 * Of course if we make any modifications after this, the inode gets
+	 * rewritten, and the CRC is updated automagically.
+	 */
+	if (xfs_sb_version_hascrc(&mp->m_sb) &&
+	    !xfs_verify_cksum((char *)dino, mp->m_sb.sb_inodesize,
+				XFS_DINODE_CRC_OFF)) {
+		retval = 1;
+		if (!uncertain)
+			do_warn(_("bad CRC for inode %" PRIu64 "%c"),
+				lino, verify_mode ? '\n' : ',');
+		if (!verify_mode) {
+			if (!no_modify) {
+				do_warn(_(" will rewrite\n"));
+				*dirty = 1;
+			} else
+				do_warn(_(" would rewrite\n"));
+		}
+	}
+
 	if (be16_to_cpu(dino->di_magic) != XFS_DINODE_MAGIC)  {
 		retval = 1;
 		if (!uncertain)
diff --git a/repair/dir2.c b/repair/dir2.c
index 6b8964d..644c214 100644
--- a/repair/dir2.c
+++ b/repair/dir2.c
@@ -198,6 +198,13 @@ _("bad dir magic number 0x%x in inode %" PRIu64 " bno = %u\n"),
 					da_cursor->ino, bno);
 			goto error_out;
 		}
+		/* corrupt node; rebuild the dir. */
+		if (bp->b_error == EFSBADCRC || bp->b_error == EFSCORRUPTED) {
+			do_warn(
+_("corrupt tree block %u for directory inode %" PRIu64 "\n"),
+				bno, da_cursor->ino);
+			goto error_out;
+		}
 		btree = xfs_da3_node_tree_p(node);
 		if (nodehdr.count > mp->m_dir_node_ents)  {
 			libxfs_putbuf(bp);
@@ -861,94 +868,33 @@ process_sf_dir2(
 _("entry \"%*.*s\" in shortform directory %" PRIu64 " references %s inode %" PRIu64 "\n"),
 				namelen, namelen, sfep->name, ino, junkreason,
 				lino);
-		if (namelen == 0)  {
-			/*
-			 * if we're really lucky, this is
-			 * the last entry in which case we
-			 * can use the dir size to set the
-			 * namelen value.  otherwise, forget
-			 * it because we're not going to be
-			 * able to find the next entry.
-			 */
-			bad_sfnamelen = 1;
 
-			if (i == num_entries - 1)  {
-				namelen = ino_dir_size -
-					((__psint_t) &sfep->name[0] -
-					 (__psint_t) sfp);
-				if (!no_modify)  {
-					do_warn(
-_("zero length entry in shortform dir %" PRIu64 ", resetting to %d\n"),
-						ino, namelen);
-					sfep->namelen = namelen;
-				} else  {
-					do_warn(
-_("zero length entry in shortform dir %" PRIu64 ", would set to %d\n"),
-						ino, namelen);
-				}
-			} else  {
-				do_warn(
-_("zero length entry in shortform dir %" PRIu64 ""),
-					ino);
-				if (!no_modify)
-					do_warn(_(", junking %d entries\n"),
-						num_entries - i);
-				else
-					do_warn(_(", would junk %d entries\n"),
-						num_entries - i);
-				/*
-				 * don't process the rest of the directory,
-				 * break out of processing looop
-				 */
-				break;
-			}
+		/* is dir namelen 0 or does this entry extend past dir size? */
+		if (namelen == 0) {
+			junkreason = _("is zero length");
+			bad_sfnamelen = 1;
 		} else if ((__psint_t) sfep - (__psint_t) sfp +
 				xfs_dir3_sf_entsize(mp, sfp, sfep->namelen)
 							> ino_dir_size)  {
+			junkreason = _("extends past end of dir");
 			bad_sfnamelen = 1;
+		}
 
-			if (i == num_entries - 1)  {
-				namelen = ino_dir_size -
-					((__psint_t) &sfep->name[0] -
-					 (__psint_t) sfp);
-				do_warn(
-_("size of last entry overflows space left in in shortform dir %" PRIu64 ", "),
-					ino);
-				if (!no_modify)  {
-					do_warn(_("resetting to %d\n"),
-						namelen);
-					sfep->namelen = namelen;
-					*dino_dirty = 1;
-				} else  {
-					do_warn(_("would reset to %d\n"),
-						namelen);
-				}
-			} else  {
-				do_warn(
-_("size of entry #%d overflows space left in in shortform dir %" PRIu64 "\n"),
-					i, ino);
-				if (!no_modify)  {
-					if (i == num_entries - 1)
-						do_warn(
-						_("junking entry #%d\n"),
-							i);
-					else
-						do_warn(
-						_("junking %d entries\n"),
-							num_entries - i);
-				} else  {
-					if (i == num_entries - 1)
-						do_warn(
-						_("would junk entry #%d\n"),
-							i);
-					else
-						do_warn(
-						_("would junk %d entries\n"),
-							num_entries - i);
-				}
-
-				break;
-			}
+		if (bad_sfnamelen) {
+			do_warn(
+_("entry #%d %s in shortform dir %" PRIu64),
+				i, junkreason, ino);
+			if (!no_modify)
+				do_warn(_(", junking %d entries\n"),
+					num_entries - i);
+			else
+				do_warn(_(", would junk %d entries\n"),
+					num_entries - i);
+			/*
+			 * don't process the rest of the directory,
+			 * break out of processing loop
+			 */
+			break;
 		}
 
 		/*
@@ -1379,6 +1325,18 @@ _("entry \"%*.*s\" at block %d offset %" PRIdPTR " in directory inode %" PRIu64
 				dep->namelen, dep->namelen, dep->name,
 				da_bno, (intptr_t)ptr - (intptr_t)d, ino,
 				clearreason, ent_ino);
+
+		/*
+		 * We have a special dot & dotdot fixer-upper below which can
+		 * sort out the proper inode number, so don't clear it.
+		 */
+		if ((dep->namelen == 1 && dep->name[0] == '.') ||
+		    (dep->namelen == 2 &&
+		     dep->name[0] == '.' && dep->name[1] == '.')) {
+			clearino = 0;
+			clearreason = NULL;
+		}
+
 		/*
 		 * If the name length is 0 (illegal) make it 1 and blast
 		 * the entry.
@@ -1468,6 +1426,7 @@ _("bad .. entry in root directory inode %" PRIu64 ", was %" PRIu64 ": "),
 					} else {
 						do_warn(_("would correct\n"));
 					}
+					*parent = ino;
 				}
 			}
 			/*
diff --git a/repair/globals.h b/repair/globals.h
index 6207ca1..f386686 100644
--- a/repair/globals.h
+++ b/repair/globals.h
@@ -57,7 +57,6 @@
 #define XR_LOG2BSIZE_MIN	9	/* min/max fs blocksize (log2) */
 #define XR_LOG2BSIZE_MAX	16	/* 2^XR_* == blocksize */
 
-#define	NUM_SBS			8	/* max # of sbs to verify */
 #define NUM_AGH_SECTS		4	/* # of components in an ag header */
 
 /*
@@ -88,7 +87,6 @@ EXTERN char	*iobuf;			/* large buffer */
 EXTERN int	iobuf_size;
 EXTERN char	*smallbuf;		/* small (1-4 page) buffer */
 EXTERN int	smallbuf_size;
-EXTERN char	*sb_bufs[NUM_SBS];	/* superblock buffers */
 EXTERN int	sbbuf_size;
 
 /* direct I/O info */
diff --git a/repair/phase6.c b/repair/phase6.c
index 0ec4f07..105bce4 100644
--- a/repair/phase6.c
+++ b/repair/phase6.c
@@ -1321,7 +1321,8 @@ longform_dir2_rebuild(
 	 * for the libxfs_dir_init() call).
 	 */
 	pip.i_ino = get_inode_parent(irec, ino_offset);
-	if (pip.i_ino == NULLFSINO)
+	if (pip.i_ino == NULLFSINO ||
+	    xfs_dir_ino_validate(mp, pip.i_ino))
 		pip.i_ino = mp->m_sb.sb_rootino;
 
 	xfs_bmap_init(&flist, &firstblock);
@@ -1348,12 +1349,19 @@ longform_dir2_rebuild(
 
 	ASSERT(done);
 
-	libxfs_dir_init(tp, ip, &pip);
+	error = libxfs_dir_init(tp, ip, &pip);
+	if (error) {
+		do_warn(_("xfs_dir_init failed -- error - %d\n"), error);
+		goto out_bmap_cancel;
+	}
 
 	error = libxfs_bmap_finish(&tp, &flist, &committed);
 
 	libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC);
 
+	if (ino == mp->m_sb.sb_rootino)
+		need_root_dotdot = 0;
+
 	/* go through the hash list and re-add the inodes */
 
 	for (p = hashtab->first; p; p = p->nextbyorder) {
@@ -1922,6 +1930,66 @@ _("entry \"%s\" in dir inode %" PRIu64 " inconsistent with .. value (%" PRIu64 "
 	freetab->ents[db].s = 0;
 }
 
+/* check v5 metadata */
+static int
+__check_dir3_header(
+	struct xfs_mount	*mp,
+	struct xfs_buf		*bp,
+	xfs_ino_t		ino,
+	__be64			owner,
+	__be64			blkno,
+	uuid_t			*uuid)
+{
+
+	/* verify owner */
+	if (be64_to_cpu(owner) != ino) {
+		do_warn(
+_("expected owner inode %" PRIu64 ", got %llu, directory block %" PRIu64 "\n"),
+			ino, be64_to_cpu(owner), bp->b_bn);
+		return 1;
+	}
+	/* verify block number */
+	if (be64_to_cpu(blkno) != bp->b_bn) {
+		do_warn(
+_("expected block %" PRIu64 ", got %llu, directory inode %" PRIu64 "\n"),
+			bp->b_bn, be64_to_cpu(blkno), ino);
+		return 1;
+	}
+	/* verify uuid */
+	if (platform_uuid_compare(uuid, &mp->m_sb.sb_uuid) != 0) {
+		do_warn(
+_("wrong FS UUID, directory inode %" PRIu64 " block %" PRIu64 "\n"),
+			ino, bp->b_bn);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int
+check_da3_header(
+	struct xfs_mount	*mp,
+	struct xfs_buf		*bp,
+	xfs_ino_t		ino)
+{
+	struct xfs_da3_blkinfo	*info = bp->b_addr;
+
+	return __check_dir3_header(mp, bp, ino, info->owner, info->blkno,
+				   &info->uuid);
+}
+
+static int
+check_dir3_header(
+	struct xfs_mount	*mp,
+	struct xfs_buf		*bp,
+	xfs_ino_t		ino)
+{
+	struct xfs_dir3_blk_hdr	*info = bp->b_addr;
+
+	return __check_dir3_header(mp, bp, ino, info->owner, info->blkno,
+				   &info->uuid);
+}
+
 /*
  * Check contents of leaf-form block.
  */
@@ -1948,7 +2016,12 @@ longform_dir2_check_leaf(
 	da_bno = mp->m_dirleafblk;
 	error = dir_read_buf(ip, da_bno, -1, &bp, &xfs_dir3_leaf1_buf_ops,
 			     &fixit);
-	if (error) {
+	if (error == EFSBADCRC || error == EFSCORRUPTED || fixit) {
+		do_warn(
+	_("leaf block %u for directory inode %" PRIu64 " bad CRC\n"),
+			da_bno, ip->i_ino);
+		return 1;
+	} else if (error) {
 		do_error(
 	_("can't read block %u for directory inode %" PRIu64 ", error %d\n"),
 			da_bno, ip->i_ino, error);
@@ -1973,6 +2046,15 @@ longform_dir2_check_leaf(
 		libxfs_putbuf(bp);
 		return 1;
 	}
+
+	if (leafhdr.magic == XFS_DIR3_LEAF1_MAGIC) {
+		error = check_da3_header(mp, bp, ip->i_ino);
+		if (error) {
+			libxfs_putbuf(bp);
+			return error;
+		}
+	}
+
 	seeval = dir_hash_see_all(hashtab, ents, leafhdr.count, leafhdr.stale);
 	if (dir_hash_check(hashtab, ip, seeval)) {
 		libxfs_putbuf(bp);
@@ -2047,12 +2129,9 @@ longform_dir2_check_node(
 		xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf);
 		ents = xfs_dir3_leaf_ents_p(leaf);
 		if (!(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC ||
-		      leafhdr.magic == XFS_DIR3_LEAFN_MAGIC)) {
-			if (leafhdr.magic == XFS_DA_NODE_MAGIC ||
-			    leafhdr.magic == XFS_DA3_NODE_MAGIC) {
-				libxfs_putbuf(bp);
-				continue;
-			}
+		      leafhdr.magic == XFS_DIR3_LEAFN_MAGIC ||
+		      leafhdr.magic == XFS_DA_NODE_MAGIC ||
+		      leafhdr.magic == XFS_DA3_NODE_MAGIC)) {
 			do_warn(
 	_("unknown magic number %#x for block %u in directory inode %" PRIu64 "\n"),
 				leafhdr.magic, da_bno, ip->i_ino);
@@ -2060,6 +2139,23 @@ longform_dir2_check_node(
 			return 1;
 		}
 
+		/* check v5 metadata */
+		if (leafhdr.magic == XFS_DIR3_LEAFN_MAGIC ||
+		    leafhdr.magic == XFS_DA3_NODE_MAGIC) {
+			error = check_da3_header(mp, bp, ip->i_ino);
+			if (error) {
+				libxfs_putbuf(bp);
+				return error;
+			}
+		}
+
+		/* ignore nodes */
+		if (leafhdr.magic == XFS_DA_NODE_MAGIC ||
+		    leafhdr.magic == XFS_DA3_NODE_MAGIC) {
+			libxfs_putbuf(bp);
+			continue;
+		}
+
 		/*
 		 * If there's a validator error, we need to ensure that we got
 		 * the right ops on the buffer for when we write it back out.
@@ -2113,6 +2209,14 @@ longform_dir2_check_node(
 			libxfs_putbuf(bp);
 			return 1;
 		}
+
+		if (freehdr.magic == XFS_DIR3_FREE_MAGIC) {
+			error = check_dir3_header(mp, bp, ip->i_ino);
+			if (error) {
+				libxfs_putbuf(bp);
+				return error;
+			}
+		}
 		for (i = used = 0; i < freehdr.nvalid; i++) {
 			if (i + freehdr.firstdb >= freetab->nents ||
 					freetab->ents[i + freehdr.firstdb].v !=
@@ -2204,6 +2308,7 @@ longform_dir2_entry_check(xfs_mount_t	*mp,
 	     da_bno = (xfs_dablk_t)next_da_bno) {
 		const struct xfs_buf_ops *ops;
 		int			 error;
+		struct xfs_dir2_data_hdr *d;
 
 		next_da_bno = da_bno + mp->m_dirblkfsbs - 1;
 		if (bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK)) {
@@ -2252,6 +2357,20 @@ longform_dir2_entry_check(xfs_mount_t	*mp,
 			}
 			continue;
 		}
+
+		/* check v5 metadata */
+		d = bplist[db]->b_addr;
+		if (be32_to_cpu(d->magic) == XFS_DIR3_BLOCK_MAGIC ||
+		    be32_to_cpu(d->magic) == XFS_DIR3_DATA_MAGIC) {
+			struct xfs_buf		 *bp = bplist[db];
+
+			error = check_dir3_header(mp, bp, ino);
+			if (error) {
+				fixit++;
+				continue;
+			}
+		}
+
 		longform_dir2_entry_check_data(mp, ip, num_illegal, need_dot,
 				irec, ino_offset, &bplist[db], hashtab,
 				&freetab, da_bno, isblock);
diff --git a/repair/sb.c b/repair/sb.c
index ad27756..ce20d0d 100644
--- a/repair/sb.c
+++ b/repair/sb.c
@@ -196,7 +196,8 @@ sb_validate_ino_align(struct xfs_sb *sb)
 	if (!xfs_sb_version_hascrc(sb))
 		return false;
 
-	align *= sb->sb_inodesize / XFS_DINODE_MIN_SIZE;
+	align = (XFS_INODE_BIG_CLUSTER_SIZE *
+		 sb->sb_inodesize / XFS_DINODE_MIN_SIZE) >> sb->sb_blocklog;
 	if (align == sb->sb_inoalignmt)
 		return true;
 
@@ -702,20 +703,11 @@ verify_set_primary_sb(xfs_sb_t		*rsb,
 	xfs_sb_t	*sb;
 	fs_geo_list_t	*list;
 	fs_geo_list_t	*current;
-	char		*checked;
 	xfs_agnumber_t	agno;
 	int		num_sbs;
-	int		skip;
 	int		size;
 	int		num_ok;
 	int		retval;
-	int		round;
-
-	/*
-	 * select the number of secondaries to try for
-	 */
-	num_sbs = MIN(NUM_SBS, rsb->sb_agcount);
-	skip = howmany(num_sbs, rsb->sb_agcount);
 
 	/*
 	 * We haven't been able to validate the sector size yet properly
@@ -724,61 +716,48 @@ verify_set_primary_sb(xfs_sb_t		*rsb,
 	 * sector size rather than the sector size in @rsb.
 	 */
 	size = NUM_AGH_SECTS * (1 << (XFS_MAX_SECTORSIZE_LOG));
-	retval = 0;
 	list = NULL;
 	num_ok = 0;
 	*sb_modified = 0;
+	num_sbs = rsb->sb_agcount;
 
 	sb = (xfs_sb_t *) alloc_ag_buf(size);
-	checked = calloc(rsb->sb_agcount, sizeof(char));
-	if (!checked) {
-		do_error(_("calloc failed in verify_set_primary_sb\n"));
-		exit(1);
-	}
 
 	/*
 	 * put the primary sb geometry info onto the geometry list
 	 */
-	checked[sb_index] = 1;
 	get_sb_geometry(&geo, rsb);
 	list = add_geo(list, &geo, sb_index);
 
 	/*
-	 * grab N secondaries.  check them off as we get them
-	 * so we only process each one once
+	 * scan the secondaries and check them off as we get them so we only
+	 * process each one once
 	 */
-	for (round = 0; round < skip; round++)  {
-		for (agno = round; agno < rsb->sb_agcount; agno += skip)  {
-			if (checked[agno])
-				continue;
+	for (agno = 1; agno < rsb->sb_agcount; agno++) {
+		off = (xfs_off_t)agno * rsb->sb_agblocks << rsb->sb_blocklog;
 
-			off = (xfs_off_t)agno * rsb->sb_agblocks << rsb->sb_blocklog;
-
-			checked[agno] = 1;
-			retval = get_sb(sb, off, size, agno);
-			if (retval == XR_EOF)
-				goto out_free_list;
-
-			if (retval == XR_OK) {
-				/*
-				 * save away geometry info.
-				 * don't bother checking the sb
-				 * against the agi/agf as the odds
-				 * of the sb being corrupted in a way
-				 * that it is internally consistent
-				 * but not consistent with the rest
-				 * of the filesystem is really really low.
-				 */
-				get_sb_geometry(&geo, sb);
-				list = add_geo(list, &geo, agno);
-				num_ok++;
-			}
+		retval = get_sb(sb, off, size, agno);
+		if (retval == XR_EOF)
+			goto out_free_list;
+
+		if (retval == XR_OK) {
+			/*
+			 * save away geometry info. don't bother checking the
+			 * sb against the agi/agf as the odds of the sb being
+			 * corrupted in a way that it is internally consistent
+			 * but not consistent with the rest of the filesystem is
+			 * really really low.
+			 */
+			get_sb_geometry(&geo, sb);
+			list = add_geo(list, &geo, agno);
+			num_ok++;
 		}
 	}
 
 	/*
 	 * see if we have enough superblocks to bother with
 	 */
+	retval = 0;
 	if (num_ok < num_sbs / 2) {
 		retval = XR_INSUFF_SEC_SB;
 		goto out_free_list;
@@ -867,6 +846,5 @@ verify_set_primary_sb(xfs_sb_t		*rsb,
 out_free_list:
 	free_geo(list);
 	free(sb);
-	free(checked);
-	return(retval);
+	return retval;
 }
diff --git a/repair/scan.c b/repair/scan.c
index 142d8d7..6508a47 100644
--- a/repair/scan.c
+++ b/repair/scan.c
@@ -225,7 +225,24 @@ _("expected level %d got %d in inode %" PRIu64 ", (%s fork) bmbt block %" PRIu64
 			do_warn(
 _("expected owner inode %" PRIu64 ", got %llu, bmbt block %" PRIu64 "\n"),
 				ino, be64_to_cpu(block->bb_u.l.bb_owner), bno);
-			return(1);
+			return 1;
+		}
+		/* verify block number */
+		if (be64_to_cpu(block->bb_u.l.bb_blkno) !=
+		    XFS_FSB_TO_DADDR(mp, bno)) {
+			do_warn(
+_("expected block %" PRIu64 ", got %llu, bmbt block %" PRIu64 "\n"),
+				XFS_FSB_TO_DADDR(mp, bno),
+				be64_to_cpu(block->bb_u.l.bb_blkno), bno);
+			return 1;
+		}
+		/* verify uuid */
+		if (platform_uuid_compare(&block->bb_u.l.bb_uuid,
+					  &mp->m_sb.sb_uuid) != 0) {
+			do_warn(
+_("wrong FS UUID, bmbt block %" PRIu64 "\n"),
+				bno);
+			return 1;
 		}
 	}
 
@@ -770,7 +787,8 @@ scan_single_ino_chunk(
 	    (inodes_per_block <= XFS_INODES_PER_CHUNK && off !=  0) ||
 	    (inodes_per_block > XFS_INODES_PER_CHUNK &&
 	     off % XFS_INODES_PER_CHUNK != 0) ||
-	    (fs_aligned_inodes && agbno % fs_ino_alignment != 0))  {
+	    (fs_aligned_inodes && fs_ino_alignment &&
+	     agbno % fs_ino_alignment != 0))  {
 		do_warn(
 	_("badly aligned inode rec (starting inode = %" PRIu64 ")\n"),
 			lino);
@@ -929,7 +947,8 @@ scan_single_finobt_chunk(
 	    (inodes_per_block <= XFS_INODES_PER_CHUNK && off !=  0) ||
 	    (inodes_per_block > XFS_INODES_PER_CHUNK &&
 	     off % XFS_INODES_PER_CHUNK != 0) ||
-	    (fs_aligned_inodes && agbno % fs_ino_alignment != 0)) {
+	    (fs_aligned_inodes && fs_ino_alignment &&
+	     agbno % fs_ino_alignment != 0)) {
 		do_warn(
 	_("badly aligned finobt inode rec (starting inode = %" PRIu64 ")\n"),
 			lino);
@@ -1483,7 +1502,7 @@ scan_ag(
 	int		status;
 	char		*objname = NULL;
 
-	sb = (struct xfs_sb *)calloc(BBSIZE, 1);
+	sb = (struct xfs_sb *)calloc(BBTOB(XFS_FSS_TO_BB(mp, 1)), 1);
 	if (!sb) {
 		do_error(_("can't allocate memory for superblock\n"));
 		return;
diff --git a/repair/versions.c b/repair/versions.c
index c1dff72..10bcd29 100644
--- a/repair/versions.c
+++ b/repair/versions.c
@@ -175,6 +175,20 @@ _("WARNING:  you have disallowed superblock-feature-bits-allowed\n"
 		}
 	}
 
+	/* Look for V5 feature flags we don't know about */
+	if (XFS_SB_VERSION_NUM(sb) >= XFS_SB_VERSION_5 &&
+	    (xfs_sb_has_compat_feature(sb, XFS_SB_FEAT_COMPAT_UNKNOWN) ||
+	     xfs_sb_has_ro_compat_feature(sb, XFS_SB_FEAT_RO_COMPAT_UNKNOWN) ||
+	     xfs_sb_has_incompat_feature(sb, XFS_SB_FEAT_INCOMPAT_UNKNOWN))) {
+		do_warn(
+_("Superblock has unknown compat/rocompat/incompat features (0x%x/0x%x/0x%x).\n"
+  "Using a more recent xfs_repair is recommended.\n"),
+			sb->sb_features_compat & XFS_SB_FEAT_COMPAT_UNKNOWN,
+			sb->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_UNKNOWN,
+			sb->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_UNKNOWN);
+		return 1;
+	}
+
 	if (xfs_sb_version_hasattr(sb))  {
 		if (!fs_attributes_allowed)  {
 			if (!no_modify)  {