public inbox for linux-xfs@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/18] xfsprogs: format the log correctly on v5 supers
@ 2015-10-02 18:19 Brian Foster
  2015-10-02 18:19 ` [PATCH v3 01/18] libxfs: validate metadata LSNs against log on v5 superblocks Brian Foster
                   ` (17 more replies)
  0 siblings, 18 replies; 19+ messages in thread
From: Brian Foster @ 2015-10-02 18:19 UTC (permalink / raw)
  To: xfs

Hi all,

Here is v3 of the userspace v5 log formatting fixes. This version is based on
the latest variant of the kernel metadata LSN verification patch:

  http://oss.sgi.com/pipermail/xfs/2015-September/043846.html

The updates are relatively minor with the exception of added support for
xfs_copy. Patches 1-6 update libxfs/libxlog to support max. metadata LSN
tracking, cycle-specific log formatting and otherwise prepare for subsequent
fixes. Patches 7-11 update xfs_repair to no longer zero the log by default and
format v5 logs correctly based on the maximum seen metadata LSN. Patches 12-13
update the xfs_db uuid and metadump commands to bump the cycle number when
formatting v5 logs. Patch 14 is an independent bug fix to enable xfs_copy to
detect and warn about a dirty log in the source filesystem. Patches 15-18
refactor and fix xfs_copy to also bump the cycle number when formatting v5 logs.

Thoughts, reviews, flames appreciated.

Brian

v3:
- Rebased on latest LSN validation kernel patch.
- Added comment for dummy log clearing tid.
- Seed max lsn value from initial log state in xfs_repair.
- Added xfs_copy fixes (non-dup. dirty log fix + v5 log format fixes).
v2: http://oss.sgi.com/pipermail/xfs/2015-September/043630.html
- Rebase to latest kernel variant of invalid metadata LSN detection.
- Added support for xfs_db's uuid command and xfs_metadump.
v1: http://oss.sgi.com/pipermail/xfs/2015-August/043397.html

Brian Foster (18):
  libxfs: validate metadata LSNs against log on v5 superblocks
  libxfs: track largest metadata LSN in use via verifiers
  libxfs: don't hardcode cycle 1 into unmount op header
  libxfs: pass lsn param to log clear and record header logging helpers
  libxfs: add ability to clear log to arbitrary log cycle
  libxlog: pull struct xlog out of xlog_is_dirty()
  xfs_repair: track log state throughout all recovery phases
  xfs_repair: process the log in no_modify mode
  xfs_repair: format the log with forward cycle number on v5 supers
  xfs_repair: don't clear the log by default
  xfs_repair: seed the max lsn from log state in phase 2
  xfs_db: do not reset current lsn from uuid command on v5 supers
  db/metadump: bump lsn when log is cleared on v5 supers
  xfs_copy: check for dirty log on non-duplicate copies
  xfs_copy: genericize write helper to facilitate separate log buf
  xfs_copy: store data buf alignment in buf data structure
  xfs_copy: refactor log format code into new helper
  xfs_copy: format v5 sb logs correctly

 Makefile                    |   2 +-
 copy/Makefile               |   4 +-
 copy/xfs_copy.c             | 196 +++++++++++++++++++++++++++++++++++---------
 copy/xfs_copy.h             |   1 +
 db/init.c                   |  25 +++---
 db/metadump.c               |  21 ++++-
 db/sb.c                     |  18 +++-
 include/libxfs.h            |  13 ++-
 include/libxlog.h           |   3 +-
 include/xfs_mount.h         |   6 ++
 libxfs/libxfs_priv.h        |   2 +
 libxfs/rdwr.c               | 160 ++++++++++++++++++++++++++++++------
 libxfs/util.c               |  41 +++++++++
 libxfs/xfs_alloc.c          |  12 ++-
 libxfs/xfs_attr_leaf.c      |   2 +
 libxfs/xfs_btree.c          |  16 +++-
 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 +
 libxlog/util.c              |  37 +++++----
 mkfs/xfs_mkfs.c             |   4 +-
 repair/phase2.c             |  90 +++++++++++++-------
 repair/xfs_repair.c         |  79 +++++++++++++++++-
 28 files changed, 614 insertions(+), 150 deletions(-)

-- 
2.1.0

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 01/18] libxfs: validate metadata LSNs against log on v5 superblocks
  2015-10-02 18:19 [PATCH v3 00/18] xfsprogs: format the log correctly on v5 supers Brian Foster
@ 2015-10-02 18:19 ` Brian Foster
  2015-10-02 18:19 ` [PATCH v3 02/18] libxfs: track largest metadata LSN in use via verifiers Brian Foster
                   ` (16 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Brian Foster @ 2015-10-02 18:19 UTC (permalink / raw)
  To: xfs

Backport the associated kernel commit. Replace the xfs_log_check_lsn()
helper with a stub.

Signed-off-by: Brian Foster <bfoster@redhat.com>
---
 libxfs/libxfs_priv.h        |  2 ++
 libxfs/util.c               |  8 ++++++++
 libxfs/xfs_alloc.c          | 12 +++++++++---
 libxfs/xfs_attr_leaf.c      |  2 ++
 libxfs/xfs_btree.c          | 16 ++++++++++++++--
 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, 65 insertions(+), 7 deletions(-)

diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h
index 22f2d53..9135aac 100644
--- a/libxfs/libxfs_priv.h
+++ b/libxfs/libxfs_priv.h
@@ -505,4 +505,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_log_check_lsn(struct xfs_mount *, xfs_lsn_t);
+
 #endif	/* __LIBXFS_INTERNAL_XFS_H__ */
diff --git a/libxfs/util.c b/libxfs/util.c
index c9f9175..fcf6e96 100644
--- a/libxfs/util.c
+++ b/libxfs/util.c
@@ -729,3 +729,11 @@ xfs_verifier_error(
 		  bp->b_error == -EFSBADCRC ? "CRC error" : "corruption",
 		  bp->b_bn, BBTOB(bp->b_length));
 }
+
+bool
+xfs_log_check_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..95c8d44 100644
--- a/libxfs/xfs_alloc.c
+++ b/libxfs/xfs_alloc.c
@@ -478,7 +478,9 @@ xfs_agfl_verify(
 		    be32_to_cpu(agfl->agfl_bno[i]) >= mp->m_sb.sb_agblocks)
 			return false;
 	}
-	return true;
+
+	return xfs_log_check_lsn(mp,
+				 be64_to_cpu(XFS_BUF_TO_AGFL(bp)->agfl_lsn));
 }
 
 static void
@@ -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_log_check_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..bf473eb 100644
--- a/libxfs/xfs_attr_leaf.c
+++ b/libxfs/xfs_attr_leaf.c
@@ -262,6 +262,8 @@ xfs_attr3_leaf_verify(
 			return false;
 		if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
 			return false;
+		if (!xfs_log_check_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..f28e3a5 100644
--- a/libxfs/xfs_btree.c
+++ b/libxfs/xfs_btree.c
@@ -240,8 +240,14 @@ 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_log_check_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 +278,14 @@ 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_log_check_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 289dc1e..bdd60a0 100644
--- a/libxfs/xfs_da_btree.c
+++ b/libxfs/xfs_da_btree.c
@@ -146,6 +146,8 @@ xfs_da3_node_verify(
 			return false;
 		if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
 			return false;
+		if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->info.lsn)))
+			return false;
 	} else {
 		if (ichdr.magic != XFS_DA_NODE_MAGIC)
 			return false;
@@ -318,6 +320,7 @@ xfs_da3_node_create(
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		struct xfs_da3_node_hdr *hdr3 = bp->b_addr;
 
+		memset(hdr3, 0, sizeof(struct xfs_da3_node_hdr));
 		ichdr.magic = XFS_DA3_NODE_MAGIC;
 		hdr3->info.blkno = cpu_to_be64(bp->b_bn);
 		hdr3->info.owner = cpu_to_be64(args->dp->i_ino);
diff --git a/libxfs/xfs_dir2_block.c b/libxfs/xfs_dir2_block.c
index 489f301..d7ba0e9 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_log_check_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..37b3b68 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_log_check_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..77c2e65 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_log_check_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..689a3fd 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_log_check_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..d39f9b6 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_log_check_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..c293d68 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_log_check_lsn(mp, sbp->sb_lsn))
+			return -EFSCORRUPTED;
 	}
 
 	if (xfs_sb_version_has_pquotino(sbp)) {
diff --git a/libxfs/xfs_symlink_remote.c b/libxfs/xfs_symlink_remote.c
index 7d46d9e..647444a 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_log_check_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] 19+ messages in thread

* [PATCH v3 02/18] libxfs: track largest metadata LSN in use via verifiers
  2015-10-02 18:19 [PATCH v3 00/18] xfsprogs: format the log correctly on v5 supers Brian Foster
  2015-10-02 18:19 ` [PATCH v3 01/18] libxfs: validate metadata LSNs against log on v5 superblocks Brian Foster
