/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2021 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ #ifndef __XFS_RTREFCOUNT_BTREE_H__ #define __XFS_RTREFCOUNT_BTREE_H__ struct xfs_buf; struct xfs_btree_cur; struct xfs_mount; struct xbtree_ifakeroot; /* refcounts only exist on crc enabled filesystems */ #define XFS_RTREFCOUNT_BLOCK_LEN XFS_BTREE_LBLOCK_CRC_LEN struct xfs_btree_cur *xfs_rtrefcountbt_init_cursor(struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_inode *ip); struct xfs_btree_cur *xfs_rtrefcountbt_stage_cursor(struct xfs_mount *mp, struct xfs_inode *ip, struct xbtree_ifakeroot *ifake); void xfs_rtrefcountbt_commit_staged_btree(struct xfs_btree_cur *cur, struct xfs_trans *tp); unsigned int xfs_rtrefcountbt_maxrecs(struct xfs_mount *mp, unsigned int blocklen, bool leaf); unsigned int xfs_rtrefcountbt_compute_maxlevels(struct xfs_mount *mp, xfs_rfsblock_t dblocks, xfs_rfsblock_t rblocks); unsigned int xfs_rtrefcountbt_droot_maxrecs(unsigned int blocklen, bool leaf); /* * Addresses of records, keys, and pointers within an incore rtrefcountbt block. * * (note that some of these may appear unused, but they are used in userspace) */ static inline struct xfs_rtrefcount_rec * xfs_rtrefcount_rec_addr( struct xfs_btree_block *block, unsigned int index) { return (struct xfs_rtrefcount_rec *) ((char *)block + XFS_RTREFCOUNT_BLOCK_LEN + (index - 1) * sizeof(struct xfs_rtrefcount_rec)); } static inline struct xfs_rtrefcount_key * xfs_rtrefcount_key_addr( struct xfs_btree_block *block, unsigned int index) { return (struct xfs_rtrefcount_key *) ((char *)block + XFS_RTREFCOUNT_BLOCK_LEN + (index - 1) * sizeof(struct xfs_rtrefcount_key)); } static inline xfs_rtrefcount_ptr_t * xfs_rtrefcount_ptr_addr( struct xfs_btree_block *block, unsigned int index, unsigned int maxrecs) { return (xfs_rtrefcount_ptr_t *) ((char *)block + XFS_RTREFCOUNT_BLOCK_LEN + maxrecs * sizeof(struct xfs_rtrefcount_key) + (index - 1) * sizeof(xfs_rtrefcount_ptr_t)); } int __init xfs_rtrefcountbt_create_cursor_cache(void); xfs_filblks_t xfs_rtrefcountbt_calc_reserves(struct xfs_mount *mp); /* Addresses of key, pointers, and records within an ondisk rtrefcount block. */ static inline struct xfs_rtrefcount_rec * xfs_rtrefcount_droot_rec_addr( struct xfs_rtrefcount_root *block, unsigned int index) { return (struct xfs_rtrefcount_rec *) ((char *)(block + 1) + (index - 1) * sizeof(struct xfs_rtrefcount_rec)); } static inline struct xfs_rtrefcount_key * xfs_rtrefcount_droot_key_addr( struct xfs_rtrefcount_root *block, unsigned int index) { return (struct xfs_rtrefcount_key *) ((char *)(block + 1) + (index - 1) * sizeof(struct xfs_rtrefcount_key)); } static inline xfs_rtrefcount_ptr_t * xfs_rtrefcount_droot_ptr_addr( struct xfs_rtrefcount_root *block, unsigned int index, unsigned int maxrecs) { return (xfs_rtrefcount_ptr_t *) ((char *)(block + 1) + maxrecs * sizeof(struct xfs_rtrefcount_key) + (index - 1) * sizeof(xfs_rtrefcount_ptr_t)); } /* * Address of pointers within the incore btree root. * * These are to be used when we know the size of the block and * we don't have a cursor. */ static inline xfs_rtrefcount_ptr_t * xfs_rtrefcount_broot_ptr_addr( struct xfs_mount *mp, struct xfs_btree_block *bb, unsigned int index, unsigned int block_size) { return xfs_rtrefcount_ptr_addr(bb, index, xfs_rtrefcountbt_maxrecs(mp, block_size, false)); } /* * Compute the space required for the incore btree root containing the given * number of records. */ static inline size_t xfs_rtrefcount_broot_space_calc( struct xfs_mount *mp, unsigned int level, unsigned int nrecs) { size_t sz = XFS_RTREFCOUNT_BLOCK_LEN; if (level > 0) return sz + nrecs * (sizeof(struct xfs_rtrefcount_key) + sizeof(xfs_rtrefcount_ptr_t)); return sz + nrecs * sizeof(struct xfs_rtrefcount_rec); } /* * Compute the space required for the incore btree root given the ondisk * btree root block. */ static inline size_t xfs_rtrefcount_broot_space(struct xfs_mount *mp, struct xfs_rtrefcount_root *bb) { return xfs_rtrefcount_broot_space_calc(mp, be16_to_cpu(bb->bb_level), be16_to_cpu(bb->bb_numrecs)); } /* Compute the space required for the ondisk root block. */ static inline size_t xfs_rtrefcount_droot_space_calc( unsigned int level, unsigned int nrecs) { size_t sz = sizeof(struct xfs_rtrefcount_root); if (level > 0) return sz + nrecs * (sizeof(struct xfs_rtrefcount_key) + sizeof(xfs_rtrefcount_ptr_t)); return sz + nrecs * sizeof(struct xfs_rtrefcount_rec); } /* * Compute the space required for the ondisk root block given an incore root * block. */ static inline size_t xfs_rtrefcount_droot_space(struct xfs_btree_block *bb) { return xfs_rtrefcount_droot_space_calc(be16_to_cpu(bb->bb_level), be16_to_cpu(bb->bb_numrecs)); } int xfs_iformat_rtrefcount(struct xfs_inode *ip, struct xfs_dinode *dip); void xfs_rtrefcountbt_to_disk(struct xfs_mount *mp, struct xfs_btree_block *rblock, int rblocklen, struct xfs_rtrefcount_root *dblock, int dblocklen); void xfs_iflush_rtrefcount(struct xfs_inode *ip, struct xfs_dinode *dip); struct xfs_imeta_end; int xfs_rtrefcountbt_create(struct xfs_trans **tpp, struct xfs_imeta_end *ic, struct xfs_inode **ipp); #endif /* __XFS_RTREFCOUNT_BTREE_H__ */