From: Chandan Babu R Date: Wed, 22 Jun 2022 19:28:52 +0000 (-0500) Subject: xfs: Introduce macros to represent new maximum extent counts for data/attr forks X-Git-Tag: v5.19.0-rc0~94 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5a8b4d6a60dffd4f09e4e30e488c8289d1813388;p=thirdparty%2Fxfsprogs-dev.git xfs: Introduce macros to represent new maximum extent counts for data/attr forks Source kernel commit: df9ad5cc7a524048ea7ff983d6feeb6d8c47a761 This commit defines new macros to represent maximum extent counts allowed by filesystems which have support for large per-inode extent counters. Reviewed-by: Darrick J. Wong Reviewed-by: Dave Chinner Signed-off-by: Chandan Babu R Signed-off-by: Eric Sandeen --- diff --git a/include/xfs_inode.h b/include/xfs_inode.h index db9faa57d..6a29b0983 100644 --- a/include/xfs_inode.h +++ b/include/xfs_inode.h @@ -164,6 +164,11 @@ static inline bool xfs_inode_has_bigtime(struct xfs_inode *ip) return ip->i_diflags2 & XFS_DIFLAG2_BIGTIME; } +static inline bool xfs_inode_has_large_extent_counts(struct xfs_inode *ip) +{ + return ip->i_diflags2 & XFS_DIFLAG2_NREXT64; +} + /* Always set the child's GID to this value, even if the parent is setgid. */ #define CRED_FORCE_GID (1U << 0) struct cred { diff --git a/libxfs/xfs_bmap.c b/libxfs/xfs_bmap.c index 40764571b..105717f4c 100644 --- a/libxfs/xfs_bmap.c +++ b/libxfs/xfs_bmap.c @@ -54,10 +54,8 @@ xfs_bmap_compute_maxlevels( int sz; /* root block size */ /* - * The maximum number of extents in a file, hence the maximum number of - * leaf entries, is controlled by the size of the on-disk extent count, - * either a signed 32-bit number for the data fork, or a signed 16-bit - * number for the attr fork. + * The maximum number of extents in a fork, hence the maximum number of + * leaf entries, is controlled by the size of the on-disk extent count. * * Note that we can no longer assume that if we are in ATTR1 that the * fork offset of all the inodes will be @@ -67,7 +65,8 @@ xfs_bmap_compute_maxlevels( * ATTR2 we have to assume the worst case scenario of a minimum size * available. */ - maxleafents = xfs_iext_max_nextents(whichfork); + maxleafents = xfs_iext_max_nextents(xfs_has_large_extent_counts(mp), + whichfork); if (whichfork == XFS_DATA_FORK) sz = XFS_BMDR_SPACE_CALC(MINDBTPTRS); else diff --git a/libxfs/xfs_bmap_btree.c b/libxfs/xfs_bmap_btree.c index ba239d6ec..c69125225 100644 --- a/libxfs/xfs_bmap_btree.c +++ b/libxfs/xfs_bmap_btree.c @@ -595,7 +595,11 @@ xfs_bmbt_maxrecs( return xfs_bmbt_block_maxrecs(blocklen, leaf); } -/* Compute the max possible height for block mapping btrees. */ +/* + * Calculate the maximum possible height of the btree that the on-disk format + * supports. This is used for sizing structures large enough to support every + * possible configuration of a filesystem that might get mounted. + */ unsigned int xfs_bmbt_maxlevels_ondisk(void) { @@ -609,7 +613,8 @@ xfs_bmbt_maxlevels_ondisk(void) minrecs[1] = xfs_bmbt_block_maxrecs(blocklen, false) / 2; /* One extra level for the inode root. */ - return xfs_btree_compute_maxlevels(minrecs, MAXEXTNUM) + 1; + return xfs_btree_compute_maxlevels(minrecs, + XFS_MAX_EXTCNT_DATA_FORK_LARGE) + 1; } /* diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h index 57b24744a..eb85bc9b2 100644 --- a/libxfs/xfs_format.h +++ b/libxfs/xfs_format.h @@ -872,9 +872,29 @@ enum xfs_dinode_fmt { /* * Max values for extnum and aextnum. + * + * The original on-disk extent counts were held in signed fields, resulting in + * maximum extent counts of 2^31 and 2^15 for the data and attr forks + * respectively. Similarly the maximum extent length is limited to 2^21 blocks + * by the 21-bit wide blockcount field of a BMBT extent record. + * + * The newly introduced data fork extent counter can hold a 64-bit value, + * however the maximum number of extents in a file is also limited to 2^54 + * extents by the 54-bit wide startoff field of a BMBT extent record. + * + * It is further limited by the maximum supported file size of 2^63 + * *bytes*. This leads to a maximum extent count for maximally sized filesystem + * blocks (64kB) of: + * + * 2^63 bytes / 2^16 bytes per block = 2^47 blocks + * + * Rounding up 47 to the nearest multiple of bits-per-byte results in 48. Hence + * 2^48 was chosen as the maximum data fork extent count. */ -#define MAXEXTNUM ((xfs_extnum_t)0x7fffffff) /* signed int */ -#define MAXAEXTNUM ((xfs_aextnum_t)0x7fff) /* signed short */ +#define XFS_MAX_EXTCNT_DATA_FORK_LARGE ((xfs_extnum_t)((1ULL << 48) - 1)) +#define XFS_MAX_EXTCNT_ATTR_FORK_LARGE ((xfs_extnum_t)((1ULL << 32) - 1)) +#define XFS_MAX_EXTCNT_DATA_FORK_SMALL ((xfs_extnum_t)((1ULL << 31) - 1)) +#define XFS_MAX_EXTCNT_ATTR_FORK_SMALL ((xfs_extnum_t)((1ULL << 15) - 1)) /* * Inode minimum and maximum sizes. diff --git a/libxfs/xfs_inode_buf.c b/libxfs/xfs_inode_buf.c index eebcb2b6c..deb143171 100644 --- a/libxfs/xfs_inode_buf.c +++ b/libxfs/xfs_inode_buf.c @@ -358,7 +358,9 @@ xfs_dinode_verify_fork( return __this_address; break; case XFS_DINODE_FMT_BTREE: - max_extents = xfs_iext_max_nextents(whichfork); + max_extents = xfs_iext_max_nextents( + xfs_dinode_has_large_extent_counts(dip), + whichfork); if (di_nextents > max_extents) return __this_address; break; diff --git a/libxfs/xfs_inode_fork.c b/libxfs/xfs_inode_fork.c index 26527602f..568c0ff4e 100644 --- a/libxfs/xfs_inode_fork.c +++ b/libxfs/xfs_inode_fork.c @@ -742,7 +742,8 @@ xfs_iext_count_may_overflow( if (whichfork == XFS_COW_FORK) return 0; - max_exts = xfs_iext_max_nextents(whichfork); + max_exts = xfs_iext_max_nextents(xfs_inode_has_large_extent_counts(ip), + whichfork); if (XFS_TEST_ERROR(false, ip->i_mount, XFS_ERRTAG_REDUCE_MAX_IEXTENTS)) max_exts = 10; diff --git a/libxfs/xfs_inode_fork.h b/libxfs/xfs_inode_fork.h index 4a8b77d42..967837a88 100644 --- a/libxfs/xfs_inode_fork.h +++ b/libxfs/xfs_inode_fork.h @@ -133,12 +133,25 @@ static inline int8_t xfs_ifork_format(struct xfs_ifork *ifp) return ifp->if_format; } -static inline xfs_extnum_t xfs_iext_max_nextents(int whichfork) +static inline xfs_extnum_t xfs_iext_max_nextents(bool has_large_extent_counts, + int whichfork) { - if (whichfork == XFS_DATA_FORK || whichfork == XFS_COW_FORK) - return MAXEXTNUM; + switch (whichfork) { + case XFS_DATA_FORK: + case XFS_COW_FORK: + if (has_large_extent_counts) + return XFS_MAX_EXTCNT_DATA_FORK_LARGE; + return XFS_MAX_EXTCNT_DATA_FORK_SMALL; + + case XFS_ATTR_FORK: + if (has_large_extent_counts) + return XFS_MAX_EXTCNT_ATTR_FORK_LARGE; + return XFS_MAX_EXTCNT_ATTR_FORK_SMALL; - return MAXAEXTNUM; + default: + ASSERT(0); + return 0; + } } static inline xfs_extnum_t diff --git a/repair/dinode.c b/repair/dinode.c index 28343083c..21d428a01 100644 --- a/repair/dinode.c +++ b/repair/dinode.c @@ -1812,7 +1812,9 @@ _("bad nblocks %llu for inode %" PRIu64 ", would reset to %" PRIu64 "\n"), } } - if (nextents > xfs_iext_max_nextents(XFS_DATA_FORK)) { + if (nextents > xfs_iext_max_nextents( + xfs_dinode_has_large_extent_counts(dino), + XFS_DATA_FORK)) { do_warn( _("too many data fork extents (%" PRIu64 ") in inode %" PRIu64 "\n"), nextents, lino); @@ -1833,7 +1835,9 @@ _("bad nextents %" PRIu64 " for inode %" PRIu64 ", would reset to %" PRIu64 "\n" } } - if (anextents > xfs_iext_max_nextents(XFS_ATTR_FORK)) { + if (anextents > xfs_iext_max_nextents( + xfs_dinode_has_large_extent_counts(dino), + XFS_ATTR_FORK)) { do_warn( _("too many attr fork extents (%" PRIu64 ") in inode %" PRIu64 "\n"), anextents, lino);