All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2 V3] allow UUID changes on V5/CRC filesystems
@ 2015-05-12 19:24 Eric Sandeen
  2015-05-12 19:27 ` [PATCH 1/2] xfs: create new metadata UUID field and incompat flag Eric Sandeen
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Eric Sandeen @ 2015-05-12 19:24 UTC (permalink / raw)
  To: xfs-oss

Final version?  This has been through some degree of testing, by changing
the UUID after a CRC mkfs, and re-setting it in between two xfs_repair runs
before and after each test in the testsuite.

I still probably owe some xfstests testcases.

This is rebased onto the new xfsprogs libxfs rebase, and I removed the noise
if a user asks to "restore" the UUID on a filesystem which doesn't need it -
it just does nothing, and succeeds silently.

Thanks,
-Eric

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

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

* [PATCH 1/2] xfs: create new metadata UUID field and incompat flag
  2015-05-12 19:24 [PATCH 0/2 V3] allow UUID changes on V5/CRC filesystems Eric Sandeen
@ 2015-05-12 19:27 ` Eric Sandeen
  2015-05-14 13:36   ` Brian Foster
                     ` (2 more replies)
  2015-05-12 19:30 ` [PATCH 2/2] xfsprogs: Add new sb_meta_uuid field, update userspace tools to manipulate it Eric Sandeen
  2015-06-03 11:14 ` [PATCH 0/2 V3] allow UUID changes on V5/CRC filesystems Linda Walsh
  2 siblings, 3 replies; 13+ messages in thread
From: Eric Sandeen @ 2015-05-12 19:27 UTC (permalink / raw)
  To: xfs-oss

This adds a new superblock field, sb_meta_uuid.  If set, along with
a new incompat flag, the code will use that field on a V5 filesystem
to compare to metadata UUIDs, which allows us to change the user-
visible UUID at will.  Userspace handles the setting and clearing
of the incompat flag as appropriate, as the UUID gets changed; i.e.
setting the user-visible UUID back to the original UUID (as stored in
the new field) will remove the incompatible feature flag.

If the incompat flag is not set, this copies the user-visible UUID into
into the meta_uuid slot in memory when the superblock is read from disk;
the meta_uuid field is not written back to disk in this case.

The remainder of this patch simply switches verifiers, initializers,
etc to use the new sb_meta_uuid field.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---

diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
index 516162b..27f76ca 100644
--- a/fs/xfs/libxfs/xfs_alloc.c
+++ b/fs/xfs/libxfs/xfs_alloc.c
@@ -450,7 +450,7 @@ xfs_agfl_verify(
 	struct xfs_agfl	*agfl = XFS_BUF_TO_AGFL(bp);
 	int		i;
 
-	if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_uuid))
+	if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid))
 		return false;
 	if (be32_to_cpu(agfl->agfl_magicnum) != XFS_AGFL_MAGIC)
 		return false;
@@ -2203,7 +2203,7 @@ 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_uuid))
+	    !uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 
 	if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) &&
diff --git a/fs/xfs/libxfs/xfs_alloc_btree.c b/fs/xfs/libxfs/xfs_alloc_btree.c
index 59d521c..90de071 100644
--- a/fs/xfs/libxfs/xfs_alloc_btree.c
+++ b/fs/xfs/libxfs/xfs_alloc_btree.c
@@ -295,7 +295,7 @@ xfs_allocbt_verify(
 	case cpu_to_be32(XFS_ABTB_CRC_MAGIC):
 		if (!xfs_sb_version_hascrc(&mp->m_sb))
 			return false;
-		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
 			return false;
@@ -313,7 +313,7 @@ xfs_allocbt_verify(
 	case cpu_to_be32(XFS_ABTC_CRC_MAGIC):
 		if (!xfs_sb_version_hascrc(&mp->m_sb))
 			return false;
-		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
 			return false;
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index 04e79d5..6755762 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -262,7 +262,7 @@ xfs_attr3_leaf_verify(
 		if (ichdr.magic != XFS_ATTR3_LEAF_MAGIC)
 			return false;
 
-		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
 			return false;
@@ -1056,7 +1056,7 @@ xfs_attr3_leaf_create(
 
 		hdr3->blkno = cpu_to_be64(bp->b_bn);
 		hdr3->owner = cpu_to_be64(dp->i_ino);
-		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
 
 		ichdr.freemap[0].base = sizeof(struct xfs_attr3_leaf_hdr);
 	} else {
diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
index 20de88d..eba0d1e 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.c
+++ b/fs/xfs/libxfs/xfs_attr_remote.c
@@ -100,7 +100,7 @@ xfs_attr3_rmt_verify(
 		return false;
 	if (rmt->rm_magic != cpu_to_be32(XFS_ATTR3_RMT_MAGIC))
 		return false;
-	if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_uuid))
+	if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid))
 		return false;
 	if (be64_to_cpu(rmt->rm_blkno) != bno)
 		return false;
@@ -217,7 +217,7 @@ xfs_attr3_rmt_hdr_set(
 	rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC);
 	rmt->rm_offset = cpu_to_be32(offset);
 	rmt->rm_bytes = cpu_to_be32(size);
-	uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_uuid);
+	uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid);
 	rmt->rm_owner = cpu_to_be64(ino);
 	rmt->rm_blkno = cpu_to_be64(bno);
 
diff --git a/fs/xfs/libxfs/xfs_bmap_btree.c b/fs/xfs/libxfs/xfs_bmap_btree.c
index 2c44c8e..6b0cf65 100644
--- a/fs/xfs/libxfs/xfs_bmap_btree.c
+++ b/fs/xfs/libxfs/xfs_bmap_btree.c
@@ -349,7 +349,8 @@ xfs_bmbt_to_bmdr(
 
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_CRC_MAGIC));
-		ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid));
+		ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid,
+		       &mp->m_sb.sb_meta_uuid));
 		ASSERT(rblock->bb_u.l.bb_blkno ==
 		       cpu_to_be64(XFS_BUF_DADDR_NULL));
 	} else
@@ -647,7 +648,7 @@ xfs_bmbt_verify(
 	case cpu_to_be32(XFS_BMAP_CRC_MAGIC):
 		if (!xfs_sb_version_hascrc(&mp->m_sb))
 			return false;
-		if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(block->bb_u.l.bb_blkno) != bp->b_bn)
 			return false;
diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
index c72283d..f7d7ee7 100644
--- a/fs/xfs/libxfs/xfs_btree.c
+++ b/fs/xfs/libxfs/xfs_btree.c
@@ -65,7 +65,8 @@ xfs_btree_check_lblock(
 
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		lblock_ok = lblock_ok &&
-			uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid) &&
+			uuid_equal(&block->bb_u.l.bb_uuid,
+				   &mp->m_sb.sb_meta_uuid) &&
 			block->bb_u.l.bb_blkno == cpu_to_be64(
 				bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
 	}
@@ -115,7 +116,8 @@ xfs_btree_check_sblock(
 
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		sblock_ok = sblock_ok &&
-			uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid) &&
+			uuid_equal(&block->bb_u.s.bb_uuid,
+				   &mp->m_sb.sb_meta_uuid) &&
 			block->bb_u.s.bb_blkno == cpu_to_be64(
 				bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
 	}
@@ -1000,7 +1002,7 @@ xfs_btree_init_block_int(
 		if (flags & XFS_BTREE_CRC_BLOCKS) {
 			buf->bb_u.l.bb_blkno = cpu_to_be64(blkno);
 			buf->bb_u.l.bb_owner = cpu_to_be64(owner);
-			uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid);
+			uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid);
 			buf->bb_u.l.bb_pad = 0;
 			buf->bb_u.l.bb_lsn = 0;
 		}
@@ -1013,7 +1015,7 @@ xfs_btree_init_block_int(
 		if (flags & XFS_BTREE_CRC_BLOCKS) {
 			buf->bb_u.s.bb_blkno = cpu_to_be64(blkno);
 			buf->bb_u.s.bb_owner = cpu_to_be32(__owner);
-			uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid);
+			uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid);
 			buf->bb_u.s.bb_lsn = 0;
 		}
 	}
diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c
index 2385f8c..e9f6709 100644
--- a/fs/xfs/libxfs/xfs_da_btree.c
+++ b/fs/xfs/libxfs/xfs_da_btree.c
@@ -146,7 +146,7 @@ xfs_da3_node_verify(
 		if (ichdr.magic != XFS_DA3_NODE_MAGIC)
 			return false;
 
-		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
 			return false;
@@ -324,7 +324,7 @@ xfs_da3_node_create(
 		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);
-		uuid_copy(&hdr3->info.uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid);
 	} else {
 		ichdr.magic = XFS_DA_NODE_MAGIC;
 	}
diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
index 9354e19..4778d1d 100644
--- a/fs/xfs/libxfs/xfs_dir2_block.c
+++ b/fs/xfs/libxfs/xfs_dir2_block.c
@@ -67,7 +67,7 @@ xfs_dir3_block_verify(
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		if (hdr3->magic != cpu_to_be32(XFS_DIR3_BLOCK_MAGIC))
 			return false;
-		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
 			return false;
@@ -157,7 +157,7 @@ xfs_dir3_block_init(
 		hdr3->magic = cpu_to_be32(XFS_DIR3_BLOCK_MAGIC);
 		hdr3->blkno = cpu_to_be64(bp->b_bn);
 		hdr3->owner = cpu_to_be64(dp->i_ino);
-		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
 		return;
 
 	}
diff --git a/fs/xfs/libxfs/xfs_dir2_data.c b/fs/xfs/libxfs/xfs_dir2_data.c
index de1ea16..6a57fdb 100644
--- a/fs/xfs/libxfs/xfs_dir2_data.c
+++ b/fs/xfs/libxfs/xfs_dir2_data.c
@@ -220,7 +220,7 @@ xfs_dir3_data_verify(
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		if (hdr3->magic != cpu_to_be32(XFS_DIR3_DATA_MAGIC))
 			return false;
-		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
 			return false;
@@ -604,7 +604,7 @@ xfs_dir3_data_init(
 		hdr3->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC);
 		hdr3->blkno = cpu_to_be64(bp->b_bn);
 		hdr3->owner = cpu_to_be64(dp->i_ino);
-		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
 
 	} else
 		hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
index 1061199..f300240 100644
--- a/fs/xfs/libxfs/xfs_dir2_leaf.c
+++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
@@ -160,7 +160,7 @@ xfs_dir3_leaf_verify(
 
 		if (leaf3->info.hdr.magic != cpu_to_be16(magic3))
 			return false;
-		if (!uuid_equal(&leaf3->info.uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&leaf3->info.uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn)
 			return false;
@@ -310,7 +310,7 @@ xfs_dir3_leaf_init(
 					 : cpu_to_be16(XFS_DIR3_LEAFN_MAGIC);
 		leaf3->info.blkno = cpu_to_be64(bp->b_bn);
 		leaf3->info.owner = cpu_to_be64(owner);
-		uuid_copy(&leaf3->info.uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&leaf3->info.uuid, &mp->m_sb.sb_meta_uuid);
 	} else {
 		memset(leaf, 0, sizeof(*leaf));
 		leaf->hdr.info.magic = cpu_to_be16(type);
diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
index 41b80d3..527b733 100644
--- a/fs/xfs/libxfs/xfs_dir2_node.c
+++ b/fs/xfs/libxfs/xfs_dir2_node.c
@@ -93,7 +93,7 @@ xfs_dir3_free_verify(
 
 		if (hdr3->magic != cpu_to_be32(XFS_DIR3_FREE_MAGIC))
 			return false;
-		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
 			return false;
@@ -226,7 +226,7 @@ xfs_dir3_free_get_buf(
 
 		hdr3->hdr.blkno = cpu_to_be64(bp->b_bn);
 		hdr3->hdr.owner = cpu_to_be64(dp->i_ino);
-		uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_meta_uuid);
 	} else
 		hdr.magic = XFS_DIR2_FREE_MAGIC;
 	dp->d_ops->free_hdr_to_disk(bp->b_addr, &hdr);
diff --git a/fs/xfs/libxfs/xfs_dquot_buf.c b/fs/xfs/libxfs/xfs_dquot_buf.c
index 6fbf2d8..5331b7f 100644
--- a/fs/xfs/libxfs/xfs_dquot_buf.c
+++ b/fs/xfs/libxfs/xfs_dquot_buf.c
@@ -163,7 +163,7 @@ xfs_dqcheck(
 	d->dd_diskdq.d_id = cpu_to_be32(id);
 
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
-		uuid_copy(&d->dd_uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&d->dd_uuid, &mp->m_sb.sb_meta_uuid);
 		xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk),
 				 XFS_DQUOT_CRC_OFF);
 	}
@@ -198,7 +198,7 @@ xfs_dquot_buf_verify_crc(
 		if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk),
 				 XFS_DQUOT_CRC_OFF))
 			return false;
-		if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 	}
 	return true;
diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 4daaa66..88c38df 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -100,7 +100,7 @@ typedef struct xfs_sb {
 	xfs_rfsblock_t	sb_dblocks;	/* number of data blocks */
 	xfs_rfsblock_t	sb_rblocks;	/* number of realtime blocks */
 	xfs_rtblock_t	sb_rextents;	/* number of realtime extents */
-	uuid_t		sb_uuid;	/* file system unique id */
+	uuid_t		sb_uuid;	/* user-visible file system unique id */
 	xfs_fsblock_t	sb_logstart;	/* starting block of log if internal */
 	xfs_ino_t	sb_rootino;	/* root inode number */
 	xfs_ino_t	sb_rbmino;	/* bitmap inode for realtime extents */
@@ -174,6 +174,7 @@ typedef struct xfs_sb {
 
 	xfs_ino_t	sb_pquotino;	/* project quota inode */
 	xfs_lsn_t	sb_lsn;		/* last write sequence */
+	uuid_t		sb_meta_uuid;	/* metadata file system unique id */
 
 	/* must be padded to 64 bit alignment */
 } xfs_sb_t;
@@ -190,7 +191,7 @@ typedef struct xfs_dsb {
 	__be64		sb_dblocks;	/* number of data blocks */
 	__be64		sb_rblocks;	/* number of realtime blocks */
 	__be64		sb_rextents;	/* number of realtime extents */
-	uuid_t		sb_uuid;	/* file system unique id */
+	uuid_t		sb_uuid;	/* user-visible file system unique id */
 	__be64		sb_logstart;	/* starting block of log if internal */
 	__be64		sb_rootino;	/* root inode number */
 	__be64		sb_rbmino;	/* bitmap inode for realtime extents */
@@ -260,6 +261,7 @@ typedef struct xfs_dsb {
 
 	__be64		sb_pquotino;	/* project quota inode */
 	__be64		sb_lsn;		/* last write sequence */
+	uuid_t		sb_meta_uuid;	/* metadata file system unique id */
 
 	/* must be padded to 64 bit alignment */
 } xfs_dsb_t;
@@ -457,8 +459,10 @@ xfs_sb_has_ro_compat_feature(
 }
 
 #define XFS_SB_FEAT_INCOMPAT_FTYPE	(1 << 0)	/* filetype in dirent */
+#define XFS_SB_FEAT_INCOMPAT_META_UUID	(1 << 1)	/* metadata UUID */
 #define XFS_SB_FEAT_INCOMPAT_ALL \
-		(XFS_SB_FEAT_INCOMPAT_FTYPE)
+		(XFS_SB_FEAT_INCOMPAT_FTYPE | \
+		 XFS_SB_FEAT_INCOMPAT_META_UUID)
 
 #define XFS_SB_FEAT_INCOMPAT_UNKNOWN	~XFS_SB_FEAT_INCOMPAT_ALL
 static inline bool
@@ -507,6 +511,18 @@ static inline int xfs_sb_version_hasfinobt(xfs_sb_t *sbp)
 }
 
 /*
+ * XFS_SB_FEAT_INCOMPAT_META_UUID indicates that the metadata UUID
+ * is stored separately from the user-visible UUID; this allows the
+ * user-visible UUID to be changed on V5 filesystems which have a
+ * filesystem UUID stamped into every piece of metadata.
+ */
+static inline int xfs_sb_version_hasmetauuid(xfs_sb_t *sbp)
+{
+	return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) &&
+		(sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID);
+}
+
+/*
  * end of superblock version macros
  */
 
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index 07349a1..d9b90c0 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -307,7 +307,8 @@ xfs_ialloc_inode_init(
 			if (version == 3) {
 				free->di_ino = cpu_to_be64(ino);
 				ino++;
-				uuid_copy(&free->di_uuid, &mp->m_sb.sb_uuid);
+				uuid_copy(&free->di_uuid,
+					  &mp->m_sb.sb_meta_uuid);
 				xfs_dinode_calc_crc(mp, free);
 			} else if (tp) {
 				/* just log the inode core */
@@ -2049,7 +2050,7 @@ xfs_agi_verify(
 	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_uuid))
+	    !uuid_equal(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 	/*
 	 * Validate the magic number of the agi block.
diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c
index 964c465..0fa2a27 100644
--- a/fs/xfs/libxfs/xfs_ialloc_btree.c
+++ b/fs/xfs/libxfs/xfs_ialloc_btree.c
@@ -230,7 +230,7 @@ xfs_inobt_verify(
 	case cpu_to_be32(XFS_FIBT_CRC_MAGIC):
 		if (!xfs_sb_version_hascrc(&mp->m_sb))
 			return false;
-		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
 			return false;
diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
index 002b6b3..0f9563e 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.c
+++ b/fs/xfs/libxfs/xfs_inode_buf.c
@@ -306,7 +306,7 @@ xfs_dinode_verify(
 		return false;
 	if (be64_to_cpu(dip->di_ino) != ip->i_ino)
 		return false;
-	if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_uuid))
+	if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_meta_uuid))
 		return false;
 	return true;
 }
@@ -368,7 +368,7 @@ xfs_iread(
 		if (xfs_sb_version_hascrc(&mp->m_sb)) {
 			ip->i_d.di_version = 3;
 			ip->i_d.di_ino = ip->i_ino;
-			uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
+			uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid);
 		} else
 			ip->i_d.di_version = 2;
 		return 0;
diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
index dc4bfc5..04f1b28 100644
--- a/fs/xfs/libxfs/xfs_sb.c
+++ b/fs/xfs/libxfs/xfs_sb.c
@@ -377,6 +377,17 @@ __xfs_sb_from_disk(
 	to->sb_pad = 0;
 	to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
 	to->sb_lsn = be64_to_cpu(from->sb_lsn);
+	/*
+	 * sb_meta_uuid is only on disk if it differs from sb_uuid and the
+	 * feature flag is set; if not set we keep it only in memory.
+	 */
+	if (xfs_sb_version_hasmetauuid(to)) {
+		memcpy(&to->sb_meta_uuid, &from->sb_meta_uuid,
+					sizeof(to->sb_meta_uuid));
+	} else {
+		memcpy(&to->sb_meta_uuid, &from->sb_uuid,
+					sizeof(to->sb_meta_uuid));
+	}
 	/* Convert on-disk flags to in-memory flags? */
 	if (convert_xquota)
 		xfs_sb_quota_from_disk(to);
@@ -518,6 +529,10 @@ xfs_sb_to_disk(
 				cpu_to_be32(from->sb_features_log_incompat);
 		to->sb_pad = 0;
 		to->sb_lsn = cpu_to_be64(from->sb_lsn);
+		if (xfs_sb_version_hasmetauuid(from)) {
+			memcpy(&to->sb_meta_uuid, &from->sb_meta_uuid,
+						sizeof(to->sb_meta_uuid));
+		}
 	}
 }
 
diff --git a/fs/xfs/libxfs/xfs_symlink_remote.c b/fs/xfs/libxfs/xfs_symlink_remote.c
index e7e26bd..8f8af05 100644
--- a/fs/xfs/libxfs/xfs_symlink_remote.c
+++ b/fs/xfs/libxfs/xfs_symlink_remote.c
@@ -63,7 +63,7 @@ xfs_symlink_hdr_set(
 	dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC);
 	dsl->sl_offset = cpu_to_be32(offset);
 	dsl->sl_bytes = cpu_to_be32(size);
-	uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_uuid);
+	uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid);
 	dsl->sl_owner = cpu_to_be64(ino);
 	dsl->sl_blkno = cpu_to_be64(bp->b_bn);
 	bp->b_ops = &xfs_symlink_buf_ops;
@@ -107,7 +107,7 @@ xfs_symlink_verify(
 		return false;
 	if (dsl->sl_magic != cpu_to_be32(XFS_SYMLINK_MAGIC))
 		return false;
-	if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_uuid))
+	if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid))
 		return false;
 	if (bp->b_bn != be64_to_cpu(dsl->sl_blkno))
 		return false;
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 02c01bb..e0c7e15 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -251,7 +251,7 @@ xfs_qm_init_dquot_blk(
 		d->dd_diskdq.d_id = cpu_to_be32(curid);
 		d->dd_diskdq.d_flags = type;
 		if (xfs_sb_version_hascrc(&mp->m_sb)) {
-			uuid_copy(&d->dd_uuid, &mp->m_sb.sb_uuid);
+			uuid_copy(&d->dd_uuid, &mp->m_sb.sb_meta_uuid);
 			xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk),
 					 XFS_DQUOT_CRC_OFF);
 		}
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index cb7e8a2..9c892cd 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -248,7 +248,7 @@ xfs_growfs_data_private(
 		agf->agf_freeblks = cpu_to_be32(tmpsize);
 		agf->agf_longest = cpu_to_be32(tmpsize);
 		if (xfs_sb_version_hascrc(&mp->m_sb))
-			uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_uuid);
+			uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid);
 
 		error = xfs_bwrite(bp);
 		xfs_buf_relse(bp);
@@ -271,7 +271,7 @@ xfs_growfs_data_private(
 		if (xfs_sb_version_hascrc(&mp->m_sb)) {
 			agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC);
 			agfl->agfl_seqno = cpu_to_be32(agno);
-			uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_uuid);
+			uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid);
 		}
 
 		agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, bp);
