From 87c955c38317de8cfd189082bb8d214a59280472 Mon Sep 17 00:00:00 2001
From: Eric Sandeen <sandeen@sandeen.net>
Date: Thu, 30 Jul 2015 09:17:43 +1000
Subject: [PATCH 14/20] metadump: Zero unused portions of inode literal area
References: bsc#939367

The data & attr regions of the inode literal area
are rarely full; unused portions should be zeroed
out so that we don't copy stale disk data.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
Acked-by: Jan Kara <jack@suse.com>

---
 db/metadump.c | 54 ++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 40 insertions(+), 14 deletions(-)

Index: xfsprogs-3.1.8/db/metadump.c
===================================================================
--- xfsprogs-3.1.8.orig/db/metadump.c
+++ xfsprogs-3.1.8/db/metadump.c
@@ -902,7 +902,7 @@ generate_obfuscated_name(
 }
 
 static void
-obfuscate_sf_dir(
+process_sf_dir(
 	xfs_dinode_t		*dip)
 {
 	xfs_dir2_sf_t		*sfp;
@@ -949,13 +949,18 @@ obfuscate_sf_dir(
 					 (char *)sfp);
 		}
 
-		generate_obfuscated_name(xfs_dir2_sf_get_inumber(sfp,
+		if (obfuscate)
+			generate_obfuscated_name(xfs_dir2_sf_get_inumber(sfp,
 				xfs_dir2_sf_inumberp(sfep)), namelen,
 				&sfep->name[0]);
 
 		sfep = (xfs_dir2_sf_entry_t *)((char *)sfep +
 				xfs_dir2_sf_entsize_byname(sfp, namelen));
 	}
+
+	/* zero stale data in rest of space in data fork, if any */
+	if (zero_stale_data && (ino_dir_size < XFS_DFORK_DSIZE(dip, mp)))
+		memset(sfep, 0, XFS_DFORK_DSIZE(dip, mp) - ino_dir_size);
 }
 
 /*
@@ -1002,7 +1007,7 @@ obfuscate_path_components(
 }
 
 static void
-obfuscate_sf_symlink(
+process_sf_symlink(
 	xfs_dinode_t		*dip)
 {
 	__uint64_t		len;
@@ -1017,11 +1022,16 @@ obfuscate_sf_symlink(
 	}
 
 	buf = (char *)XFS_DFORK_DPTR(dip);
-	obfuscate_path_components(buf, len);
+	if (obfuscate)
+		obfuscate_path_components(buf, len);
+
+	/* zero stale data in rest of space in data fork, if any */
+	if (zero_stale_data && len < XFS_DFORK_DSIZE(dip, mp))
+		memset(&buf[len], 0, XFS_DFORK_DSIZE(dip, mp) - len);
 }
 
 static void
-obfuscate_sf_attr(
+process_sf_attr(
 	xfs_dinode_t		*dip)
 {
 	/*
@@ -1065,12 +1075,20 @@ obfuscate_sf_attr(
 			break;
 		}
 
-		generate_obfuscated_name(0, asfep->namelen, &asfep->nameval[0]);
-		memset(&asfep->nameval[asfep->namelen], 'v', asfep->valuelen);
+		if (obfuscate) {
+			generate_obfuscated_name(0, asfep->namelen,
+						 &asfep->nameval[0]);
+			memset(&asfep->nameval[asfep->namelen], 'v',
+			       asfep->valuelen);
+		}
 
 		asfep = (xfs_attr_sf_entry_t *)((char *)asfep +
 				XFS_ATTR_SF_ENTSIZE(asfep));
 	}
+
+	/* zero stale data in rest of space in attr fork, if any */
+	if (zero_stale_data && (ino_attr_size < XFS_DFORK_ASIZE(dip, mp)))
+		memset(asfep, 0, XFS_DFORK_ASIZE(dip, mp) - ino_attr_size);
 }
 
 /*
@@ -1567,19 +1585,26 @@ process_exinode(
 	typnm_t			itype)
 {
 	int			whichfork;
+	int			used;
 	xfs_extnum_t		nex;
 
 	whichfork = (itype == TYP_ATTR) ? XFS_ATTR_FORK : XFS_DATA_FORK;
 
 	nex = XFS_DFORK_NEXTENTS(dip, whichfork);
-	if (nex < 0 || nex > XFS_DFORK_SIZE(dip, mp, whichfork) /
-						sizeof(xfs_bmbt_rec_t)) {
+	used = nex * sizeof(xfs_bmbt_rec_t);
+	if (nex < 0 || used > XFS_DFORK_SIZE(dip, mp, whichfork)) {
 		if (show_warnings)
 			print_warning("bad number of extents %d in inode %lld",
 				nex, (long long)cur_ino);
 		return 1;
 	}
 
+	/* Zero unused data fork past used extents */
+	if (zero_stale_data && (used < XFS_DFORK_SIZE(dip, mp, whichfork)))
+		memset(XFS_DFORK_PTR(dip, whichfork) + used, 0,
+		       XFS_DFORK_SIZE(dip, mp, whichfork) - used);
+
+
 	return process_bmbt_reclist((xfs_bmbt_rec_t *)XFS_DFORK_PTR(dip,
 					whichfork), nex, itype);
 }
@@ -1591,14 +1616,14 @@ process_inode_data(
 {
 	switch (dip->di_format) {
 		case XFS_DINODE_FMT_LOCAL:
-			if (obfuscate)
+			if (obfuscate || zero_stale_data)
 				switch (itype) {
 					case TYP_DIR2:
-						obfuscate_sf_dir(dip);
+						process_sf_dir(dip);
 						break;
 
 					case TYP_SYMLINK:
-						obfuscate_sf_symlink(dip);
+						process_sf_symlink(dip);
 						break;
 
 					default: ;
@@ -1655,8 +1680,8 @@ process_inode(
 		attr_data.remote_val_count = 0;
 		switch (dip->di_aformat) {
 			case XFS_DINODE_FMT_LOCAL:
-				if (obfuscate)
-					obfuscate_sf_attr(dip);
+				if (obfuscate || zero_stale_data)
+					process_sf_attr(dip);
 				break;
 
 			case XFS_DINODE_FMT_EXTENTS:
