Blame SOURCES/xfsprogs-3.2.3-fixes.patch

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