@@ -307,7 +307,7 @@ xfs_growfs_data_private(
 		agi->agi_newino = cpu_to_be32(NULLAGINO);
 		agi->agi_dirino = cpu_to_be32(NULLAGINO);
 		if (xfs_sb_version_hascrc(&mp->m_sb))
-			uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid);
+			uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid);
 		if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
 			agi->agi_free_root = cpu_to_be32(XFS_FIBT_BLOCK(mp));
 			agi->agi_free_level = cpu_to_be32(1);
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index d6ebc85..9a2ecb7 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -787,7 +787,7 @@ xfs_ialloc(
 
 	if (ip->i_d.di_version == 3) {
 		ASSERT(ip->i_d.di_ino == ino);
-		ASSERT(uuid_equal(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid));
+		ASSERT(uuid_equal(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid));
 		ip->i_d.di_crc = 0;
 		ip->i_d.di_changecount = 1;
 		ip->i_d.di_lsn = 0;
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 4f5784f..4da291c 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -325,7 +325,7 @@ xlog_header_check_recover(
 		XFS_ERROR_REPORT("xlog_header_check_recover(1)",
 				 XFS_ERRLEVEL_HIGH, mp);
 		return -EFSCORRUPTED;
-	} else if (unlikely(!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid))) {
+	} else if (!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid)) {
 		xfs_warn(mp,
 	"dirty log entry has mismatched uuid - can't recover");
 		xlog_header_check_dump(mp, head);
@@ -353,7 +353,7 @@ xlog_header_check_mount(
 		 * by IRIX and continue.
 		 */
 		xfs_warn(mp, "nil uuid in log - IRIX style log");
-	} else if (unlikely(!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid))) {
+	} else if (!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid)) {
 		xfs_warn(mp, "log has mismatched uuid - can't recover");
 		xlog_header_check_dump(mp, head);
 		XFS_ERROR_REPORT("xlog_header_check_mount",


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

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

* [PATCH 2/2] xfsprogs: Add new sb_meta_uuid field, update userspace tools to manipulate it
  2015-05-12 19:24 [PATCH 0/2 V3] allow UUID changes on V5/CRC filesystems Eric Sandeen
  2015-05-12 19:27 ` [PATCH 1/2] xfs: create new metadata UUID field and incompat flag Eric Sandeen
@ 2015-05-12 19:30 ` Eric Sandeen
  2015-05-14 13:39   ` Brian Foster
  2015-05-14 21:54   ` [PATCH 2/2 V4] " Eric Sandeen
  2015-06-03 11:14 ` [PATCH 0/2 V3] allow UUID changes on V5/CRC filesystems Linda Walsh
  2 siblings, 2 replies; 13+ messages in thread
From: Eric Sandeen @ 2015-05-12 19:30 UTC (permalink / raw)
  To: xfs-oss

This adds a new superblock field, sb_meta_uuid.  This allows us to
change the use-visible UUID on crc-enabled filesytems from userspace
if desired, by copying the existing UUID to the new location for
metadata comparisons.  If this is done, an incompat flag must be
set to prevent older filesystems from mounting the filesystem, but
the original UUID can be restored, and the incompat flag removed,
with a new xfs_db / xfs_admin UUID command, "restore."

Much of this patch mirrors the kernel patch in simply renaming
the field used for metadata uuid comparison; other bits:

* Teach xfs_db to print the new meta_uuid field
* Allow xfs_db to generate a new UUID for CRC-enabled filesystems
* Allow xfs_db to revert to the original UUID and clear the flag
* Fix up xfs_copy to work with CRC-enabled filesystems
* Update the xfs_admin manpage to show the UUID "restore" command

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---

This version makes the UUID "restore" command silent if there
is nothing to do.

Still open to bike-shedding on the "restore" name.  Maybe "revert?"

diff --git a/copy/xfs_copy.c b/copy/xfs_copy.c
index 279527c..a58eee5 100644
--- a/copy/xfs_copy.c
+++ b/copy/xfs_copy.c
@@ -466,6 +466,34 @@ write_wbuf(void)
 	sighold(SIGCHLD);
 }
 
+void
+sb_update_uuid(
+	xfs_sb_t	*sb,
+	ag_header_t	*ag_hdr,
+	thread_args	*tcarg)
+{
+	/*
+	 * If this filesystem has CRCs, the original UUID is stamped into
+	 * all metadata.  We need to copy the original UUID into the meta_uuid
+	 * slot and set the incompat flag if that hasn't already been done.
+	 */
+	if (xfs_sb_version_hascrc(sb) && !xfs_sb_version_hasmetauuid(sb)) {
+		__be32 feat;
+
+		feat = be32_to_cpu(ag_hdr->xfs_sb->sb_features_incompat);
+		feat |= XFS_SB_FEAT_INCOMPAT_META_UUID;
+		ag_hdr->xfs_sb->sb_features_incompat = cpu_to_be32(feat);
+		platform_uuid_copy(&ag_hdr->xfs_sb->sb_meta_uuid,
+				   &ag_hdr->xfs_sb->sb_uuid);
+	}
+
+	platform_uuid_copy(&ag_hdr->xfs_sb->sb_uuid, &tcarg->uuid);
+
+	/* We changed the UUID, so update the superblock CRC if needed */
+	if (xfs_sb_version_hascrc(sb))
+		xfs_update_cksum((char *)&ag_hdr->xfs_sb, sb->sb_sectsize,
+							 XFS_SB_CRC_OFF);
+}
 
 int
 main(int argc, char **argv)
@@ -659,16 +687,6 @@ main(int argc, char **argv)
 	sb = &mbuf.m_sb;
 	libxfs_sb_from_disk(sb, XFS_BUF_TO_SBP(sbp));
 
-	/*
-	 * For now, V5 superblock filesystems are not supported without -d;
-	 * we do not have the infrastructure yet to fix CRCs when a new UUID
-	 * is generated.
-	 */
-	if (xfs_sb_version_hascrc(sb) && !duplicate) {
-		do_log(_("%s: Cannot yet copy V5 fs without '-d'\n"), progname);
-		exit(1);
-	}
-
 	mp = libxfs_mount(&mbuf, sb, xargs.ddev, xargs.logdev, xargs.rtdev, 0);
 	if (mp == NULL) {
 		do_log(_("%s: %s filesystem failed to initialize\n"
@@ -1127,8 +1145,7 @@ main(int argc, char **argv)
 			/* do each thread in turn, each has its own UUID */
 
 			for (j = 0, tcarg = targ; j < num_targets; j++)  {
-				platform_uuid_copy(&ag_hdr.xfs_sb->sb_uuid,
-							&tcarg->uuid);
+				sb_update_uuid(sb, &ag_hdr, tcarg);
 				do_write(tcarg);
 				tcarg++;
 			}
diff --git a/db/sb.c b/db/sb.c
index cd12f83..a1dd039 100644
--- a/db/sb.c
+++ b/db/sb.c
@@ -29,6 +29,8 @@
 #include "output.h"
 #include "init.h"
 
+#define uuid_equal(s,d)		(platform_uuid_compare((s),(d)) == 0)
+
 static int	sb_f(int argc, char **argv);
 static void     sb_help(void);
 static int	uuid_f(int argc, char **argv);
@@ -121,6 +123,7 @@ const field_t	sb_flds[] = {
 	{ "crc", FLDT_CRC, OI(OFF(crc)), C1, 0, TYP_NONE },
 	{ "pquotino", FLDT_INO, OI(OFF(pquotino)), C1, 0, TYP_INODE },
 	{ "lsn", FLDT_UINT64X, OI(OFF(lsn)), C1, 0, TYP_NONE },
+	{ "meta_uuid", FLDT_UUID, OI(OFF(meta_uuid)), C1, 0, TYP_NONE },
 	{ NULL }
 };
 
@@ -334,6 +337,32 @@ do_uuid(xfs_agnumber_t agno, uuid_t *uuid)
 		return &uu;
 	}
 	/* set uuid */
+	if (!xfs_sb_version_hascrc(&tsb))
+		goto write;
+	/*
+	 * If we have CRCs, and this UUID differs from that stamped in the
+	 * metadata, set the incompat flag and copy the old one to the
+	 * metadata-specific location.
+	 *
+	 * If we are setting the user-visible UUID back to match the metadata
+	 * UUID, clear the metadata-specific location and the incompat flag.
+	 */
+	if (!xfs_sb_version_hasmetauuid(&tsb) &&
+	    !uuid_equal(uuid, &mp->m_sb.sb_meta_uuid)) {
+		mp->m_sb.sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_META_UUID;
+		tsb.sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_META_UUID;
+		memcpy(&tsb.sb_meta_uuid, &tsb.sb_uuid, sizeof(uuid_t));
+	} else if (xfs_sb_version_hasmetauuid(&tsb) &&
+		   uuid_equal(uuid, &mp->m_sb.sb_meta_uuid)) {
+		memset(&tsb.sb_meta_uuid, 0, sizeof(uuid_t));
+		/* Write those zeros now; it's ignored once we clear the flag */
+		libxfs_sb_to_disk(iocur_top->data, &tsb);
+		mp->m_sb.sb_features_incompat &=
+						~XFS_SB_FEAT_INCOMPAT_META_UUID;
+		tsb.sb_features_incompat &= ~XFS_SB_FEAT_INCOMPAT_META_UUID;
+	}
+
+write:
 	memcpy(&tsb.sb_uuid, uuid, sizeof(uuid_t));
 	libxfs_sb_to_disk(iocur_top->data, &tsb);
 	write_cur();
@@ -363,18 +392,6 @@ uuid_f(
 			return 0;
 		}
 
-		/*
-		 * For now, changing the UUID of V5 superblock filesystems is
-		 * not supported; we do not have the infrastructure to fix all
-		 * other metadata when a new superblock UUID is generated.
-		 */
-		if (xfs_sb_version_hascrc(&mp->m_sb) &&
-		    strcasecmp(argv[1], "rewrite")) {
-			dbprintf(_("%s: only 'rewrite' supported on V5 fs\n"),
-				progname);
-			return 0;
-		}
-
 		if (!strcasecmp(argv[1], "generate")) {
 			platform_uuid_generate(&uu);
 		} else if (!strcasecmp(argv[1], "nil")) {
@@ -388,6 +405,17 @@ uuid_f(
 			memcpy(&uu, uup, sizeof(uuid_t));
 			platform_uuid_unparse(&uu, bp);
 			dbprintf(_("old UUID = %s\n"), bp);
+		} else if (!strcasecmp(argv[1], "restore")) {
+			xfs_sb_t	tsb;
+
+			if (!get_sb(0, &tsb))
+				return 0;
+
+			/* Not set; nothing to do.  Success! */
+			if (!xfs_sb_version_hasmetauuid(&tsb))
+				return 0;
+		
+			memcpy(&uu, mp->m_sb.sb_meta_uuid, sizeof(uuid_t));
 		} else {
 			if (platform_uuid_parse(argv[1], &uu)) {
 				dbprintf(_("invalid UUID\n"));
@@ -660,6 +688,8 @@ version_string(
 		strcat(s, ",CRC");
 	if (xfs_sb_version_hasftype(sbp))
 		strcat(s, ",FTYPE");
+	if (xfs_sb_version_hasmetauuid(sbp))
+		strcat(s, ",META_UUID");
 	return s;
 }
 
diff --git a/libxfs/xfs_alloc.c b/libxfs/xfs_alloc.c
index 23e3c53..62dce1e 100644
--- a/libxfs/xfs_alloc.c
+++ b/libxfs/xfs_alloc.c
@@ -446,7 +446,7 @@ xfs_agfl_verify(
 	struct xfs_agfl	*agfl = XFS_BUF_TO_AGFL(bp);
 	int		i;
 
-	if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_uuid))
+	if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid))
 		return false;
 	if (be32_to_cpu(agfl->agfl_magicnum) != XFS_AGFL_MAGIC)
 		return false;
@@ -2199,7 +2199,7 @@ 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_uuid))
+	    !uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 
 	if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) &&
diff --git a/libxfs/xfs_alloc_btree.c b/libxfs/xfs_alloc_btree.c
index 7fd72af..e60538a 100644
--- a/libxfs/xfs_alloc_btree.c
+++ b/libxfs/xfs_alloc_btree.c
@@ -293,7 +293,7 @@ xfs_allocbt_verify(
 	case cpu_to_be32(XFS_ABTB_CRC_MAGIC):
 		if (!xfs_sb_version_hascrc(&mp->m_sb))
 			return false;
-		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
 			return false;
@@ -311,7 +311,7 @@ xfs_allocbt_verify(
 	case cpu_to_be32(XFS_ABTC_CRC_MAGIC):
 		if (!xfs_sb_version_hascrc(&mp->m_sb))
 			return false;
-		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
 			return false;
diff --git a/libxfs/xfs_attr_leaf.c b/libxfs/xfs_attr_leaf.c
index 200bd30..69b6af3 100644
--- a/libxfs/xfs_attr_leaf.c
+++ b/libxfs/xfs_attr_leaf.c
@@ -258,7 +258,7 @@ xfs_attr3_leaf_verify(
 		if (ichdr.magic != XFS_ATTR3_LEAF_MAGIC)
 			return false;
 
-		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
 			return false;
@@ -1052,7 +1052,7 @@ xfs_attr3_leaf_create(
 
 		hdr3->blkno = cpu_to_be64(bp->b_bn);
 		hdr3->owner = cpu_to_be64(dp->i_ino);
-		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
 
 		ichdr.freemap[0].base = sizeof(struct xfs_attr3_leaf_hdr);
 	} else {
diff --git a/libxfs/xfs_attr_remote.c b/libxfs/xfs_attr_remote.c
index 4f492c1..5feaf55 100644
--- a/libxfs/xfs_attr_remote.c
+++ b/libxfs/xfs_attr_remote.c
@@ -95,7 +95,7 @@ xfs_attr3_rmt_verify(
 		return false;
 	if (rmt->rm_magic != cpu_to_be32(XFS_ATTR3_RMT_MAGIC))
 		return false;
-	if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_uuid))
+	if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid))
 		return false;
 	if (be64_to_cpu(rmt->rm_blkno) != bno)
 		return false;
@@ -212,7 +212,7 @@ xfs_attr3_rmt_hdr_set(
 	rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC);
 	rmt->rm_offset = cpu_to_be32(offset);
 	rmt->rm_bytes = cpu_to_be32(size);
-	uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_uuid);
+	uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid);
 	rmt->rm_owner = cpu_to_be64(ino);
 	rmt->rm_blkno = cpu_to_be64(bno);
 
diff --git a/libxfs/xfs_bmap_btree.c b/libxfs/xfs_bmap_btree.c
index 2fd04e0..f42bc2d 100644
--- a/libxfs/xfs_bmap_btree.c
+++ b/libxfs/xfs_bmap_btree.c
@@ -346,7 +346,8 @@ xfs_bmbt_to_bmdr(
 
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_CRC_MAGIC));
-		ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid));
+		ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid,
+		       &mp->m_sb.sb_meta_uuid));
 		ASSERT(rblock->bb_u.l.bb_blkno ==
 		       cpu_to_be64(XFS_BUF_DADDR_NULL));
 	} else
@@ -644,7 +645,7 @@ xfs_bmbt_verify(
 	case cpu_to_be32(XFS_BMAP_CRC_MAGIC):
 		if (!xfs_sb_version_hascrc(&mp->m_sb))
 			return false;
-		if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(block->bb_u.l.bb_blkno) != bp->b_bn)
 			return false;
diff --git a/libxfs/xfs_btree.c b/libxfs/xfs_btree.c
index 203e7d2..a16ae7d 100644
--- a/libxfs/xfs_btree.c
+++ b/libxfs/xfs_btree.c
@@ -62,7 +62,8 @@ xfs_btree_check_lblock(
 
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		lblock_ok = lblock_ok &&
-			uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid) &&
+			uuid_equal(&block->bb_u.l.bb_uuid,
+				   &mp->m_sb.sb_meta_uuid) &&
 			block->bb_u.l.bb_blkno == cpu_to_be64(
 				bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
 	}
@@ -112,7 +113,8 @@ xfs_btree_check_sblock(
 
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		sblock_ok = sblock_ok &&
-			uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid) &&
+			uuid_equal(&block->bb_u.s.bb_uuid,
+				   &mp->m_sb.sb_meta_uuid) &&
 			block->bb_u.s.bb_blkno == cpu_to_be64(
 				bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
 	}
@@ -997,7 +999,7 @@ xfs_btree_init_block_int(
 		if (flags & XFS_BTREE_CRC_BLOCKS) {
 			buf->bb_u.l.bb_blkno = cpu_to_be64(blkno);
 			buf->bb_u.l.bb_owner = cpu_to_be64(owner);
-			uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid);
+			uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid);
 			buf->bb_u.l.bb_pad = 0;
 			buf->bb_u.l.bb_lsn = 0;
 		}
@@ -1010,7 +1012,7 @@ xfs_btree_init_block_int(
 		if (flags & XFS_BTREE_CRC_BLOCKS) {
 			buf->bb_u.s.bb_blkno = cpu_to_be64(blkno);
 			buf->bb_u.s.bb_owner = cpu_to_be32(__owner);
-			uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid);
+			uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid);
 			buf->bb_u.s.bb_lsn = 0;
 		}
 	}
diff --git a/libxfs/xfs_da_btree.c b/libxfs/xfs_da_btree.c
index 441bef4..3de4cd3 100644
--- a/libxfs/xfs_da_btree.c
+++ b/libxfs/xfs_da_btree.c
@@ -142,7 +142,7 @@ xfs_da3_node_verify(
 		if (ichdr.magic != XFS_DA3_NODE_MAGIC)
 			return false;
 
-		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
 			return false;
@@ -320,7 +320,7 @@ xfs_da3_node_create(
 		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);
-		uuid_copy(&hdr3->info.uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid);
 	} else {
 		ichdr.magic = XFS_DA_NODE_MAGIC;
 	}
diff --git a/libxfs/xfs_dir2_block.c b/libxfs/xfs_dir2_block.c
index f061a99..489f301 100644
--- a/libxfs/xfs_dir2_block.c
+++ b/libxfs/xfs_dir2_block.c
@@ -64,7 +64,7 @@ xfs_dir3_block_verify(
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		if (hdr3->magic != cpu_to_be32(XFS_DIR3_BLOCK_MAGIC))
 			return false;
-		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
 			return false;
@@ -154,7 +154,7 @@ xfs_dir3_block_init(
 		hdr3->magic = cpu_to_be32(XFS_DIR3_BLOCK_MAGIC);
 		hdr3->blkno = cpu_to_be64(bp->b_bn);
 		hdr3->owner = cpu_to_be64(dp->i_ino);
-		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
 		return;
 
 	}
diff --git a/libxfs/xfs_dir2_data.c b/libxfs/xfs_dir2_data.c
index 609c097..c475ba8 100644
--- a/libxfs/xfs_dir2_data.c
+++ b/libxfs/xfs_dir2_data.c
@@ -218,7 +218,7 @@ xfs_dir3_data_verify(
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		if (hdr3->magic != cpu_to_be32(XFS_DIR3_DATA_MAGIC))
 			return false;
-		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
 			return false;
@@ -602,7 +602,7 @@ xfs_dir3_data_init(
 		hdr3->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC);
 		hdr3->blkno = cpu_to_be64(bp->b_bn);
 		hdr3->owner = cpu_to_be64(dp->i_ino);
-		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
 
 	} else
 		hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
diff --git a/libxfs/xfs_dir2_leaf.c b/libxfs/xfs_dir2_leaf.c
index c2dba8a..80d03b3 100644
--- a/libxfs/xfs_dir2_leaf.c
+++ b/libxfs/xfs_dir2_leaf.c
@@ -158,7 +158,7 @@ xfs_dir3_leaf_verify(
 
 		if (leaf3->info.hdr.magic != cpu_to_be16(magic3))
 			return false;
-		if (!uuid_equal(&leaf3->info.uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&leaf3->info.uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn)
 			return false;
@@ -308,7 +308,7 @@ xfs_dir3_leaf_init(
 					 : cpu_to_be16(XFS_DIR3_LEAFN_MAGIC);
 		leaf3->info.blkno = cpu_to_be64(bp->b_bn);
 		leaf3->info.owner = cpu_to_be64(owner);
-		uuid_copy(&leaf3->info.uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&leaf3->info.uuid, &mp->m_sb.sb_meta_uuid);
 	} else {
 		memset(leaf, 0, sizeof(*leaf));
 		leaf->hdr.info.magic = cpu_to_be16(type);
diff --git a/libxfs/xfs_dir2_node.c b/libxfs/xfs_dir2_node.c
index 3b71e9e..581d648 100644
--- a/libxfs/xfs_dir2_node.c
+++ b/libxfs/xfs_dir2_node.c
@@ -91,7 +91,7 @@ xfs_dir3_free_verify(
 
 		if (hdr3->magic != cpu_to_be32(XFS_DIR3_FREE_MAGIC))
 			return false;
-		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
 			return false;
@@ -224,7 +224,7 @@ xfs_dir3_free_get_buf(
 
 		hdr3->hdr.blkno = cpu_to_be64(bp->b_bn);
 		hdr3->hdr.owner = cpu_to_be64(dp->i_ino);
-		uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_meta_uuid);
 	} else
 		hdr.magic = XFS_DIR2_FREE_MAGIC;
 	dp->d_ops->free_hdr_to_disk(bp->b_addr, &hdr);
diff --git a/libxfs/xfs_dquot_buf.c b/libxfs/xfs_dquot_buf.c
index 2e0484a..1a2546b 100644
--- a/libxfs/xfs_dquot_buf.c
+++ b/libxfs/xfs_dquot_buf.c
@@ -171,7 +171,7 @@ xfs_dqcheck(
 	d->dd_diskdq.d_id = cpu_to_be32(id);
 
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
-		uuid_copy(&d->dd_uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&d->dd_uuid, &mp->m_sb.sb_meta_uuid);
 		xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk),
 				 XFS_DQUOT_CRC_OFF);
 	}
@@ -206,7 +206,7 @@ xfs_dquot_buf_verify_crc(
 		if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk),
 				 XFS_DQUOT_CRC_OFF))
 			return false;
-		if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 	}
 	return true;
diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
index 4d313d3..c360585 100644
--- a/libxfs/xfs_format.h
+++ b/libxfs/xfs_format.h
@@ -100,7 +100,7 @@ typedef struct xfs_sb {
 	xfs_rfsblock_t	sb_dblocks;	/* number of data blocks */
 	xfs_rfsblock_t	sb_rblocks;	/* number of realtime blocks */
 	xfs_rtblock_t	sb_rextents;	/* number of realtime extents */
-	uuid_t		sb_uuid;	/* file system unique id */
+	uuid_t		sb_uuid;	/* user-visible file system unique id */
 	xfs_fsblock_t	sb_logstart;	/* starting block of log if internal */
 	xfs_ino_t	sb_rootino;	/* root inode number */
 	xfs_ino_t	sb_rbmino;	/* bitmap inode for realtime extents */
@@ -174,6 +174,7 @@ typedef struct xfs_sb {
 
 	xfs_ino_t	sb_pquotino;	/* project quota inode */
 	xfs_lsn_t	sb_lsn;		/* last write sequence */
+	uuid_t		sb_meta_uuid;	/* metadata file system unique id */
 
 	/* must be padded to 64 bit alignment */
 } xfs_sb_t;
@@ -190,7 +191,7 @@ typedef struct xfs_dsb {
 	__be64		sb_dblocks;	/* number of data blocks */
 	__be64		sb_rblocks;	/* number of realtime blocks */
 	__be64		sb_rextents;	/* number of realtime extents */
-	uuid_t		sb_uuid;	/* file system unique id */
+	uuid_t		sb_uuid;	/* user-visible file system unique id */
 	__be64		sb_logstart;	/* starting block of log if internal */
 	__be64		sb_rootino;	/* root inode number */
 	__be64		sb_rbmino;	/* bitmap inode for realtime extents */
@@ -260,6 +261,7 @@ typedef struct xfs_dsb {
 
 	__be64		sb_pquotino;	/* project quota inode */
 	__be64		sb_lsn;		/* last write sequence */
+	uuid_t		sb_meta_uuid;	/* metadata file system unique id */
 
 	/* must be padded to 64 bit alignment */
 } xfs_dsb_t;
@@ -457,8 +459,10 @@ xfs_sb_has_ro_compat_feature(
 }
 
 #define XFS_SB_FEAT_INCOMPAT_FTYPE	(1 << 0)	/* filetype in dirent */
+#define XFS_SB_FEAT_INCOMPAT_META_UUID	(1 << 1)	/* metadata UUID */
 #define XFS_SB_FEAT_INCOMPAT_ALL \
-		(XFS_SB_FEAT_INCOMPAT_FTYPE)
+		(XFS_SB_FEAT_INCOMPAT_FTYPE | \
+		 XFS_SB_FEAT_INCOMPAT_META_UUID)
 
 #define XFS_SB_FEAT_INCOMPAT_UNKNOWN	~XFS_SB_FEAT_INCOMPAT_ALL
 static inline bool
@@ -507,6 +511,18 @@ static inline int xfs_sb_version_hasfinobt(xfs_sb_t *sbp)
 }
 
 /*
+ * XFS_SB_FEAT_INCOMPAT_META_UUID indicates that the metadata UUID
+ * is stored separately from the user-visible UUID; this allows the
+ * user-visible UUID to be changed on V5 filesystems which have a
+ * filesystem UUID stamped into every piece of metadata.
+ */
+static inline int xfs_sb_version_hasmetauuid(xfs_sb_t *sbp)
+{
+	return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) &&
+		(sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID);
+}
+
+/*
  * end of superblock version macros
  */
 
diff --git a/libxfs/xfs_ialloc.c b/libxfs/xfs_ialloc.c
index 2b4e4e0..71af28e 100644
--- a/libxfs/xfs_ialloc.c
+++ b/libxfs/xfs_ialloc.c
@@ -302,7 +302,8 @@ xfs_ialloc_inode_init(
 			if (version == 3) {
 				free->di_ino = cpu_to_be64(ino);
 				ino++;
-				uuid_copy(&free->di_uuid, &mp->m_sb.sb_uuid);
+				uuid_copy(&free->di_uuid,
+					  &mp->m_sb.sb_meta_uuid);
 				xfs_dinode_calc_crc(mp, free);
 			} else if (tp) {
 				/* just log the inode core */
@@ -2044,7 +2045,7 @@ xfs_agi_verify(
 	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_uuid))
+	    !uuid_equal(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 	/*
 	 * Validate the magic number of the agi block.
diff --git a/libxfs/xfs_ialloc_btree.c b/libxfs/xfs_ialloc_btree.c
index 9ac143a..e8ec5e7 100644
--- a/libxfs/xfs_ialloc_btree.c
+++ b/libxfs/xfs_ialloc_btree.c
@@ -229,7 +229,7 @@ xfs_inobt_verify(
 	case cpu_to_be32(XFS_FIBT_CRC_MAGIC):
 		if (!xfs_sb_version_hascrc(&mp->m_sb))
 			return false;
-		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
 			return false;
diff --git a/libxfs/xfs_inode_buf.c b/libxfs/xfs_inode_buf.c
index fd48f04..3f20303 100644
--- a/libxfs/xfs_inode_buf.c
+++ b/libxfs/xfs_inode_buf.c
@@ -304,7 +304,7 @@ xfs_dinode_verify(
 		return false;
 	if (be64_to_cpu(dip->di_ino) != ino)
 		return false;
-	if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_uuid))
+	if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_meta_uuid))
 		return false;
 	return true;
 }
@@ -366,7 +366,7 @@ xfs_iread(
 		if (xfs_sb_version_hascrc(&mp->m_sb)) {
 			ip->i_d.di_version = 3;
 			ip->i_d.di_ino = ip->i_ino;
-			uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
+			uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid);
 		} else
 			ip->i_d.di_version = 2;
 		return 0;
diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c
index 6844cd8..b3c5de9 100644
--- a/libxfs/xfs_sb.c
+++ b/libxfs/xfs_sb.c
@@ -360,6 +360,17 @@ __xfs_sb_from_disk(
 	to->sb_pad = 0;
 	to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
 	to->sb_lsn = be64_to_cpu(from->sb_lsn);
+	/*
+	 * sb_meta_uuid is only on disk if it differs from sb_uuid and the
+	 * feature flag is set; if not set we keep it only in memory.
+	 */
+	if (xfs_sb_version_hasmetauuid(to)) {
+		memcpy(&to->sb_meta_uuid, &from->sb_meta_uuid,
+					sizeof(to->sb_meta_uuid));
+	} else {
+		memcpy(&to->sb_meta_uuid, &from->sb_uuid,
+					sizeof(to->sb_meta_uuid));
+	}
 	/* Convert on-disk flags to in-memory flags? */
 	if (convert_xquota)
 		xfs_sb_quota_from_disk(to);
@@ -501,6 +512,10 @@ xfs_sb_to_disk(
 				cpu_to_be32(from->sb_features_log_incompat);
 		to->sb_pad = 0;
 		to->sb_lsn = cpu_to_be64(from->sb_lsn);
+		if (xfs_sb_version_hasmetauuid(from)) {
+			memcpy(&to->sb_meta_uuid, &from->sb_meta_uuid,
+						sizeof(to->sb_meta_uuid));
+		}
 	}
 }
 
diff --git a/libxfs/xfs_symlink_remote.c b/libxfs/xfs_symlink_remote.c
index 6bc5af5..7d46d9e 100644
--- a/libxfs/xfs_symlink_remote.c
+++ b/libxfs/xfs_symlink_remote.c
@@ -60,7 +60,7 @@ xfs_symlink_hdr_set(
 	dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC);
 	dsl->sl_offset = cpu_to_be32(offset);
 	dsl->sl_bytes = cpu_to_be32(size);
-	uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_uuid);
+	uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid);
 	dsl->sl_owner = cpu_to_be64(ino);
 	dsl->sl_blkno = cpu_to_be64(bp->b_bn);
 	bp->b_ops = &xfs_symlink_buf_ops;
@@ -104,7 +104,7 @@ xfs_symlink_verify(
 		return false;
 	if (dsl->sl_magic != cpu_to_be32(XFS_SYMLINK_MAGIC))
 		return false;
-	if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_uuid))
+	if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid))
 		return false;
 	if (bp->b_bn != be64_to_cpu(dsl->sl_blkno))
 		return false;
diff --git a/libxlog/util.c b/libxlog/util.c
index 053cf04..fd1011f 100644
--- a/libxlog/util.c
+++ b/libxlog/util.c
@@ -29,8 +29,10 @@ header_check_uuid(xfs_mount_t *mp, xlog_rec_header_t *head)
 {
     char uu_log[64], uu_sb[64];
 
-    if (print_skip_uuid) return 0;
-    if (!platform_uuid_compare(&mp->m_sb.sb_uuid, &head->h_fs_uuid)) return 0;
+    if (print_skip_uuid)
+		return 0;
+    if (!platform_uuid_compare(&mp->m_sb.sb_uuid, &head->h_fs_uuid))
+		return 0;
 
     platform_uuid_unparse(&mp->m_sb.sb_uuid, uu_sb);
     platform_uuid_unparse(&head->h_fs_uuid, uu_log);
diff --git a/man/man8/xfs_admin.8 b/man/man8/xfs_admin.8
index b393d74..c17b35e 100644
--- a/man/man8/xfs_admin.8
+++ b/man/man8/xfs_admin.8
@@ -98,7 +98,12 @@ The
 .I uuid
 may also be
 .BR generate ,
-which will generate a new UUID for the filesystem.
+which will generate a new UUID for the filesystem.  Note that on CRC-enabled
+filesystems, this will set an incompatible flag such that older kernels will
+not be able to mount the filesystem.  To remove this incompatible flag, use
+.BR restore ,
+which will restore the original UUID and remove the incompatible
+feature flag as needed.
 .TP
 .B \-V
 Prints the version number and exits.
diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
index d527230..df54bb7 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -664,7 +664,7 @@ The possible data types are:
 .BR sb ", " symlink " and " text .
 See the TYPES section below for more information on these data types.
 .TP
-.BI "uuid [" uuid " | " generate " | " rewrite ]
+.BI "uuid [" uuid " | " generate " | " rewrite " | " restore ]
 Set the filesystem universally unique identifier (UUID).
 The filesystem UUID can be used by
 .BR mount (8)
@@ -675,7 +675,12 @@ can be set directly to the desired UUID, or it can
 be automatically generated using the
 .B generate
 option. These options will both write the UUID into every copy of the
-superblock in the filesystem.
+superblock in the filesystem.  On a CRC-enabled filesystem, this will
+set an incompatible superblock flag, and the filesystem will not be
+mountable with older kernels.  This can be reverted with the
+.B restore
+option, which will copy the original UUID back into place and clear
+the incompatible flag as needed.
 .B rewrite
 copies the current UUID from the primary superblock
 to all secondary copies of the superblock.
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 1770666..cb9f7f5 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -2598,6 +2598,8 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
 	sbp->sb_rextents = rtextents;
 	platform_uuid_generate(&uuid);
 	platform_uuid_copy(&sbp->sb_uuid, &uuid);
+	/* Only in memory; libxfs expects this as if read from disk */
+	platform_uuid_copy(&sbp->sb_meta_uuid, &uuid);
 	sbp->sb_logstart = logstart;
 	sbp->sb_rootino = sbp->sb_rbmino = sbp->sb_rsumino = NULLFSINO;
 	sbp->sb_rextsize = rtextblocks;
diff --git a/repair/agheader.c b/repair/agheader.c
index 9ae2deb..cfca529 100644
--- a/repair/agheader.c
+++ b/repair/agheader.c
@@ -112,7 +112,7 @@ verify_set_agf(xfs_mount_t *mp, xfs_agf_t *agf, xfs_agnumber_t i)
 	if (!xfs_sb_version_hascrc(&mp->m_sb))
 		return retval;
 
-	if (platform_uuid_compare(&agf->agf_uuid, &mp->m_sb.sb_uuid)) {
+	if (platform_uuid_compare(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid)) {
 		char uu[64];
 
 		retval = XR_AG_AGF;
@@ -120,7 +120,8 @@ verify_set_agf(xfs_mount_t *mp, xfs_agf_t *agf, xfs_agnumber_t i)
 		do_warn(_("bad uuid %s for agf %d\n"), uu, i);
 
 		if (!no_modify)
-			platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_uuid);
+			platform_uuid_copy(&agf->agf_uuid,
+					   &mp->m_sb.sb_meta_uuid);
 	}
 	return retval;
 }
@@ -190,7 +191,7 @@ verify_set_agi(xfs_mount_t *mp, xfs_agi_t *agi, xfs_agnumber_t agno)
 	if (!xfs_sb_version_hascrc(&mp->m_sb))
 		return retval;
 
-	if (platform_uuid_compare(&agi->agi_uuid, &mp->m_sb.sb_uuid)) {
+	if (platform_uuid_compare(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid)) {
 		char uu[64];
 
 		retval = XR_AG_AGI;
@@ -198,7 +199,8 @@ verify_set_agi(xfs_mount_t *mp, xfs_agi_t *agi, xfs_agnumber_t agno)
 		do_warn(_("bad uuid %s for agi %d\n"), uu, agno);
 
 		if (!no_modify)
-			platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid);
+			platform_uuid_copy(&agi->agi_uuid,
+					   &mp->m_sb.sb_meta_uuid);
 	}
 
 	return retval;
@@ -245,7 +247,7 @@ compare_sb(xfs_mount_t *mp, xfs_sb_t *sb)
  * superblocks, not just the secondary superblocks.
  */
 static int
-secondary_sb_wack(
+secondary_sb_whack(
 	struct xfs_mount *mp,
 	struct xfs_buf	*sbuf,
 	struct xfs_sb	*sb,
@@ -267,7 +269,10 @@ secondary_sb_wack(
 	 *
 	 * size is the size of data which is valid for this sb.
 	 */
-	if (xfs_sb_version_hascrc(sb))
+	if (xfs_sb_version_hasmetauuid(sb))
+		size = offsetof(xfs_sb_t, sb_meta_uuid)
+			+ sizeof(sb->sb_meta_uuid);
+	else if (xfs_sb_version_hascrc(sb))
 		size = offsetof(xfs_sb_t, sb_lsn)
 			+ sizeof(sb->sb_lsn);
 	else if (xfs_sb_version_hasmorebits(sb))
@@ -511,7 +516,7 @@ verify_set_agheader(xfs_mount_t *mp, xfs_buf_t *sbuf, xfs_sb_t *sb,
 		rval |= XR_AG_SB;
 	}
 
-	rval |= secondary_sb_wack(mp, sbuf, sb, i);
+	rval |= secondary_sb_whack(mp, sbuf, sb, i);
 
 	rval |= verify_set_agf(mp, agf, i);
 	rval |= verify_set_agi(mp, agi, i);
diff --git a/repair/agheader.h b/repair/agheader.h
index 5541fb9..6b2974c 100644
--- a/repair/agheader.h
+++ b/repair/agheader.h
@@ -24,7 +24,6 @@ typedef struct fs_geometry  {
 	xfs_rfsblock_t	sb_dblocks;	/* # data blocks */
 	xfs_rfsblock_t	sb_rblocks;	/* # realtime blocks */
 	xfs_rtblock_t	sb_rextents;	/* # realtime extents */
-	uuid_t		sb_uuid;	/* fs uuid */
 	xfs_fsblock_t	sb_logstart;	/* starting log block # */
 	xfs_agblock_t	sb_rextsize;	/* realtime extent size (blocks )*/
 	xfs_agblock_t	sb_agblocks;	/* # of blocks per ag */
diff --git a/repair/dinode.c b/repair/dinode.c
index 179203e..0ea5a9e 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -207,9 +207,9 @@ clear_dinode_core(struct xfs_mount *mp, xfs_dinode_t *dinoc, xfs_ino_t ino_num)
 		dinoc->di_ino = cpu_to_be64(ino_num);
 	}
 
-	if (platform_uuid_compare(&dinoc->di_uuid, &mp->m_sb.sb_uuid)) {
+	if (platform_uuid_compare(&dinoc->di_uuid, &mp->m_sb.sb_meta_uuid)) {
 		__dirty_no_modify_ret(dirty);
-		platform_uuid_copy(&dinoc->di_uuid, &mp->m_sb.sb_uuid);
+		platform_uuid_copy(&dinoc->di_uuid, &mp->m_sb.sb_meta_uuid);
 	}
 
 	for (i = 0; i < sizeof(dinoc->di_pad2)/sizeof(dinoc->di_pad2[0]); i++) {
@@ -2287,7 +2287,8 @@ _("inode identifier %llu mismatch on inode %" PRIu64 "\n"),
 				return 1;
 			goto clear_bad_out;
 		}
-		if (platform_uuid_compare(&dino->di_uuid, &mp->m_sb.sb_uuid)) {
+		if (platform_uuid_compare(&dino->di_uuid,
+					  &mp->m_sb.sb_meta_uuid)) {
 			if (!uncertain)
 				do_warn(
 			_("UUID mismatch on inode %" PRIu64 "\n"), lino);
diff --git a/repair/phase5.c b/repair/phase5.c
index 1ce57a1..d40b71d 100644
--- a/repair/phase5.c
+++ b/repair/phase5.c
@@ -1119,7 +1119,7 @@ build_agi(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *btree_curs,
 		agi->agi_unlinked[i] = cpu_to_be32(NULLAGINO);
 
 	if (xfs_sb_version_hascrc(&mp->m_sb))
-		platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid);
+		platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid);
 
 	if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
 		agi->agi_free_root = cpu_to_be32(finobt_curs->root);
@@ -1360,7 +1360,7 @@ build_agf_agfl(xfs_mount_t	*mp,
 #endif
 
 	if (xfs_sb_version_hascrc(&mp->m_sb))
-		platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_uuid);
+		platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid);
 
 	/* initialise the AGFL, then fill it if there are blocks left over. */
 	agfl_buf = libxfs_getbuf(mp->m_dev,
@@ -1374,7 +1374,7 @@ build_agf_agfl(xfs_mount_t	*mp,
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC);
 		agfl->agfl_seqno = cpu_to_be32(agno);
-		platform_uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_uuid);
+		platform_uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid);
 		for (i = 0; i < XFS_AGFL_SIZE(mp); i++)
 			agfl->agfl_bno[i] = cpu_to_be32(NULLAGBLOCK);
 	}
diff --git a/repair/phase6.c b/repair/phase6.c
index 7902be9..5148693 100644
--- a/repair/phase6.c
+++ b/repair/phase6.c
@@ -527,7 +527,7 @@ mk_rbmino(xfs_mount_t *mp)
 		ip->i_d.di_flags2 = 0;
 		ip->i_d.di_ino = mp->m_sb.sb_rbmino;
 		memset(&(ip->i_d.di_pad2[0]), 0, sizeof(ip->i_d.di_pad2));
-		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
+		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid);
 		times |= XFS_ICHGTIME_CREATE;
 	}
 	libxfs_trans_ichgtime(tp, ip, times);
@@ -783,7 +783,7 @@ mk_rsumino(xfs_mount_t *mp)
 		ip->i_d.di_flags2 = 0;
 		ip->i_d.di_ino = mp->m_sb.sb_rsumino;
 		memset(&(ip->i_d.di_pad2[0]), 0, sizeof(ip->i_d.di_pad2));
-		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
+		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid);
 		times |= XFS_ICHGTIME_CREATE;
 	}
 	libxfs_trans_ichgtime(tp, ip, times);
@@ -897,7 +897,7 @@ mk_root_dir(xfs_mount_t *mp)
 		ip->i_d.di_flags2 = 0;
 		ip->i_d.di_ino = mp->m_sb.sb_rootino;
 		memset(&(ip->i_d.di_pad2[0]), 0, sizeof(ip->i_d.di_pad2));
-		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
+		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid);
 		times |= XFS_ICHGTIME_CREATE;
 	}
 	libxfs_trans_ichgtime(tp, ip, times);

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

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

* Re: [PATCH 1/2] xfs: create new metadata UUID field and incompat flag
  2015-05-12 19:27 ` [PATCH 1/2] xfs: create new metadata UUID field and incompat flag Eric Sandeen
@ 2015-05-14 13:36   ` Brian Foster
  2015-05-14 22:36   ` Dave Chinner
  2015-05-14 22:55   ` [PATCH 1/2 V4] " Eric Sandeen
  2 siblings, 0 replies; 13+ messages in thread
From: Brian Foster @ 2015-05-14 13:36 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: xfs-oss

On Tue, May 12, 2015 at 02:27:51PM -0500, Eric Sandeen wrote:
> This adds a new superblock field, sb_meta_uuid.  If set, along with
> a new incompat flag, the code will use that field on a V5 filesystem
> to compare to metadata UUIDs, which allows us to change the user-
> visible UUID at will.  Userspace handles the setting and clearing
> of the incompat flag as appropriate, as the UUID gets changed; i.e.
> setting the user-visible UUID back to the original UUID (as stored in
> the new field) will remove the incompatible feature flag.
> 
> If the incompat flag is not set, this copies the user-visible UUID into
> into the meta_uuid slot in memory when the superblock is read from disk;
> the meta_uuid field is not written back to disk in this case.
> 
> The remainder of this patch simply switches verifiers, initializers,
> etc to use the new sb_meta_uuid field.
> 
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> ---

Looks good to me:

Reviewed-by: Brian Foster <bfoster@redhat.com>

> 
> diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
> index 516162b..27f76ca 100644
> --- a/fs/xfs/libxfs/xfs_alloc.c
> +++ b/fs/xfs/libxfs/xfs_alloc.c
> @@ -450,7 +450,7 @@ xfs_agfl_verify(
>  	struct xfs_agfl	*agfl = XFS_BUF_TO_AGFL(bp);
>  	int		i;
>  
> -	if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_uuid))
> +	if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid))
>  		return false;
>  	if (be32_to_cpu(agfl->agfl_magicnum) != XFS_AGFL_MAGIC)
>  		return false;
> @@ -2203,7 +2203,7 @@ 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_uuid))
> +	    !uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  
>  	if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) &&
> diff --git a/fs/xfs/libxfs/xfs_alloc_btree.c b/fs/xfs/libxfs/xfs_alloc_btree.c
> index 59d521c..90de071 100644
> --- a/fs/xfs/libxfs/xfs_alloc_btree.c
> +++ b/fs/xfs/libxfs/xfs_alloc_btree.c
> @@ -295,7 +295,7 @@ xfs_allocbt_verify(
>  	case cpu_to_be32(XFS_ABTB_CRC_MAGIC):
>  		if (!xfs_sb_version_hascrc(&mp->m_sb))
>  			return false;
> -		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
>  			return false;
> @@ -313,7 +313,7 @@ xfs_allocbt_verify(
>  	case cpu_to_be32(XFS_ABTC_CRC_MAGIC):
>  		if (!xfs_sb_version_hascrc(&mp->m_sb))
>  			return false;
> -		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
>  			return false;
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> index 04e79d5..6755762 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -262,7 +262,7 @@ xfs_attr3_leaf_verify(
>  		if (ichdr.magic != XFS_ATTR3_LEAF_MAGIC)
>  			return false;
>  
> -		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
>  			return false;
> @@ -1056,7 +1056,7 @@ xfs_attr3_leaf_create(
>  
>  		hdr3->blkno = cpu_to_be64(bp->b_bn);
>  		hdr3->owner = cpu_to_be64(dp->i_ino);
> -		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
> +		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
>  
>  		ichdr.freemap[0].base = sizeof(struct xfs_attr3_leaf_hdr);
>  	} else {
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> index 20de88d..eba0d1e 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.c
> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> @@ -100,7 +100,7 @@ xfs_attr3_rmt_verify(
>  		return false;
>  	if (rmt->rm_magic != cpu_to_be32(XFS_ATTR3_RMT_MAGIC))
>  		return false;
> -	if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_uuid))
> +	if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid))
>  		return false;
>  	if (be64_to_cpu(rmt->rm_blkno) != bno)
>  		return false;
> @@ -217,7 +217,7 @@ xfs_attr3_rmt_hdr_set(
>  	rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC);
>  	rmt->rm_offset = cpu_to_be32(offset);
>  	rmt->rm_bytes = cpu_to_be32(size);
> -	uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_uuid);
> +	uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid);
>  	rmt->rm_owner = cpu_to_be64(ino);
>  	rmt->rm_blkno = cpu_to_be64(bno);
>  
> diff --git a/fs/xfs/libxfs/xfs_bmap_btree.c b/fs/xfs/libxfs/xfs_bmap_btree.c
> index 2c44c8e..6b0cf65 100644
> --- a/fs/xfs/libxfs/xfs_bmap_btree.c
> +++ b/fs/xfs/libxfs/xfs_bmap_btree.c
> @@ -349,7 +349,8 @@ xfs_bmbt_to_bmdr(
>  
>  	if (xfs_sb_version_hascrc(&mp->m_sb)) {
>  		ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_CRC_MAGIC));
> -		ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid));
> +		ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid,
> +		       &mp->m_sb.sb_meta_uuid));
>  		ASSERT(rblock->bb_u.l.bb_blkno ==
>  		       cpu_to_be64(XFS_BUF_DADDR_NULL));
>  	} else
> @@ -647,7 +648,7 @@ xfs_bmbt_verify(
>  	case cpu_to_be32(XFS_BMAP_CRC_MAGIC):
>  		if (!xfs_sb_version_hascrc(&mp->m_sb))
>  			return false;
> -		if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (be64_to_cpu(block->bb_u.l.bb_blkno) != bp->b_bn)
>  			return false;
> diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
> index c72283d..f7d7ee7 100644
> --- a/fs/xfs/libxfs/xfs_btree.c
> +++ b/fs/xfs/libxfs/xfs_btree.c
> @@ -65,7 +65,8 @@ xfs_btree_check_lblock(
>  
>  	if (xfs_sb_version_hascrc(&mp->m_sb)) {
>  		lblock_ok = lblock_ok &&
> -			uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid) &&
> +			uuid_equal(&block->bb_u.l.bb_uuid,
> +				   &mp->m_sb.sb_meta_uuid) &&
>  			block->bb_u.l.bb_blkno == cpu_to_be64(
>  				bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
>  	}
> @@ -115,7 +116,8 @@ xfs_btree_check_sblock(
>  
>  	if (xfs_sb_version_hascrc(&mp->m_sb)) {
>  		sblock_ok = sblock_ok &&
> -			uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid) &&
> +			uuid_equal(&block->bb_u.s.bb_uuid,
> +				   &mp->m_sb.sb_meta_uuid) &&
>  			block->bb_u.s.bb_blkno == cpu_to_be64(
>  				bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
>  	}
> @@ -1000,7 +1002,7 @@ xfs_btree_init_block_int(
>  		if (flags & XFS_BTREE_CRC_BLOCKS) {
>  			buf->bb_u.l.bb_blkno = cpu_to_be64(blkno);
>  			buf->bb_u.l.bb_owner = cpu_to_be64(owner);
> -			uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid);
> +			uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid);
>  			buf->bb_u.l.bb_pad = 0;
>  			buf->bb_u.l.bb_lsn = 0;
>  		}
> @@ -1013,7 +1015,7 @@ xfs_btree_init_block_int(
>  		if (flags & XFS_BTREE_CRC_BLOCKS) {
>  			buf->bb_u.s.bb_blkno = cpu_to_be64(blkno);
>  			buf->bb_u.s.bb_owner = cpu_to_be32(__owner);
> -			uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid);
> +			uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid);
>  			buf->bb_u.s.bb_lsn = 0;
>  		}
>  	}
> diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c
> index 2385f8c..e9f6709 100644
> --- a/fs/xfs/libxfs/xfs_da_btree.c
> +++ b/fs/xfs/libxfs/xfs_da_btree.c
> @@ -146,7 +146,7 @@ xfs_da3_node_verify(
>  		if (ichdr.magic != XFS_DA3_NODE_MAGIC)
>  			return false;
>  
> -		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
>  			return false;
> @@ -324,7 +324,7 @@ xfs_da3_node_create(
>  		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);
> -		uuid_copy(&hdr3->info.uuid, &mp->m_sb.sb_uuid);
> +		uuid_copy(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid);
>  	} else {
>  		ichdr.magic = XFS_DA_NODE_MAGIC;
>  	}
> diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
> index 9354e19..4778d1d 100644
> --- a/fs/xfs/libxfs/xfs_dir2_block.c
> +++ b/fs/xfs/libxfs/xfs_dir2_block.c
> @@ -67,7 +67,7 @@ xfs_dir3_block_verify(
>  	if (xfs_sb_version_hascrc(&mp->m_sb)) {
>  		if (hdr3->magic != cpu_to_be32(XFS_DIR3_BLOCK_MAGIC))
>  			return false;
> -		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
>  			return false;
> @@ -157,7 +157,7 @@ xfs_dir3_block_init(
>  		hdr3->magic = cpu_to_be32(XFS_DIR3_BLOCK_MAGIC);
>  		hdr3->blkno = cpu_to_be64(bp->b_bn);
>  		hdr3->owner = cpu_to_be64(dp->i_ino);
> -		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
> +		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
>  		return;
>  
>  	}
> diff --git a/fs/xfs/libxfs/xfs_dir2_data.c b/fs/xfs/libxfs/xfs_dir2_data.c
> index de1ea16..6a57fdb 100644
> --- a/fs/xfs/libxfs/xfs_dir2_data.c
> +++ b/fs/xfs/libxfs/xfs_dir2_data.c
> @@ -220,7 +220,7 @@ xfs_dir3_data_verify(
>  	if (xfs_sb_version_hascrc(&mp->m_sb)) {
>  		if (hdr3->magic != cpu_to_be32(XFS_DIR3_DATA_MAGIC))
>  			return false;
> -		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
>  			return false;
> @@ -604,7 +604,7 @@ xfs_dir3_data_init(
>  		hdr3->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC);
>  		hdr3->blkno = cpu_to_be64(bp->b_bn);
>  		hdr3->owner = cpu_to_be64(dp->i_ino);
> -		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
> +		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
>  
>  	} else
>  		hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
> diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
> index 1061199..f300240 100644
> --- a/fs/xfs/libxfs/xfs_dir2_leaf.c
> +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
> @@ -160,7 +160,7 @@ xfs_dir3_leaf_verify(
>  
>  		if (leaf3->info.hdr.magic != cpu_to_be16(magic3))
>  			return false;
> -		if (!uuid_equal(&leaf3->info.uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&leaf3->info.uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn)
>  			return false;
> @@ -310,7 +310,7 @@ xfs_dir3_leaf_init(
>  					 : cpu_to_be16(XFS_DIR3_LEAFN_MAGIC);
>  		leaf3->info.blkno = cpu_to_be64(bp->b_bn);
>  		leaf3->info.owner = cpu_to_be64(owner);
> -		uuid_copy(&leaf3->info.uuid, &mp->m_sb.sb_uuid);
> +		uuid_copy(&leaf3->info.uuid, &mp->m_sb.sb_meta_uuid);
>  	} else {
>  		memset(leaf, 0, sizeof(*leaf));
>  		leaf->hdr.info.magic = cpu_to_be16(type);
> diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
> index 41b80d3..527b733 100644
> --- a/fs/xfs/libxfs/xfs_dir2_node.c
> +++ b/fs/xfs/libxfs/xfs_dir2_node.c
> @@ -93,7 +93,7 @@ xfs_dir3_free_verify(
>  
>  		if (hdr3->magic != cpu_to_be32(XFS_DIR3_FREE_MAGIC))
>  			return false;
> -		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
>  			return false;
> @@ -226,7 +226,7 @@ xfs_dir3_free_get_buf(
>  
>  		hdr3->hdr.blkno = cpu_to_be64(bp->b_bn);
>  		hdr3->hdr.owner = cpu_to_be64(dp->i_ino);
> -		uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_uuid);
> +		uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_meta_uuid);
>  	} else
>  		hdr.magic = XFS_DIR2_FREE_MAGIC;
>  	dp->d_ops->free_hdr_to_disk(bp->b_addr, &hdr);
> diff --git a/fs/xfs/libxfs/xfs_dquot_buf.c b/fs/xfs/libxfs/xfs_dquot_buf.c
> index 6fbf2d8..5331b7f 100644
> --- a/fs/xfs/libxfs/xfs_dquot_buf.c
> +++ b/fs/xfs/libxfs/xfs_dquot_buf.c
> @@ -163,7 +163,7 @@ xfs_dqcheck(
>  	d->dd_diskdq.d_id = cpu_to_be32(id);
>  
>  	if (xfs_sb_version_hascrc(&mp->m_sb)) {
> -		uuid_copy(&d->dd_uuid, &mp->m_sb.sb_uuid);
> +		uuid_copy(&d->dd_uuid, &mp->m_sb.sb_meta_uuid);
>  		xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk),
>  				 XFS_DQUOT_CRC_OFF);
>  	}
> @@ -198,7 +198,7 @@ xfs_dquot_buf_verify_crc(
>  		if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk),
>  				 XFS_DQUOT_CRC_OFF))
>  			return false;
> -		if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  	}
>  	return true;
> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> index 4daaa66..88c38df 100644
> --- a/fs/xfs/libxfs/xfs_format.h
> +++ b/fs/xfs/libxfs/xfs_format.h
> @@ -100,7 +100,7 @@ typedef struct xfs_sb {
>  	xfs_rfsblock_t	sb_dblocks;	/* number of data blocks */
>  	xfs_rfsblock_t	sb_rblocks;	/* number of realtime blocks */
>  	xfs_rtblock_t	sb_rextents;	/* number of realtime extents */
> -	uuid_t		sb_uuid;	/* file system unique id */
> +	uuid_t		sb_uuid;	/* user-visible file system unique id */
>  	xfs_fsblock_t	sb_logstart;	/* starting block of log if internal */
>  	xfs_ino_t	sb_rootino;	/* root inode number */
>  	xfs_ino_t	sb_rbmino;	/* bitmap inode for realtime extents */
> @@ -174,6 +174,7 @@ typedef struct xfs_sb {
>  
>  	xfs_ino_t	sb_pquotino;	/* project quota inode */
>  	xfs_lsn_t	sb_lsn;		/* last write sequence */
> +	uuid_t		sb_meta_uuid;	/* metadata file system unique id */
>  
>  	/* must be padded to 64 bit alignment */
>  } xfs_sb_t;
> @@ -190,7 +191,7 @@ typedef struct xfs_dsb {
>  	__be64		sb_dblocks;	/* number of data blocks */
>  	__be64		sb_rblocks;	/* number of realtime blocks */
>  	__be64		sb_rextents;	/* number of realtime extents */
> -	uuid_t		sb_uuid;	/* file system unique id */
> +	uuid_t		sb_uuid;	/* user-visible file system unique id */
>  	__be64		sb_logstart;	/* starting block of log if internal */
>  	__be64		sb_rootino;	/* root inode number */
>  	__be64		sb_rbmino;	/* bitmap inode for realtime extents */
> @@ -260,6 +261,7 @@ typedef struct xfs_dsb {
>  
>  	__be64		sb_pquotino;	/* project quota inode */
>  	__be64		sb_lsn;		/* last write sequence */
> +	uuid_t		sb_meta_uuid;	/* metadata file system unique id */
>  
>  	/* must be padded to 64 bit alignment */
>  } xfs_dsb_t;
> @@ -457,8 +459,10 @@ xfs_sb_has_ro_compat_feature(
>  }
>  
>  #define XFS_SB_FEAT_INCOMPAT_FTYPE	(1 << 0)	/* filetype in dirent */
> +#define XFS_SB_FEAT_INCOMPAT_META_UUID	(1 << 1)	/* metadata UUID */
>  #define XFS_SB_FEAT_INCOMPAT_ALL \
> -		(XFS_SB_FEAT_INCOMPAT_FTYPE)
> +		(XFS_SB_FEAT_INCOMPAT_FTYPE | \
> +		 XFS_SB_FEAT_INCOMPAT_META_UUID)
>  
>  #define XFS_SB_FEAT_INCOMPAT_UNKNOWN	~XFS_SB_FEAT_INCOMPAT_ALL
>  static inline bool
> @@ -507,6 +511,18 @@ static inline int xfs_sb_version_hasfinobt(xfs_sb_t *sbp)
>  }
>  
>  /*
> + * XFS_SB_FEAT_INCOMPAT_META_UUID indicates that the metadata UUID
> + * is stored separately from the user-visible UUID; this allows the
> + * user-visible UUID to be changed on V5 filesystems which have a
> + * filesystem UUID stamped into every piece of metadata.
> + */
> +static inline int xfs_sb_version_hasmetauuid(xfs_sb_t *sbp)
> +{
> +	return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) &&
> +		(sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID);
> +}
> +
> +/*
>   * end of superblock version macros
>   */
>  
> diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
> index 07349a1..d9b90c0 100644
> --- a/fs/xfs/libxfs/xfs_ialloc.c
> +++ b/fs/xfs/libxfs/xfs_ialloc.c
> @@ -307,7 +307,8 @@ xfs_ialloc_inode_init(
>  			if (version == 3) {
>  				free->di_ino = cpu_to_be64(ino);
>  				ino++;
> -				uuid_copy(&free->di_uuid, &mp->m_sb.sb_uuid);
> +				uuid_copy(&free->di_uuid,
> +					  &mp->m_sb.sb_meta_uuid);
>  				xfs_dinode_calc_crc(mp, free);
>  			} else if (tp) {
>  				/* just log the inode core */
> @@ -2049,7 +2050,7 @@ xfs_agi_verify(
>  	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_uuid))
> +	    !uuid_equal(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  	/*
>  	 * Validate the magic number of the agi block.
> diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c
> index 964c465..0fa2a27 100644
> --- a/fs/xfs/libxfs/xfs_ialloc_btree.c
> +++ b/fs/xfs/libxfs/xfs_ialloc_btree.c
> @@ -230,7 +230,7 @@ xfs_inobt_verify(
>  	case cpu_to_be32(XFS_FIBT_CRC_MAGIC):
>  		if (!xfs_sb_version_hascrc(&mp->m_sb))
>  			return false;
> -		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
>  			return false;
> diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
> index 002b6b3..0f9563e 100644
> --- a/fs/xfs/libxfs/xfs_inode_buf.c
> +++ b/fs/xfs/libxfs/xfs_inode_buf.c
> @@ -306,7 +306,7 @@ xfs_dinode_verify(
>  		return false;
>  	if (be64_to_cpu(dip->di_ino) != ip->i_ino)
>  		return false;
> -	if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_uuid))
> +	if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_meta_uuid))
>  		return false;
>  	return true;
>  }
> @@ -368,7 +368,7 @@ xfs_iread(
>  		if (xfs_sb_version_hascrc(&mp->m_sb)) {
>  			ip->i_d.di_version = 3;
>  			ip->i_d.di_ino = ip->i_ino;
> -			uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
> +			uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid);
>  		} else
>  			ip->i_d.di_version = 2;
>  		return 0;
> diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
> index dc4bfc5..04f1b28 100644
> --- a/fs/xfs/libxfs/xfs_sb.c
> +++ b/fs/xfs/libxfs/xfs_sb.c
> @@ -377,6 +377,17 @@ __xfs_sb_from_disk(
>  	to->sb_pad = 0;
>  	to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
>  	to->sb_lsn = be64_to_cpu(from->sb_lsn);
> +	/*
> +	 * sb_meta_uuid is only on disk if it differs from sb_uuid and the
> +	 * feature flag is set; if not set we keep it only in memory.
> +	 */
> +	if (xfs_sb_version_hasmetauuid(to)) {
> +		memcpy(&to->sb_meta_uuid, &from->sb_meta_uuid,
> +					sizeof(to->sb_meta_uuid));
> +	} else {
> +		memcpy(&to->sb_meta_uuid, &from->sb_uuid,
> +					sizeof(to->sb_meta_uuid));
> +	}
>  	/* Convert on-disk flags to in-memory flags? */
>  	if (convert_xquota)
>  		xfs_sb_quota_from_disk(to);
> @@ -518,6 +529,10 @@ xfs_sb_to_disk(
>  				cpu_to_be32(from->sb_features_log_incompat);
>  		to->sb_pad = 0;
>  		to->sb_lsn = cpu_to_be64(from->sb_lsn);
> +		if (xfs_sb_version_hasmetauuid(from)) {
> +			memcpy(&to->sb_meta_uuid, &from->sb_meta_uuid,
> +						sizeof(to->sb_meta_uuid));
> +		}
>  	}
>  }
>  
> diff --git a/fs/xfs/libxfs/xfs_symlink_remote.c b/fs/xfs/libxfs/xfs_symlink_remote.c
> index e7e26bd..8f8af05 100644
> --- a/fs/xfs/libxfs/xfs_symlink_remote.c
> +++ b/fs/xfs/libxfs/xfs_symlink_remote.c
> @@ -63,7 +63,7 @@ xfs_symlink_hdr_set(
>  	dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC);
>  	dsl->sl_offset = cpu_to_be32(offset);
>  	dsl->sl_bytes = cpu_to_be32(size);
> -	uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_uuid);
> +	uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid);
>  	dsl->sl_owner = cpu_to_be64(ino);
>  	dsl->sl_blkno = cpu_to_be64(bp->b_bn);
>  	bp->b_ops = &xfs_symlink_buf_ops;
> @@ -107,7 +107,7 @@ xfs_symlink_verify(
>  		return false;
>  	if (dsl->sl_magic != cpu_to_be32(XFS_SYMLINK_MAGIC))
>  		return false;
> -	if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_uuid))
> +	if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid))
>  		return false;
>  	if (bp->b_bn != be64_to_cpu(dsl->sl_blkno))
>  		return false;
> diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
> index 02c01bb..e0c7e15 100644
> --- a/fs/xfs/xfs_dquot.c
> +++ b/fs/xfs/xfs_dquot.c
> @@ -251,7 +251,7 @@ xfs_qm_init_dquot_blk(
>  		d->dd_diskdq.d_id = cpu_to_be32(curid);
>  		d->dd_diskdq.d_flags = type;
>  		if (xfs_sb_version_hascrc(&mp->m_sb)) {
> -			uuid_copy(&d->dd_uuid, &mp->m_sb.sb_uuid);
> +			uuid_copy(&d->dd_uuid, &mp->m_sb.sb_meta_uuid);
>  			xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk),
>  					 XFS_DQUOT_CRC_OFF);
>  		}
> diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
> index cb7e8a2..9c892cd 100644
> --- a/fs/xfs/xfs_fsops.c
> +++ b/fs/xfs/xfs_fsops.c
> @@ -248,7 +248,7 @@ xfs_growfs_data_private(
>  		agf->agf_freeblks = cpu_to_be32(tmpsize);
>  		agf->agf_longest = cpu_to_be32(tmpsize);
>  		if (xfs_sb_version_hascrc(&mp->m_sb))
> -			uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_uuid);
> +			uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid);
>  
>  		error = xfs_bwrite(bp);
>  		xfs_buf_relse(bp);
> @@ -271,7 +271,7 @@ xfs_growfs_data_private(
>  		if (xfs_sb_version_hascrc(&mp->m_sb)) {
>  			agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC);
>  			agfl->agfl_seqno = cpu_to_be32(agno);
> -			uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_uuid);
> +			uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid);
>  		}
>  
>  		agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, bp);
> @@ -307,7 +307,7 @@ xfs_growfs_data_private(
>  		agi->agi_newino = cpu_to_be32(NULLAGINO);
>  		agi->agi_dirino = cpu_to_be32(NULLAGINO);
>  		if (xfs_sb_version_hascrc(&mp->m_sb))
> -			uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid);
> +			uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid);
>  		if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
>  			agi->agi_free_root = cpu_to_be32(XFS_FIBT_BLOCK(mp));
>  			agi->agi_free_level = cpu_to_be32(1);
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index d6ebc85..9a2ecb7 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -787,7 +787,7 @@ xfs_ialloc(
>  
>  	if (ip->i_d.di_version == 3) {
>  		ASSERT(ip->i_d.di_ino == ino);
> -		ASSERT(uuid_equal(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid));
> +		ASSERT(uuid_equal(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid));
>  		ip->i_d.di_crc = 0;
>  		ip->i_d.di_changecount = 1;
>  		ip->i_d.di_lsn = 0;
> diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
> index 4f5784f..4da291c 100644
> --- a/fs/xfs/xfs_log_recover.c
> +++ b/fs/xfs/xfs_log_recover.c
> @@ -325,7 +325,7 @@ xlog_header_check_recover(
>  		XFS_ERROR_REPORT("xlog_header_check_recover(1)",
>  				 XFS_ERRLEVEL_HIGH, mp);
>  		return -EFSCORRUPTED;
> -	} else if (unlikely(!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid))) {
> +	} else if (!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid)) {
>  		xfs_warn(mp,
>  	"dirty log entry has mismatched uuid - can't recover");
>  		xlog_header_check_dump(mp, head);
> @@ -353,7 +353,7 @@ xlog_header_check_mount(
>  		 * by IRIX and continue.
>  		 */
>  		xfs_warn(mp, "nil uuid in log - IRIX style log");
> -	} else if (unlikely(!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid))) {
> +	} else if (!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid)) {
>  		xfs_warn(mp, "log has mismatched uuid - can't recover");
>  		xlog_header_check_dump(mp, head);
>  		XFS_ERROR_REPORT("xlog_header_check_mount",
> 
> 
> _______________________________________________
> xfs mailing list
> xfs@oss.sgi.com
> http://oss.sgi.com/mailman/listinfo/xfs

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

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

* Re: [PATCH 2/2] xfsprogs: Add new sb_meta_uuid field, update userspace tools to manipulate it
  2015-05-12 19:30 ` [PATCH 2/2] xfsprogs: Add new sb_meta_uuid field, update userspace tools to manipulate it Eric Sandeen
@ 2015-05-14 13:39   ` Brian Foster
  2015-05-14 16:29     ` Eric Sandeen
  2015-05-14 21:54   ` [PATCH 2/2 V4] " Eric Sandeen
  1 sibling, 1 reply; 13+ messages in thread
From: Brian Foster @ 2015-05-14 13:39 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: xfs-oss

On Tue, May 12, 2015 at 02:30:15PM -0500, Eric Sandeen wrote:
> This adds a new superblock field, sb_meta_uuid.  This allows us to
> change the use-visible UUID on crc-enabled filesytems from userspace
> if desired, by copying the existing UUID to the new location for
> metadata comparisons.  If this is done, an incompat flag must be
> set to prevent older filesystems from mounting the filesystem, but
> the original UUID can be restored, and the incompat flag removed,
> with a new xfs_db / xfs_admin UUID command, "restore."
> 
> Much of this patch mirrors the kernel patch in simply renaming
> the field used for metadata uuid comparison; other bits:
> 
> * Teach xfs_db to print the new meta_uuid field
> * Allow xfs_db to generate a new UUID for CRC-enabled filesystems
> * Allow xfs_db to revert to the original UUID and clear the flag
> * Fix up xfs_copy to work with CRC-enabled filesystems
> * Update the xfs_admin manpage to show the UUID "restore" command
> 
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> ---
> 
> This version makes the UUID "restore" command silent if there
> is nothing to do.
> 
> Still open to bike-shedding on the "restore" name.  Maybe "revert?"
> 

Restore seems fine to me...

> diff --git a/copy/xfs_copy.c b/copy/xfs_copy.c
> index 279527c..a58eee5 100644
> --- a/copy/xfs_copy.c
> +++ b/copy/xfs_copy.c
> @@ -466,6 +466,34 @@ write_wbuf(void)
>  	sighold(SIGCHLD);
>  }
>  
> +void
> +sb_update_uuid(
> +	xfs_sb_t	*sb,
> +	ag_header_t	*ag_hdr,
> +	thread_args	*tcarg)
> +{
> +	/*
> +	 * If this filesystem has CRCs, the original UUID is stamped into
> +	 * all metadata.  We need to copy the original UUID into the meta_uuid
> +	 * slot and set the incompat flag if that hasn't already been done.
> +	 */
> +	if (xfs_sb_version_hascrc(sb) && !xfs_sb_version_hasmetauuid(sb)) {
> +		__be32 feat;
> +
> +		feat = be32_to_cpu(ag_hdr->xfs_sb->sb_features_incompat);
> +		feat |= XFS_SB_FEAT_INCOMPAT_META_UUID;
> +		ag_hdr->xfs_sb->sb_features_incompat = cpu_to_be32(feat);
> +		platform_uuid_copy(&ag_hdr->xfs_sb->sb_meta_uuid,
> +				   &ag_hdr->xfs_sb->sb_uuid);
> +	}
> +
> +	platform_uuid_copy(&ag_hdr->xfs_sb->sb_uuid, &tcarg->uuid);
> +
> +	/* We changed the UUID, so update the superblock CRC if needed */
> +	if (xfs_sb_version_hascrc(sb))
> +		xfs_update_cksum((char *)&ag_hdr->xfs_sb, sb->sb_sectsize,
> +							 XFS_SB_CRC_OFF);
> +}
>  
>  int
>  main(int argc, char **argv)
> @@ -659,16 +687,6 @@ main(int argc, char **argv)
>  	sb = &mbuf.m_sb;
>  	libxfs_sb_from_disk(sb, XFS_BUF_TO_SBP(sbp));
>  
> -	/*
> -	 * For now, V5 superblock filesystems are not supported without -d;
> -	 * we do not have the infrastructure yet to fix CRCs when a new UUID
> -	 * is generated.
> -	 */
> -	if (xfs_sb_version_hascrc(sb) && !duplicate) {
> -		do_log(_("%s: Cannot yet copy V5 fs without '-d'\n"), progname);
> -		exit(1);
> -	}
> -
>  	mp = libxfs_mount(&mbuf, sb, xargs.ddev, xargs.logdev, xargs.rtdev, 0);
>  	if (mp == NULL) {
>  		do_log(_("%s: %s filesystem failed to initialize\n"
> @@ -1127,8 +1145,7 @@ main(int argc, char **argv)
>  			/* do each thread in turn, each has its own UUID */
>  
>  			for (j = 0, tcarg = targ; j < num_targets; j++)  {
> -				platform_uuid_copy(&ag_hdr.xfs_sb->sb_uuid,
> -							&tcarg->uuid);
> +				sb_update_uuid(sb, &ag_hdr, tcarg);

xfs_copy doesn't work for me (crc=1,finobt=1)...

# ./copy/xfs_copy /dev/vdb1 /dev/vdb2 
 0%  ... 10%  ... 20%  ... 30%  ... 40%  ... 50%  ... 60%  ... 70%  ... 80%  ... 90%  ... 100%

All copies completed.
# mount /dev/vdb2 /mnt/
mount: mount /dev/vdb2 on /mnt failed: Structure needs cleaning
# dmesg | tail
...
[ 4145.609403] XFS (vdb2): Metadata CRC error detected at xfs_sb_read_verify+0x112/0x170 [xfs], block 0xffffffffffffffff
[ 4145.611224] XFS (vdb2): Unmount and run xfs_repair
[ 4145.611945] XFS (vdb2): First 64 bytes of corrupted metadata buffer:
[ 4145.612873] ffff8800d8def000: 58 46 53 42 00 00 10 00 00 00 00 00 00 25 40 00  XFSB.........%@.
[ 4145.615047] ffff8800d8def010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
[ 4145.616359] ffff8800d8def020: 73 68 6d 76 a1 6d 43 96 8f 35 cb 98 2c ff fd 8d  shmv.mC..5..,...
[ 4145.617926] ffff8800d8def030: 00 00 00 00 00 20 00 05 00 00 00 00 00 00 00 60  ..... .........`
[ 4145.619267] XFS (vdb2): SB validate failed with error -74.

The same thing occurs with -d. It looks like the crc might not have
updated..?

>  				do_write(tcarg);
>  				tcarg++;
>  			}
> diff --git a/db/sb.c b/db/sb.c
> index cd12f83..a1dd039 100644
> --- a/db/sb.c
> +++ b/db/sb.c
> @@ -29,6 +29,8 @@
>  #include "output.h"
>  #include "init.h"
>  
...
> @@ -388,6 +405,17 @@ uuid_f(
>  			memcpy(&uu, uup, sizeof(uuid_t));
>  			platform_uuid_unparse(&uu, bp);
>  			dbprintf(_("old UUID = %s\n"), bp);
> +		} else if (!strcasecmp(argv[1], "restore")) {
> +			xfs_sb_t	tsb;
> +
> +			if (!get_sb(0, &tsb))
> +				return 0;
> +
> +			/* Not set; nothing to do.  Success! */
> +			if (!xfs_sb_version_hasmetauuid(&tsb))
> +				return 0;
> +		

Trailing whitespace on the line above.

Brian

> +			memcpy(&uu, mp->m_sb.sb_meta_uuid, sizeof(uuid_t));
>  		} else {
>  			if (platform_uuid_parse(argv[1], &uu)) {
>  				dbprintf(_("invalid UUID\n"));
> @@ -660,6 +688,8 @@ version_string(
>  		strcat(s, ",CRC");
>  	if (xfs_sb_version_hasftype(sbp))
>  		strcat(s, ",FTYPE");
> +	if (xfs_sb_version_hasmetauuid(sbp))
> +		strcat(s, ",META_UUID");
>  	return s;
>  }
>  
> diff --git a/libxfs/xfs_alloc.c b/libxfs/xfs_alloc.c
> index 23e3c53..62dce1e 100644
> --- a/libxfs/xfs_alloc.c
> +++ b/libxfs/xfs_alloc.c
> @@ -446,7 +446,7 @@ xfs_agfl_verify(
>  	struct xfs_agfl	*agfl = XFS_BUF_TO_AGFL(bp);
>  	int		i;
>  
> -	if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_uuid))
> +	if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid))
>  		return false;
>  	if (be32_to_cpu(agfl->agfl_magicnum) != XFS_AGFL_MAGIC)
>  		return false;
> @@ -2199,7 +2199,7 @@ 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_uuid))
> +	    !uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  
>  	if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) &&
> diff --git a/libxfs/xfs_alloc_btree.c b/libxfs/xfs_alloc_btree.c
> index 7fd72af..e60538a 100644
> --- a/libxfs/xfs_alloc_btree.c
> +++ b/libxfs/xfs_alloc_btree.c
> @@ -293,7 +293,7 @@ xfs_allocbt_verify(
>  	case cpu_to_be32(XFS_ABTB_CRC_MAGIC):
>  		if (!xfs_sb_version_hascrc(&mp->m_sb))
>  			return false;
> -		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
>  			return false;
> @@ -311,7 +311,7 @@ xfs_allocbt_verify(
>  	case cpu_to_be32(XFS_ABTC_CRC_MAGIC):
>  		if (!xfs_sb_version_hascrc(&mp->m_sb))
>  			return false;
> -		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
>  			return false;
> diff --git a/libxfs/xfs_attr_leaf.c b/libxfs/xfs_attr_leaf.c
> index 200bd30..69b6af3 100644
> --- a/libxfs/xfs_attr_leaf.c
> +++ b/libxfs/xfs_attr_leaf.c
> @@ -258,7 +258,7 @@ xfs_attr3_leaf_verify(
>  		if (ichdr.magic != XFS_ATTR3_LEAF_MAGIC)
>  			return false;
>  
> -		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
>  			return false;
> @@ -1052,7 +1052,7 @@ xfs_attr3_leaf_create(
>  
>  		hdr3->blkno = cpu_to_be64(bp->b_bn);
>  		hdr3->owner = cpu_to_be64(dp->i_ino);
> -		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
> +		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
>  
>  		ichdr.freemap[0].base = sizeof(struct xfs_attr3_leaf_hdr);
>  	} else {
> diff --git a/libxfs/xfs_attr_remote.c b/libxfs/xfs_attr_remote.c
> index 4f492c1..5feaf55 100644
> --- a/libxfs/xfs_attr_remote.c
> +++ b/libxfs/xfs_attr_remote.c
> @@ -95,7 +95,7 @@ xfs_attr3_rmt_verify(
>  		return false;
>  	if (rmt->rm_magic != cpu_to_be32(XFS_ATTR3_RMT_MAGIC))
>  		return false;
> -	if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_uuid))
> +	if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid))
>  		return false;
>  	if (be64_to_cpu(rmt->rm_blkno) != bno)
>  		return false;
> @@ -212,7 +212,7 @@ xfs_attr3_rmt_hdr_set(
>  	rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC);
>  	rmt->rm_offset = cpu_to_be32(offset);
>  	rmt->rm_bytes = cpu_to_be32(size);
> -	uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_uuid);
> +	uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid);
>  	rmt->rm_owner = cpu_to_be64(ino);
>  	rmt->rm_blkno = cpu_to_be64(bno);
>  
> diff --git a/libxfs/xfs_bmap_btree.c b/libxfs/xfs_bmap_btree.c
> index 2fd04e0..f42bc2d 100644
> --- a/libxfs/xfs_bmap_btree.c
> +++ b/libxfs/xfs_bmap_btree.c
> @@ -346,7 +346,8 @@ xfs_bmbt_to_bmdr(
>  
>  	if (xfs_sb_version_hascrc(&mp->m_sb)) {
>  		ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_CRC_MAGIC));
> -		ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid));
> +		ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid,
> +		       &mp->m_sb.sb_meta_uuid));
>  		ASSERT(rblock->bb_u.l.bb_blkno ==
>  		       cpu_to_be64(XFS_BUF_DADDR_NULL));
>  	} else
> @@ -644,7 +645,7 @@ xfs_bmbt_verify(
>  	case cpu_to_be32(XFS_BMAP_CRC_MAGIC):
>  		if (!xfs_sb_version_hascrc(&mp->m_sb))
>  			return false;
> -		if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (be64_to_cpu(block->bb_u.l.bb_blkno) != bp->b_bn)
>  			return false;
> diff --git a/libxfs/xfs_btree.c b/libxfs/xfs_btree.c
> index 203e7d2..a16ae7d 100644
> --- a/libxfs/xfs_btree.c
> +++ b/libxfs/xfs_btree.c
> @@ -62,7 +62,8 @@ xfs_btree_check_lblock(
>  
>  	if (xfs_sb_version_hascrc(&mp->m_sb)) {
>  		lblock_ok = lblock_ok &&
> -			uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid) &&
> +			uuid_equal(&block->bb_u.l.bb_uuid,
> +				   &mp->m_sb.sb_meta_uuid) &&
>  			block->bb_u.l.bb_blkno == cpu_to_be64(
>  				bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
>  	}
> @@ -112,7 +113,8 @@ xfs_btree_check_sblock(
>  
>  	if (xfs_sb_version_hascrc(&mp->m_sb)) {
>  		sblock_ok = sblock_ok &&
> -			uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid) &&
> +			uuid_equal(&block->bb_u.s.bb_uuid,
> +				   &mp->m_sb.sb_meta_uuid) &&
>  			block->bb_u.s.bb_blkno == cpu_to_be64(
>  				bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
>  	}
> @@ -997,7 +999,7 @@ xfs_btree_init_block_int(
>  		if (flags & XFS_BTREE_CRC_BLOCKS) {
>  			buf->bb_u.l.bb_blkno = cpu_to_be64(blkno);
>  			buf->bb_u.l.bb_owner = cpu_to_be64(owner);
> -			uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid);
> +			uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid);
>  			buf->bb_u.l.bb_pad = 0;
>  			buf->bb_u.l.bb_lsn = 0;
>  		}
> @@ -1010,7 +1012,7 @@ xfs_btree_init_block_int(
>  		if (flags & XFS_BTREE_CRC_BLOCKS) {
>  			buf->bb_u.s.bb_blkno = cpu_to_be64(blkno);
>  			buf->bb_u.s.bb_owner = cpu_to_be32(__owner);
> -			uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid);
> +			uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid);
>  			buf->bb_u.s.bb_lsn = 0;
>  		}
>  	}
> diff --git a/libxfs/xfs_da_btree.c b/libxfs/xfs_da_btree.c
> index 441bef4..3de4cd3 100644
> --- a/libxfs/xfs_da_btree.c
> +++ b/libxfs/xfs_da_btree.c
> @@ -142,7 +142,7 @@ xfs_da3_node_verify(
>  		if (ichdr.magic != XFS_DA3_NODE_MAGIC)
>  			return false;
>  
> -		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
>  			return false;
> @@ -320,7 +320,7 @@ xfs_da3_node_create(
>  		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);
> -		uuid_copy(&hdr3->info.uuid, &mp->m_sb.sb_uuid);
> +		uuid_copy(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid);
>  	} else {
>  		ichdr.magic = XFS_DA_NODE_MAGIC;
>  	}
> diff --git a/libxfs/xfs_dir2_block.c b/libxfs/xfs_dir2_block.c
> index f061a99..489f301 100644
> --- a/libxfs/xfs_dir2_block.c
> +++ b/libxfs/xfs_dir2_block.c
> @@ -64,7 +64,7 @@ xfs_dir3_block_verify(
>  	if (xfs_sb_version_hascrc(&mp->m_sb)) {
>  		if (hdr3->magic != cpu_to_be32(XFS_DIR3_BLOCK_MAGIC))
>  			return false;
> -		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
>  			return false;
> @@ -154,7 +154,7 @@ xfs_dir3_block_init(
>  		hdr3->magic = cpu_to_be32(XFS_DIR3_BLOCK_MAGIC);
>  		hdr3->blkno = cpu_to_be64(bp->b_bn);
>  		hdr3->owner = cpu_to_be64(dp->i_ino);
> -		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
> +		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
>  		return;
>  
>  	}
> diff --git a/libxfs/xfs_dir2_data.c b/libxfs/xfs_dir2_data.c
> index 609c097..c475ba8 100644
> --- a/libxfs/xfs_dir2_data.c
> +++ b/libxfs/xfs_dir2_data.c
> @@ -218,7 +218,7 @@ xfs_dir3_data_verify(
>  	if (xfs_sb_version_hascrc(&mp->m_sb)) {
>  		if (hdr3->magic != cpu_to_be32(XFS_DIR3_DATA_MAGIC))
>  			return false;
> -		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
>  			return false;
> @@ -602,7 +602,7 @@ xfs_dir3_data_init(
>  		hdr3->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC);
>  		hdr3->blkno = cpu_to_be64(bp->b_bn);
>  		hdr3->owner = cpu_to_be64(dp->i_ino);
> -		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
> +		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
>  
>  	} else
>  		hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
> diff --git a/libxfs/xfs_dir2_leaf.c b/libxfs/xfs_dir2_leaf.c
> index c2dba8a..80d03b3 100644
> --- a/libxfs/xfs_dir2_leaf.c
> +++ b/libxfs/xfs_dir2_leaf.c
> @@ -158,7 +158,7 @@ xfs_dir3_leaf_verify(
>  
>  		if (leaf3->info.hdr.magic != cpu_to_be16(magic3))
>  			return false;
> -		if (!uuid_equal(&leaf3->info.uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&leaf3->info.uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn)
>  			return false;
> @@ -308,7 +308,7 @@ xfs_dir3_leaf_init(
>  					 : cpu_to_be16(XFS_DIR3_LEAFN_MAGIC);
>  		leaf3->info.blkno = cpu_to_be64(bp->b_bn);
>  		leaf3->info.owner = cpu_to_be64(owner);
> -		uuid_copy(&leaf3->info.uuid, &mp->m_sb.sb_uuid);
> +		uuid_copy(&leaf3->info.uuid, &mp->m_sb.sb_meta_uuid);
>  	} else {
>  		memset(leaf, 0, sizeof(*leaf));
>  		leaf->hdr.info.magic = cpu_to_be16(type);
> diff --git a/libxfs/xfs_dir2_node.c b/libxfs/xfs_dir2_node.c
> index 3b71e9e..581d648 100644
> --- a/libxfs/xfs_dir2_node.c
> +++ b/libxfs/xfs_dir2_node.c
> @@ -91,7 +91,7 @@ xfs_dir3_free_verify(
>  
>  		if (hdr3->magic != cpu_to_be32(XFS_DIR3_FREE_MAGIC))
>  			return false;
> -		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
>  			return false;
> @@ -224,7 +224,7 @@ xfs_dir3_free_get_buf(
>  
>  		hdr3->hdr.blkno = cpu_to_be64(bp->b_bn);
>  		hdr3->hdr.owner = cpu_to_be64(dp->i_ino);
> -		uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_uuid);
> +		uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_meta_uuid);
>  	} else
>  		hdr.magic = XFS_DIR2_FREE_MAGIC;
>  	dp->d_ops->free_hdr_to_disk(bp->b_addr, &hdr);
> diff --git a/libxfs/xfs_dquot_buf.c b/libxfs/xfs_dquot_buf.c
> index 2e0484a..1a2546b 100644
> --- a/libxfs/xfs_dquot_buf.c
> +++ b/libxfs/xfs_dquot_buf.c
> @@ -171,7 +171,7 @@ xfs_dqcheck(
>  	d->dd_diskdq.d_id = cpu_to_be32(id);
>  
>  	if (xfs_sb_version_hascrc(&mp->m_sb)) {
> -		uuid_copy(&d->dd_uuid, &mp->m_sb.sb_uuid);
> +		uuid_copy(&d->dd_uuid, &mp->m_sb.sb_meta_uuid);
>  		xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk),
>  				 XFS_DQUOT_CRC_OFF);
>  	}
> @@ -206,7 +206,7 @@ xfs_dquot_buf_verify_crc(
>  		if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk),
>  				 XFS_DQUOT_CRC_OFF))
>  			return false;
> -		if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  	}
>  	return true;
> diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
> index 4d313d3..c360585 100644
> --- a/libxfs/xfs_format.h
> +++ b/libxfs/xfs_format.h
> @@ -100,7 +100,7 @@ typedef struct xfs_sb {
>  	xfs_rfsblock_t	sb_dblocks;	/* number of data blocks */
>  	xfs_rfsblock_t	sb_rblocks;	/* number of realtime blocks */
>  	xfs_rtblock_t	sb_rextents;	/* number of realtime extents */
> -	uuid_t		sb_uuid;	/* file system unique id */
> +	uuid_t		sb_uuid;	/* user-visible file system unique id */
>  	xfs_fsblock_t	sb_logstart;	/* starting block of log if internal */
>  	xfs_ino_t	sb_rootino;	/* root inode number */
>  	xfs_ino_t	sb_rbmino;	/* bitmap inode for realtime extents */
> @@ -174,6 +174,7 @@ typedef struct xfs_sb {
>  
>  	xfs_ino_t	sb_pquotino;	/* project quota inode */
>  	xfs_lsn_t	sb_lsn;		/* last write sequence */
> +	uuid_t		sb_meta_uuid;	/* metadata file system unique id */
>  
>  	/* must be padded to 64 bit alignment */
>  } xfs_sb_t;
> @@ -190,7 +191,7 @@ typedef struct xfs_dsb {
>  	__be64		sb_dblocks;	/* number of data blocks */
>  	__be64		sb_rblocks;	/* number of realtime blocks */
>  	__be64		sb_rextents;	/* number of realtime extents */
> -	uuid_t		sb_uuid;	/* file system unique id */
> +	uuid_t		sb_uuid;	/* user-visible file system unique id */
>  	__be64		sb_logstart;	/* starting block of log if internal */
>  	__be64		sb_rootino;	/* root inode number */
>  	__be64		sb_rbmino;	/* bitmap inode for realtime extents */
> @@ -260,6 +261,7 @@ typedef struct xfs_dsb {
>  
>  	__be64		sb_pquotino;	/* project quota inode */
>  	__be64		sb_lsn;		/* last write sequence */
> +	uuid_t		sb_meta_uuid;	/* metadata file system unique id */
>  
>  	/* must be padded to 64 bit alignment */
>  } xfs_dsb_t;
> @@ -457,8 +459,10 @@ xfs_sb_has_ro_compat_feature(
>  }
>  
>  #define XFS_SB_FEAT_INCOMPAT_FTYPE	(1 << 0)	/* filetype in dirent */
> +#define XFS_SB_FEAT_INCOMPAT_META_UUID	(1 << 1)	/* metadata UUID */
>  #define XFS_SB_FEAT_INCOMPAT_ALL \
> -		(XFS_SB_FEAT_INCOMPAT_FTYPE)
> +		(XFS_SB_FEAT_INCOMPAT_FTYPE | \
> +		 XFS_SB_FEAT_INCOMPAT_META_UUID)
>  
>  #define XFS_SB_FEAT_INCOMPAT_UNKNOWN	~XFS_SB_FEAT_INCOMPAT_ALL
>  static inline bool
> @@ -507,6 +511,18 @@ static inline int xfs_sb_version_hasfinobt(xfs_sb_t *sbp)
>  }
>  
>  /*
> + * XFS_SB_FEAT_INCOMPAT_META_UUID indicates that the metadata UUID
> + * is stored separately from the user-visible UUID; this allows the
> + * user-visible UUID to be changed on V5 filesystems which have a
> + * filesystem UUID stamped into every piece of metadata.
> + */
> +static inline int xfs_sb_version_hasmetauuid(xfs_sb_t *sbp)
> +{
> +	return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) &&
> +		(sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID);
> +}
> +
> +/*
>   * end of superblock version macros
>   */
>  
> diff --git a/libxfs/xfs_ialloc.c b/libxfs/xfs_ialloc.c
> index 2b4e4e0..71af28e 100644
> --- a/libxfs/xfs_ialloc.c
> +++ b/libxfs/xfs_ialloc.c
> @@ -302,7 +302,8 @@ xfs_ialloc_inode_init(
>  			if (version == 3) {
>  				free->di_ino = cpu_to_be64(ino);
>  				ino++;
> -				uuid_copy(&free->di_uuid, &mp->m_sb.sb_uuid);
> +				uuid_copy(&free->di_uuid,
> +					  &mp->m_sb.sb_meta_uuid);
>  				xfs_dinode_calc_crc(mp, free);
>  			} else if (tp) {
>  				/* just log the inode core */
> @@ -2044,7 +2045,7 @@ xfs_agi_verify(
>  	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_uuid))
> +	    !uuid_equal(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  	/*
>  	 * Validate the magic number of the agi block.
> diff --git a/libxfs/xfs_ialloc_btree.c b/libxfs/xfs_ialloc_btree.c
> index 9ac143a..e8ec5e7 100644
> --- a/libxfs/xfs_ialloc_btree.c
> +++ b/libxfs/xfs_ialloc_btree.c
> @@ -229,7 +229,7 @@ xfs_inobt_verify(
>  	case cpu_to_be32(XFS_FIBT_CRC_MAGIC):
>  		if (!xfs_sb_version_hascrc(&mp->m_sb))
>  			return false;
> -		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
>  			return false;
> diff --git a/libxfs/xfs_inode_buf.c b/libxfs/xfs_inode_buf.c
> index fd48f04..3f20303 100644
> --- a/libxfs/xfs_inode_buf.c
> +++ b/libxfs/xfs_inode_buf.c
> @@ -304,7 +304,7 @@ xfs_dinode_verify(
>  		return false;
>  	if (be64_to_cpu(dip->di_ino) != ino)
>  		return false;
> -	if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_uuid))
> +	if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_meta_uuid))
>  		return false;
>  	return true;
>  }
> @@ -366,7 +366,7 @@ xfs_iread(
>  		if (xfs_sb_version_hascrc(&mp->m_sb)) {
>  			ip->i_d.di_version = 3;
>  			ip->i_d.di_ino = ip->i_ino;
> -			uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
> +			uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid);
>  		} else
>  			ip->i_d.di_version = 2;
>  		return 0;
> diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c
> index 6844cd8..b3c5de9 100644
> --- a/libxfs/xfs_sb.c
> +++ b/libxfs/xfs_sb.c
> @@ -360,6 +360,17 @@ __xfs_sb_from_disk(
>  	to->sb_pad = 0;
>  	to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
>  	to->sb_lsn = be64_to_cpu(from->sb_lsn);
> +	/*
> +	 * sb_meta_uuid is only on disk if it differs from sb_uuid and the
> +	 * feature flag is set; if not set we keep it only in memory.
> +	 */
> +	if (xfs_sb_version_hasmetauuid(to)) {
> +		memcpy(&to->sb_meta_uuid, &from->sb_meta_uuid,
> +					sizeof(to->sb_meta_uuid));
> +	} else {
> +		memcpy(&to->sb_meta_uuid, &from->sb_uuid,
> +					sizeof(to->sb_meta_uuid));
> +	}
>  	/* Convert on-disk flags to in-memory flags? */
>  	if (convert_xquota)
>  		xfs_sb_quota_from_disk(to);
> @@ -501,6 +512,10 @@ xfs_sb_to_disk(
>  				cpu_to_be32(from->sb_features_log_incompat);
>  		to->sb_pad = 0;
>  		to->sb_lsn = cpu_to_be64(from->sb_lsn);
> +		if (xfs_sb_version_hasmetauuid(from)) {
> +			memcpy(&to->sb_meta_uuid, &from->sb_meta_uuid,
> +						sizeof(to->sb_meta_uuid));
> +		}
>  	}
>  }
>  
> diff --git a/libxfs/xfs_symlink_remote.c b/libxfs/xfs_symlink_remote.c
> index 6bc5af5..7d46d9e 100644
> --- a/libxfs/xfs_symlink_remote.c
> +++ b/libxfs/xfs_symlink_remote.c
> @@ -60,7 +60,7 @@ xfs_symlink_hdr_set(
>  	dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC);
>  	dsl->sl_offset = cpu_to_be32(offset);
>  	dsl->sl_bytes = cpu_to_be32(size);
> -	uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_uuid);
> +	uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid);
>  	dsl->sl_owner = cpu_to_be64(ino);
>  	dsl->sl_blkno = cpu_to_be64(bp->b_bn);
>  	bp->b_ops = &xfs_symlink_buf_ops;
> @@ -104,7 +104,7 @@ xfs_symlink_verify(
>  		return false;
>  	if (dsl->sl_magic != cpu_to_be32(XFS_SYMLINK_MAGIC))
>  		return false;
> -	if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_uuid))
> +	if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid))
>  		return false;
>  	if (bp->b_bn != be64_to_cpu(dsl->sl_blkno))
>  		return false;
> diff --git a/libxlog/util.c b/libxlog/util.c
> index 053cf04..fd1011f 100644
> --- a/libxlog/util.c
> +++ b/libxlog/util.c
> @@ -29,8 +29,10 @@ header_check_uuid(xfs_mount_t *mp, xlog_rec_header_t *head)
>  {
>      char uu_log[64], uu_sb[64];
>  
> -    if (print_skip_uuid) return 0;
> -    if (!platform_uuid_compare(&mp->m_sb.sb_uuid, &head->h_fs_uuid)) return 0;
> +    if (print_skip_uuid)
> +		return 0;
> +    if (!platform_uuid_compare(&mp->m_sb.sb_uuid, &head->h_fs_uuid))
> +		return 0;
>  
>      platform_uuid_unparse(&mp->m_sb.sb_uuid, uu_sb);
>      platform_uuid_unparse(&head->h_fs_uuid, uu_log);
> diff --git a/man/man8/xfs_admin.8 b/man/man8/xfs_admin.8
> index b393d74..c17b35e 100644
> --- a/man/man8/xfs_admin.8
> +++ b/man/man8/xfs_admin.8
> @@ -98,7 +98,12 @@ The
>  .I uuid
>  may also be
>  .BR generate ,
> -which will generate a new UUID for the filesystem.
> +which will generate a new UUID for the filesystem.  Note that on CRC-enabled
> +filesystems, this will set an incompatible flag such that older kernels will
> +not be able to mount the filesystem.  To remove this incompatible flag, use
> +.BR restore ,
> +which will restore the original UUID and remove the incompatible
> +feature flag as needed.
>  .TP
>  .B \-V
>  Prints the version number and exits.
> diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
> index d527230..df54bb7 100644
> --- a/man/man8/xfs_db.8
> +++ b/man/man8/xfs_db.8
> @@ -664,7 +664,7 @@ The possible data types are:
>  .BR sb ", " symlink " and " text .
>  See the TYPES section below for more information on these data types.
>  .TP
> -.BI "uuid [" uuid " | " generate " | " rewrite ]
> +.BI "uuid [" uuid " | " generate " | " rewrite " | " restore ]
>  Set the filesystem universally unique identifier (UUID).
>  The filesystem UUID can be used by
>  .BR mount (8)
> @@ -675,7 +675,12 @@ can be set directly to the desired UUID, or it can
>  be automatically generated using the
>  .B generate
>  option. These options will both write the UUID into every copy of the
> -superblock in the filesystem.
> +superblock in the filesystem.  On a CRC-enabled filesystem, this will
> +set an incompatible superblock flag, and the filesystem will not be
> +mountable with older kernels.  This can be reverted with the
> +.B restore
> +option, which will copy the original UUID back into place and clear
> +the incompatible flag as needed.
>  .B rewrite
>  copies the current UUID from the primary superblock
>  to all secondary copies of the superblock.
> diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
> index 1770666..cb9f7f5 100644
> --- a/mkfs/xfs_mkfs.c
> +++ b/mkfs/xfs_mkfs.c
> @@ -2598,6 +2598,8 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
>  	sbp->sb_rextents = rtextents;
>  	platform_uuid_generate(&uuid);
>  	platform_uuid_copy(&sbp->sb_uuid, &uuid);
> +	/* Only in memory; libxfs expects this as if read from disk */
> +	platform_uuid_copy(&sbp->sb_meta_uuid, &uuid);
>  	sbp->sb_logstart = logstart;
>  	sbp->sb_rootino = sbp->sb_rbmino = sbp->sb_rsumino = NULLFSINO;
>  	sbp->sb_rextsize = rtextblocks;
> diff --git a/repair/agheader.c b/repair/agheader.c
> index 9ae2deb..cfca529 100644
> --- a/repair/agheader.c
> +++ b/repair/agheader.c
> @@ -112,7 +112,7 @@ verify_set_agf(xfs_mount_t *mp, xfs_agf_t *agf, xfs_agnumber_t i)
>  	if (!xfs_sb_version_hascrc(&mp->m_sb))
>  		return retval;
>  
> -	if (platform_uuid_compare(&agf->agf_uuid, &mp->m_sb.sb_uuid)) {
> +	if (platform_uuid_compare(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid)) {
>  		char uu[64];
>  
>  		retval = XR_AG_AGF;
> @@ -120,7 +120,8 @@ verify_set_agf(xfs_mount_t *mp, xfs_agf_t *agf, xfs_agnumber_t i)
>  		do_warn(_("bad uuid %s for agf %d\n"), uu, i);
>  
>  		if (!no_modify)
> -			platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_uuid);
> +			platform_uuid_copy(&agf->agf_uuid,
> +					   &mp->m_sb.sb_meta_uuid);
>  	}
>  	return retval;
>  }
> @@ -190,7 +191,7 @@ verify_set_agi(xfs_mount_t *mp, xfs_agi_t *agi, xfs_agnumber_t agno)
>  	if (!xfs_sb_version_hascrc(&mp->m_sb))
>  		return retval;
>  
> -	if (platform_uuid_compare(&agi->agi_uuid, &mp->m_sb.sb_uuid)) {
> +	if (platform_uuid_compare(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid)) {
>  		char uu[64];
>  
>  		retval = XR_AG_AGI;
> @@ -198,7 +199,8 @@ verify_set_agi(xfs_mount_t *mp, xfs_agi_t *agi, xfs_agnumber_t agno)
>  		do_warn(_("bad uuid %s for agi %d\n"), uu, agno);
>  
>  		if (!no_modify)
> -			platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid);
> +			platform_uuid_copy(&agi->agi_uuid,
> +					   &mp->m_sb.sb_meta_uuid);
>  	}
>  
>  	return retval;
> @@ -245,7 +247,7 @@ compare_sb(xfs_mount_t *mp, xfs_sb_t *sb)
>   * superblocks, not just the secondary superblocks.
>   */
>  static int
> -secondary_sb_wack(
> +secondary_sb_whack(
>  	struct xfs_mount *mp,
>  	struct xfs_buf	*sbuf,
>  	struct xfs_sb	*sb,
> @@ -267,7 +269,10 @@ secondary_sb_wack(
>  	 *
>  	 * size is the size of data which is valid for this sb.
>  	 */
> -	if (xfs_sb_version_hascrc(sb))
> +	if (xfs_sb_version_hasmetauuid(sb))
> +		size = offsetof(xfs_sb_t, sb_meta_uuid)
> +			+ sizeof(sb->sb_meta_uuid);
> +	else if (xfs_sb_version_hascrc(sb))
>  		size = offsetof(xfs_sb_t, sb_lsn)
>  			+ sizeof(sb->sb_lsn);
>  	else if (xfs_sb_version_hasmorebits(sb))
> @@ -511,7 +516,7 @@ verify_set_agheader(xfs_mount_t *mp, xfs_buf_t *sbuf, xfs_sb_t *sb,
>  		rval |= XR_AG_SB;
>  	}
>  
> -	rval |= secondary_sb_wack(mp, sbuf, sb, i);
> +	rval |= secondary_sb_whack(mp, sbuf, sb, i);
>  
>  	rval |= verify_set_agf(mp, agf, i);
>  	rval |= verify_set_agi(mp, agi, i);
> diff --git a/repair/agheader.h b/repair/agheader.h
> index 5541fb9..6b2974c 100644
> --- a/repair/agheader.h
> +++ b/repair/agheader.h
> @@ -24,7 +24,6 @@ typedef struct fs_geometry  {
>  	xfs_rfsblock_t	sb_dblocks;	/* # data blocks */
>  	xfs_rfsblock_t	sb_rblocks;	/* # realtime blocks */
>  	xfs_rtblock_t	sb_rextents;	/* # realtime extents */
> -	uuid_t		sb_uuid;	/* fs uuid */
>  	xfs_fsblock_t	sb_logstart;	/* starting log block # */
>  	xfs_agblock_t	sb_rextsize;	/* realtime extent size (blocks )*/
>  	xfs_agblock_t	sb_agblocks;	/* # of blocks per ag */
> diff --git a/repair/dinode.c b/repair/dinode.c
> index 179203e..0ea5a9e 100644
> --- a/repair/dinode.c
> +++ b/repair/dinode.c
> @@ -207,9 +207,9 @@ clear_dinode_core(struct xfs_mount *mp, xfs_dinode_t *dinoc, xfs_ino_t ino_num)
>  		dinoc->di_ino = cpu_to_be64(ino_num);
>  	}
>  
> -	if (platform_uuid_compare(&dinoc->di_uuid, &mp->m_sb.sb_uuid)) {
> +	if (platform_uuid_compare(&dinoc->di_uuid, &mp->m_sb.sb_meta_uuid)) {
>  		__dirty_no_modify_ret(dirty);
> -		platform_uuid_copy(&dinoc->di_uuid, &mp->m_sb.sb_uuid);
> +		platform_uuid_copy(&dinoc->di_uuid, &mp->m_sb.sb_meta_uuid);
>  	}
>  
>  	for (i = 0; i < sizeof(dinoc->di_pad2)/sizeof(dinoc->di_pad2[0]); i++) {
> @@ -2287,7 +2287,8 @@ _("inode identifier %llu mismatch on inode %" PRIu64 "\n"),
>  				return 1;
>  			goto clear_bad_out;
>  		}
> -		if (platform_uuid_compare(&dino->di_uuid, &mp->m_sb.sb_uuid)) {
> +		if (platform_uuid_compare(&dino->di_uuid,
> +					  &mp->m_sb.sb_meta_uuid)) {
>  			if (!uncertain)
>  				do_warn(
>  			_("UUID mismatch on inode %" PRIu64 "\n"), lino);
> diff --git a/repair/phase5.c b/repair/phase5.c
> index 1ce57a1..d40b71d 100644
> --- a/repair/phase5.c
> +++ b/repair/phase5.c
> @@ -1119,7 +1119,7 @@ build_agi(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *btree_curs,
>  		agi->agi_unlinked[i] = cpu_to_be32(NULLAGINO);
>  
>  	if (xfs_sb_version_hascrc(&mp->m_sb))
> -		platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid);
> +		platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid);
>  
>  	if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
>  		agi->agi_free_root = cpu_to_be32(finobt_curs->root);
> @@ -1360,7 +1360,7 @@ build_agf_agfl(xfs_mount_t	*mp,
>  #endif
>  
>  	if (xfs_sb_version_hascrc(&mp->m_sb))
> -		platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_uuid);
> +		platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid);
>  
>  	/* initialise the AGFL, then fill it if there are blocks left over. */
>  	agfl_buf = libxfs_getbuf(mp->m_dev,
> @@ -1374,7 +1374,7 @@ build_agf_agfl(xfs_mount_t	*mp,
>  	if (xfs_sb_version_hascrc(&mp->m_sb)) {
>  		agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC);
>  		agfl->agfl_seqno = cpu_to_be32(agno);
> -		platform_uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_uuid);
> +		platform_uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid);
>  		for (i = 0; i < XFS_AGFL_SIZE(mp); i++)
>  			agfl->agfl_bno[i] = cpu_to_be32(NULLAGBLOCK);
>  	}
> diff --git a/repair/phase6.c b/repair/phase6.c
> index 7902be9..5148693 100644
> --- a/repair/phase6.c
> +++ b/repair/phase6.c
> @@ -527,7 +527,7 @@ mk_rbmino(xfs_mount_t *mp)
>  		ip->i_d.di_flags2 = 0;
>  		ip->i_d.di_ino = mp->m_sb.sb_rbmino;
>  		memset(&(ip->i_d.di_pad2[0]), 0, sizeof(ip->i_d.di_pad2));
> -		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
> +		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid);
>  		times |= XFS_ICHGTIME_CREATE;
>  	}
>  	libxfs_trans_ichgtime(tp, ip, times);
> @@ -783,7 +783,7 @@ mk_rsumino(xfs_mount_t *mp)
>  		ip->i_d.di_flags2 = 0;
>  		ip->i_d.di_ino = mp->m_sb.sb_rsumino;
>  		memset(&(ip->i_d.di_pad2[0]), 0, sizeof(ip->i_d.di_pad2));
> -		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
> +		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid);
>  		times |= XFS_ICHGTIME_CREATE;
>  	}
>  	libxfs_trans_ichgtime(tp, ip, times);
> @@ -897,7 +897,7 @@ mk_root_dir(xfs_mount_t *mp)
>  		ip->i_d.di_flags2 = 0;
>  		ip->i_d.di_ino = mp->m_sb.sb_rootino;
>  		memset(&(ip->i_d.di_pad2[0]), 0, sizeof(ip->i_d.di_pad2));
> -		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
> +		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid);
>  		times |= XFS_ICHGTIME_CREATE;
>  	}
>  	libxfs_trans_ichgtime(tp, ip, times);
> 
> _______________________________________________
> xfs mailing list
> xfs@oss.sgi.com
> http://oss.sgi.com/mailman/listinfo/xfs

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

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

