[PATCH 24/28] repair: reconstruct sparse inode records correctly on disk

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Phase 5 traverses all of the in-core inode records and regenerates the
inode btrees a record at a time. The record insertion code doesn't
account for sparse inodes which means the ir_holemask and ir_count
fields are not set on-disk and ir_freecount is set with an invalid value
for sparse inode records.

Update build_ino_tree() to handle sparse inode records correctly. We
must account real, allocated inodes only into the ir_freecount field.
The 64-bit in-core sparse inode bitmask must be converted to compressed
16-bit ir_holemask format. Finally, the ir_count field must set to the
total (non-sparse) inode count of the record.

If the fs does not support sparse inodes, both the ir_holemask and
ir_count field are initialized to zero to preserve backwards
compatibility. These bytes historically landed in the high order bytes
of ir_freecount and must be 0 to be interpreted correctly by older XFS
implementations without sparse inode support.

Signed-off-by: Brian Foster <bfoster@xxxxxxxxxx>
---
 repair/phase5.c | 47 +++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 39 insertions(+), 8 deletions(-)

diff --git a/repair/phase5.c b/repair/phase5.c
index 30f2d05..0601810 100644
--- a/repair/phase5.c
+++ b/repair/phase5.c
@@ -1158,8 +1158,12 @@ build_ino_tree(xfs_mount_t *mp, xfs_agnumber_t agno,
 	xfs_agino_t		count = 0;
 	xfs_agino_t		freecount = 0;
 	int			inocnt;
+	uint8_t			finocnt;
 	int			k;
 	int			level = btree_curs->num_levels;
+	int			spmask;
+	uint64_t		sparse;
+	uint16_t		holemask;
 
 	for (i = 0; i < level; i++)  {
 		lptr = &btree_curs->level[i];
@@ -1243,19 +1247,46 @@ build_ino_tree(xfs_mount_t *mp, xfs_agnumber_t agno,
 					cpu_to_be32(ino_rec->ino_startnum);
 			bt_rec[j].ir_free = cpu_to_be64(ino_rec->ir_free);
 
-			inocnt = 0;
+			inocnt = finocnt = 0;
 			for (k = 0; k < sizeof(xfs_inofree_t)*NBBY; k++)  {
 				ASSERT(is_inode_confirmed(ino_rec, k));
-				inocnt += is_inode_free(ino_rec, k);
+
+				if (is_inode_sparse(ino_rec, k))
+					continue;
+				if (is_inode_free(ino_rec, k))
+					finocnt++;
+				inocnt++;
 			}
 
-			if (xfs_sb_version_hassparseinodes(&mp->m_sb))
-				bt_rec[j].ir_u.sp.ir_freecount = inocnt;
-			else
+			if (!xfs_sb_version_hassparseinodes(&mp->m_sb)) {
 				bt_rec[j].ir_u.f.ir_freecount =
-							cpu_to_be32(inocnt);
-			freecount += inocnt;
-			count += XFS_INODES_PER_CHUNK;
+							cpu_to_be32(finocnt);
+				goto nextrec;
+			}
+
+			/*
+			 * Convert the 64-bit in-core sparse inode state to the
+			 * 16-bit on-disk holemask.
+			 */
+			holemask = 0;
+			spmask = (1 << XFS_INODES_PER_HOLEMASK_BIT) - 1;
+			sparse = ino_rec->ir_sparse;
+			for (k = 0; k < XFS_INOBT_HOLEMASK_BITS; k++) {
+				if (sparse & spmask) {
+					ASSERT((sparse & spmask) == spmask);
+					holemask |= (1 << k);
+				} else
+					ASSERT((sparse & spmask) == 0);
+				sparse >>= XFS_INODES_PER_HOLEMASK_BIT;
+			}
+
+			bt_rec[j].ir_u.sp.ir_freecount = finocnt;
+			bt_rec[j].ir_u.sp.ir_count = inocnt;
+			bt_rec[j].ir_u.sp.ir_holemask = cpu_to_be16(holemask);
+
+nextrec:
+			freecount += finocnt;
+			count += inocnt;
 
 			if (finobt)
 				ino_rec = next_free_ino_rec(ino_rec);
-- 
1.9.3

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




[Index of Archives]     [Linux XFS Devel]     [Linux Filesystem Development]     [Filesystem Testing]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux