linux-stable/fs/xfs/libxfs/xfs_rtbitmap.h
Darrick J. Wong 7195f240c6 xfs: make xfs_rtblock_t a segmented address like xfs_fsblock_t
Now that we've finished adding allocation groups to the realtime volume,
let's make the file block mapping address (xfs_rtblock_t) a segmented
value just like we do on the data device.  This means that group number
and block number conversions can be done with shifting and masking
instead of integer division.

While in theory we could continue caching the rgno shift value in
m_rgblklog, the fact that we now always use the shift value means that
we have an opportunity to increase the redundancy of the rt geometry by
storing it in the ondisk superblock and adding more sb verifier code.
Extend the sueprblock to store the rgblklog value.

Now that we have segmented addresses, set the correct values in
m_groups[XG_TYPE_RTG] so that the xfs_group helpers work correctly.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
2024-11-05 13:38:44 -08:00

445 lines
11 KiB
C

// 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 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__ */