[PATCH] xfs: Allow scrub to detect inodes with non-maximal sized extents

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

 



This commit now makes it possible for scrub to check if an inode's extents are
maximally sized i.e. it checks if an inode's extent is contiguous (in terms of
both file offset and disk offset) with neighbouring extents and the total
length of both the extents is less than the maximum allowed extent
length (i.e. MAXEXTLEN).

Signed-off-by: Chandan Babu R <chandanrlinux@xxxxxxxxx>
---
 fs/xfs/scrub/inode.c   | 11 +++++++----
 fs/xfs/xfs_bmap_util.c | 36 +++++++++++++++++++++++++++++++-----
 fs/xfs/xfs_bmap_util.h |  5 +++--
 fs/xfs/xfs_qm.c        |  2 +-
 4 files changed, 42 insertions(+), 12 deletions(-)

diff --git a/fs/xfs/scrub/inode.c b/fs/xfs/scrub/inode.c
index faf65eb5bd31..33b530785e36 100644
--- a/fs/xfs/scrub/inode.c
+++ b/fs/xfs/scrub/inode.c
@@ -478,23 +478,26 @@ xchk_inode_xref_bmap(
 	xfs_filblks_t		count;
 	xfs_filblks_t		acount;
 	int			error;
+	bool			maximal_sized_exts;
 
 	if (xchk_skip_xref(sc->sm))
 		return;
 
 	/* Walk all the extents to check nextents/naextents/nblocks. */
+	maximal_sized_exts = true;
 	error = xfs_bmap_count_blocks(sc->tp, sc->ip, XFS_DATA_FORK,
-			&nextents, &count);
+			&nextents, &count, &maximal_sized_exts);
 	if (!xchk_should_check_xref(sc, &error, NULL))
 		return;
-	if (nextents < be32_to_cpu(dip->di_nextents))
+	if (nextents < be32_to_cpu(dip->di_nextents) || !maximal_sized_exts)
 		xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
 
+	maximal_sized_exts = true;
 	error = xfs_bmap_count_blocks(sc->tp, sc->ip, XFS_ATTR_FORK,
-			&nextents, &acount);
+			&nextents, &acount, &maximal_sized_exts);
 	if (!xchk_should_check_xref(sc, &error, NULL))
 		return;
-	if (nextents != be16_to_cpu(dip->di_anextents))
+	if (nextents != be16_to_cpu(dip->di_anextents) || !maximal_sized_exts)
 		xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
 
 	/* Check nblocks against the inode. */
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index e7d68318e6a5..eca39677a46f 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -176,6 +176,25 @@ xfs_bmap_rtalloc(
  * Extent tree block counting routines.
  */
 
+STATIC bool
+is_maximal_extent(
+	struct xfs_ifork	*ifp,
+	struct xfs_iext_cursor	*icur,
+	struct xfs_bmbt_irec	*got)
+{
+	struct xfs_bmbt_irec	left;
+
+	if (xfs_iext_peek_prev_extent(ifp, icur, &left) &&
+		!isnullstartblock(left.br_startblock) &&
+		left.br_startoff + left.br_blockcount == got->br_startoff &&
+		left.br_startblock + left.br_blockcount == got->br_startblock &&
+		left.br_state == got->br_state &&
+		left.br_blockcount + got->br_blockcount <= MAXEXTLEN)
+		return false;
+	else
+		return true;
+}
+
 /*
  * Count leaf blocks given a range of extent records.  Delayed allocation
  * extents are not counted towards the totals.
@@ -183,7 +202,8 @@ xfs_bmap_rtalloc(
 xfs_extnum_t
 xfs_bmap_count_leaves(
 	struct xfs_ifork	*ifp,
-	xfs_filblks_t		*count)
+	xfs_filblks_t		*count,
+	bool			*maximal_sized_exts)
 {
 	struct xfs_iext_cursor	icur;
 	struct xfs_bmbt_irec	got;
@@ -191,6 +211,10 @@ xfs_bmap_count_leaves(
 
 	for_each_xfs_iext(ifp, &icur, &got) {
 		if (!isnullstartblock(got.br_startblock)) {
+			if (maximal_sized_exts)
+				*maximal_sized_exts =
+					is_maximal_extent(ifp, &icur, &got);
+
 			*count += got.br_blockcount;
 			numrecs++;
 		}
@@ -209,7 +233,8 @@ xfs_bmap_count_blocks(
 	struct xfs_inode	*ip,
 	int			whichfork,
 	xfs_extnum_t		*nextents,
-	xfs_filblks_t		*count)
+	xfs_filblks_t		*count,
+	bool			*maximal_sized_exts)
 {
 	struct xfs_mount	*mp = ip->i_mount;
 	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
@@ -246,7 +271,8 @@ xfs_bmap_count_blocks(
 
 		/* fall through */
 	case XFS_DINODE_FMT_EXTENTS:
-		*nextents = xfs_bmap_count_leaves(ifp, count);
+		*nextents = xfs_bmap_count_leaves(ifp, count,
+				maximal_sized_exts);
 		break;
 	}
 