* Re: [PATCH 2/2] xfsprogs: Add new sb_meta_uuid field, update userspace tools to manipulate it
  2015-05-14 13:39   ` Brian Foster
@ 2015-05-14 16:29     ` Eric Sandeen
  0 siblings, 0 replies; 13+ messages in thread
From: Eric Sandeen @ 2015-05-14 16:29 UTC (permalink / raw)
  To: Brian Foster; +Cc: xfs-oss

On 5/14/15 8:39 AM, Brian Foster wrote:
> On Tue, May 12, 2015 at 02:30:15PM -0500, Eric Sandeen wrote:
>> This adds a new superblock field, sb_meta_uuid.  This allows us to
>> change the use-visible UUID on crc-enabled filesytems from userspace
>> if desired, by copying the existing UUID to the new location for
>> metadata comparisons.  If this is done, an incompat flag must be
>> set to prevent older filesystems from mounting the filesystem, but
>> the original UUID can be restored, and the incompat flag removed,
>> with a new xfs_db / xfs_admin UUID command, "restore."
>>
>> Much of this patch mirrors the kernel patch in simply renaming
>> the field used for metadata uuid comparison; other bits:
>>
>> * Teach xfs_db to print the new meta_uuid field
>> * Allow xfs_db to generate a new UUID for CRC-enabled filesystems
>> * Allow xfs_db to revert to the original UUID and clear the flag
>> * Fix up xfs_copy to work with CRC-enabled filesystems
>> * Update the xfs_admin manpage to show the UUID "restore" command
>>
>> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
>> ---
>>
>> This version makes the UUID "restore" command silent if there
>> is nothing to do.
>>
>> Still open to bike-shedding on the "restore" name.  Maybe "revert?"
>>
> 
> Restore seems fine to me...
> 
>> diff --git a/copy/xfs_copy.c b/copy/xfs_copy.c
>> index 279527c..a58eee5 100644
>> --- a/copy/xfs_copy.c
>> +++ b/copy/xfs_copy.c
>> @@ -466,6 +466,34 @@ write_wbuf(void)
>>  	sighold(SIGCHLD);
>>  }
>>  
>> +void
>> +sb_update_uuid(
>> +	xfs_sb_t	*sb,
>> +	ag_header_t	*ag_hdr,
>> +	thread_args	*tcarg)
>> +{
>> +	/*
>> +	 * If this filesystem has CRCs, the original UUID is stamped into
>> +	 * all metadata.  We need to copy the original UUID into the meta_uuid
>> +	 * slot and set the incompat flag if that hasn't already been done.
>> +	 */
>> +	if (xfs_sb_version_hascrc(sb) && !xfs_sb_version_hasmetauuid(sb)) {
>> +		__be32 feat;
>> +
>> +		feat = be32_to_cpu(ag_hdr->xfs_sb->sb_features_incompat);
>> +		feat |= XFS_SB_FEAT_INCOMPAT_META_UUID;
>> +		ag_hdr->xfs_sb->sb_features_incompat = cpu_to_be32(feat);
>> +		platform_uuid_copy(&ag_hdr->xfs_sb->sb_meta_uuid,
>> +				   &ag_hdr->xfs_sb->sb_uuid);
>> +	}
>> +
>> +	platform_uuid_copy(&ag_hdr->xfs_sb->sb_uuid, &tcarg->uuid);
>> +
>> +	/* We changed the UUID, so update the superblock CRC if needed */
>> +	if (xfs_sb_version_hascrc(sb))
>> +		xfs_update_cksum((char *)&ag_hdr->xfs_sb, sb->sb_sectsize,
>> +							 XFS_SB_CRC_OFF);

> xfs_copy doesn't work for me (crc=1,finobt=1)...
> 
> # ./copy/xfs_copy /dev/vdb1 /dev/vdb2 
>  0%  ... 10%  ... 20%  ... 30%  ... 40%  ... 50%  ... 60%  ... 70%  ... 80%  ... 90%  ... 100%
> 
> All copies completed.
> # mount /dev/vdb2 /mnt/
> mount: mount /dev/vdb2 on /mnt failed: Structure needs cleaning
> # dmesg | tail
> ...
> [ 4145.609403] XFS (vdb2): Metadata CRC error detected at xfs_sb_read_verify+0x112/0x170 [xfs], block 0xffffffffffffffff
> [ 4145.611224] XFS (vdb2): Unmount and run xfs_repair
> [ 4145.611945] XFS (vdb2): First 64 bytes of corrupted metadata buffer:
> [ 4145.612873] ffff8800d8def000: 58 46 53 42 00 00 10 00 00 00 00 00 00 25 40 00  XFSB.........%@.
> [ 4145.615047] ffff8800d8def010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
> [ 4145.616359] ffff8800d8def020: 73 68 6d 76 a1 6d 43 96 8f 35 cb 98 2c ff fd 8d  shmv.mC..5..,...
> [ 4145.617926] ffff8800d8def030: 00 00 00 00 00 20 00 05 00 00 00 00 00 00 00 60  ..... .........`
> [ 4145.619267] XFS (vdb2): SB validate failed with error -74.
> 
> The same thing occurs with -d. It looks like the crc might not have
> updated..?

yeargh,

-		xfs_update_cksum((char *)&ag_hdr->xfs_sb, sb->sb_sectsize,
+		xfs_update_cksum((char *)ag_hdr->xfs_sb, sb->sb_sectsize,

will fix up, test harder, and resend :(

-Eric

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

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

* [PATCH 2/2 V4] xfsprogs: Add new sb_meta_uuid field, update userspace tools to manipulate it
  2015-05-12 19:30 ` [PATCH 2/2] xfsprogs: Add new sb_meta_uuid field, update userspace tools to manipulate it Eric Sandeen
  2015-05-14 13:39   ` Brian Foster
@ 2015-05-14 21:54   ` Eric Sandeen
  2015-05-14 23:00     ` [PATCH 2/2 V5] " Eric Sandeen
  1 sibling, 1 reply; 13+ messages in thread
From: Eric Sandeen @ 2015-05-14 21:54 UTC (permalink / raw)
  To: xfs-oss

This adds a new superblock field, sb_meta_uuid.  This allows us to
change the use-visible UUID on crc-enabled filesytems from userspace
if desired, by copying the existing UUID to the new location for
metadata comparisons.  If this is done, an incompat flag must be
set to prevent older filesystems from mounting the filesystem, but
the original UUID can be restored, and the incompat flag removed,
with a new xfs_db / xfs_admin UUID command, "restore."

Much of this patch mirrors the kernel patch in simply renaming
the field used for metadata uuid comparison; other bits:

* Teach xfs_db to print the new meta_uuid field
* Allow xfs_db to generate a new UUID for CRC-enabled filesystems
* Allow xfs_db to revert to the original UUID and clear the flag
* Fix up xfs_copy to work with CRC-enabled filesystems
* Update the xfs_admin manpage to show the UUID "restore" command

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---

This version makes the UUID "restore" command silent if there
is nothing to do.

Also removed an errant "&" in xfs_copy, which was making the
checksum update fail.  :(

And don't set the META_UUID flag in xfs_copy if the UUID we
are writing is the same as the original.

diff --git a/copy/xfs_copy.c b/copy/xfs_copy.c
index 279527c..5cef8d2 100644
--- a/copy/xfs_copy.c
+++ b/copy/xfs_copy.c
@@ -466,6 +466,37 @@ write_wbuf(void)
 	sighold(SIGCHLD);
 }
 
+void
+sb_update_uuid(
+	xfs_sb_t	*sb,
+	ag_header_t	*ag_hdr,
+	thread_args	*tcarg)
+{
+	/*
+	 * If this filesystem has CRCs, the original UUID is stamped into
+	 * all metadata.  If the new UUID is different, We need to copy the
+	 * original UUID into the meta_uuid slot and set the incompat flag
+	 * if that hasn't already been done.
+	 */
+	if (xfs_sb_version_hascrc(sb) &&
+	    platform_uuid_compare(&tcarg->uuid, &ag_hdr->xfs_sb->sb_uuid) &&
+	    !xfs_sb_version_hasmetauuid(sb)) {
+		__be32 feat;
+
+		feat = be32_to_cpu(ag_hdr->xfs_sb->sb_features_incompat);
+		feat |= XFS_SB_FEAT_INCOMPAT_META_UUID;
+		ag_hdr->xfs_sb->sb_features_incompat = cpu_to_be32(feat);
+		platform_uuid_copy(&ag_hdr->xfs_sb->sb_meta_uuid,
+				   &ag_hdr->xfs_sb->sb_uuid);
+	}
+
+	platform_uuid_copy(&ag_hdr->xfs_sb->sb_uuid, &tcarg->uuid);
+
+	/* We might have changed the UUID, so update the superblock CRC */
+	if (xfs_sb_version_hascrc(sb))
+		xfs_update_cksum((char *)ag_hdr->xfs_sb, sb->sb_sectsize,
+							 XFS_SB_CRC_OFF);
+}
 
 int
 main(int argc, char **argv)
@@ -659,16 +690,6 @@ main(int argc, char **argv)
 	sb = &mbuf.m_sb;
 	libxfs_sb_from_disk(sb, XFS_BUF_TO_SBP(sbp));
 
-	/*
-	 * For now, V5 superblock filesystems are not supported without -d;
-	 * we do not have the infrastructure yet to fix CRCs when a new UUID
-	 * is generated.
-	 */
-	if (xfs_sb_version_hascrc(sb) && !duplicate) {
-		do_log(_("%s: Cannot yet copy V5 fs without '-d'\n"), progname);
-		exit(1);
-	}
-
 	mp = libxfs_mount(&mbuf, sb, xargs.ddev, xargs.logdev, xargs.rtdev, 0);
 	if (mp == NULL) {
 		do_log(_("%s: %s filesystem failed to initialize\n"
@@ -1127,8 +1148,7 @@ main(int argc, char **argv)
 			/* do each thread in turn, each has its own UUID */
 
 			for (j = 0, tcarg = targ; j < num_targets; j++)  {
-				platform_uuid_copy(&ag_hdr.xfs_sb->sb_uuid,
-							&tcarg->uuid);
+				sb_update_uuid(sb, &ag_hdr, tcarg);
 				do_write(tcarg);
 				tcarg++;
 			}
diff --git a/db/sb.c b/db/sb.c
index cd12f83..a1dd039 100644
--- a/db/sb.c
+++ b/db/sb.c
@@ -29,6 +29,8 @@
 #include "output.h"
 #include "init.h"
 
+#define uuid_equal(s,d)		(platform_uuid_compare((s),(d)) == 0)
+
 static int	sb_f(int argc, char **argv);
 static void     sb_help(void);
 static int	uuid_f(int argc, char **argv);
@@ -121,6 +123,7 @@ const field_t	sb_flds[] = {
 	{ "crc", FLDT_CRC, OI(OFF(crc)), C1, 0, TYP_NONE },
 	{ "pquotino", FLDT_INO, OI(OFF(pquotino)), C1, 0, TYP_INODE },
 	{ "lsn", FLDT_UINT64X, OI(OFF(lsn)), C1, 0, TYP_NONE },
+	{ "meta_uuid", FLDT_UUID, OI(OFF(meta_uuid)), C1, 0, TYP_NONE },
 	{ NULL }
 };
 
@@ -334,6 +337,32 @@ do_uuid(xfs_agnumber_t agno, uuid_t *uuid)
 		return &uu;
 	}
 	/* set uuid */
+	if (!xfs_sb_version_hascrc(&tsb))
+		goto write;
+	/*
+	 * If we have CRCs, and this UUID differs from that stamped in the
+	 * metadata, set the incompat flag and copy the old one to the
+	 * metadata-specific location.
+	 *
+	 * If we are setting the user-visible UUID back to match the metadata
+	 * UUID, clear the metadata-specific location and the incompat flag.
+	 */
+	if (!xfs_sb_version_hasmetauuid(&tsb) &&
+	    !uuid_equal(uuid, &mp->m_sb.sb_meta_uuid)) {
+		mp->m_sb.sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_META_UUID;
+		tsb.sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_META_UUID;
+		memcpy(&tsb.sb_meta_uuid, &tsb.sb_uuid, sizeof(uuid_t));
+	} else if (xfs_sb_version_hasmetauuid(&tsb) &&
+		   uuid_equal(uuid, &mp->m_sb.sb_meta_uuid)) {
+		memset(&tsb.sb_meta_uuid, 0, sizeof(uuid_t));
+		/* Write those zeros now; it's ignored once we clear the flag */
+		libxfs_sb_to_disk(iocur_top->data, &tsb);
+		mp->m_sb.sb_features_incompat &=
+						~XFS_SB_FEAT_INCOMPAT_META_UUID;
+		tsb.sb_features_incompat &= ~XFS_SB_FEAT_INCOMPAT_META_UUID;
+	}
+
+write:
 	memcpy(&tsb.sb_uuid, uuid, sizeof(uuid_t));
 	libxfs_sb_to_disk(iocur_top->data, &tsb);
 	write_cur();
@@ -363,18 +392,6 @@ uuid_f(
 			return 0;
 		}
 
-		/*
-		 * For now, changing the UUID of V5 superblock filesystems is
-		 * not supported; we do not have the infrastructure to fix all
-		 * other metadata when a new superblock UUID is generated.
-		 */
-		if (xfs_sb_version_hascrc(&mp->m_sb) &&
-		    strcasecmp(argv[1], "rewrite")) {
-			dbprintf(_("%s: only 'rewrite' supported on V5 fs\n"),
-				progname);
-			return 0;
-		}
-
 		if (!strcasecmp(argv[1], "generate")) {
 			platform_uuid_generate(&uu);
 		} else if (!strcasecmp(argv[1], "nil")) {
@@ -388,6 +405,17 @@ uuid_f(
 			memcpy(&uu, uup, sizeof(uuid_t));
 			platform_uuid_unparse(&uu, bp);
 			dbprintf(_("old UUID = %s\n"), bp);
+		} else if (!strcasecmp(argv[1], "restore")) {
+			xfs_sb_t	tsb;
+
+			if (!get_sb(0, &tsb))
+				return 0;
+
+			/* Not set; nothing to do.  Success! */
+			if (!xfs_sb_version_hasmetauuid(&tsb))
+				return 0;
+		
+			memcpy(&uu, mp->m_sb.sb_meta_uuid, sizeof(uuid_t));
 		} else {
 			if (platform_uuid_parse(argv[1], &uu)) {
 				dbprintf(_("invalid UUID\n"));
@@ -660,6 +688,8 @@ version_string(
 		strcat(s, ",CRC");
 	if (xfs_sb_version_hasftype(sbp))
 		strcat(s, ",FTYPE");
+	if (xfs_sb_version_hasmetauuid(sbp))
+		strcat(s, ",META_UUID");
 	return s;
 }
 
diff --git a/libxfs/xfs_alloc.c b/libxfs/xfs_alloc.c
index 23e3c53..62dce1e 100644
--- a/libxfs/xfs_alloc.c
+++ b/libxfs/xfs_alloc.c
@@ -446,7 +446,7 @@ xfs_agfl_verify(
 	struct xfs_agfl	*agfl = XFS_BUF_TO_AGFL(bp);
 	int		i;
 
-	if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_uuid))
+	if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid))
 		return false;
 	if (be32_to_cpu(agfl->agfl_magicnum) != XFS_AGFL_MAGIC)
 		return false;
@@ -2199,7 +2199,7 @@ 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_uuid))
+	    !uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 
 	if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) &&
diff --git a/libxfs/xfs_alloc_btree.c b/libxfs/xfs_alloc_btree.c
index 7fd72af..e60538a 100644
--- a/libxfs/xfs_alloc_btree.c
+++ b/libxfs/xfs_alloc_btree.c
@@ -293,7 +293,7 @@ xfs_allocbt_verify(
 	case cpu_to_be32(XFS_ABTB_CRC_MAGIC):
 		if (!xfs_sb_version_hascrc(&mp->m_sb))
 			return false;
-		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
 			return false;
@@ -311,7 +311,7 @@ xfs_allocbt_verify(
 	case cpu_to_be32(XFS_ABTC_CRC_MAGIC):
 		if (!xfs_sb_version_hascrc(&mp->m_sb))
 			return false;
-		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
 			return false;
diff --git a/libxfs/xfs_attr_leaf.c b/libxfs/xfs_attr_leaf.c
index 200bd30..69b6af3 100644
--- a/libxfs/xfs_attr_leaf.c
+++ b/libxfs/xfs_attr_leaf.c
@@ -258,7 +258,7 @@ xfs_attr3_leaf_verify(
 		if (ichdr.magic != XFS_ATTR3_LEAF_MAGIC)
 			return false;
 
-		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
 			return false;
@@ -1052,7 +1052,7 @@ xfs_attr3_leaf_create(
 
 		hdr3->blkno = cpu_to_be64(bp->b_bn);
 		hdr3->owner = cpu_to_be64(dp->i_ino);
-		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
 
 		ichdr.freemap[0].base = sizeof(struct xfs_attr3_leaf_hdr);
 	} else {
diff --git a/libxfs/xfs_attr_remote.c b/libxfs/xfs_attr_remote.c
index 4f492c1..5feaf55 100644
--- a/libxfs/xfs_attr_remote.c
+++ b/libxfs/xfs_attr_remote.c
@@ -95,7 +95,7 @@ xfs_attr3_rmt_verify(
 		return false;
 	if (rmt->rm_magic != cpu_to_be32(XFS_ATTR3_RMT_MAGIC))
 		return false;
-	if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_uuid))
+	if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid))
 		return false;
 	if (be64_to_cpu(rmt->rm_blkno) != bno)
 		return false;
@@ -212,7 +212,7 @@ xfs_attr3_rmt_hdr_set(
 	rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC);
 	rmt->rm_offset = cpu_to_be32(offset);
 	rmt->rm_bytes = cpu_to_be32(size);
-	uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_uuid);
+	uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid);
 	rmt->rm_owner = cpu_to_be64(ino);
 	rmt->rm_blkno = cpu_to_be64(bno);
 
diff --git a/libxfs/xfs_bmap_btree.c b/libxfs/xfs_bmap_btree.c
index 2fd04e0..f42bc2d 100644
--- a/libxfs/xfs_bmap_btree.c
+++ b/libxfs/xfs_bmap_btree.c
@@ -346,7 +346,8 @@ xfs_bmbt_to_bmdr(
 
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_CRC_MAGIC));
-		ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid));
+		ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid,
+		       &mp->m_sb.sb_meta_uuid));
 		ASSERT(rblock->bb_u.l.bb_blkno ==
 		       cpu_to_be64(XFS_BUF_DADDR_NULL));
 	} else
@@ -644,7 +645,7 @@ xfs_bmbt_verify(
 	case cpu_to_be32(XFS_BMAP_CRC_MAGIC):
 		if (!xfs_sb_version_hascrc(&mp->m_sb))
 			return false;
-		if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(block->bb_u.l.bb_blkno) != bp->b_bn)
 			return false;
diff --git a/libxfs/xfs_btree.c b/libxfs/xfs_btree.c
index 203e7d2..a16ae7d 100644
--- a/libxfs/xfs_btree.c
+++ b/libxfs/xfs_btree.c
@@ -62,7 +62,8 @@ xfs_btree_check_lblock(
 
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		lblock_ok = lblock_ok &&
-			uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid) &&
+			uuid_equal(&block->bb_u.l.bb_uuid,
+				   &mp->m_sb.sb_meta_uuid) &&
 			block->bb_u.l.bb_blkno == cpu_to_be64(
 				bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
 	}
@@ -112,7 +113,8 @@ xfs_btree_check_sblock(
 
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		sblock_ok = sblock_ok &&
-			uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid) &&
+			uuid_equal(&block->bb_u.s.bb_uuid,
+				   &mp->m_sb.sb_meta_uuid) &&
 			block->bb_u.s.bb_blkno == cpu_to_be64(
 				bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
 	}
@@ -997,7 +999,7 @@ xfs_btree_init_block_int(
 		if (flags & XFS_BTREE_CRC_BLOCKS) {
 			buf->bb_u.l.bb_blkno = cpu_to_be64(blkno);
 			buf->bb_u.l.bb_owner = cpu_to_be64(owner);
-			uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid);
+			uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid);
 			buf->bb_u.l.bb_pad = 0;
 			buf->bb_u.l.bb_lsn = 0;
 		}
@@ -1010,7 +1012,7 @@ xfs_btree_init_block_int(
 		if (flags & XFS_BTREE_CRC_BLOCKS) {
 			buf->bb_u.s.bb_blkno = cpu_to_be64(blkno);
 			buf->bb_u.s.bb_owner = cpu_to_be32(__owner);
-			uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid);
+			uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid);
 			buf->bb_u.s.bb_lsn = 0;
 		}
 	}
diff --git a/libxfs/xfs_da_btree.c b/libxfs/xfs_da_btree.c
index 441bef4..3de4cd3 100644
--- a/libxfs/xfs_da_btree.c
+++ b/libxfs/xfs_da_btree.c
@@ -142,7 +142,7 @@ xfs_da3_node_verify(
 		if (ichdr.magic != XFS_DA3_NODE_MAGIC)
 			return false;
 
-		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
 			return false;
@@ -320,7 +320,7 @@ xfs_da3_node_create(
 		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);
-		uuid_copy(&hdr3->info.uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid);
 	} else {
 		ichdr.magic = XFS_DA_NODE_MAGIC;
 	}
diff --git a/libxfs/xfs_dir2_block.c b/libxfs/xfs_dir2_block.c
index f061a99..489f301 100644
--- a/libxfs/xfs_dir2_block.c
+++ b/libxfs/xfs_dir2_block.c
@@ -64,7 +64,7 @@ xfs_dir3_block_verify(
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		if (hdr3->magic != cpu_to_be32(XFS_DIR3_BLOCK_MAGIC))
 			return false;
-		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
 			return false;
@@ -154,7 +154,7 @@ xfs_dir3_block_init(
 		hdr3->magic = cpu_to_be32(XFS_DIR3_BLOCK_MAGIC);
 		hdr3->blkno = cpu_to_be64(bp->b_bn);
 		hdr3->owner = cpu_to_be64(dp->i_ino);
-		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
 		return;
 
 	}
diff --git a/libxfs/xfs_dir2_data.c b/libxfs/xfs_dir2_data.c
index 609c097..c475ba8 100644
--- a/libxfs/xfs_dir2_data.c
+++ b/libxfs/xfs_dir2_data.c
@@ -218,7 +218,7 @@ xfs_dir3_data_verify(
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		if (hdr3->magic != cpu_to_be32(XFS_DIR3_DATA_MAGIC))
 			return false;
-		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
 			return false;
@@ -602,7 +602,7 @@ xfs_dir3_data_init(
 		hdr3->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC);
 		hdr3->blkno = cpu_to_be64(bp->b_bn);
 		hdr3->owner = cpu_to_be64(dp->i_ino);
-		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
 
 	} else
 		hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
diff --git a/libxfs/xfs_dir2_leaf.c b/libxfs/xfs_dir2_leaf.c
index c2dba8a..80d03b3 100644
--- a/libxfs/xfs_dir2_leaf.c
+++ b/libxfs/xfs_dir2_leaf.c
@@ -158,7 +158,7 @@ xfs_dir3_leaf_verify(
 
 		if (leaf3->info.hdr.magic != cpu_to_be16(magic3))
 			return false;
-		if (!uuid_equal(&leaf3->info.uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&leaf3->info.uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn)
 			return false;
@@ -308,7 +308,7 @@ xfs_dir3_leaf_init(
 					 : cpu_to_be16(XFS_DIR3_LEAFN_MAGIC);
 		leaf3->info.blkno = cpu_to_be64(bp->b_bn);
 		leaf3->info.owner = cpu_to_be64(owner);
-		uuid_copy(&leaf3->info.uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&leaf3->info.uuid, &mp->m_sb.sb_meta_uuid);
 	} else {
 		memset(leaf, 0, sizeof(*leaf));
 		leaf->hdr.info.magic = cpu_to_be16(type);
diff --git a/libxfs/xfs_dir2_node.c b/libxfs/xfs_dir2_node.c
index 3b71e9e..581d648 100644
--- a/libxfs/xfs_dir2_node.c
+++ b/libxfs/xfs_dir2_node.c
@@ -91,7 +91,7 @@ xfs_dir3_free_verify(
 
 		if (hdr3->magic != cpu_to_be32(XFS_DIR3_FREE_MAGIC))
 			return false;
-		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
 			return false;
@@ -224,7 +224,7 @@ xfs_dir3_free_get_buf(
 
 		hdr3->hdr.blkno = cpu_to_be64(bp->b_bn);
 		hdr3->hdr.owner = cpu_to_be64(dp->i_ino);
-		uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_meta_uuid);
 	} else
 		hdr.magic = XFS_DIR2_FREE_MAGIC;
 	dp->d_ops->free_hdr_to_disk(bp->b_addr, &hdr);
diff --git a/libxfs/xfs_dquot_buf.c b/libxfs/xfs_dquot_buf.c
index 2e0484a..1a2546b 100644
--- a/libxfs/xfs_dquot_buf.c
+++ b/libxfs/xfs_dquot_buf.c
@@ -171,7 +171,7 @@ xfs_dqcheck(
 	d->dd_diskdq.d_id = cpu_to_be32(id);
 
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
-		uuid_copy(&d->dd_uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&d->dd_uuid, &mp->m_sb.sb_meta_uuid);
 		xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk),
 				 XFS_DQUOT_CRC_OFF);
 	}
@@ -206,7 +206,7 @@ xfs_dquot_buf_verify_crc(
 		if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk),
 				 XFS_DQUOT_CRC_OFF))
 			return false;
-		if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 	}
 	return true;
diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
index 4d313d3..c360585 100644
--- a/libxfs/xfs_format.h
+++ b/libxfs/xfs_format.h
@@ -100,7 +100,7 @@ typedef struct xfs_sb {
 	xfs_rfsblock_t	sb_dblocks;	/* number of data blocks */
 	xfs_rfsblock_t	sb_rblocks;	/* number of realtime blocks */
 	xfs_rtblock_t	sb_rextents;	/* number of realtime extents */
-	uuid_t		sb_uuid;	/* file system unique id */
+	uuid_t		sb_uuid;	/* user-visible file system unique id */
 	xfs_fsblock_t	sb_logstart;	/* starting block of log if internal */
 	xfs_ino_t	sb_rootino;	/* root inode number */
 	xfs_ino_t	sb_rbmino;	/* bitmap inode for realtime extents */
@@ -174,6 +174,7 @@ typedef struct xfs_sb {
 
 	xfs_ino_t	sb_pquotino;	/* project quota inode */
 	xfs_lsn_t	sb_lsn;		/* last write sequence */
+	uuid_t		sb_meta_uuid;	/* metadata file system unique id */
 
 	/* must be padded to 64 bit alignment */
 } xfs_sb_t;
@@ -190,7 +191,7 @@ typedef struct xfs_dsb {
 	__be64		sb_dblocks;	/* number of data blocks */
 	__be64		sb_rblocks;	/* number of realtime blocks */
 	__be64		sb_rextents;	/* number of realtime extents */
-	uuid_t		sb_uuid;	/* file system unique id */
+	uuid_t		sb_uuid;	/* user-visible file system unique id */
 	__be64		sb_logstart;	/* starting block of log if internal */
 	__be64		sb_rootino;	/* root inode number */
 	__be64		sb_rbmino;	/* bitmap inode for realtime extents */
@@ -260,6 +261,7 @@ typedef struct xfs_dsb {
 
 	__be64		sb_pquotino;	/* project quota inode */
 	__be64		sb_lsn;		/* last write sequence */
+	uuid_t		sb_meta_uuid;	/* metadata file system unique id */
 
 	/* must be padded to 64 bit alignment */
 } xfs_dsb_t;
@@ -457,8 +459,10 @@ xfs_sb_has_ro_compat_feature(
 }
 
 #define XFS_SB_FEAT_INCOMPAT_FTYPE	(1 << 0)	/* filetype in dirent */
+#define XFS_SB_FEAT_INCOMPAT_META_UUID	(1 << 1)	/* metadata UUID */
 #define XFS_SB_FEAT_INCOMPAT_ALL \
-		(XFS_SB_FEAT_INCOMPAT_FTYPE)
+		(XFS_SB_FEAT_INCOMPAT_FTYPE | \
+		 XFS_SB_FEAT_INCOMPAT_META_UUID)
 
 #define XFS_SB_FEAT_INCOMPAT_UNKNOWN	~XFS_SB_FEAT_INCOMPAT_ALL
 static inline bool
@@ -507,6 +511,18 @@ static inline int xfs_sb_version_hasfinobt(xfs_sb_t *sbp)
 }
 
 /*
+ * XFS_SB_FEAT_INCOMPAT_META_UUID indicates that the metadata UUID
+ * is stored separately from the user-visible UUID; this allows the
+ * user-visible UUID to be changed on V5 filesystems which have a
+ * filesystem UUID stamped into every piece of metadata.
+ */
+static inline int xfs_sb_version_hasmetauuid(xfs_sb_t *sbp)
+{
+	return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) &&
+		(sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID);
+}
+
+/*
  * end of superblock version macros
  */
 
diff --git a/libxfs/xfs_ialloc.c b/libxfs/xfs_ialloc.c
index 2b4e4e0..71af28e 100644
--- a/libxfs/xfs_ialloc.c
+++ b/libxfs/xfs_ialloc.c
@@ -302,7 +302,8 @@ xfs_ialloc_inode_init(
 			if (version == 3) {
 				free->di_ino = cpu_to_be64(ino);
 				ino++;
-				uuid_copy(&free->di_uuid, &mp->m_sb.sb_uuid);
+				uuid_copy(&free->di_uuid,
+					  &mp->m_sb.sb_meta_uuid);
 				xfs_dinode_calc_crc(mp, free);
 			} else if (tp) {
 				/* just log the inode core */
@@ -2044,7 +2045,7 @@ xfs_agi_verify(
 	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_uuid))
+	    !uuid_equal(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 	/*
 	 * Validate the magic number of the agi block.
diff --git a/libxfs/xfs_ialloc_btree.c b/libxfs/xfs_ialloc_btree.c
index 9ac143a..e8ec5e7 100644
--- a/libxfs/xfs_ialloc_btree.c
+++ b/libxfs/xfs_ialloc_btree.c
@@ -229,7 +229,7 @@ xfs_inobt_verify(
 	case cpu_to_be32(XFS_FIBT_CRC_MAGIC):
 		if (!xfs_sb_version_hascrc(&mp->m_sb))
 			return false;
-		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
 			return false;
diff --git a/libxfs/xfs_inode_buf.c b/libxfs/xfs_inode_buf.c
index fd48f04..3f20303 100644
--- a/libxfs/xfs_inode_buf.c
+++ b/libxfs/xfs_inode_buf.c
@@ -304,7 +304,7 @@ xfs_dinode_verify(
 		return false;
 	if (be64_to_cpu(dip->di_ino) != ino)
 		return false;
-	if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_uuid))
+	if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_meta_uuid))
 		return false;
 	return true;
 }
@@ -366,7 +366,7 @@ xfs_iread(
 		if (xfs_sb_version_hascrc(&mp->m_sb)) {
 			ip->i_d.di_version = 3;
 			ip->i_d.di_ino = ip->i_ino;
-			uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
+			uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid);
 		} else
 			ip->i_d.di_version = 2;
 		return 0;
diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c
index 6844cd8..b3c5de9 100644
--- a/libxfs/xfs_sb.c
+++ b/libxfs/xfs_sb.c
@@ -360,6 +360,17 @@ __xfs_sb_from_disk(
 	to->sb_pad = 0;
 	to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
 	to->sb_lsn = be64_to_cpu(from->sb_lsn);
+	/*
+	 * sb_meta_uuid is only on disk if it differs from sb_uuid and the
+	 * feature flag is set; if not set we keep it only in memory.
+	 */
+	if (xfs_sb_version_hasmetauuid(to)) {
+		memcpy(&to->sb_meta_uuid, &from->sb_meta_uuid,
+					sizeof(to->sb_meta_uuid));
+	} else {
+		memcpy(&to->sb_meta_uuid, &from->sb_uuid,
+					sizeof(to->sb_meta_uuid));
+	}
 	/* Convert on-disk flags to in-memory flags? */
 	if (convert_xquota)
 		xfs_sb_quota_from_disk(to);
@@ -501,6 +512,10 @@ xfs_sb_to_disk(
 				cpu_to_be32(from->sb_features_log_incompat);
 		to->sb_pad = 0;
 		to->sb_lsn = cpu_to_be64(from->sb_lsn);
+		if (xfs_sb_version_hasmetauuid(from)) {
+			memcpy(&to->sb_meta_uuid, &from->sb_meta_uuid,
+						sizeof(to->sb_meta_uuid));
+		}
 	}
 }
 
diff --git a/libxfs/xfs_symlink_remote.c b/libxfs/xfs_symlink_remote.c
index 6bc5af5..7d46d9e 100644
--- a/libxfs/xfs_symlink_remote.c
+++ b/libxfs/xfs_symlink_remote.c
@@ -60,7 +60,7 @@ xfs_symlink_hdr_set(
 	dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC);
 	dsl->sl_offset = cpu_to_be32(offset);
 	dsl->sl_bytes = cpu_to_be32(size);
-	uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_uuid);
+	uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid);
 	dsl->sl_owner = cpu_to_be64(ino);
 	dsl->sl_blkno = cpu_to_be64(bp->b_bn);
 	bp->b_ops = &xfs_symlink_buf_ops;
@@ -104,7 +104,7 @@ xfs_symlink_verify(
 		return false;
 	if (dsl->sl_magic != cpu_to_be32(XFS_SYMLINK_MAGIC))
 		return false;
-	if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_uuid))
+	if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid))
 		return false;
 	if (bp->b_bn != be64_to_cpu(dsl->sl_blkno))
 		return false;
diff --git a/libxlog/util.c b/libxlog/util.c
index 053cf04..fd1011f 100644
--- a/libxlog/util.c
+++ b/libxlog/util.c
@@ -29,8 +29,10 @@ header_check_uuid(xfs_mount_t *mp, xlog_rec_header_t *head)
 {
     char uu_log[64], uu_sb[64];
 
-    if (print_skip_uuid) return 0;
-    if (!platform_uuid_compare(&mp->m_sb.sb_uuid, &head->h_fs_uuid)) return 0;
+    if (print_skip_uuid)
+		return 0;
+    if (!platform_uuid_compare(&mp->m_sb.sb_uuid, &head->h_fs_uuid))
+		return 0;
 
     platform_uuid_unparse(&mp->m_sb.sb_uuid, uu_sb);
     platform_uuid_unparse(&head->h_fs_uuid, uu_log);
diff --git a/man/man8/xfs_admin.8 b/man/man8/xfs_admin.8
index b393d74..c17b35e 100644
--- a/man/man8/xfs_admin.8
+++ b/man/man8/xfs_admin.8
@@ -98,7 +98,12 @@ The
 .I uuid
 may also be
 .BR generate ,
-which will generate a new UUID for the filesystem.
+which will generate a new UUID for the filesystem.  Note that on CRC-enabled
+filesystems, this will set an incompatible flag such that older kernels will
+not be able to mount the filesystem.  To remove this incompatible flag, use
+.BR restore ,
+which will restore the original UUID and remove the incompatible
+feature flag as needed.
 .TP
 .B \-V
 Prints the version number and exits.
diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
index d527230..df54bb7 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -664,7 +664,7 @@ The possible data types are:
 .BR sb ", " symlink " and " text .
 See the TYPES section below for more information on these data types.
 .TP
-.BI "uuid [" uuid " | " generate " | " rewrite ]
+.BI "uuid [" uuid " | " generate " | " rewrite " | " restore ]
 Set the filesystem universally unique identifier (UUID).
 The filesystem UUID can be used by
 .BR mount (8)
@@ -675,7 +675,12 @@ can be set directly to the desired UUID, or it can
 be automatically generated using the
 .B generate
 option. These options will both write the UUID into every copy of the
-superblock in the filesystem.
+superblock in the filesystem.  On a CRC-enabled filesystem, this will
+set an incompatible superblock flag, and the filesystem will not be
+mountable with older kernels.  This can be reverted with the
+.B restore
+option, which will copy the original UUID back into place and clear
+the incompatible flag as needed.
 .B rewrite
 copies the current UUID from the primary superblock
 to all secondary copies of the superblock.
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 1770666..cb9f7f5 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -2598,6 +2598,8 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
 	sbp->sb_rextents = rtextents;
 	platform_uuid_generate(&uuid);
 	platform_uuid_copy(&sbp->sb_uuid, &uuid);
+	/* Only in memory; libxfs expects this as if read from disk */
+	platform_uuid_copy(&sbp->sb_meta_uuid, &uuid);
 	sbp->sb_logstart = logstart;
 	sbp->sb_rootino = sbp->sb_rbmino = sbp->sb_rsumino = NULLFSINO;
 	sbp->sb_rextsize = rtextblocks;
diff --git a/repair/agheader.c b/repair/agheader.c
index 9ae2deb..cfca529 100644
--- a/repair/agheader.c
+++ b/repair/agheader.c
@@ -112,7 +112,7 @@ verify_set_agf(xfs_mount_t *mp, xfs_agf_t *agf, xfs_agnumber_t i)
 	if (!xfs_sb_version_hascrc(&mp->m_sb))
 		return retval;
 
-	if (platform_uuid_compare(&agf->agf_uuid, &mp->m_sb.sb_uuid)) {
+	if (platform_uuid_compare(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid)) {
 		char uu[64];
 
 		retval = XR_AG_AGF;
@@ -120,7 +120,8 @@ verify_set_agf(xfs_mount_t *mp, xfs_agf_t *agf, xfs_agnumber_t i)
 		do_warn(_("bad uuid %s for agf %d\n"), uu, i);
 
 		if (!no_modify)
-			platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_uuid);
+			platform_uuid_copy(&agf->agf_uuid,
+					   &mp->m_sb.sb_meta_uuid);
 	}
 	return retval;
 }
@@ -190,7 +191,7 @@ verify_set_agi(xfs_mount_t *mp, xfs_agi_t *agi, xfs_agnumber_t agno)
 	if (!xfs_sb_version_hascrc(&mp->m_sb))
 		return retval;
 
-	if (platform_uuid_compare(&agi->agi_uuid, &mp->m_sb.sb_uuid)) {
+	if (platform_uuid_compare(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid)) {
 		char uu[64];
 
 		retval = XR_AG_AGI;
@@ -198,7 +199,8 @@ verify_set_agi(xfs_mount_t *mp, xfs_agi_t *agi, xfs_agnumber_t agno)
 		do_warn(_("bad uuid %s for agi %d\n"), uu, agno);
 
 		if (!no_modify)
-			platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid);
+			platform_uuid_copy(&agi->agi_uuid,
+					   &mp->m_sb.sb_meta_uuid);
 	}
 
 	return retval;
@@ -245,7 +247,7 @@ compare_sb(xfs_mount_t *mp, xfs_sb_t *sb)
  * superblocks, not just the secondary superblocks.
  */
 static int
-secondary_sb_wack(
+secondary_sb_whack(
 	struct xfs_mount *mp,
 	struct xfs_buf	*sbuf,
 	struct xfs_sb	*sb,
@@ -267,7 +269,10 @@ secondary_sb_wack(
 	 *
 	 * size is the size of data which is valid for this sb.
 	 */
-	if (xfs_sb_version_hascrc(sb))
+	if (xfs_sb_version_hasmetauuid(sb))
+		size = offsetof(xfs_sb_t, sb_meta_uuid)
+			+ sizeof(sb->sb_meta_uuid);
+	else if (xfs_sb_version_hascrc(sb))
 		size = offsetof(xfs_sb_t, sb_lsn)
 			+ sizeof(sb->sb_lsn);
 	else if (xfs_sb_version_hasmorebits(sb))
@@ -511,7 +516,7 @@ verify_set_agheader(xfs_mount_t *mp, xfs_buf_t *sbuf, xfs_sb_t *sb,
 		rval |= XR_AG_SB;
 	}
 
-	rval |= secondary_sb_wack(mp, sbuf, sb, i);
+	rval |= secondary_sb_whack(mp, sbuf, sb, i);
 
 	rval |= verify_set_agf(mp, agf, i);
 	rval |= verify_set_agi(mp, agi, i);
diff --git a/repair/agheader.h b/repair/agheader.h
index 5541fb9..6b2974c 100644
--- a/repair/agheader.h
+++ b/repair/agheader.h
@@ -24,7 +24,6 @@ typedef struct fs_geometry  {
 	xfs_rfsblock_t	sb_dblocks;	/* # data blocks */
 	xfs_rfsblock_t	sb_rblocks;	/* # realtime blocks */
 	xfs_rtblock_t	sb_rextents;	/* # realtime extents */
-	uuid_t		sb_uuid;	/* fs uuid */
 	xfs_fsblock_t	sb_logstart;	/* starting log block # */
 	xfs_agblock_t	sb_rextsize;	/* realtime extent size (blocks )*/
 	xfs_agblock_t	sb_agblocks;	/* # of blocks per ag */
diff --git a/repair/dinode.c b/repair/dinode.c
index 179203e..0ea5a9e 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -207,9 +207,9 @@ clear_dinode_core(struct xfs_mount *mp, xfs_dinode_t *dinoc, xfs_ino_t ino_num)
 		dinoc->di_ino = cpu_to_be64(ino_num);
 	}
 
-	if (platform_uuid_compare(&dinoc->di_uuid, &mp->m_sb.sb_uuid)) {
+	if (platform_uuid_compare(&dinoc->di_uuid, &mp->m_sb.sb_meta_uuid)) {
 		__dirty_no_modify_ret(dirty);
-		platform_uuid_copy(&dinoc->di_uuid, &mp->m_sb.sb_uuid);
+		platform_uuid_copy(&dinoc->di_uuid, &mp->m_sb.sb_meta_uuid);
 	}
 
 	for (i = 0; i < sizeof(dinoc->di_pad2)/sizeof(dinoc->di_pad2[0]); i++) {
@@ -2287,7 +2287,8 @@ _("inode identifier %llu mismatch on inode %" PRIu64 "\n"),
 				return 1;
 			goto clear_bad_out;
 		}
-		if (platform_uuid_compare(&dino->di_uuid, &mp->m_sb.sb_uuid)) {
+		if (platform_uuid_compare(&dino->di_uuid,
+					  &mp->m_sb.sb_meta_uuid)) {
 			if (!uncertain)
 				do_warn(
 			_("UUID mismatch on inode %" PRIu64 "\n"), lino);
diff --git a/repair/phase5.c b/repair/phase5.c
index 1ce57a1..d40b71d 100644
--- a/repair/phase5.c
+++ b/repair/phase5.c
@@ -1119,7 +1119,7 @@ build_agi(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *btree_curs,
 		agi->agi_unlinked[i] = cpu_to_be32(NULLAGINO);
 
 	if (xfs_sb_version_hascrc(&mp->m_sb))
-		platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid);
+		platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid);
 
 	if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
 		agi->agi_free_root = cpu_to_be32(finobt_curs->root);
@@ -1360,7 +1360,7 @@ build_agf_agfl(xfs_mount_t	*mp,
 #endif
 
 	if (xfs_sb_version_hascrc(&mp->m_sb))
-		platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_uuid);
+		platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid);
 
 	/* initialise the AGFL, then fill it if there are blocks left over. */
 	agfl_buf = libxfs_getbuf(mp->m_dev,
@@ -1374,7 +1374,7 @@ build_agf_agfl(xfs_mount_t	*mp,
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC);
 		agfl->agfl_seqno = cpu_to_be32(agno);
-		platform_uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_uuid);
+		platform_uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid);
 		for (i = 0; i < XFS_AGFL_SIZE(mp); i++)
 			agfl->agfl_bno[i] = cpu_to_be32(NULLAGBLOCK);
 	}
diff --git a/repair/phase6.c b/repair/phase6.c
index 7902be9..5148693 100644
--- a/repair/phase6.c
+++ b/repair/phase6.c
@@ -527,7 +527,7 @@ mk_rbmino(xfs_mount_t *mp)
 		ip->i_d.di_flags2 = 0;
 		ip->i_d.di_ino = mp->m_sb.sb_rbmino;
 		memset(&(ip->i_d.di_pad2[0]), 0, sizeof(ip->i_d.di_pad2));
-		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
+		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid);
 		times |= XFS_ICHGTIME_CREATE;
 	}
 	libxfs_trans_ichgtime(tp, ip, times);
@@ -783,7 +783,7 @@ mk_rsumino(xfs_mount_t *mp)
 		ip->i_d.di_flags2 = 0;
 		ip->i_d.di_ino = mp->m_sb.sb_rsumino;
 		memset(&(ip->i_d.di_pad2[0]), 0, sizeof(ip->i_d.di_pad2));
-		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
+		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid);
 		times |= XFS_ICHGTIME_CREATE;
 	}
 	libxfs_trans_ichgtime(tp, ip, times);
@@ -897,7 +897,7 @@ mk_root_dir(xfs_mount_t *mp)
 		ip->i_d.di_flags2 = 0;
 		ip->i_d.di_ino = mp->m_sb.sb_rootino;
 		memset(&(ip->i_d.di_pad2[0]), 0, sizeof(ip->i_d.di_pad2));
-		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
+		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid);
 		times |= XFS_ICHGTIME_CREATE;
 	}
 	libxfs_trans_ichgtime(tp, ip, times);

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

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

* Re: [PATCH 1/2] xfs: create new metadata UUID field and incompat flag
  2015-05-12 19:27 ` [PATCH 1/2] xfs: create new metadata UUID field and incompat flag Eric Sandeen
  2015-05-14 13:36   ` Brian Foster
@ 2015-05-14 22:36   ` Dave Chinner
  2015-05-14 22:55   ` [PATCH 1/2 V4] " Eric Sandeen
  2 siblings, 0 replies; 13+ messages in thread
From: Dave Chinner @ 2015-05-14 22:36 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: xfs-oss

On Tue, May 12, 2015 at 02:27:51PM -0500, Eric Sandeen wrote:
> This adds a new superblock field, sb_meta_uuid.  If set, along with
> a new incompat flag, the code will use that field on a V5 filesystem
> to compare to metadata UUIDs, which allows us to change the user-
> visible UUID at will.  Userspace handles the setting and clearing
> of the incompat flag as appropriate, as the UUID gets changed; i.e.
> setting the user-visible UUID back to the original UUID (as stored in
> the new field) will remove the incompatible feature flag.
> 
> If the incompat flag is not set, this copies the user-visible UUID into
> into the meta_uuid slot in memory when the superblock is read from disk;
> the meta_uuid field is not written back to disk in this case.
> 
> The remainder of this patch simply switches verifiers, initializers,
> etc to use the new sb_meta_uuid field.
> 
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>

Couple of minor things:
>  
>  /*
> + * XFS_SB_FEAT_INCOMPAT_META_UUID indicates that the metadata UUID
> + * is stored separately from the user-visible UUID; this allows the
> + * user-visible UUID to be changed on V5 filesystems which have a
> + * filesystem UUID stamped into every piece of metadata.
> + */
> +static inline int xfs_sb_version_hasmetauuid(xfs_sb_t *sbp)

bool, struct xfs_sb.

> +++ b/fs/xfs/libxfs/xfs_sb.c
> @@ -377,6 +377,17 @@ __xfs_sb_from_disk(
>  	to->sb_pad = 0;
>  	to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
>  	to->sb_lsn = be64_to_cpu(from->sb_lsn);
> +	/*
> +	 * sb_meta_uuid is only on disk if it differs from sb_uuid and the
> +	 * feature flag is set; if not set we keep it only in memory.
> +	 */
> +	if (xfs_sb_version_hasmetauuid(to)) {
> +		memcpy(&to->sb_meta_uuid, &from->sb_meta_uuid,
> +					sizeof(to->sb_meta_uuid));
> +	} else {
> +		memcpy(&to->sb_meta_uuid, &from->sb_uuid,
> +					sizeof(to->sb_meta_uuid));
> +	}

uuid_copy()

>  	/* Convert on-disk flags to in-memory flags? */
>  	if (convert_xquota)
>  		xfs_sb_quota_from_disk(to);
> @@ -518,6 +529,10 @@ xfs_sb_to_disk(
>  				cpu_to_be32(from->sb_features_log_incompat);
>  		to->sb_pad = 0;
>  		to->sb_lsn = cpu_to_be64(from->sb_lsn);
> +		if (xfs_sb_version_hasmetauuid(from)) {
> +			memcpy(&to->sb_meta_uuid, &from->sb_meta_uuid,
> +						sizeof(to->sb_meta_uuid));
> +		}

uuid_copy() here, too.

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

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

* [PATCH 1/2 V4] xfs: create new metadata UUID field and incompat flag
  2015-05-12 19:27 ` [PATCH 1/2] xfs: create new metadata UUID field and incompat flag Eric Sandeen
  2015-05-14 13:36   ` Brian Foster
  2015-05-14 22:36   ` Dave Chinner
@ 2015-05-14 22:55   ` Eric Sandeen
  2 siblings, 0 replies; 13+ messages in thread
From: Eric Sandeen @ 2015-05-14 22:55 UTC (permalink / raw)
  To: xfs-oss

This adds a new superblock field, sb_meta_uuid.  If set, along with
a new incompat flag, the code will use that field on a V5 filesystem
to compare to metadata UUIDs, which allows us to change the user-
visible UUID at will.  Userspace handles the setting and clearing
of the incompat flag as appropriate, as the UUID gets changed; i.e.
setting the user-visible UUID back to the original UUID (as stored in
the new field) will remove the incompatible feature flag.

If the incompat flag is not set, this copies the user-visible UUID into
into the meta_uuid slot in memory when the superblock is read from disk;
the meta_uuid field is not written back to disk in this case.

The remainder of this patch simply switches verifiers, initializers,
etc to use the new sb_meta_uuid field.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---

diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
index 516162b..27f76ca 100644
--- a/fs/xfs/libxfs/xfs_alloc.c
+++ b/fs/xfs/libxfs/xfs_alloc.c
@@ -450,7 +450,7 @@ xfs_agfl_verify(
 	struct xfs_agfl	*agfl = XFS_BUF_TO_AGFL(bp);
 	int		i;
 
-	if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_uuid))
+	if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid))
 		return false;
 	if (be32_to_cpu(agfl->agfl_magicnum) != XFS_AGFL_MAGIC)
 		return false;
@@ -2203,7 +2203,7 @@ 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_uuid))
+	    !uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 
 	if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) &&
diff --git a/fs/xfs/libxfs/xfs_alloc_btree.c b/fs/xfs/libxfs/xfs_alloc_btree.c
index 59d521c..90de071 100644
--- a/fs/xfs/libxfs/xfs_alloc_btree.c
+++ b/fs/xfs/libxfs/xfs_alloc_btree.c
@@ -295,7 +295,7 @@ xfs_allocbt_verify(
 	case cpu_to_be32(XFS_ABTB_CRC_MAGIC):
 		if (!xfs_sb_version_hascrc(&mp->m_sb))
 			return false;
-		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
 			return false;
@@ -313,7 +313,7 @@ xfs_allocbt_verify(
 	case cpu_to_be32(XFS_ABTC_CRC_MAGIC):
 		if (!xfs_sb_version_hascrc(&mp->m_sb))
 			return false;
-		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
 			return false;
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index 04e79d5..6755762 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -262,7 +262,7 @@ xfs_attr3_leaf_verify(
 		if (ichdr.magic != XFS_ATTR3_LEAF_MAGIC)
 			return false;
 
-		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
 			return false;
@@ -1056,7 +1056,7 @@ xfs_attr3_leaf_create(
 
 		hdr3->blkno = cpu_to_be64(bp->b_bn);
 		hdr3->owner = cpu_to_be64(dp->i_ino);
-		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
 
 		ichdr.freemap[0].base = sizeof(struct xfs_attr3_leaf_hdr);
 	} else {
diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
index 20de88d..eba0d1e 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.c
+++ b/fs/xfs/libxfs/xfs_attr_remote.c
@@ -100,7 +100,7 @@ xfs_attr3_rmt_verify(
 		return false;
 	if (rmt->rm_magic != cpu_to_be32(XFS_ATTR3_RMT_MAGIC))
 		return false;
-	if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_uuid))
+	if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid))
 		return false;
 	if (be64_to_cpu(rmt->rm_blkno) != bno)
 		return false;
@@ -217,7 +217,7 @@ xfs_attr3_rmt_hdr_set(
 	rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC);
 	rmt->rm_offset = cpu_to_be32(offset);
 	rmt->rm_bytes = cpu_to_be32(size);
-	uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_uuid);
+	uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid);
 	rmt->rm_owner = cpu_to_be64(ino);
 	rmt->rm_blkno = cpu_to_be64(bno);
 
diff --git a/fs/xfs/libxfs/xfs_bmap_btree.c b/fs/xfs/libxfs/xfs_bmap_btree.c
index 2c44c8e..6b0cf65 100644
--- a/fs/xfs/libxfs/xfs_bmap_btree.c
+++ b/fs/xfs/libxfs/xfs_bmap_btree.c
@@ -349,7 +349,8 @@ xfs_bmbt_to_bmdr(
 
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_CRC_MAGIC));
-		ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid));
+		ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid,
+		       &mp->m_sb.sb_meta_uuid));
 		ASSERT(rblock->bb_u.l.bb_blkno ==
 		       cpu_to_be64(XFS_BUF_DADDR_NULL));
 	} else
@@ -647,7 +648,7 @@ xfs_bmbt_verify(
 	case cpu_to_be32(XFS_BMAP_CRC_MAGIC):
 		if (!xfs_sb_version_hascrc(&mp->m_sb))
 			return false;
-		if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(block->bb_u.l.bb_blkno) != bp->b_bn)
 			return false;
diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
index c72283d..f7d7ee7 100644
--- a/fs/xfs/libxfs/xfs_btree.c
+++ b/fs/xfs/libxfs/xfs_btree.c
@@ -65,7 +65,8 @@ xfs_btree_check_lblock(
 
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		lblock_ok = lblock_ok &&
-			uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid) &&
+			uuid_equal(&block->bb_u.l.bb_uuid,
+				   &mp->m_sb.sb_meta_uuid) &&
 			block->bb_u.l.bb_blkno == cpu_to_be64(
 				bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
 	}
@@ -115,7 +116,8 @@ xfs_btree_check_sblock(
 
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		sblock_ok = sblock_ok &&
-			uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid) &&
+			uuid_equal(&block->bb_u.s.bb_uuid,
+				   &mp->m_sb.sb_meta_uuid) &&
 			block->bb_u.s.bb_blkno == cpu_to_be64(
 				bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
 	}
@@ -1000,7 +1002,7 @@ xfs_btree_init_block_int(
 		if (flags & XFS_BTREE_CRC_BLOCKS) {
 			buf->bb_u.l.bb_blkno = cpu_to_be64(blkno);
 			buf->bb_u.l.bb_owner = cpu_to_be64(owner);
-			uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid);
+			uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid);
 			buf->bb_u.l.bb_pad = 0;
 			buf->bb_u.l.bb_lsn = 0;
 		}
@@ -1013,7 +1015,7 @@ xfs_btree_init_block_int(
 		if (flags & XFS_BTREE_CRC_BLOCKS) {
 			buf->bb_u.s.bb_blkno = cpu_to_be64(blkno);
 			buf->bb_u.s.bb_owner = cpu_to_be32(__owner);
-			uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid);
+			uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid);
 			buf->bb_u.s.bb_lsn = 0;
 		}
 	}
diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c
index 2385f8c..e9f6709 100644
--- a/fs/xfs/libxfs/xfs_da_btree.c
+++ b/fs/xfs/libxfs/xfs_da_btree.c
@@ -146,7 +146,7 @@ xfs_da3_node_verify(
 		if (ichdr.magic != XFS_DA3_NODE_MAGIC)
 			return false;
 
-		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
 			return false;
@@ -324,7 +324,7 @@ xfs_da3_node_create(
 		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);
-		uuid_copy(&hdr3->info.uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid);
 	} else {
 		ichdr.magic = XFS_DA_NODE_MAGIC;
 	}
diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
index 9354e19..4778d1d 100644
--- a/fs/xfs/libxfs/xfs_dir2_block.c
+++ b/fs/xfs/libxfs/xfs_dir2_block.c
@@ -67,7 +67,7 @@ xfs_dir3_block_verify(
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		if (hdr3->magic != cpu_to_be32(XFS_DIR3_BLOCK_MAGIC))
 			return false;
-		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
 			return false;
@@ -157,7 +157,7 @@ xfs_dir3_block_init(
 		hdr3->magic = cpu_to_be32(XFS_DIR3_BLOCK_MAGIC);
 		hdr3->blkno = cpu_to_be64(bp->b_bn);
 		hdr3->owner = cpu_to_be64(dp->i_ino);
-		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
 		return;
 
 	}
diff --git a/fs/xfs/libxfs/xfs_dir2_data.c b/fs/xfs/libxfs/xfs_dir2_data.c
index de1ea16..6a57fdb 100644
--- a/fs/xfs/libxfs/xfs_dir2_data.c
+++ b/fs/xfs/libxfs/xfs_dir2_data.c
@@ -220,7 +220,7 @@ xfs_dir3_data_verify(
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		if (hdr3->magic != cpu_to_be32(XFS_DIR3_DATA_MAGIC))
 			return false;
-		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
 			return false;
@@ -604,7 +604,7 @@ xfs_dir3_data_init(
 		hdr3->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC);
 		hdr3->blkno = cpu_to_be64(bp->b_bn);
 		hdr3->owner = cpu_to_be64(dp->i_ino);
-		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
 
 	} else
 		hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
index 1061199..f300240 100644
--- a/fs/xfs/libxfs/xfs_dir2_leaf.c
+++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
@@ -160,7 +160,7 @@ xfs_dir3_leaf_verify(
 
 		if (leaf3->info.hdr.magic != cpu_to_be16(magic3))
 			return false;
-		if (!uuid_equal(&leaf3->info.uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&leaf3->info.uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn)
 			return false;
@@ -310,7 +310,7 @@ xfs_dir3_leaf_init(
 					 : cpu_to_be16(XFS_DIR3_LEAFN_MAGIC);
 		leaf3->info.blkno = cpu_to_be64(bp->b_bn);
 		leaf3->info.owner = cpu_to_be64(owner);
-		uuid_copy(&leaf3->info.uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&leaf3->info.uuid, &mp->m_sb.sb_meta_uuid);
 	} else {
 		memset(leaf, 0, sizeof(*leaf));
 		leaf->hdr.info.magic = cpu_to_be16(type);
diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
index 41b80d3..527b733 100644
--- a/fs/xfs/libxfs/xfs_dir2_node.c
+++ b/fs/xfs/libxfs/xfs_dir2_node.c
@@ -93,7 +93,7 @@ xfs_dir3_free_verify(
 
 		if (hdr3->magic != cpu_to_be32(XFS_DIR3_FREE_MAGIC))
 			return false;
-		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
 			return false;
@@ -226,7 +226,7 @@ xfs_dir3_free_get_buf(
 
 		hdr3->hdr.blkno = cpu_to_be64(bp->b_bn);
 		hdr3->hdr.owner = cpu_to_be64(dp->i_ino);
-		uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_meta_uuid);
 	} else
 		hdr.magic = XFS_DIR2_FREE_MAGIC;
 	dp->d_ops->free_hdr_to_disk(bp->b_addr, &hdr);
diff --git a/fs/xfs/libxfs/xfs_dquot_buf.c b/fs/xfs/libxfs/xfs_dquot_buf.c
index 6fbf2d8..5331b7f 100644
--- a/fs/xfs/libxfs/xfs_dquot_buf.c
+++ b/fs/xfs/libxfs/xfs_dquot_buf.c
@@ -163,7 +163,7 @@ xfs_dqcheck(
 	d->dd_diskdq.d_id = cpu_to_be32(id);
 
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
-		uuid_copy(&d->dd_uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&d->dd_uuid, &mp->m_sb.sb_meta_uuid);
 		xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk),
 				 XFS_DQUOT_CRC_OFF);
 	}
@@ -198,7 +198,7 @@ xfs_dquot_buf_verify_crc(
 		if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk),
 				 XFS_DQUOT_CRC_OFF))
 			return false;
-		if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 	}
 	return true;
diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 4daaa66..263e4ae 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -100,7 +100,7 @@ typedef struct xfs_sb {
 	xfs_rfsblock_t	sb_dblocks;	/* number of data blocks */
 	xfs_rfsblock_t	sb_rblocks;	/* number of realtime blocks */
 	xfs_rtblock_t	sb_rextents;	/* number of realtime extents */
-	uuid_t		sb_uuid;	/* file system unique id */
+	uuid_t		sb_uuid;	/* user-visible file system unique id */
 	xfs_fsblock_t	sb_logstart;	/* starting block of log if internal */
 	xfs_ino_t	sb_rootino;	/* root inode number */
 	xfs_ino_t	sb_rbmino;	/* bitmap inode for realtime extents */
@@ -174,6 +174,7 @@ typedef struct xfs_sb {
 
 	xfs_ino_t	sb_pquotino;	/* project quota inode */
 	xfs_lsn_t	sb_lsn;		/* last write sequence */
+	uuid_t		sb_meta_uuid;	/* metadata file system unique id */
 
 	/* must be padded to 64 bit alignment */
 } xfs_sb_t;
@@ -190,7 +191,7 @@ typedef struct xfs_dsb {
 	__be64		sb_dblocks;	/* number of data blocks */
 	__be64		sb_rblocks;	/* number of realtime blocks */
 	__be64		sb_rextents;	/* number of realtime extents */
-	uuid_t		sb_uuid;	/* file system unique id */
+	uuid_t		sb_uuid;	/* user-visible file system unique id */
 	__be64		sb_logstart;	/* starting block of log if internal */
 	__be64		sb_rootino;	/* root inode number */
 	__be64		sb_rbmino;	/* bitmap inode for realtime extents */
@@ -260,6 +261,7 @@ typedef struct xfs_dsb {
 
 	__be64		sb_pquotino;	/* project quota inode */
 	__be64		sb_lsn;		/* last write sequence */
+	uuid_t		sb_meta_uuid;	/* metadata file system unique id */
 
 	/* must be padded to 64 bit alignment */
 } xfs_dsb_t;
@@ -457,8 +459,10 @@ xfs_sb_has_ro_compat_feature(
 }
 
 #define XFS_SB_FEAT_INCOMPAT_FTYPE	(1 << 0)	/* filetype in dirent */
+#define XFS_SB_FEAT_INCOMPAT_META_UUID	(1 << 1)	/* metadata UUID */
 #define XFS_SB_FEAT_INCOMPAT_ALL \
-		(XFS_SB_FEAT_INCOMPAT_FTYPE)
+		(XFS_SB_FEAT_INCOMPAT_FTYPE | \
+		 XFS_SB_FEAT_INCOMPAT_META_UUID)
 
 #define XFS_SB_FEAT_INCOMPAT_UNKNOWN	~XFS_SB_FEAT_INCOMPAT_ALL
 static inline bool
@@ -507,6 +511,18 @@ static inline int xfs_sb_version_hasfinobt(xfs_sb_t *sbp)
 }
 
 /*
+ * XFS_SB_FEAT_INCOMPAT_META_UUID indicates that the metadata UUID
+ * is stored separately from the user-visible UUID; this allows the
+ * user-visible UUID to be changed on V5 filesystems which have a
+ * filesystem UUID stamped into every piece of metadata.
+ */
+static inline bool xfs_sb_version_hasmetauuid(struct xfs_sb *sbp)
+{
+	return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) &&
+		(sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID);
+}
+
+/*
  * end of superblock version macros
  */
 
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index 07349a1..d9b90c0 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -307,7 +307,8 @@ xfs_ialloc_inode_init(
 			if (version == 3) {
 				free->di_ino = cpu_to_be64(ino);
 				ino++;
-				uuid_copy(&free->di_uuid, &mp->m_sb.sb_uuid);
+				uuid_copy(&free->di_uuid,
+					  &mp->m_sb.sb_meta_uuid);
 				xfs_dinode_calc_crc(mp, free);
 			} else if (tp) {
 				/* just log the inode core */
@@ -2049,7 +2050,7 @@ xfs_agi_verify(
 	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_uuid))
+	    !uuid_equal(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 	/*
 	 * Validate the magic number of the agi block.
diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c
index 964c465..0fa2a27 100644
--- a/fs/xfs/libxfs/xfs_ialloc_btree.c
+++ b/fs/xfs/libxfs/xfs_ialloc_btree.c
@@ -230,7 +230,7 @@ xfs_inobt_verify(
 	case cpu_to_be32(XFS_FIBT_CRC_MAGIC):
 		if (!xfs_sb_version_hascrc(&mp->m_sb))
 			return false;
-		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
 			return false;
diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
index 002b6b3..0f9563e 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.c
+++ b/fs/xfs/libxfs/xfs_inode_buf.c
@@ -306,7 +306,7 @@ xfs_dinode_verify(
 		return false;
 	if (be64_to_cpu(dip->di_ino) != ip->i_ino)
 		return false;
-	if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_uuid))
+	if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_meta_uuid))
 		return false;
 	return true;
 }
@@ -368,7 +368,7 @@ xfs_iread(
 		if (xfs_sb_version_hascrc(&mp->m_sb)) {
 			ip->i_d.di_version = 3;
 			ip->i_d.di_ino = ip->i_ino;
-			uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
+			uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid);
 		} else
 			ip->i_d.di_version = 2;
 		return 0;
diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
index dc4bfc5..cfc1c95 100644
--- a/fs/xfs/libxfs/xfs_sb.c
+++ b/fs/xfs/libxfs/xfs_sb.c
@@ -377,6 +377,14 @@ __xfs_sb_from_disk(
 	to->sb_pad = 0;
 	to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
 	to->sb_lsn = be64_to_cpu(from->sb_lsn);
+	/*
+	 * sb_meta_uuid is only on disk if it differs from sb_uuid and the
+	 * feature flag is set; if not set we keep it only in memory.
+	 */
+	if (xfs_sb_version_hasmetauuid(to))
+		uuid_copy(&to->sb_meta_uuid, &from->sb_meta_uuid);
+	else
+		uuid_copy(&to->sb_meta_uuid, &from->sb_uuid);
 	/* Convert on-disk flags to in-memory flags? */
 	if (convert_xquota)
 		xfs_sb_quota_from_disk(to);
@@ -518,6 +526,8 @@ xfs_sb_to_disk(
 				cpu_to_be32(from->sb_features_log_incompat);
 		to->sb_pad = 0;
 		to->sb_lsn = cpu_to_be64(from->sb_lsn);
+		if (xfs_sb_version_hasmetauuid(from))
+			uuid_copy(&to->sb_meta_uuid, &from->sb_meta_uuid);
 	}
 }
 
diff --git a/fs/xfs/libxfs/xfs_symlink_remote.c b/fs/xfs/libxfs/xfs_symlink_remote.c
index e7e26bd..8f8af05 100644
--- a/fs/xfs/libxfs/xfs_symlink_remote.c
+++ b/fs/xfs/libxfs/xfs_symlink_remote.c
@@ -63,7 +63,7 @@ xfs_symlink_hdr_set(
 	dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC);
 	dsl->sl_offset = cpu_to_be32(offset);
 	dsl->sl_bytes = cpu_to_be32(size);
-	uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_uuid);
+	uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid);
 	dsl->sl_owner = cpu_to_be64(ino);
 	dsl->sl_blkno = cpu_to_be64(bp->b_bn);
 	bp->b_ops = &xfs_symlink_buf_ops;
@@ -107,7 +107,7 @@ xfs_symlink_verify(
 		return false;
 	if (dsl->sl_magic != cpu_to_be32(XFS_SYMLINK_MAGIC))
 		return false;
-	if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_uuid))
+	if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid))
 		return false;
 	if (bp->b_bn != be64_to_cpu(dsl->sl_blkno))
 		return false;
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 02c01bb..e0c7e15 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -251,7 +251,7 @@ xfs_qm_init_dquot_blk(
 		d->dd_diskdq.d_id = cpu_to_be32(curid);
 		d->dd_diskdq.d_flags = type;
 		if (xfs_sb_version_hascrc(&mp->m_sb)) {
-			uuid_copy(&d->dd_uuid, &mp->m_sb.sb_uuid);
+			uuid_copy(&d->dd_uuid, &mp->m_sb.sb_meta_uuid);
 			xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk),
 					 XFS_DQUOT_CRC_OFF);
 		}
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index cb7e8a2..9c892cd 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -248,7 +248,7 @@ xfs_growfs_data_private(
 		agf->agf_freeblks = cpu_to_be32(tmpsize);
 		agf->agf_longest = cpu_to_be32(tmpsize);
 		if (xfs_sb_version_hascrc(&mp->m_sb))
-			uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_uuid);
+			uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid);
 
 		error = xfs_bwrite(bp);
 		xfs_buf_relse(bp);
@@ -271,7 +271,7 @@ xfs_growfs_data_private(
 		if (xfs_sb_version_hascrc(&mp->m_sb)) {
 			agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC);
 			agfl->agfl_seqno = cpu_to_be32(agno);
-			uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_uuid);
+			uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid);
 		}
 
 		agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, bp);
@@ -307,7 +307,7 @@ xfs_growfs_data_private(
 		agi->agi_newino = cpu_to_be32(NULLAGINO);
 		agi->agi_dirino = cpu_to_be32(NULLAGINO);
 		if (xfs_sb_version_hascrc(&mp->m_sb))
-			uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid);
+			uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid);
 		if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
 			agi->agi_free_root = cpu_to_be32(XFS_FIBT_BLOCK(mp));
 			agi->agi_free_level = cpu_to_be32(1);
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index d6ebc85..9a2ecb7 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -787,7 +787,7 @@ xfs_ialloc(
 
 	if (ip->i_d.di_version == 3) {
 		ASSERT(ip->i_d.di_ino == ino);
-		ASSERT(uuid_equal(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid));
+		ASSERT(uuid_equal(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid));
 		ip->i_d.di_crc = 0;
 		ip->i_d.di_changecount = 1;
 		ip->i_d.di_lsn = 0;
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 4f5784f..4da291c 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -325,7 +325,7 @@ xlog_header_check_recover(
 		XFS_ERROR_REPORT("xlog_header_check_recover(1)",
 				 XFS_ERRLEVEL_HIGH, mp);
 		return -EFSCORRUPTED;
-	} else if (unlikely(!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid))) {
+	} else if (!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid)) {
 		xfs_warn(mp,
 	"dirty log entry has mismatched uuid - can't recover");
 		xlog_header_check_dump(mp, head);
@@ -353,7 +353,7 @@ xlog_header_check_mount(
 		 * by IRIX and continue.
 		 */
 		xfs_warn(mp, "nil uuid in log - IRIX style log");
-	} else if (unlikely(!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid))) {
+	} else if (!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid)) {
 		xfs_warn(mp, "log has mismatched uuid - can't recover");
 		xlog_header_check_dump(mp, head);
 		XFS_ERROR_REPORT("xlog_header_check_mount",


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

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

* [PATCH 2/2 V5] xfsprogs: Add new sb_meta_uuid field, update userspace tools to manipulate it
  2015-05-14 21:54   ` [PATCH 2/2 V4] " Eric Sandeen
@ 2015-05-14 23:00     ` Eric Sandeen
  2015-05-18 14:35       ` Brian Foster
  0 siblings, 1 reply; 13+ messages in thread
From: Eric Sandeen @ 2015-05-14 23:00 UTC (permalink / raw)
  To: xfs-oss

This adds a new superblock field, sb_meta_uuid.  If set, along with
a new incompat flag, the code will use that field on a V5 filesystem
to compare to metadata UUIDs, which allows us to change the user-
visible UUID at will.  Userspace handles the setting and clearing
of the incompat flag as appropriate, as the UUID gets changed; i.e.
setting the user-visible UUID back to the original UUID (as stored in
the new field) will remove the incompatible feature flag.

If the incompat flag is not set, this copies the user-visible UUID into
into the meta_uuid slot in memory when the superblock is read from disk;
the meta_uuid field is not written back to disk in this case.

The remainder of this patch simply switches verifiers, initializers,
etc to use the new sb_meta_uuid field.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---

V5: bools and structs and xfs_copy()s to match kernelspace...


diff --git a/copy/xfs_copy.c b/copy/xfs_copy.c
index 279527c..5cef8d2 100644
--- a/copy/xfs_copy.c
+++ b/copy/xfs_copy.c
@@ -466,6 +466,37 @@ write_wbuf(void)
 	sighold(SIGCHLD);
 }
 
