* [PATCH 1/9] xfs: validate metadata LSNs against log on v5 superblocks
2015-08-28 18:06 [PATCH 0/9] xfsprogs: handle the log correctly on v5 supers Brian Foster
@ 2015-08-28 18:06 ` Brian Foster
2015-08-28 18:06 ` [PATCH 2/9] libxfs: track largest metadata LSN in use via verifiers Brian Foster
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Brian Foster @ 2015-08-28 18:06 UTC (permalink / raw)
To: xfs
Backport of kernel commit. Replace xfs_valid_lsn() with stub.
Signed-off-by: Brian Foster <bfoster@redhat.com>
---
libxfs/libxfs_priv.h | 2 ++
libxfs/util.c | 14 ++++++++++++++
libxfs/xfs_alloc.c | 10 ++++++++--
libxfs/xfs_attr_leaf.c | 3 +++
libxfs/xfs_btree.c | 18 ++++++++++++++++--
libxfs/xfs_da_btree.c | 3 +++
libxfs/xfs_dir2_block.c | 2 ++
libxfs/xfs_dir2_data.c | 2 ++
libxfs/xfs_dir2_leaf.c | 2 ++
libxfs/xfs_dir2_node.c | 2 ++
libxfs/xfs_ialloc.c | 9 +++++++--
libxfs/xfs_sb.c | 9 +++++++++
libxfs/xfs_symlink_remote.c | 3 +++
13 files changed, 73 insertions(+), 6 deletions(-)
diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h
index 2a8b850..d21e78e 100644
--- a/libxfs/libxfs_priv.h
+++ b/libxfs/libxfs_priv.h
@@ -506,4 +506,6 @@ void xfs_verifier_error(struct xfs_buf *bp);
/* xfs_rtalloc.c */
int libxfs_rtfree_extent(struct xfs_trans *, xfs_rtblock_t, xfs_extlen_t);
+bool xfs_valid_lsn(struct xfs_mount *, xfs_lsn_t);
+
#endif /* __LIBXFS_INTERNAL_XFS_H__ */
diff --git a/libxfs/util.c b/libxfs/util.c
index c9f9175..96ce31f 100644
--- a/libxfs/util.c
+++ b/libxfs/util.c
@@ -729,3 +729,17 @@ xfs_verifier_error(
bp->b_error == -EFSBADCRC ? "CRC error" : "corruption",
bp->b_bn, BBTOB(bp->b_length));
}
+
+/*
+ * This is called from I/O verifiers on v5 superblock filesystems. In the
+ * kernel, it validates the metadata LSN parameter against the current LSN of
+ * the active log. We don't have an active log in userspace, so just return
+ * true.
+ */
+bool
+xfs_valid_lsn(
+ struct xfs_mount *mp,
+ xfs_lsn_t lsn)
+{
+ return true;
+}
diff --git a/libxfs/xfs_alloc.c b/libxfs/xfs_alloc.c
index 4f3008a..4a3df1f 100644
--- a/libxfs/xfs_alloc.c
+++ b/libxfs/xfs_alloc.c
@@ -464,6 +464,8 @@ xfs_agfl_verify(
return false;
if (be32_to_cpu(agfl->agfl_magicnum) != XFS_AGFL_MAGIC)
return false;
+ if (!xfs_valid_lsn(mp, be64_to_cpu(XFS_BUF_TO_AGFL(bp)->agfl_lsn)))
+ return false;
/*
* during growfs operations, the perag is not fully initialised,
* so we can't use it for any useful checking. growfs ensures we can't
@@ -2255,9 +2257,13 @@ xfs_agf_verify(
{
struct xfs_agf *agf = XFS_BUF_TO_AGF(bp);
- if (xfs_sb_version_hascrc(&mp->m_sb) &&
- !uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid))
+ if (xfs_sb_version_hascrc(&mp->m_sb)) {
+ if (!uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid))
return false;
+ if (!xfs_valid_lsn(mp,
+ be64_to_cpu(XFS_BUF_TO_AGF(bp)->agf_lsn)))
+ return false;
+ }
if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) &&
XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) &&
diff --git a/libxfs/xfs_attr_leaf.c b/libxfs/xfs_attr_leaf.c
index cc25068..ae49d7f 100644
--- a/libxfs/xfs_attr_leaf.c
+++ b/libxfs/xfs_attr_leaf.c
@@ -262,6 +262,9 @@ xfs_attr3_leaf_verify(
return false;
if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
return false;
+
+ if (!xfs_valid_lsn(mp, be64_to_cpu(hdr3->info.lsn)))
+ return false;
} else {
if (ichdr.magic != XFS_ATTR_LEAF_MAGIC)
return false;
diff --git a/libxfs/xfs_btree.c b/libxfs/xfs_btree.c
index a16ae7d..9c1296f 100644
--- a/libxfs/xfs_btree.c
+++ b/libxfs/xfs_btree.c
@@ -240,8 +240,15 @@ bool
xfs_btree_lblock_verify_crc(
struct xfs_buf *bp)
{
- if (xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb))
+ struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
+ struct xfs_mount *mp = bp->b_target->bt_mount;
+
+ if (xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb)) {
+ if (!xfs_valid_lsn(mp, be64_to_cpu(block->bb_u.l.bb_lsn)))
+ return false;
+
return xfs_buf_verify_cksum(bp, XFS_BTREE_LBLOCK_CRC_OFF);
+ }
return true;
}
@@ -272,8 +279,15 @@ bool
xfs_btree_sblock_verify_crc(
struct xfs_buf *bp)
{
- if (xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb))
+ struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
+ struct xfs_mount *mp = bp->b_target->bt_mount;
+
+ if (xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb)) {
+ if (!xfs_valid_lsn(mp, be64_to_cpu(block->bb_u.s.bb_lsn)))
+ return false;
+
return xfs_buf_verify_cksum(bp, XFS_BTREE_SBLOCK_CRC_OFF);
+ }
return true;
}
diff --git a/libxfs/xfs_da_btree.c b/libxfs/xfs_da_btree.c
index c874164..99a8ad7 100644
--- a/libxfs/xfs_da_btree.c
+++ b/libxfs/xfs_da_btree.c
@@ -146,6 +146,9 @@ xfs_da3_node_verify(
return false;
if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
return false;
+
+ if (!xfs_valid_lsn(mp, be64_to_cpu(hdr3->info.lsn)))
+ return false;
} else {
if (ichdr.magic != XFS_DA_NODE_MAGIC)
return false;
diff --git a/libxfs/xfs_dir2_block.c b/libxfs/xfs_dir2_block.c
index 489f301..567b5a4 100644
--- a/libxfs/xfs_dir2_block.c
+++ b/libxfs/xfs_dir2_block.c
@@ -68,6 +68,8 @@ xfs_dir3_block_verify(
return false;
if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
return false;
+ if (!xfs_valid_lsn(mp, be64_to_cpu(hdr3->lsn)))
+ return false;
} else {
if (hdr3->magic != cpu_to_be32(XFS_DIR2_BLOCK_MAGIC))
return false;
diff --git a/libxfs/xfs_dir2_data.c b/libxfs/xfs_dir2_data.c
index 0c9f529..58bbc80 100644
--- a/libxfs/xfs_dir2_data.c
+++ b/libxfs/xfs_dir2_data.c
@@ -222,6 +222,8 @@ xfs_dir3_data_verify(
return false;
if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
return false;
+ if (!xfs_valid_lsn(mp, be64_to_cpu(hdr3->lsn)))
+ return false;
} else {
if (hdr3->magic != cpu_to_be32(XFS_DIR2_DATA_MAGIC))
return false;
diff --git a/libxfs/xfs_dir2_leaf.c b/libxfs/xfs_dir2_leaf.c
index 80d03b3..37b9c4a 100644
--- a/libxfs/xfs_dir2_leaf.c
+++ b/libxfs/xfs_dir2_leaf.c
@@ -162,6 +162,8 @@ xfs_dir3_leaf_verify(
return false;
if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn)
return false;
+ if (!xfs_valid_lsn(mp, be64_to_cpu(leaf3->info.lsn)))
+ return false;
} else {
if (leaf->hdr.info.magic != cpu_to_be16(magic))
return false;
diff --git a/libxfs/xfs_dir2_node.c b/libxfs/xfs_dir2_node.c
index 0514cea..d03b7ff 100644
--- a/libxfs/xfs_dir2_node.c
+++ b/libxfs/xfs_dir2_node.c
@@ -95,6 +95,8 @@ xfs_dir3_free_verify(
return false;
if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
return false;
+ if (!xfs_valid_lsn(mp, be64_to_cpu(hdr3->lsn)))
+ return false;
} else {
if (hdr->magic != cpu_to_be32(XFS_DIR2_FREE_MAGIC))
return false;
diff --git a/libxfs/xfs_ialloc.c b/libxfs/xfs_ialloc.c
index 93bfaea..6a0e4e2 100644
--- a/libxfs/xfs_ialloc.c
+++ b/libxfs/xfs_ialloc.c
@@ -2495,9 +2495,14 @@ xfs_agi_verify(
struct xfs_mount *mp = bp->b_target->bt_mount;
struct xfs_agi *agi = XFS_BUF_TO_AGI(bp);
- if (xfs_sb_version_hascrc(&mp->m_sb) &&
- !uuid_equal(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid))
+ if (xfs_sb_version_hascrc(&mp->m_sb)) {
+ if (!uuid_equal(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid))
+ return false;
+ if (!xfs_valid_lsn(mp,
+ be64_to_cpu(XFS_BUF_TO_AGI(bp)->agi_lsn)))
return false;
+ }
+
/*
* Validate the magic number of the agi block.
*/
diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c
index f944a58..97e2b66 100644
--- a/libxfs/xfs_sb.c
+++ b/libxfs/xfs_sb.c
@@ -161,6 +161,15 @@ xfs_mount_validate_sb(
"Filesystem can not be safely mounted by this kernel.");
return -EINVAL;
}
+ } else if (xfs_sb_version_hascrc(sbp)) {
+ /*
+ * We can't read verify the sb LSN because the read verifier is
+ * called before the log is allocated and processed. We know the
+ * log is set up before write verifier (!check_version) calls,
+ * so just check it here.
+ */
+ if (!xfs_valid_lsn(mp, sbp->sb_lsn))
+ return -EINVAL;
}
if (xfs_sb_version_has_pquotino(sbp)) {
diff --git a/libxfs/xfs_symlink_remote.c b/libxfs/xfs_symlink_remote.c
index 7d46d9e..bb9f89f 100644
--- a/libxfs/xfs_symlink_remote.c
+++ b/libxfs/xfs_symlink_remote.c
@@ -57,6 +57,7 @@ xfs_symlink_hdr_set(
if (!xfs_sb_version_hascrc(&mp->m_sb))
return 0;
+ memset(dsl, 0, sizeof(struct xfs_dsymlink_hdr));
dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC);
dsl->sl_offset = cpu_to_be32(offset);
dsl->sl_bytes = cpu_to_be32(size);
@@ -113,6 +114,8 @@ xfs_symlink_verify(
return false;
if (dsl->sl_owner == 0)
return false;
+ if (!xfs_valid_lsn(mp, be64_to_cpu(dsl->sl_lsn)))
+ return false;
return true;
}
--
2.1.0
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 2/9] libxfs: track largest metadata LSN in use via verifiers
2015-08-28 18:06 [PATCH 0/9] xfsprogs: handle the log correctly on v5 supers Brian Foster
2015-08-28 18:06 ` [PATCH 1/9] xfs: validate metadata LSNs against log on v5 superblocks Brian Foster
@ 2015-08-28 18:06 ` Brian Foster
2015-08-28 18:06 ` [PATCH 3/9] libxfs: don't hardcode cycle 1 into unmount op header Brian Foster
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Brian Foster @ 2015-08-28 18:06 UTC (permalink / raw)
To: xfs
The LSN validation helper is called in the I/O verifier codepath for
metadata that embed a last-modification LSN. While the codepath exists,
this is not used in userspace as in the kernel because the former
doesn't have an active log.
xfs_repair does need to check the validity of the LSN metadata with
respect to the on-disk log, however. Use the LSN validation mechanism to
track the largest LSN that has been seen. Export the value so repair can
use it once it has processed the entire filesystem. Note that the helper
continues to always return true to preserve existing behavior.
Signed-off-by: Brian Foster <bfoster@redhat.com>
---
include/libxfs.h | 1 +
libxfs/util.c | 28 +++++++++++++++++++++++++++-
2 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/include/libxfs.h b/include/libxfs.h
index b1604e2..cc06fc6 100644
--- a/include/libxfs.h
+++ b/include/libxfs.h
@@ -134,6 +134,7 @@ typedef struct {
#define LIBXFS_DIRECT 0x0020 /* can use direct I/O, not buffered */
extern char *progname;
+extern xfs_lsn_t libxfs_max_lsn;
extern int libxfs_init (libxfs_init_t *);
extern void libxfs_destroy (void);
extern int libxfs_device_to_fd (dev_t);
diff --git a/libxfs/util.c b/libxfs/util.c
index 96ce31f..0116e3d 100644
--- a/libxfs/util.c
+++ b/libxfs/util.c
@@ -733,13 +733,39 @@ xfs_verifier_error(
/*
* This is called from I/O verifiers on v5 superblock filesystems. In the
* kernel, it validates the metadata LSN parameter against the current LSN of
- * the active log. We don't have an active log in userspace, so just return
+ * the active log. We don't have an active log in userspace so always return
* true.
+ *
+ * xfs_repair piggybacks off this mechanism to help track the largest metadata
+ * LSN in use on a filesystem. Keep a record of the largest LSN seen such that
+ * repair can validate it against the state of the log.
*/
+xfs_lsn_t libxfs_max_lsn = 0;
+pthread_mutex_t libxfs_max_lsn_lock = PTHREAD_MUTEX_INITIALIZER;
+
bool
xfs_valid_lsn(
struct xfs_mount *mp,
xfs_lsn_t lsn)
{
+ int cycle = CYCLE_LSN(lsn);
+ int block = BLOCK_LSN(lsn);
+ int max_cycle;
+ int max_block;
+
+ if (lsn == NULLCOMMITLSN)
+ return true;
+
+ pthread_mutex_lock(&libxfs_max_lsn_lock);
+
+ max_cycle = CYCLE_LSN(libxfs_max_lsn);
+ max_block = BLOCK_LSN(libxfs_max_lsn);
+
+ if ((cycle > max_cycle) ||
+ (cycle == max_cycle && block > max_block))
+ libxfs_max_lsn = lsn;
+
+ pthread_mutex_unlock(&libxfs_max_lsn_lock);
+
return true;
}
--
2.1.0
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 3/9] libxfs: don't hardcode cycle 1 into unmount op header
2015-08-28 18:06 [PATCH 0/9] xfsprogs: handle the log correctly on v5 supers Brian Foster
2015-08-28 18:06 ` [PATCH 1/9] xfs: validate metadata LSNs against log on v5 superblocks Brian Foster
2015-08-28 18:06 ` [PATCH 2/9] libxfs: track largest metadata LSN in use via verifiers Brian Foster
@ 2015-08-28 18:06 ` Brian Foster
2015-08-28 18:06 ` [PATCH 4/9] libxfs: pass lsn param to log clear and record header logging helpers Brian Foster
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Brian Foster @ 2015-08-28 18:06 UTC (permalink / raw)
To: xfs
The libxfs helper to write a log record after zeroing the log fills much
of the record header and unmount record with dummy data. It also
hardcodes the cycle number into the transaction oh_tid field as the
kernel expects to find the cycle stamped at the top of each block and
the original oh_tid value packed into h_cycle_data of the record header.
The log clearing code requires the ability to format the log to an
arbitrary cycle number to fix v5 superblock log recovery ordering
problems. As a result, the unmount record helper must not hardcode a
cycle of 1.
Fix up libxfs_log_header() to pack the unmount record appropriately, as
is already done for extra blocks that might exist beyond the record. Use
h_cycle_data for the original 32-bit word of the log record data block
and stamp the cycle number in its place. This allows unmount_record() to
work for arbitrary cycle numbers and libxfs_log_header() to pack a cycle
value that matches the lsn used in the record header. Note that this
patch does not change behavior as the lsn is still hardcoded to (1:0).
Signed-off-by: Brian Foster <bfoster@redhat.com>
---
libxfs/rdwr.c | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/libxfs/rdwr.c b/libxfs/rdwr.c
index 4f8212f..3c0179f 100644
--- a/libxfs/rdwr.c
+++ b/libxfs/rdwr.c
@@ -122,7 +122,7 @@ static void unmount_record(void *p)
} magic = { XLOG_UNMOUNT_TYPE, 0, 0 };
memset(p, 0, BBSIZE);
- op->oh_tid = cpu_to_be32(1);
+ op->oh_tid = cpu_to_be32(0xb0c0d0d0);
op->oh_len = cpu_to_be32(sizeof(magic));
op->oh_clientid = XFS_LOG;
op->oh_flags = XLOG_UNMOUNT_TRANS;
@@ -188,10 +188,6 @@ libxfs_log_header(
len = ((version == 2) && sunit) ? BTOBB(sunit) : 1;
- /* note that oh_tid actually contains the cycle number
- * and the tid is stored in h_cycle_data[0] - that's the
- * way things end up on disk.
- */
memset(p, 0, BBSIZE);
head->h_magicno = cpu_to_be32(XLOG_HEADER_MAGIC_NUM);
head->h_cycle = cpu_to_be32(1);
@@ -203,7 +199,6 @@ libxfs_log_header(
head->h_crc = cpu_to_le32(0);
head->h_prev_block = cpu_to_be32(-1);
head->h_num_logops = cpu_to_be32(1);
- head->h_cycle_data[0] = cpu_to_be32(0xb0c0d0d0);
head->h_fmt = cpu_to_be32(fmt);
head->h_size = cpu_to_be32(XLOG_HEADER_CYCLE_SIZE);
@@ -212,11 +207,25 @@ libxfs_log_header(
memcpy(&head->h_fs_uuid, fs_uuid, sizeof(uuid_t));
- len = MAX(len, 2);
p = nextfunc(p, BBSIZE, private);
unmount_record(p);
+ /*
+ * The kernel expects to see either a log record header magic or the LSN
+ * cycle at the top of every log block (for example, see
+ * xlog_[un]pack_data() and xlog_get_cycle()). Pack the unmount record
+ * block appropriately here.
+ */
cycle_lsn = CYCLE_LSN_DISK(head->h_lsn);
+ head->h_cycle_data[0] = *(__be32 *)p;
+ *(__be32 *)p = cycle_lsn;
+
+ /*
+ * Now zero any remaining blocks in the record and stamp with the cycle.
+ * Note that we don't need to swap into h_cycle_data because it has
+ * already been initialized to zero.
+ */
+ len = MAX(len, 2);
for (i = 2; i < len; i++) {
p = nextfunc(p, BBSIZE, private);
memset(p, 0, BBSIZE);
--
2.1.0
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 4/9] libxfs: pass lsn param to log clear and record header logging helpers
2015-08-28 18:06 [PATCH 0/9] xfsprogs: handle the log correctly on v5 supers Brian Foster
` (2 preceding siblings ...)
2015-08-28 18:06 ` [PATCH 3/9] libxfs: don't hardcode cycle 1 into unmount op header Brian Foster
@ 2015-08-28 18:06 ` Brian Foster
2015-08-28 18:06 ` [PATCH 5/9] libxfs: add ability to clear log to arbitrary log cycle Brian Foster
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Brian Foster @ 2015-08-28 18:06 UTC (permalink / raw)
To: xfs
In preparation to support the ability to format the log with an
arbitrary cycle number, the log clear and record logging helpers must be
updated to receive the desired cycle and LSN values as parameters.
Update libxfs_log_clear() to receive the desired cycle number to format
the log with. Define a preprocessor directive to represent the currently
hardcoded case of cycle 1. Update libxfs_log_header() to receive the lsn
and tail_lsn of the record to write. Use a NULL value LSN to represent
the currently hardcoded behavior.
All callers are updated to use the current default values. As such, this
patch does not change behavior in any way.
Signed-off-by: Brian Foster <bfoster@redhat.com>
---
copy/xfs_copy.c | 4 ++--
db/sb.c | 2 +-
include/libxfs.h | 12 ++++++++----
libxfs/rdwr.c | 26 ++++++++++++++++++++------
mkfs/xfs_mkfs.c | 2 +-
repair/phase2.c | 2 +-
6 files changed, 33 insertions(+), 15 deletions(-)
diff --git a/copy/xfs_copy.c b/copy/xfs_copy.c
index 2f4f5cb..949be5f 100644
--- a/copy/xfs_copy.c
+++ b/copy/xfs_copy.c
@@ -1212,8 +1212,8 @@ write_log_header(int fd, wbuf *buf, xfs_mount_t *mp)
offset = libxfs_log_header(p, &buf->owner->uuid,
xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1,
- mp->m_sb.sb_logsunit, XLOG_FMT,
- next_log_chunk, buf);
+ mp->m_sb.sb_logsunit, XLOG_FMT, NULLCOMMITLSN,
+ NULLCOMMITLSN, next_log_chunk, buf);
do_write(buf->owner);
return roundup(logstart + offset, buf->length);
diff --git a/db/sb.c b/db/sb.c
index 598e787..560e653 100644
--- a/db/sb.c
+++ b/db/sb.c
@@ -278,7 +278,7 @@ sb_logzero(uuid_t *uuidp)
(xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks),
uuidp,
xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1,
- mp->m_sb.sb_logsunit, XLOG_FMT)) {
+ mp->m_sb.sb_logsunit, XLOG_FMT, XLOG_INIT_CYCLE)) {
dbprintf(_("ERROR: cannot clear the log\n"));
return 0;
}
diff --git a/include/libxfs.h b/include/libxfs.h
index cc06fc6..6c87934 100644
--- a/include/libxfs.h
+++ b/include/libxfs.h
@@ -149,10 +149,14 @@ extern int platform_nproc(void);
/* check or write log footer: specify device, log size in blocks & uuid */
typedef char *(libxfs_get_block_t)(char *, int, void *);
-extern int libxfs_log_clear (struct xfs_buftarg *, xfs_daddr_t, uint,
- uuid_t *, int, int, int);
-extern int libxfs_log_header (char *, uuid_t *, int, int, int,
- libxfs_get_block_t *, void *);
+/*
+ * Helpers to clear the log to a particular log cycle.
+ */
+#define XLOG_INIT_CYCLE 1
+extern int libxfs_log_clear(struct xfs_buftarg *, xfs_daddr_t, uint,
+ uuid_t *, int, int, int, int);
+extern int libxfs_log_header(char *, uuid_t *, int, int, int, xfs_lsn_t,
+ xfs_lsn_t, libxfs_get_block_t *, void *);
/* Shared utility routines */
diff --git a/libxfs/rdwr.c b/libxfs/rdwr.c
index 3c0179f..9cd7f3d 100644
--- a/libxfs/rdwr.c
+++ b/libxfs/rdwr.c
@@ -149,14 +149,21 @@ libxfs_log_clear(
uuid_t *fs_uuid,
int version,
int sunit,
- int fmt)
+ int fmt,
+ int cycle)
{
xfs_buf_t *bp;
int len;
+ xfs_lsn_t lsn;
if (!btp->dev || !fs_uuid)
return -EINVAL;
+ if (cycle != XLOG_INIT_CYCLE)
+ return -EINVAL;
+
+ lsn = xlog_assign_lsn(cycle, 0);
+
/* first zero the log */
libxfs_device_zero(btp, start, length);
@@ -164,8 +171,8 @@ libxfs_log_clear(
len = ((version == 2) && sunit) ? BTOBB(sunit) : 2;
len = MAX(len, 2);
bp = libxfs_getbufr(btp, start, len);
- libxfs_log_header(XFS_BUF_PTR(bp),
- fs_uuid, version, sunit, fmt, next, bp);
+ libxfs_log_header(XFS_BUF_PTR(bp), fs_uuid, version, sunit, fmt, lsn,
+ lsn, next, bp);
bp->b_flags |= LIBXFS_B_DIRTY;
libxfs_putbufr(bp);
return 0;
@@ -178,6 +185,8 @@ libxfs_log_header(
int version,
int sunit,
int fmt,
+ xfs_lsn_t lsn,
+ xfs_lsn_t tail_lsn,
libxfs_get_block_t *nextfunc,
void *private)
{
@@ -186,11 +195,16 @@ libxfs_log_header(
__be32 cycle_lsn;
int i, len;
+ if (lsn == NULLCOMMITLSN)
+ lsn = xlog_assign_lsn(XLOG_INIT_CYCLE, 0);
+ if (tail_lsn == NULLCOMMITLSN)
+ tail_lsn = lsn;
+
len = ((version == 2) && sunit) ? BTOBB(sunit) : 1;
memset(p, 0, BBSIZE);
head->h_magicno = cpu_to_be32(XLOG_HEADER_MAGIC_NUM);
- head->h_cycle = cpu_to_be32(1);
+ head->h_cycle = cpu_to_be32(CYCLE_LSN(lsn));
head->h_version = cpu_to_be32(version);
if (len != 1)
head->h_len = cpu_to_be32(sunit - BBSIZE);
@@ -202,8 +216,8 @@ libxfs_log_header(
head->h_fmt = cpu_to_be32(fmt);
head->h_size = cpu_to_be32(XLOG_HEADER_CYCLE_SIZE);
- head->h_lsn = cpu_to_be64(xlog_assign_lsn(1, 0));
- head->h_tail_lsn = cpu_to_be64(xlog_assign_lsn(1, 0));
+ head->h_lsn = cpu_to_be64(lsn);
+ head->h_tail_lsn = cpu_to_be64(tail_lsn);
memcpy(&head->h_fs_uuid, fs_uuid, sizeof(uuid_t));
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index d993fc0..238d400 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -2670,7 +2670,7 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
libxfs_log_clear(mp->m_logdev_targp,
XFS_FSB_TO_DADDR(mp, logstart),
(xfs_extlen_t)XFS_FSB_TO_BB(mp, logblocks),
- &sbp->sb_uuid, logversion, lsunit, XLOG_FMT);
+ &sbp->sb_uuid, logversion, lsunit, XLOG_FMT, XLOG_INIT_CYCLE);
mp = libxfs_mount(mp, sbp, xi.ddev, xi.logdev, xi.rtdev, 0);
if (mp == NULL) {
diff --git a/repair/phase2.c b/repair/phase2.c
index 7e264c4..0673a0c 100644
--- a/repair/phase2.c
+++ b/repair/phase2.c
@@ -98,7 +98,7 @@ zero_log(xfs_mount_t *mp)
(xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks),
&mp->m_sb.sb_uuid,
xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1,
- mp->m_sb.sb_logsunit, XLOG_FMT);
+ mp->m_sb.sb_logsunit, XLOG_FMT, XLOG_INIT_CYCLE);
}
/*
--
2.1.0
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 5/9] libxfs: add ability to clear log to arbitrary log cycle
2015-08-28 18:06 [PATCH 0/9] xfsprogs: handle the log correctly on v5 supers Brian Foster
` (3 preceding siblings ...)
2015-08-28 18:06 ` [PATCH 4/9] libxfs: pass lsn param to log clear and record header logging helpers Brian Foster
@ 2015-08-28 18:06 ` Brian Foster
2015-08-28 18:06 ` [PATCH 6/9] xfs_repair: track log state throughout all recovery phases Brian Foster
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Brian Foster @ 2015-08-28 18:06 UTC (permalink / raw)
To: xfs
The libxfs_log_clear() helper currently zeroes the log and writes a
single log record such that the kernel code detects the log has been
zeroed and mounts successfully. This is not sufficient for v5
filesystems, which must have the log cleared to an LSN that is
guaranteed to be ahead of any LSN that has been previously stamped into
on-disk metadata.
Update libxfs_log_clear() to support the ability to format the log to an
arbitrary cycle number. First, the log is physically zeroed. A log
record is written to the first block of the log with the desired lsn and
refers to the tail_lsn as the last record of the previous cycle. The
rest of the log is filled with log records of the previous cycle. This
causes the kernel to set the current LSN to start of the desired cycle
number at mount time.
Signed-off-by: Brian Foster <bfoster@redhat.com>
---
libxfs/rdwr.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 61 insertions(+), 6 deletions(-)
diff --git a/libxfs/rdwr.c b/libxfs/rdwr.c
index 9cd7f3d..8b6ded2 100644
--- a/libxfs/rdwr.c
+++ b/libxfs/rdwr.c
@@ -155,26 +155,81 @@ libxfs_log_clear(
xfs_buf_t *bp;
int len;
xfs_lsn_t lsn;
+ xfs_lsn_t tail_lsn;
+ xfs_daddr_t blk;
+ xfs_daddr_t end_blk;
if (!btp->dev || !fs_uuid)
return -EINVAL;
- if (cycle != XLOG_INIT_CYCLE)
+ if (cycle < XLOG_INIT_CYCLE)
return -EINVAL;
- lsn = xlog_assign_lsn(cycle, 0);
-
/* first zero the log */
libxfs_device_zero(btp, start, length);
- /* then write a log record header */
+ /*
+ * Initialize the log record length and LSNs. XLOG_INIT_CYCLE is a
+ * special reset case where we only write a single record where the lsn
+ * and tail_lsn match. Otherwise, the record lsn starts at block 0 of
+ * the specified cycle and points tail_lsn at the last record of the
+ * previous cycle.
+ */
len = ((version == 2) && sunit) ? BTOBB(sunit) : 2;
len = MAX(len, 2);
+ lsn = xlog_assign_lsn(cycle, 0);
+ if (cycle == XLOG_INIT_CYCLE)
+ tail_lsn = lsn;
+ else
+ tail_lsn = xlog_assign_lsn(cycle - 1, length - len);
+
+ /* write out the first log record */
bp = libxfs_getbufr(btp, start, len);
- libxfs_log_header(XFS_BUF_PTR(bp), fs_uuid, version, sunit, fmt, lsn,
- lsn, next, bp);
+ libxfs_log_header(XFS_BUF_PTR(bp), fs_uuid, version, sunit, fmt,
+ lsn, tail_lsn, next, bp);
bp->b_flags |= LIBXFS_B_DIRTY;
libxfs_putbufr(bp);
+
+ /*
+ * There's nothing else to do if this is a log reset. The kernel detects
+ * the rest of the log is zeroed and starts at cycle 1.
+ */
+ if (cycle == XLOG_INIT_CYCLE)
+ return 0;
+
+ /*
+ * Otherwise, fill everything beyond the initial record with records of
+ * the previous cycle so the kernel head/tail detection works correctly.
+ *
+ * We don't particularly care about the record size or content here.
+ * It's only important that the headers are in place such that the
+ * kernel finds 1.) a clean log and 2.) the correct current cycle value.
+ * Therefore, bump up the record size to the max to use larger I/Os and
+ * improve performance.
+ */
+ cycle--;
+ blk = start + len;
+ end_blk = start + length;
+
+ len = min(end_blk - blk, BTOBB(BDSTRAT_SIZE));
+ while (blk < end_blk) {
+ lsn = xlog_assign_lsn(cycle, blk - start);
+ tail_lsn = xlog_assign_lsn(cycle, blk - start - len);
+
+ bp = libxfs_getbufr(btp, blk, len);
+ /*
+ * Note: pass the full buffer length as the sunit to initialize
+ * the entire buffer.
+ */
+ libxfs_log_header(XFS_BUF_PTR(bp), fs_uuid, version, BBTOB(len),
+ fmt, lsn, tail_lsn, next, bp);
+ bp->b_flags |= LIBXFS_B_DIRTY;
+ libxfs_putbufr(bp);
+
+ len = min(end_blk - blk, BTOBB(BDSTRAT_SIZE));
+ blk += len;
+ }
+
return 0;
}
--
2.1.0
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 6/9] xfs_repair: track log state throughout all recovery phases
2015-08-28 18:06 [PATCH 0/9] xfsprogs: handle the log correctly on v5 supers Brian Foster
` (4 preceding siblings ...)
2015-08-28 18:06 ` [PATCH 5/9] libxfs: add ability to clear log to arbitrary log cycle Brian Foster
@ 2015-08-28 18:06 ` Brian Foster
2015-08-28 18:06 ` [PATCH 7/9] xfs_repair: process the log in no_modify mode Brian Foster
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Brian Foster @ 2015-08-28 18:06 UTC (permalink / raw)
To: xfs
xfs_repair examines and clears the log in phase 2. Phase 2 acquires the
log state in local data structures that are lost upon phase exit. v5
filesystems require that the log is formatted with a higher cycle number
after the fs is repaired. This requires assessment of the log state to
determine whether a reformat is necessary.
Rather than duplicate the log processing code, update phase 2 to
populate a globally available log data structure. Add a log pointer to
xfs_mount, as exists in kernel space, that repair uses to store a
reference to the log that is available to various phases. Note that this
patch simply plumbs through the global log data structure and does not
change behavior in any way.
Signed-off-by: Brian Foster <bfoster@redhat.com>
---
include/xfs_mount.h | 6 ++++++
repair/phase2.c | 34 +++++++++++++++++++---------------
repair/xfs_repair.c | 8 +++++++-
3 files changed, 32 insertions(+), 16 deletions(-)
diff --git a/include/xfs_mount.h b/include/xfs_mount.h
index ed897a2..5ec6866 100644
--- a/include/xfs_mount.h
+++ b/include/xfs_mount.h
@@ -98,6 +98,12 @@ typedef struct xfs_mount {
int qi_dqperchunk;
} *m_quotainfo;
+ /*
+ * xlog is defined in libxlog and thus is not intialized by libxfs. This
+ * allows an application to initialize and store a reference to the log
+ * if warranted.
+ */
+ struct xlog *m_log;
} xfs_mount_t;
/*
diff --git a/repair/phase2.c b/repair/phase2.c
index 0673a0c..11504e3 100644
--- a/repair/phase2.c
+++ b/repair/phase2.c
@@ -39,33 +39,33 @@ static void
zero_log(xfs_mount_t *mp)
{
int error;
- struct xlog log;
xfs_daddr_t head_blk, tail_blk;
+ struct xlog *log = mp->m_log;
- memset(&log, 0, sizeof(log));
+ memset(log, 0, sizeof(struct xlog));
x.logBBsize = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
x.logBBstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart);
x.lbsize = BBSIZE;
if (xfs_sb_version_hassector(&mp->m_sb))
x.lbsize <<= (mp->m_sb.sb_logsectlog - BBSHIFT);
- log.l_dev = mp->m_logdev_targp;
- log.l_logBBsize = x.logBBsize;
- log.l_logBBstart = x.logBBstart;
- log.l_sectBBsize = BTOBB(x.lbsize);
- log.l_mp = mp;
+ log->l_dev = mp->m_logdev_targp;
+ log->l_logBBsize = x.logBBsize;
+ log->l_logBBstart = x.logBBstart;
+ log->l_sectBBsize = BTOBB(x.lbsize);
+ log->l_mp = mp;
if (xfs_sb_version_hassector(&mp->m_sb)) {
- log.l_sectbb_log = mp->m_sb.sb_logsectlog - BBSHIFT;
- ASSERT(log.l_sectbb_log <= mp->m_sectbb_log);
+ log->l_sectbb_log = mp->m_sb.sb_logsectlog - BBSHIFT;
+ ASSERT(log->l_sectbb_log <= mp->m_sectbb_log);
/* for larger sector sizes, must have v2 or external log */
- ASSERT(log.l_sectbb_log == 0 ||
- log.l_logBBstart == 0 ||
+ ASSERT(log->l_sectbb_log == 0 ||
+ log->l_logBBstart == 0 ||
xfs_sb_version_haslogv2(&mp->m_sb));
ASSERT(mp->m_sb.sb_logsectlog >= BBSHIFT);
}
- log.l_sectbb_mask = (1 << log.l_sectbb_log) - 1;
+ log->l_sectbb_mask = (1 << log->l_sectbb_log) - 1;
- if ((error = xlog_find_tail(&log, &head_blk, &tail_blk))) {
+ if ((error = xlog_find_tail(log, &head_blk, &tail_blk))) {
do_warn(_("zero_log: cannot find log head/tail "
"(xlog_find_tail=%d), zeroing it anyway\n"),
error);
@@ -93,12 +93,16 @@ zero_log(xfs_mount_t *mp)
}
}
- libxfs_log_clear(log.l_dev,
- XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
+ libxfs_log_clear(log->l_dev, XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
(xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks),
&mp->m_sb.sb_uuid,
xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1,
mp->m_sb.sb_logsunit, XLOG_FMT, XLOG_INIT_CYCLE);
+
+ /* update the log data structure with new state */
+ error = xlog_find_tail(log, &head_blk, &tail_blk);
+ if (error || head_blk != tail_blk)
+ do_error(_("failed to clear log"));
}
/*
diff --git a/repair/xfs_repair.c b/repair/xfs_repair.c
index 85a012b..0e80124 100644
--- a/repair/xfs_repair.c
+++ b/repair/xfs_repair.c
@@ -539,6 +539,7 @@ main(int argc, char **argv)
xfs_dsb_t *dsb;
xfs_buf_t *sbp;
xfs_mount_t xfs_m;
+ struct xlog log = {0};
char *msgbuf;
struct xfs_sb psb;
int rval;
@@ -620,7 +621,11 @@ main(int argc, char **argv)
}
}
- /* prepare the mount structure */
+ /*
+ * Prepare the mount structure. Point the log reference to our local
+ * copy so it's available to the various phases. The log bits are
+ * initialized in phase 2.
+ */
memset(&xfs_m, 0, sizeof(xfs_mount_t));
mp = libxfs_mount(&xfs_m, &psb, x.ddev, x.logdev, x.rtdev, 0);
@@ -630,6 +635,7 @@ main(int argc, char **argv)
progname);
exit(1);
}
+ mp->m_log = &log;
/*
* set XFS-independent status vars from the mount/sb structure
--
2.1.0
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 7/9] xfs_repair: process the log in no_modify mode
2015-08-28 18:06 [PATCH 0/9] xfsprogs: handle the log correctly on v5 supers Brian Foster
` (5 preceding siblings ...)
2015-08-28 18:06 ` [PATCH 6/9] xfs_repair: track log state throughout all recovery phases Brian Foster
@ 2015-08-28 18:06 ` Brian Foster
2015-08-28 18:06 ` [PATCH 8/9] xfs_repair: format the log with forward cycle number on v5 supers Brian Foster
2015-08-28 18:06 ` [PATCH 9/9] xfs_repair: don't clear the log by default Brian Foster
8 siblings, 0 replies; 10+ messages in thread
From: Brian Foster @ 2015-08-28 18:06 UTC (permalink / raw)
To: xfs
xfs_repair does not zero the log in no_modify mode. In doing so, it also
skips the function that scans the log, locates the head/tail blocks and
sets the current LSN. Now that the log state is used beyond phase 2, the
log scan must occur regardless of whether no_modify mode is enabled or
not.
Update phase 2 to always execute the log scanning code. Push down the
no_modify checks into the log clearing helper such that the log is still
not modified in no_modify mode.
Signed-off-by: Brian Foster <bfoster@redhat.com>
---
repair/phase2.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/repair/phase2.c b/repair/phase2.c
index 11504e3..72132ce 100644
--- a/repair/phase2.c
+++ b/repair/phase2.c
@@ -75,7 +75,7 @@ zero_log(xfs_mount_t *mp)
_("zero_log: head block %" PRId64 " tail block %" PRId64 "\n"),
head_blk, tail_blk);
}
- if (head_blk != tail_blk) {
+ if (!no_modify && head_blk != tail_blk) {
if (zap_log) {
do_warn(_(
"ALERT: The filesystem has valuable metadata changes in a log which is being\n"
@@ -93,6 +93,9 @@ zero_log(xfs_mount_t *mp)
}
}
+ if (no_modify)
+ return;
+
libxfs_log_clear(log->l_dev, XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
(xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks),
&mp->m_sb.sb_uuid,
@@ -136,10 +139,8 @@ phase2(
do_log(_("Phase 2 - using internal log\n"));
/* Zero log if applicable */
- if (!no_modify) {
- do_log(_(" - zero log...\n"));
- zero_log(mp);
- }
+ do_log(_(" - zero log...\n"));
+ zero_log(mp);
do_log(_(" - scan filesystem freespace and inode maps...\n"));
--
2.1.0
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 8/9] xfs_repair: format the log with forward cycle number on v5 supers
2015-08-28 18:06 [PATCH 0/9] xfsprogs: handle the log correctly on v5 supers Brian Foster
` (6 preceding siblings ...)
2015-08-28 18:06 ` [PATCH 7/9] xfs_repair: process the log in no_modify mode Brian Foster
@ 2015-08-28 18:06 ` Brian Foster
2015-08-28 18:06 ` [PATCH 9/9] xfs_repair: don't clear the log by default Brian Foster
8 siblings, 0 replies; 10+ messages in thread
From: Brian Foster @ 2015-08-28 18:06 UTC (permalink / raw)
To: xfs
v5 filesystems use the current LSN and the last modified LSN stored
within fs metadata to provide correct log recovery ordering. xfs_repair
historically clears the log in phase 2. This resets to the current LSN
of the filesystem to the initial cycle, as if the fs was just created.
This is problematic because the filesystem LSN is now behind many
pre-existing metadata structures on-disk until either the current
filesystem LSN catches up or those particular data structures are
modified and written out. If a filesystem crash occurs in the meantime,
log recovery can incorrectly skip log items and cause filesystem
corruption.
Update xfs_repair to check the maximum metadata LSN value against the
current log state once the filesystem has been processed. If the maximum
LSN exceeds the current LSN with respect to the log, reformat the log
with a cycle number that exceeds that of the maximum LSN.
Signed-off-by: Brian Foster <bfoster@redhat.com>
---
repair/xfs_repair.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 68 insertions(+), 2 deletions(-)
diff --git a/repair/xfs_repair.c b/repair/xfs_repair.c
index 0e80124..8285d9d 100644
--- a/repair/xfs_repair.c
+++ b/repair/xfs_repair.c
@@ -531,6 +531,63 @@ _("sb realtime summary inode %" PRIu64 " %sinconsistent with calculated value %u
}
+/*
+ * v5 superblock metadata track the LSN of last modification and thus require
+ * that the current LSN is always moving forward. The current LSN is reset if
+ * the log has been cleared, which puts the log behind parts of the filesystem
+ * on-disk and can disrupt log recovery.
+ *
+ * We have tracked the maximum LSN of every piece of metadata that has been read
+ * in via the read verifiers. Compare the max LSN with the log and if the log is
+ * behind, bump the cycle number and reformat the log.
+ */
+static void
+format_log_max_lsn(
+ struct xfs_mount *mp)
+{
+ struct xlog *log = mp->m_log;
+ int max_cycle;
+ int max_block;
+ int new_cycle;
+ xfs_daddr_t logstart;
+ xfs_daddr_t logblocks;
+ int logversion;
+
+ if (!xfs_sb_version_hascrc(&mp->m_sb))
+ return;
+
+ /*
+ * If the log is ahead of the highest metadata LSN we've seen, we're
+ * safe and there's nothing to do.
+ */
+ max_cycle = CYCLE_LSN(libxfs_max_lsn);
+ max_block = BLOCK_LSN(libxfs_max_lsn);
+ if (max_cycle < log->l_curr_cycle ||
+ (max_cycle == log->l_curr_cycle && max_block < log->l_curr_block))
+ return;
+
+ /*
+ * Going to the next cycle should be sufficient but we bump by a few
+ * counts to help cover any metadata LSNs we could have missed.
+ */
+ new_cycle = max_cycle + 3;
+ logstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart);
+ logblocks = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
+ logversion = xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1;
+
+ do_warn(_("Maximum metadata LSN (%d:%d) is ahead of log (%d:%d).\n"),
+ max_cycle, max_block, log->l_curr_cycle, log->l_curr_block);
+
+ if (no_modify) {
+ do_warn(_("Would format log to cycle %d.\n"), new_cycle);
+ return;
+ }
+
+ do_warn(_("Format log to cycle %d.\n"), new_cycle);
+ libxfs_log_clear(log->l_dev, logstart, logblocks, &mp->m_sb.sb_uuid,
+ logversion, mp->m_sb.sb_logsunit, XLOG_FMT, new_cycle);
+}
+
int
main(int argc, char **argv)
{
@@ -896,6 +953,12 @@ _("Warning: project quota information would be cleared.\n"
stop_progress_rpt();
if (no_modify) {
+ /*
+ * Warn if the current LSN is problematic and the log requires a
+ * reformat.
+ */
+ format_log_max_lsn(mp);
+
do_log(
_("No modify flag set, skipping filesystem flush and exiting.\n"));
if (verbose)
@@ -931,11 +994,14 @@ _("Note - stripe unit (%d) and width (%d) were copied from a backup superblock.\
libxfs_writebuf(sbp, 0);
/*
- * Done, flush all cached buffers and inodes.
+ * Done. Flush all cached buffers and inodes first to ensure all
+ * verifiers are run (where we discover the max metadata LSN), reformat
+ * the log if necessary and unmount.
*/
libxfs_bcache_flush();
-
+ format_log_max_lsn(mp);
libxfs_umount(mp);
+
if (x.rtdev)
libxfs_device_close(x.rtdev);
if (x.logdev && x.logdev != x.ddev)
--
2.1.0
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 9/9] xfs_repair: don't clear the log by default
2015-08-28 18:06 [PATCH 0/9] xfsprogs: handle the log correctly on v5 supers Brian Foster
` (7 preceding siblings ...)
2015-08-28 18:06 ` [PATCH 8/9] xfs_repair: format the log with forward cycle number on v5 supers Brian Foster
@ 2015-08-28 18:06 ` Brian Foster
8 siblings, 0 replies; 10+ messages in thread
From: Brian Foster @ 2015-08-28 18:06 UTC (permalink / raw)
To: xfs
xfs_repair currently clears the log regardless of whether it is
corrupted, clean or contains data. This is traditionally harmless but
now causes log recovery problems on v5 filesystems. v5 filesystems
expect a clean log to always have an LSN out ahead of the maximum last
modification LSN stamped on any bit of metadata throughout the fs. If
this is not the case, repair must reformat the log with a larger cycle
number after fs processing is complete.
Given that unconditional log clearing actually introduces a filesystem
inconsistency on v5 superblocks (that repair must subsequently recover
from) and provides no tangible benefit for v4 filesystems that otherwise
have a clean and covered log, it is more appropriate behavior to not
clear the log by default.
Update xfs_repair to always and only clear the log when the -L parameter
is specified. Retain the existing logic to require -L or otherwise exit
if the log appears to contain data. Adopt similar behavior if the log
appears to be corrupted.
Signed-off-by: Brian Foster <bfoster@redhat.com>
---
repair/phase2.c | 60 ++++++++++++++++++++++++++++++++++++++-------------------
1 file changed, 40 insertions(+), 20 deletions(-)
diff --git a/repair/phase2.c b/repair/phase2.c
index 72132ce..fe7ed2b 100644
--- a/repair/phase2.c
+++ b/repair/phase2.c
@@ -36,11 +36,13 @@ int xlog_recover_do_trans(struct xlog *log, xlog_recover_t *t, int p)
}
static void
-zero_log(xfs_mount_t *mp)
+zero_log(
+ struct xfs_mount *mp)
{
- int error;
- xfs_daddr_t head_blk, tail_blk;
- struct xlog *log = mp->m_log;
+ int error;
+ xfs_daddr_t head_blk;
+ xfs_daddr_t tail_blk;
+ struct xlog *log = mp->m_log;
memset(log, 0, sizeof(struct xlog));
x.logBBsize = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
@@ -65,10 +67,22 @@ zero_log(xfs_mount_t *mp)
}
log->l_sectbb_mask = (1 << log->l_sectbb_log) - 1;
- if ((error = xlog_find_tail(log, &head_blk, &tail_blk))) {
- do_warn(_("zero_log: cannot find log head/tail "
- "(xlog_find_tail=%d), zeroing it anyway\n"),
+ /*
+ * Find the log head and tail and alert the user to the situation if the
+ * log appears corrupted or contains data. In either case, we do not
+ * proceed past this point unless the user explicitly requests to zap
+ * the log.
+ */
+ error = xlog_find_tail(log, &head_blk, &tail_blk);
+ if (error) {
+ do_warn(
+ _("zero_log: cannot find log head/tail (xlog_find_tail=%d)\n"),
error);
+ if (!no_modify && !zap_log)
+ do_error(_(
+"ERROR: The log head and/or tail cannot be discovered. Attempt to mount the\n"
+"filesystem to replay the log or use the -L option to destroy the log and\n"
+"attempt a repair.\n"));
} else {
if (verbose) {
do_warn(
@@ -93,19 +107,25 @@ zero_log(xfs_mount_t *mp)
}
}
- if (no_modify)
- return;
-
- libxfs_log_clear(log->l_dev, XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
- (xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks),
- &mp->m_sb.sb_uuid,
- xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1,
- mp->m_sb.sb_logsunit, XLOG_FMT, XLOG_INIT_CYCLE);
-
- /* update the log data structure with new state */
- error = xlog_find_tail(log, &head_blk, &tail_blk);
- if (error || head_blk != tail_blk)
- do_error(_("failed to clear log"));
+ /*
+ * Only clear the log when explicitly requested. Doing so is unnecessary
+ * unless something is wrong. Further, this resets the current LSN of
+ * the filesystem and creates more work for repair of v5 superblock
+ * filesystems.
+ */
+ if (!no_modify && zap_log) {
+ libxfs_log_clear(log->l_dev,
+ XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
+ (xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks),
+ &mp->m_sb.sb_uuid,
+ xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1,
+ mp->m_sb.sb_logsunit, XLOG_FMT, XLOG_INIT_CYCLE);
+
+ /* update the log data structure with new state */
+ error = xlog_find_tail(log, &head_blk, &tail_blk);
+ if (error || head_blk != tail_blk)
+ do_error(_("failed to clear log"));
+ }
}
/*
--
2.1.0
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply related [flat|nested] 10+ messages in thread