|
22 | 22 | #include "xfs_extent_busy.h" |
23 | 23 | #include "xfs_ag.h" |
24 | 24 | #include "xfs_ag_resv.h" |
| 25 | +#include "xfs_buf_mem.h" |
| 26 | +#include "xfs_btree_mem.h" |
25 | 27 |
|
26 | 28 | static struct kmem_cache *xfs_rmapbt_cur_cache; |
27 | 29 |
|
@@ -541,6 +543,151 @@ xfs_rmapbt_init_cursor( |
541 | 543 | return cur; |
542 | 544 | } |
543 | 545 |
|
| 546 | +#ifdef CONFIG_XFS_BTREE_IN_MEM |
| 547 | +static inline unsigned int |
| 548 | +xfs_rmapbt_mem_block_maxrecs( |
| 549 | + unsigned int blocklen, |
| 550 | + bool leaf) |
| 551 | +{ |
| 552 | + if (leaf) |
| 553 | + return blocklen / sizeof(struct xfs_rmap_rec); |
| 554 | + return blocklen / |
| 555 | + (2 * sizeof(struct xfs_rmap_key) + sizeof(__be64)); |
| 556 | +} |
| 557 | + |
| 558 | +/* |
| 559 | + * Validate an in-memory rmap btree block. Callers are allowed to generate an |
| 560 | + * in-memory btree even if the ondisk feature is not enabled. |
| 561 | + */ |
| 562 | +static xfs_failaddr_t |
| 563 | +xfs_rmapbt_mem_verify( |
| 564 | + struct xfs_buf *bp) |
| 565 | +{ |
| 566 | + struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); |
| 567 | + xfs_failaddr_t fa; |
| 568 | + unsigned int level; |
| 569 | + unsigned int maxrecs; |
| 570 | + |
| 571 | + if (!xfs_verify_magic(bp, block->bb_magic)) |
| 572 | + return __this_address; |
| 573 | + |
| 574 | + fa = xfs_btree_fsblock_v5hdr_verify(bp, XFS_RMAP_OWN_UNKNOWN); |
| 575 | + if (fa) |
| 576 | + return fa; |
| 577 | + |
| 578 | + level = be16_to_cpu(block->bb_level); |
| 579 | + if (level >= xfs_rmapbt_maxlevels_ondisk()) |
| 580 | + return __this_address; |
| 581 | + |
| 582 | + maxrecs = xfs_rmapbt_mem_block_maxrecs( |
| 583 | + XFBNO_BLOCKSIZE - XFS_BTREE_LBLOCK_CRC_LEN, level == 0); |
| 584 | + return xfs_btree_memblock_verify(bp, maxrecs); |
| 585 | +} |
| 586 | + |
| 587 | +static void |
| 588 | +xfs_rmapbt_mem_rw_verify( |
| 589 | + struct xfs_buf *bp) |
| 590 | +{ |
| 591 | + xfs_failaddr_t fa = xfs_rmapbt_mem_verify(bp); |
| 592 | + |
| 593 | + if (fa) |
| 594 | + xfs_verifier_error(bp, -EFSCORRUPTED, fa); |
| 595 | +} |
| 596 | + |
| 597 | +/* skip crc checks on in-memory btrees to save time */ |
| 598 | +static const struct xfs_buf_ops xfs_rmapbt_mem_buf_ops = { |
| 599 | + .name = "xfs_rmapbt_mem", |
| 600 | + .magic = { 0, cpu_to_be32(XFS_RMAP_CRC_MAGIC) }, |
| 601 | + .verify_read = xfs_rmapbt_mem_rw_verify, |
| 602 | + .verify_write = xfs_rmapbt_mem_rw_verify, |
| 603 | + .verify_struct = xfs_rmapbt_mem_verify, |
| 604 | +}; |
| 605 | + |
| 606 | +const struct xfs_btree_ops xfs_rmapbt_mem_ops = { |
| 607 | + .name = "mem_rmap", |
| 608 | + .type = XFS_BTREE_TYPE_MEM, |
| 609 | + .geom_flags = XFS_BTGEO_OVERLAPPING, |
| 610 | + |
| 611 | + .rec_len = sizeof(struct xfs_rmap_rec), |
| 612 | + /* Overlapping btree; 2 keys per pointer. */ |
| 613 | + .key_len = 2 * sizeof(struct xfs_rmap_key), |
| 614 | + .ptr_len = XFS_BTREE_LONG_PTR_LEN, |
| 615 | + |
| 616 | + .lru_refs = XFS_RMAP_BTREE_REF, |
| 617 | + .statoff = XFS_STATS_CALC_INDEX(xs_rmap_mem_2), |
| 618 | + |
| 619 | + .dup_cursor = xfbtree_dup_cursor, |
| 620 | + .set_root = xfbtree_set_root, |
| 621 | + .alloc_block = xfbtree_alloc_block, |
| 622 | + .free_block = xfbtree_free_block, |
| 623 | + .get_minrecs = xfbtree_get_minrecs, |
| 624 | + .get_maxrecs = xfbtree_get_maxrecs, |
| 625 | + .init_key_from_rec = xfs_rmapbt_init_key_from_rec, |
| 626 | + .init_high_key_from_rec = xfs_rmapbt_init_high_key_from_rec, |
| 627 | + .init_rec_from_cur = xfs_rmapbt_init_rec_from_cur, |
| 628 | + .init_ptr_from_cur = xfbtree_init_ptr_from_cur, |
| 629 | + .key_diff = xfs_rmapbt_key_diff, |
| 630 | + .buf_ops = &xfs_rmapbt_mem_buf_ops, |
| 631 | + .diff_two_keys = xfs_rmapbt_diff_two_keys, |
| 632 | + .keys_inorder = xfs_rmapbt_keys_inorder, |
| 633 | + .recs_inorder = xfs_rmapbt_recs_inorder, |
| 634 | + .keys_contiguous = xfs_rmapbt_keys_contiguous, |
| 635 | +}; |
| 636 | + |
| 637 | +/* Create a cursor for an in-memory btree. */ |
| 638 | +struct xfs_btree_cur * |
| 639 | +xfs_rmapbt_mem_cursor( |
| 640 | + struct xfs_perag *pag, |
| 641 | + struct xfs_trans *tp, |
| 642 | + struct xfbtree *xfbt) |
| 643 | +{ |
| 644 | + struct xfs_btree_cur *cur; |
| 645 | + struct xfs_mount *mp = pag->pag_mount; |
| 646 | + |
| 647 | + cur = xfs_btree_alloc_cursor(mp, tp, &xfs_rmapbt_mem_ops, |
| 648 | + xfs_rmapbt_maxlevels_ondisk(), xfs_rmapbt_cur_cache); |
| 649 | + cur->bc_mem.xfbtree = xfbt; |
| 650 | + cur->bc_nlevels = xfbt->nlevels; |
| 651 | + |
| 652 | + cur->bc_mem.pag = xfs_perag_hold(pag); |
| 653 | + return cur; |
| 654 | +} |
| 655 | + |
| 656 | +/* Create an in-memory rmap btree. */ |
| 657 | +int |
| 658 | +xfs_rmapbt_mem_init( |
| 659 | + struct xfs_mount *mp, |
| 660 | + struct xfbtree *xfbt, |
| 661 | + struct xfs_buftarg *btp, |
| 662 | + xfs_agnumber_t agno) |
| 663 | +{ |
| 664 | + xfbt->owner = agno; |
| 665 | + return xfbtree_init(mp, xfbt, btp, &xfs_rmapbt_mem_ops); |
| 666 | +} |
| 667 | + |
| 668 | +/* Compute the max possible height for reverse mapping btrees in memory. */ |
| 669 | +static unsigned int |
| 670 | +xfs_rmapbt_mem_maxlevels(void) |
| 671 | +{ |
| 672 | + unsigned int minrecs[2]; |
| 673 | + unsigned int blocklen; |
| 674 | + |
| 675 | + blocklen = XFBNO_BLOCKSIZE - XFS_BTREE_LBLOCK_CRC_LEN; |
| 676 | + |
| 677 | + minrecs[0] = xfs_rmapbt_mem_block_maxrecs(blocklen, true) / 2; |
| 678 | + minrecs[1] = xfs_rmapbt_mem_block_maxrecs(blocklen, false) / 2; |
| 679 | + |
| 680 | + /* |
| 681 | + * How tall can an in-memory rmap btree become if we filled the entire |
| 682 | + * AG with rmap records? |
| 683 | + */ |
| 684 | + return xfs_btree_compute_maxlevels(minrecs, |
| 685 | + XFS_MAX_AG_BYTES / sizeof(struct xfs_rmap_rec)); |
| 686 | +} |
| 687 | +#else |
| 688 | +# define xfs_rmapbt_mem_maxlevels() (0) |
| 689 | +#endif /* CONFIG_XFS_BTREE_IN_MEM */ |
| 690 | + |
544 | 691 | /* |
545 | 692 | * Install a new reverse mapping btree root. Caller is responsible for |
546 | 693 | * invalidating and freeing the old btree blocks. |
@@ -611,7 +758,8 @@ xfs_rmapbt_maxlevels_ondisk(void) |
611 | 758 | * like if it consumes almost all the blocks in the AG due to maximal |
612 | 759 | * sharing factor. |
613 | 760 | */ |
614 | | - return xfs_btree_space_to_height(minrecs, XFS_MAX_CRC_AG_BLOCKS); |
| 761 | + return max(xfs_btree_space_to_height(minrecs, XFS_MAX_CRC_AG_BLOCKS), |
| 762 | + xfs_rmapbt_mem_maxlevels()); |
615 | 763 | } |
616 | 764 |
|
617 | 765 | /* Compute the maximum height of an rmap btree. */ |
|
0 commit comments