+void
+sb_update_uuid(
+	xfs_sb_t	*sb,
+	ag_header_t	*ag_hdr,
+	thread_args	*tcarg)
+{
+	/*
+	 * If this filesystem has CRCs, the original UUID is stamped into
+	 * all metadata.  If the new UUID is different, We need to copy the
+	 * original UUID into the meta_uuid slot and set the incompat flag
+	 * if that hasn't already been done.
+	 */
+	if (xfs_sb_version_hascrc(sb) &&
+	    platform_uuid_compare(&tcarg->uuid, &ag_hdr->xfs_sb->sb_uuid) &&
+	    !xfs_sb_version_hasmetauuid(sb)) {
+		__be32 feat;
+
+		feat = be32_to_cpu(ag_hdr->xfs_sb->sb_features_incompat);
+		feat |= XFS_SB_FEAT_INCOMPAT_META_UUID;
+		ag_hdr->xfs_sb->sb_features_incompat = cpu_to_be32(feat);
+		platform_uuid_copy(&ag_hdr->xfs_sb->sb_meta_uuid,
+				   &ag_hdr->xfs_sb->sb_uuid);
+	}
+
+	platform_uuid_copy(&ag_hdr->xfs_sb->sb_uuid, &tcarg->uuid);
+
+	/* We might have changed the UUID, so update the superblock CRC */
+	if (xfs_sb_version_hascrc(sb))
+		xfs_update_cksum((char *)ag_hdr->xfs_sb, sb->sb_sectsize,
+							 XFS_SB_CRC_OFF);
+}
 
 int
 main(int argc, char **argv)
