This commit defines new macros to represent maximum extent counts allowed by filesystems which have support for large per-inode extent counters. Signed-off-by: Chandan Babu R <chandan.babu@xxxxxxxxxx> --- libxfs/xfs_bmap.c | 9 ++++----- libxfs/xfs_bmap_btree.c | 3 ++- libxfs/xfs_format.h | 24 ++++++++++++++++++++++-- libxfs/xfs_inode_buf.c | 4 +++- libxfs/xfs_inode_fork.c | 3 ++- libxfs/xfs_inode_fork.h | 19 +++++++++++++++---- repair/dinode.c | 8 ++++++-- 7 files changed, 54 insertions(+), 16 deletions(-) diff --git a/libxfs/xfs_bmap.c b/libxfs/xfs_bmap.c index 88c0ccc4..ce2e78ed 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 ba239d6e..da771e06 100644 --- a/libxfs/xfs_bmap_btree.c +++ b/libxfs/xfs_bmap_btree.c @@ -609,7 +609,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 7b08e07c..da3cd6e7 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 06e7aaaa..d4b969c6 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 dbaff8ba..1f04ad06 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 4a8b77d4..623049ac 100644 --- a/libxfs/xfs_inode_fork.h +++ b/libxfs/xfs_inode_fork.h @@ -133,12 +133,23 @@ 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: + return has_large_extent_counts ? XFS_MAX_EXTCNT_DATA_FORK_LARGE + : XFS_MAX_EXTCNT_DATA_FORK_SMALL; + + case XFS_ATTR_FORK: + return has_large_extent_counts ? XFS_MAX_EXTCNT_ATTR_FORK_LARGE + : 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 4cfc6352..f0a2b32a 100644 --- a/repair/dinode.c +++ b/repair/dinode.c @@ -1804,7 +1804,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); @@ -1826,7 +1828,9 @@ _("bad nextents %lu 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); -- 2.30.2