public inbox for linux-xfs@vger.kernel.org
 help / color / mirror / Atom feed
From: Brian Foster <bfoster@redhat.com>
To: xfs@oss.sgi.com
Subject: [PATCH 18/28] repair: scan and track sparse inode chunks correctly
Date: Tue,  2 Jun 2015 14:41:51 -0400	[thread overview]
Message-ID: <1433270521-62026-19-git-send-email-bfoster@redhat.com> (raw)
In-Reply-To: <1433270521-62026-1-git-send-email-bfoster@redhat.com>

Phase 2 of xfs_repair scans the on-disk inobt and creates in-core
records for all inodes in the fs. This also involves marking
free/allocated state of all inodes, internal record verification and
block state management for the inode chunks tracked by inode records.
Various parts of the inobt scan mechanism assume fully allocated inode
records and thus lead to spurious errors when sparse inode records are
encountered.

Update the inobt scan to detect and handle sparse inode records
correctly. Do not set the allocation state of blocks in sparse inode
regions as these blocks do not belong to the record. Do not account
sparse inodes against the ir_freecount as these inodes do not exist and
are not available for allocation by the fs. Finally, track the sparse
status of each individual inode in the in-core inode records for future
reference.

Signed-off-by: Brian Foster <bfoster@redhat.com>
---
 include/libxfs.h    | 16 ++++++++++++++++
 repair/incore.h     | 14 ++++++++++++++
 repair/incore_ino.c |  1 +
 repair/scan.c       | 48 +++++++++++++++++++++++++++++++++++++++++-------
 4 files changed, 72 insertions(+), 7 deletions(-)

diff --git a/include/libxfs.h b/include/libxfs.h
index 6a59cc0..3321c50 100644
--- a/include/libxfs.h
+++ b/include/libxfs.h
@@ -183,6 +183,22 @@ extern unsigned long	libxfs_physmem(void);	/* in kilobytes */
 #define XFS_INOBT_IS_FREE_DISK(rp,i)		\
 			((be64_to_cpu((rp)->ir_free) & XFS_INOBT_MASK(i)) != 0)
 