@@ -659,16 +690,6 @@ main(int argc, char **argv)
 	sb = &mbuf.m_sb;
 	libxfs_sb_from_disk(sb, XFS_BUF_TO_SBP(sbp));
 
-	/*
-	 * For now, V5 superblock filesystems are not supported without -d;
-	 * we do not have the infrastructure yet to fix CRCs when a new UUID
-	 * is generated.
-	 */
-	if (xfs_sb_version_hascrc(sb) && !duplicate) {
-		do_log(_("%s: Cannot yet copy V5 fs without '-d'\n"), progname);
-		exit(1);
-	}
-
 	mp = libxfs_mount(&mbuf, sb, xargs.ddev, xargs.logdev, xargs.rtdev, 0);
 	if (mp == NULL) {
 		do_log(_("%s: %s filesystem failed to initialize\n"
@@ -1127,8 +1148,7 @@ main(int argc, char **argv)
 			/* do each thread in turn, each has its own UUID */
 
 			for (j = 0, tcarg = targ; j < num_targets; j++)  {
-				platform_uuid_copy(&ag_hdr.xfs_sb->sb_uuid,
-							&tcarg->uuid);
+				sb_update_uuid(sb, &ag_hdr, tcarg);
 				do_write(tcarg);
 				tcarg++;
 			}
diff --git a/db/sb.c b/db/sb.c
index cd12f83..a1dd039 100644
--- a/db/sb.c
+++ b/db/sb.c
@@ -29,6 +29,8 @@
 #include "output.h"
 #include "init.h"
 
+#define uuid_equal(s,d)		(platform_uuid_compare((s),(d)) == 0)
+
 static int	sb_f(int argc, char **argv);
 static void     sb_help(void);
 static int	uuid_f(int argc, char **argv);
@@ -121,6 +123,7 @@ const field_t	sb_flds[] = {
 	{ "crc", FLDT_CRC, OI(OFF(crc)), C1, 0, TYP_NONE },
 	{ "pquotino", FLDT_INO, OI(OFF(pquotino)), C1, 0, TYP_INODE },
 	{ "lsn", FLDT_UINT64X, OI(OFF(lsn)), C1, 0, TYP_NONE },
+	{ "meta_uuid", FLDT_UUID, OI(OFF(meta_uuid)), C1, 0, TYP_NONE },
 	{ NULL }
 };
 
@@ -334,6 +337,32 @@ do_uuid(xfs_agnumber_t agno, uuid_t *uuid)
 		return &uu;
 	}
 	/* set uuid */
+	if (!xfs_sb_version_hascrc(&tsb))
+		goto write;
+	/*
+	 * If we have CRCs, and this UUID differs from that stamped in the
+	 * metadata, set the incompat flag and copy the old one to the
+	 * metadata-specific location.
+	 *
+	 * If we are setting the user-visible UUID back to match the metadata
+	 * UUID, clear the metadata-specific location and the incompat flag.
+	 */
+	if (!xfs_sb_version_hasmetauuid(&tsb) &&
+	    !uuid_equal(uuid, &mp->m_sb.sb_meta_uuid)) {
+		mp->m_sb.sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_META_UUID;
+		tsb.sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_META_UUID;
+		memcpy(&tsb.sb_meta_uuid, &tsb.sb_uuid, sizeof(uuid_t));
+	} else if (xfs_sb_version_hasmetauuid(&tsb) &&
+		   uuid_equal(uuid, &mp->m_sb.sb_meta_uuid)) {
+		memset(&tsb.sb_meta_uuid, 0, sizeof(uuid_t));
+		/* Write those zeros now; it's ignored once we clear the flag */
+		libxfs_sb_to_disk(iocur_top->data, &tsb);
+		mp->m_sb.sb_features_incompat &=
+						~XFS_SB_FEAT_INCOMPAT_META_UUID;
+		tsb.sb_features_incompat &= ~XFS_SB_FEAT_INCOMPAT_META_UUID;
+	}
+
+write:
 	memcpy(&tsb.sb_uuid, uuid, sizeof(uuid_t));
 	libxfs_sb_to_disk(iocur_top->data, &tsb);
 	write_cur();
@@ -363,18 +392,6 @@ uuid_f(
 			return 0;
 		}
 
-		/*
-		 * For now, changing the UUID of V5 superblock filesystems is
-		 * not supported; we do not have the infrastructure to fix all
-		 * other metadata when a new superblock UUID is generated.
-		 */
-		if (xfs_sb_version_hascrc(&mp->m_sb) &&
-		    strcasecmp(argv[1], "rewrite")) {
-			dbprintf(_("%s: only 'rewrite' supported on V5 fs\n"),
-				progname);
-			return 0;
-		}
-
 		if (!strcasecmp(argv[1], "generate")) {
 			platform_uuid_generate(&uu);
 		} else if (!strcasecmp(argv[1], "nil")) {
@@ -388,6 +405,17 @@ uuid_f(
 			memcpy(&uu, uup, sizeof(uuid_t));
 			platform_uuid_unparse(&uu, bp);
 			dbprintf(_("old UUID = %s\n"), bp);
+		} else if (!strcasecmp(argv[1], "restore")) {
+			xfs_sb_t	tsb;
+
+			if (!get_sb(0, &tsb))
+				return 0;
+
+			/* Not set; nothing to do.  Success! */
+			if (!xfs_sb_version_hasmetauuid(&tsb))
+				return 0;
+		
+			memcpy(&uu, mp->m_sb.sb_meta_uuid, sizeof(uuid_t));
 		} else {
 			if (platform_uuid_parse(argv[1], &uu)) {
 				dbprintf(_("invalid UUID\n"));
@@ -660,6 +688,8 @@ version_string(
 		strcat(s, ",CRC");
 	if (xfs_sb_version_hasftype(sbp))
 		strcat(s, ",FTYPE");
+	if (xfs_sb_version_hasmetauuid(sbp))
+		strcat(s, ",META_UUID");
 	return s;
 }
 
diff --git a/libxfs/xfs_alloc.c b/libxfs/xfs_alloc.c
index 23e3c53..62dce1e 100644
--- a/libxfs/xfs_alloc.c
+++ b/libxfs/xfs_alloc.c
@@ -446,7 +446,7 @@ xfs_agfl_verify(
 	struct xfs_agfl	*agfl = XFS_BUF_TO_AGFL(bp);
 	int		i;
 
-	if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_uuid))
+	if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid))
 		return false;
 	if (be32_to_cpu(agfl->agfl_magicnum) != XFS_AGFL_MAGIC)
 		return false;
@@ -2199,7 +2199,7 @@ 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_uuid))
+	    !uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 
 	if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) &&