@ 2015-10-02 18:19 ` Brian Foster
  2015-10-02 18:19 ` [PATCH v3 03/18] libxfs: don't hardcode cycle 1 into unmount op header Brian Foster
                   ` (15 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Brian Foster @ 2015-10-02 18:19 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    | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 34 insertions(+)

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 fcf6e96..6192e6c 100644
--- a/libxfs/util.c
+++ b/libxfs/util.c
@@ -730,10 +730,43 @@ xfs_verifier_error(
 		  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 this kind of
+ * validation is not required. Therefore, this function always returns true in
+ * userspace.
+ *
+ * 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_log_check_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] 19+ messages in thread

* [PATCH v3 03/18] libxfs: don't hardcode cycle 1 into unmount op header
  2015-10-02 18:19 [PATCH v3 00/18] xfsprogs: format the log correctly on v5 supers Brian Foster
  2015-10-02 18:19 ` [PATCH v3 01/18] libxfs: validate metadata LSNs against log on v5 superblocks Brian Foster
  2015-10-02 18:19 ` [PATCH v3 02/18] libxfs: track largest metadata LSN in use via verifiers Brian Foster
@ 2015-10-02 18:19 ` Brian Foster
  2015-10-02 18:19 ` [PATCH v3 04/18] libxfs: pass lsn param to log clear and record header logging helpers Brian Foster
                   ` (14 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Brian Foster @ 2015-10-02 18:19 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 | 24 +++++++++++++++++-------
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/libxfs/rdwr.c b/libxfs/rdwr.c
index bc77699..282f22d 100644
--- a/libxfs/rdwr.c
+++ b/libxfs/rdwr.c
@@ -122,7 +122,8 @@ static void unmount_record(void *p)
 	} magic = { XLOG_UNMOUNT_TYPE, 0, 0 };
 
 	memset(p, 0, BBSIZE);
-	op->oh_tid = cpu_to_be32(1);
+	/* dummy tid to mark this as written from userspace */
+	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 +189,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 +200,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 +208,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] 19+ messages in thread

* [PATCH v3 04/18] libxfs: pass lsn param to log clear and record header logging helpers
  2015-10-02 18:19 [PATCH v3 00/18] xfsprogs: format the log correctly on v5 supers Brian Foster
                   ` (2 preceding siblings ...)
  2015-10-02 18:19 ` [PATCH v3 03/18] libxfs: don't hardcode cycle 1 into unmount op header Brian Foster
@ 2015-10-02 18:19 ` Brian Foster
  2015-10-02 18:19 ` [PATCH v3 05/18] libxfs: add ability to clear log to arbitrary log cycle Brian Foster
                   ` (13 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Brian Foster @ 2015-10-02 18:19 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 282f22d..da781da 100644
--- a/libxfs/rdwr.c
+++ b/libxfs/rdwr.c
@@ -150,14 +150,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);
 
@@ -165,8 +172,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;
@@ -179,6 +186,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)
 {
@@ -187,11 +196,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);
@@ -203,8 +217,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] 19+ messages in thread

* [PATCH v3 05/18] libxfs: add ability to clear log to arbitrary log cycle
  2015-10-02 18:19 [PATCH v3 00/18] xfsprogs: format the log correctly on v5 supers Brian Foster
                   ` (3 preceding siblings ...)
  2015-10-02 18:19 ` [PATCH v3 04/18] libxfs: pass lsn param to log clear and record header logging helpers Brian Foster
@ 2015-10-02 18:19 ` Brian Foster
  2015-10-02 18:19 ` [PATCH v3 06/18] libxlog: pull struct xlog out of xlog_is_dirty() Brian Foster
                   ` (12 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Brian Foster @ 2015-10-02 18:19 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 | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 60 insertions(+), 8 deletions(-)

diff --git a/libxfs/rdwr.c b/libxfs/rdwr.c
index da781da..93f6eb7 100644
--- a/libxfs/rdwr.c
+++ b/libxfs/rdwr.c
@@ -156,26 +156,78 @@ 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)
-		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] 19+ messages in thread

* [PATCH v3 06/18] libxlog: pull struct xlog out of xlog_is_dirty()
  2015-10-02 18:19 [PATCH v3 00/18] xfsprogs: format the log correctly on v5 supers Brian Foster
                   ` (4 preceding siblings ...)
  2015-10-02 18:19 ` [PATCH v3 05/18] libxfs: add ability to clear log to arbitrary log cycle Brian Foster
@ 2015-10-02 18:19 ` Brian Foster
  2015-10-02 18:19 ` [PATCH v3 07/18] xfs_repair: track log state throughout all recovery phases Brian Foster
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Brian Foster @ 2015-10-02 18:19 UTC (permalink / raw)
  To: xfs

The xlog_is_dirty() helper is called in various places to acquire the
current log head, tail and to determine whether the log is dirty. Some
callers will require additional information to deal with formatting the
log, such as the current LSN. xlog_is_dirty() already acquires this
information through existing sub-helpers, but it is not available to
callers as the xlog structure is allocated on the local stack.

Update xlog_is_dirty() to receive the xlog structure as a parameter and
pass it along such that additional information about the log is
available to callers. Update the existing callers to allocate the xlog
structure on the stack.

Signed-off-by: Brian Foster <bfoster@redhat.com>
---
 db/metadump.c     |  5 +++--
 db/sb.c           |  3 ++-
 include/libxlog.h |  3 ++-
 libxlog/util.c    | 37 +++++++++++++++++++------------------
 4 files changed, 26 insertions(+), 22 deletions(-)

