Skip to content

Commit 0ed5f73

Browse files
author
Darrick J. Wong
committed
xfs: compute absolute maximum nlevels for each btree type
Add code for all five btree types so that we can compute the absolute maximum possible btree height for each btree type. This is a setup for the next patch, which makes every btree type have its own cursor cache. The functions are exported so that we can have xfs_db report the absolute maximum btree heights for each btree type, rather than making everyone run their own ad-hoc computations. Signed-off-by: Darrick J. Wong <[email protected]> Reviewed-by: Dave Chinner <[email protected]>
1 parent bc8883e commit 0ed5f73

14 files changed

+203
-17
lines changed

fs/xfs/libxfs/xfs_alloc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2198,6 +2198,7 @@ xfs_alloc_compute_maxlevels(
21982198
{
21992199
mp->m_alloc_maxlevels = xfs_btree_compute_maxlevels(mp->m_alloc_mnr,
22002200
(mp->m_sb.sb_agblocks + 1) / 2);
2201+
ASSERT(mp->m_alloc_maxlevels <= xfs_allocbt_maxlevels_ondisk());
22012202
}
22022203

22032204
/*

fs/xfs/libxfs/xfs_alloc_btree.c

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,17 @@ xfs_allocbt_commit_staged_btree(
566566
}
567567
}
568568

569+
/* Calculate number of records in an alloc btree block. */
570+
static inline unsigned int
571+
xfs_allocbt_block_maxrecs(
572+
unsigned int blocklen,
573+
bool leaf)
574+
{
575+
if (leaf)
576+
return blocklen / sizeof(xfs_alloc_rec_t);
577+
return blocklen / (sizeof(xfs_alloc_key_t) + sizeof(xfs_alloc_ptr_t));
578+
}
579+
569580
/*
570581
* Calculate number of records in an alloc btree block.
571582
*/
@@ -576,10 +587,26 @@ xfs_allocbt_maxrecs(
576587
int leaf)
577588
{
578589
blocklen -= XFS_ALLOC_BLOCK_LEN(mp);
590+
return xfs_allocbt_block_maxrecs(blocklen, leaf);
591+
}
579592

580-
if (leaf)
581-
return blocklen / sizeof(xfs_alloc_rec_t);
582-
return blocklen / (sizeof(xfs_alloc_key_t) + sizeof(xfs_alloc_ptr_t));
593+
/* Free space btrees are at their largest when every other block is free. */
594+
#define XFS_MAX_FREESP_RECORDS ((XFS_MAX_AG_BLOCKS + 1) / 2)
595+
596+
/* Compute the max possible height for free space btrees. */
597+
unsigned int
598+
xfs_allocbt_maxlevels_ondisk(void)
599+
{
600+
unsigned int minrecs[2];
601+
unsigned int blocklen;
602+
603+
blocklen = min(XFS_MIN_BLOCKSIZE - XFS_BTREE_SBLOCK_LEN,
604+
XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_SBLOCK_CRC_LEN);
605+
606+
minrecs[0] = xfs_allocbt_block_maxrecs(blocklen, true) / 2;
607+
minrecs[1] = xfs_allocbt_block_maxrecs(blocklen, false) / 2;
608+
609+
return xfs_btree_compute_maxlevels(minrecs, XFS_MAX_FREESP_RECORDS);
583610
}
584611

585612
/* Calculate the freespace btree size for some records. */

fs/xfs/libxfs/xfs_alloc_btree.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,6 @@ extern xfs_extlen_t xfs_allocbt_calc_size(struct xfs_mount *mp,
6060
void xfs_allocbt_commit_staged_btree(struct xfs_btree_cur *cur,
6161
struct xfs_trans *tp, struct xfs_buf *agbp);
6262

63+
unsigned int xfs_allocbt_maxlevels_ondisk(void);
64+
6365
#endif /* __XFS_ALLOC_BTREE_H__ */

fs/xfs/libxfs/xfs_bmap.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ xfs_bmap_compute_maxlevels(
9393
maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs;
9494
}
9595
mp->m_bm_maxlevels[whichfork] = level;
96+
ASSERT(mp->m_bm_maxlevels[whichfork] <= xfs_bmbt_maxlevels_ondisk());
9697
}
9798

9899
unsigned int

fs/xfs/libxfs/xfs_bmap_btree.c

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,17 @@ xfs_bmbt_init_cursor(
571571
return cur;
572572
}
573573

574+
/* Calculate number of records in a block mapping btree block. */
575+
static inline unsigned int
576+
xfs_bmbt_block_maxrecs(
577+
unsigned int blocklen,
578+
bool leaf)
579+
{
580+
if (leaf)
581+
return blocklen / sizeof(xfs_bmbt_rec_t);
582+
return blocklen / (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t));
583+
}
584+
574585
/*
575586
* Calculate number of records in a bmap btree block.
576587
*/
@@ -581,10 +592,24 @@ xfs_bmbt_maxrecs(
581592
int leaf)
582593
{
583594
blocklen -= XFS_BMBT_BLOCK_LEN(mp);
595+
return xfs_bmbt_block_maxrecs(blocklen, leaf);
596+
}
584597