diff --git a/libxfs/xfs_alloc_btree.c b/libxfs/xfs_alloc_btree.c
index 7fd72af..e60538a 100644
--- a/libxfs/xfs_alloc_btree.c
+++ b/libxfs/xfs_alloc_btree.c
@@ -293,7 +293,7 @@ xfs_allocbt_verify(
 	case cpu_to_be32(XFS_ABTB_CRC_MAGIC):
 		if (!xfs_sb_version_hascrc(&mp->m_sb))
 			return false;
-		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
 			return false;
@@ -311,7 +311,7 @@ xfs_allocbt_verify(
 	case cpu_to_be32(XFS_ABTC_CRC_MAGIC):
 		if (!xfs_sb_version_hascrc(&mp->m_sb))
 			return false;
-		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
 			return false;
diff --git a/libxfs/xfs_attr_leaf.c b/libxfs/xfs_attr_leaf.c
index 200bd30..69b6af3 100644
--- a/libxfs/xfs_attr_leaf.c
+++ b/libxfs/xfs_attr_leaf.c
@@ -258,7 +258,7 @@ xfs_attr3_leaf_verify(
 		if (ichdr.magic != XFS_ATTR3_LEAF_MAGIC)
 			return false;
 
-		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
 			return false;
@@ -1052,7 +1052,7 @@ xfs_attr3_leaf_create(
 
 		hdr3->blkno = cpu_to_be64(bp->b_bn);
 		hdr3->owner = cpu_to_be64(dp->i_ino);
-		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
 
 		ichdr.freemap[0].base = sizeof(struct xfs_attr3_leaf_hdr);
 	} else {
diff --git a/libxfs/xfs_attr_remote.c b/libxfs/xfs_attr_remote.c
index 4f492c1..5feaf55 100644
--- a/libxfs/xfs_attr_remote.c
+++ b/libxfs/xfs_attr_remote.c
@@ -95,7 +95,7 @@ xfs_attr3_rmt_verify(
 		return false;
 	if (rmt->rm_magic != cpu_to_be32(XFS_ATTR3_RMT_MAGIC))
 		return false;
-	if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_uuid))
+	if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid))
 		return false;
 	if (be64_to_cpu(rmt->rm_blkno) != bno)
 		return false;
@@ -212,7 +212,7 @@ xfs_attr3_rmt_hdr_set(
 	rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC);
 	rmt->rm_offset = cpu_to_be32(offset);
 	rmt->rm_bytes = cpu_to_be32(size);
-	uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_uuid);
+	uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid);
 	rmt->rm_owner = cpu_to_be64(ino);
 	rmt->rm_blkno = cpu_to_be64(bno);
 
diff --git a/libxfs/xfs_bmap_btree.c b/libxfs/xfs_bmap_btree.c
index 2fd04e0..f42bc2d 100644
--- a/libxfs/xfs_bmap_btree.c
+++ b/libxfs/xfs_bmap_btree.c
@@ -346,7 +346,8 @@ xfs_bmbt_to_bmdr(
 
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_CRC_MAGIC));
-		ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid));
+		ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid,
+		       &mp->m_sb.sb_meta_uuid));
 		ASSERT(rblock->bb_u.l.bb_blkno ==
 		       cpu_to_be64(XFS_BUF_DADDR_NULL));
 	} else
@@ -644,7 +645,7 @@ xfs_bmbt_verify(
 	case cpu_to_be32(XFS_BMAP_CRC_MAGIC):
 		if (!xfs_sb_version_hascrc(&mp->m_sb))
 			return false;
-		if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(block->bb_u.l.bb_blkno) != bp->b_bn)
 			return false;
diff --git a/libxfs/xfs_btree.c b/libxfs/xfs_btree.c
index 203e7d2..a16ae7d 100644
--- a/libxfs/xfs_btree.c
+++ b/libxfs/xfs_btree.c
@@ -62,7 +62,8 @@ xfs_btree_check_lblock(
 
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		lblock_ok = lblock_ok &&
-			uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid) &&
+			uuid_equal(&block->bb_u.l.bb_uuid,
+				   &mp->m_sb.sb_meta_uuid) &&
 			block->bb_u.l.bb_blkno == cpu_to_be64(
 				bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
 	}
@@ -112,7 +113,8 @@ xfs_btree_check_sblock(
 
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		sblock_ok = sblock_ok &&
-			uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid) &&
+			uuid_equal(&block->bb_u.s.bb_uuid,
+				   &mp->m_sb.sb_meta_uuid) &&
 			block->bb_u.s.bb_blkno == cpu_to_be64(
 				bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
 	}
@@ -997,7 +999,7 @@ xfs_btree_init_block_int(
 		if (flags & XFS_BTREE_CRC_BLOCKS) {
 			buf->bb_u.l.bb_blkno = cpu_to_be64(blkno);
 			buf->bb_u.l.bb_owner = cpu_to_be64(owner);
-			uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid);
+			uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid);
 			buf->bb_u.l.bb_pad = 0;
 			buf->bb_u.l.bb_lsn = 0;
 		}