diff --git a/db/metadump.c b/db/metadump.c
index af96e12..129670e 100644
--- a/db/metadump.c
+++ b/db/metadump.c
@@ -2512,7 +2512,8 @@ copy_sb_inodes(void)
 static int
 copy_log(void)
 {
-	int dirty;
+	struct xlog	log;
+	int		dirty;
 
 	if (show_progress)
 		print_progress("Copying log");
@@ -2530,7 +2531,7 @@ copy_log(void)
 	if (!obfuscate && !zero_stale_data)
 		goto done;
 
-	dirty = xlog_is_dirty(mp, &x, 0);
+	dirty = xlog_is_dirty(mp, &log, &x, 0);
 
 	switch (dirty) {
 	case 0:
diff --git a/db/sb.c b/db/sb.c
index 560e653..9c585ca 100644
--- a/db/sb.c
+++ b/db/sb.c
@@ -229,6 +229,7 @@ int xlog_recover_do_trans(struct xlog *log, xlog_recover_t *t, int p)
 int
 sb_logcheck(void)
 {
+	struct xlog	log;
 	int		dirty;
 
 	if (mp->m_sb.sb_logstart) {
@@ -247,7 +248,7 @@ sb_logcheck(void)
 
 	libxfs_buftarg_init(mp, x.ddev, x.logdev, x.rtdev);
 
-	dirty = xlog_is_dirty(mp, &x, 0);
+	dirty = xlog_is_dirty(mp, &log, &x, 0);
 	if (dirty == -1) {
 		dbprintf(_("ERROR: cannot find log head/tail, run xfs_repair\n"));
 		return 0;
diff --git a/include/libxlog.h b/include/libxlog.h
index 05b16e8..6c6e83a 100644
--- a/include/libxlog.h
+++ b/include/libxlog.h
@@ -84,7 +84,8 @@ extern int	print_record_header;
 extern libxfs_init_t	x;
 
 
-extern int xlog_is_dirty(xfs_mount_t *mp, libxfs_init_t *x, int verbose);
+extern int xlog_is_dirty(struct xfs_mount *, struct xlog *, libxfs_init_t *,
+			 int);
 extern struct xfs_buf *xlog_get_bp(struct xlog *, int);
 extern void	xlog_put_bp(struct xfs_buf *);
 extern int	xlog_bread(struct xlog *log, xfs_daddr_t blk_no, int nbblks,
diff --git a/libxlog/util.c b/libxlog/util.c
index c6b8f2a..72b8b18 100644
--- a/libxlog/util.c
+++ b/libxlog/util.c
@@ -29,15 +29,15 @@ libxfs_init_t x;
  */
 int
 xlog_is_dirty(
-	xfs_mount_t *mp,
-	libxfs_init_t *x,
-	int verbose)
+	struct xfs_mount	*mp,
+	struct xlog		*log,
+	libxfs_init_t		*x,
+	int			verbose)
 {
-	int error;
-	struct xlog	log;
-	xfs_daddr_t head_blk, tail_blk;
+	int			error;
+	xfs_daddr_t		head_blk, tail_blk;
 
-	memset(&log, 0, sizeof(log));
+	memset(log, 0, sizeof(*log));
 
 	/* We (re-)init members of libxfs_init_t here?  really? */
 	x->logBBsize = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
@@ -46,23 +46,24 @@ xlog_is_dirty(
 	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))) {
+	error = xlog_find_tail(log, &head_blk, &tail_blk);
+	if (error) {
 		xlog_warn(_("%s: cannot find log head/tail "
 			  "(xlog_find_tail=%d)\n"),
 			__func__, error);
-- 
2.1.0

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 07/18] xfs_repair: track log state throughout all recovery phases
  2015-10-02 18:19 [PATCH v3 00/18] xfsprogs: format the log correctly on v5 supers Brian Foster
                   ` (5 preceding siblings ...)
  2015-10-02 18:19 ` [PATCH v3 06/18] libxlog: pull struct xlog out of xlog_is_dirty() Brian Foster
@ 2015-10-02 18:19 ` Brian Foster
  2015-10-02 18:19 ` [PATCH v3 08/18] xfs_repair: process the log in no_modify mode Brian Foster
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Brian Foster @ 2015-10-02 18:19 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] 19+ messages in thread

* [PATCH v3 08/18] xfs_repair: process the log in no_modify mode
  2015-10-02 18:19 [PATCH v3 00/18] xfsprogs: format the log correctly on v5 supers Brian Foster
                   ` (6 preceding siblings ...)
  2015-10-02 18:19 ` [PATCH v3 07/18] xfs_repair: track log state throughout all recovery phases Brian Foster
@ 2015-10-02 18:19 ` Brian Foster
  2015-10-02 18:19 ` [PATCH v3 09/18] xfs_repair: format the log with forward cycle number on v5 supers Brian Foster
                   ` (9 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Brian Foster @ 2015-10-02 18:19 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] 19+ messages in thread

* [PATCH v3 09/18] xfs_repair: format the log with forward cycle number on v5 supers
  2015-10-02 18:19 [PATCH v3 00/18] xfsprogs: format the log correctly on v5 supers Brian Foster
                   ` (7 preceding siblings ...)
  2015-10-02 18:19 ` [PATCH v3 08/18] xfs_repair: process the log in no_modify mode Brian Foster
@ 2015-10-02 18:19 ` Brian Foster
  2015-10-02 18:19 ` [PATCH v3 10/18] xfs_repair: don't clear the log by default Brian Foster
                   ` (8 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Brian Foster @ 2015-10-02 18:19 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] 19+ messages in thread

* [PATCH v3 10/18] xfs_repair: don't clear the log by default
  2015-10-02 18:19 [PATCH v3 00/18] xfsprogs: format the log correctly on v5 supers Brian Foster
                   ` (8 preceding siblings ...)
  2015-10-02 18:19 ` [PATCH v3 09/18] xfs_repair: format the log with forward cycle number on v5 supers Brian Foster
@ 2015-10-02 18:19 ` Brian Foster
  2015-10-02 18:19 ` [PATCH v3 11/18] xfs_repair: seed the max lsn from log state in phase 2 Brian Foster
                   ` (7 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Brian Foster @ 2015-10-02 18:19 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] 19+ messages in thread

* [PATCH v3 11/18] xfs_repair: seed the max lsn from log state in phase 2
  2015-10-02 18:19 [PATCH v3 00/18] xfsprogs: format the log correctly on v5 supers Brian Foster
                   ` (9 preceding siblings ...)
  2015-10-02 18:19 ` [PATCH v3 10/18] xfs_repair: don't clear the log by default Brian Foster
@ 2015-10-02 18:19 ` Brian Foster
  2015-10-02 18:19 ` [PATCH v3 12/18] xfs_db: do not reset current lsn from uuid command on v5 supers Brian Foster
                   ` (6 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Brian Foster @ 2015-10-02 18:19 UTC (permalink / raw)
  To: xfs

At this point, the log state is always available once repair has
progressed through phase 2 and the log is only ever zeroed when
absolutely necessary. This means that in the common case, repair runs
with the log in a non-initialized state. The libxfs max metadata LSN
tracking initializes the max LSN to zero, however, which will require
updates throughout the repair process even if all metadata LSNs are
behind the current LSN.

Since all metadata LSNs that are behind the current LSN are valid, seed
the libxfs maximum seen LSN value with the log state from phase 2. This
is a minor optimization to minimize global variable updates in the
common case where all (or most) metadata LSNs are valid.

Signed-off-by: Brian Foster <bfoster@redhat.com>
---
 repair/phase2.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/repair/phase2.c b/repair/phase2.c
index fe7ed2b..f9d0e22 100644
--- a/repair/phase2.c
+++ b/repair/phase2.c
@@ -126,6 +126,13 @@ zero_log(
 		if (error || head_blk != tail_blk)
 			do_error(_("failed to clear log"));
 	}
+
+	/*
+	 * Finally, seed the max LSN from the current state of the log if this
+	 * is a v5 filesystem.
+	 */
+	if (xfs_sb_version_hascrc(&mp->m_sb))
+		libxfs_max_lsn = log->l_last_sync_lsn;
 }
 
 /*
-- 
2.1.0

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 12/18] xfs_db: do not reset current lsn from uuid command on v5 supers
  2015-10-02 18:19 [PATCH v3 00/18] xfsprogs: format the log correctly on v5 supers Brian Foster
                   ` (10 preceding siblings ...)
  2015-10-02 18:19 ` [PATCH v3 11/18] xfs_repair: seed the max lsn from log state in phase 2 Brian Foster
@ 2015-10-02 18:19 ` Brian Foster
  2015-10-02 18:19 ` [PATCH v3 13/18] db/metadump: bump lsn when log is cleared " Brian Foster
                   ` (5 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Brian Foster @ 2015-10-02 18:19 UTC (permalink / raw)
  To: xfs

The xfs_db uuid command modifes the uuid of the filesystem. As part of
this process, it is required to clear the log and format it with records
that use the new uuid. It currently resets the log to cycle 1, which is
not safe for v5 superblocks.

Update the uuid log clearing implementation to bump the current cycle
when the log is formatted on v5 superblock filesystems. This ensures
that the current LSN remains ahead of metadata LSNs on the subsequent
mount. Since the log is checked and cleared across a couple different
functions, also add a new global xlog structure, associate it with the
preexisting global mount structure and reference it to get and use the
current log cycle.

Signed-off-by: Brian Foster <bfoster@redhat.com>
---
 db/init.c | 25 ++++++++++++++-----------
 db/sb.c   | 19 +++++++++++++++----
 2 files changed, 29 insertions(+), 15 deletions(-)

diff --git a/db/init.c b/db/init.c
index 9537a38..c0472c8 100644
--- a/db/init.c
+++ b/db/init.c
@@ -17,6 +17,7 @@
  */
 
 #include "libxfs.h"
+#include "libxlog.h"
 #include <signal.h>
 #include "command.h"
 #include "init.h"
@@ -28,17 +29,18 @@
 #include "malloc.h"
 #include "type.h"
 
-static char	**cmdline;
-static int	ncmdline;
-char		*fsdevice;
-int		blkbb;
-int		exitcode;
-int		expert_mode;
-int		force;
-xfs_mount_t	xmount;
-xfs_mount_t	*mp;
-libxfs_init_t	x;
-xfs_agnumber_t	cur_agno = NULLAGNUMBER;
+static char		**cmdline;
+static int		ncmdline;
+char			*fsdevice;
+int			blkbb;
+int			exitcode;
+int			expert_mode;
+int			force;
+struct xfs_mount	xmount;
+struct xfs_mount	*mp;
+struct xlog		xlog;
+libxfs_init_t		x;
+xfs_agnumber_t		cur_agno = NULLAGNUMBER;
 
 static void
 usage(void)
@@ -154,6 +156,7 @@ init(
 			progname, fsdevice);
 		exit(1);
 	}
+	mp->m_log = &xlog;
 	blkbb = 1 << mp->m_blkbb_log;
 
 	/*
diff --git a/db/sb.c b/db/sb.c
index 9c585ca..30c622d 100644
--- a/db/sb.c
+++ b/db/sb.c
@@ -229,7 +229,6 @@ int xlog_recover_do_trans(struct xlog *log, xlog_recover_t *t, int p)
 int
 sb_logcheck(void)
 {
-	struct xlog	log;
 	int		dirty;
 
 	if (mp->m_sb.sb_logstart) {
@@ -248,7 +247,7 @@ sb_logcheck(void)
 
 	libxfs_buftarg_init(mp, x.ddev, x.logdev, x.rtdev);
 
-	dirty = xlog_is_dirty(mp, &log, &x, 0);
+	dirty = xlog_is_dirty(mp, mp->m_log, &x, 0);
 	if (dirty == -1) {
 		dbprintf(_("ERROR: cannot find log head/tail, run xfs_repair\n"));
 		return 0;
@@ -269,20 +268,32 @@ sb_logcheck(void)
 static int
 sb_logzero(uuid_t *uuidp)
 {
+	int	cycle = XLOG_INIT_CYCLE;
+	int	error;
+
 	if (!sb_logcheck())
 		return 0;
 
+	/*
+	 * The log must always move forward on v5 superblocks. Bump it to the
+	 * next cycle.
+	 */
+	if (xfs_sb_version_hascrc(&mp->m_sb))
+		cycle = mp->m_log->l_curr_cycle + 1;
+
 	dbprintf(_("Clearing log and setting UUID\n"));
 
-	if (libxfs_log_clear(mp->m_logdev_targp,
+	error =  libxfs_log_clear(mp->m_logdev_targp,
 			XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
 			(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, XLOG_INIT_CYCLE)) {
+			mp->m_sb.sb_logsunit, XLOG_FMT, cycle);
+	if (error) {
 		dbprintf(_("ERROR: cannot clear the log\n"));
 		return 0;
 	}
+
 	return 1;
 }
 
-- 
2.1.0

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 13/18] db/metadump: bump lsn when log is cleared on v5 supers
  2015-10-02 18:19 [PATCH v3 00/18] xfsprogs: format the log correctly on v5 supers Brian Foster
                   ` (11 preceding siblings ...)
  2015-10-02 18:19 ` [PATCH v3 12/18] xfs_db: do not reset current lsn from uuid command on v5 supers Brian Foster
@ 2015-10-02 18:19 ` Brian Foster
  2015-10-02 18:19 ` [PATCH v3 14/18] xfs_copy: check for dirty log on non-duplicate copies Brian Foster
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Brian Foster @ 2015-10-02 18:19 UTC (permalink / raw)
  To: xfs

xfs_metadump handles the log in different ways depending on the mode of
operation. If the log is dirty or obfuscation and stale data zeroing are
disabled, the log is copied as is. In all other scenarios, the log is
explicitly zeroed. This is incorrect for version 5 superblocks where the
current LSN is always expected to be ahead of all fs metadata.

Update metadump to use libxfs_log_clear() to format the log with an
elevated LSN rather than zero the log and reset the current the LSN.
Metadump does not use buffers for the dump target, instead using a
cursor implementation to access the log via a single memory buffer.
Therefore, update libxfs_log_clear() to receive an optional (but
exclusive to the buftarg parameter) memory buffer pointer for the log.
If the pointer is provided, the log format is written out to this
buffer. Otherwise, fall back to the original behavior and access the log
through buftarg buffers.

Signed-off-by: Brian Foster <bfoster@redhat.com>
---
 db/metadump.c       | 16 +++++++++++--
 db/sb.c             |  2 +-
 include/libxfs.h    |  4 ++--
 libxfs/rdwr.c       | 68 +++++++++++++++++++++++++++++++++++++++--------------
 mkfs/xfs_mkfs.c     |  2 +-
 repair/phase2.c     |  2 +-
 repair/xfs_repair.c |  5 ++--
 7 files changed, 72 insertions(+), 27 deletions(-)

diff --git a/db/metadump.c b/db/metadump.c
index 129670e..56b733e 100644
--- a/db/metadump.c
+++ b/db/metadump.c
@@ -2514,6 +2514,10 @@ copy_log(void)
 {
 	struct xlog	log;
 	int		dirty;
+	xfs_daddr_t	logstart;
+	int		logblocks;
+	int		logversion;
+	int		cycle = XLOG_INIT_CYCLE;
 
 	if (show_progress)
 		print_progress("Copying log");
@@ -2538,8 +2542,16 @@ copy_log(void)
 		/* clear out a clean log */
 		if (show_progress)
 			print_progress("Zeroing clean log");
-		memset(iocur_top->data, 0,
-			mp->m_sb.sb_logblocks * mp->m_sb.sb_blocksize);
+
+		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;
+		if (xfs_sb_version_hascrc(&mp->m_sb))
+			cycle = log.l_curr_cycle + 1;
+
+		libxfs_log_clear(NULL, iocur_top->data, logstart, logblocks,
+				 &mp->m_sb.sb_uuid, logversion,
+				 mp->m_sb.sb_logsunit, XLOG_FMT, cycle);
 		break;
 	case 1:
 		/* keep the dirty log */
diff --git a/db/sb.c b/db/sb.c
index 30c622d..17d446c 100644
--- a/db/sb.c
+++ b/db/sb.c
@@ -283,7 +283,7 @@ sb_logzero(uuid_t *uuidp)
 
 	dbprintf(_("Clearing log and setting UUID\n"));
 
-	error =  libxfs_log_clear(mp->m_logdev_targp,
+	error =  libxfs_log_clear(mp->m_logdev_targp, NULL,
 			XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
 			(xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks),
 			uuidp,
diff --git a/include/libxfs.h b/include/libxfs.h
index 6c87934..f733c36 100644
--- a/include/libxfs.h
+++ b/include/libxfs.h
@@ -153,8 +153,8 @@ typedef char	*(libxfs_get_block_t)(char *, int, 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_clear(struct xfs_buftarg *, char *, 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 *);
 
diff --git a/libxfs/rdwr.c b/libxfs/rdwr.c
index 93f6eb7..ee41a1e 100644
--- a/libxfs/rdwr.c
+++ b/libxfs/rdwr.c
@@ -133,38 +133,54 @@ static void unmount_record(void *p)
 	memcpy((char *)p + sizeof(xlog_op_header_t), &magic, sizeof(magic));
 }
 
-static char *next(char *ptr, int offset, void *private)
+static char *next(
+	char		*ptr,
+	int		offset,
+	void		*private)
 {
-	xfs_buf_t	*buf = (xfs_buf_t *)private;
+	struct xfs_buf	*buf = (struct xfs_buf *)private;
 
-	if (XFS_BUF_COUNT(buf) < (int)(ptr - XFS_BUF_PTR(buf)) + offset)
+	if (buf &&
+	    (XFS_BUF_COUNT(buf) < (int)(ptr - XFS_BUF_PTR(buf)) + offset))
 		abort();
+
 	return ptr + offset;
 }
 
+/*
+ * Format the log. The caller provides either a buftarg which is used to access
+ * the log via buffers or a direct pointer to a buffer that encapsulates the
+ * entire log.
+ */
 int
 libxfs_log_clear(
 	struct xfs_buftarg	*btp,
+	char			*dptr,
 	xfs_daddr_t		start,
-	uint			length,
+	uint			length,		/* basic blocks */
 	uuid_t			*fs_uuid,
 	int			version,
-	int			sunit,
+	int			sunit,		/* bytes */
 	int			fmt,
 	int			cycle)
 {
-	xfs_buf_t		*bp;
+	struct xfs_buf		*bp = NULL;
 	int			len;
 	xfs_lsn_t		lsn;
 	xfs_lsn_t		tail_lsn;
 	xfs_daddr_t		blk;
 	xfs_daddr_t		end_blk;
+	char			*ptr;
 
-	if (!btp->dev || !fs_uuid)
+	if (((btp && dptr) || (!btp && !dptr)) ||
+	    (btp && !btp->dev) || !fs_uuid)
 		return -EINVAL;
 
 	/* first zero the log */
-	libxfs_device_zero(btp, start, length);
+	if (btp)
+		libxfs_device_zero(btp, start, length);
+	else
+		memset(dptr, 0, BBTOB(length));
 
 	/*
 	 * Initialize the log record length and LSNs. XLOG_INIT_CYCLE is a
@@ -182,11 +198,17 @@ libxfs_log_clear(
 		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, tail_lsn, next, bp);
-	bp->b_flags |= LIBXFS_B_DIRTY;
-	libxfs_putbufr(bp);
+	ptr = dptr;
+	if (btp) {
+		bp = libxfs_getbufr(btp, start, len);
+		ptr = XFS_BUF_PTR(bp);
+	}
+	libxfs_log_header(ptr, fs_uuid, version, sunit, fmt, lsn, tail_lsn,
+			  next, bp);
+	if (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
@@ -207,6 +229,8 @@ libxfs_log_clear(
 	 */
 	cycle--;
 	blk = start + len;
+	if (dptr)
+		dptr += BBTOB(len);
 	end_blk = start + length;
 
 	len = min(end_blk - blk, BTOBB(BDSTRAT_SIZE));
@@ -214,18 +238,26 @@ libxfs_log_clear(
 		lsn = xlog_assign_lsn(cycle, blk - start);
 		tail_lsn = xlog_assign_lsn(cycle, blk - start - len);
 
-		bp = libxfs_getbufr(btp, blk, len);
+		ptr = dptr;
+		if (btp) {
+			bp = libxfs_getbufr(btp, blk, len);
+			ptr = XFS_BUF_PTR(bp);
+		}
 		/*
 		 * 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);
+		libxfs_log_header(ptr, fs_uuid, version, BBTOB(len), fmt, lsn,
+				  tail_lsn, next, bp);
+		if (bp) {
+			bp->b_flags |= LIBXFS_B_DIRTY;
+			libxfs_putbufr(bp);
+		}
 
 		len = min(end_blk - blk, BTOBB(BDSTRAT_SIZE));
 		blk += len;
+		if (dptr)
+			dptr += BBTOB(len);
 	}
 
 	return 0;
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 238d400..5f939b5 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -2667,7 +2667,7 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
 	/*
 	 * Zero the log....
 	 */
-	libxfs_log_clear(mp->m_logdev_targp,
+	libxfs_log_clear(mp->m_logdev_targp, NULL,
 		XFS_FSB_TO_DADDR(mp, logstart),
 		(xfs_extlen_t)XFS_FSB_TO_BB(mp, logblocks),
 		&sbp->sb_uuid, logversion, lsunit, XLOG_FMT, XLOG_INIT_CYCLE);
diff --git a/repair/phase2.c b/repair/phase2.c
index f9d0e22..cb24711 100644
--- a/repair/phase2.c
+++ b/repair/phase2.c
@@ -114,7 +114,7 @@ zero_log(
 	 * filesystems.
 	 */
 	if (!no_modify && zap_log) {
-		libxfs_log_clear(log->l_dev,
+		libxfs_log_clear(log->l_dev, NULL,
 			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,
diff --git a/repair/xfs_repair.c b/repair/xfs_repair.c
index 8285d9d..bed2ff5 100644
--- a/repair/xfs_repair.c
+++ b/repair/xfs_repair.c
@@ -584,8 +584,9 @@ format_log_max_lsn(
 	}
 
 	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);
+	libxfs_log_clear(log->l_dev, NULL, logstart, logblocks,
+			 &mp->m_sb.sb_uuid, logversion, mp->m_sb.sb_logsunit,
+			 XLOG_FMT, new_cycle);
 }
 
 int
-- 
2.1.0

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 14/18] xfs_copy: check for dirty log on non-duplicate copies
  2015-10-02 18:19 [PATCH v3 00/18] xfsprogs: format the log correctly on v5 supers Brian Foster
                   ` (12 preceding siblings ...)
  2015-10-02 18:19 ` [PATCH v3 13/18] db/metadump: bump lsn when log is cleared " Brian Foster
@ 2015-10-02 18:19 ` Brian Foster
  2015-10-02 18:19 ` [PATCH v3 15/18] xfs_copy: genericize write helper to facilitate separate log buf Brian Foster
                   ` (3 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Brian Foster @ 2015-10-02 18:19 UTC (permalink / raw)
  To: xfs

xfs_copy either copies the log as-is or formats the log of the target(s)
based on whether duplicate copy mode is enabled. The target log is
formatted when non-duplicate mode is enabled because copies gain a new
fs UUID and the new UUID must be stamped into the log.

When non-duplicate mode is enabled, however, xfs_copy does not check
whether the source filesystem log is actually clean. If the source log
is dirty, the target filesystem is silently created with a clean log and
thus ends up in a potentially corrupted state.

Update xfs_copy to check the source log state and fail the copy if in
non-duplicate mode and the log is dirty. Encourage the user to mount the
filesystem or run xfs_repair to clear the log. Note that the log is
scanned unconditionally as opposed to only in non-duplicate mode because
v5 superblock log format support requires the current cycle number to
format the log correctly.

Signed-off-by: Brian Foster <bfoster@redhat.com>
---
 Makefile        |  2 +-
 copy/Makefile   |  4 ++--
 copy/xfs_copy.c | 33 +++++++++++++++++++++++++++++++++
 3 files changed, 36 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile
index 19fb8c5..fca0a42 100644
--- a/Makefile
+++ b/Makefile
@@ -81,7 +81,7 @@ growfs: libxcmd
 io: libxcmd libhandle
 quota: libxcmd
 repair: libxlog
-
+copy: libxlog
 
 ifeq ($(HAVE_BUILDDEFS), yes)
 include $(BUILDRULES)
diff --git a/copy/Makefile b/copy/Makefile
index beabbd4..e630b17 100644
--- a/copy/Makefile
+++ b/copy/Makefile
@@ -9,8 +9,8 @@ LTCOMMAND = xfs_copy
 CFILES = xfs_copy.c
 HFILES = xfs_copy.h
 
-LLDLIBS = $(LIBXFS) $(LIBUUID) $(LIBPTHREAD) $(LIBRT)
-LTDEPENDENCIES = $(LIBXFS)
+LLDLIBS = $(LIBXFS) $(LIBXLOG) $(LIBUUID) $(LIBPTHREAD) $(LIBRT)
+LTDEPENDENCIES = $(LIBXFS) $(LIBXLOG)
 LLDFLAGS = -static-libtool-libs
 
 default: depend $(LTCOMMAND)
diff --git a/copy/xfs_copy.c b/copy/xfs_copy.c
index 949be5f..f3e5288 100644
--- a/copy/xfs_copy.c
+++ b/copy/xfs_copy.c
@@ -23,6 +23,7 @@
 #include <signal.h>
 #include <stdarg.h>
 #include "xfs_copy.h"
+#include "libxlog.h"
 
 #define	rounddown(x, y)	(((x)/(y))*(y))
 #define uuid_equal(s,d) (platform_uuid_compare((s),(d)) == 0)
@@ -128,6 +129,12 @@ do_message(int flags, int code, const char *fmt, ...)
 			exit(1); \
 		} while (0)
 
+/* workaround craziness in the xlog routines */
+int xlog_recover_do_trans(struct xlog *log, struct xlog_recover *t, int p)
+{
+	return 0;
+}
+
 void
 check_errors(void)
 {
@@ -522,6 +529,7 @@ main(int argc, char **argv)
 	ag_header_t	ag_hdr;
 	xfs_mount_t	*mp;
 	xfs_mount_t	mbuf;
+	struct xlog	xlog;
 	xfs_buf_t	*sbp;
 	xfs_sb_t	*sb;
 	xfs_agnumber_t	num_ags, agno;
@@ -717,6 +725,31 @@ main(int argc, char **argv)
 		exit(1);
 	}
 
+
+	/*
+	 * Set up the mount pointer to access the log and check whether the log
+	 * is clean. Fail on a dirty or corrupt log in non-duplicate mode
+	 * because the log is formatted as part of the copy and we don't want to
+	 * destroy data. We also need the current log cycle to format v5
+	 * superblock logs correctly.
+	 */
+	memset(&xlog, 0, sizeof(struct xlog));
+	mp->m_log = &xlog;
+	c = xlog_is_dirty(mp, mp->m_log, &xargs, 0);
+	if (!duplicate) {
+		if (c == 1) {
+			do_log(_(
+"Error: source filesystem log is dirty. Mount the filesystem to replay the\n"
+"log, unmount and retry xfs_copy.\n"));
+			exit(1);
+		} else if (c < 0) {
+			do_log(_(
+"Error: could not determine the log head or tail of the source filesystem.\n"
+"Mount the filesystem to replay the log or run xfs_repair.\n"));
+			exit(1);
+		}
+	}
+
 	source_blocksize = mp->m_sb.sb_blocksize;
 	source_sectorsize = mp->m_sb.sb_sectsize;
 
-- 
2.1.0

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 15/18] xfs_copy: genericize write helper to facilitate separate log buf
  2015-10-02 18:19 [PATCH v3 00/18] xfsprogs: format the log correctly on v5 supers Brian Foster
                   ` (13 preceding siblings ...)
  2015-10-02 18:19 ` [PATCH v3 14/18] xfs_copy: check for dirty log on non-duplicate copies Brian Foster
@ 2015-10-02 18:19 ` Brian Foster
  2015-10-02 18:19 ` [PATCH v3 16/18] xfs_copy: store data buf alignment in buf data structure Brian Foster
                   ` (2 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Brian Foster @ 2015-10-02 18:19 UTC (permalink / raw)
  To: xfs

xfs_copy uses a fixed write buffer throughout the code for the various
targets. This is a global buffer and is assumed to be the write source
in the do_write() helper used by the log clearing code.

v5 superblock log formatting will require a larger, independent buffer
to format the log. Therefore, update do_write() to accept a write buffer
parameter to optionally override the global write buffer. This patch
does not change current behavior.

Signed-off-by: Brian Foster <bfoster@redhat.com>
---
 copy/xfs_copy.c | 34 ++++++++++++++++++++--------------
 1 file changed, 20 insertions(+), 14 deletions(-)

diff --git a/copy/xfs_copy.c b/copy/xfs_copy.c
index f3e5288..0481ece 100644
--- a/copy/xfs_copy.c
+++ b/copy/xfs_copy.c
@@ -170,20 +170,26 @@ check_errors(void)
  * are taken care of when the buffer's read in
  */
 int
-do_write(thread_args *args)
+do_write(
+	thread_args	*args,
+	wbuf		*buf)
 {
-	int	res, error = 0;
+	int		res;
+	int		error = 0;
 
-	if (target[args->id].position != w_buf.position)  {
-		if (lseek64(args->fd, w_buf.position, SEEK_SET) < 0)  {
+	if (!buf)
+		buf = &w_buf;
+
+	if (target[args->id].position != buf->position)  {
+		if (lseek64(args->fd, buf->position, SEEK_SET) < 0)  {
 			error = target[args->id].err_type = 1;
 		} else  {
-			target[args->id].position = w_buf.position;
+			target[args->id].position = buf->position;
 		}
 	}
 
-	if ((res = write(target[args->id].fd, w_buf.data,
-				w_buf.length)) == w_buf.length)  {
+	if ((res = write(target[args->id].fd, buf->data,
+				buf->length)) == buf->length)  {
 		target[args->id].position += res;
 	} else  {
 		error = 2;
@@ -191,7 +197,7 @@ do_write(thread_args *args)
 
 	if (error) {
 		target[args->id].error = errno;
-		target[args->id].position = w_buf.position;
+		target[args->id].position = buf->position;
 	}
 	return error;
 }
@@ -203,7 +209,7 @@ begin_reader(void *arg)
 
 	for (;;) {
 		pthread_mutex_lock(&args->wait);
-		if (do_write(args))
+		if (do_write(args, NULL))
 			goto handle_error;
 	        pthread_mutex_lock(&glob_masks.mutex);
 		if (--glob_masks.num_working == 0)
@@ -1168,7 +1174,7 @@ main(int argc, char **argv)
 				memset(w_buf.data, 0, w_buf.length);
 
 				while (w_buf.position < end_pos)  {
-					do_write(tcarg);
+					do_write(tcarg, NULL);
 					w_buf.position += w_buf.length;
 				}
 				tcarg++;
@@ -1190,7 +1196,7 @@ main(int argc, char **argv)
 
 			for (j = 0, tcarg = targ; j < num_targets; j++)  {
 				sb_update_uuid(sb, &ag_hdr, tcarg);
-				do_write(tcarg);
+				do_write(tcarg, NULL);
 				tcarg++;
 			}
 		}
@@ -1212,7 +1218,7 @@ next_log_chunk(char *p, int offset, void *private)
 	if (buf->length < (int)(p - buf->data) + offset) {
 		/* need to flush this one, then start afresh */
 
-		do_write(buf->owner);
+		do_write(buf->owner, NULL);
 		memset(buf->data, 0, buf->length);
 		return buf->data;
 	}
@@ -1247,7 +1253,7 @@ write_log_header(int fd, wbuf *buf, xfs_mount_t *mp)
 			xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1,
 			mp->m_sb.sb_logsunit, XLOG_FMT, NULLCOMMITLSN,
 			NULLCOMMITLSN, next_log_chunk, buf);
-	do_write(buf->owner);
+	do_write(buf->owner, NULL);
 
 	return roundup(logstart + offset, buf->length);
 }
@@ -1272,7 +1278,7 @@ write_log_trailer(int fd, wbuf *buf, xfs_mount_t *mp)
 		read_wbuf(fd, buf, mp);
 		offset = (int)(logend - buf->position);
 		memset(buf->data, 0, offset);
-		do_write(buf->owner);
+		do_write(buf->owner, NULL);
 	}
 
 	return buf->position;
-- 
2.1.0

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 16/18] xfs_copy: store data buf alignment in buf data structure
  2015-10-02 18:19 [PATCH v3 00/18] xfsprogs: format the log correctly on v5 supers Brian Foster
                   ` (14 preceding siblings ...)
  2015-10-02 18:19 ` [PATCH v3 15/18] xfs_copy: genericize write helper to facilitate separate log buf Brian Foster
@ 2015-10-02 18:19 ` Brian Foster
  2015-10-02 18:19 ` [PATCH v3 17/18] xfs_copy: refactor log format code into new helper Brian Foster
  2015-10-02 18:19 ` [PATCH v3 18/18] xfs_copy: format v5 sb logs correctly Brian Foster
  17 siblings, 0 replies; 19+ messages in thread
From: Brian Foster @ 2015-10-02 18:19 UTC (permalink / raw)
  To: xfs

The write buffer data structure stores various characteristics of the
write buffer, such as I/O alignment requirements, etc., but does not
include the required data buffer alignment.

Data buffer alignment is a required buffer initialization parameter and
the v5 log format support code would like to initialize an independent
log buffer based on the predetermined alignment constraints encoded into
the global write buffer. Update the write buffer data structure to store
the provided data alignment value such that it can be accessed
throughout the codebase. This patch does not change existing behavior.

Signed-off-by: Brian Foster <bfoster@redhat.com>
---
 copy/xfs_copy.c | 1 +
 copy/xfs_copy.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/copy/xfs_copy.c b/copy/xfs_copy.c
index 0481ece..e03796a 100644
--- a/copy/xfs_copy.c
+++ b/copy/xfs_copy.c
@@ -352,6 +352,7 @@ wbuf_init(wbuf *buf, int data_size, int data_align, int min_io_size, int id)
 			return NULL;
 	}
 	ASSERT(min_io_size % BBSIZE == 0);
+	buf->data_align = data_align;
 	buf->min_io_size = min_io_size;
 	buf->size = data_size;
 	buf->id = id;
diff --git a/copy/xfs_copy.h b/copy/xfs_copy.h
index e76b937..6b94130 100644
--- a/copy/xfs_copy.h
+++ b/copy/xfs_copy.h
@@ -54,6 +54,7 @@ typedef struct {
 	int		id;		/* buffer ID */
 	size_t		size;		/* size of buffer -- fixed */
 	size_t		min_io_size;	/* for direct I/O */
+	int		data_align;	/* data buffer alignment */
 	xfs_off_t	position;	/* requested position (bytes) */
 	size_t		length;		/* requested length (bytes) */
 	char		*data;		/* pointer to data buffer */
-- 
2.1.0

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 17/18] xfs_copy: refactor log format code into new helper
  2015-10-02 18:19 [PATCH v3 00/18] xfsprogs: format the log correctly on v5 supers Brian Foster
                   ` (15 preceding siblings ...)
  2015-10-02 18:19 ` [PATCH v3 16/18] xfs_copy: store data buf alignment in buf data structure Brian Foster
@ 2015-10-02 18:19 ` Brian Foster
  2015-10-02 18:19 ` [PATCH v3 18/18] xfs_copy: format v5 sb logs correctly Brian Foster
  17 siblings, 0 replies; 19+ messages in thread
From: Brian Foster @ 2015-10-02 18:19 UTC (permalink / raw)
  To: xfs

The xfs_copy log format code is mostly open-coded into the main()
function of the application. Support for v5 superblock log formatting
will require an alternate mechanism than that utilized for v4
superblocks and older.

As such, refactor the log formatting code into new helper functions. The
top-level helper iterates the copy target devices and another helper
implements the log format magic. This patch does not change existing
behavior.

Signed-off-by: Brian Foster <bfoster@redhat.com>
---
 copy/xfs_copy.c | 69 +++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 45 insertions(+), 24 deletions(-)

diff --git a/copy/xfs_copy.c b/copy/xfs_copy.c
index e03796a..a5f25ad 100644
--- a/copy/xfs_copy.c
+++ b/copy/xfs_copy.c
@@ -62,8 +62,9 @@ pthread_mutex_t	mainwait;
 #define ACTIVE		1
 #define INACTIVE	2
 
-xfs_off_t write_log_trailer(int fd, wbuf *w, xfs_mount_t *mp);
-xfs_off_t write_log_header(int fd, wbuf *w, xfs_mount_t *mp);
+xfs_off_t	write_log_trailer(int fd, wbuf *w, xfs_mount_t *mp);
+xfs_off_t	write_log_header(int fd, wbuf *w, xfs_mount_t *mp);
+static void	format_logs(struct xfs_mount *);
 
 /* general purpose message reporting routine */
 
@@ -518,7 +519,7 @@ main(int argc, char **argv)
 	int		i, j;
 	int		howfar = 0;
 	int		open_flags;
-	xfs_off_t	pos, end_pos;
+	xfs_off_t	pos;
 	size_t		length;
 	int		c;
 	__uint64_t	size, sizeb;
@@ -1160,29 +1161,11 @@ main(int argc, char **argv)
 	}
 
 	if (kids > 0)  {
-		if (!duplicate)  {
-
+		if (!duplicate)
 			/* write a clean log using the specified UUID */
-			for (j = 0, tcarg = targ; j < num_targets; j++)  {
-				w_buf.owner = tcarg;
-				w_buf.length = rounddown(w_buf.size,
-							 w_buf.min_io_size);
-				pos = write_log_header(
-							source_fd, &w_buf, mp);
-				end_pos = write_log_trailer(
-							source_fd, &w_buf, mp);
-				w_buf.position = pos;
-				memset(w_buf.data, 0, w_buf.length);
-
-				while (w_buf.position < end_pos)  {
-					do_write(tcarg, NULL);
-					w_buf.position += w_buf.length;
-				}
-				tcarg++;
-			}
-		} else {
+			format_logs(mp);
+		else
 			num_ags = 1;
-		}
 
 		/* reread and rewrite superblocks (UUID and in-progress) */
 		/* [backwards, so inprogress bit only updated when done] */
@@ -1284,3 +1267,41 @@ write_log_trailer(int fd, wbuf *buf, xfs_mount_t *mp)
 
 	return buf->position;
 }
+
+/*
+ * Clear a log by writing a record at the head, the tail and zeroing everything
+ * in between.
+ */
+static void
+clear_log(
+	struct xfs_mount	*mp,
+	thread_args		*tcarg)
+{
+	xfs_off_t		pos;
+	xfs_off_t		end_pos;
+
+	w_buf.owner = tcarg;
+	w_buf.length = rounddown(w_buf.size, w_buf.min_io_size);
+	pos = write_log_header(source_fd, &w_buf, mp);
+	end_pos = write_log_trailer(source_fd, &w_buf, mp);
+	w_buf.position = pos;
+	memset(w_buf.data, 0, w_buf.length);
+
+	while (w_buf.position < end_pos)  {
+		do_write(tcarg, NULL);
+		w_buf.position += w_buf.length;
+	}
+}
+
+static void
+format_logs(
+	struct xfs_mount	*mp)
+{
+	thread_args		*tcarg;
+	int			i;
+
+	for (i = 0, tcarg = targ; i < num_targets; i++)  {
+		clear_log(mp, tcarg);
+		tcarg++;
+	}
+}
-- 
2.1.0

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 18/18] xfs_copy: format v5 sb logs correctly
  2015-10-02 18:19 [PATCH v3 00/18] xfsprogs: format the log correctly on v5 supers Brian Foster
                   ` (16 preceding siblings ...)
  2015-10-02 18:19 ` [PATCH v3 17/18] xfs_copy: refactor log format code into new helper Brian Foster
@ 2015-10-02 18:19 ` Brian Foster
  17 siblings, 0 replies; 19+ messages in thread
From: Brian Foster @ 2015-10-02 18:19 UTC (permalink / raw)
  To: xfs

xfs_copy formats the target filesystem log in non-duplicate copy mode to
stamp the new fs UUID into the log. The current format mechanism resets
the current LSN of the target filesystem to cycle 1, which is invalid
for v5 superblocks. The current LSN of v5 superblocks must always move
forward and remain ahead of metadata LSNs stored in filesystem metadata.

Update the log format helper to detect and use an alternate format
mechanism for v5 superblock logs. Allocate an independent log format
buffer based on the size of the log and format the buffer with an
incremented cycle count using the libxfs log format mechanism.

Note that the new libxfs log format mechanism could be used for both v5
and older superblock formats. The new mechanism requires a new, full log
sized buffer allocation as well as doing I/O to the entire log whereas
the pre-v5 sb mechanism only writes to the log head and tail. This is
due to how xfs_copy uses its own internal buffer data structure rather
than libxfs buftarg structures. As such, keep the original mechanism
around to avoid potential disruption for non-v5 users. The old mechanism
can be removed at some point in the future when the new mechanism is
shaken out and v5 filesystems tend to outnumber v4.

Signed-off-by: Brian Foster <bfoster@redhat.com>
---
 copy/xfs_copy.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 59 insertions(+), 2 deletions(-)

diff --git a/copy/xfs_copy.c b/copy/xfs_copy.c
index a5f25ad..1dc7c65 100644
--- a/copy/xfs_copy.c
+++ b/copy/xfs_copy.c
@@ -64,7 +64,7 @@ pthread_mutex_t	mainwait;
 
 xfs_off_t	write_log_trailer(int fd, wbuf *w, xfs_mount_t *mp);
 xfs_off_t	write_log_header(int fd, wbuf *w, xfs_mount_t *mp);
-static void	format_logs(struct xfs_mount *);
+static int	format_logs(struct xfs_mount *);
 
 /* general purpose message reporting routine */
 
@@ -1293,15 +1293,72 @@ clear_log(
 	}
 }
 
+/*
+ * Format the log to a particular cycle number. This is required for version 5
+ * superblock filesystems to provide metadata LSN validity guarantees.
+ */
 static void
+format_log(
+	struct xfs_mount	*mp,
+	thread_args		*tcarg,
+	wbuf			*buf)
+{
+	int			logstart;
+	int			length;
+	int			cycle = XLOG_INIT_CYCLE;
+
+	buf->owner = tcarg;
+	buf->length = buf->size;
+	buf->position = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart) << BBSHIFT;
+
+	logstart = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logstart);
+	length = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
+
+	/*
+	 * Bump the cycle number on v5 superblock filesystems to guarantee that
+	 * all existing metadata LSNs are valid (behind the current LSN) on the
+	 * target fs.
+	 */
+	if (xfs_sb_version_hascrc(&mp->m_sb))
+		cycle = mp->m_log->l_curr_cycle + 1;
+
+	/*
+	 * Format the entire log into the memory buffer and write it out. If the
+	 * write fails, mark the target inactive so the failure is reported.
+	 */
+	libxfs_log_clear(NULL, buf->data, logstart, length, &buf->owner->uuid,
+			 xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1,
+			 mp->m_sb.sb_logsunit, XLOG_FMT, cycle);
+	if (do_write(buf->owner, buf))
+		target[tcarg->id].state = INACTIVE;
+}
+
+static int
 format_logs(
 	struct xfs_mount	*mp)
 {
 	thread_args		*tcarg;
 	int			i;
+	wbuf			logbuf;
+	int			logsize;
+
+	if (xfs_sb_version_hascrc(&mp->m_sb)) {
+		logsize = XFS_FSB_TO_B(mp, mp->m_sb.sb_logblocks);
+		if (!wbuf_init(&logbuf, logsize, w_buf.data_align,
+			       w_buf.min_io_size, w_buf.id))
+			return -ENOMEM;
+	}
 
 	for (i = 0, tcarg = targ; i < num_targets; i++)  {
-		clear_log(mp, tcarg);
+		if (xfs_sb_version_hascrc(&mp->m_sb))
+			format_log(mp, tcarg, &logbuf);
+		else
+			clear_log(mp, tcarg);
 		tcarg++;
 	}
+
+	if (xfs_sb_version_hascrc(&mp->m_sb))
+		free(logbuf.data);
+
+	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] 19+ messages in thread

end of thread, other threads:[~2015-10-02 18:20 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-10-02 18:19 [PATCH v3 00/18] xfsprogs: format the log correctly on v5 supers Brian Foster
2015-10-02 18:19 ` [PATCH v3 01/18] libxfs: validate metadata LSNs against log on v5 superblocks Brian Foster
2015-10-02 18:19 ` [PATCH v3 02/18] libxfs: track largest metadata LSN in use via verifiers Brian Foster
2015-10-02 18:19 ` [PATCH v3 03/18] libxfs: don't hardcode cycle 1 into unmount op header Brian Foster
2015-10-02 18:19 ` [PATCH v3 04/18] libxfs: pass lsn param to log clear and record header logging helpers Brian Foster
2015-10-02 18:19 ` [PATCH v3 05/18] libxfs: add ability to clear log to arbitrary log cycle Brian Foster
2015-10-02 18:19 ` [PATCH v3 06/18] libxlog: pull struct xlog out of xlog_is_dirty() Brian Foster
2015-10-02 18:19 ` [PATCH v3 07/18] xfs_repair: track log state throughout all recovery phases Brian Foster
2015-10-02 18:19 ` [PATCH v3 08/18] xfs_repair: process the log in no_modify mode Brian Foster
2015-10-02 18:19 ` [PATCH v3 09/18] xfs_repair: format the log with forward cycle number on v5 supers Brian Foster
2015-10-02 18:19 ` [PATCH v3 10/18] xfs_repair: don't clear the log by default Brian Foster
2015-10-02 18:19 ` [PATCH v3 11/18] xfs_repair: seed the max lsn from log state in phase 2 Brian Foster
2015-10-02 18:19 ` [PATCH v3 12/18] xfs_db: do not reset current lsn from uuid command on v5 supers Brian Foster
2015-10-02 18:19 ` [PATCH v3 13/18] db/metadump: bump lsn when log is cleared " Brian Foster
2015-10-02 18:19 ` [PATCH v3 14/18] xfs_copy: check for dirty log on non-duplicate copies Brian Foster
2015-10-02 18:19 ` [PATCH v3 15/18] xfs_copy: genericize write helper to facilitate separate log buf Brian Foster
2015-10-02 18:19 ` [PATCH v3 16/18] xfs_copy: store data buf alignment in buf data structure Brian Foster
2015-10-02 18:19 ` [PATCH v3 17/18] xfs_copy: refactor log format code into new helper Brian Foster
2015-10-02 18:19 ` [PATCH v3 18/18] xfs_copy: format v5 sb logs correctly Brian Foster

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox