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 | 2 +- libxfs/xfs_format.h | 20 ++++++++++++++++---- libxfs/xfs_inode_buf.c | 3 ++- libxfs/xfs_inode_fork.c | 2 +- libxfs/xfs_inode_fork.h | 19 +++++++++++++++---- repair/dinode.c | 6 ++++-- 7 files changed, 43 insertions(+), 18 deletions(-) diff --git a/libxfs/xfs_bmap.c b/libxfs/xfs_bmap.c index 51e9b6ce..8dd084b9 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_nrext64(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..02b36620 100644 --- a/libxfs/xfs_bmap_btree.c +++ b/libxfs/xfs_bmap_btree.c @@ -609,7 +609,7 @@ 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) + 1; } /* diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h index 9934c320..d3dfd45c 100644 --- a/libxfs/xfs_format.h +++ b/libxfs/xfs_format.h @@ -872,10 +872,22 @@ enum xfs_dinode_fmt { /* * Max values for extlen, extnum, aextnum. - */ -#define MAXEXTLEN ((xfs_extlen_t)0x001fffff) /* 21 bits */ -#define MAXEXTNUM ((xfs_extnum_t)0x7fffffff) /* signed int */ -#define MAXAEXTNUM ((xfs_aextnum_t)0x7fff) /* signed short */ + * + * The newly introduced data fork extent counter is a 64-bit field. However, the + * maximum number of extents in a file is limited to 2^54 extents (assuming one + * blocks per extent) by the 54-bit wide startoff field of an extent record. + * + * A further limitation applies as shown below, + * 2^63 (max file size) / 64k (max block size) = 2^47 + * + * 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 MAXEXTLEN ((xfs_extlen_t)((1ULL << 21) - 1)) /* 21 bits */ +#define XFS_MAX_EXTCNT_DATA_FORK ((xfs_extnum_t)((1ULL << 48) - 1)) /* Unsigned 48-bits */ +#define XFS_MAX_EXTCNT_ATTR_FORK ((xfs_extnum_t)((1ULL << 32) - 1)) /* Unsigned 32-bits */ +#define XFS_MAX_EXTCNT_DATA_FORK_OLD ((xfs_extnum_t)((1ULL << 31) - 1)) /* Signed 32-bits */ +#define XFS_MAX_EXTCNT_ATTR_FORK_OLD ((xfs_extnum_t)((1ULL << 15) - 1)) /* Signed 16-bits */ /* * Inode minimum and maximum sizes. diff --git a/libxfs/xfs_inode_buf.c b/libxfs/xfs_inode_buf.c index 29204e4a..b3f6be93 100644 --- a/libxfs/xfs_inode_buf.c +++ b/libxfs/xfs_inode_buf.c @@ -358,7 +358,8 @@ 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_nrext64(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 f7fa0af5..9e80396a 100644 --- a/libxfs/xfs_inode_fork.c +++ b/libxfs/xfs_inode_fork.c @@ -743,7 +743,7 @@ 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_nrext64(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..e5680343 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_nrext64, + 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_nrext64 ? XFS_MAX_EXTCNT_DATA_FORK + : XFS_MAX_EXTCNT_DATA_FORK_OLD; + + case XFS_ATTR_FORK: + return has_nrext64 ? XFS_MAX_EXTCNT_ATTR_FORK + : XFS_MAX_EXTCNT_ATTR_FORK_OLD; - return MAXAEXTNUM; + default: + ASSERT(0); + return 0; + } } static inline xfs_extnum_t diff --git a/repair/dinode.c b/repair/dinode.c index 4cfc6352..54efe571 100644 --- a/repair/dinode.c +++ b/repair/dinode.c @@ -1804,7 +1804,8 @@ _("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_nrext64(dino), + XFS_DATA_FORK)) { do_warn( _("too many data fork extents (%" PRIu64 ") in inode %" PRIu64 "\n"), nextents, lino); @@ -1826,7 +1827,8 @@ _("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_nrext64(dino), + XFS_ATTR_FORK)) { do_warn( _("too many attr fork extents (%" PRIu64 ") in inode %" PRIu64 "\n"), anextents, lino); -- 2.30.2