@@ -1010,7 +1012,7 @@ xfs_btree_init_block_int(
 		if (flags & XFS_BTREE_CRC_BLOCKS) {
 			buf->bb_u.s.bb_blkno = cpu_to_be64(blkno);
 			buf->bb_u.s.bb_owner = cpu_to_be32(__owner);
-			uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid);
+			uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid);
 			buf->bb_u.s.bb_lsn = 0;
 		}
 	}
diff --git a/libxfs/xfs_da_btree.c b/libxfs/xfs_da_btree.c
index 441bef4..3de4cd3 100644
--- a/libxfs/xfs_da_btree.c
+++ b/libxfs/xfs_da_btree.c
@@ -142,7 +142,7 @@ xfs_da3_node_verify(
 		if (ichdr.magic != XFS_DA3_NODE_MAGIC)
 			return false;
 
-		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
 			return false;
@@ -320,7 +320,7 @@ xfs_da3_node_create(
 		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);
-		uuid_copy(&hdr3->info.uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid);
 	} else {
 		ichdr.magic = XFS_DA_NODE_MAGIC;
 	}
diff --git a/libxfs/xfs_dir2_block.c b/libxfs/xfs_dir2_block.c
index f061a99..489f301 100644
--- a/libxfs/xfs_dir2_block.c
+++ b/libxfs/xfs_dir2_block.c
@@ -64,7 +64,7 @@ xfs_dir3_block_verify(
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		if (hdr3->magic != cpu_to_be32(XFS_DIR3_BLOCK_MAGIC))
 			return false;
-		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
 			return false;
@@ -154,7 +154,7 @@ xfs_dir3_block_init(
 		hdr3->magic = cpu_to_be32(XFS_DIR3_BLOCK_MAGIC);
 		hdr3->blkno = cpu_to_be64(bp->b_bn);
 		hdr3->owner = cpu_to_be64(dp->i_ino);
-		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
 		return;
 
 	}
diff --git a/libxfs/xfs_dir2_data.c b/libxfs/xfs_dir2_data.c
index 609c097..c475ba8 100644
--- a/libxfs/xfs_dir2_data.c
+++ b/libxfs/xfs_dir2_data.c
@@ -218,7 +218,7 @@ xfs_dir3_data_verify(
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		if (hdr3->magic != cpu_to_be32(XFS_DIR3_DATA_MAGIC))
 			return false;
-		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
 			return false;
@@ -602,7 +602,7 @@ xfs_dir3_data_init(
 		hdr3->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC);
 		hdr3->blkno = cpu_to_be64(bp->b_bn);
 		hdr3->owner = cpu_to_be64(dp->i_ino);
-		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
 
 	} else
 		hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
diff --git a/libxfs/xfs_dir2_leaf.c b/libxfs/xfs_dir2_leaf.c
index c2dba8a..80d03b3 100644
--- a/libxfs/xfs_dir2_leaf.c
+++ b/libxfs/xfs_dir2_leaf.c
@@ -158,7 +158,7 @@ xfs_dir3_leaf_verify(
 
 		if (leaf3->info.hdr.magic != cpu_to_be16(magic3))
 			return false;
-		if (!uuid_equal(&leaf3->info.uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&leaf3->info.uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn)
 			return false;
@@ -308,7 +308,7 @@ xfs_dir3_leaf_init(
 					 : cpu_to_be16(XFS_DIR3_LEAFN_MAGIC);
 		leaf3->info.blkno = cpu_to_be64(bp->b_bn);
 		leaf3->info.owner = cpu_to_be64(owner);
-		uuid_copy(&leaf3->info.uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&leaf3->info.uuid, &mp->m_sb.sb_meta_uuid);
 	} else {
 		memset(leaf, 0, sizeof(*leaf));
 		leaf->hdr.info.magic = cpu_to_be16(type);
diff --git a/libxfs/xfs_dir2_node.c b/libxfs/xfs_dir2_node.c
index 3b71e9e..581d648 100644
--- a/libxfs/xfs_dir2_node.c
+++ b/libxfs/xfs_dir2_node.c
@@ -91,7 +91,7 @@ xfs_dir3_free_verify(
 
 		if (hdr3->magic != cpu_to_be32(XFS_DIR3_FREE_MAGIC))
 			return false;
-		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
 			return false;
@@ -224,7 +224,7 @@ xfs_dir3_free_get_buf(
 
 		hdr3->hdr.blkno = cpu_to_be64(bp->b_bn);
 		hdr3->hdr.owner = cpu_to_be64(dp->i_ino);
-		uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_meta_uuid);
 	} else
 		hdr.magic = XFS_DIR2_FREE_MAGIC;
 	dp->d_ops->free_hdr_to_disk(bp->b_addr, &hdr);
diff --git a/libxfs/xfs_dquot_buf.c b/libxfs/xfs_dquot_buf.c
index 2e0484a..1a2546b 100644
--- a/libxfs/xfs_dquot_buf.c
+++ b/libxfs/xfs_dquot_buf.c
@@ -171,7 +171,7 @@ xfs_dqcheck(
 	d->dd_diskdq.d_id = cpu_to_be32(id);
 
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
-		uuid_copy(&d->dd_uuid, &mp->m_sb.sb_uuid);
+		uuid_copy(&d->dd_uuid, &mp->m_sb.sb_meta_uuid);
 		xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk),
 				 XFS_DQUOT_CRC_OFF);
 	}
@@ -206,7 +206,7 @@ xfs_dquot_buf_verify_crc(
 		if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk),
 				 XFS_DQUOT_CRC_OFF))
 			return false;
-		if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 	}
 	return true;
diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
index 4d313d3..12ddcf9 100644
--- a/libxfs/xfs_format.h
+++ b/libxfs/xfs_format.h
@@ -100,7 +100,7 @@ typedef struct xfs_sb {
 	xfs_rfsblock_t	sb_dblocks;	/* number of data blocks */
 	xfs_rfsblock_t	sb_rblocks;	/* number of realtime blocks */
 	xfs_rtblock_t	sb_rextents;	/* number of realtime extents */
-	uuid_t		sb_uuid;	/* file system unique id */
+	uuid_t		sb_uuid;	/* user-visible file system unique id */
 	xfs_fsblock_t	sb_logstart;	/* starting block of log if internal */
 	xfs_ino_t	sb_rootino;	/* root inode number */
 	xfs_ino_t	sb_rbmino;	/* bitmap inode for realtime extents */
@@ -174,6 +174,7 @@ typedef struct xfs_sb {
 
 	xfs_ino_t	sb_pquotino;	/* project quota inode */
 	xfs_lsn_t	sb_lsn;		/* last write sequence */
+	uuid_t		sb_meta_uuid;	/* metadata file system unique id */
 
 	/* must be padded to 64 bit alignment */
 } xfs_sb_t;
@@ -190,7 +191,7 @@ typedef struct xfs_dsb {
 	__be64		sb_dblocks;	/* number of data blocks */
 	__be64		sb_rblocks;	/* number of realtime blocks */
 	__be64		sb_rextents;	/* number of realtime extents */
-	uuid_t		sb_uuid;	/* file system unique id */
+	uuid_t		sb_uuid;	/* user-visible file system unique id */
 	__be64		sb_logstart;	/* starting block of log if internal */
 	__be64		sb_rootino;	/* root inode number */
 	__be64		sb_rbmino;	/* bitmap inode for realtime extents */
@@ -260,6 +261,7 @@ typedef struct xfs_dsb {
 
 	__be64		sb_pquotino;	/* project quota inode */
 	__be64		sb_lsn;		/* last write sequence */
+	uuid_t		sb_meta_uuid;	/* metadata file system unique id */
 
 	/* must be padded to 64 bit alignment */
 } xfs_dsb_t;
@@ -457,8 +459,10 @@ xfs_sb_has_ro_compat_feature(
 }
 
 #define XFS_SB_FEAT_INCOMPAT_FTYPE	(1 << 0)	/* filetype in dirent */
+#define XFS_SB_FEAT_INCOMPAT_META_UUID	(1 << 1)	/* metadata UUID */
 #define XFS_SB_FEAT_INCOMPAT_ALL \
-		(XFS_SB_FEAT_INCOMPAT_FTYPE)
+		(XFS_SB_FEAT_INCOMPAT_FTYPE | \
+		 XFS_SB_FEAT_INCOMPAT_META_UUID)
 
 #define XFS_SB_FEAT_INCOMPAT_UNKNOWN	~XFS_SB_FEAT_INCOMPAT_ALL
 static inline bool
@@ -507,6 +511,18 @@ static inline int xfs_sb_version_hasfinobt(xfs_sb_t *sbp)
 }
 
 /*
+ * XFS_SB_FEAT_INCOMPAT_META_UUID indicates that the metadata UUID
+ * is stored separately from the user-visible UUID; this allows the
+ * user-visible UUID to be changed on V5 filesystems which have a
+ * filesystem UUID stamped into every piece of metadata.
+ */
+static inline bool xfs_sb_version_hasmetauuid(struct xfs_sb *sbp)
+{
+	return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) &&
+		(sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID);
+}
+
+/*
  * end of superblock version macros
  */
 
diff --git a/libxfs/xfs_ialloc.c b/libxfs/xfs_ialloc.c
index 2b4e4e0..71af28e 100644
--- a/libxfs/xfs_ialloc.c
+++ b/libxfs/xfs_ialloc.c
@@ -302,7 +302,8 @@ xfs_ialloc_inode_init(
 			if (version == 3) {
 				free->di_ino = cpu_to_be64(ino);
 				ino++;
-				uuid_copy(&free->di_uuid, &mp->m_sb.sb_uuid);
+				uuid_copy(&free->di_uuid,
+					  &mp->m_sb.sb_meta_uuid);
 				xfs_dinode_calc_crc(mp, free);
 			} else if (tp) {
 				/* just log the inode core */
@@ -2044,7 +2045,7 @@ xfs_agi_verify(
 	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_uuid))
+	    !uuid_equal(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 	/*
 	 * Validate the magic number of the agi block.
diff --git a/libxfs/xfs_ialloc_btree.c b/libxfs/xfs_ialloc_btree.c
index 9ac143a..e8ec5e7 100644
--- a/libxfs/xfs_ialloc_btree.c
+++ b/libxfs/xfs_ialloc_btree.c
@@ -229,7 +229,7 @@ xfs_inobt_verify(
 	case cpu_to_be32(XFS_FIBT_CRC_MAGIC):
 		if (!xfs_sb_version_hascrc(&mp->m_sb))
 			return false;
-		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
+		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
 			return false;
 		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
 			return false;
diff --git a/libxfs/xfs_inode_buf.c b/libxfs/xfs_inode_buf.c
index fd48f04..3f20303 100644
--- a/libxfs/xfs_inode_buf.c
+++ b/libxfs/xfs_inode_buf.c
@@ -304,7 +304,7 @@ xfs_dinode_verify(
 		return false;
 	if (be64_to_cpu(dip->di_ino) != ino)
 		return false;
-	if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_uuid))
+	if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_meta_uuid))
 		return false;
 	return true;
 }
@@ -366,7 +366,7 @@ xfs_iread(
 		if (xfs_sb_version_hascrc(&mp->m_sb)) {
 			ip->i_d.di_version = 3;
 			ip->i_d.di_ino = ip->i_ino;
-			uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
+			uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid);
 		} else
 			ip->i_d.di_version = 2;
 		return 0;
diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c
index 6844cd8..0ffc497 100644
--- a/libxfs/xfs_sb.c
+++ b/libxfs/xfs_sb.c
@@ -360,6 +360,14 @@ __xfs_sb_from_disk(
 	to->sb_pad = 0;
 	to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
 	to->sb_lsn = be64_to_cpu(from->sb_lsn);
+	/*
+	 * sb_meta_uuid is only on disk if it differs from sb_uuid and the
+	 * feature flag is set; if not set we keep it only in memory.
+	 */
+	if (xfs_sb_version_hasmetauuid(to))
+		uuid_copy(&to->sb_meta_uuid, &from->sb_meta_uuid);
+	else
+		uuid_copy(&to->sb_meta_uuid, &from->sb_uuid);
 	/* Convert on-disk flags to in-memory flags? */
 	if (convert_xquota)
 		xfs_sb_quota_from_disk(to);
@@ -501,6 +509,8 @@ xfs_sb_to_disk(
 				cpu_to_be32(from->sb_features_log_incompat);
 		to->sb_pad = 0;
 		to->sb_lsn = cpu_to_be64(from->sb_lsn);
+		if (xfs_sb_version_hasmetauuid(from))
+			uuid_copy(&to->sb_meta_uuid, &from->sb_meta_uuid);
 	}
 }
 
diff --git a/libxfs/xfs_symlink_remote.c b/libxfs/xfs_symlink_remote.c
index 6bc5af5..7d46d9e 100644
--- a/libxfs/xfs_symlink_remote.c
+++ b/libxfs/xfs_symlink_remote.c
@@ -60,7 +60,7 @@ xfs_symlink_hdr_set(
 	dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC);
 	dsl->sl_offset = cpu_to_be32(offset);
 	dsl->sl_bytes = cpu_to_be32(size);
-	uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_uuid);
+	uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid);
 	dsl->sl_owner = cpu_to_be64(ino);
 	dsl->sl_blkno = cpu_to_be64(bp->b_bn);
 	bp->b_ops = &xfs_symlink_buf_ops;
@@ -104,7 +104,7 @@ xfs_symlink_verify(
 		return false;
 	if (dsl->sl_magic != cpu_to_be32(XFS_SYMLINK_MAGIC))
 		return false;
-	if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_uuid))
+	if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid))
 		return false;
 	if (bp->b_bn != be64_to_cpu(dsl->sl_blkno))
 		return false;
diff --git a/libxlog/util.c b/libxlog/util.c
index 053cf04..fd1011f 100644
--- a/libxlog/util.c
+++ b/libxlog/util.c
@@ -29,8 +29,10 @@ header_check_uuid(xfs_mount_t *mp, xlog_rec_header_t *head)
 {
     char uu_log[64], uu_sb[64];
 
-    if (print_skip_uuid) return 0;
-    if (!platform_uuid_compare(&mp->m_sb.sb_uuid, &head->h_fs_uuid)) return 0;
+    if (print_skip_uuid)
+		return 0;
+    if (!platform_uuid_compare(&mp->m_sb.sb_uuid, &head->h_fs_uuid))
+		return 0;
 
     platform_uuid_unparse(&mp->m_sb.sb_uuid, uu_sb);
     platform_uuid_unparse(&head->h_fs_uuid, uu_log);
diff --git a/man/man8/xfs_admin.8 b/man/man8/xfs_admin.8
index b393d74..c17b35e 100644
--- a/man/man8/xfs_admin.8
+++ b/man/man8/xfs_admin.8
@@ -98,7 +98,12 @@ The
 .I uuid
 may also be
 .BR generate ,
-which will generate a new UUID for the filesystem.
+which will generate a new UUID for the filesystem.  Note that on CRC-enabled
+filesystems, this will set an incompatible flag such that older kernels will
+not be able to mount the filesystem.  To remove this incompatible flag, use
+.BR restore ,
+which will restore the original UUID and remove the incompatible
+feature flag as needed.
 .TP
 .B \-V
 Prints the version number and exits.
diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
index d527230..df54bb7 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -664,7 +664,7 @@ The possible data types are:
 .BR sb ", " symlink " and " text .
 See the TYPES section below for more information on these data types.
 .TP
-.BI "uuid [" uuid " | " generate " | " rewrite ]
+.BI "uuid [" uuid " | " generate " | " rewrite " | " restore ]
 Set the filesystem universally unique identifier (UUID).
 The filesystem UUID can be used by
 .BR mount (8)
@@ -675,7 +675,12 @@ can be set directly to the desired UUID, or it can
 be automatically generated using the
 .B generate
 option. These options will both write the UUID into every copy of the
-superblock in the filesystem.
+superblock in the filesystem.  On a CRC-enabled filesystem, this will
+set an incompatible superblock flag, and the filesystem will not be
+mountable with older kernels.  This can be reverted with the
+.B restore
+option, which will copy the original UUID back into place and clear
+the incompatible flag as needed.
 .B rewrite
 copies the current UUID from the primary superblock
 to all secondary copies of the superblock.
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 1770666..cb9f7f5 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -2598,6 +2598,8 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
 	sbp->sb_rextents = rtextents;
 	platform_uuid_generate(&uuid);
 	platform_uuid_copy(&sbp->sb_uuid, &uuid);
+	/* Only in memory; libxfs expects this as if read from disk */
+	platform_uuid_copy(&sbp->sb_meta_uuid, &uuid);
 	sbp->sb_logstart = logstart;
 	sbp->sb_rootino = sbp->sb_rbmino = sbp->sb_rsumino = NULLFSINO;
 	sbp->sb_rextsize = rtextblocks;
diff --git a/repair/agheader.c b/repair/agheader.c
index 9ae2deb..cfca529 100644
--- a/repair/agheader.c
+++ b/repair/agheader.c
@@ -112,7 +112,7 @@ verify_set_agf(xfs_mount_t *mp, xfs_agf_t *agf, xfs_agnumber_t i)
 	if (!xfs_sb_version_hascrc(&mp->m_sb))
 		return retval;
 
-	if (platform_uuid_compare(&agf->agf_uuid, &mp->m_sb.sb_uuid)) {
+	if (platform_uuid_compare(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid)) {
 		char uu[64];
 
 		retval = XR_AG_AGF;
@@ -120,7 +120,8 @@ verify_set_agf(xfs_mount_t *mp, xfs_agf_t *agf, xfs_agnumber_t i)
 		do_warn(_("bad uuid %s for agf %d\n"), uu, i);
 
 		if (!no_modify)
-			platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_uuid);
+			platform_uuid_copy(&agf->agf_uuid,
+					   &mp->m_sb.sb_meta_uuid);
 	}
 	return retval;
 }
@@ -190,7 +191,7 @@ verify_set_agi(xfs_mount_t *mp, xfs_agi_t *agi, xfs_agnumber_t agno)
 	if (!xfs_sb_version_hascrc(&mp->m_sb))
 		return retval;
 
-	if (platform_uuid_compare(&agi->agi_uuid, &mp->m_sb.sb_uuid)) {
+	if (platform_uuid_compare(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid)) {
 		char uu[64];
 
 		retval = XR_AG_AGI;
@@ -198,7 +199,8 @@ verify_set_agi(xfs_mount_t *mp, xfs_agi_t *agi, xfs_agnumber_t agno)
 		do_warn(_("bad uuid %s for agi %d\n"), uu, agno);
 
 		if (!no_modify)
-			platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid);
+			platform_uuid_copy(&agi->agi_uuid,
+					   &mp->m_sb.sb_meta_uuid);
 	}
 
 	return retval;
@@ -245,7 +247,7 @@ compare_sb(xfs_mount_t *mp, xfs_sb_t *sb)
  * superblocks, not just the secondary superblocks.
  */
 static int
-secondary_sb_wack(
+secondary_sb_whack(
 	struct xfs_mount *mp,
 	struct xfs_buf	*sbuf,
 	struct xfs_sb	*sb,
@@ -267,7 +269,10 @@ secondary_sb_wack(
 	 *
 	 * size is the size of data which is valid for this sb.
 	 */
-	if (xfs_sb_version_hascrc(sb))
+	if (xfs_sb_version_hasmetauuid(sb))
+		size = offsetof(xfs_sb_t, sb_meta_uuid)
+			+ sizeof(sb->sb_meta_uuid);
+	else if (xfs_sb_version_hascrc(sb))
 		size = offsetof(xfs_sb_t, sb_lsn)
 			+ sizeof(sb->sb_lsn);
 	else if (xfs_sb_version_hasmorebits(sb))
@@ -511,7 +516,7 @@ verify_set_agheader(xfs_mount_t *mp, xfs_buf_t *sbuf, xfs_sb_t *sb,
 		rval |= XR_AG_SB;
 	}
 
-	rval |= secondary_sb_wack(mp, sbuf, sb, i);
+	rval |= secondary_sb_whack(mp, sbuf, sb, i);
 
 	rval |= verify_set_agf(mp, agf, i);
 	rval |= verify_set_agi(mp, agi, i);
diff --git a/repair/agheader.h b/repair/agheader.h
index 5541fb9..6b2974c 100644
--- a/repair/agheader.h
+++ b/repair/agheader.h
@@ -24,7 +24,6 @@ typedef struct fs_geometry  {
 	xfs_rfsblock_t	sb_dblocks;	/* # data blocks */
 	xfs_rfsblock_t	sb_rblocks;	/* # realtime blocks */
 	xfs_rtblock_t	sb_rextents;	/* # realtime extents */
-	uuid_t		sb_uuid;	/* fs uuid */
 	xfs_fsblock_t	sb_logstart;	/* starting log block # */
 	xfs_agblock_t	sb_rextsize;	/* realtime extent size (blocks )*/
 	xfs_agblock_t	sb_agblocks;	/* # of blocks per ag */
diff --git a/repair/dinode.c b/repair/dinode.c
index 179203e..0ea5a9e 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -207,9 +207,9 @@ clear_dinode_core(struct xfs_mount *mp, xfs_dinode_t *dinoc, xfs_ino_t ino_num)
 		dinoc->di_ino = cpu_to_be64(ino_num);
 	}
 
-	if (platform_uuid_compare(&dinoc->di_uuid, &mp->m_sb.sb_uuid)) {
+	if (platform_uuid_compare(&dinoc->di_uuid, &mp->m_sb.sb_meta_uuid)) {
 		__dirty_no_modify_ret(dirty);
-		platform_uuid_copy(&dinoc->di_uuid, &mp->m_sb.sb_uuid);
+		platform_uuid_copy(&dinoc->di_uuid, &mp->m_sb.sb_meta_uuid);
 	}
 
 	for (i = 0; i < sizeof(dinoc->di_pad2)/sizeof(dinoc->di_pad2[0]); i++) {
@@ -2287,7 +2287,8 @@ _("inode identifier %llu mismatch on inode %" PRIu64 "\n"),
 				return 1;
 			goto clear_bad_out;
 		}
-		if (platform_uuid_compare(&dino->di_uuid, &mp->m_sb.sb_uuid)) {
+		if (platform_uuid_compare(&dino->di_uuid,
+					  &mp->m_sb.sb_meta_uuid)) {
 			if (!uncertain)
 				do_warn(
 			_("UUID mismatch on inode %" PRIu64 "\n"), lino);
diff --git a/repair/phase5.c b/repair/phase5.c
index 1ce57a1..d40b71d 100644
--- a/repair/phase5.c
+++ b/repair/phase5.c
@@ -1119,7 +1119,7 @@ build_agi(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *btree_curs,
 		agi->agi_unlinked[i] = cpu_to_be32(NULLAGINO);
 
 	if (xfs_sb_version_hascrc(&mp->m_sb))
-		platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid);
+		platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid);
 
 	if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
 		agi->agi_free_root = cpu_to_be32(finobt_curs->root);
@@ -1360,7 +1360,7 @@ build_agf_agfl(xfs_mount_t	*mp,
 #endif
 
 	if (xfs_sb_version_hascrc(&mp->m_sb))
-		platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_uuid);
+		platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid);
 
 	/* initialise the AGFL, then fill it if there are blocks left over. */
 	agfl_buf = libxfs_getbuf(mp->m_dev,
@@ -1374,7 +1374,7 @@ build_agf_agfl(xfs_mount_t	*mp,
 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
 		agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC);
 		agfl->agfl_seqno = cpu_to_be32(agno);
-		platform_uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_uuid);
+		platform_uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid);
 		for (i = 0; i < XFS_AGFL_SIZE(mp); i++)
 			agfl->agfl_bno[i] = cpu_to_be32(NULLAGBLOCK);
 	}
diff --git a/repair/phase6.c b/repair/phase6.c
index 7902be9..5148693 100644
--- a/repair/phase6.c
+++ b/repair/phase6.c
@@ -527,7 +527,7 @@ mk_rbmino(xfs_mount_t *mp)
 		ip->i_d.di_flags2 = 0;
 		ip->i_d.di_ino = mp->m_sb.sb_rbmino;
 		memset(&(ip->i_d.di_pad2[0]), 0, sizeof(ip->i_d.di_pad2));
-		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
+		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid);
 		times |= XFS_ICHGTIME_CREATE;
 	}
 	libxfs_trans_ichgtime(tp, ip, times);
@@ -783,7 +783,7 @@ mk_rsumino(xfs_mount_t *mp)
 		ip->i_d.di_flags2 = 0;
 		ip->i_d.di_ino = mp->m_sb.sb_rsumino;
 		memset(&(ip->i_d.di_pad2[0]), 0, sizeof(ip->i_d.di_pad2));
-		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
+		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid);
 		times |= XFS_ICHGTIME_CREATE;
 	}
 	libxfs_trans_ichgtime(tp, ip, times);
@@ -897,7 +897,7 @@ mk_root_dir(xfs_mount_t *mp)
 		ip->i_d.di_flags2 = 0;
 		ip->i_d.di_ino = mp->m_sb.sb_rootino;
 		memset(&(ip->i_d.di_pad2[0]), 0, sizeof(ip->i_d.di_pad2));
-		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
+		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid);
 		times |= XFS_ICHGTIME_CREATE;
 	}
 	libxfs_trans_ichgtime(tp, ip, times);

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

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

* Re: [PATCH 2/2 V5] xfsprogs: Add new sb_meta_uuid field, update userspace tools to manipulate it
  2015-05-14 23:00     ` [PATCH 2/2 V5] " Eric Sandeen
@ 2015-05-18 14:35       ` Brian Foster
  0 siblings, 0 replies; 13+ messages in thread
From: Brian Foster @ 2015-05-18 14:35 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: xfs-oss

On Thu, May 14, 2015 at 06:00:51PM -0500, Eric Sandeen wrote:
> This adds a new superblock field, sb_meta_uuid.  If set, along with
> a new incompat flag, the code will use that field on a V5 filesystem
> to compare to metadata UUIDs, which allows us to change the user-
> visible UUID at will.  Userspace handles the setting and clearing
> of the incompat flag as appropriate, as the UUID gets changed; i.e.
> setting the user-visible UUID back to the original UUID (as stored in
> the new field) will remove the incompatible feature flag.
> 
> If the incompat flag is not set, this copies the user-visible UUID into
> into the meta_uuid slot in memory when the superblock is read from disk;
> the meta_uuid field is not written back to disk in this case.
> 
> The remainder of this patch simply switches verifiers, initializers,
> etc to use the new sb_meta_uuid field.
> 
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> ---

Reviewed-by: Brian Foster <bfoster@redhat.com>