585-
if (leaf)
586-
return blocklen / sizeof(xfs_bmbt_rec_t);
587-
return blocklen / (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t));
598+
/* Compute the max possible height for block mapping btrees. */
599+
unsigned int
600+
xfs_bmbt_maxlevels_ondisk(void)
601+
{
602+
unsigned int minrecs[2];
603+
unsigned int blocklen;
604+
605+
blocklen = min(XFS_MIN_BLOCKSIZE - XFS_BTREE_SBLOCK_LEN,
606+
XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_SBLOCK_CRC_LEN);
607+
608+
minrecs[0] = xfs_bmbt_block_maxrecs(blocklen, true) / 2;
609+
minrecs[1] = xfs_bmbt_block_maxrecs(blocklen, false) / 2;
610+
611+
/* One extra level for the inode root. */
612+
return xfs_btree_compute_maxlevels(minrecs, MAXEXTNUM) + 1;
588613
}
589614

590615
/*

fs/xfs/libxfs/xfs_bmap_btree.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,6 @@ extern struct xfs_btree_cur *xfs_bmbt_init_cursor(struct xfs_mount *,
110110
extern unsigned long long xfs_bmbt_calc_size(struct xfs_mount *mp,
111111
unsigned long long len);
112112

113+
unsigned int xfs_bmbt_maxlevels_ondisk(void);
114+
113115
#endif /* __XFS_BMAP_BTREE_H__ */