@@ -1442,14 +1468,14 @@ xfs_swap_extent_forks(
 	if (XFS_IFORK_Q(ip) && ip->i_afp->if_nextents > 0 &&
 	    ip->i_afp->if_format != XFS_DINODE_FMT_LOCAL) {
 		error = xfs_bmap_count_blocks(tp, ip, XFS_ATTR_FORK, &junk,
-				&aforkblks);
+				&aforkblks, NULL);
 		if (error)
 			return error;
 	}
 	if (XFS_IFORK_Q(tip) && tip->i_afp->if_nextents > 0 &&
 	    tip->i_afp->if_format != XFS_DINODE_FMT_LOCAL) {
 		error = xfs_bmap_count_blocks(tp, tip, XFS_ATTR_FORK, &junk,
-				&taforkblks);
+				&taforkblks, NULL);
 		if (error)
 			return error;
 	}
diff --git a/fs/xfs/xfs_bmap_util.h b/fs/xfs/xfs_bmap_util.h
index 9f993168b55b..7b0ce227c7bd 100644
--- a/fs/xfs/xfs_bmap_util.h
+++ b/fs/xfs/xfs_bmap_util.h
@@ -71,10 +71,11 @@ int	xfs_swap_extents(struct xfs_inode *ip, struct xfs_inode *tip,
 
 xfs_daddr_t xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb);
 
-xfs_extnum_t xfs_bmap_count_leaves(struct xfs_ifork *ifp, xfs_filblks_t *count);
+xfs_extnum_t xfs_bmap_count_leaves(struct xfs_ifork *ifp, xfs_filblks_t *count,
+		bool *maximal_sized_exts);
 int xfs_bmap_count_blocks(struct xfs_trans *tp, struct xfs_inode *ip,
 			  int whichfork, xfs_extnum_t *nextents,
-			  xfs_filblks_t *count);
+			  xfs_filblks_t *count, bool *maximal_sized_exts);
 
 int	xfs_flush_unmap_range(struct xfs_inode *ip, xfs_off_t offset,
 			      xfs_off_t len);
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index 742d1413e2d0..04fcca5583b3 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -1170,7 +1170,7 @@ xfs_qm_dqusage_adjust(
 				goto error0;
 		}
 
-		xfs_bmap_count_leaves(ifp, &rtblks);
+		xfs_bmap_count_leaves(ifp, &rtblks, NULL);
 	}
 
 	nblks = (xfs_qcnt_t)ip->i_d.di_nblocks - rtblks;
-- 
2.29.2




[Index of Archives]     [XFS Filesystem Development (older mail)]     [Linux Filesystem Development]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux RAID]     [Linux SCSI]


  Powered by Linux