> 
> V5: bools and structs and xfs_copy()s to match kernelspace...
> 
> 
> diff --git a/copy/xfs_copy.c b/copy/xfs_copy.c
> index 279527c..5cef8d2 100644
> --- a/copy/xfs_copy.c
> +++ b/copy/xfs_copy.c
> @@ -466,6 +466,37 @@ write_wbuf(void)
>  	sighold(SIGCHLD);
>  }
>  
> +void
> +sb_update_uuid(
> +	xfs_sb_t	*sb,
> +	ag_header_t	*ag_hdr,
> +	thread_args	*tcarg)
> +{
> +	/*
> +	 * If this filesystem has CRCs, the original UUID is stamped into
> +	 * all metadata.  If the new UUID is different, We need to copy the
> +	 * original UUID into the meta_uuid slot and set the incompat flag
> +	 * if that hasn't already been done.
> +	 */
> +	if (xfs_sb_version_hascrc(sb) &&
> +	    platform_uuid_compare(&tcarg->uuid, &ag_hdr->xfs_sb->sb_uuid) &&
> +	    !xfs_sb_version_hasmetauuid(sb)) {
> +		__be32 feat;
> +
> +		feat = be32_to_cpu(ag_hdr->xfs_sb->sb_features_incompat);
> +		feat |= XFS_SB_FEAT_INCOMPAT_META_UUID;
> +		ag_hdr->xfs_sb->sb_features_incompat = cpu_to_be32(feat);
> +		platform_uuid_copy(&ag_hdr->xfs_sb->sb_meta_uuid,
> +				   &ag_hdr->xfs_sb->sb_uuid);
> +	}
> +
> +	platform_uuid_copy(&ag_hdr->xfs_sb->sb_uuid, &tcarg->uuid);
> +
> +	/* We might have changed the UUID, so update the superblock CRC */
> +	if (xfs_sb_version_hascrc(sb))
> +		xfs_update_cksum((char *)ag_hdr->xfs_sb, sb->sb_sectsize,
> +							 XFS_SB_CRC_OFF);
> +}
>  
>  int
>  main(int argc, char **argv)
> @@ -659,16 +690,6 @@ main(int argc, char **argv)
>  	sb = &mbuf.m_sb;
>  	libxfs_sb_from_disk(sb, XFS_BUF_TO_SBP(sbp));
>  
> -	/*
> -	 * For now, V5 superblock filesystems are not supported without -d;
> -	 * we do not have the infrastructure yet to fix CRCs when a new UUID
> -	 * is generated.
> -	 */
> -	if (xfs_sb_version_hascrc(sb) && !duplicate) {
> -		do_log(_("%s: Cannot yet copy V5 fs without '-d'\n"), progname);
> -		exit(1);
> -	}
> -
>  	mp = libxfs_mount(&mbuf, sb, xargs.ddev, xargs.logdev, xargs.rtdev, 0);
>  	if (mp == NULL) {
>  		do_log(_("%s: %s filesystem failed to initialize\n"
> @@ -1127,8 +1148,7 @@ main(int argc, char **argv)
>  			/* do each thread in turn, each has its own UUID */
>  
>  			for (j = 0, tcarg = targ; j < num_targets; j++)  {
> -				platform_uuid_copy(&ag_hdr.xfs_sb->sb_uuid,
> -							&tcarg->uuid);
> +				sb_update_uuid(sb, &ag_hdr, tcarg);
>  				do_write(tcarg);
>  				tcarg++;
>  			}
> diff --git a/db/sb.c b/db/sb.c
> index cd12f83..a1dd039 100644
> --- a/db/sb.c
> +++ b/db/sb.c
> @@ -29,6 +29,8 @@
>  #include "output.h"
>  #include "init.h"
>  
> +#define uuid_equal(s,d)		(platform_uuid_compare((s),(d)) == 0)
> +
>  static int	sb_f(int argc, char **argv);
>  static void     sb_help(void);
>  static int	uuid_f(int argc, char **argv);
> @@ -121,6 +123,7 @@ const field_t	sb_flds[] = {
>  	{ "crc", FLDT_CRC, OI(OFF(crc)), C1, 0, TYP_NONE },
>  	{ "pquotino", FLDT_INO, OI(OFF(pquotino)), C1, 0, TYP_INODE },
>  	{ "lsn", FLDT_UINT64X, OI(OFF(lsn)), C1, 0, TYP_NONE },
> +	{ "meta_uuid", FLDT_UUID, OI(OFF(meta_uuid)), C1, 0, TYP_NONE },
>  	{ NULL }
>  };
>  
> @@ -334,6 +337,32 @@ do_uuid(xfs_agnumber_t agno, uuid_t *uuid)
>  		return &uu;
>  	}
>  	/* set uuid */
> +	if (!xfs_sb_version_hascrc(&tsb))
> +		goto write;
> +	/*
> +	 * If we have CRCs, and this UUID differs from that stamped in the
> +	 * metadata, set the incompat flag and copy the old one to the
> +	 * metadata-specific location.
> +	 *
> +	 * If we are setting the user-visible UUID back to match the metadata
> +	 * UUID, clear the metadata-specific location and the incompat flag.
> +	 */
> +	if (!xfs_sb_version_hasmetauuid(&tsb) &&
> +	    !uuid_equal(uuid, &mp->m_sb.sb_meta_uuid)) {
> +		mp->m_sb.sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_META_UUID;
> +		tsb.sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_META_UUID;
> +		memcpy(&tsb.sb_meta_uuid, &tsb.sb_uuid, sizeof(uuid_t));
> +	} else if (xfs_sb_version_hasmetauuid(&tsb) &&
> +		   uuid_equal(uuid, &mp->m_sb.sb_meta_uuid)) {
> +		memset(&tsb.sb_meta_uuid, 0, sizeof(uuid_t));
> +		/* Write those zeros now; it's ignored once we clear the flag */
> +		libxfs_sb_to_disk(iocur_top->data, &tsb);
> +		mp->m_sb.sb_features_incompat &=
> +						~XFS_SB_FEAT_INCOMPAT_META_UUID;
> +		tsb.sb_features_incompat &= ~XFS_SB_FEAT_INCOMPAT_META_UUID;
> +	}
> +
> +write:
>  	memcpy(&tsb.sb_uuid, uuid, sizeof(uuid_t));
>  	libxfs_sb_to_disk(iocur_top->data, &tsb);
>  	write_cur();
> @@ -363,18 +392,6 @@ uuid_f(
>  			return 0;
>  		}
>  
> -		/*
> -		 * For now, changing the UUID of V5 superblock filesystems is
> -		 * not supported; we do not have the infrastructure to fix all
> -		 * other metadata when a new superblock UUID is generated.
> -		 */
> -		if (xfs_sb_version_hascrc(&mp->m_sb) &&
> -		    strcasecmp(argv[1], "rewrite")) {
> -			dbprintf(_("%s: only 'rewrite' supported on V5 fs\n"),
> -				progname);
> -			return 0;
> -		}
> -
>  		if (!strcasecmp(argv[1], "generate")) {
>  			platform_uuid_generate(&uu);
>  		} else if (!strcasecmp(argv[1], "nil")) {
> @@ -388,6 +405,17 @@ uuid_f(
>  			memcpy(&uu, uup, sizeof(uuid_t));
>  			platform_uuid_unparse(&uu, bp);
>  			dbprintf(_("old UUID = %s\n"), bp);
> +		} else if (!strcasecmp(argv[1], "restore")) {
> +			xfs_sb_t	tsb;
> +
> +			if (!get_sb(0, &tsb))
> +				return 0;
> +
> +			/* Not set; nothing to do.  Success! */
> +			if (!xfs_sb_version_hasmetauuid(&tsb))
> +				return 0;
> +		
> +			memcpy(&uu, mp->m_sb.sb_meta_uuid, sizeof(uuid_t));
>  		} else {
>  			if (platform_uuid_parse(argv[1], &uu)) {
>  				dbprintf(_("invalid UUID\n"));
> @@ -660,6 +688,8 @@ version_string(
>  		strcat(s, ",CRC");
>  	if (xfs_sb_version_hasftype(sbp))
>  		strcat(s, ",FTYPE");
> +	if (xfs_sb_version_hasmetauuid(sbp))
> +		strcat(s, ",META_UUID");
>  	return s;
>  }
>  
> diff --git a/libxfs/xfs_alloc.c b/libxfs/xfs_alloc.c
> index 23e3c53..62dce1e 100644
> --- a/libxfs/xfs_alloc.c
> +++ b/libxfs/xfs_alloc.c
> @@ -446,7 +446,7 @@ xfs_agfl_verify(
>  	struct xfs_agfl	*agfl = XFS_BUF_TO_AGFL(bp);
>  	int		i;
>  
> -	if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_uuid))
> +	if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid))
>  		return false;
>  	if (be32_to_cpu(agfl->agfl_magicnum) != XFS_AGFL_MAGIC)
>  		return false;
> @@ -2199,7 +2199,7 @@ 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_uuid))
> +	    !uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  
>  	if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) &&
> diff --git a/libxfs/xfs_alloc_btree.c b/libxfs/xfs_alloc_btree.c
> index 7fd72af..e60538a 100644
> --- a/libxfs/xfs_alloc_btree.c
> +++ b/libxfs/xfs_alloc_btree.c
> @@ -293,7 +293,7 @@ xfs_allocbt_verify(
>  	case cpu_to_be32(XFS_ABTB_CRC_MAGIC):
>  		if (!xfs_sb_version_hascrc(&mp->m_sb))
>  			return false;
> -		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
>  			return false;
> @@ -311,7 +311,7 @@ xfs_allocbt_verify(
>  	case cpu_to_be32(XFS_ABTC_CRC_MAGIC):
>  		if (!xfs_sb_version_hascrc(&mp->m_sb))
>  			return false;
> -		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
>  			return false;
> diff --git a/libxfs/xfs_attr_leaf.c b/libxfs/xfs_attr_leaf.c
> index 200bd30..69b6af3 100644
> --- a/libxfs/xfs_attr_leaf.c
> +++ b/libxfs/xfs_attr_leaf.c
> @@ -258,7 +258,7 @@ xfs_attr3_leaf_verify(
>  		if (ichdr.magic != XFS_ATTR3_LEAF_MAGIC)
>  			return false;
>  
> -		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
>  			return false;
> @@ -1052,7 +1052,7 @@ xfs_attr3_leaf_create(
>  
>  		hdr3->blkno = cpu_to_be64(bp->b_bn);
>  		hdr3->owner = cpu_to_be64(dp->i_ino);
> -		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
> +		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
>  
>  		ichdr.freemap[0].base = sizeof(struct xfs_attr3_leaf_hdr);
>  	} else {
> diff --git a/libxfs/xfs_attr_remote.c b/libxfs/xfs_attr_remote.c
> index 4f492c1..5feaf55 100644
> --- a/libxfs/xfs_attr_remote.c
> +++ b/libxfs/xfs_attr_remote.c
> @@ -95,7 +95,7 @@ xfs_attr3_rmt_verify(
>  		return false;
>  	if (rmt->rm_magic != cpu_to_be32(XFS_ATTR3_RMT_MAGIC))
>  		return false;
> -	if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_uuid))
> +	if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid))
>  		return false;
>  	if (be64_to_cpu(rmt->rm_blkno) != bno)
>  		return false;
> @@ -212,7 +212,7 @@ xfs_attr3_rmt_hdr_set(
>  	rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC);
>  	rmt->rm_offset = cpu_to_be32(offset);
>  	rmt->rm_bytes = cpu_to_be32(size);
> -	uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_uuid);
> +	uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid);
>  	rmt->rm_owner = cpu_to_be64(ino);
>  	rmt->rm_blkno = cpu_to_be64(bno);
>  
> diff --git a/libxfs/xfs_bmap_btree.c b/libxfs/xfs_bmap_btree.c
> index 2fd04e0..f42bc2d 100644
> --- a/libxfs/xfs_bmap_btree.c
> +++ b/libxfs/xfs_bmap_btree.c
> @@ -346,7 +346,8 @@ xfs_bmbt_to_bmdr(
>  
>  	if (xfs_sb_version_hascrc(&mp->m_sb)) {
>  		ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_CRC_MAGIC));
> -		ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid));
> +		ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid,
> +		       &mp->m_sb.sb_meta_uuid));
>  		ASSERT(rblock->bb_u.l.bb_blkno ==
>  		       cpu_to_be64(XFS_BUF_DADDR_NULL));
>  	} else
> @@ -644,7 +645,7 @@ xfs_bmbt_verify(
>  	case cpu_to_be32(XFS_BMAP_CRC_MAGIC):
>  		if (!xfs_sb_version_hascrc(&mp->m_sb))
>  			return false;
> -		if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (be64_to_cpu(block->bb_u.l.bb_blkno) != bp->b_bn)
>  			return false;
> diff --git a/libxfs/xfs_btree.c b/libxfs/xfs_btree.c
> index 203e7d2..a16ae7d 100644
> --- a/libxfs/xfs_btree.c
> +++ b/libxfs/xfs_btree.c
> @@ -62,7 +62,8 @@ xfs_btree_check_lblock(
>  
>  	if (xfs_sb_version_hascrc(&mp->m_sb)) {
>  		lblock_ok = lblock_ok &&
> -			uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid) &&
> +			uuid_equal(&block->bb_u.l.bb_uuid,
> +				   &mp->m_sb.sb_meta_uuid) &&
>  			block->bb_u.l.bb_blkno == cpu_to_be64(
>  				bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
>  	}
> @@ -112,7 +113,8 @@ xfs_btree_check_sblock(
>  
>  	if (xfs_sb_version_hascrc(&mp->m_sb)) {
>  		sblock_ok = sblock_ok &&
> -			uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid) &&
> +			uuid_equal(&block->bb_u.s.bb_uuid,
> +				   &mp->m_sb.sb_meta_uuid) &&
>  			block->bb_u.s.bb_blkno == cpu_to_be64(
>  				bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
>  	}
> @@ -997,7 +999,7 @@ xfs_btree_init_block_int(
>  		if (flags & XFS_BTREE_CRC_BLOCKS) {
>  			buf->bb_u.l.bb_blkno = cpu_to_be64(blkno);
>  			buf->bb_u.l.bb_owner = cpu_to_be64(owner);
> -			uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid);
> +			uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid);
>  			buf->bb_u.l.bb_pad = 0;
>  			buf->bb_u.l.bb_lsn = 0;
>  		}
> @@ -1010,7 +1012,7 @@ xfs_btree_init_block_int(
>  		if (flags & XFS_BTREE_CRC_BLOCKS) {
>  			buf->bb_u.s.bb_blkno = cpu_to_be64(blkno);
>  			buf->bb_u.s.bb_owner = cpu_to_be32(__owner);
> -			uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid);
> +			uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid);
>  			buf->bb_u.s.bb_lsn = 0;
>  		}
>  	}
> diff --git a/libxfs/xfs_da_btree.c b/libxfs/xfs_da_btree.c
> index 441bef4..3de4cd3 100644
> --- a/libxfs/xfs_da_btree.c
> +++ b/libxfs/xfs_da_btree.c
> @@ -142,7 +142,7 @@ xfs_da3_node_verify(
>  		if (ichdr.magic != XFS_DA3_NODE_MAGIC)
>  			return false;
>  
> -		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
>  			return false;
> @@ -320,7 +320,7 @@ xfs_da3_node_create(
>  		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);
> -		uuid_copy(&hdr3->info.uuid, &mp->m_sb.sb_uuid);
> +		uuid_copy(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid);
>  	} else {
>  		ichdr.magic = XFS_DA_NODE_MAGIC;
>  	}
> diff --git a/libxfs/xfs_dir2_block.c b/libxfs/xfs_dir2_block.c
> index f061a99..489f301 100644
> --- a/libxfs/xfs_dir2_block.c
> +++ b/libxfs/xfs_dir2_block.c
> @@ -64,7 +64,7 @@ xfs_dir3_block_verify(
>  	if (xfs_sb_version_hascrc(&mp->m_sb)) {
>  		if (hdr3->magic != cpu_to_be32(XFS_DIR3_BLOCK_MAGIC))
>  			return false;
> -		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
>  			return false;
> @@ -154,7 +154,7 @@ xfs_dir3_block_init(
>  		hdr3->magic = cpu_to_be32(XFS_DIR3_BLOCK_MAGIC);
>  		hdr3->blkno = cpu_to_be64(bp->b_bn);
>  		hdr3->owner = cpu_to_be64(dp->i_ino);
> -		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
> +		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
>  		return;
>  
>  	}
> diff --git a/libxfs/xfs_dir2_data.c b/libxfs/xfs_dir2_data.c
> index 609c097..c475ba8 100644
> --- a/libxfs/xfs_dir2_data.c
> +++ b/libxfs/xfs_dir2_data.c
> @@ -218,7 +218,7 @@ xfs_dir3_data_verify(
>  	if (xfs_sb_version_hascrc(&mp->m_sb)) {
>  		if (hdr3->magic != cpu_to_be32(XFS_DIR3_DATA_MAGIC))
>  			return false;
> -		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
>  			return false;
> @@ -602,7 +602,7 @@ xfs_dir3_data_init(
>  		hdr3->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC);
>  		hdr3->blkno = cpu_to_be64(bp->b_bn);
>  		hdr3->owner = cpu_to_be64(dp->i_ino);
> -		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
> +		uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
>  
>  	} else
>  		hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
> diff --git a/libxfs/xfs_dir2_leaf.c b/libxfs/xfs_dir2_leaf.c
> index c2dba8a..80d03b3 100644
> --- a/libxfs/xfs_dir2_leaf.c
> +++ b/libxfs/xfs_dir2_leaf.c
> @@ -158,7 +158,7 @@ xfs_dir3_leaf_verify(
>  
>  		if (leaf3->info.hdr.magic != cpu_to_be16(magic3))
>  			return false;
> -		if (!uuid_equal(&leaf3->info.uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&leaf3->info.uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn)
>  			return false;
> @@ -308,7 +308,7 @@ xfs_dir3_leaf_init(
>  					 : cpu_to_be16(XFS_DIR3_LEAFN_MAGIC);
>  		leaf3->info.blkno = cpu_to_be64(bp->b_bn);
>  		leaf3->info.owner = cpu_to_be64(owner);
> -		uuid_copy(&leaf3->info.uuid, &mp->m_sb.sb_uuid);
> +		uuid_copy(&leaf3->info.uuid, &mp->m_sb.sb_meta_uuid);
>  	} else {
>  		memset(leaf, 0, sizeof(*leaf));
>  		leaf->hdr.info.magic = cpu_to_be16(type);
> diff --git a/libxfs/xfs_dir2_node.c b/libxfs/xfs_dir2_node.c
> index 3b71e9e..581d648 100644
> --- a/libxfs/xfs_dir2_node.c
> +++ b/libxfs/xfs_dir2_node.c
> @@ -91,7 +91,7 @@ xfs_dir3_free_verify(
>  
>  		if (hdr3->magic != cpu_to_be32(XFS_DIR3_FREE_MAGIC))
>  			return false;
> -		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
>  			return false;
> @@ -224,7 +224,7 @@ xfs_dir3_free_get_buf(
>  
>  		hdr3->hdr.blkno = cpu_to_be64(bp->b_bn);
>  		hdr3->hdr.owner = cpu_to_be64(dp->i_ino);
> -		uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_uuid);
> +		uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_meta_uuid);
>  	} else
>  		hdr.magic = XFS_DIR2_FREE_MAGIC;
>  	dp->d_ops->free_hdr_to_disk(bp->b_addr, &hdr);
> diff --git a/libxfs/xfs_dquot_buf.c b/libxfs/xfs_dquot_buf.c
> index 2e0484a..1a2546b 100644
> --- a/libxfs/xfs_dquot_buf.c
> +++ b/libxfs/xfs_dquot_buf.c
> @@ -171,7 +171,7 @@ xfs_dqcheck(
>  	d->dd_diskdq.d_id = cpu_to_be32(id);
>  
>  	if (xfs_sb_version_hascrc(&mp->m_sb)) {
> -		uuid_copy(&d->dd_uuid, &mp->m_sb.sb_uuid);
> +		uuid_copy(&d->dd_uuid, &mp->m_sb.sb_meta_uuid);
>  		xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk),
>  				 XFS_DQUOT_CRC_OFF);
>  	}
> @@ -206,7 +206,7 @@ xfs_dquot_buf_verify_crc(
>  		if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk),
>  				 XFS_DQUOT_CRC_OFF))
>  			return false;
> -		if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  	}
>  	return true;
> diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
> index 4d313d3..12ddcf9 100644
> --- a/libxfs/xfs_format.h
> +++ b/libxfs/xfs_format.h
> @@ -100,7 +100,7 @@ typedef struct xfs_sb {
>  	xfs_rfsblock_t	sb_dblocks;	/* number of data blocks */
>  	xfs_rfsblock_t	sb_rblocks;	/* number of realtime blocks */
>  	xfs_rtblock_t	sb_rextents;	/* number of realtime extents */
> -	uuid_t		sb_uuid;	/* file system unique id */
> +	uuid_t		sb_uuid;	/* user-visible file system unique id */
>  	xfs_fsblock_t	sb_logstart;	/* starting block of log if internal */
>  	xfs_ino_t	sb_rootino;	/* root inode number */
>  	xfs_ino_t	sb_rbmino;	/* bitmap inode for realtime extents */
> @@ -174,6 +174,7 @@ typedef struct xfs_sb {
>  
>  	xfs_ino_t	sb_pquotino;	/* project quota inode */
>  	xfs_lsn_t	sb_lsn;		/* last write sequence */
> +	uuid_t		sb_meta_uuid;	/* metadata file system unique id */
>  
>  	/* must be padded to 64 bit alignment */
>  } xfs_sb_t;
> @@ -190,7 +191,7 @@ typedef struct xfs_dsb {
>  	__be64		sb_dblocks;	/* number of data blocks */
>  	__be64		sb_rblocks;	/* number of realtime blocks */
>  	__be64		sb_rextents;	/* number of realtime extents */
> -	uuid_t		sb_uuid;	/* file system unique id */
> +	uuid_t		sb_uuid;	/* user-visible file system unique id */
>  	__be64		sb_logstart;	/* starting block of log if internal */
>  	__be64		sb_rootino;	/* root inode number */
>  	__be64		sb_rbmino;	/* bitmap inode for realtime extents */
> @@ -260,6 +261,7 @@ typedef struct xfs_dsb {
>  
>  	__be64		sb_pquotino;	/* project quota inode */
>  	__be64		sb_lsn;		/* last write sequence */
> +	uuid_t		sb_meta_uuid;	/* metadata file system unique id */
>  
>  	/* must be padded to 64 bit alignment */
>  } xfs_dsb_t;
> @@ -457,8 +459,10 @@ xfs_sb_has_ro_compat_feature(
>  }
>  
>  #define XFS_SB_FEAT_INCOMPAT_FTYPE	(1 << 0)	/* filetype in dirent */
> +#define XFS_SB_FEAT_INCOMPAT_META_UUID	(1 << 1)	/* metadata UUID */
>  #define XFS_SB_FEAT_INCOMPAT_ALL \
> -		(XFS_SB_FEAT_INCOMPAT_FTYPE)
> +		(XFS_SB_FEAT_INCOMPAT_FTYPE | \
> +		 XFS_SB_FEAT_INCOMPAT_META_UUID)
>  
>  #define XFS_SB_FEAT_INCOMPAT_UNKNOWN	~XFS_SB_FEAT_INCOMPAT_ALL
>  static inline bool
> @@ -507,6 +511,18 @@ static inline int xfs_sb_version_hasfinobt(xfs_sb_t *sbp)
>  }
>  
>  /*
> + * XFS_SB_FEAT_INCOMPAT_META_UUID indicates that the metadata UUID
> + * is stored separately from the user-visible UUID; this allows the
> + * user-visible UUID to be changed on V5 filesystems which have a
> + * filesystem UUID stamped into every piece of metadata.
> + */
> +static inline bool xfs_sb_version_hasmetauuid(struct xfs_sb *sbp)
> +{
> +	return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) &&
> +		(sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID);
> +}
> +
> +/*
>   * end of superblock version macros
>   */
>  
> diff --git a/libxfs/xfs_ialloc.c b/libxfs/xfs_ialloc.c
> index 2b4e4e0..71af28e 100644
> --- a/libxfs/xfs_ialloc.c
> +++ b/libxfs/xfs_ialloc.c
> @@ -302,7 +302,8 @@ xfs_ialloc_inode_init(
>  			if (version == 3) {
>  				free->di_ino = cpu_to_be64(ino);
>  				ino++;
> -				uuid_copy(&free->di_uuid, &mp->m_sb.sb_uuid);
> +				uuid_copy(&free->di_uuid,
> +					  &mp->m_sb.sb_meta_uuid);
>  				xfs_dinode_calc_crc(mp, free);
>  			} else if (tp) {
>  				/* just log the inode core */
> @@ -2044,7 +2045,7 @@ xfs_agi_verify(
>  	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_uuid))
> +	    !uuid_equal(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  	/*
>  	 * Validate the magic number of the agi block.
> diff --git a/libxfs/xfs_ialloc_btree.c b/libxfs/xfs_ialloc_btree.c
> index 9ac143a..e8ec5e7 100644
> --- a/libxfs/xfs_ialloc_btree.c
> +++ b/libxfs/xfs_ialloc_btree.c
> @@ -229,7 +229,7 @@ xfs_inobt_verify(
>  	case cpu_to_be32(XFS_FIBT_CRC_MAGIC):
>  		if (!xfs_sb_version_hascrc(&mp->m_sb))
>  			return false;
> -		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
> +		if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
>  			return false;
>  		if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn))
>  			return false;
> diff --git a/libxfs/xfs_inode_buf.c b/libxfs/xfs_inode_buf.c
> index fd48f04..3f20303 100644
> --- a/libxfs/xfs_inode_buf.c
> +++ b/libxfs/xfs_inode_buf.c
> @@ -304,7 +304,7 @@ xfs_dinode_verify(
>  		return false;
>  	if (be64_to_cpu(dip->di_ino) != ino)
>  		return false;
> -	if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_uuid))
> +	if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_meta_uuid))
>  		return false;
>  	return true;
>  }
> @@ -366,7 +366,7 @@ xfs_iread(
>  		if (xfs_sb_version_hascrc(&mp->m_sb)) {
>  			ip->i_d.di_version = 3;
>  			ip->i_d.di_ino = ip->i_ino;
> -			uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
> +			uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid);
>  		} else
>  			ip->i_d.di_version = 2;
>  		return 0;
> diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c
> index 6844cd8..0ffc497 100644
> --- a/libxfs/xfs_sb.c
> +++ b/libxfs/xfs_sb.c
> @@ -360,6 +360,14 @@ __xfs_sb_from_disk(
>  	to->sb_pad = 0;
>  	to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
>  	to->sb_lsn = be64_to_cpu(from->sb_lsn);
> +	/*
> +	 * sb_meta_uuid is only on disk if it differs from sb_uuid and the
> +	 * feature flag is set; if not set we keep it only in memory.
> +	 */
> +	if (xfs_sb_version_hasmetauuid(to))
> +		uuid_copy(&to->sb_meta_uuid, &from->sb_meta_uuid);
> +	else
> +		uuid_copy(&to->sb_meta_uuid, &from->sb_uuid);
>  	/* Convert on-disk flags to in-memory flags? */
>  	if (convert_xquota)
>  		xfs_sb_quota_from_disk(to);
> @@ -501,6 +509,8 @@ xfs_sb_to_disk(
>  				cpu_to_be32(from->sb_features_log_incompat);
>  		to->sb_pad = 0;
>  		to->sb_lsn = cpu_to_be64(from->sb_lsn);
> +		if (xfs_sb_version_hasmetauuid(from))
> +			uuid_copy(&to->sb_meta_uuid, &from->sb_meta_uuid);
>  	}
>  }
>  
> diff --git a/libxfs/xfs_symlink_remote.c b/libxfs/xfs_symlink_remote.c
> index 6bc5af5..7d46d9e 100644
> --- a/libxfs/xfs_symlink_remote.c
> +++ b/libxfs/xfs_symlink_remote.c
> @@ -60,7 +60,7 @@ xfs_symlink_hdr_set(
>  	dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC);
>  	dsl->sl_offset = cpu_to_be32(offset);
>  	dsl->sl_bytes = cpu_to_be32(size);
> -	uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_uuid);
> +	uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid);
>  	dsl->sl_owner = cpu_to_be64(ino);
>  	dsl->sl_blkno = cpu_to_be64(bp->b_bn);
>  	bp->b_ops = &xfs_symlink_buf_ops;
> @@ -104,7 +104,7 @@ xfs_symlink_verify(
>  		return false;
>  	if (dsl->sl_magic != cpu_to_be32(XFS_SYMLINK_MAGIC))
>  		return false;
> -	if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_uuid))
> +	if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid))
>  		return false;
>  	if (bp->b_bn != be64_to_cpu(dsl->sl_blkno))
>  		return false;
> diff --git a/libxlog/util.c b/libxlog/util.c
> index 053cf04..fd1011f 100644
> --- a/libxlog/util.c
> +++ b/libxlog/util.c
> @@ -29,8 +29,10 @@ header_check_uuid(xfs_mount_t *mp, xlog_rec_header_t *head)
>  {
>      char uu_log[64], uu_sb[64];
>  
> -    if (print_skip_uuid) return 0;
> -    if (!platform_uuid_compare(&mp->m_sb.sb_uuid, &head->h_fs_uuid)) return 0;
> +    if (print_skip_uuid)
> +		return 0;
> +    if (!platform_uuid_compare(&mp->m_sb.sb_uuid, &head->h_fs_uuid))
> +		return 0;
>  
>      platform_uuid_unparse(&mp->m_sb.sb_uuid, uu_sb);
>      platform_uuid_unparse(&head->h_fs_uuid, uu_log);
> diff --git a/man/man8/xfs_admin.8 b/man/man8/xfs_admin.8
> index b393d74..c17b35e 100644
> --- a/man/man8/xfs_admin.8
> +++ b/man/man8/xfs_admin.8
> @@ -98,7 +98,12 @@ The
>  .I uuid
>  may also be
>  .BR generate ,
> -which will generate a new UUID for the filesystem.
> +which will generate a new UUID for the filesystem.  Note that on CRC-enabled
> +filesystems, this will set an incompatible flag such that older kernels will
> +not be able to mount the filesystem.  To remove this incompatible flag, use
> +.BR restore ,
> +which will restore the original UUID and remove the incompatible
> +feature flag as needed.
>  .TP
>  .B \-V
>  Prints the version number and exits.
> diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
> index d527230..df54bb7 100644
> --- a/man/man8/xfs_db.8
> +++ b/man/man8/xfs_db.8
> @@ -664,7 +664,7 @@ The possible data types are:
>  .BR sb ", " symlink " and " text .
>  See the TYPES section below for more information on these data types.
>  .TP
> -.BI "uuid [" uuid " | " generate " | " rewrite ]
> +.BI "uuid [" uuid " | " generate " | " rewrite " | " restore ]
>  Set the filesystem universally unique identifier (UUID).
>  The filesystem UUID can be used by
>  .BR mount (8)
> @@ -675,7 +675,12 @@ can be set directly to the desired UUID, or it can
>  be automatically generated using the
>  .B generate
>  option. These options will both write the UUID into every copy of the
> -superblock in the filesystem.
> +superblock in the filesystem.  On a CRC-enabled filesystem, this will
> +set an incompatible superblock flag, and the filesystem will not be
> +mountable with older kernels.  This can be reverted with the
> +.B restore
> +option, which will copy the original UUID back into place and clear
> +the incompatible flag as needed.
>  .B rewrite
>  copies the current UUID from the primary superblock
>  to all secondary copies of the superblock.
> diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
> index 1770666..cb9f7f5 100644
> --- a/mkfs/xfs_mkfs.c
> +++ b/mkfs/xfs_mkfs.c
> @@ -2598,6 +2598,8 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
>  	sbp->sb_rextents = rtextents;
>  	platform_uuid_generate(&uuid);
>  	platform_uuid_copy(&sbp->sb_uuid, &uuid);
> +	/* Only in memory; libxfs expects this as if read from disk */
> +	platform_uuid_copy(&sbp->sb_meta_uuid, &uuid);
>  	sbp->sb_logstart = logstart;
>  	sbp->sb_rootino = sbp->sb_rbmino = sbp->sb_rsumino = NULLFSINO;
>  	sbp->sb_rextsize = rtextblocks;
> diff --git a/repair/agheader.c b/repair/agheader.c
> index 9ae2deb..cfca529 100644
> --- a/repair/agheader.c
> +++ b/repair/agheader.c
> @@ -112,7 +112,7 @@ verify_set_agf(xfs_mount_t *mp, xfs_agf_t *agf, xfs_agnumber_t i)
>  	if (!xfs_sb_version_hascrc(&mp->m_sb))
>  		return retval;
>  
> -	if (platform_uuid_compare(&agf->agf_uuid, &mp->m_sb.sb_uuid)) {
> +	if (platform_uuid_compare(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid)) {
>  		char uu[64];
>  
>  		retval = XR_AG_AGF;
> @@ -120,7 +120,8 @@ verify_set_agf(xfs_mount_t *mp, xfs_agf_t *agf, xfs_agnumber_t i)
>  		do_warn(_("bad uuid %s for agf %d\n"), uu, i);
>  
>  		if (!no_modify)
> -			platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_uuid);
> +			platform_uuid_copy(&agf->agf_uuid,
> +					   &mp->m_sb.sb_meta_uuid);
>  	}
>  	return retval;
>  }
> @@ -190,7 +191,7 @@ verify_set_agi(xfs_mount_t *mp, xfs_agi_t *agi, xfs_agnumber_t agno)
>  	if (!xfs_sb_version_hascrc(&mp->m_sb))
>  		return retval;
>  
> -	if (platform_uuid_compare(&agi->agi_uuid, &mp->m_sb.sb_uuid)) {
> +	if (platform_uuid_compare(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid)) {
>  		char uu[64];
>  
>  		retval = XR_AG_AGI;
> @@ -198,7 +199,8 @@ verify_set_agi(xfs_mount_t *mp, xfs_agi_t *agi, xfs_agnumber_t agno)
>  		do_warn(_("bad uuid %s for agi %d\n"), uu, agno);
>  
>  		if (!no_modify)
> -			platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid);
> +			platform_uuid_copy(&agi->agi_uuid,
> +					   &mp->m_sb.sb_meta_uuid);
>  	}
>  
>  	return retval;
> @@ -245,7 +247,7 @@ compare_sb(xfs_mount_t *mp, xfs_sb_t *sb)
>   * superblocks, not just the secondary superblocks.
>   */
>  static int
> -secondary_sb_wack(
> +secondary_sb_whack(
>  	struct xfs_mount *mp,
>  	struct xfs_buf	*sbuf,
>  	struct xfs_sb	*sb,
> @@ -267,7 +269,10 @@ secondary_sb_wack(
>  	 *
>  	 * size is the size of data which is valid for this sb.
>  	 */
> -	if (xfs_sb_version_hascrc(sb))
> +	if (xfs_sb_version_hasmetauuid(sb))
> +		size = offsetof(xfs_sb_t, sb_meta_uuid)
> +			+ sizeof(sb->sb_meta_uuid);
> +	else if (xfs_sb_version_hascrc(sb))
>  		size = offsetof(xfs_sb_t, sb_lsn)
>  			+ sizeof(sb->sb_lsn);
>  	else if (xfs_sb_version_hasmorebits(sb))
> @@ -511,7 +516,7 @@ verify_set_agheader(xfs_mount_t *mp, xfs_buf_t *sbuf, xfs_sb_t *sb,
>  		rval |= XR_AG_SB;
>  	}
>  
> -	rval |= secondary_sb_wack(mp, sbuf, sb, i);
> +	rval |= secondary_sb_whack(mp, sbuf, sb, i);
>  
>  	rval |= verify_set_agf(mp, agf, i);
>  	rval |= verify_set_agi(mp, agi, i);
> diff --git a/repair/agheader.h b/repair/agheader.h
> index 5541fb9..6b2974c 100644
> --- a/repair/agheader.h
> +++ b/repair/agheader.h
> @@ -24,7 +24,6 @@ typedef struct fs_geometry  {
>  	xfs_rfsblock_t	sb_dblocks;	/* # data blocks */
>  	xfs_rfsblock_t	sb_rblocks;	/* # realtime blocks */
>  	xfs_rtblock_t	sb_rextents;	/* # realtime extents */
> -	uuid_t		sb_uuid;	/* fs uuid */
>  	xfs_fsblock_t	sb_logstart;	/* starting log block # */
>  	xfs_agblock_t	sb_rextsize;	/* realtime extent size (blocks )*/
>  	xfs_agblock_t	sb_agblocks;	/* # of blocks per ag */
> diff --git a/repair/dinode.c b/repair/dinode.c
> index 179203e..0ea5a9e 100644
> --- a/repair/dinode.c
> +++ b/repair/dinode.c
> @@ -207,9 +207,9 @@ clear_dinode_core(struct xfs_mount *mp, xfs_dinode_t *dinoc, xfs_ino_t ino_num)
>  		dinoc->di_ino = cpu_to_be64(ino_num);
>  	}
>  
> -	if (platform_uuid_compare(&dinoc->di_uuid, &mp->m_sb.sb_uuid)) {
> +	if (platform_uuid_compare(&dinoc->di_uuid, &mp->m_sb.sb_meta_uuid)) {
>  		__dirty_no_modify_ret(dirty);
> -		platform_uuid_copy(&dinoc->di_uuid, &mp->m_sb.sb_uuid);
> +		platform_uuid_copy(&dinoc->di_uuid, &mp->m_sb.sb_meta_uuid);
>  	}
>  
>  	for (i = 0; i < sizeof(dinoc->di_pad2)/sizeof(dinoc->di_pad2[0]); i++) {
> @@ -2287,7 +2287,8 @@ _("inode identifier %llu mismatch on inode %" PRIu64 "\n"),
>  				return 1;
>  			goto clear_bad_out;
>  		}
> -		if (platform_uuid_compare(&dino->di_uuid, &mp->m_sb.sb_uuid)) {
> +		if (platform_uuid_compare(&dino->di_uuid,
> +					  &mp->m_sb.sb_meta_uuid)) {
>  			if (!uncertain)
>  				do_warn(
>  			_("UUID mismatch on inode %" PRIu64 "\n"), lino);
> diff --git a/repair/phase5.c b/repair/phase5.c
> index 1ce57a1..d40b71d 100644
> --- a/repair/phase5.c
> +++ b/repair/phase5.c
> @@ -1119,7 +1119,7 @@ build_agi(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *btree_curs,
>  		agi->agi_unlinked[i] = cpu_to_be32(NULLAGINO);
>  
>  	if (xfs_sb_version_hascrc(&mp->m_sb))
> -		platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid);
> +		platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid);
>  
>  	if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
>  		agi->agi_free_root = cpu_to_be32(finobt_curs->root);
> @@ -1360,7 +1360,7 @@ build_agf_agfl(xfs_mount_t	*mp,
>  #endif
>  
>  	if (xfs_sb_version_hascrc(&mp->m_sb))
> -		platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_uuid);
> +		platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid);
>  
>  	/* initialise the AGFL, then fill it if there are blocks left over. */
>  	agfl_buf = libxfs_getbuf(mp->m_dev,
> @@ -1374,7 +1374,7 @@ build_agf_agfl(xfs_mount_t	*mp,
>  	if (xfs_sb_version_hascrc(&mp->m_sb)) {
>  		agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC);
>  		agfl->agfl_seqno = cpu_to_be32(agno);
> -		platform_uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_uuid);
> +		platform_uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid);
>  		for (i = 0; i < XFS_AGFL_SIZE(mp); i++)
>  			agfl->agfl_bno[i] = cpu_to_be32(NULLAGBLOCK);
>  	}
> diff --git a/repair/phase6.c b/repair/phase6.c
> index 7902be9..5148693 100644
> --- a/repair/phase6.c
> +++ b/repair/phase6.c
> @@ -527,7 +527,7 @@ mk_rbmino(xfs_mount_t *mp)
>  		ip->i_d.di_flags2 = 0;
>  		ip->i_d.di_ino = mp->m_sb.sb_rbmino;
>  		memset(&(ip->i_d.di_pad2[0]), 0, sizeof(ip->i_d.di_pad2));
> -		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
> +		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid);
>  		times |= XFS_ICHGTIME_CREATE;
>  	}
>  	libxfs_trans_ichgtime(tp, ip, times);
> @@ -783,7 +783,7 @@ mk_rsumino(xfs_mount_t *mp)
>  		ip->i_d.di_flags2 = 0;
>  		ip->i_d.di_ino = mp->m_sb.sb_rsumino;
>  		memset(&(ip->i_d.di_pad2[0]), 0, sizeof(ip->i_d.di_pad2));
> -		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
> +		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid);
>  		times |= XFS_ICHGTIME_CREATE;
>  	}
>  	libxfs_trans_ichgtime(tp, ip, times);
> @@ -897,7 +897,7 @@ mk_root_dir(xfs_mount_t *mp)
>  		ip->i_d.di_flags2 = 0;
>  		ip->i_d.di_ino = mp->m_sb.sb_rootino;
>  		memset(&(ip->i_d.di_pad2[0]), 0, sizeof(ip->i_d.di_pad2));
> -		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
> +		platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid);
>  		times |= XFS_ICHGTIME_CREATE;
>  	}
>  	libxfs_trans_ichgtime(tp, ip, times);
> 
> _______________________________________________
> xfs mailing list
> xfs@oss.sgi.com
> http://oss.sgi.com/mailman/listinfo/xfs

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

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

* Re: [PATCH 0/2 V3] allow UUID changes on V5/CRC filesystems
  2015-05-12 19:24 [PATCH 0/2 V3] allow UUID changes on V5/CRC filesystems Eric Sandeen
  2015-05-12 19:27 ` [PATCH 1/2] xfs: create new metadata UUID field and incompat flag Eric Sandeen
  2015-05-12 19:30 ` [PATCH 2/2] xfsprogs: Add new sb_meta_uuid field, update userspace tools to manipulate it Eric Sandeen
@ 2015-06-03 11:14 ` Linda Walsh
  2015-06-03 20:31   ` Eric Sandeen
  2 siblings, 1 reply; 13+ messages in thread
From: Linda Walsh @ 2015-06-03 11:14 UTC (permalink / raw)
  To: xfs-oss



Eric Sandeen wrote:
> Final version?  This has been through some degree of testing, by changing
> the UUID after a CRC mkfs, and re-setting it in between two xfs_repair runs
> before and after each test in the testsuite.
---
	I think I see my problem.

	Is there some strong technical reason why 'crc' has to 
be on to get -finobt=1 && ftype=1.  I'd like to try the latter two
features, but the 'crc' stuff has me a bit bugged -- for unanticipated
reasons like not being able to set the UUID (I so very often hit
those corner cases...*lucky-me*).

> 

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

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

* Re: [PATCH 0/2 V3] allow UUID changes on V5/CRC filesystems
  2015-06-03 11:14 ` [PATCH 0/2 V3] allow UUID changes on V5/CRC filesystems Linda Walsh
@ 2015-06-03 20:31   ` Eric Sandeen
  0 siblings, 0 replies; 13+ messages in thread
From: Eric Sandeen @ 2015-06-03 20:31 UTC (permalink / raw)
  To: Linda Walsh, xfs-oss

On 6/3/15 6:14 AM, Linda Walsh wrote:
> 
> 
> Eric Sandeen wrote:
>> Final version?  This has been through some degree of testing, by changing
>> the UUID after a CRC mkfs, and re-setting it in between two xfs_repair runs
>> before and after each test in the testsuite.
> ---
>     I think I see my problem.

Oh?  what's that?  ;)

>     Is there some strong technical reason why 'crc' has to be on to get -finobt=1 && ftype=1.  I'd like to try the latter two
> features, but the 'crc' stuff has me a bit bugged -- for unanticipated
> reasons like not being able to set the UUID (I so very often hit
> those corner cases...*lucky-me*).

mkfs.xfs -n ftype=1 will get you ftype w/ no crcs.

But some of the above requirements are just because we can't have an infinite test matrix.  

Look at ext4 - would you like a flex_bg filesystem with bigalloc? what about a no-extents, meta-bg nodelalloc filesystem?  Maybe a 64bit, no-resize-inode ... you get the picture.  There are some very dark corners in a test matrix like that.

So the decision was made that for most new features, they were going to depend on the latest rev of the disk format, to keep the xfs code, developers, and users all relatively sane.   Relatively...

-Eric

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

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

end of thread, other threads:[~2015-06-03 20:31 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-12 19:24 [PATCH 0/2 V3] allow UUID changes on V5/CRC filesystems Eric Sandeen
2015-05-12 19:27 ` [PATCH 1/2] xfs: create new metadata UUID field and incompat flag Eric Sandeen
2015-05-14 13:36   ` Brian Foster
2015-05-14 22:36   ` Dave Chinner
2015-05-14 22:55   ` [PATCH 1/2 V4] " Eric Sandeen
2015-05-12 19:30 ` [PATCH 2/2] xfsprogs: Add new sb_meta_uuid field, update userspace tools to manipulate it Eric Sandeen
2015-05-14 13:39   ` Brian Foster
2015-05-14 16:29     ` Eric Sandeen
2015-05-14 21:54   ` [PATCH 2/2 V4] " Eric Sandeen
2015-05-14 23:00     ` [PATCH 2/2 V5] " Eric Sandeen
2015-05-18 14:35       ` Brian Foster
2015-06-03 11:14 ` [PATCH 0/2 V3] allow UUID changes on V5/CRC filesystems Linda Walsh
2015-06-03 20:31   ` Eric Sandeen

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.