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) {