+static inline bool
+XFS_INOBT_IS_SPARSE_DISK(
+	struct xfs_inobt_rec	*rp,
+	int			offset)
+{
+	int			spshift;
+	uint16_t		holemask;
+
+	holemask = be16_to_cpu(rp->ir_u.sp.ir_holemask);
+	spshift = offset / XFS_INODES_PER_HOLEMASK_BIT;
+	if ((1 << spshift) & holemask)
+		return true;
+
+	return false;
+}
+
 static inline void
 libxfs_bmbt_disk_get_all(
 	struct xfs_bmbt_rec	*rp,
diff --git a/repair/incore.h b/repair/incore.h
index ba819b4..d4e44a7 100644
--- a/repair/incore.h
+++ b/repair/incore.h
@@ -285,6 +285,7 @@ typedef struct ino_tree_node  {
 	avlnode_t		avl_node;
 	xfs_agino_t		ino_startnum;	/* starting inode # */
 	xfs_inofree_t		ir_free;	/* inode free bit mask */
+	__uint64_t		ir_sparse;	/* sparse inode bitmask */
 	__uint64_t		ino_confirmed;	/* confirmed bitmask */
 	__uint64_t		ino_isa_dir;	/* bit == 1 if a directory */
 	__uint8_t		nlink_size;
@@ -477,6 +478,19 @@ static inline int is_inode_free(struct ino_tree_node *irec, int offset)
 }
 
 /*
+ * set/test is inode sparse (not physically allocated)
+ */
+static inline void set_inode_sparse(struct ino_tree_node *irec, int offset)
+{
+	irec->ir_sparse |= XFS_INOBT_MASK(offset);
+}
+
+static inline bool is_inode_sparse(struct ino_tree_node *irec, int offset)
+{
+	return irec->ir_sparse & XFS_INOBT_MASK(offset);
+}
+
+/*
  * add_inode_reached() is set on inode I only if I has been reached
  * by an inode P claiming to be the parent and if I is a directory,
  * the .. link in the I says that P is I's parent.
diff --git a/repair/incore_ino.c b/repair/incore_ino.c
index 9502648..cda6c2b 100644
--- a/repair/incore_ino.c
+++ b/repair/incore_ino.c
@@ -258,6 +258,7 @@ alloc_ino_node(
 	irec->ino_confirmed = 0;
 	irec->ino_isa_dir = 0;
 	irec->ir_free = (xfs_inofree_t) - 1;
+	irec->ir_sparse = 0;
 	irec->ino_un.ex_data = NULL;
 	irec->nlink_size = sizeof(__uint8_t);
 	irec->disk_nlinks.un8 = alloc_nlink_array(irec->nlink_size);
diff --git a/repair/scan.c b/repair/scan.c
index 8677e41..5b67e15 100644
--- a/repair/scan.c
+++ b/repair/scan.c
@@ -736,6 +736,17 @@ _("%s freespace btree block claimed (state %d), agno %d, bno %d, suspect %d\n"),
 	}
 }
 
+static bool
+ino_issparse(
+	struct xfs_inobt_rec	*rp,
+	int			offset)
+{
+	if (!xfs_sb_version_hassparseinodes(&mp->m_sb))
+		return false;
+
+	return XFS_INOBT_IS_SPARSE_DISK(rp, offset);
+}
+
 static int
 scan_single_ino_chunk(
 	xfs_agnumber_t		agno,
@@ -749,7 +760,8 @@ scan_single_ino_chunk(
 	int			nfree;
 	int			off;
 	int			state;
-	ino_tree_node_t		*ino_rec, *first_rec, *last_rec;
+	ino_tree_node_t		*ino_rec = NULL;
+	ino_tree_node_t		*first_rec, *last_rec;
 	int			freecount;
 
 	ino = be32_to_cpu(rp->ir_startino);
@@ -815,8 +827,12 @@ _("bad ending inode # (%" PRIu64 " (0x%x 0x%zx)) in ino rec, skipping rec\n"),
 		for (j = 0;
 		     j < XFS_INODES_PER_CHUNK;
 		     j += mp->m_sb.sb_inopblock)  {
-			agbno = XFS_AGINO_TO_AGBNO(mp, ino + j);
 
+			/* inodes in sparse chunks don't use blocks */
+			if (ino_issparse(rp, j))
+				continue;
+
+			agbno = XFS_AGINO_TO_AGBNO(mp, ino + j);
 			state = get_bmap(agno, agbno);
 			if (state == XR_E_UNKNOWN)  {
 				set_bmap(agno, agbno, XR_E_INO);
@@ -861,8 +877,6 @@ _("inode rec for ino %" PRIu64 " (%d/%d) overlaps existing rec (start %d/%d)\n")
 			return suspect;
 	}
 
-	nfree = 0;
-
 	/*
 	 * now mark all the inodes as existing and free or used.
 	 * if the tree is suspect, put them into the uncertain
@@ -870,14 +884,12 @@ _("inode rec for ino %" PRIu64 " (%d/%d) overlaps existing rec (start %d/%d)\n")
 	 */
 	if (!suspect)  {
 		if (XFS_INOBT_IS_FREE_DISK(rp, 0)) {
-			nfree++;
 			ino_rec = set_inode_free_alloc(mp, agno, ino);
 		} else  {
 			ino_rec = set_inode_used_alloc(mp, agno, ino);
 		}
 		for (j = 1; j < XFS_INODES_PER_CHUNK; j++) {
 			if (XFS_INOBT_IS_FREE_DISK(rp, j)) {
-				nfree++;
 				set_inode_free(ino_rec, j);
 			} else  {
 				set_inode_used(ino_rec, j);
@@ -886,7 +898,6 @@ _("inode rec for ino %" PRIu64 " (%d/%d) overlaps existing rec (start %d/%d)\n")
 	} else  {
 		for (j = 0; j < XFS_INODES_PER_CHUNK; j++) {
 			if (XFS_INOBT_IS_FREE_DISK(rp, j)) {
-				nfree++;
 				add_aginode_uncertain(mp, agno, ino + j, 1);
 			} else  {
 				add_aginode_uncertain(mp, agno, ino + j, 0);
@@ -894,6 +905,29 @@ _("inode rec for ino %" PRIu64 " (%d/%d) overlaps existing rec (start %d/%d)\n")
 		}
 	}
 
+	/*
+	 * Mark sparse inodes as such in the in-core tree. Verify that sparse
+	 * inodes are free and that freecount is consistent with the free mask.
+	 */
+	nfree = 0;
+	for (j = 0; j < XFS_INODES_PER_CHUNK; j++) {
+		if (ino_issparse(rp, j)) {
+			if (!suspect && !XFS_INOBT_IS_FREE_DISK(rp, j)) {
+				do_warn(
+_("ir_holemask/ir_free mismatch, inode chunk %d/%u, holemask 0x%x free 0x%llx\n"),
+					agno, ino,
+					be16_to_cpu(rp->ir_u.sp.ir_holemask),
+					be64_to_cpu(rp->ir_free));
+				suspect++;
+			}
+			if (!suspect && ino_rec)
+				set_inode_sparse(ino_rec, j);
+		} else if (XFS_INOBT_IS_FREE_DISK(rp, j)) {
+			/* freecount only tracks non-sparse inos */
+			nfree++;
+		}
+	}
+
 	if (nfree != freecount) {
 		do_warn(
 _("ir_freecount/free mismatch, inode chunk %d/%u, freecount %d nfree %d\n"),
-- 
1.9.3

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

  parent reply	other threads:[~2015-06-02 18:42 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-06-02 18:41 [PATCH 00/28] xfsprogs: sparse inode chunks Brian Foster
2015-06-02 18:41 ` [PATCH 01/28] xfs: create individual inode alloc. helper Brian Foster
2015-06-02 18:41 ` [PATCH 02/28] xfs: update free inode record logic to support sparse inode records Brian Foster
2015-06-02 18:41 ` [PATCH 03/28] xfs: support min/max agbno args in block allocator Brian Foster
2015-06-02 18:41 ` [PATCH 04/28] xfs: add sparse inode chunk alignment superblock field Brian Foster
2015-06-02 18:41 ` [PATCH 05/28] xfs: use sparse chunk alignment for min. inode allocation requirement Brian Foster
2015-06-02 18:41 ` [PATCH 06/28] xfs: sparse inode chunks feature helpers and mount requirements Brian Foster
2015-06-02 18:41 ` [PATCH 07/28] xfs: add fs geometry bit for sparse inode chunks Brian Foster
2015-06-02 18:41 ` [PATCH 08/28] xfs: introduce inode record hole mask " Brian Foster
2015-06-02 18:41 ` [PATCH 09/28] xfs: pass inode count through ordered icreate log item Brian Foster
2015-06-02 18:41 ` [PATCH 10/28] xfs: enable sparse inode chunks for v5 superblocks Brian Foster
2015-06-02 18:41 ` [PATCH 11/28] mkfs: sparse inode chunk support Brian Foster
2015-06-02 18:41 ` [PATCH 12/28] db: support sparse inode chunk inobt record and sb fields Brian Foster
2015-06-02 18:41 ` [PATCH 13/28] db: show sparse inodes feature state in version command output Brian Foster
2015-06-02 18:41 ` [PATCH 14/28] growfs: display sparse inode status from xfs_info Brian Foster
2015-06-02 18:41 ` [PATCH 15/28] repair: handle sparse format inobt record freecount correctly Brian Foster
2015-06-05  0:53   ` Dave Chinner
2015-06-02 18:41 ` [PATCH 16/28] repair: remove duplicate field from aghdr_cnts Brian Foster
2015-06-02 18:41 ` [PATCH 17/28] repair: use ir_count for filesystems with sparse inode support Brian Foster
2015-06-02 18:41 ` Brian Foster [this message]
2015-06-05  0:56   ` [PATCH 18/28] repair: scan and track sparse inode chunks correctly Dave Chinner
2015-06-02 18:41 ` [PATCH 19/28] repair: scan sparse finobt records correctly Brian Foster
2015-06-05  1:03   ` Dave Chinner
2015-06-05 16:52     ` Brian Foster
2015-06-02 18:41 ` [PATCH 20/28] repair: validate ir_count field for sparse format records Brian Foster
2015-06-02 18:41 ` [PATCH 21/28] repair: process sparse inode records correctly Brian Foster
2015-06-05  1:12   ` Dave Chinner
2015-06-02 18:41 ` [PATCH 22/28] repair: factor out sparse inodes from finobt reconstruction Brian Foster
2015-06-02 18:41 ` [PATCH 23/28] repair: do not account sparse inodes in phase 5 cursor init Brian Foster
2015-06-02 18:41 ` [PATCH 24/28] repair: reconstruct sparse inode records correctly on disk Brian Foster
2015-06-02 18:41 ` [PATCH 25/28] repair: do not prefetch holes in sparse inode chunks Brian Foster
2015-06-02 18:41 ` [PATCH 26/28] repair: handle sparse inode alignment Brian Foster
2015-06-02 18:42 ` [PATCH 27/28] metadump: reorder inode record sanity checks and inode buffer read Brian Foster
2015-06-02 18:42 ` [PATCH 28/28] metadump: support sparse inode records Brian Foster
2015-06-16  0:33 ` [PATCH 00/28] xfsprogs: sparse inode chunks Dave Chinner
2015-06-16  0:39   ` Dave Chinner
2015-06-16 10:55     ` Brian Foster
2015-06-16 20:26       ` Dave Chinner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1433270521-62026-19-git-send-email-bfoster@redhat.com \
    --to=bfoster@redhat.com \
    --cc=xfs@oss.sgi.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox