| // SPDX-License-Identifier: GPL-2.0 | |
| /* | |
| * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. | |
| * All Rights Reserved. | |
| */ | |
| #ifndef __XFS_RTBITMAP_H__ | |
| #define __XFS_RTBITMAP_H__ | |
| #include "xfs_rtgroup.h" | |
| struct xfs_rtalloc_args { | |
| struct xfs_rtgroup *rtg; | |
| struct xfs_mount *mp; | |
| struct xfs_trans *tp; | |
| struct xfs_buf *rbmbp; /* bitmap block buffer */ | |
| struct xfs_buf *sumbp; /* summary block buffer */ | |
| xfs_fileoff_t rbmoff; /* bitmap block number */ | |
| xfs_fileoff_t sumoff; /* summary block number */ | |
| }; | |
| static inline xfs_rtblock_t | |
| xfs_rtx_to_rtb( | |
| struct xfs_rtgroup *rtg, | |
| xfs_rtxnum_t rtx) | |
| { | |
| struct xfs_mount *mp = rtg_mount(rtg); | |
| xfs_rtblock_t start = xfs_group_start_fsb(rtg_group(rtg)); | |
| if (mp->m_rtxblklog >= 0) | |
| return start + (rtx << mp->m_rtxblklog); | |
| return start + (rtx * mp->m_sb.sb_rextsize); | |
| } | |
| /* Convert an rgbno into an rt extent number. */ | |
| static inline xfs_rtxnum_t | |
| xfs_rgbno_to_rtx( | |
| struct xfs_mount *mp, | |
| xfs_rgblock_t rgbno) | |
| { | |
| if (likely(mp->m_rtxblklog >= 0)) | |
| return rgbno >> mp->m_rtxblklog; | |
| return rgbno / mp->m_sb.sb_rextsize; | |
| } | |
| static inline uint64_t | |
| xfs_rtbxlen_to_blen( | |
| struct xfs_mount *mp, | |
| xfs_rtbxlen_t rtbxlen) | |
| { | |
| if (mp->m_rtxblklog >= 0) | |
| return rtbxlen << mp->m_rtxblklog; | |
| return rtbxlen * mp->m_sb.sb_rextsize; | |
| } | |
| static inline xfs_extlen_t | |
| xfs_rtxlen_to_extlen( | |
| struct xfs_mount *mp, | |
| xfs_rtxlen_t rtxlen) | |
| { | |
| if (mp->m_rtxblklog >= 0) | |
| return rtxlen << mp->m_rtxblklog; | |
| return rtxlen * mp->m_sb.sb_rextsize; | |
| } | |
| /* Compute the misalignment between an extent length and a realtime extent .*/ | |
| static inline unsigned int | |
| xfs_extlen_to_rtxmod( | |
| struct xfs_mount *mp, | |
| xfs_extlen_t len) | |
| { | |
| if (mp->m_rtxblklog >= 0) | |
| return len & mp->m_rtxblkmask; | |
| return len % mp->m_sb.sb_rextsize; | |
| } | |
| static inline xfs_rtxlen_t | |
| xfs_extlen_to_rtxlen( | |
| struct xfs_mount *mp, | |
| xfs_extlen_t len) | |
| { | |
| if (mp->m_rtxblklog >= 0) | |
| return len >> mp->m_rtxblklog; | |
| return len / mp->m_sb.sb_rextsize; | |
| } | |
| /* Convert an rt block count into an rt extent count. */ | |
| static inline xfs_rtbxlen_t | |
| xfs_blen_to_rtbxlen( | |
| struct xfs_mount *mp, | |
| uint64_t blen) | |
| { | |
| if (likely(mp->m_rtxblklog >= 0)) | |
| return blen >> mp->m_rtxblklog; | |
| return div_u64(blen, mp->m_sb.sb_rextsize); | |
| } | |
| /* Return the offset of a file block length within an rt extent. */ | |
| static inline xfs_extlen_t | |
| xfs_blen_to_rtxoff( | |
| struct xfs_mount *mp, | |
| xfs_filblks_t blen) | |
| { | |
| if (likely(mp->m_rtxblklog >= 0)) | |
| return blen & mp->m_rtxblkmask; | |
| return do_div(blen, mp->m_sb.sb_rextsize); | |
| } | |
| /* Round this block count up to the nearest rt extent size. */ | |
| static inline xfs_filblks_t | |
| xfs_blen_roundup_rtx( | |
| struct xfs_mount *mp, | |
| xfs_filblks_t blen) | |
| { | |
| return roundup_64(blen, mp->m_sb.sb_rextsize); | |
| } | |
| /* Convert an rt block number into an rt extent number. */ | |
| static inline xfs_rtxnum_t | |
| xfs_rtb_to_rtx( | |
| struct xfs_mount *mp, | |
| xfs_rtblock_t rtbno) | |
| { | |
| /* open-coded 64-bit masking operation */ | |
| rtbno &= mp->m_groups[XG_TYPE_RTG].blkmask; | |
| if (likely(mp->m_rtxblklog >= 0)) | |
| return rtbno >> mp->m_rtxblklog; | |
| return div_u64(rtbno, mp->m_sb.sb_rextsize); | |
| } | |
| /* Return the offset of a rtgroup block number within an rt extent. */ | |
| static inline xfs_extlen_t | |
| xfs_rgbno_to_rtxoff( | |
| struct xfs_mount *mp, | |
| xfs_rgblock_t rgbno) | |
| { | |
| return rgbno % mp->m_sb.sb_rextsize; | |
| } | |
| /* Return the offset of an rt block number within an rt extent. */ | |
| static inline xfs_extlen_t | |
| xfs_rtb_to_rtxoff( | |
| struct xfs_mount *mp, | |
| xfs_rtblock_t rtbno) | |
| { | |
| /* open-coded 64-bit masking operation */ | |
| rtbno &= mp->m_groups[XG_TYPE_RTG].blkmask; | |
| if (likely(mp->m_rtxblklog >= 0)) | |
| return rtbno & mp->m_rtxblkmask; | |
| return do_div(rtbno, mp->m_sb.sb_rextsize); | |
| } | |
| /* Round this file block offset up to the nearest rt extent size. */ | |
| static inline xfs_rtblock_t | |
| xfs_fileoff_roundup_rtx( | |
| struct xfs_mount *mp, | |
| xfs_fileoff_t off) | |
| { | |
| return roundup_64(off, mp->m_sb.sb_rextsize); | |
| } | |
| /* Round this file block offset down to the nearest rt extent size. */ | |
| static inline xfs_rtblock_t | |
| xfs_fileoff_rounddown_rtx( | |
| struct xfs_mount *mp, | |
| xfs_fileoff_t off) | |
| { | |
| return rounddown_64(off, mp->m_sb.sb_rextsize); | |
| } | |
| /* Convert an rt extent number to a file block offset in the rt bitmap file. */ | |
| static inline xfs_fileoff_t | |
| xfs_rtx_to_rbmblock( | |
| struct xfs_mount *mp, | |
| xfs_rtxnum_t rtx) | |
| { | |
| if (xfs_has_rtgroups(mp)) | |
| return div_u64(rtx, mp->m_rtx_per_rbmblock); | |
| return rtx >> mp->m_blkbit_log; | |
| } | |
| /* Convert an rt extent number to a word offset within an rt bitmap block. */ | |
| static inline unsigned int | |
| xfs_rtx_to_rbmword( | |
| struct xfs_mount *mp, | |
| xfs_rtxnum_t rtx) | |
| { | |
| if (xfs_has_rtgroups(mp)) { | |
| unsigned int mod; | |
| div_u64_rem(rtx >> XFS_NBWORDLOG, mp->m_blockwsize, &mod); | |
| return mod; | |
| } | |
| return (rtx >> XFS_NBWORDLOG) & (mp->m_blockwsize - 1); | |
| } | |
| /* Convert a file block offset in the rt bitmap file to an rt extent number. */ | |
| static inline xfs_rtxnum_t | |
| xfs_rbmblock_to_rtx( | |
| struct xfs_mount *mp, | |
| xfs_fileoff_t rbmoff) | |
| { | |
| if (xfs_has_rtgroups(mp)) | |
| return rbmoff * mp->m_rtx_per_rbmblock; | |
| return rbmoff << mp->m_blkbit_log; | |
| } | |
| /* Return a pointer to a bitmap word within a rt bitmap block. */ | |
| static inline union xfs_rtword_raw * | |
| xfs_rbmblock_wordptr( | |
| struct xfs_rtalloc_args *args, | |
| unsigned int index) | |
| { | |
| struct xfs_mount *mp = args->mp; | |
| union xfs_rtword_raw *words; | |
| struct xfs_rtbuf_blkinfo *hdr = args->rbmbp->b_addr; | |
| if (xfs_has_rtgroups(mp)) | |
| words = (union xfs_rtword_raw *)(hdr + 1); | |
| else | |
| words = args->rbmbp->b_addr; | |
| return words + index; | |
| } | |
| /* Convert an ondisk bitmap word to its incore representation. */ | |
| static inline xfs_rtword_t | |
| xfs_rtbitmap_getword( | |
| struct xfs_rtalloc_args *args, | |
| unsigned int index) | |
| { | |
| union xfs_rtword_raw *word = xfs_rbmblock_wordptr(args, index); | |
| if (xfs_has_rtgroups(args->mp)) | |
| return be32_to_cpu(word->rtg); | |
| return word->old; | |
| } | |
| /* Set an ondisk bitmap word from an incore representation. */ | |
| static inline void | |
| xfs_rtbitmap_setword( | |
| struct xfs_rtalloc_args *args, | |
| unsigned int index, | |
| xfs_rtword_t value) | |
| { | |
| union xfs_rtword_raw *word = xfs_rbmblock_wordptr(args, index); | |
| if (xfs_has_rtgroups(args->mp)) | |
| word->rtg = cpu_to_be32(value); | |
| else | |
| word->old = value; | |
| } | |
| /* | |
| * Convert a rt extent length and rt bitmap block number to a xfs_suminfo_t | |
| * offset within the rt summary file. | |
| */ | |
| static inline xfs_rtsumoff_t | |
| xfs_rtsumoffs( | |
| struct xfs_mount *mp, | |
| int log2_len, | |
| xfs_fileoff_t rbmoff) | |
| { | |
| return log2_len * mp->m_sb.sb_rbmblocks + rbmoff; | |
| } | |
| /* | |
| * Convert an xfs_suminfo_t offset to a file block offset within the rt summary | |
| * file. | |
| */ | |
| static inline xfs_fileoff_t | |
| xfs_rtsumoffs_to_block( | |
| struct xfs_mount *mp, | |
| xfs_rtsumoff_t rsumoff) | |
| { | |
| if (xfs_has_rtgroups(mp)) | |
| return rsumoff / mp->m_blockwsize; | |
| return XFS_B_TO_FSBT(mp, rsumoff * sizeof(xfs_suminfo_t)); | |
| } | |
| /* | |
| * Convert an xfs_suminfo_t offset to an info word offset within an rt summary | |
| * block. | |
| */ | |
| static inline unsigned int | |
| xfs_rtsumoffs_to_infoword( | |
| struct xfs_mount *mp, | |
| xfs_rtsumoff_t rsumoff) | |
| { | |
| unsigned int mask = mp->m_blockmask >> XFS_SUMINFOLOG; | |
| if (xfs_has_rtgroups(mp)) | |
| return rsumoff % mp->m_blockwsize; | |
| return rsumoff & mask; | |
| } | |
| /* Return a pointer to a summary info word within a rt summary block. */ | |
| static inline union xfs_suminfo_raw * | |
| xfs_rsumblock_infoptr( | |
| struct xfs_rtalloc_args *args, | |
| unsigned int index) | |
| { | |
| union xfs_suminfo_raw *info; | |
| struct xfs_rtbuf_blkinfo *hdr = args->sumbp->b_addr; | |
| if (xfs_has_rtgroups(args->mp)) | |
| info = (union xfs_suminfo_raw *)(hdr + 1); | |
| else | |
| info = args->sumbp->b_addr; | |
| return info + index; | |
| } | |
| /* Get the current value of a summary counter. */ | |
| static inline xfs_suminfo_t | |
| xfs_suminfo_get( | |
| struct xfs_rtalloc_args *args, | |
| unsigned int index) | |
| { | |
| union xfs_suminfo_raw *info = xfs_rsumblock_infoptr(args, index); | |
| if (xfs_has_rtgroups(args->mp)) | |
| return be32_to_cpu(info->rtg); | |
| return info->old; | |
| } | |
| /* Add to the current value of a summary counter and return the new value. */ | |
| static inline xfs_suminfo_t | |
| xfs_suminfo_add( | |
| struct xfs_rtalloc_args *args, | |
| unsigned int index, | |
| int delta) | |
| { | |
| union xfs_suminfo_raw *info = xfs_rsumblock_infoptr(args, index); | |
| if (xfs_has_rtgroups(args->mp)) { | |
| be32_add_cpu(&info->rtg, delta); | |
| return be32_to_cpu(info->rtg); | |
| } | |
| info->old += delta; | |
| return info->old; | |
| } | |
| static inline const struct xfs_buf_ops * | |
| xfs_rtblock_ops( | |
| struct xfs_mount *mp, | |
| enum xfs_rtg_inodes type) | |
| { | |
| if (xfs_has_rtgroups(mp)) { | |
| if (type == XFS_RTGI_SUMMARY) | |
| return &xfs_rtsummary_buf_ops; | |
| return &xfs_rtbitmap_buf_ops; | |
| } | |
| return &xfs_rtbuf_ops; | |
| } | |
| /* | |
| * Functions for walking free space rtextents in the realtime bitmap. | |
| */ | |
| struct xfs_rtalloc_rec { | |
| xfs_rtxnum_t ar_startext; | |
| xfs_rtbxlen_t ar_extcount; | |
| }; | |
| typedef int (*xfs_rtalloc_query_range_fn)( | |
| struct xfs_rtgroup *rtg, | |
| struct xfs_trans *tp, | |
| const struct xfs_rtalloc_rec *rec, | |
| void *priv); | |
| #ifdef CONFIG_XFS_RT | |
| void xfs_rtbuf_cache_relse(struct xfs_rtalloc_args *args); | |
| int xfs_rtbitmap_read_buf(struct xfs_rtalloc_args *args, xfs_fileoff_t block); | |
| int xfs_rtsummary_read_buf(struct xfs_rtalloc_args *args, xfs_fileoff_t block); | |
| int xfs_rtcheck_range(struct xfs_rtalloc_args *args, xfs_rtxnum_t start, | |
| xfs_rtxlen_t len, int val, xfs_rtxnum_t *new, int *stat); | |
| int xfs_rtfind_back(struct xfs_rtalloc_args *args, xfs_rtxnum_t start, | |
| xfs_rtxnum_t *rtblock); | |
| int xfs_rtfind_forw(struct xfs_rtalloc_args *args, xfs_rtxnum_t start, | |
| xfs_rtxnum_t limit, xfs_rtxnum_t *rtblock); | |
| int xfs_rtmodify_range(struct xfs_rtalloc_args *args, xfs_rtxnum_t start, | |
| xfs_rtxlen_t len, int val); | |
| int xfs_rtget_summary(struct xfs_rtalloc_args *args, int log, | |
| xfs_fileoff_t bbno, xfs_suminfo_t *sum); | |
| int xfs_rtmodify_summary(struct xfs_rtalloc_args *args, int log, | |
| xfs_fileoff_t bbno, int delta); | |
| int xfs_rtfree_range(struct xfs_rtalloc_args *args, xfs_rtxnum_t start, | |
| xfs_rtxlen_t len); | |
| int xfs_rtalloc_query_range(struct xfs_rtgroup *rtg, struct xfs_trans *tp, | |
| xfs_rtxnum_t start, xfs_rtxnum_t end, | |
| xfs_rtalloc_query_range_fn fn, void *priv); | |
| int xfs_rtalloc_query_all(struct xfs_rtgroup *rtg, struct xfs_trans *tp, | |
| xfs_rtalloc_query_range_fn fn, void *priv); | |
| int xfs_rtalloc_extent_is_free(struct xfs_rtgroup *rtg, struct xfs_trans *tp, | |
| xfs_rtxnum_t start, xfs_rtxlen_t len, bool *is_free); | |
| int xfs_rtfree_extent(struct xfs_trans *tp, struct xfs_rtgroup *rtg, | |
| xfs_rtxnum_t start, xfs_rtxlen_t len); | |
| /* Same as above, but in units of rt blocks. */ | |
| int xfs_rtfree_blocks(struct xfs_trans *tp, struct xfs_rtgroup *rtg, | |
| xfs_fsblock_t rtbno, xfs_filblks_t rtlen); | |
| xfs_rtxnum_t xfs_rtbitmap_rtx_per_rbmblock(struct xfs_mount *mp); | |
| xfs_filblks_t xfs_rtbitmap_blockcount(struct xfs_mount *mp); | |
| xfs_filblks_t xfs_rtbitmap_blockcount_len(struct xfs_mount *mp, | |
| xfs_rtbxlen_t rtextents); | |
| xfs_filblks_t xfs_rtsummary_blockcount(struct xfs_mount *mp, | |
| unsigned int *rsumlevels); | |
| int xfs_rtfile_initialize_blocks(struct xfs_rtgroup *rtg, | |
| enum xfs_rtg_inodes type, xfs_fileoff_t offset_fsb, | |
| xfs_fileoff_t end_fsb, void *data); | |
| int xfs_rtbitmap_create(struct xfs_rtgroup *rtg, struct xfs_inode *ip, | |
| struct xfs_trans *tp, bool init); | |
| int xfs_rtsummary_create(struct xfs_rtgroup *rtg, struct xfs_inode *ip, | |
| struct xfs_trans *tp, bool init); | |
| #else /* CONFIG_XFS_RT */ | |
| # define xfs_rtfree_extent(t,b,l) (-ENOSYS) | |
| static inline int xfs_rtfree_blocks(struct xfs_trans *tp, | |
| struct xfs_rtgroup *rtg, xfs_fsblock_t rtbno, | |
| xfs_filblks_t rtlen) | |
| { | |
| return -ENOSYS; | |
| } | |
| # define xfs_rtalloc_query_range(m,t,l,h,f,p) (-ENOSYS) | |
| # define xfs_rtalloc_query_all(m,t,f,p) (-ENOSYS) | |
| # define xfs_rtbitmap_read_buf(a,b) (-ENOSYS) | |
| # define xfs_rtsummary_read_buf(a,b) (-ENOSYS) | |
| # define xfs_rtbuf_cache_relse(a) (0) | |
| # define xfs_rtalloc_extent_is_free(m,t,s,l,i) (-ENOSYS) | |
| static inline xfs_filblks_t | |
| xfs_rtbitmap_blockcount_len(struct xfs_mount *mp, xfs_rtbxlen_t rtextents) | |
| { | |
| /* shut up gcc */ | |
| return 0; | |
| } | |
| #endif /* CONFIG_XFS_RT */ | |
| #endif /* __XFS_RTBITMAP_H__ */ |