Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <djwong@kernel.org>
Reviewed-by: Dave Chinner <dchinner@redhat.com>

+203 -17
+1
fs/xfs/libxfs/xfs_alloc.c
··· 2198 2198 { 2199 2199 mp->m_alloc_maxlevels = xfs_btree_compute_maxlevels(mp->m_alloc_mnr, 2200 2200 (mp->m_sb.sb_agblocks + 1) / 2); 2201 + ASSERT(mp->m_alloc_maxlevels <= xfs_allocbt_maxlevels_ondisk()); 2201 2202 } 2202 2203 2203 2204 /*
+30 -3
fs/xfs/libxfs/xfs_alloc_btree.c
··· 566 566 } 567 567 } 568 568 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 + 569 580 /* 570 581 * Calculate number of records in an alloc btree block. 571 582 */ ··· 587 576 int leaf) 588 577 { 589 578 blocklen -= XFS_ALLOC_BLOCK_LEN(mp); 579 + return xfs_allocbt_block_maxrecs(blocklen, leaf); 580 + } 590 581 591 - if (leaf) 592 - return blocklen / sizeof(xfs_alloc_rec_t); 593 - return blocklen / (sizeof(xfs_alloc_key_t) + sizeof(xfs_alloc_ptr_t)); 582 + /* Free space btrees are at their largest when every other block is free. */ 583 + #define XFS_MAX_FREESP_RECORDS ((XFS_MAX_AG_BLOCKS + 1) / 2) 584 + 585 + /* Compute the max possible height for free space btrees. */ 586 + unsigned int 587 + xfs_allocbt_maxlevels_ondisk(void) 588 + { 589 + unsigned int minrecs[2]; 590 + unsigned int blocklen; 591 + 592 + blocklen = min(XFS_MIN_BLOCKSIZE - XFS_BTREE_SBLOCK_LEN, 593 + XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_SBLOCK_CRC_LEN); 594 + 595 + minrecs[0] = xfs_allocbt_block_maxrecs(blocklen, true) / 2; 596 + minrecs[1] = xfs_allocbt_block_maxrecs(blocklen, false) / 2; 597 + 598 + return xfs_btree_compute_maxlevels(minrecs, XFS_MAX_FREESP_RECORDS); 594 599 } 595 600 596 601 /* Calculate the freespace btree size for some records. */
+2
fs/xfs/libxfs/xfs_alloc_btree.h
··· 60 60 void xfs_allocbt_commit_staged_btree(struct xfs_btree_cur *cur, 61 61 struct xfs_trans *tp, struct xfs_buf *agbp); 62 62 63 + unsigned int xfs_allocbt_maxlevels_ondisk(void); 64 + 63 65 #endif /* __XFS_ALLOC_BTREE_H__ */
+1
fs/xfs/libxfs/xfs_bmap.c
··· 93 93 maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs; 94 94 } 95 95 mp->m_bm_maxlevels[whichfork] = level; 96 + ASSERT(mp->m_bm_maxlevels[whichfork] <= xfs_bmbt_maxlevels_ondisk()); 96 97 } 97 98 98 99 unsigned int
+28 -3
fs/xfs/libxfs/xfs_bmap_btree.c
··· 571 571 return cur; 572 572 } 573 573 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 + 574 585 /* 575 586 * Calculate number of records in a bmap btree block. 576 587 */ ··· 592 581 int leaf) 593 582 { 594 583 blocklen -= XFS_BMBT_BLOCK_LEN(mp); 584 + return xfs_bmbt_block_maxrecs(blocklen, leaf); 585 + } 595 586 596 - if (leaf) 597 - return blocklen / sizeof(xfs_bmbt_rec_t); 598 - return blocklen / (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t)); 587 + /* Compute the max possible height for block mapping btrees. */ 588 + unsigned int 589 + xfs_bmbt_maxlevels_ondisk(void) 590 + { 591 + unsigned int minrecs[2]; 592 + unsigned int blocklen; 593 + 594 + blocklen = min(XFS_MIN_BLOCKSIZE - XFS_BTREE_SBLOCK_LEN, 595 + XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_SBLOCK_CRC_LEN); 596 + 597 + minrecs[0] = xfs_bmbt_block_maxrecs(blocklen, true) / 2; 598 + minrecs[1] = xfs_bmbt_block_maxrecs(blocklen, false) / 2; 599 + 600 + /* One extra level for the inode root. */ 601 + return xfs_btree_compute_maxlevels(minrecs, MAXEXTNUM) + 1; 599 602 } 600 603 601 604 /*
+2
fs/xfs/libxfs/xfs_bmap_btree.h
··· 110 110 extern unsigned long long xfs_bmbt_calc_size(struct xfs_mount *mp, 111 111 unsigned long long len); 112 112 113 + unsigned int xfs_bmbt_maxlevels_ondisk(void); 114 + 113 115 #endif /* __XFS_BMAP_BTREE_H__ */
+2
fs/xfs/libxfs/xfs_fs.h
··· 268 268 */ 269 269 #define XFS_MIN_AG_BYTES (1ULL << 24) /* 16 MB */ 270 270 #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) 271 273 272 274 /* keep the maximum size under 2^31 by a small amount */ 273 275 #define XFS_MAX_LOG_BYTES \
+1
fs/xfs/libxfs/xfs_ialloc.c
··· 2793 2793 inodes = (1LL << XFS_INO_AGINO_BITS(mp)) >> XFS_INODES_PER_CHUNK_LOG; 2794 2794 igeo->inobt_maxlevels = xfs_btree_compute_maxlevels(igeo->inobt_mnr, 2795 2795 inodes); 2796 + ASSERT(igeo->inobt_maxlevels <= xfs_iallocbt_maxlevels_ondisk()); 2796 2797 2797 2798 /* 2798 2799 * Set the maximum inode count for this filesystem, being careful not
+58 -3
fs/xfs/libxfs/xfs_ialloc_btree.c
··· 526 526 } 527 527 } 528 528 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 + 529 540 /* 530 541 * Calculate number of records in an inobt btree block. 531 542 */ ··· 547 536 int leaf) 548 537 { 549 538 blocklen -= XFS_INOBT_BLOCK_LEN(mp); 539 + return xfs_inobt_block_maxrecs(blocklen, leaf); 540 + } 550 541 551 - if (leaf) 552 - return blocklen / sizeof(xfs_inobt_rec_t); 553 - return blocklen / (sizeof(xfs_inobt_key_t) + sizeof(xfs_inobt_ptr_t)); 542 + /* 543 + * Maximum number of inode btree records per AG. Pretend that we can fill an 544 + * entire AG completely full of inodes except for the AG headers. 545 + */ 546 + #define XFS_MAX_INODE_RECORDS \ 547 + ((XFS_MAX_AG_BYTES - (4 * BBSIZE)) / XFS_DINODE_MIN_SIZE) / \ 548 + XFS_INODES_PER_CHUNK 549 + 550 + /* Compute the max possible height for the inode btree. */ 551 + static inline unsigned int 552 + xfs_inobt_maxlevels_ondisk(void) 553 + { 554 + unsigned int minrecs[2]; 555 + unsigned int blocklen; 556 + 557 + blocklen = min(XFS_MIN_BLOCKSIZE - XFS_BTREE_SBLOCK_LEN, 558 + XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_SBLOCK_CRC_LEN); 559 + 560 + minrecs[0] = xfs_inobt_block_maxrecs(blocklen, true) / 2; 561 + minrecs[1] = xfs_inobt_block_maxrecs(blocklen, false) / 2; 562 + 563 + return xfs_btree_compute_maxlevels(minrecs, XFS_MAX_INODE_RECORDS); 564 + } 565 + 566 + /* Compute the max possible height for the free inode btree. */ 567 + static inline unsigned int 568 + xfs_finobt_maxlevels_ondisk(void) 569 + { 570 + unsigned int minrecs[2]; 571 + unsigned int blocklen; 572 + 573 + blocklen = XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_SBLOCK_CRC_LEN; 574 + 575 + minrecs[0] = xfs_inobt_block_maxrecs(blocklen, true) / 2; 576 + minrecs[1] = xfs_inobt_block_maxrecs(blocklen, false) / 2; 577 + 578 + return xfs_btree_compute_maxlevels(minrecs, XFS_MAX_INODE_RECORDS); 579 + } 580 + 581 + /* Compute the max possible height for either inode btree. */ 582 + unsigned int 583 + xfs_iallocbt_maxlevels_ondisk(void) 584 + { 585 + return max(xfs_inobt_maxlevels_ondisk(), 586 + xfs_finobt_maxlevels_ondisk()); 554 587 } 555 588 556 589 /*
+2
fs/xfs/libxfs/xfs_ialloc_btree.h
··· 75 75 void xfs_inobt_commit_staged_btree(struct xfs_btree_cur *cur, 76 76 struct xfs_trans *tp, struct xfs_buf *agbp); 77 77 78 + unsigned int xfs_iallocbt_maxlevels_ondisk(void); 79 + 78 80 #endif /* __XFS_IALLOC_BTREE_H__ */
+33 -4
fs/xfs/libxfs/xfs_refcount_btree.c
··· 393 393 xfs_btree_commit_afakeroot(cur, tp, agbp, &xfs_refcountbt_ops); 394 394 } 395 395 396 + /* Calculate number of records in a refcount btree block. */ 397 + static inline unsigned int 398 + xfs_refcountbt_block_maxrecs( 399 + unsigned int blocklen, 400 + bool leaf) 401 + { 402 + if (leaf) 403 + return blocklen / sizeof(struct xfs_refcount_rec); 404 + return blocklen / (sizeof(struct xfs_refcount_key) + 405 + sizeof(xfs_refcount_ptr_t)); 406 + } 407 + 396 408 /* 397 409 * Calculate the number of records in a refcount btree block. 398 410 */ ··· 414 402 bool leaf) 415 403 { 416 404 blocklen -= XFS_REFCOUNT_BLOCK_LEN; 405 + return xfs_refcountbt_block_maxrecs(blocklen, leaf); 406 + } 417 407 418 - if (leaf) 419 - return blocklen / sizeof(struct xfs_refcount_rec); 420 - return blocklen / (sizeof(struct xfs_refcount_key) + 421 - sizeof(xfs_refcount_ptr_t)); 408 + /* Compute the max possible height of the maximally sized refcount btree. */ 409 + unsigned int 410 + xfs_refcountbt_maxlevels_ondisk(void) 411 + { 412 + unsigned int minrecs[2]; 413 + unsigned int blocklen; 414 + 415 + blocklen = XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_SBLOCK_CRC_LEN; 416 + 417 + minrecs[0] = xfs_refcountbt_block_maxrecs(blocklen, true) / 2; 418 + minrecs[1] = xfs_refcountbt_block_maxrecs(blocklen, false) / 2; 419 + 420 + return xfs_btree_compute_maxlevels(minrecs, XFS_MAX_CRC_AG_BLOCKS); 422 421 } 423 422 424 423 /* Compute the maximum height of a refcount btree. */ ··· 437 414 xfs_refcountbt_compute_maxlevels( 438 415 struct xfs_mount *mp) 439 416 { 417 + if (!xfs_has_reflink(mp)) { 418 + mp->m_refc_maxlevels = 0; 419 + return; 420 + } 421 + 440 422 mp->m_refc_maxlevels = xfs_btree_compute_maxlevels( 441 423 mp->m_refc_mnr, mp->m_sb.sb_agblocks); 424 + ASSERT(mp->m_refc_maxlevels <= xfs_refcountbt_maxlevels_ondisk()); 442 425 } 443 426 444 427 /* Calculate the refcount btree size for some records. */
+2
fs/xfs/libxfs/xfs_refcount_btree.h
··· 65 65 void xfs_refcountbt_commit_staged_btree(struct xfs_btree_cur *cur, 66 66 struct xfs_trans *tp, struct xfs_buf *agbp); 67 67 68 + unsigned int xfs_refcountbt_maxlevels_ondisk(void); 69 + 68 70 #endif /* __XFS_REFCOUNT_BTREE_H__ */
+39 -4
fs/xfs/libxfs/xfs_rmap_btree.c
··· 519 519 xfs_btree_commit_afakeroot(cur, tp, agbp, &xfs_rmapbt_ops); 520 520 } 521 521 522 + /* Calculate number of records in a reverse mapping btree block. */ 523 + static inline unsigned int 524 + xfs_rmapbt_block_maxrecs( 525 + unsigned int blocklen, 526 + bool leaf) 527 + { 528 + if (leaf) 529 + return blocklen / sizeof(struct xfs_rmap_rec); 530 + return blocklen / 531 + (2 * sizeof(struct xfs_rmap_key) + sizeof(xfs_rmap_ptr_t)); 532 + } 533 + 522 534 /* 523 535 * Calculate number of records in an rmap btree block. 524 536 */ ··· 540 528 int leaf) 541 529 { 542 530 blocklen -= XFS_RMAP_BLOCK_LEN; 531 + return xfs_rmapbt_block_maxrecs(blocklen, leaf); 532 + } 543 533 544 - if (leaf) 545 - return blocklen / sizeof(struct xfs_rmap_rec); 546 - return blocklen / 547 - (2 * sizeof(struct xfs_rmap_key) + sizeof(xfs_rmap_ptr_t)); 534 + /* Compute the max possible height for reverse mapping btrees. */ 535 + unsigned int 536 + xfs_rmapbt_maxlevels_ondisk(void) 537 + { 538 + unsigned int minrecs[2]; 539 + unsigned int blocklen; 540 + 541 + blocklen = XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_SBLOCK_CRC_LEN; 542 + 543 + minrecs[0] = xfs_rmapbt_block_maxrecs(blocklen, true) / 2; 544 + minrecs[1] = xfs_rmapbt_block_maxrecs(blocklen, false) / 2; 545 + 546 + /* 547 + * Compute the asymptotic maxlevels for an rmapbt on any reflink fs. 548 + * 549 + * On a reflink filesystem, each AG block can have up to 2^32 (per the 550 + * refcount record format) owners, which means that theoretically we 551 + * could face up to 2^64 rmap records. However, we're likely to run 552 + * out of blocks in the AG long before that happens, which means that 553 + * we must compute the max height based on what the btree will look 554 + * like if it consumes almost all the blocks in the AG due to maximal 555 + * sharing factor. 556 + */ 557 + return xfs_btree_space_to_height(minrecs, XFS_MAX_CRC_AG_BLOCKS); 548 558 } 549 559 550 560 /* Compute the maximum height of an rmap btree. */ ··· 603 569 mp->m_rmap_maxlevels = xfs_btree_compute_maxlevels( 604 570 mp->m_rmap_mnr, mp->m_sb.sb_agblocks); 605 571 } 572 + ASSERT(mp->m_rmap_maxlevels <= xfs_rmapbt_maxlevels_ondisk()); 606 573 } 607 574 608 575 /* Calculate the refcount btree size for some records. */
+2
fs/xfs/libxfs/xfs_rmap_btree.h
··· 59 59 extern int xfs_rmapbt_calc_reserves(struct xfs_mount *mp, struct xfs_trans *tp, 60 60 struct xfs_perag *pag, xfs_extlen_t *ask, xfs_extlen_t *used); 61 61 62 + unsigned int xfs_rmapbt_maxlevels_ondisk(void); 63 + 62 64 #endif /* __XFS_RMAP_BTREE_H__ */