fs/xfs/libxfs/xfs_fs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,8 @@ typedef struct xfs_fsop_resblks {
268268
*/
269269
#define XFS_MIN_AG_BYTES (1ULL << 24) /* 16 MB */
270270
#define XFS_MAX_AG_BYTES (1ULL << 40) /* 1 TB */
271+
#define XFS_MAX_AG_BLOCKS (XFS_MAX_AG_BYTES / XFS_MIN_BLOCKSIZE)
272+
#define XFS_MAX_CRC_AG_BLOCKS (XFS_MAX_AG_BYTES / XFS_MIN_CRC_BLOCKSIZE)
271273

272274
/* keep the maximum size under 2^31 by a small amount */
273275
#define XFS_MAX_LOG_BYTES \

fs/xfs/libxfs/xfs_ialloc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2793,6 +2793,7 @@ xfs_ialloc_setup_geometry(
27932793
inodes = (1LL << XFS_INO_AGINO_BITS(mp)) >> XFS_INODES_PER_CHUNK_LOG;
27942794
igeo->inobt_maxlevels = xfs_btree_compute_maxlevels(igeo->inobt_mnr,
27952795
inodes);
2796+
ASSERT(igeo->inobt_maxlevels <= xfs_iallocbt_maxlevels_ondisk());
27962797

27972798
/*
27982799
* Set the maximum inode count for this filesystem, being careful not

fs/xfs/libxfs/xfs_ialloc_btree.c

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,17 @@ xfs_inobt_commit_staged_btree(
526526
}
527527
}
528528

529+
/* Calculate number of records in an inode btree block. */
530+
static inline unsigned int
531+
xfs_inobt_block_maxrecs(
532+
unsigned int blocklen,
533+
bool leaf)
534+
{
535+
if (leaf)
536+
return blocklen / sizeof(xfs_inobt_rec_t);
537+
return blocklen / (sizeof(xfs_inobt_key_t) + sizeof(xfs_inobt_ptr_t));
538+
}
539+
529540
/*
530541
* Calculate number of records in an inobt btree block.
531542
*/
@@ -536,10 +547,54 @@ xfs_inobt_maxrecs(
536547
int leaf)
537548
{
538549
blocklen -= XFS_INOBT_BLOCK_LEN(mp);
550+
return xfs_inobt_block_maxrecs(blocklen, leaf);
551+
}
539552

540-
if (leaf)
541-
return blocklen / sizeof(xfs_inobt_rec_t);
542-
return blocklen / (sizeof(xfs_inobt_key_t) + sizeof(xfs_inobt_ptr_t));
553+
/*
554+
* Maximum number of inode btree records per AG. Pretend that we can fill an
555+
* entire AG completely full of inodes except for the AG headers.
556+
*/
557+
#define XFS_MAX_INODE_RECORDS \
558+
((XFS_MAX_AG_BYTES - (4 * BBSIZE)) / XFS_DINODE_MIN_SIZE) / \
559+
XFS_INODES_PER_CHUNK
560+
561+
/* Compute the max possible height for the inode btree. */
562+
static inline unsigned int
563+
xfs_inobt_maxlevels_ondisk(void)
564+
{
565+
unsigned int minrecs[2];
566+
unsigned int blocklen;
567+
568+
blocklen = min(XFS_MIN_BLOCKSIZE - XFS_BTREE_SBLOCK_LEN,
569+
XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_SBLOCK_CRC_LEN);
570+
571+
minrecs[0] = xfs_inobt_block_maxrecs(blocklen, true) / 2;
572+
minrecs[1] = xfs_inobt_block_maxrecs(blocklen, false) / 2;
573+
574+
return xfs_btree_compute_maxlevels(minrecs, XFS_MAX_INODE_RECORDS);
575+
}
576+
577+
/* Compute the max possible height for the free inode btree. */
578+
static inline unsigned int
579+
xfs_finobt_maxlevels_ondisk(void)
580+
{
581+
unsigned int minrecs[2];
582+
unsigned int blocklen;
583+
584+
blocklen = XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_SBLOCK_CRC_LEN;
585+
586+
minrecs[0] = xfs_inobt_block_maxrecs(blocklen, true) / 2;
587+
minrecs[1] = xfs_inobt_block_maxrecs(blocklen, false) / 2;
588+
589+
return xfs_btree_compute_maxlevels(minrecs, XFS_MAX_INODE_RECORDS);
590+
}
591+
592+
/* Compute the max possible height for either inode btree. */
593+
unsigned int
594+
xfs_iallocbt_maxlevels_ondisk(void)
595+
{
596+
return max(xfs_inobt_maxlevels_ondisk(),
597+
xfs_finobt_maxlevels_ondisk());
543598
}
544599

545600
/*

fs/xfs/libxfs/xfs_ialloc_btree.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,6 @@ int xfs_inobt_cur(struct xfs_mount *mp, struct xfs_trans *tp,
7575
void xfs_inobt_commit_staged_btree(struct xfs_btree_cur *cur,
7676
struct xfs_trans *tp, struct xfs_buf *agbp);
7777

78+
unsigned int xfs_iallocbt_maxlevels_ondisk(void);
79+
7880
#endif /* __XFS_IALLOC_BTREE_H__ */

0 commit comments

Comments
 (0)