struct xfs_mount *mp = ap->ip->i_mount;
if (XFS_IS_REALTIME_INODE(ap->ip) &&
- (ap->datatype & XFS_ALLOC_USERDATA))
- return x < mp->m_sb.sb_rblocks;
+ (ap->datatype & XFS_ALLOC_USERDATA)) {
+ if (x >= mp->m_sb.sb_rblocks)
+ return false;
+ if (!xfs_has_rtgroups(mp))
+ return true;
+
+ return xfs_rtb_to_rgno(mp, x) == xfs_rtb_to_rgno(mp, y) &&
+ xfs_rtb_to_rgno(mp, x) < mp->m_sb.sb_rgcount &&
+ xfs_rtb_to_rtx(mp, x) < mp->m_sb.sb_rgextents;
+
+ }
return XFS_FSB_TO_AGNO(mp, x) == XFS_FSB_TO_AGNO(mp, y) &&
XFS_FSB_TO_AGNO(mp, x) < mp->m_sb.sb_agcount &&
fdblocks = indlen;
if (XFS_IS_REALTIME_INODE(ip)) {
- error = xfs_dec_frextents(mp, xfs_rtb_to_rtx(mp, alen));
+ error = xfs_dec_frextents(mp, xfs_blen_to_rtbxlen(mp, alen));
if (error)
goto out_unreserve_quota;
} else {
out_unreserve_frextents:
if (XFS_IS_REALTIME_INODE(ip))
- xfs_add_frextents(mp, xfs_rtb_to_rtx(mp, alen));
+ xfs_add_frextents(mp, xfs_blen_to_rtbxlen(mp, alen));
out_unreserve_quota:
if (XFS_IS_QUOTA_ON(mp))
xfs_quota_unreserve_blkres(ip, alen);
fdblocks = da_diff;
if (isrt)
- xfs_add_frextents(mp, xfs_rtb_to_rtx(mp, del->br_blockcount));
+ xfs_add_frextents(mp, xfs_blen_to_rtbxlen(mp, del->br_blockcount));
else
fdblocks += del->br_blockcount;
ip->i_delayed_blks -= del->br_blockcount;
}
+static int
+xfs_bmap_free_rtblocks(
+ struct xfs_trans *tp,
+ struct xfs_bmbt_irec *del)
+{
+ struct xfs_rtgroup *rtg;
+ int error;
+
+ rtg = xfs_rtgroup_grab(tp->t_mountp, 0);
+ if (!rtg)
+ return -EIO;
+
+ /*
+ * Ensure the bitmap and summary inodes are locked and joined to the
+ * transaction before modifying them.
+ */
+ if (!(tp->t_flags & XFS_TRANS_RTBITMAP_LOCKED)) {
+ tp->t_flags |= XFS_TRANS_RTBITMAP_LOCKED;
+ xfs_rtgroup_lock(rtg, XFS_RTGLOCK_BITMAP);
+ xfs_rtgroup_trans_join(tp, rtg, XFS_RTGLOCK_BITMAP);
+ }
+
+ error = xfs_rtfree_blocks(tp, rtg, del->br_startblock,
+ del->br_blockcount);
+ xfs_rtgroup_rele(rtg);
+ return error;
+}
+
/*
* Called by xfs_bmapi to update file extent records and the btree
* after removing space.
if (xfs_is_reflink_inode(ip) && whichfork == XFS_DATA_FORK) {
xfs_refcount_decrease_extent(tp, isrt, del);
} else if (isrt && !xfs_has_rtgroups(mp)) {
- /*
- * Ensure the bitmap and summary inodes are locked
- * and joined to the transaction before modifying them.
- */
- if (!(tp->t_flags & XFS_TRANS_RTBITMAP_LOCKED)) {
- tp->t_flags |= XFS_TRANS_RTBITMAP_LOCKED;
- xfs_rtbitmap_lock(mp);
- xfs_rtbitmap_trans_join(tp);
- }
- error = xfs_rtfree_blocks(tp, del->br_startblock,
- del->br_blockcount);
+ error = xfs_bmap_free_rtblocks(tp, del);
} else {
unsigned int efi_flags = 0;
xfs_metafile_resv_free(
struct xfs_inode *ip)
{
- if (!ip)
+ /*
+ * We can end up here for the rt bitmap/summary inodes that don't have
+ * reservations. Just exist early in that case.
+ */
+ if (!ip || !ip->i_delayed_blks)
return;
ASSERT(xfs_is_metadir_inode(ip));
#include "xfs_fs.h"
#include "xfs_shared.h"
#include "xfs_format.h"
+#include "xfs_sb.h"
#include "xfs_log_format.h"
#include "xfs_trans_resv.h"
#include "xfs_bit.h"
if (issum) {
cbpp = &args->sumbp;
coffp = &args->sumoff;
- ip = mp->m_rsumip;
+ ip = args->rtg->rtg_inodes[XFS_RTG_SUMMARY];
type = XFS_BLFT_RTSUMMARY_BUF;
} else {
cbpp = &args->rbmbp;
coffp = &args->rbmoff;
- ip = mp->m_rbmip;
+ ip = args->rtg->rtg_inodes[XFS_RTG_BITMAP];
type = XFS_BLFT_RTBITMAP_BUF;
}
{
struct xfs_mount *mp = args->mp;
xfs_rtsumoff_t so = xfs_rtsumoffs(mp, log, bbno);
+ uint8_t *rsum_cache = args->rtg->rtg_rsum_cache;
unsigned int infoword;
xfs_suminfo_t val;
int error;
infoword = xfs_rtsumoffs_to_infoword(mp, so);
val = xfs_suminfo_add(args, infoword, delta);
- if (mp->m_rsum_cache) {
- if (val == 0 && log + 1 == mp->m_rsum_cache[bbno])
- mp->m_rsum_cache[bbno] = log;
- if (val != 0 && log >= mp->m_rsum_cache[bbno])
- mp->m_rsum_cache[bbno] = log + 1;
+ if (rsum_cache) {
+ if (val == 0 && log + 1 == rsum_cache[bbno])
+ rsum_cache[bbno] = log;
+ if (val != 0 && log >= rsum_cache[bbno])
+ rsum_cache[bbno] = log + 1;
}
xfs_trans_log_rtsummary(args, infoword);
/*
* Find the next allocated block (end of allocated extent).
*/
- error = xfs_rtfind_forw(args, end, mp->m_sb.sb_rextents - 1,
+ error = xfs_rtfind_forw(args, end, args->rtg->rtg_extents - 1,
&postblock);
if (error)
return error;
int
xfs_rtfree_extent(
struct xfs_trans *tp, /* transaction pointer */
+ struct xfs_rtgroup *rtg,
xfs_rtxnum_t start, /* starting rtext number to free */
xfs_rtxlen_t len) /* length of extent freed */
{
struct xfs_mount *mp = tp->t_mountp;
+ struct xfs_inode *rbmip = rtg->rtg_inodes[XFS_RTG_BITMAP];
struct xfs_rtalloc_args args = {
.mp = mp,
.tp = tp,
+ .rtg = rtg,
};
int error;
struct timespec64 atime;
- ASSERT(mp->m_rbmip->i_itemp != NULL);
- xfs_assert_ilocked(mp->m_rbmip, XFS_ILOCK_EXCL);
+ ASSERT(rbmip->i_itemp != NULL);
+ xfs_assert_ilocked(rbmip, XFS_ILOCK_EXCL);
if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_FREE_EXTENT))
return -EIO;
* Mark more blocks free in the superblock.
*/
xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, (long)len);
+
/*
* If we've now freed all the blocks, reset the file sequence
- * number to 0.
+ * number to 0 for legacy file systems.
*/
- if (tp->t_frextents_delta + mp->m_sb.sb_frextents ==
+ if (!xfs_has_rtgroups(mp) &&
+ tp->t_frextents_delta + mp->m_sb.sb_frextents ==
mp->m_sb.sb_rextents) {
- if (!(mp->m_rbmip->i_diflags & XFS_DIFLAG_NEWRTBM))
- mp->m_rbmip->i_diflags |= XFS_DIFLAG_NEWRTBM;
-
- if (xfs_has_rtgroups(mp)) {
- mp->m_rtgrotor = 0;
- } else {
- atime = inode_get_atime(VFS_I(mp->m_rbmip));
- atime.tv_sec = 0;
- inode_set_atime_to_ts(VFS_I(mp->m_rbmip), atime);
- xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE);
- }
+ rbmip->i_diflags |= XFS_DIFLAG_NEWRTBM;
+
+ atime = inode_get_atime(VFS_I(rbmip));
+ atime.tv_sec = 0;
+ inode_set_atime_to_ts(VFS_I(rbmip), atime);
+ xfs_trans_log_inode(tp, rbmip, XFS_ILOG_CORE);
}
error = 0;
out:
int
xfs_rtfree_blocks(
struct xfs_trans *tp,
+ struct xfs_rtgroup *rtg,
xfs_fsblock_t rtbno,
xfs_filblks_t rtlen)
{
return -EIO;
}
- return xfs_rtfree_extent(tp, xfs_rtb_to_rtx(mp, rtbno),
- xfs_rtb_to_rtx(mp, rtlen));
+ return xfs_rtfree_extent(tp, rtg, xfs_rtb_to_rtx(mp, rtbno),
+ xfs_extlen_to_rtxlen(mp, rtlen));
}
/* Find all the free records within a given range. */
int
xfs_rtalloc_query_range(
- struct xfs_mount *mp,
+ struct xfs_rtgroup *rtg,
struct xfs_trans *tp,
xfs_rtxnum_t start,
xfs_rtxnum_t end,
xfs_rtalloc_query_range_fn fn,
void *priv)
{
+ struct xfs_mount *mp = rtg->rtg_mount;
struct xfs_rtalloc_args args = {
+ .rtg = rtg,
.mp = mp,
.tp = tp,
};
if (start > end)
return -EINVAL;
- if (start == end || start >= mp->m_sb.sb_rextents)
+ if (start == end || start >= rtg->rtg_extents)
return 0;
- end = min(end, mp->m_sb.sb_rextents - 1);
+ end = min(end, rtg->rtg_extents - 1);
/* Iterate the bitmap, looking for discrepancies. */
while (start <= end) {
rec.ar_startext = start;
rec.ar_extcount = rtend - start + 1;
- error = fn(mp, tp, &rec, priv);
+ error = fn(rtg, tp, &rec, priv);
if (error)
break;
}
/* Find all the free records. */
int
xfs_rtalloc_query_all(
- struct xfs_mount *mp,
+ struct xfs_rtgroup *rtg,
struct xfs_trans *tp,
xfs_rtalloc_query_range_fn fn,
void *priv)
{
- return xfs_rtalloc_query_range(mp, tp, 0, mp->m_sb.sb_rextents - 1, fn,
+ return xfs_rtalloc_query_range(rtg, tp, 0, rtg->rtg_extents - 1, fn,
priv);
}
/* Is the given extent all free? */
int
xfs_rtalloc_extent_is_free(
- struct xfs_mount *mp,
+ struct xfs_rtgroup *rtg,
struct xfs_trans *tp,
xfs_rtxnum_t start,
xfs_rtxlen_t len,
bool *is_free)
{
struct xfs_rtalloc_args args = {
- .mp = mp,
+ .mp = rtg->rtg_mount,
+ .rtg = rtg,
.tp = tp,
};
xfs_rtxnum_t end;
return rbmblock_bytes * NBBY;
}
+xfs_filblks_t
+__xfs_rtbitmap_blockcount(
+ struct xfs_mount *mp,
+ xfs_rtbxlen_t rtextents)
+{
+ return howmany_64(rtextents, xfs_rtbitmap_rtx_per_rbmblock(mp));
+}
+
/*
* Compute the number of rtbitmap blocks needed to track the given number of rt
* extents.
*/
xfs_filblks_t
xfs_rtbitmap_blockcount(
- struct xfs_mount *mp,
- xfs_rtbxlen_t rtextents)
+ struct xfs_mount *mp)
{
- return howmany_64(rtextents, xfs_rtbitmap_rtx_per_rbmblock(mp));
+ if (xfs_has_rtgroups(mp))
+ return __xfs_rtbitmap_blockcount(mp, mp->m_sb.sb_rgextents);
+ return __xfs_rtbitmap_blockcount(mp, mp->m_sb.sb_rextents);
}
/*
*/
unsigned long long
xfs_rtbitmap_wordcount(
- struct xfs_mount *mp,
- xfs_rtbxlen_t rtextents)
+ struct xfs_mount *mp)
{
- xfs_filblks_t blocks;
-
- blocks = xfs_rtbitmap_blockcount(mp, rtextents);
- return XFS_FSB_TO_B(mp, blocks) >> XFS_WORDLOG;
+ return XFS_FSB_TO_B(mp, xfs_rtbitmap_blockcount(mp)) >> XFS_WORDLOG;
}
/* Compute the number of rtsummary blocks needed to track the given rt space. */
return XFS_FSB_TO_B(mp, blocks) >> XFS_WORDLOG;
}
-/* Lock both realtime free space metadata inodes for a freespace update. */
-void
-xfs_rtbitmap_lock(
- struct xfs_mount *mp)
-{
- xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL);
- xfs_ilock(mp->m_rsumip, XFS_ILOCK_EXCL);
-}
-
-/*
- * Join both realtime free space metadata inodes to the transaction. The
- * ILOCKs will be released on transaction commit.
- */
-void
-xfs_rtbitmap_trans_join(
- struct xfs_trans *tp)
-{
- xfs_trans_ijoin(tp, tp->t_mountp->m_rbmip, XFS_ILOCK_EXCL);
- xfs_trans_ijoin(tp, tp->t_mountp->m_rsumip, XFS_ILOCK_EXCL);
-}
-
-/* Unlock both realtime free space metadata inodes after a freespace update. */
-void
-xfs_rtbitmap_unlock(
- struct xfs_mount *mp)
-{
- xfs_iunlock(mp->m_rsumip, XFS_ILOCK_EXCL);
- xfs_iunlock(mp->m_rbmip, XFS_ILOCK_EXCL);
-}
-
-/*
- * Lock the realtime free space metadata inodes for a freespace scan. Callers
- * must walk metadata blocks in order of increasing file offset.
- */
-void
-xfs_rtbitmap_lock_shared(
- struct xfs_mount *mp,
- unsigned int rbmlock_flags)
-{
- if (rbmlock_flags & XFS_RBMLOCK_BITMAP)
- xfs_ilock(mp->m_rbmip, XFS_ILOCK_SHARED);
-
- if (rbmlock_flags & XFS_RBMLOCK_SUMMARY)
- xfs_ilock(mp->m_rsumip, XFS_ILOCK_SHARED);
-}
-
-/* Unlock the realtime free space metadata inodes after a freespace scan. */
-void
-xfs_rtbitmap_unlock_shared(
+unsigned int
+xfs_compute_rsumlevels(
struct xfs_mount *mp,
- unsigned int rbmlock_flags)
+ uint64_t rextents)
{
- if (rbmlock_flags & XFS_RBMLOCK_SUMMARY)
- xfs_iunlock(mp->m_rsumip, XFS_ILOCK_SHARED);
-
- if (rbmlock_flags & XFS_RBMLOCK_BITMAP)
- xfs_iunlock(mp->m_rbmip, XFS_ILOCK_SHARED);
+ if (xfs_has_rtgroups(mp))
+ rextents = mp->m_sb.sb_rgextents;
+ return xfs_compute_rextslog(rextents) + 1;
}
static int
/* Get a buffer for the block. */
static int
xfs_rtfile_initialize_block(
- struct xfs_inode *ip,
+ struct xfs_rtgroup *rtg,
+ enum xfs_rtg_inodes type,
xfs_fsblock_t fsbno,
void *data)
{
- struct xfs_mount *mp = ip->i_mount;
+ struct xfs_mount *mp = rtg->rtg_mount;
+ struct xfs_inode *ip = rtg->rtg_inodes[type];
struct xfs_trans *tp;
struct xfs_buf *bp;
void *bufdata;
enum xfs_blft buf_type;
int error;
- if (ip == mp->m_rsumip)
+ if (type == XFS_RTG_BITMAP)
+ buf_type = XFS_BLFT_RTBITMAP_BUF;
+ else if (type == XFS_RTG_SUMMARY)
buf_type = XFS_BLFT_RTSUMMARY_BUF;
else
- buf_type = XFS_BLFT_RTBITMAP_BUF;
+ return -EINVAL;
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growrtzero, 0, 0, 0, &tp);
if (error)
bufdata = bp->b_addr;
xfs_trans_buf_set_type(tp, bp, buf_type);
- bp->b_ops = xfs_rtblock_ops(mp, buf_type == XFS_BLFT_RTSUMMARY_BUF);
+ bp->b_ops = xfs_rtblock_ops(mp, type == XFS_RTG_SUMMARY);
if (xfs_has_rtgroups(mp)) {
struct xfs_rtbuf_blkinfo *hdr = bp->b_addr;
- if (buf_type == XFS_BLFT_RTBITMAP_BUF)
+ if (type == XFS_RTG_BITMAP)
hdr->rt_magic = cpu_to_be32(XFS_RTBITMAP_MAGIC);
else
hdr->rt_magic = cpu_to_be32(XFS_RTSUMMARY_MAGIC);
*/
int
xfs_rtfile_initialize_blocks(
- struct xfs_inode *ip, /* inode (bitmap/summary) */
+ struct xfs_rtgroup *rtg,
+ enum xfs_rtg_inodes type,
xfs_fileoff_t offset_fsb, /* offѕet to start from */
xfs_fileoff_t end_fsb, /* offѕet to allocate to */
void *data) /* data to fill the blocks */
{
- struct xfs_mount *mp = ip->i_mount;
+ struct xfs_mount *mp = rtg->rtg_mount;
const size_t copylen = mp->m_blockwsize << XFS_WORDLOG;
while (offset_fsb < end_fsb) {
xfs_filblks_t i;
int error;
- error = xfs_rtfile_alloc_blocks(ip, offset_fsb,
- end_fsb - offset_fsb, &map);
+ error = xfs_rtfile_alloc_blocks(rtg->rtg_inodes[type],
+ offset_fsb, end_fsb - offset_fsb, &map);
if (error)
return error;
* Do this one block per transaction, to keep it simple.
*/
for (i = 0; i < map.br_blockcount; i++) {
- error = xfs_rtfile_initialize_block(ip,
+ error = xfs_rtfile_initialize_block(rtg, type,
map.br_startblock + i, data);
if (error)
return error;
return 0;
}
+
+int
+xfs_rtbitmap_create(
+ struct xfs_rtgroup *rtg,
+ struct xfs_inode *ip,
+ struct xfs_trans *tp,
+ bool init)
+{
+ struct xfs_mount *mp = rtg->rtg_mount;
+
+ ip->i_disk_size = mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize;
+ if (init && !xfs_has_rtgroups(mp)) {
+ ip->i_diflags |= XFS_DIFLAG_NEWRTBM;
+ inode_set_atime(VFS_I(ip), 0, 0);
+ }
+ xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+ return 0;
+}
+
+int
+xfs_rtsummary_create(
+ struct xfs_rtgroup *rtg,
+ struct xfs_inode *ip,
+ struct xfs_trans *tp,
+ bool init)
+{
+ ip->i_disk_size = rtg->rtg_mount->m_rsumsize;
+ xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+ return 0;
+}
#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;
xfs_fileoff_t sumoff; /* summary block number */
};
-static inline xfs_rtblock_t
-xfs_rtx_to_rtb(
+static inline uint64_t
+xfs_rtbxlen_to_blen(
struct xfs_mount *mp,
- xfs_rtxnum_t rtx)
+ xfs_rtbxlen_t rtbxlen)
{
if (mp->m_rtxblklog >= 0)
- return rtx << mp->m_rtxblklog;
+ return rtbxlen << mp->m_rtxblklog;
- return rtx * mp->m_sb.sb_rextsize;
+ return rtbxlen * mp->m_sb.sb_rextsize;
}
static inline xfs_extlen_t
return len / mp->m_sb.sb_rextsize;
}
-/* Convert an rt block number into an rt extent number. */
-static inline xfs_rtxnum_t
-xfs_rtb_to_rtx(
+/* Convert an rt block count into an rt extent count. */
+static inline xfs_rtbxlen_t
+xfs_blen_to_rtbxlen(
struct xfs_mount *mp,
- xfs_rtblock_t rtbno)
+ uint64_t blen)
{
if (likely(mp->m_rtxblklog >= 0))
- return rtbno >> mp->m_rtxblklog;
+ return blen >> mp->m_rtxblklog;
- return div_u64(rtbno, mp->m_sb.sb_rextsize);
+ return div_u64(blen, mp->m_sb.sb_rextsize);
}
/* Return the offset of an rt block number within an rt extent. */
return do_div(rtbno, mp->m_sb.sb_rextsize);
}
-/*
- * Convert an rt block number into an rt extent number, rounding up to the next
- * rt extent if the rt block is not aligned to an rt extent boundary.
- */
-static inline xfs_rtxnum_t
-xfs_rtb_to_rtxup(
- struct xfs_mount *mp,
- xfs_rtblock_t rtbno)
-{
- if (likely(mp->m_rtxblklog >= 0)) {
- if (rtbno & mp->m_rtxblkmask)
- return (rtbno >> mp->m_rtxblklog) + 1;
- return rtbno >> mp->m_rtxblklog;
- }
-
- if (do_div(rtbno, mp->m_sb.sb_rextsize))
- rtbno++;
- return rtbno;
-}
-
/* Round this rtblock up to the nearest rt extent size. */
static inline xfs_rtblock_t
xfs_rtb_roundup_rtx(
};
typedef int (*xfs_rtalloc_query_range_fn)(
- struct xfs_mount *mp,
+ struct xfs_rtgroup *rtg,
struct xfs_trans *tp,
const struct xfs_rtalloc_rec *rec,
void *priv);
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_mount *mp, struct xfs_trans *tp,
+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_mount *mp, struct xfs_trans *tp,
+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_mount *mp, struct xfs_trans *tp,
- xfs_rtxnum_t start, xfs_rtxlen_t len,
- bool *is_free);
-/*
- * Free an extent in the realtime subvolume. Length is expressed in
- * realtime extents, as is the block number.
- */
-int /* error */
-xfs_rtfree_extent(
- struct xfs_trans *tp, /* transaction pointer */
- xfs_rtxnum_t start, /* starting rtext number to free */
- xfs_rtxlen_t len); /* length of extent freed */
-
+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, xfs_fsblock_t rtbno,
- xfs_filblks_t rtlen);
+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_rtbxlen_t
- rtextents);
-unsigned long long xfs_rtbitmap_wordcount(struct xfs_mount *mp,
+xfs_filblks_t __xfs_rtbitmap_blockcount(struct xfs_mount *mp,
xfs_rtbxlen_t rtextents);
+xfs_filblks_t xfs_rtbitmap_blockcount(struct xfs_mount *mp);
+unsigned long long xfs_rtbitmap_wordcount(struct xfs_mount *mp);
xfs_filblks_t xfs_rtsummary_blockcount(struct xfs_mount *mp,
unsigned int rsumlevels, xfs_extlen_t rbmblocks);
unsigned long long xfs_rtsummary_wordcount(struct xfs_mount *mp,
unsigned int rsumlevels, xfs_extlen_t rbmblocks);
+unsigned int xfs_compute_rsumlevels(struct xfs_mount *mp, uint64_t rextents);
-int xfs_rtfile_initialize_blocks(struct xfs_inode *ip,
- xfs_fileoff_t offset_fsb, xfs_fileoff_t end_fsb, void *data);
+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);
-void xfs_rtbitmap_lock(struct xfs_mount *mp);
-void xfs_rtbitmap_unlock(struct xfs_mount *mp);
-void xfs_rtbitmap_trans_join(struct xfs_trans *tp);
-
-/* Lock the rt bitmap inode in shared mode */
-#define XFS_RBMLOCK_BITMAP (1U << 0)
-/* Lock the rt summary inode in shared mode */
-#define XFS_RBMLOCK_SUMMARY (1U << 1)
-
-void xfs_rtbitmap_lock_shared(struct xfs_mount *mp,
- unsigned int rbmlock_flags);
-void xfs_rtbitmap_unlock_shared(struct xfs_mount *mp,
- unsigned int rbmlock_flags);
#else /* CONFIG_XFS_RT */
# define xfs_rtfree_extent(t,b,l) (-ENOSYS)
-# define xfs_rtfree_blocks(t,rb,rl) (-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_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(struct xfs_mount *mp, xfs_rtbxlen_t rtextents)
+__xfs_rtbitmap_blockcount(struct xfs_mount *mp, xfs_rtbxlen_t rtextents)
{
/* shut up gcc */
return 0;
}
-# define xfs_rtbitmap_wordcount(mp, r) (0)
+# define xfs_rtbitmap_wordcount(mp) (0)
# define xfs_rtsummary_blockcount(mp, l, b) (0)
# define xfs_rtsummary_wordcount(mp, l, b) (0)
-# define xfs_rtbitmap_lock(mp) do { } while (0)
-# define xfs_rtbitmap_trans_join(tp) do { } while (0)
-# define xfs_rtbitmap_unlock(mp) do { } while (0)
-# define xfs_rtbitmap_lock_shared(mp, lf) do { } while (0)
-# define xfs_rtbitmap_unlock_shared(mp, lf) do { } while (0)
#endif /* CONFIG_XFS_RT */
#endif /* __XFS_RTBITMAP_H__ */
int error;
if (!xfs_has_rtgroups(mp))
- return 0;
+ rgcount = 1;
/*
* Walk the current rtgroup tree so we don't try to initialise rt
struct xfs_rtgroup *rtg;
xfs_rgnumber_t rgno;
- if (!xfs_has_rtgroups(mp))
- return;
-
for (rgno = 0; rgno < mp->m_sb.sb_rgcount; rgno++) {
spin_lock(&mp->m_rtgroup_lock);
rtg = radix_tree_delete(&mp->m_rtgroup_tree, rgno);
}
}
-/* Find the size of the rtgroup, in blocks. */
-static xfs_rgblock_t
-__xfs_rtgroup_block_count(
+/* Compute the number of rt extents in this realtime group. */
+xfs_rtxnum_t
+xfs_rtgroup_extents(
struct xfs_mount *mp,
- xfs_rgnumber_t rgno,
- xfs_rgnumber_t rgcount,
- xfs_rfsblock_t rblocks)
+ xfs_rgnumber_t rgno)
{
- ASSERT(rgno < rgcount);
+ xfs_rgnumber_t rgcount = mp->m_sb.sb_rgcount;
- if (rgno < rgcount - 1)
- return mp->m_rgblocks;
- return xfs_rtb_rounddown_rtx(mp,
- rblocks - ((xfs_rtblock_t)rgno * mp->m_rgblocks));
-}
+ ASSERT(rgno < rgcount);
+ if (rgno == rgcount - 1)
+ return mp->m_sb.sb_rextents -
+ ((xfs_rtxnum_t)rgno * mp->m_sb.sb_rgextents);
-/* Compute the number of blocks in this realtime group. */
-xfs_rgblock_t
-xfs_rtgroup_block_count(
- struct xfs_mount *mp,
- xfs_rgnumber_t rgno)
-{
- return __xfs_rtgroup_block_count(mp, rgno, mp->m_sb.sb_rgcount,
- mp->m_sb.sb_rblocks);
+ ASSERT(xfs_has_rtgroups(mp));
+ return mp->m_sb.sb_rgextents;
}
/* Check superblock fields for a read or a write. */
ASSERT(!(rtglock_flags & XFS_RTGLOCK_BITMAP_SHARED) ||
!(rtglock_flags & XFS_RTGLOCK_BITMAP));
- if (rtglock_flags & XFS_RTGLOCK_BITMAP)
- xfs_rtbitmap_lock(rtg->rtg_mount);
- else if (rtglock_flags & XFS_RTGLOCK_BITMAP_SHARED)
- xfs_rtbitmap_lock_shared(rtg->rtg_mount, XFS_RBMLOCK_BITMAP);
+ if (rtglock_flags & XFS_RTGLOCK_BITMAP) {
+ /*
+ * Lock both realtime free space metadata inodes for a freespace
+ * update.
+ */
+ xfs_ilock(rtg->rtg_inodes[XFS_RTG_BITMAP], XFS_ILOCK_EXCL);
+ xfs_ilock(rtg->rtg_inodes[XFS_RTG_SUMMARY], XFS_ILOCK_EXCL);
+ } else if (rtglock_flags & XFS_RTGLOCK_BITMAP_SHARED) {
+ xfs_ilock(rtg->rtg_inodes[XFS_RTG_BITMAP], XFS_ILOCK_SHARED);
+ }
if ((rtglock_flags & XFS_RTGLOCK_RMAP) &&
rtg->rtg_inodes[XFS_RTG_RMAP] != NULL)
if ((rtglock_flags & XFS_RTGLOCK_RMAP) && rtg->rtg_inodes[XFS_RTG_RMAP])
xfs_iunlock(rtg->rtg_inodes[XFS_RTG_RMAP], XFS_ILOCK_EXCL);
- if (rtglock_flags & XFS_RTGLOCK_BITMAP)
- xfs_rtbitmap_unlock(rtg->rtg_mount);
- else if (rtglock_flags & XFS_RTGLOCK_BITMAP_SHARED)
- xfs_rtbitmap_unlock_shared(rtg->rtg_mount, XFS_RBMLOCK_BITMAP);
+ if (rtglock_flags & XFS_RTGLOCK_BITMAP) {
+ xfs_iunlock(rtg->rtg_inodes[XFS_RTG_SUMMARY], XFS_ILOCK_EXCL);
+ xfs_iunlock(rtg->rtg_inodes[XFS_RTG_BITMAP], XFS_ILOCK_EXCL);
+ } else if (rtglock_flags & XFS_RTGLOCK_BITMAP_SHARED) {
+ xfs_iunlock(rtg->rtg_inodes[XFS_RTG_BITMAP], XFS_ILOCK_SHARED);
+ }
}
/*
ASSERT(!(rtglock_flags & ~XFS_RTGLOCK_ALL_FLAGS));
ASSERT(!(rtglock_flags & XFS_RTGLOCK_BITMAP_SHARED));
- if (rtglock_flags & XFS_RTGLOCK_BITMAP)
- xfs_rtbitmap_trans_join(tp);
-
+ if (rtglock_flags & XFS_RTGLOCK_BITMAP) {
+ xfs_trans_ijoin(tp, rtg->rtg_inodes[XFS_RTG_BITMAP],
+ XFS_ILOCK_EXCL);
+ xfs_trans_ijoin(tp, rtg->rtg_inodes[XFS_RTG_SUMMARY],
+ XFS_ILOCK_EXCL);
+ }
if ((rtglock_flags & XFS_RTGLOCK_RMAP) &&
rtg->rtg_inodes[XFS_RTG_RMAP] != NULL)
xfs_trans_ijoin(tp, rtg->rtg_inodes[XFS_RTG_RMAP],
/* Fill out form. */
memset(rgeo, 0, sizeof(*rgeo));
rgeo->rg_number = rtg->rtg_rgno;
- rgeo->rg_length = rtg->rtg_blockcount;
+ rgeo->rg_length = rtg->rtg_extents * rtg->rtg_mount->m_sb.sb_rextsize;
xfs_rtgroup_geom_health(rtg, rgeo);
return 0;
}
};
static const struct xfs_rtginode_ops xfs_rtginode_ops[XFS_RTG_MAX] = {
+ [XFS_RTG_BITMAP] = {
+ .name = "bitmap",
+ .sick = XFS_SICK_RT_BITMAP,
+ .create = xfs_rtbitmap_create,
+ },
+ [XFS_RTG_SUMMARY] = {
+ .name = "summary",
+ .sick = XFS_SICK_RT_SUMMARY,
+ .create = xfs_rtsummary_create,
+ },
[XFS_RTG_RMAP] = {
.name = "rmap",
.format = XFS_DINODE_FMT_RMAP,
{
const struct xfs_rtginode_ops *ops = &xfs_rtginode_ops[type];
+ if (!ops->enabled)
+ return true;
return ops->enabled(rtg->rtg_mount);
}
{
const struct xfs_rtginode_ops *ops = &xfs_rtginode_ops[type];
struct xfs_mount *mp = tp->t_mountp;
- const char *path;
struct xfs_inode *ip;
int error;
if (!xfs_rtginode_enabled(rtg, type))
return 0;
- path = xfs_rtginode_path(rtg->rtg_rgno, type);
- if (!path)
- return -ENOMEM;
- error = xfs_metadir_load(tp, mp->m_rtdirip, path, S_IFREG, &ip);
- kfree(path);
+ if (!xfs_has_rtgroups(mp)) {
+ xfs_ino_t ino;
+
+ switch (type) {
+ case XFS_RTG_BITMAP:
+ ino = mp->m_sb.sb_rbmino;
+ break;
+ case XFS_RTG_SUMMARY:
+ ino = mp->m_sb.sb_rsumino;
+ break;
+ default:
+ return 0;
+ }
+
+ error = xfs_metafile_iget(tp, ino, S_IFREG, &ip);
+ } else {
+ const char *path;
+
+ path = xfs_rtginode_path(rtg->rtg_rgno, type);
+ if (!path)
+ return -ENOMEM;
+ error = xfs_metadir_load(tp, mp->m_rtdirip, path, S_IFREG, &ip);
+ kfree(path);
+ }
if (error) {
if (xfs_metadata_is_sick(error))
return error;
}
- if (XFS_IS_CORRUPT(mp, ip->i_df.if_format != ops->format)) {
+ if (ops->format &&
+ XFS_IS_CORRUPT(mp, ip->i_df.if_format != ops->format)) {
xfs_irele(ip);
xfs_rtgroup_mark_sick(rtg, ops->sick);
return -EFSCORRUPTED;
{
struct xfs_mount *mp = tp->t_mountp;
+ if (!xfs_has_rtgroups(mp))
+ return 0;
return xfs_metadir_load(tp, mp->m_metadirip, "rtgroups", S_IFDIR,
&mp->m_rtdirip);
}
struct xfs_trans;
enum xfs_rtg_inodes {
+ XFS_RTG_BITMAP, /* allocation bitmap */
+ XFS_RTG_SUMMARY, /* allocation summary */
XFS_RTG_RMAP, /* rmap btree inode */
XFS_RTG_REFCOUNT, /* refcount btree inode */
+
XFS_RTG_MAX,
};
struct xfs_inode *rtg_inodes[XFS_RTG_MAX];
/* Number of blocks in this group */
- xfs_rgblock_t rtg_blockcount;
+ xfs_rtxnum_t rtg_extents;
/*
* Bitsets of per-rtgroup metadata that have been checked and/or are
uint16_t rtg_checked;
uint16_t rtg_sick;
+ /*
+ * Optional cache of rt summary level per bitmap block with the
+ * invariant that rtg_rsum_cache[bbno] > the maximum i for which
+ * rsum[i][bbno] != 0, or 0 if rsum[i][bbno] == 0 for all i.
+ * Reads and writes are serialized by the rsumip inode lock.
+ */
+ uint8_t *rtg_rsum_cache;
+
#ifdef __KERNEL__
/* -- kernel only structures below this line -- */
spinlock_t rtg_state_lock;
{
struct xfs_mount *mp = rtg->rtg_mount;
- if (rgbno >= rtg->rtg_blockcount)
+ if (rgbno >= rtg->rtg_extents * mp->m_sb.sb_rextsize)
return false;
if (xfs_has_rtsb(mp) && rtg->rtg_rgno == 0 &&
rgbno < mp->m_sb.sb_rextsize)
return xfs_verify_rgbno(rtg, rgbno + len - 1);
}
+static inline xfs_rtblock_t
+xfs_rgno_start_rtb(
+ struct xfs_mount *mp,
+ xfs_rgnumber_t rgno)
+{
+ if (mp->m_rgblklog >= 0)
+ return ((xfs_rtblock_t)rgno << mp->m_rgblklog);
+ return ((xfs_rtblock_t)rgno * mp->m_rgblocks);
+}
+
static inline xfs_rtblock_t
xfs_rgbno_to_rtb(
struct xfs_mount *mp,
xfs_rgnumber_t rgno,
xfs_rgblock_t rgbno)
{
- ASSERT(xfs_has_rtgroups(mp));
-
- if (mp->m_rgblklog >= 0)
- return ((xfs_rtblock_t)rgno << mp->m_rgblklog) | rgbno;
-
- return ((xfs_rtblock_t)rgno * mp->m_rgblocks) + rgbno;
+ return xfs_rgno_start_rtb(mp, rgno) + rgbno;
}
static inline xfs_rgnumber_t
struct xfs_mount *mp,
xfs_rtblock_t rtbno)
{
- ASSERT(xfs_has_rtgroups(mp));
-
if (mp->m_rgblklog >= 0)
return rtbno >> mp->m_rgblklog;
{
uint32_t rem;
- ASSERT(xfs_has_rtgroups(mp));
-
if (mp->m_rgblklog >= 0) {
*rgno = rtbno >> mp->m_rgblklog;
return rtbno & mp->m_rgblkmask;
return rem;
}
+static inline xfs_rtblock_t
+xfs_rtx_to_rtb(
+ struct xfs_rtgroup *rtg,
+ xfs_rtxnum_t rtx)
+{
+ struct xfs_mount *mp = rtg->rtg_mount;
+ xfs_rtblock_t start = xfs_rgno_start_rtb(mp, rtg->rtg_rgno);
+
+ 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;
+}
+
+/* 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)
+{
+ uint64_t rgbno;
+
+ if (mp->m_rgblklog >= 0) {
+ rgbno = rtbno & mp->m_rgblkmask;
+ } else {
+ uint32_t rem;
+
+ div_u64_rem(rtbno, mp->m_rgblocks, &rem);
+ rgbno = rem;
+ }
+
+ if (likely(mp->m_rtxblklog >= 0))
+ return rgbno >> mp->m_rtxblklog;
+ return div_u64(rgbno, mp->m_sb.sb_rextsize);
+}
+
static inline xfs_daddr_t
xfs_rtb_to_daddr(
struct xfs_mount *mp,
}
#ifdef CONFIG_XFS_RT
-xfs_rgblock_t xfs_rtgroup_block_count(struct xfs_mount *mp,
- xfs_rgnumber_t rgno);
+xfs_rtxnum_t xfs_rtgroup_extents(struct xfs_mount *mp, xfs_rgnumber_t rgno);
void xfs_rtgroup_update_super(struct xfs_buf *rtsb_bp,
const struct xfs_buf *sb_bp);
return kasprintf(GFP_KERNEL, "%u.%s", rgno, xfs_rtginode_name(type));
}
#else
-# define xfs_rtgroup_block_count(mp, rgno) (0)
+# define xfs_rtgroup_extents(mp, rgno) (0)
# define xfs_rtgroup_update_super(bp, sb_bp) ((void)0)
# define xfs_rtgroup_log_super(tp, sb_bp) (NULL)
# define xfs_rtgroup_lock(rtg, gf) ((void)0)
xfs_sb_calc_rbmblocks(
struct xfs_sb *sbp)
{
- unsigned int rbmblock_bytes = sbp->sb_blocksize;
+ if (!xfs_sb_version_hasrtgroups(sbp))
+ return howmany_64(sbp->sb_rextents, NBBY * sbp->sb_blocksize);
- if (xfs_sb_is_v5(sbp) &&
- (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_RTGROUPS))
- rbmblock_bytes -= sizeof(struct xfs_rtbuf_blkinfo);
-
- return howmany_64(sbp->sb_rextents, NBBY * rbmblock_bytes);
+ return howmany_64(sbp->sb_rgextents,
+ NBBY * (sbp->sb_blocksize - sizeof(struct xfs_rtbuf_blkinfo)));
}
/* Validate the realtime geometry */
to->sb_rgcount = be32_to_cpu(from->sb_rgcount);
to->sb_rgextents = be32_to_cpu(from->sb_rgextents);
} else {
- to->sb_rgcount = 0;
- to->sb_rgextents = 0;
+ to->sb_rgcount = 1;
+ to->sb_rgextents = UINT_MAX;
}
}
unsigned int t1, t2 = 0;
rtxlen = xfs_extlen_to_rtxlen(mp, XFS_MAX_BMBT_EXTLEN);
- rtbmp_blocks = xfs_rtbitmap_blockcount(mp, rtxlen);
+ rtbmp_blocks = __xfs_rtbitmap_blockcount(mp, rtxlen);
t1 = (rtbmp_blocks + 1) * num_ops;
if (xfs_has_rmapbt(mp))
return xfs_verify_ino(mp, ino);
}
-/*
- * Verify that an rtgroup block number pointer neither points outside the
- * rtgroup nor at static metadata.
- */
-static inline bool
-xfs_verify_rgno_rgbno(
- struct xfs_mount *mp,
- xfs_rgnumber_t rgno,
- xfs_rgblock_t rgbno)
-{
- xfs_rgblock_t eorg;
-
- eorg = xfs_rtgroup_block_count(mp, rgno);
- if (rgbno >= eorg)
- return false;
- if (xfs_has_rtsb(mp) && rgno == 0 && rgbno < mp->m_sb.sb_rextsize)
- return false;
- return true;
-}
-
/*
* Verify that a realtime block number pointer neither points outside the
* allocatable areas of the rtgroup nor off the end of the realtime
struct xfs_mount *mp,
xfs_rtblock_t rtbno)
{
- xfs_rgnumber_t rgno;
- xfs_rgblock_t rgbno;
-
if (rtbno >= mp->m_sb.sb_rblocks)
return false;
- if (!xfs_has_rtgroups(mp))
- return true;
-
- rgbno = xfs_rtb_to_rgbno(mp, rtbno, &rgno);
- if (rgno >= mp->m_sb.sb_rgcount)
- return false;
-
- return xfs_verify_rgno_rgbno(mp, rgno, rgbno);
+ if (xfs_has_rtgroups(mp)) {
+ xfs_rgnumber_t rgno = xfs_rtb_to_rgno(mp, rtbno);
+ xfs_rtxnum_t rtx = xfs_rtb_to_rtx(mp, rtbno);
+
+ if (rgno >= mp->m_sb.sb_rgcount)
+ return false;
+ if (rtx >= xfs_rtgroup_extents(mp, rgno))
+ return false;
+ if (xfs_has_rtsb(mp) && rgno == 0 && rtx == 0)
+ return false;
+ }
+ return true;
}
/*
xfs_rgblock_t rgbno;
int error;
- if (!xfs_has_rtrmapbt(mp)) {
- xchk_rt_init(info->sc, &info->sc->sr,
- XCHK_RTLOCK_BITMAP_SHARED);
- xchk_xref_is_used_rt_space(info->sc, irec->br_startblock,
- irec->br_blockcount);
- xchk_rt_unlock(info->sc, &info->sc->sr);
- return;
- }
-
rgbno = xfs_rtb_to_rgbno(mp, irec->br_startblock, &rgno);
error = xchk_rtgroup_init(info->sc, rgno, &info->sc->sr,
XCHK_RTGLOCK_ALL);
xchk_xref_is_used_rt_space(info->sc, irec->br_startblock,
irec->br_blockcount);
+
+ if (!xfs_has_rtrmapbt(mp))
+ goto out_free;
+
switch (info->whichfork) {
case XFS_DATA_FORK:
xchk_bmap_xref_rmap(info, irec, rgbno);
struct xfs_btree_cur *cur,
const struct xfs_rmap_irec *rec)
{
- xfs_rtblock_t rtbno;
-
/* xattr extents are never stored on realtime devices */
if (rec->rm_flags & XFS_RMAP_ATTR_FORK)
return -EFSCORRUPTED;
return -EFSCORRUPTED;
/* Make sure this isn't free space. */
- rtbno = xfs_rgbno_to_rtb(sc->mp, cur->bc_ino.rtg->rtg_rgno,
- rec->rm_startblock);
- return xrep_require_rtext_inuse(sc, rtbno, rec->rm_blockcount, false);
+ return xrep_require_rtext_inuse(sc, cur->bc_ino.rtg, rec->rm_startblock,
+ rec->rm_blockcount, false);
}
/* Record realtime extents that belong to this inode's fork. */
struct xfs_scrub *sc = rb->sc;
int error;
- if (xrep_is_rtmeta_ino(sc, rtg, sc->ip->i_ino))
+ if (xrep_is_rtmeta_ino(rtg, sc->ip->i_ino))
return 0;
error = xrep_rtgroup_init(sc, rtg, &sc->sr,
int error = 0;
/* Iterate the rtrmaps for extents. */
- for_each_rtgroup(sc->mp, rgno, rtg) {
- error = xrep_bmap_scan_rtgroup(rb, rtg);
- if (error) {
- xfs_rtgroup_rele(rtg);
- return error;
+ if (xfs_has_rtgroups(sc->mp)) {
+ for_each_rtgroup(sc->mp, rgno, rtg) {
+ error = xrep_bmap_scan_rtgroup(rb, rtg);
+ if (error) {
+ xfs_rtgroup_rele(rtg);
+ return error;
+ }
}
}
return 0;
}
-/*
- * For scrubbing a realtime file, grab all the in-core resources we'll need to
- * check the realtime metadata, which means taking the ILOCK of the realtime
- * metadata inodes. Callers must not join these inodes to the transaction
- * with non-zero lockflags or concurrency problems will result. The
- * @rtlock_flags argument takes XCHK_RTLOCK_* flags because scrub has somewhat
- * unusual locking requirements.
- */
-void
-xchk_rt_init(
- struct xfs_scrub *sc,
- struct xchk_rt *sr,
- unsigned int rtlock_flags)
-{
- ASSERT(!(rtlock_flags & ~XCHK_RTLOCK_ALL));
- ASSERT(hweight32(rtlock_flags & (XCHK_RTLOCK_BITMAP |
- XCHK_RTLOCK_BITMAP_SHARED)) < 2);
- ASSERT(hweight32(rtlock_flags & (XCHK_RTLOCK_SUMMARY |
- XCHK_RTLOCK_SUMMARY_SHARED)) < 2);
- ASSERT(sr->rtg == NULL);
-
- if (rtlock_flags & XCHK_RTLOCK_BITMAP)
- xfs_ilock(sc->mp->m_rbmip, XFS_ILOCK_EXCL);
- else if (rtlock_flags & XCHK_RTLOCK_BITMAP_SHARED)
- xfs_ilock(sc->mp->m_rbmip, XFS_ILOCK_SHARED);
-
- if (rtlock_flags & XCHK_RTLOCK_SUMMARY)
- xfs_ilock(sc->mp->m_rsumip, XFS_ILOCK_EXCL);
- else if (rtlock_flags & XCHK_RTLOCK_SUMMARY_SHARED)
- xfs_ilock(sc->mp->m_rsumip, XFS_ILOCK_SHARED);
-
- sr->rtlock_flags = rtlock_flags;
-}
-
-/*
- * Unlock the realtime metadata inodes. This must be done /after/ committing
- * (or cancelling) the scrub transaction.
- */
-void
-xchk_rt_unlock(
- struct xfs_scrub *sc,
- struct xchk_rt *sr)
-{
- ASSERT(sr->rtg == NULL);
-
- if (!sr->rtlock_flags)
- return;
-
- if (sr->rtlock_flags & XCHK_RTLOCK_SUMMARY)
- xfs_iunlock(sc->mp->m_rsumip, XFS_ILOCK_EXCL);
- else if (sr->rtlock_flags & XCHK_RTLOCK_SUMMARY_SHARED)
- xfs_iunlock(sc->mp->m_rsumip, XFS_ILOCK_SHARED);
-
- if (sr->rtlock_flags & XCHK_RTLOCK_BITMAP)
- xfs_iunlock(sc->mp->m_rbmip, XFS_ILOCK_EXCL);
- else if (sr->rtlock_flags & XCHK_RTLOCK_BITMAP_SHARED)
- xfs_iunlock(sc->mp->m_rbmip, XFS_ILOCK_SHARED);
-
- sr->rtlock_flags = 0;
-}
-
-/* Drop only the shared rt bitmap lock. */
-void
-xchk_rt_unlock_rtbitmap(
- struct xfs_scrub *sc)
-{
- ASSERT(sc->sr.rtlock_flags & XCHK_RTLOCK_BITMAP_SHARED);
-
- xfs_iunlock(sc->mp->m_rbmip, XFS_ILOCK_SHARED);
- sc->sr.rtlock_flags &= ~XCHK_RTLOCK_BITMAP_SHARED;
-}
-
#ifdef CONFIG_XFS_RT
/* Lock all the rt group metadata inode ILOCKs and wait for intents. */
int
int xchk_setup_dirtree(struct xfs_scrub *sc);
int xchk_setup_metapath(struct xfs_scrub *sc);
#ifdef CONFIG_XFS_RT
-int xchk_setup_rtbitmap(struct xfs_scrub *sc);
int xchk_setup_rtsummary(struct xfs_scrub *sc);
int xchk_setup_rgsuperblock(struct xfs_scrub *sc);
int xchk_setup_rgbitmap(struct xfs_scrub *sc);
int xchk_setup_rtrmapbt(struct xfs_scrub *sc);
int xchk_setup_rtrefcountbt(struct xfs_scrub *sc);
#else
-# define xchk_setup_rtbitmap xchk_setup_nothing
# define xchk_setup_rtsummary xchk_setup_nothing
# define xchk_setup_rgsuperblock xchk_setup_nothing
# define xchk_setup_rgbitmap xchk_setup_nothing
return error == -ENOENT ? -EFSCORRUPTED : error;
}
-/* Lock the rt bitmap in exclusive mode */
-#define XCHK_RTLOCK_BITMAP (1U << 31)
-/* Lock the rt bitmap in shared mode */
-#define XCHK_RTLOCK_BITMAP_SHARED (1U << 30)
-/* Lock the rt summary in exclusive mode */
-#define XCHK_RTLOCK_SUMMARY (1U << 29)
-/* Lock the rt summary in shared mode */
-#define XCHK_RTLOCK_SUMMARY_SHARED (1U << 28)
-
-#define XCHK_RTLOCK_ALL (XCHK_RTLOCK_BITMAP | \
- XCHK_RTLOCK_BITMAP_SHARED | \
- XCHK_RTLOCK_SUMMARY | \
- XCHK_RTLOCK_SUMMARY_SHARED)
-
-void xchk_rt_init(struct xfs_scrub *sc, struct xchk_rt *sr,
- unsigned int xchk_rtlock_flags);
-void xchk_rt_unlock(struct xfs_scrub *sc, struct xchk_rt *sr);
-void xchk_rt_unlock_rtbitmap(struct xfs_scrub *sc);
-
#ifdef CONFIG_XFS_RT
/* All the locks we need to check an rtgroup. */
if (!rtg)
return -EFSCORRUPTED;
- if (xrep_is_rtmeta_ino(sc, rtg, sc->ip->i_ino))
+ if (xrep_is_rtmeta_ino(rtg, sc->ip->i_ino))
goto out_rtg;
error = xrep_rtgroup_init(sc, rtg, &sc->sr,
xfs_extlen_t maxlen,
struct xrep_cow_extent *repl)
{
- xfs_rtxnum_t rtx = 0;
- xfs_rtxlen_t maxrtx;
- xfs_rtxlen_t rtxlen = 0;
- xfs_rtblock_t rtbno;
- xfs_extlen_t len;
+ xfs_rtxlen_t maxrtx = xfs_extlen_to_rtxlen(sc->mp, maxlen);
int error;
- maxrtx = xfs_rtb_to_rtx(sc->mp, maxlen);
error = xfs_trans_reserve_more(sc->tp, 0, maxrtx);
if (error)
return error;
- xfs_rtbitmap_lock(sc->mp);
- xfs_rtbitmap_trans_join(sc->tp);
- error = xfs_rtallocate_extent(sc->tp, 0, maxlen, &rtxlen, &rtx);
+ error = xfs_rtallocate_rtgs(sc->tp, 0, 1, maxrtx, 1, false, false,
+ &repl->fsbno, &repl->len);
if (error)
return error;
-
- rtbno = xfs_rtx_to_rtb(sc->mp, rtx);
- len = xfs_rtxlen_to_extlen(sc->mp, rtxlen);
- xfs_refcount_alloc_cow_extent(sc->tp, true, rtbno, len);
-
- repl->fsbno = rtbno;
- repl->len = len;
+ xfs_refcount_alloc_cow_extent(sc->tp, true, repl->fsbno, repl->len);
return 0;
}
#include "xfs_rtbitmap.h"
#include "xfs_inode.h"
#include "xfs_icache.h"
+#include "xfs_rtgroup.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
#include "scrub/trace.h"
#ifdef CONFIG_XFS_RT
STATIC int
xchk_fscount_add_frextent(
- struct xfs_mount *mp,
+ struct xfs_rtgroup *rtg,
struct xfs_trans *tp,
const struct xfs_rtalloc_rec *rec,
void *priv)
struct xchk_fscounters *fsc)
{
struct xfs_mount *mp = sc->mp;
+ struct xfs_rtgroup *rtg;
+ xfs_rgnumber_t rgno;
int error;
fsc->frextents = 0;
if (!xfs_has_realtime(mp))
return 0;
- xfs_rtbitmap_lock_shared(sc->mp, XFS_RBMLOCK_BITMAP);
- error = xfs_rtalloc_query_all(sc->mp, sc->tp,
- xchk_fscount_add_frextent, fsc);
- if (error) {
- xchk_set_incomplete(sc);
- goto out_unlock;
+ for_each_rtgroup(mp, rgno, rtg) {
+ xfs_rtgroup_lock(rtg, XFS_RTGLOCK_BITMAP_SHARED);
+ error = xfs_rtalloc_query_all(rtg, sc->tp,
+ xchk_fscount_add_frextent, fsc);
+ xfs_rtgroup_unlock(rtg, XFS_RTGLOCK_BITMAP_SHARED);
+ if (error) {
+ xchk_set_incomplete(sc);
+ xfs_rtgroup_rele(rtg);
+ return error;
+ }
}
fsc->frextents_delayed = percpu_counter_sum(&mp->m_delalloc_rtextents);
-
-out_unlock:
- xfs_rtbitmap_unlock_shared(sc->mp, XFS_RBMLOCK_BITMAP);
- return error;
+ return 0;
}
#else
STATIC int
[XFS_SCRUB_TYPE_XATTR] = { XHG_INO, XFS_SICK_INO_XATTR },
[XFS_SCRUB_TYPE_SYMLINK] = { XHG_INO, XFS_SICK_INO_SYMLINK },
[XFS_SCRUB_TYPE_PARENT] = { XHG_INO, XFS_SICK_INO_PARENT },
- [XFS_SCRUB_TYPE_RTBITMAP] = { XHG_RT, XFS_SICK_RT_BITMAP },
- [XFS_SCRUB_TYPE_RTSUM] = { XHG_RT, XFS_SICK_RT_SUMMARY },
+ [XFS_SCRUB_TYPE_RGBITMAP] = { XHG_RTGROUP, XFS_SICK_RG_BITMAP },
+ [XFS_SCRUB_TYPE_RTSUM] = { XHG_RTGROUP, XFS_SICK_RT_SUMMARY },
[XFS_SCRUB_TYPE_UQUOTA] = { XHG_FS, XFS_SICK_FS_UQUOTA },
[XFS_SCRUB_TYPE_GQUOTA] = { XHG_FS, XFS_SICK_FS_GQUOTA },
[XFS_SCRUB_TYPE_PQUOTA] = { XHG_FS, XFS_SICK_FS_PQUOTA },
[XFS_SCRUB_TYPE_DIRTREE] = { XHG_INO, XFS_SICK_INO_DIRTREE },
[XFS_SCRUB_TYPE_METAPATH] = { XHG_FS, XFS_SICK_FS_METAPATH },
[XFS_SCRUB_TYPE_RGSUPER] = { XHG_RTGROUP, XFS_SICK_RG_SUPER },
- [XFS_SCRUB_TYPE_RGBITMAP] = { XHG_RTGROUP, XFS_SICK_RG_BITMAP },
[XFS_SCRUB_TYPE_RTRMAPBT] = { XHG_RTGROUP, XFS_SICK_RG_RMAPBT },
[XFS_SCRUB_TYPE_RTREFCBT] = { XHG_RTGROUP, XFS_SICK_RG_REFCNTBT },
};
int error;
if (!xfs_has_realtime(sc->mp) ||
- xrep_is_rtmeta_ino(sc, rtg, sc->sm->sm_ino))
+ xrep_is_rtmeta_ino(rtg, sc->sm->sm_ino))
return 0;
error = xrep_rtgroup_init(sc, rtg, &sc->sr, XFS_RTGLOCK_RMAP);
if (!xfs_has_rmapbt(ri->sc->mp))
return -EOPNOTSUPP;
- for_each_rtgroup(ri->sc->mp, rgno, rtg) {
- error = xrep_dinode_count_rtgroup_rmaps(ri, rtg);
- if (error) {
- xfs_rtgroup_rele(rtg);
- return error;
+ if (xfs_has_rtgroups(ri->sc->mp)) {
+ for_each_rtgroup(ri->sc->mp, rgno, rtg) {
+ error = xrep_dinode_count_rtgroup_rmaps(ri, rtg);
+ if (error) {
+ xfs_rtgroup_rele(rtg);
+ return error;
+ }
}
}
return 0;
rtg = xfs_rtgroup_get(mp, sm->sm_agno);
- usedlen = rtg->rtg_blockcount;
+ usedlen = rtg->rtg_extents * mp->m_sb.sb_rextsize;
xfs_rtgroup_put(rtg);
if (xfs_has_rmapbt(mp))
int
xrep_require_rtext_inuse(
struct xfs_scrub *sc,
- xfs_rtblock_t rtbno,
+ struct xfs_rtgroup *rtg,
+ xfs_rgblock_t rgbno,
xfs_filblks_t len,
bool must_align)
{
bool is_free = false;
int error;
- mod = xfs_rtb_to_rtxoff(mp, rtbno);
+ mod = xfs_rtb_to_rtxoff(mp, rgbno);
if (must_align && mod != 0)
return -EFSCORRUPTED;
- startrtx = xfs_rtb_to_rtx(mp, rtbno);
+ startrtx = xfs_rgbno_to_rtx(mp, rgbno);
- mod = xfs_rtb_to_rtxoff(mp, rtbno + len - 1);
+ mod = xfs_rtb_to_rtxoff(mp, rgbno + len - 1);
if (must_align && mod != mp->m_sb.sb_rextsize - 1)
return -EFSCORRUPTED;
- endrtx = xfs_rtb_to_rtx(mp, rtbno + len - 1);
+ endrtx = xfs_rgbno_to_rtx(mp, rgbno + len - 1);
- error = xfs_rtalloc_extent_is_free(mp, sc->tp, startrtx,
+ error = xfs_rtalloc_extent_is_free(rtg, sc->tp, startrtx,
endrtx - startrtx + 1, &is_free);
if (error)
return error;
/* Are we looking at a realtime metadata inode? */
bool
xrep_is_rtmeta_ino(
- struct xfs_scrub *sc,
struct xfs_rtgroup *rtg,
xfs_ino_t ino)
{
unsigned int i;
- /*
- * All filesystems have rt bitmap and summary inodes, even if they
- * don't have an rt section.
- */
- if (ino == sc->mp->m_rbmip->i_ino)
- return true;
- if (ino == sc->mp->m_rsumip->i_ino)
- return true;
-
- /* Newer rtgroup metadata files are not guaranteed to exist */
for (i = 0; i < XFS_RTG_MAX; i++) {
if (rtg->rtg_inodes[i] && ino == rtg->rtg_inodes[i]->i_ino)
return true;
int xrep_rtgroup_init(struct xfs_scrub *sc, struct xfs_rtgroup *rtg,
struct xchk_rt *sr, unsigned int rtglock_flags);
void xrep_rtgroup_btcur_init(struct xfs_scrub *sc, struct xchk_rt *sr);
-int xrep_require_rtext_inuse(struct xfs_scrub *sc, xfs_rtblock_t rtbno,
- xfs_filblks_t len, bool must_align);
+int xrep_require_rtext_inuse(struct xfs_scrub *sc, struct xfs_rtgroup *rtg,
+ xfs_rgblock_t rgbno, xfs_filblks_t len, bool must_align);
xfs_extlen_t xrep_calc_rtgroup_resblks(struct xfs_scrub *sc);
#else
# define xrep_rtgroup_init(sc, rtg, sr, lockflags) (-ENOSYS)
# define xrep_calc_rtgroup_resblks(sc) (0)
#endif /* CONFIG_XFS_RT */
-bool xrep_is_rtmeta_ino(struct xfs_scrub *sc, struct xfs_rtgroup *rtg,
- xfs_ino_t ino);
+bool xrep_is_rtmeta_ino(struct xfs_rtgroup *rtg, xfs_ino_t ino);
int xrep_check_ino_btree_mapping(struct xfs_scrub *sc,
const struct xfs_rmap_irec *rec);
int xrep_metapath(struct xfs_scrub *sc);
#ifdef CONFIG_XFS_RT
-int xrep_rtbitmap(struct xfs_scrub *sc);
int xrep_rtsummary(struct xfs_scrub *sc);
int xrep_rgsuperblock(struct xfs_scrub *sc);
int xrep_rgbitmap(struct xfs_scrub *sc);
int xrep_rtrmapbt(struct xfs_scrub *sc);
int xrep_rtrefcountbt(struct xfs_scrub *sc);
#else
-# define xrep_rtbitmap xrep_notsupported
# define xrep_rtsummary xrep_notsupported
# define xrep_rgsuperblock xrep_notsupported
# define xrep_rgbitmap xrep_notsupported
#define xrep_bmap_data xrep_notsupported
#define xrep_bmap_attr xrep_notsupported
#define xrep_bmap_cow xrep_notsupported
-#define xrep_rtbitmap xrep_notsupported
#define xrep_quota xrep_notsupported
#define xrep_quotacheck xrep_notsupported
#define xrep_nlinks xrep_notsupported
#include "scrub/rtbitmap.h"
#include "scrub/btree.h"
-static inline void
-xchk_rtbitmap_compute_geometry(
- struct xfs_mount *mp,
- struct xchk_rtbitmap *rtb)
-{
- if (mp->m_sb.sb_rblocks == 0)
- return;
-
- rtb->rextents = xfs_rtb_to_rtx(mp, mp->m_sb.sb_rblocks);
- rtb->rextslog = xfs_compute_rextslog(rtb->rextents);
- rtb->rbmblocks = xfs_rtbitmap_blockcount(mp, rtb->rextents);
-}
-
/* Set us up with the realtime group metadata locked. */
int
xchk_setup_rgbitmap(
{
struct xfs_mount *mp = sc->mp;
struct xchk_rgbitmap *rgb;
+ struct xfs_rtgroup *rtg;
unsigned int wordcnt = xchk_rgbitmap_wordcnt(sc);
int error;
sc->buf = rgb;
rgb->rtglock_flags = XCHK_RTGLOCK_ALL;
+ rtg = xfs_rtgroup_get(mp, sc->sm->sm_agno);
+ if (!rtg)
+ return -ENOENT;
+
if (xchk_could_repair(sc)) {
error = xrep_setup_rgbitmap(sc, rgb);
if (error)
- return error;
+ goto out_rtg;
}
- error = xchk_trans_alloc(sc, rgb->rtb.resblks);
+ error = xchk_trans_alloc(sc, rgb->resblks);
if (error)
- return error;
+ goto out_rtg;
- error = xchk_install_live_inode(sc, mp->m_rbmip);
+ error = xchk_install_live_inode(sc, rtg->rtg_inodes[XFS_RTG_BITMAP]);
if (error)
- return error;
+ goto out_rtg;
error = xchk_rtgroup_init(sc, sc->sm->sm_agno, &sc->sr,
rgb->rtglock_flags);
if (error)
- return error;
+ goto out_rtg;
/*
* Now that we've locked the rtbitmap, we can't race with growfsrt
* trying to expand the bitmap or change the size of the rt volume.
* Hence it is safe to compute and check the geometry values.
*/
- xchk_rtbitmap_compute_geometry(mp, &rgb->rtb);
- return 0;
-}
-
-/* Set us up with the realtime metadata locked. */
-int
-xchk_setup_rtbitmap(
- struct xfs_scrub *sc)
-{
- struct xfs_mount *mp = sc->mp;
- struct xchk_rtbitmap *rtb;
- int error;
-
- if (xchk_need_intent_drain(sc))
- xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN);
-
- rtb = kzalloc(sizeof(struct xchk_rtbitmap), XCHK_GFP_FLAGS);
- if (!rtb)
- return -ENOMEM;
- sc->buf = rtb;
-
- if (xchk_could_repair(sc)) {
- error = xrep_setup_rtbitmap(sc, rtb);
- if (error)
- return error;
+ if (mp->m_sb.sb_rblocks) {
+ rgb->rextents = xfs_blen_to_rtbxlen(mp, mp->m_sb.sb_rblocks);
+ rgb->rextslog = xfs_compute_rextslog(rgb->rextents);
+ rgb->rbmblocks = xfs_rtbitmap_blockcount(mp);
}
-
- error = xchk_trans_alloc(sc, rtb->resblks);
- if (error)
- return error;
-
- error = xchk_install_live_inode(sc, sc->mp->m_rbmip);
- if (error)
- return error;
-
- error = xchk_ino_dqattach(sc);
- if (error)
- return error;
-
- xchk_rt_init(sc, &sc->sr, XCHK_RTLOCK_BITMAP);
-
- /*
- * Now that we've locked the rtbitmap, we can't race with growfsrt
- * trying to expand the bitmap or change the size of the rt volume.
- * Hence it is safe to compute and check the geometry values.
- */
- xchk_rtbitmap_compute_geometry(mp, rtb);
- return 0;
+out_rtg:
+ xfs_rtgroup_put(rtg);
+ return error;
}
-/* Per-rtgroup bitmap contents. */
-
/* Cross-reference rtbitmap entries with other metadata. */
STATIC void
xchk_rgbitmap_xref(
/* Scrub a free extent record from the realtime bitmap. */
STATIC int
xchk_rgbitmap_rec(
- struct xfs_mount *mp,
+ struct xfs_rtgroup *rtg,
struct xfs_trans *tp,
const struct xfs_rtalloc_rec *rec,
void *priv)
xfs_rtblock_t startblock;
xfs_filblks_t blockcount;
- startblock = xfs_rtx_to_rtb(mp, rec->ar_startext);
- blockcount = xfs_rtx_to_rtb(mp, rec->ar_extcount);
+ startblock = xfs_rtx_to_rtb(rtg, rec->ar_startext);
+ blockcount = xfs_rtxlen_to_extlen(rtg->rtg_mount, rec->ar_extcount);
- if (!xfs_verify_rtbext(mp, startblock, blockcount))
+ if (!xfs_verify_rtbext(rtg->rtg_mount, startblock, blockcount))
xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
xchk_rgbitmap_xref(rgb, startblock, blockcount);
return 0;
}
-/* Scrub this group's realtime bitmap. */
-int
-xchk_rgbitmap(
- struct xfs_scrub *sc)
-{
- struct xfs_mount *mp = sc->mp;
- struct xfs_rtgroup *rtg = sc->sr.rtg;
- struct xchk_rgbitmap *rgb = sc->buf;
- xfs_rtblock_t start, last;
- xfs_rgblock_t last_rgbno = rtg->rtg_blockcount - 1;
- int error;
-
- /* Sanity check the realtime bitmap size. */
- if (sc->ip->i_disk_size < XFS_FSB_TO_B(mp, rgb->rtb.rbmblocks)) {
- xchk_ino_set_corrupt(sc, sc->ip->i_ino);
- return 0;
- }
-
- /*
- * Check only the portion of the rtbitmap that corresponds to this
- * realtime group.
- */
- rgb->next_free_rgbno = 0;
- start = xfs_rgbno_to_rtb(mp, rtg->rtg_rgno, 0);
- last = xfs_rgbno_to_rtb(mp, rtg->rtg_rgno, last_rgbno);
-
- error = xfs_rtalloc_query_range(mp, sc->tp, xfs_rtb_to_rtx(mp, start),
- xfs_rtb_to_rtx(mp, last), xchk_rgbitmap_rec, rgb);
- if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
- return error;
-
- /*
- * Check that the are rmappings for all rt extents between the end of
- * the last free extent we saw and the last possible extent in the rt
- * group.
- */
- if (rgb->next_free_rgbno < last_rgbno)
- xchk_xref_has_rt_owner(sc, rgb->next_free_rgbno,
- last_rgbno - rgb->next_free_rgbno);
-
- return 0;
-}
-
-/* Realtime bitmap. */
-
-/* Scrub a free extent record from the realtime bitmap. */
-STATIC int
-xchk_rtbitmap_rec(
- struct xfs_mount *mp,
- struct xfs_trans *tp,
- const struct xfs_rtalloc_rec *rec,
- void *priv)
-{
- struct xfs_scrub *sc = priv;
- xfs_rtblock_t startblock;
- xfs_filblks_t blockcount;
-
- startblock = xfs_rtx_to_rtb(mp, rec->ar_startext);
- blockcount = xfs_rtx_to_rtb(mp, rec->ar_extcount);
-
- if (!xfs_verify_rt_freesp(mp, startblock, blockcount))
- xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
- return 0;
-}
-
/* Make sure the entire rtbitmap file is mapped with written extents. */
STATIC int
xchk_rtbitmap_check_extents(
return error;
}
-/* Scrub the realtime bitmap. */
+/* Scrub this group's realtime bitmap. */
int
-xchk_rtbitmap(
+xchk_rgbitmap(
struct xfs_scrub *sc)
{
struct xfs_mount *mp = sc->mp;
- struct xchk_rtbitmap *rtb = sc->buf;
+ struct xfs_rtgroup *rtg = sc->sr.rtg;
+ struct xfs_inode *rbmip = rtg->rtg_inodes[XFS_RTG_BITMAP];
+ struct xchk_rgbitmap *rgb = sc->buf;
+ xfs_rgblock_t last_rgbno =
+ (rtg->rtg_extents * mp->m_sb.sb_rextsize) - 1;
int error;
/* Is sb_rextents correct? */
- if (mp->m_sb.sb_rextents != rtb->rextents) {
- xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
+ if (mp->m_sb.sb_rextents != rgb->rextents) {
+ xchk_ino_set_corrupt(sc, rbmip->i_ino);
return 0;
}
/* Is sb_rextslog correct? */
- if (mp->m_sb.sb_rextslog != rtb->rextslog) {
- xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
+ if (mp->m_sb.sb_rextslog != rgb->rextslog) {
+ xchk_ino_set_corrupt(sc, rbmip->i_ino);
return 0;
}
* Is sb_rbmblocks large enough to handle the current rt volume? In no
* case can we exceed 4bn bitmap blocks since the super field is a u32.
*/
- if (rtb->rbmblocks > U32_MAX) {
- xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
+ if (rgb->rbmblocks > U32_MAX) {
+ xchk_ino_set_corrupt(sc, rbmip->i_ino);
return 0;
}
- if (mp->m_sb.sb_rbmblocks != rtb->rbmblocks) {
- xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
+ if (mp->m_sb.sb_rbmblocks != rgb->rbmblocks) {
+ xchk_ino_set_corrupt(sc, rbmip->i_ino);
return 0;
}
/* The bitmap file length must be aligned to an fsblock. */
- if (mp->m_rbmip->i_disk_size & mp->m_blockmask) {
- xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
+ if (rbmip->i_disk_size & mp->m_blockmask) {
+ xchk_ino_set_corrupt(sc, rbmip->i_ino);
return 0;
}
* growfsrt expands the bitmap file before updating sb_rextents, so the
* file can be larger than sb_rbmblocks.
*/
- if (mp->m_rbmip->i_disk_size < XFS_FSB_TO_B(mp, rtb->rbmblocks)) {
- xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
+ if (rbmip->i_disk_size < XFS_FSB_TO_B(mp, rgb->rbmblocks)) {
+ xchk_ino_set_corrupt(sc, rbmip->i_ino);
return 0;
}
if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
return error;
- /*
- * Each rtgroup checks its portion of the rt bitmap, so if we don't
- * have that feature, we have to check the bitmap contents now.
- */
- if (xfs_has_rtgroups(mp))
- return 0;
-
- error = xfs_rtalloc_query_all(mp, sc->tp, xchk_rtbitmap_rec, sc);
+ rgb->next_free_rgbno = 0;
+ error = xfs_rtalloc_query_all(rtg, sc->tp, xchk_rgbitmap_rec, rgb);
if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
return error;
+ /*
+ * Check that the are rmappings for all rt extents between the end of
+ * the last free extent we saw and the last possible extent in the rt
+ * group.
+ */
+ if (rgb->next_free_rgbno < last_rgbno)
+ xchk_xref_has_rt_owner(sc, rgb->next_free_rgbno,
+ last_rgbno - rgb->next_free_rgbno);
return 0;
}
xfs_rtblock_t rtbno,
xfs_extlen_t len)
{
+ struct xfs_rtgroup *rtg = sc->sr.rtg;
xfs_rtxnum_t startext;
xfs_rtxnum_t endext;
bool is_free;
startext = xfs_rtb_to_rtx(sc->mp, rtbno);
endext = xfs_rtb_to_rtx(sc->mp, rtbno + len - 1);
- error = xfs_rtalloc_extent_is_free(sc->mp, sc->tp, startext,
+ error = xfs_rtalloc_extent_is_free(rtg, sc->tp, startext,
endext - startext + 1, &is_free);
if (!xchk_should_check_xref(sc, &error, NULL))
return;
if (is_free)
- xchk_ino_xref_set_corrupt(sc, sc->mp->m_rbmip->i_ino);
+ xchk_ino_xref_set_corrupt(sc,
+ rtg->rtg_inodes[XFS_RTG_BITMAP]->i_ino);
}
#ifndef __XFS_SCRUB_RTBITMAP_H__
#define __XFS_SCRUB_RTBITMAP_H__
-struct xchk_rtbitmap {
- uint64_t rextents;
- uint64_t rbmblocks;
- unsigned int rextslog;
- unsigned int resblks;
-};
-
/*
* We use an xfile to construct new bitmap blocks for the portion of the
* rtbitmap file that we're replacing. Whereas the ondisk bitmap must be
struct xchk_rgbitmap {
struct xfs_scrub *sc;
- struct xchk_rtbitmap rtb;
+ uint64_t rblocks;
+ uint64_t rextents;
+ unsigned int rextslog;
+ uint64_t rbmblocks;
+ unsigned int resblks;
/* The next free rt group block number that we expect to see. */
xfs_rgblock_t next_free_rgbno;
struct xrep_tempexch tempexch;
#endif
- /* file offset inside the rtbitmap where we start swapping */
- xfs_fileoff_t group_rbmoff;
-
- /* number of rtbitmap blocks for this group */
- xfs_filblks_t group_rbmlen;
-
/* The next rtgroup block we expect to see during our rtrmapbt walk. */
xfs_rgblock_t next_rgbno;
};
#ifdef CONFIG_XFS_ONLINE_REPAIR
-int xrep_setup_rtbitmap(struct xfs_scrub *sc, struct xchk_rtbitmap *rtb);
int xrep_setup_rgbitmap(struct xfs_scrub *sc, struct xchk_rgbitmap *rgb);
/*
return 0;
}
#else
-# define xrep_setup_rtbitmap(sc, rtb) (0)
# define xrep_setup_rgbitmap(sc, rgb) (0)
# define xchk_rgbitmap_wordcnt(sc) (0)
#endif /* CONFIG_XFS_ONLINE_REPAIR */
return error;
/* Create an xfile to hold our reconstructed bitmap. */
- rtbmp_words = xfs_rtbitmap_wordcount(mp, mp->m_sb.sb_rextents);
+ rtbmp_words = xfs_rtbitmap_wordcount(mp);
descr = xchk_xfile_rtgroup_descr(sc, "bitmap file");
error = xfile_create(descr, rtbmp_words << XFS_WORDLOG, &sc->xfile);
kfree(descr);
blocks += xfs_bmbt_calc_size(mp, blocks) * 2;
if (blocks > UINT_MAX)
return -EOPNOTSUPP;
-
- rgb->rtb.resblks += blocks;
+ rgb->resblks += blocks;
/*
* We must hold rbmip with ILOCK_EXCL to use the file mapping exchange
wordoff << XFS_WORDLOG);
}
-/*
- * Preserve the portions of the rtbitmap block for the start of this rtgroup
- * that map to the previous rtgroup.
- */
-STATIC int
-xrep_rgbitmap_load_before(
- struct xchk_rgbitmap *rgb)
-{
- struct xfs_scrub *sc = rgb->sc;
- struct xfs_mount *mp = sc->mp;
- struct xfs_rtgroup *rtg = sc->sr.rtg;
- xrep_wordoff_t wordoff;
- xfs_rtblock_t group_rtbno;
- xfs_rtxnum_t group_rtx, rbmoff_rtx;
- xfs_rtword_t ondisk_word;
- xfs_rtword_t xfile_word;
- xfs_rtword_t mask;
- xrep_wordcnt_t wordcnt;
- int bit;
- int error;
-
- /*
- * Compute the file offset within the rtbitmap block that corresponds
- * to the start of this group, and decide if we need to read blocks
- * from the group before this one.
- */
- group_rtbno = xfs_rgbno_to_rtb(mp, rtg->rtg_rgno, 0);
- group_rtx = xfs_rtb_to_rtx(mp, group_rtbno);
-
- rgb->group_rbmoff = xfs_rtx_to_rbmblock(mp, group_rtx);
- rbmoff_rtx = xfs_rbmblock_to_rtx(mp, rgb->group_rbmoff);
- rgb->prep_wordoff = rtx_to_wordoff(mp, rbmoff_rtx);
-
- trace_xrep_rgbitmap_load(rtg, rgb->group_rbmoff, rbmoff_rtx,
- group_rtx - 1);
-
- if (rbmoff_rtx == group_rtx)
- return 0;
-
- rgb->args.mp = sc->mp;
- rgb->args.tp = sc->tp;
- error = xfs_rtbitmap_read_buf(&rgb->args, rgb->group_rbmoff);
- if (error) {
- /*
- * Reading the existing rbmblock failed, and we must deal with
- * the part of the rtbitmap block that corresponds to the
- * previous group. The most conservative option is to fill
- * that part of the bitmap with zeroes so that it won't get
- * allocated. The xfile contains zeroes already, so we can
- * return.
- */
- return 0;
- }
-
- /*
- * Copy full rtbitmap words into memory from the beginning of the
- * ondisk block until we get to the word that corresponds to the start
- * of this group.
- */
- wordoff = rtx_to_wordoff(mp, rbmoff_rtx);
- wordcnt = rtxlen_to_wordcnt(group_rtx - rbmoff_rtx);
- if (wordcnt > 0) {
- union xfs_rtword_raw *p;
-
- p = xfs_rbmblock_wordptr(&rgb->args, 0);
- error = xfbmp_copyin(rgb, wordoff, p, wordcnt);
- if (error)
- goto out_rele;
-
- trace_xrep_rgbitmap_load_words(mp, rgb->group_rbmoff, wordoff,
- wordcnt);
- wordoff += wordcnt;
- }
-
- /*
- * Compute the bit position of the first rtextent of this group. If
- * the bit position is zero, we don't have to RMW a partial word and
- * move to the next step.
- */
- bit = group_rtx & XREP_RTBMP_WORDMASK;
- if (bit == 0)
- goto out_rele;
-
- /*
- * Create a mask of the bits that we want to load from disk. These
- * bits track space in a different rtgroup, which is why we must
- * preserve them even as we replace parts of the bitmap.
- */
- mask = ~((((xfs_rtword_t)1 << (XFS_NBWORD - bit)) - 1) << bit);
-
- error = xfbmp_load(rgb, wordoff, &xfile_word);
- if (error)
- goto out_rele;
- ondisk_word = xfs_rtbitmap_getword(&rgb->args, wordcnt);
-
- trace_xrep_rgbitmap_load_word(mp, wordoff, bit, ondisk_word,
- xfile_word, mask);
-
- xfile_word &= ~mask;
- xfile_word |= (ondisk_word & mask);
-
- error = xfbmp_store(rgb, wordoff, xfile_word);
- if (error)
- goto out_rele;
-
-out_rele:
- xfs_rtbuf_cache_relse(&rgb->args);
- return error;
-}
-
-/*
- * Preserve the portions of the rtbitmap block for the end of this rtgroup
- * that map to the next rtgroup.
- */
-STATIC int
-xrep_rgbitmap_load_after(
- struct xchk_rgbitmap *rgb)
-{
- struct xfs_scrub *sc = rgb->sc;
- struct xfs_mount *mp = rgb->sc->mp;
- struct xfs_rtgroup *rtg = rgb->sc->sr.rtg;
- xrep_wordoff_t wordoff;
- xfs_rtblock_t last_rtbno;
- xfs_rtxnum_t last_group_rtx, last_rbmblock_rtx;
- xfs_fileoff_t last_group_rbmoff;
- xfs_rtword_t ondisk_word;
- xfs_rtword_t xfile_word;
- xfs_rtword_t mask;
- xrep_wordcnt_t wordcnt;
- unsigned int last_group_word;
- int bit;
- int error;
-
- last_rtbno = xfs_rgbno_to_rtb(mp, rtg->rtg_rgno,
- rtg->rtg_blockcount - 1);
- last_group_rtx = xfs_rtb_to_rtx(mp, last_rtbno);
-
- last_group_rbmoff = xfs_rtx_to_rbmblock(mp, last_group_rtx);
- rgb->group_rbmlen = last_group_rbmoff - rgb->group_rbmoff + 1;
- last_rbmblock_rtx = xfs_rbmblock_to_rtx(mp, last_group_rbmoff + 1) - 1;
-
- trace_xrep_rgbitmap_load(rtg, last_group_rbmoff, last_group_rtx + 1,
- last_rbmblock_rtx);
-
- if (last_rbmblock_rtx == last_group_rtx ||
- rtg->rtg_rgno == mp->m_sb.sb_rgcount - 1)
- return 0;
-
- rgb->args.mp = sc->mp;
- rgb->args.tp = sc->tp;
- error = xfs_rtbitmap_read_buf(&rgb->args, last_group_rbmoff);
- if (error) {
- /*
- * Reading the existing rbmblock failed, and we must deal with
- * the part of the rtbitmap block that corresponds to the
- * previous group. The most conservative option is to fill
- * that part of the bitmap with zeroes so that it won't get
- * allocated. The xfile contains zeroes already, so we can
- * return.
- */
- return 0;
- }
-
- /*
- * Compute the bit position of the first rtextent of the next group.
- * If the bit position is zero, we don't have to RMW a partial word
- * and move to the next step.
- */
- wordoff = rtx_to_wordoff(mp, last_group_rtx);
- bit = (last_group_rtx + 1) & XREP_RTBMP_WORDMASK;
- if (bit == 0)
- goto copy_words;
-
- /*
- * Create a mask of the bits that we want to load from disk. These
- * bits track space in a different rtgroup, which is why we must
- * preserve them even as we replace parts of the bitmap.
- */
- mask = (((xfs_rtword_t)1 << (XFS_NBWORD - bit)) - 1) << bit;
-
- error = xfbmp_load(rgb, wordoff, &xfile_word);
- if (error)
- goto out_rele;
- last_group_word = xfs_rtx_to_rbmword(mp, last_group_rtx);
- ondisk_word = xfs_rtbitmap_getword(&rgb->args, last_group_word);
-
- trace_xrep_rgbitmap_load_word(mp, wordoff, bit, ondisk_word,
- xfile_word, mask);
-
- xfile_word &= ~mask;
- xfile_word |= (ondisk_word & mask);
-
- error = xfbmp_store(rgb, wordoff, xfile_word);
- if (error)
- goto out_rele;
-
-copy_words:
- /* Copy as many full words as we can. */
- wordoff++;
- wordcnt = rtxlen_to_wordcnt(last_rbmblock_rtx - last_group_rtx);
- if (wordcnt > 0) {
- union xfs_rtword_raw *p;
-
- p = xfs_rbmblock_wordptr(&rgb->args,
- mp->m_blockwsize - wordcnt);
- error = xfbmp_copyin(rgb, wordoff, p, wordcnt);
- if (error)
- goto out_rele;
-
- trace_xrep_rgbitmap_load_words(mp, last_group_rbmoff, wordoff,
- wordcnt);
- }
-
-out_rele:
- xfs_rtbuf_cache_relse(&rgb->args);
- return error;
-}
-
/* Perform a logical OR operation on an rtword in the incore bitmap. */
static int
xrep_rgbitmap_or(
struct xfs_mount *mp = rgb->sc->mp;
struct xchk_rt *sr = &rgb->sc->sr;
struct xfs_rtgroup *rtg = sr->rtg;
- xfs_rtblock_t rtbno;
xfs_rtxnum_t startrtx;
xfs_rtxnum_t nextrtx;
xrep_wordoff_t wordoff, nextwordoff;
* Convert rt blocks to rt extents The block range we find must be
* aligned to an rtextent boundary on both ends.
*/
- rtbno = xfs_rgbno_to_rtb(mp, rtg->rtg_rgno, rgb->next_rgbno);
- mod = xfs_rtb_to_rtxoff(mp, rtbno);
+ startrtx = xfs_rgbno_to_rtx(mp, rgb->next_rgbno);
+ mod = xfs_rtb_to_rtxoff(mp, rgb->next_rgbno);
if (mod)
return -EFSCORRUPTED;
- startrtx = xfs_rtb_to_rtx(mp, rtbno);
- rtbno = xfs_rgbno_to_rtb(mp, rtg->rtg_rgno, rgbno - 1);
- mod = xfs_rtb_to_rtxoff(mp, rtbno);
+ nextrtx = xfs_rgbno_to_rtx(mp, rgbno - 1) + 1;
+ mod = xfs_rtb_to_rtxoff(mp, rgbno - 1);
if (mod != mp->m_sb.sb_rextsize - 1)
return -EFSCORRUPTED;
- nextrtx = xfs_rtb_to_rtx(mp, rtbno) + 1;
/* Must not be shared or CoW staging. */
if (sr->refc_cur) {
struct xfs_scrub *sc = rgb->sc;
struct xfs_mount *mp = sc->mp;
struct xfs_rtgroup *rtg = sc->sr.rtg;
+ u64 blockcount;
int error;
/* Prepare a buffer of ones so that we can accelerate bulk setting. */
* Mark as free every possible rt extent from the last one we saw to
* the end of the rt group.
*/
- if (rgb->next_rgbno < rtg->rtg_blockcount) {
- error = xrep_rgbitmap_mark_free(rgb, rtg->rtg_blockcount);
+ blockcount = rtg->rtg_extents * mp->m_sb.sb_rextsize;
+ if (rgb->next_rgbno < blockcount) {
+ error = xrep_rgbitmap_mark_free(rgb, blockcount);
if (error)
goto out;
}
return 0;
}
-/* Repair the realtime bitmap for this rt group. */
-int
-xrep_rgbitmap(
- struct xfs_scrub *sc)
-{
- struct xchk_rgbitmap *rgb = sc->buf;
- int error;
-
- /* We require the realtime rmapbt to rebuild anything. */
- if (!xfs_has_rtrmapbt(sc->mp))
- return -EOPNOTSUPP;
- /* We require atomic file exchange range to rebuild anything. */
- if (!xfs_has_exchange_range(sc->mp))
- return -EOPNOTSUPP;
-
- /*
- * If the start or end of this rt group happens to be in the middle of
- * an rtbitmap block, try to read in the parts of the bitmap that are
- * from some other group.
- */
- error = xrep_rgbitmap_load_before(rgb);
- if (error)
- return error;
- error = xrep_rgbitmap_load_after(rgb);
- if (error)
- return error;
-
- /*
- * Generate the new rtbitmap data. We don't need the rtbmp information
- * once this call is finished.
- */
- error = xrep_rgbitmap_find_freespace(rgb);
- if (error)
- return error;
-
- /*
- * Try to take ILOCK_EXCL of the temporary file. We had better be the
- * only ones holding onto this inode, but we can't block while holding
- * the rtbitmap file's ILOCK_EXCL.
- */
- while (!xrep_tempfile_ilock_nowait(sc)) {
- if (xchk_should_terminate(sc, &error))
- return error;
- delay(1);
- }
-
- /*
- * Make sure we have space allocated for the part of the bitmap
- * file that corresponds to this group.
- */
- xfs_trans_ijoin(sc->tp, sc->ip, 0);
- xfs_trans_ijoin(sc->tp, sc->tempip, 0);
- error = xrep_tempfile_prealloc(sc, rgb->group_rbmoff, rgb->group_rbmlen);
- if (error)
- return error;
-
- /* Last chance to abort before we start committing fixes. */
- if (xchk_should_terminate(sc, &error))
- return error;
-
- /* Copy the bitmap file that we generated. */
- error = xrep_tempfile_copyin(sc, rgb->group_rbmoff, rgb->group_rbmlen,
- xrep_rgbitmap_prep_buf, rgb);
- if (error)
- return error;
- error = xrep_tempfile_set_isize(sc,
- XFS_FSB_TO_B(sc->mp, sc->mp->m_sb.sb_rbmblocks));
- if (error)
- return error;
-
- /*
- * Now exchange the data fork contents. We're done with the temporary
- * buffer, so we can reuse it for the tempfile exchmaps information.
- */
- error = xrep_tempexch_trans_reserve(sc, XFS_DATA_FORK,
- rgb->group_rbmoff, rgb->group_rbmlen, &rgb->tempexch);
- if (error)
- return error;
-
- error = xrep_tempexch_contents(sc, &rgb->tempexch);
- if (error)
- return error;
-
- /* Free the old bitmap blocks if they are free. */
- return xrep_reap_ifork(sc, sc->tempip, XFS_DATA_FORK);
-}
-
-/* rt bitmap file repairs */
-
-/* Set up to repair the realtime bitmap file metadata. */
-int
-xrep_setup_rtbitmap(
- struct xfs_scrub *sc,
- struct xchk_rtbitmap *rtb)
-{
- struct xfs_mount *mp = sc->mp;
- unsigned long long blocks = 0;
-
- /*
- * Reserve enough blocks to write out a completely new bmbt for a
- * maximally fragmented bitmap file. We do not hold the rtbitmap
- * ILOCK yet, so this is entirely speculative.
- */
- blocks = xfs_bmbt_calc_size(mp, mp->m_sb.sb_rbmblocks);
- if (blocks > UINT_MAX)
- return -EOPNOTSUPP;
-
- rtb->resblks += blocks;
- return 0;
-}
-
/*
* Make sure that the given range of the data fork of the realtime file is
* mapped to written blocks. The caller must ensure that the inode is joined
STATIC int
xrep_rtbitmap_geometry(
struct xfs_scrub *sc,
- struct xchk_rtbitmap *rtb)
+ struct xchk_rgbitmap *rgb)
{
struct xfs_mount *mp = sc->mp;
struct xfs_trans *tp = sc->tp;
/* Superblock fields */
- if (mp->m_sb.sb_rextents != rtb->rextents)
+ if (mp->m_sb.sb_rextents != rgb->rextents)
xfs_trans_mod_sb(sc->tp, XFS_TRANS_SB_REXTENTS,
- rtb->rextents - mp->m_sb.sb_rextents);
+ rgb->rextents - mp->m_sb.sb_rextents);
- if (mp->m_sb.sb_rbmblocks != rtb->rbmblocks)
+ if (mp->m_sb.sb_rbmblocks != rgb->rbmblocks)
xfs_trans_mod_sb(tp, XFS_TRANS_SB_RBMBLOCKS,
- rtb->rbmblocks - mp->m_sb.sb_rbmblocks);
-
- if (mp->m_sb.sb_rextslog != rtb->rextslog)
+ rgb->rbmblocks - mp->m_sb.sb_rbmblocks);
+ if (mp->m_sb.sb_rextslog != rgb->rextslog)
xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTSLOG,
- rtb->rextslog - mp->m_sb.sb_rextslog);
+ rgb->rextslog - mp->m_sb.sb_rextslog);
/* Fix broken isize */
sc->ip->i_disk_size = roundup_64(sc->ip->i_disk_size,
mp->m_sb.sb_blocksize);
- if (sc->ip->i_disk_size < XFS_FSB_TO_B(mp, rtb->rbmblocks))
- sc->ip->i_disk_size = XFS_FSB_TO_B(mp, rtb->rbmblocks);
+ if (sc->ip->i_disk_size < XFS_FSB_TO_B(mp, rgb->rbmblocks))
+ sc->ip->i_disk_size = XFS_FSB_TO_B(mp, rgb->rbmblocks);
xfs_trans_log_inode(sc->tp, sc->ip, XFS_ILOG_CORE);
return xrep_roll_trans(sc);
}
-/* Repair the realtime bitmap file metadata. */
+/* Repair the realtime bitmap for this rt group. */
int
-xrep_rtbitmap(
+xrep_rgbitmap(
struct xfs_scrub *sc)
{
- struct xchk_rtbitmap *rtb = sc->buf;
+ struct xchk_rgbitmap *rgb = sc->buf;
struct xfs_mount *mp = sc->mp;
unsigned long long blocks = 0;
int error;
+ /* We require the realtime rmapbt to rebuild anything. */
+ if (!xfs_has_rtrmapbt(sc->mp))
+ return -EOPNOTSUPP;
+ /* We require atomic file exchange range to rebuild anything. */
+ if (!xfs_has_exchange_range(sc->mp))
+ return -EOPNOTSUPP;
+
/* Impossibly large rtbitmap means we can't touch the filesystem. */
- if (rtb->rbmblocks > U32_MAX)
+ if (rgb->rbmblocks > U32_MAX)
return 0;
/*
* figure out if we need to adjust the block reservation in the
* transaction.
*/
- blocks = xfs_bmbt_calc_size(mp, rtb->rbmblocks);
+ blocks = xfs_bmbt_calc_size(mp, rgb->rbmblocks);
if (blocks > UINT_MAX)
return -EOPNOTSUPP;
- if (blocks > rtb->resblks) {
+ if (blocks > rgb->resblks) {
error = xfs_trans_reserve_more(sc->tp, blocks, 0);
if (error)
return error;
- rtb->resblks += blocks;
+ rgb->resblks += blocks;
}
/* Fix inode core and forks. */
xfs_trans_ijoin(sc->tp, sc->ip, 0);
/* Ensure no unwritten extents. */
- error = xrep_rtbitmap_data_mappings(sc, rtb->rbmblocks);
+ error = xrep_rtbitmap_data_mappings(sc, rgb->rbmblocks);
if (error)
return error;
/* Fix inconsistent bitmap geometry */
- return xrep_rtbitmap_geometry(sc, rtb);
+ error = xrep_rtbitmap_geometry(sc, rgb);
+ if (error)
+ return error;
+
+ /*
+ * Generate the new rtbitmap data. We don't need the rtbmp information
+ * once this call is finished.
+ */
+ error = xrep_rgbitmap_find_freespace(rgb);
+ if (error)
+ return error;
+
+ /*
+ * Try to take ILOCK_EXCL of the temporary file. We had better be the
+ * only ones holding onto this inode, but we can't block while holding
+ * the rtbitmap file's ILOCK_EXCL.
+ */
+ while (!xrep_tempfile_ilock_nowait(sc)) {
+ if (xchk_should_terminate(sc, &error))
+ return error;
+ delay(1);
+ }
+
+ /*
+ * Make sure we have space allocated for the part of the bitmap
+ * file that corresponds to this group.
+ */
+ xfs_trans_ijoin(sc->tp, sc->ip, 0);
+ xfs_trans_ijoin(sc->tp, sc->tempip, 0);
+ error = xrep_tempfile_prealloc(sc, 0, rgb->rbmblocks);
+ if (error)
+ return error;
+
+ /* Last chance to abort before we start committing fixes. */
+ if (xchk_should_terminate(sc, &error))
+ return error;
+
+ /* Copy the bitmap file that we generated. */
+ error = xrep_tempfile_copyin(sc, 0, rgb->rbmblocks,
+ xrep_rgbitmap_prep_buf, rgb);
+ if (error)
+ return error;
+ error = xrep_tempfile_set_isize(sc,
+ XFS_FSB_TO_B(sc->mp, sc->mp->m_sb.sb_rbmblocks));
+ if (error)
+ return error;
+
+ /*
+ * Now exchange the data fork contents. We're done with the temporary
+ * buffer, so we can reuse it for the tempfile exchmaps information.
+ */
+ error = xrep_tempexch_trans_reserve(sc, XFS_DATA_FORK, 0,
+ rgb->rbmblocks, &rgb->tempexch);
+ if (error)
+ return error;
+
+ error = xrep_tempexch_contents(sc, &rgb->tempexch);
+ if (error)
+ return error;
+
+ /* Free the old bitmap blocks if they are free. */
+ return xrep_reap_ifork(sc, sc->tempip, XFS_DATA_FORK);
}
struct xfs_scrub *sc,
const struct xfs_refcount_irec *rec)
{
- xfs_rtblock_t rtbno;
-
if (xfs_rtrefcount_check_irec(sc->sr.rtg, rec) != NULL)
return -EFSCORRUPTED;
/* Make sure this isn't free space or misaligned. */
- rtbno = xfs_rgbno_to_rtb(sc->mp, sc->sr.rtg->rtg_rgno,
- rec->rc_startblock);
- return xrep_require_rtext_inuse(sc, rtbno, rec->rc_blockcount, true);
+ return xrep_require_rtext_inuse(sc, sc->sr.rtg, rec->rc_startblock,
+ rec->rc_blockcount, true);
}
/* Record a reference count extent. */
struct xfs_scrub *sc,
const struct xfs_rmap_irec *rec)
{
- xfs_rtblock_t rtbno;
-
if (xfs_rtrmap_check_irec(sc->sr.rtg, rec) != NULL)
return -EFSCORRUPTED;
/* Make sure this isn't free space. */
- rtbno = xfs_rgbno_to_rtb(sc->mp, sc->sr.rtg->rtg_rgno,
- rec->rm_startblock);
- return xrep_require_rtext_inuse(sc, rtbno, rec->rm_blockcount, false);
+ return xrep_require_rtext_inuse(sc, sc->sr.rtg, rec->rm_startblock,
+ rec->rm_blockcount, false);
}
/* Store a reverse-mapping record. */
#include "xfs_bmap.h"
#include "xfs_sb.h"
#include "xfs_exchmaps.h"
+#include "xfs_rtgroup.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
#include "scrub/trace.h"
struct xfs_scrub *sc)
{
struct xfs_mount *mp = sc->mp;
+ struct xfs_rtgroup *rtg;
char *descr;
struct xchk_rtsummary *rts;
int error;
+ if (xchk_need_intent_drain(sc))
+ xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN);
+
rts = kvzalloc(struct_size(rts, words, mp->m_blockwsize),
XCHK_GFP_FLAGS);
if (!rts)
return -ENOMEM;
sc->buf = rts;
+ rtg = xfs_rtgroup_get(mp, sc->sm->sm_agno);
+ if (!rtg)
+ return -ENOENT;
+
if (xchk_could_repair(sc)) {
error = xrep_setup_rtsummary(sc, rts);
if (error)
- return error;
+ goto out_rtg;
}
/*
error = xfile_create(descr, mp->m_rsumsize, &sc->xfile);
kfree(descr);
if (error)
- return error;
+ goto out_rtg;
error = xchk_trans_alloc(sc, rts->resblks);
if (error)
- return error;
+ goto out_rtg;
- error = xchk_install_live_inode(sc, mp->m_rsumip);
+ error = xchk_install_live_inode(sc, rtg->rtg_inodes[XFS_RTG_SUMMARY]);
if (error)
- return error;
+ goto out_rtg;
error = xchk_ino_dqattach(sc);
if (error)
return error;
- xchk_rt_init(sc, &sc->sr,
- XCHK_RTLOCK_SUMMARY | XCHK_RTLOCK_BITMAP_SHARED);
+ /*
+ * There is no strict requirement for an exclusive lock on the summary
+ * here, but to keep the locking APIs simple we lock both inodes
+ * exclusively here. If we ever start caring about running concurrent
+ * fsmap with scrub this could be changed.
+ */
+ error = xchk_rtgroup_init(sc, sc->sm->sm_agno, &sc->sr,
+ XFS_RTGLOCK_BITMAP);
+ if (error)
+ goto out_rtg;
/*
* Now that we've locked the rtbitmap and rtsummary, we can't race with
* growfsrt trying to expand the summary or change the size of the rt
* volume. Hence it is safe to compute and check the geometry values.
*/
- if (mp->m_sb.sb_rblocks) {
- xfs_filblks_t rsumblocks;
- int rextslog;
-
- rts->rextents = xfs_rtb_to_rtx(mp, mp->m_sb.sb_rblocks);
- rextslog = xfs_compute_rextslog(rts->rextents);
- rts->rsumlevels = rextslog + 1;
- rts->rbmblocks = xfs_rtbitmap_blockcount(mp, rts->rextents);
- rsumblocks = xfs_rtsummary_blockcount(mp, rts->rsumlevels,
- rts->rbmblocks);
- rts->rsumsize = XFS_FSB_TO_B(mp, rsumblocks);
- }
- return 0;
+ if (!mp->m_sb.sb_rblocks)
+ goto out_rtg;
+
+ rts->rextents = xfs_blen_to_rtbxlen(mp, mp->m_sb.sb_rblocks);
+ rts->rbmblocks = xfs_rtbitmap_blockcount(mp);
+ rts->rsumlevels = xfs_compute_rsumlevels(mp, rts->rextents);
+ rts->rsumsize = XFS_FSB_TO_B(mp,
+ xfs_rtsummary_blockcount(mp, rts->rsumlevels, rts->rbmblocks));
+
+out_rtg:
+ xfs_rtgroup_put(rtg);
+ return error;
}
/* Helper functions to record suminfo words in an xfile. */
/* Update the summary file to reflect the free extent that we've accumulated. */
STATIC int
xchk_rtsum_record_free(
- struct xfs_mount *mp,
+ struct xfs_rtgroup *rtg,
struct xfs_trans *tp,
const struct xfs_rtalloc_rec *rec,
void *priv)
{
+ struct xfs_mount *mp = rtg->rtg_mount;
struct xfs_scrub *sc = priv;
xfs_fileoff_t rbmoff;
xfs_rtblock_t rtbno;
lenlog = xfs_highbit64(rec->ar_extcount);
offs = xfs_rtsumoffs(mp, lenlog, rbmoff);
- rtbno = xfs_rtx_to_rtb(mp, rec->ar_startext);
- rtlen = xfs_rtx_to_rtb(mp, rec->ar_extcount);
+ rtbno = xfs_rtx_to_rtb(rtg, rec->ar_startext);
+ rtlen = xfs_rtxlen_to_extlen(mp, rec->ar_extcount);
if (!xfs_verify_rt_freesp(mp, rtbno, rtlen)) {
- xchk_ino_xref_set_corrupt(sc, mp->m_rbmip->i_ino);
+ xchk_ino_xref_set_corrupt(sc,
+ rtg->rtg_inodes[XFS_RTG_BITMAP]->i_ino);
return -EFSCORRUPTED;
}
struct xfs_scrub *sc)
{
struct xfs_mount *mp = sc->mp;
- unsigned long long rtbmp_blocks;
+ struct xfs_rtgroup *rtg = sc->sr.rtg;
/* If the bitmap size doesn't match the computed size, bail. */
- rtbmp_blocks = xfs_rtbitmap_blockcount(mp, mp->m_sb.sb_rextents);
- if (XFS_FSB_TO_B(mp, rtbmp_blocks) != mp->m_rbmip->i_disk_size)
+ if (XFS_FSB_TO_B(mp, xfs_rtbitmap_blockcount(mp)) !=
+ rtg->rtg_inodes[XFS_RTG_BITMAP]->i_disk_size)
return -EFSCORRUPTED;
- return xfs_rtalloc_query_all(sc->mp, sc->tp, xchk_rtsum_record_free,
- sc);
+ return xfs_rtalloc_query_all(rtg, sc->tp, xchk_rtsum_record_free, sc);
}
/* Compare the rtsummary file against the one we computed. */
xfs_rtsumoff_t sumoff = 0;
int error = 0;
- rts->args.mp = sc->mp;
+ rts->args.mp = mp;
rts->args.tp = sc->tp;
+ rts->args.rtg = sc->sr.rtg;
/* Mappings may not cross or lie beyond EOF. */
endoff = XFS_B_TO_FSB(mp, ip->i_disk_size);
struct xfs_scrub *sc)
{
struct xfs_mount *mp = sc->mp;
+ struct xfs_rtgroup *rtg = sc->sr.rtg;
+ struct xfs_inode *rsumip = rtg->rtg_inodes[XFS_RTG_SUMMARY];
struct xchk_rtsummary *rts = sc->buf;
- int error = 0;
+ int error;
/* Is sb_rextents correct? */
if (mp->m_sb.sb_rextents != rts->rextents) {
- xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
- goto out_rbm;
+ xchk_ino_set_corrupt(sc,
+ rtg->rtg_inodes[XFS_RTG_BITMAP]->i_ino);
+ return 0;
}
/* Is m_rsumlevels correct? */
if (mp->m_rsumlevels != rts->rsumlevels) {
- xchk_ino_set_corrupt(sc, mp->m_rsumip->i_ino);
- goto out_rbm;
+ xchk_ino_set_corrupt(sc, rsumip->i_ino);
+ return 0;
}
/* Is m_rsumsize correct? */
if (mp->m_rsumsize != rts->rsumsize) {
- xchk_ino_set_corrupt(sc, mp->m_rsumip->i_ino);
- goto out_rbm;
+ xchk_ino_set_corrupt(sc, rsumip->i_ino);
+ return 0;
}
/* The summary file length must be aligned to an fsblock. */
- if (mp->m_rsumip->i_disk_size & mp->m_blockmask) {
- xchk_ino_set_corrupt(sc, mp->m_rsumip->i_ino);
- goto out_rbm;
+ if (rsumip->i_disk_size & mp->m_blockmask) {
+ xchk_ino_set_corrupt(sc, rsumip->i_ino);
+ return 0;
}
/*
* growfsrt expands the summary file before updating sb_rextents, so
* the file can be larger than rsumsize.
*/
- if (mp->m_rsumip->i_disk_size < rts->rsumsize) {
- xchk_ino_set_corrupt(sc, mp->m_rsumip->i_ino);
- goto out_rbm;
+ if (rsumip->i_disk_size < rts->rsumsize) {
+ xchk_ino_set_corrupt(sc, rsumip->i_ino);
+ return 0;
}
/* Invoke the fork scrubber. */
error = xchk_metadata_inode_forks(sc);
if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
- goto out_rbm;
+ return error;
/* Construct the new summary file from the rtbitmap. */
error = xchk_rtsum_compute(sc);
* EFSCORRUPTED means the rtbitmap is corrupt, which is an xref
* error since we're checking the summary file.
*/
- xchk_ino_xref_set_corrupt(sc, mp->m_rbmip->i_ino);
- error = 0;
- goto out_rbm;
+ xchk_ino_xref_set_corrupt(sc,
+ rtg->rtg_inodes[XFS_RTG_BITMAP]->i_ino);
+ return error;
}
if (error)
- goto out_rbm;
-
+ return error;
/* Does the computed summary file match the actual rtsummary file? */
- error = xchk_rtsum_compare(sc);
-
-out_rbm:
- /*
- * Unlock the rtbitmap since we're done with it. All other writers of
- * the rt free space metadata grab the bitmap and summary ILOCKs in
- * that order, so we're still protected against allocation activities
- * even if we continue on to the repair function.
- */
- xchk_rt_unlock_rtbitmap(sc);
- return error;
+ return xchk_rtsum_compare(sc);
}
union xfs_suminfo_raw *ondisk;
int error;
- rts->args.mp = sc->mp;
+ rts->args.mp = mp;
rts->args.tp = sc->tp;
+ rts->args.rtg = sc->sr.rtg;
rts->args.sumbp = bp;
ondisk = xfs_rsumblock_infoptr(&rts->args, 0);
rts->args.sumbp = NULL;
return error;
/* Reset incore state and blow out the summary cache. */
- if (mp->m_rsum_cache)
- memset(mp->m_rsum_cache, 0xFF, mp->m_sb.sb_rbmblocks);
+ if (sc->sr.rtg->rtg_rsum_cache)
+ memset(sc->sr.rtg->rtg_rsum_cache, 0xFF, mp->m_sb.sb_rbmblocks);
mp->m_rsumlevels = rts->rsumlevels;
mp->m_rsumsize = rts->rsumsize;
xfs_trans_cancel(sc->tp);
sc->tp = NULL;
}
+
if (sc->sr.rtg)
xchk_rtgroup_free(sc, &sc->sr);
- else
- xchk_rt_unlock(sc, &sc->sr);
+
if (sc->ip) {
if (sc->ilock_flags)
xchk_iunlock(sc, sc->ilock_flags);
.scrub = xchk_parent,
.repair = xrep_parent,
},
- [XFS_SCRUB_TYPE_RTBITMAP] = { /* realtime bitmap */
- .type = ST_FS,
- .setup = xchk_setup_rtbitmap,
- .scrub = xchk_rtbitmap,
- .repair = xrep_rtbitmap,
- },
[XFS_SCRUB_TYPE_RTSUM] = { /* realtime summary */
.type = ST_FS,
.setup = xchk_setup_rtsummary,
/* incore rtgroup, if applicable */
struct xfs_rtgroup *rtg;
- /*
- * XCHK_RTLOCK_* lock state if rtg == NULL, or XFS_RTGLOCK_* lock state
- * if rtg != NULL.
- */
+ /* XFS_RTGLOCK_* */
unsigned int rtlock_flags;
/* rtgroup btrees */
int xchk_dirtree(struct xfs_scrub *sc);
int xchk_metapath(struct xfs_scrub *sc);
#ifdef CONFIG_XFS_RT
-int xchk_rtbitmap(struct xfs_scrub *sc);
int xchk_rtsummary(struct xfs_scrub *sc);
int xchk_rgsuperblock(struct xfs_scrub *sc);
int xchk_rgbitmap(struct xfs_scrub *sc);
int xchk_rtrmapbt(struct xfs_scrub *sc);
int xchk_rtrefcountbt(struct xfs_scrub *sc);
#else
-# define xchk_rtbitmap xchk_nothing
# define xchk_rtsummary xchk_nothing
# define xchk_rgsuperblock xchk_nothing
# define xchk_rgbitmap xchk_nothing
[XFS_SCRUB_TYPE_XATTR] = "xattr",
[XFS_SCRUB_TYPE_SYMLINK] = "symlink",
[XFS_SCRUB_TYPE_PARENT] = "parent",
- [XFS_SCRUB_TYPE_RTBITMAP] = "rtbitmap",
[XFS_SCRUB_TYPE_RTSUM] = "rtsummary",
[XFS_SCRUB_TYPE_UQUOTA] = "usrquota",
[XFS_SCRUB_TYPE_GQUOTA] = "grpquota",
TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_XATTR);
TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_SYMLINK);
TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_PARENT);
-TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_RTBITMAP);
TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_RTSUM);
TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_UQUOTA);
TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_GQUOTA);
{ XFS_SCRUB_TYPE_XATTR, "xattr" }, \
{ XFS_SCRUB_TYPE_SYMLINK, "symlink" }, \
{ XFS_SCRUB_TYPE_PARENT, "parent" }, \
- { XFS_SCRUB_TYPE_RTBITMAP, "rtbitmap" }, \
{ XFS_SCRUB_TYPE_RTSUM, "rtsummary" }, \
{ XFS_SCRUB_TYPE_UQUOTA, "usrquota" }, \
{ XFS_SCRUB_TYPE_GQUOTA, "grpquota" }, \
#include "xfs_ag.h"
#include "xfs_health.h"
#include "xfs_rtbitmap.h"
+#include "xfs_rtgroup.h"
/*
* Notes on an efficient, low latency fstrim algorithm
static int
xfs_trim_gather_rtextent(
- struct xfs_mount *mp,
+ struct xfs_rtgroup *rtg,
struct xfs_trans *tp,
const struct xfs_rtalloc_rec *rec,
void *priv)
return -ECANCELED;
}
- rbno = xfs_rtx_to_rtb(mp, rec->ar_startext);
- rlen = xfs_rtx_to_rtb(mp, rec->ar_extcount);
+ rbno = xfs_rtx_to_rtb(rtg, rec->ar_startext);
+ rlen = xfs_rtxlen_to_extlen(rtg->rtg_mount, rec->ar_extcount);
/* Ignore too small. */
if (rlen < tr->minlen_fsb) {
- trace_xfs_discard_rttoosmall(mp, rbno, rlen);
+ trace_xfs_discard_rttoosmall(rtg->rtg_mount, rbno, rlen);
return 0;
}
}
static int
-xfs_trim_rtdev_extents(
- struct xfs_mount *mp,
- xfs_daddr_t start,
- xfs_daddr_t end,
+xfs_trim_rtg_extents(
+ struct xfs_rtgroup *rtg,
+ xfs_rtxnum_t low,
+ xfs_rtxnum_t high,
xfs_daddr_t minlen,
uint64_t *blocks_trimmed)
{
+ struct xfs_mount *mp = rtg->rtg_mount;
struct xfs_trim_rtdev tr = {
.blocks_trimmed = blocks_trimmed,
.minlen_fsb = XFS_BB_TO_FSB(mp, minlen),
+ .extent_list = LIST_HEAD_INIT(tr.extent_list),
};
- xfs_rtxnum_t low, high;
struct xfs_trans *tp;
- xfs_daddr_t rtdev_daddr;
int error;
- INIT_LIST_HEAD(&tr.extent_list);
-
- /* Shift the start and end downwards to match the rt device. */
- rtdev_daddr = XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks);
- if (start > rtdev_daddr)
- start -= rtdev_daddr;
- else
- start = 0;
-
- if (end <= rtdev_daddr)
- return 0;
- end -= rtdev_daddr;
-
error = xfs_trans_alloc_empty(mp, &tp);
if (error)
return error;
- end = min_t(xfs_daddr_t, end,
- XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks) - 1);
-
- /* Convert the rt blocks to rt extents */
- low = xfs_rtb_to_rtxup(mp, XFS_BB_TO_FSB(mp, start));
- high = xfs_rtb_to_rtx(mp, XFS_BB_TO_FSBT(mp, end));
-
/*
* Walk the free ranges between low and high. The query_range function
* trims the extents returned.
*/
do {
tr.stop_rtx = low + xfs_rtbitmap_rtx_per_rbmblock(mp);
- xfs_rtbitmap_lock_shared(mp, XFS_RBMLOCK_BITMAP);
- error = xfs_rtalloc_query_range(mp, tp, low, high,
+ xfs_rtgroup_lock(rtg, XFS_RTGLOCK_BITMAP_SHARED);
+ error = xfs_rtalloc_query_range(rtg, tp, low, high,
xfs_trim_gather_rtextent, &tr);
-
if (error == -ECANCELED)
error = 0;
if (error) {
- xfs_rtbitmap_unlock_shared(mp, XFS_RBMLOCK_BITMAP);
+ xfs_rtgroup_unlock(rtg, XFS_RTGLOCK_BITMAP_SHARED);
xfs_discard_free_rtdev_extents(&tr);
break;
}
if (list_empty(&tr.extent_list)) {
- xfs_rtbitmap_unlock_shared(mp, XFS_RBMLOCK_BITMAP);
+ xfs_rtgroup_unlock(rtg, XFS_RTGLOCK_BITMAP_SHARED);
break;
}
error = xfs_discard_rtdev_extents(mp, &tr);
- xfs_rtbitmap_unlock_shared(mp, XFS_RBMLOCK_BITMAP);
+ xfs_rtgroup_unlock(rtg, XFS_RTGLOCK_BITMAP_SHARED);
if (error)
break;
xfs_trans_cancel(tp);
return error;
}
+
+static int
+xfs_trim_rtdev_extents(
+ struct xfs_mount *mp,
+ xfs_daddr_t start,
+ xfs_daddr_t end,
+ xfs_daddr_t minlen,
+ uint64_t *blocks_trimmed)
+{
+ xfs_rtblock_t start_rtbno, end_rtbno;
+ xfs_rtxnum_t start_rtx, end_rtx;
+ xfs_rgnumber_t rgno, end_rgno;
+ int last_error = 0, error;
+ struct xfs_rtgroup *rtg;
+
+ /* Shift the start and end downwards to match the rt device. */
+ start_rtbno = xfs_daddr_to_rtb(mp, start);
+ if (start_rtbno > mp->m_sb.sb_dblocks)
+ start_rtbno -= mp->m_sb.sb_dblocks;
+ else
+ start_rtbno = 0;
+ start_rtx = xfs_rtb_to_rtx(mp, start_rtbno);
+ rgno = xfs_rtb_to_rgno(mp, start_rtbno);
+
+ end_rtbno = xfs_daddr_to_rtb(mp, end);
+ if (end_rtbno <= mp->m_sb.sb_dblocks)
+ return 0;
+ end_rtbno -= mp->m_sb.sb_dblocks;
+ end_rtx = xfs_rtb_to_rtx(mp, end_rtbno + mp->m_sb.sb_rextsize - 1);
+ end_rgno = xfs_rtb_to_rgno(mp, end_rtbno);
+
+ for_each_rtgroup_range(mp, rgno, end_rgno, rtg) {
+ xfs_rtxnum_t rtg_end = rtg->rtg_extents;
+
+ if (rgno == end_rgno)
+ rtg_end = min(rtg_end, end_rtx);
+
+ error = xfs_trim_rtg_extents(rtg, start_rtx, rtg_end, minlen,
+ blocks_trimmed);
+ if (error)
+ last_error = error;
+
+ if (xfs_trim_should_stop()) {
+ xfs_rtgroup_rele(rtg);
+ break;
+ }
+ start_rtx = 0;
+ }
+
+ return last_error;
+}
#else
# define xfs_trim_rtdev_extents(m,s,e,n,b) (-EOPNOTSUPP)
#endif /* CONFIG_XFS_RT */
struct xfs_mount *mp = tp->t_mountp;
struct xfs_extent_free_item *xefi = xefi_entry(item);
struct xfs_efd_log_item *efdp = EFD_ITEM(done);
+ struct xfs_rtgroup **rtgp = (struct xfs_rtgroup **)state;
int error = 0;
- /*
- * Lock the rt bitmap if we've any realtime extents to free and we
- * haven't locked the rt inodes yet.
- */
- if (*state == NULL) {
- xfs_rtbitmap_lock(mp);
- xfs_rtbitmap_trans_join(tp);
- *state = (struct xfs_btree_cur *)1;
- }
-
trace_xfs_extent_free_deferred(mp, xefi);
- if (!(xefi->xefi_flags & XFS_EFI_CANCELLED))
- error = xfs_rtfree_blocks(tp, xefi->xefi_startblock,
- xefi->xefi_blockcount);
+ if (!(xefi->xefi_flags & XFS_EFI_CANCELLED)) {
+ if (*rtgp != xefi->xefi_rtg) {
+ xfs_rtgroup_lock(xefi->xefi_rtg, XFS_RTGLOCK_BITMAP);
+ xfs_rtgroup_trans_join(tp, xefi->xefi_rtg,
+ XFS_RTGLOCK_BITMAP);
+ *rtgp = xefi->xefi_rtg;
+ }
+ error = xfs_rtfree_blocks(tp, xefi->xefi_rtg,
+ xefi->xefi_startblock, xefi->xefi_blockcount);
+ }
if (error == -EAGAIN) {
xfs_efd_from_efi(efdp);
return error;
/* Transform a rtbitmap "record" into a fsmap */
STATIC int
xfs_getfsmap_rtdev_rtbitmap_helper(
- struct xfs_mount *mp,
+ struct xfs_rtgroup *rtg,
struct xfs_trans *tp,
const struct xfs_rtalloc_rec *rec,
void *priv)
{
+ struct xfs_mount *mp = rtg->rtg_mount;
struct xfs_getfsmap_info *info = priv;
- struct xfs_rmap_irec irec;
- xfs_rtblock_t rtbno;
- xfs_daddr_t rec_daddr, len_daddr;
-
- rtbno = xfs_rtx_to_rtb(mp, rec->ar_startext);
- rec_daddr = XFS_FSB_TO_BB(mp, rtbno);
- irec.rm_startblock = rtbno;
-
- rtbno = xfs_rtx_to_rtb(mp, rec->ar_extcount);
- len_daddr = XFS_FSB_TO_BB(mp, rtbno);
- irec.rm_blockcount = rtbno;
-
- irec.rm_owner = XFS_RMAP_OWN_NULL; /* "free" */
- irec.rm_offset = 0;
- irec.rm_flags = 0;
-
- return xfs_getfsmap_helper(tp, info, &irec, rec_daddr, len_daddr);
+ struct xfs_rmap_irec irec = {
+ .rm_startblock = xfs_rtx_to_rtb(rtg, rec->ar_startext),
+ .rm_blockcount = xfs_rtxlen_to_extlen(mp, rec->ar_extcount),
+ .rm_owner = XFS_RMAP_OWN_NULL, /* "free" */
+ };
+
+ return xfs_getfsmap_helper(tp, info, &irec,
+ XFS_FSB_TO_BB(mp, irec.rm_startblock),
+ XFS_FSB_TO_BB(mp, irec.rm_blockcount));
}
/* Execute a getfsmap query against the realtime device rtbitmap. */
const struct xfs_fsmap *keys,
struct xfs_getfsmap_info *info)
{
-
- struct xfs_rtalloc_rec ahigh = { 0 };
struct xfs_mount *mp = tp->t_mountp;
- xfs_rtblock_t start_rtb;
- xfs_rtblock_t end_rtb;
- xfs_rtxnum_t high;
+ xfs_rtblock_t start_rtbno, end_rtbno;
+ xfs_rtxnum_t start_rtx, end_rtx;
+ xfs_rgnumber_t rgno, end_rgno;
+ struct xfs_rtgroup *rtg;
uint64_t eofs;
int error;
- eofs = XFS_FSB_TO_BB(mp, xfs_rtx_to_rtb(mp, mp->m_sb.sb_rextents));
+ eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks);
if (keys[0].fmr_physical >= eofs)
return 0;
- start_rtb = XFS_BB_TO_FSBT(mp,
- keys[0].fmr_physical + keys[0].fmr_length);
- end_rtb = XFS_BB_TO_FSB(mp, min(eofs - 1, keys[1].fmr_physical));
info->missing_owner = XFS_FMR_OWN_UNKNOWN;
/* Adjust the low key if we are continuing from where we left off. */
+ start_rtbno =
+ XFS_BB_TO_FSBT(mp, keys[0].fmr_physical + keys[0].fmr_length);
if (keys[0].fmr_length > 0) {
- info->low_daddr = XFS_FSB_TO_BB(mp, start_rtb);
+ info->low_daddr = XFS_FSB_TO_BB(mp, start_rtbno);
if (info->low_daddr >= eofs)
return 0;
}
+ start_rtx = xfs_rtb_to_rtx(mp, start_rtbno);
+ rgno = xfs_rtb_to_rgno(mp, start_rtbno);
+ trace_xfs_fsmap_low_key_linear(mp, info->dev, start_rtbno);
+
+ end_rtbno = XFS_BB_TO_FSB(mp, min(eofs - 1, keys[1].fmr_physical));
+ end_rtx = xfs_rtb_to_rtx(mp, end_rtbno + mp->m_sb.sb_rextsize - 1);
+ end_rgno = xfs_rtb_to_rgno(mp, end_rtbno);
+ trace_xfs_fsmap_high_key_linear(mp, info->dev, end_rtbno);
+
+ for_each_rtgroup_range(mp, rgno, end_rgno, rtg) {
+ xfs_rtxnum_t rtg_end = rtg->rtg_extents;
+
+ if (rgno == end_rgno)
+ rtg_end = end_rtx;
+
+ xfs_rtgroup_lock(rtg, XFS_RTGLOCK_BITMAP_SHARED);
+ error = xfs_rtalloc_query_range(rtg, tp, start_rtx, rtg_end,
+ xfs_getfsmap_rtdev_rtbitmap_helper, info);
+ if (!error) {
+ struct xfs_rtalloc_rec ahigh = {
+ .ar_startext = rtg_end,
+ };
+
+ /*
+ * Report any gaps at the end of the rtbitmap by
+ * simulating a null rmap starting at the block after
+ * the end of the query range.
+ */
+ info->last = true;
+ error = xfs_getfsmap_rtdev_rtbitmap_helper(rtg, tp,
+ &ahigh, info);
+ }
+ xfs_rtgroup_unlock(rtg, XFS_RTGLOCK_BITMAP_SHARED);
+ if (error) {
+ xfs_rtgroup_rele(rtg);
+ return error;
+ }
+ start_rtx = 0;
+ }
- trace_xfs_fsmap_low_key_linear(mp, info->dev, start_rtb);
- trace_xfs_fsmap_high_key_linear(mp, info->dev, end_rtb);
-
- xfs_rtbitmap_lock_shared(mp, XFS_RBMLOCK_BITMAP);
-
- /*
- * Set up query parameters to return free rtextents covering the range
- * we want.
- */
- high = xfs_rtb_to_rtxup(mp, end_rtb);
- error = xfs_rtalloc_query_range(mp, tp, xfs_rtb_to_rtx(mp, start_rtb),
- high, xfs_getfsmap_rtdev_rtbitmap_helper, info);
- if (error)
- goto err;
-
- /*
- * Report any gaps at the end of the rtbitmap by simulating a null
- * rmap starting at the block after the end of the query range.
- */
- info->last = true;
- ahigh.ar_startext = min(mp->m_sb.sb_rextents, high);
-
- error = xfs_getfsmap_rtdev_rtbitmap_helper(mp, tp, &ahigh, info);
- if (error)
- goto err;
-err:
- xfs_rtbitmap_unlock_shared(mp, XFS_RBMLOCK_BITMAP);
- return error;
+ return 0;
}
/* Transform a realtime rmapbt record into a fsmap */
uint64_t eofs;
int error = 0;
- eofs = XFS_FSB_TO_BB(mp, xfs_rtx_to_rtb(mp, mp->m_sb.sb_rextents));
+ eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks);
if (keys[0].fmr_physical >= eofs)
return 0;
start_rtb = XFS_BB_TO_FSBT(mp, keys[0].fmr_physical);
iomap->type = IOMAP_DELALLOC;
} else {
xfs_daddr_t bno = xfs_fsb_to_db(ip, imap->br_startblock);
- xfs_rgnumber_t dummy;
iomap->addr = BBTOB(bno);
if (mapping_flags & IOMAP_DAX)
* single RTG.
*/
if (XFS_IS_REALTIME_INODE(ip) && xfs_has_rtgroups(mp) &&
- xfs_rtb_to_rgbno(mp, bno, &dummy) == 0)
+ xfs_rtb_to_rtx(mp, bno) == 0 &&
+ xfs_rtb_to_rtxoff(mp, bno) == 0)
iomap->flags |= IOMAP_F_BOUNDARY;
}
iomap->offset = XFS_FSB_TO_B(mp, imap->br_startoff);
alloc_blocks);
if (unlikely(XFS_IS_REALTIME_INODE(ip)))
- freesp = xfs_rtx_to_rtb(mp,
- xfs_iomap_freesp(&mp->m_frextents,
+ freesp = xfs_rtbxlen_to_blen(mp,
+ xfs_iomap_freesp(&mp->m_frextents,
mp->m_low_rtexts, &shift));
else
freesp = xfs_iomap_freesp(&mp->m_fdblocks, mp->m_low_space,
if (XFS_IS_REALTIME_INODE(ip)) {
percpu_counter_add_batch(&mp->m_delalloc_rtextents,
- xfs_rtb_to_rtx(mp, data_delta),
+ xfs_blen_to_rtbxlen(mp, data_delta),
XFS_DELALLOC_BATCH);
if (!ind_delta)
return;
struct xfs_da_geometry *m_dir_geo; /* directory block geometry */
struct xfs_da_geometry *m_attr_geo; /* attribute block geometry */
struct xlog *m_log; /* log specific stuff */
- struct xfs_inode *m_rbmip; /* pointer to bitmap inode */
- struct xfs_inode *m_rsumip; /* pointer to summary inode */
struct xfs_inode *m_rootip; /* pointer to root directory */
struct xfs_inode *m_metadirip; /* ptr to metadata directory */
struct xfs_inode *m_rtdirip; /* ptr to realtime metadir */
struct xfs_buftarg *m_logdev_targp;/* log device */
struct xfs_buftarg *m_rtdev_targp; /* rt device */
void __percpu *m_inodegc; /* percpu inodegc structures */
-
- /*
- * Optional cache of rt summary level per bitmap block with the
- * invariant that m_rsum_cache[bbno] > the maximum i for which
- * rsum[i][bbno] != 0, or 0 if rsum[i][bbno] == 0 for all i.
- * Reads and writes are serialized by the rsumip inode lock.
- */
- uint8_t *m_rsum_cache;
struct xfs_mru_cache *m_filestream; /* per-mount filestream data */
struct workqueue_struct *m_buf_workqueue;
struct workqueue_struct *m_unwritten_workqueue;
#ifdef CONFIG_XFS_ONLINE_SCRUB_STATS
struct xchk_stats *m_scrub_stats;
#endif
- xfs_rgnumber_t m_rtgrotor; /* last rtgroup rtpicked */
xfs_agnumber_t m_agfrotor; /* last ag where space found */
atomic_t m_agirotor; /* last ag dir inode alloced */
+ atomic_t m_rtgrotor; /* last rtgroup rtpicked */
/* Memory shrinker to throttle and reprioritize inodegc */
struct shrinker *m_inodegc_shrinker;
#include "xfs_health.h"
#include "xfs_da_format.h"
#include "xfs_metafile.h"
+#include "xfs_rtgroup.h"
/*
* The global quota manager. There is only one of these for the entire
}
}
+static void
+xfs_qm_unmount_rt(
+ struct xfs_mount *mp)
+{
+ struct xfs_rtgroup *rtg = xfs_rtgroup_grab(mp, 0);
+
+ if (!rtg)
+ return;
+ if (rtg->rtg_inodes[XFS_RTG_BITMAP])
+ xfs_qm_dqdetach(rtg->rtg_inodes[XFS_RTG_BITMAP]);
+ if (rtg->rtg_inodes[XFS_RTG_SUMMARY])
+ xfs_qm_dqdetach(rtg->rtg_inodes[XFS_RTG_SUMMARY]);
+ xfs_rtgroup_rele(rtg);
+}
+
/*
* Called from the vfsops layer.
*/
*/
ASSERT(mp->m_rootip);
xfs_qm_dqdetach(mp->m_rootip);
- if (mp->m_rbmip)
- xfs_qm_dqdetach(mp->m_rbmip);
- if (mp->m_rsumip)
- xfs_qm_dqdetach(mp->m_rsumip);
+
+ /*
+ * For pre-RTG file systems, the RT inodes have quotas attached,
+ * detach them now.
+ */
+ if (!xfs_has_rtgroups(mp))
+ xfs_qm_unmount_rt(mp);
/*
* Release the quota inodes.
}
}
+ if (!xfs_has_rtgroups(mp))
+ return 0;
+
for_each_rtgroup(mp, rgno, rtg) {
error = xfs_refcount_recover_rtcow_leftovers(mp, rtg);
if (error) {
#include "xfs_trace.h"
#include "xfs_rtrefcount_btree.h"
-/*
- * Realtime metadata files are not quite regular files because userspace can't
- * access the realtime bitmap directly, and because we take the ILOCK of the rt
- * bitmap file (and then the rt summary file) while holding the ILOCK of a
- * regular realtime file. This double locking confuses lockdep, so create
- * different lockdep classes here to help it keep things straight.
- */
-static struct lock_class_key xfs_rtbitmap_key;
-static struct lock_class_key xfs_rtsummary_key;
-
/*
* Return whether there are any free extents in the size range given
* by low and high, for the bitmap block bbno.
xfs_fileoff_t bbno, /* bitmap block number */
int *maxlog) /* out: max log2 extent size free */
{
- struct xfs_mount *mp = args->mp;
+ uint8_t *rsum_cache = args->rtg->rtg_rsum_cache;
int error;
int log; /* loop counter, log2 of ext. size */
xfs_suminfo_t sum; /* summary data */
- /* There are no extents at levels >= m_rsum_cache[bbno]. */
- if (mp->m_rsum_cache) {
- high = min(high, mp->m_rsum_cache[bbno] - 1);
+ /* There are no extents at levels >= rsum_cache[bbno]. */
+ if (rsum_cache) {
+ high = min(high, rsum_cache[bbno] - 1);
if (low > high) {
*maxlog = -1;
return 0;
*maxlog = -1;
out:
/* There were no extents at levels > log. */
- if (mp->m_rsum_cache && log + 1 < mp->m_rsum_cache[bbno])
- mp->m_rsum_cache[bbno] = log + 1;
+ if (rsum_cache && log + 1 < rsum_cache[bbno])
+ rsum_cache[bbno] = log + 1;
return 0;
}
-
/*
* Copy and transform the summary file, given the old and new
* parameters in the mount structures.
xfs_rtbuf_cache_relse(oargs);
return 0;
}
+
/*
* Mark an extent specified by start and len allocated.
* Updates all the summary information as well as the bitmap.
xfs_rtxlen_t len) /* in/out: summary block number */
{
struct xfs_mount *mp = args->mp;
- xfs_rtxnum_t end; /* end of the allocated rtext */
+ xfs_rtxnum_t end = start + len - 1;
int error;
xfs_rtxnum_t postblock = 0; /* first rtext allocated > end */
xfs_rtxnum_t preblock = 0; /* first rtext allocated < start */
- end = start + len - 1;
/*
* Assume we're allocating out of the middle of a free extent.
* We need to find the beginning and end of the extent so we can
/*
* Find the next allocated block (end of free extent).
*/
- error = xfs_rtfind_forw(args, end, mp->m_sb.sb_rextents - 1,
+ error = xfs_rtfind_forw(args, end, args->rtg->rtg_extents - 1,
&postblock);
if (error)
return error;
*/
static inline xfs_rtxlen_t
xfs_rtallocate_clamp_len(
- struct xfs_mount *mp,
+ struct xfs_rtgroup *rtg,
xfs_rtxnum_t startrtx,
xfs_rtxlen_t rtxlen,
xfs_rtxlen_t prod)
{
xfs_rtxlen_t ret;
- ret = min(mp->m_sb.sb_rextents, startrtx + rtxlen) - startrtx;
+ ret = min(rtg->rtg_extents, startrtx + rtxlen) - startrtx;
return xfs_rtalloc_align_len(ret, prod);
}
-/*
- * Given a candidate range of freespace that might be allocated, clamp the end
- * of the range to the end of the rtgroup to avoid crossing rtgroup boundaries.
- * Caller needs to round down the return value to prod if needed.
- */
-static inline xfs_rtxlen_t
-xfs_rtalloc_clamp_rtgroup(
- struct xfs_mount *mp,
- xfs_rtxnum_t startrtx,
- xfs_rtxlen_t rtxlen)
-{
- xfs_rtxnum_t next_rtx;
- xfs_rtblock_t rtb, next_rtb;
- xfs_rgnumber_t rgno;
-
- rtb = xfs_rtx_to_rtb(mp, startrtx);
- rgno = xfs_rtb_to_rgno(mp, rtb);
- next_rtb = xfs_rgbno_to_rtb(mp, rgno + 1, 0);
- next_rtx = xfs_rtb_to_rtx(mp, next_rtb);
-
- return min(next_rtx, startrtx + rtxlen) - startrtx;
-}
-
/*
* Attempt to allocate an extent minlen<=len<=maxlen starting from
* bitmap block bbno. If we don't get maxlen then use prod to trim
xfs_rtxnum_t next; /* next rtext to try */
xfs_rtxlen_t scanlen; /* number of free rtx to look for */
xfs_rtxlen_t bestlen = 0; /* best length found so far */
- xfs_rtxlen_t thislen; /* candidate length */
int stat; /* status from internal calls */
int error;
* Loop over all the extents starting in this bitmap block up to the
* end of the rt volume, looking for one that's long enough.
*/
- end = min(mp->m_sb.sb_rextents, xfs_rbmblock_to_rtx(mp, bbno + 1)) - 1;
+ end = min(args->rtg->rtg_extents, xfs_rbmblock_to_rtx(mp, bbno + 1)) -
+ 1;
for (i = xfs_rbmblock_to_rtx(mp, bbno); i <= end; i++) {
/* Make sure we don't scan off the end of the rt volume. */
- scanlen = xfs_rtallocate_clamp_len(mp, i, maxlen, prod);
+ scanlen = xfs_rtallocate_clamp_len(args->rtg, i, maxlen, prod);
if (scanlen < minlen)
break;
error = xfs_rtcheck_range(args, i, scanlen, 1, &next, &stat);
if (error)
return error;
- if (stat && xfs_has_rtgroups(mp)) {
- /*
- * i to scanlen is all free, but we can't return space
- * that would cross an rtgroup boundary. If it does
- * cross the boundary, treat this like a short
- * allocation.
- */
- thislen = xfs_rtalloc_clamp_rtgroup(mp, i, scanlen);
- if (thislen != scanlen) {
- next = i + thislen;
- stat = 0;
- }
- }
if (stat) {
/*
* i to scanlen is all free, allocate and return that.
* so far, remember it.
*/
if (minlen < maxlen) {
- if (xfs_has_rtgroups(mp))
- thislen = xfs_rtalloc_clamp_rtgroup(mp, i,
- next - i);
- else
- thislen = next - i;
+ xfs_rtxlen_t thislen = next - i;
+
if (thislen >= minlen && thislen > bestlen) {
besti = i;
bestlen = thislen;
xfs_rtxlen_t prod, /* extent product factor */
xfs_rtxnum_t *rtx) /* out: start rtext allocated */
{
- struct xfs_mount *mp = args->mp;
xfs_rtxnum_t next; /* next rtext to try (dummy) */
xfs_rtxlen_t alloclen; /* candidate length */
xfs_rtxlen_t scanlen; /* number of free rtx to look for */
ASSERT(maxlen % prod == 0);
/* Make sure we don't run off the end of the rt volume. */
- scanlen = xfs_rtallocate_clamp_len(mp, start, maxlen, prod);
+ scanlen = xfs_rtallocate_clamp_len(args->rtg, start, maxlen, prod);
if (scanlen < minlen)
return -ENOSPC;
if (error)
return error;
- if (isfree && xfs_has_rtgroups(mp)) {
- /*
- * start to scanlen is all free, but we can't return space that
- * would cross an rtgroup boundary. If it does, treat this
- * like a short allocation.
- */
- alloclen = xfs_rtalloc_clamp_rtgroup(mp, start, scanlen);
- if (alloclen < scanlen) {
- next = start + alloclen;
- isfree = 0;
- }
- }
-
if (isfree) {
/* start to scanlen is all free; allocate it. */
alloclen = scanlen;
} else {
/* If not, allocate what there is, if it's at least minlen. */
- if (xfs_has_rtgroups(mp))
- alloclen = xfs_rtalloc_clamp_rtgroup(mp, start,
- next - start);
- else
- alloclen = next - start;
+ alloclen = next - start;
if (alloclen < minlen)
return -ENOSPC;
ASSERT(maxlen % prod == 0);
/*
- * If the block number given is off the end, silently set it to
- * the last block.
+ * If the block number given is off the end, silently set it to the last
+ * block.
*/
- if (start >= mp->m_sb.sb_rextents)
- start = mp->m_sb.sb_rextents - 1;
+ start = min(start, args->rtg->rtg_extents);
/*
* Try the exact allocation first.
static int
xfs_alloc_rsum_cache(
- struct xfs_mount *mp,
+ struct xfs_rtgroup *rtg,
xfs_extlen_t rbmblocks)
{
/*
* The rsum cache is initialized to the maximum value, which is
* trivially an upper bound on the maximum level with any free extents.
*/
- mp->m_rsum_cache = kvmalloc(rbmblocks, GFP_KERNEL);
- if (!mp->m_rsum_cache)
+ rtg->rtg_rsum_cache = kvmalloc(rbmblocks, GFP_KERNEL);
+ if (!rtg->rtg_rsum_cache)
return -ENOMEM;
- memset(mp->m_rsum_cache, -1, rbmblocks);
+ memset(rtg->rtg_rsum_cache, -1, rbmblocks);
return 0;
}
return xfs_rtginode_create(rtg, type, true);
}
-/* Add rtgroups as needed to deal with this phase of rt expansion. */
-STATIC int
-xfs_growfsrt_alloc_rtgroups(
- struct xfs_mount *mp,
- xfs_rgnumber_t last_rgno,
- struct xfs_mount *nmp)
-{
- struct xfs_sb *nsbp = &nmp->m_sb;
- struct xfs_rtgroup *rtg;
- struct xfs_trans *tp;
- int error;
-
- /* Make sure the /rtgroups dir has been created */
- if (!mp->m_rtdirip) {
- error = xfs_trans_alloc_empty(mp, &tp);
- if (error)
- return error;
-
- error = xfs_rtginode_load_parent(tp);
- xfs_trans_cancel(tp);
- switch (error) {
- case 0:
- break;
- case -ENOENT:
- error = xfs_rtginode_mkdir_parent(mp);
- if (error)
- return error;
- break;
- default:
- return error;
- }
- }
-
- nsbp->sb_rgcount = howmany_64(nsbp->sb_rextents, nsbp->sb_rgextents);
- error = xfs_initialize_rtgroups(mp, nsbp->sb_rgcount);
- if (error)
- return error;
-
- for_each_rtgroup_range(mp, last_rgno, nsbp->sb_rgcount, rtg) {
- error = xfs_rtginode_ensure(rtg, XFS_RTG_RMAP);
- if (error) {
- xfs_rtgroup_rele(rtg);
- return error;
- }
-
- error = xfs_rtginode_ensure(rtg, XFS_RTG_REFCOUNT);
- if (error) {
- xfs_rtgroup_rele(rtg);
- return error;
- }
- }
-
- return 0;
-}
-
-/* Remove excess rtgroups after a grow failed. */
-STATIC void
-xfs_growfsrt_free_rtgroups(
- struct xfs_mount *mp,
- struct xfs_mount *nmp)
-{
- struct xfs_rtgroup *rtg;
- xfs_rgnumber_t rgno = mp->m_sb.sb_rgcount + 1;
- unsigned int i;
-
- for_each_rtgroup_range(mp, rgno, nmp->m_sb.sb_rgcount, rtg) {
- for (i = 0; i < XFS_RTG_MAX; i++)
- xfs_rtginode_irele(&rtg->rtg_inodes[i]);
- }
-
- xfs_free_unused_rtgroup_range(mp, mp->m_sb.sb_rgcount + 1,
- nmp->m_sb.sb_rgcount);
-}
-
/* Free all the new space and return the number of extents actually freed. */
static int
xfs_growfs_rt_free_new(
- struct xfs_mount *mp,
+ struct xfs_rtgroup *rtg,
struct xfs_rtalloc_args *nargs,
xfs_rtbxlen_t *freed_rtx)
{
- struct xfs_mount *nmp = nargs->mp;
- struct xfs_sb *sbp = &mp->m_sb;
- struct xfs_sb *nsbp = &nmp->m_sb;
- xfs_rtxnum_t start_rtx = sbp->sb_rextents;
+ struct xfs_mount *mp = rtg->rtg_mount;
+ xfs_rgnumber_t rgno = rtg->rtg_rgno;
+ xfs_rtxnum_t start_rtx = 0, end_rtx;
+
+ if (rgno < mp->m_sb.sb_rgcount)
+ start_rtx = xfs_rtgroup_extents(mp, rgno);
+ end_rtx = xfs_rtgroup_extents(nargs->mp, rgno);
/*
* Compute the first new extent that we want to free, being careful to
* skip past a realtime superblock at the start of the realtime volume.
*/
- if (xfs_has_rtsb(mp) && start_rtx == 0)
+ if (xfs_has_rtsb(mp) && rgno == 0 && start_rtx == 0)
start_rtx++;
-
- *freed_rtx = nsbp->sb_rextents - start_rtx;
+ *freed_rtx = end_rtx - start_rtx;
return xfs_rtfree_range(nargs, start_rtx, *freed_rtx);
}
mp->m_sb.sb_rblocks = rblocks;
mp->m_sb.sb_rextsize = rextsize;
mp->m_sb.sb_rextents = div_u64(rblocks, rextsize);
- mp->m_sb.sb_rbmblocks =
- xfs_rtbitmap_blockcount(mp, mp->m_sb.sb_rextents);
+ mp->m_sb.sb_rbmblocks = xfs_rtbitmap_blockcount(mp);
mp->m_sb.sb_rextslog = xfs_compute_rextslog(mp->m_sb.sb_rextents);
+ mp->m_sb.sb_rgcount =
+ howmany_64(mp->m_sb.sb_rextents, mp->m_sb.sb_rgextents);
- mp->m_rsumlevels = mp->m_sb.sb_rextslog + 1;
+ mp->m_rsumlevels = xfs_compute_rsumlevels(mp, mp->m_sb.sb_rextents);
mp->m_rsumsize = XFS_FSB_TO_B(mp,
xfs_rtsummary_blockcount(mp, mp->m_rsumlevels,
mp->m_sb.sb_rbmblocks));
static int
xfs_growfs_rt_bmblock(
- struct xfs_mount *mp,
+ struct xfs_rtgroup *rtg,
xfs_rfsblock_t nrblocks,
xfs_agblock_t rextsize,
xfs_fileoff_t bmbno)
{
- struct xfs_inode *rbmip = mp->m_rbmip;
- struct xfs_inode *rsumip = mp->m_rsumip;
+ struct xfs_mount *mp = rtg->rtg_mount;
+ struct xfs_inode *rbmip = rtg->rtg_inodes[XFS_RTG_BITMAP];
+ struct xfs_inode *rsumip = rtg->rtg_inodes[XFS_RTG_SUMMARY];
struct xfs_rtalloc_args args = {
.mp = mp,
+ .rtg = rtg,
};
struct xfs_rtalloc_args nargs = {
+ .rtg = rtg,
};
struct xfs_mount *nmp;
- struct xfs_rtgroup *rtg;
+ xfs_rtbxlen_t freed_rtx = 0;
xfs_rfsblock_t nrblocks_step;
- xfs_rtbxlen_t freed_rtx;
- xfs_rgnumber_t last_rgno = mp->m_sb.sb_rgcount - 1;
int error;
- nrblocks_step = (bmbno + 1) * mp->m_rtx_per_rbmblock * rextsize;
+ nrblocks_step = rtg->rtg_rgno * mp->m_rgblocks +
+ min(mp->m_rgblocks,
+ (bmbno + 1) * mp->m_rtx_per_rbmblock * rextsize);
nmp = nargs.mp = kmemdup(mp, sizeof(*mp), GFP_KERNEL);
if (!nmp)
return -ENOMEM;
/*
- * Calculate new sb and mount fields for this round.
+ * Calculate new sb and mount fields for this round. Also ensure the
+ * rtg_extents value is uptodate as the rtbitmap code relies on it.
*/
xfs_rt_compute_geometry(nmp, min(nrblocks, nrblocks_step), rextsize);
+ rtg->rtg_extents = xfs_rtgroup_extents(nmp, rtg->rtg_rgno);
/* recompute growfsrt reservation from new rsumsize */
xfs_trans_resv_calc(nmp, &nmp->m_resv);
- if (xfs_has_rtgroups(mp)) {
- error = xfs_growfsrt_alloc_rtgroups(mp, last_rgno, nmp);
- if (error)
- goto out_free;
- }
-
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growrtfree, 0, 0, 0,
&args.tp);
if (error)
goto out_free;
nargs.tp = args.tp;
- xfs_rtbitmap_lock(mp);
- xfs_rtbitmap_trans_join(args.tp);
+ xfs_rtgroup_lock(args.rtg, XFS_RTGLOCK_BITMAP);
+ xfs_rtgroup_trans_join(args.tp, args.rtg, XFS_RTGLOCK_BITMAP);
/*
* Update the bitmap inode's size ondisk and incore. We need to update
/*
* Free the new extent.
*/
- freed_rtx = nmp->m_sb.sb_rextents - mp->m_sb.sb_rextents;
- error = xfs_growfs_rt_free_new(mp, &nargs, &freed_rtx);
+ error = xfs_growfs_rt_free_new(rtg, &nargs, &freed_rtx);
xfs_rtbuf_cache_relse(&nargs);
if (error)
goto out_cancel;
if (error)
goto out_free;
- for_each_rtgroup_from(mp, last_rgno, rtg)
- rtg->rtg_blockcount =
- xfs_rtgroup_block_count(mp, rtg->rtg_rgno);
-
/*
* Ensure the mount RT feature flag is now set, and compute new
* maxlevels for rt btrees.
out_cancel:
xfs_trans_cancel(args.tp);
out_free:
- if (xfs_has_rtgroups(mp))
- xfs_growfsrt_free_rtgroups(mp, nmp);
kfree(nmp);
return error;
}
*/
static xfs_fileoff_t
xfs_last_rt_bmblock(
- struct xfs_mount *mp)
+ struct xfs_rtgroup *rtg)
{
- xfs_fileoff_t bmbno = mp->m_sb.sb_rbmblocks;
+ struct xfs_mount *mp = rtg->rtg_mount;
+ xfs_rgnumber_t rgno = rtg->rtg_rgno;
+ xfs_fileoff_t bmbno = 0;
+
+ ASSERT(rgno >= mp->m_sb.sb_rgcount - 1);
+ if (rgno == mp->m_sb.sb_rgcount - 1) {
+ xfs_rtxnum_t nrext = xfs_rtgroup_extents(mp, rgno);
+
+ /* Skip the current block if it is exactly full. */
+ bmbno = __xfs_rtbitmap_blockcount(mp, nrext);
+ if (xfs_rtx_to_rbmword(mp, nrext) != 0)
+ bmbno--;
+ }
- /* Skip the current block if it is exactly full. */
- if (xfs_rtx_to_rbmword(mp, mp->m_sb.sb_rextents) != 0)
- bmbno--;
return bmbno;
}
return error;
}
+/*
+ * Allocate space to the bitmap and summary files, as necessary.
+ */
+static int
+xfs_growfs_rt_alloc_blocks(
+ struct xfs_rtgroup *rtg,
+ xfs_rfsblock_t nrblocks,
+ xfs_agblock_t rextsize,
+ xfs_extlen_t *nrbmblocks)
+{
+ struct xfs_mount *mp = rtg->rtg_mount;
+ struct xfs_inode *rbmip = rtg->rtg_inodes[XFS_RTG_BITMAP];
+ struct xfs_inode *rsumip = rtg->rtg_inodes[XFS_RTG_SUMMARY];
+ xfs_rtxnum_t nrextents = div_u64(nrblocks, rextsize);
+ xfs_extlen_t orbmblocks;
+ xfs_extlen_t orsumblocks;
+ xfs_extlen_t nrsumblocks;
+ int error;
+
+ if (xfs_has_rtgroups(mp)) {
+ /*
+ * For file systems with the rtgroups feature, the RT bitmap and
+ * summary are always fully allocated, which means that we never
+ * need to grow the existing files.
+ */
+ *nrbmblocks = mp->m_sb.sb_rbmblocks;
+ if (rtg->rtg_rgno <= mp->m_sb.sb_rgcount - 1)
+ return 0;
+ orbmblocks = 0;
+ orsumblocks = 0;
+ nrsumblocks = XFS_B_TO_FSB(mp, mp->m_rsumsize);
+ } else {
+ /*
+ * Get the old block counts for bitmap and summary inodes.
+ * These can't change since other growfs callers are locked out.
+ */
+ orbmblocks = XFS_B_TO_FSB(mp, rbmip->i_disk_size);
+ orsumblocks = XFS_B_TO_FSB(mp, rsumip->i_disk_size);
+
+ *nrbmblocks = __xfs_rtbitmap_blockcount(mp, nrextents);
+ nrsumblocks = xfs_rtsummary_blockcount(mp,
+ xfs_compute_rsumlevels(mp, nrextents), *nrbmblocks);
+ }
+
+ error = xfs_rtfile_initialize_blocks(rtg, XFS_RTG_BITMAP, orbmblocks,
+ *nrbmblocks, NULL);
+ if (error)
+ return error;
+ return xfs_rtfile_initialize_blocks(rtg, XFS_RTG_SUMMARY, orsumblocks,
+ nrsumblocks, NULL);
+}
+
+static int
+xfs_growfs_rtg(
+ struct xfs_rtgroup *rtg,
+ xfs_rfsblock_t nrblocks,
+ xfs_agblock_t rextsize)
+{
+ uint8_t *old_rsum_cache = NULL;
+ xfs_extlen_t bmblocks;
+ xfs_fileoff_t bmbno;
+ int error;
+
+ error = xfs_growfs_rt_alloc_blocks(rtg, nrblocks, rextsize, &bmblocks);
+ if (error)
+ return error;
+
+ if (bmblocks != rtg->rtg_mount->m_sb.sb_rbmblocks) {
+ old_rsum_cache = rtg->rtg_rsum_cache;
+ error = xfs_alloc_rsum_cache(rtg, bmblocks);
+ if (error)
+ return error;
+ }
+
+ for (bmbno = xfs_last_rt_bmblock(rtg); bmbno < bmblocks; bmbno++) {
+ error = xfs_growfs_rt_bmblock(rtg, nrblocks, rextsize, bmbno);
+ if (error)
+ goto out_error;
+ }
+
+ if (old_rsum_cache)
+ kvfree(old_rsum_cache);
+ return 0;
+
+out_error:
+ /*
+ * Reset rtg_extents to the old value if adding more blocks failed.
+ */
+ rtg->rtg_extents = xfs_rtgroup_extents(rtg->rtg_mount, rtg->rtg_rgno);
+ if (old_rsum_cache) {
+ kvfree(rtg->rtg_rsum_cache);
+ rtg->rtg_rsum_cache = old_rsum_cache;
+ }
+ return error;
+}
+
/*
* Check that changes to the realtime geometry won't affect the minimum
* log size, which would cause the fs to become unusable.
*/
int
xfs_growfs_rt(
- xfs_mount_t *mp, /* mount point for filesystem */
- xfs_growfs_rt_t *in) /* growfs rt input struct */
+ struct xfs_mount *mp,
+ struct xfs_growfs_rt *in)
{
- xfs_fileoff_t bmbno; /* bitmap block number */
- struct xfs_buf *bp; /* temporary buffer */
- int error; /* error return value */
- xfs_extlen_t nrbmblocks; /* new number of rt bitmap blocks */
- xfs_rtxnum_t nrextents; /* new number of realtime extents */
- xfs_extlen_t nrsumblocks; /* new number of summary blocks */
- xfs_extlen_t rbmblocks; /* current number of rt bitmap blocks */
- xfs_extlen_t rsumblocks; /* current number of rt summary blks */
- uint8_t *rsum_cache; /* old summary cache */
+ xfs_rgnumber_t last_rgno = mp->m_sb.sb_rgcount - 1;
+ unsigned int new_rgcount = 1;
+ xfs_rtxnum_t nrextents;
+ struct xfs_rtgroup *rtg;
+ xfs_rgnumber_t rgno;
+ struct xfs_buf *bp;
+ int error;
+ unsigned int i;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
/* Needs to have been mounted with an rt device. */
if (!XFS_IS_REALTIME_MOUNT(mp))
return -EINVAL;
- /*
- * Mount should fail if the rt bitmap/summary files don't load, but
- * we'll check anyway.
- */
- if (!mp->m_rbmip || !mp->m_rsumip)
- return -EINVAL;
/* Shrink not supported. */
if (in->newblocks <= mp->m_sb.sb_rblocks)
nrextents = div_u64(in->newblocks, in->extsize);
if (nrextents == 0)
return -EINVAL;
- nrbmblocks = xfs_rtbitmap_blockcount(mp, nrextents);
- nrsumblocks = xfs_rtsummary_blockcount(mp,
- xfs_compute_rextslog(nrextents) + 1, nrbmblocks);
/* Make sure the new fs size won't cause problems with the log. */
error = xfs_growfs_check_rtgeom(mp, mp->m_sb.sb_dblocks, in->newblocks,
* because the userspace ABI doesn't support it.
*/
if (xfs_has_rtgroups(mp)) {
- uint64_t new_rgcount;
-
new_rgcount = howmany_64(nrextents, mp->m_sb.sb_rgextents);
if (new_rgcount > XFS_MAX_RGNUMBER)
return -EINVAL;
- }
- /* Set up the realtime superblock if we're adding a new rt section. */
- if (xfs_has_rtsb(mp) && mp->m_sb.sb_rblocks == 0) {
- error = xfs_growfs_rt_init_super(mp);
- if (error)
- return error;
+ /*
+ * Set up the realtime superblock if we're adding a new rt
+ * section.
+ */
+ if (xfs_has_rtsb(mp) && mp->m_sb.sb_rblocks == 0) {
+ error = xfs_growfs_rt_init_super(mp);
+ if (error)
+ return error;
+ }
+
+ /* Make sure the /rtgroups dir has been created */
+ if (!mp->m_rtdirip) {
+ struct xfs_trans *tp;
+
+ error = xfs_trans_alloc_empty(mp, &tp);
+ if (error)
+ return error;
+ error = xfs_rtginode_load_parent(tp);
+ xfs_trans_cancel(tp);
+
+ if (error == -ENOENT)
+ error = xfs_rtginode_mkdir_parent(mp);
+ if (error)
+ return error;
+ }
}
- /*
- * Get the old block counts for bitmap and summary inodes.
- * These can't change since other growfs callers are locked out.
- */
- rbmblocks = XFS_B_TO_FSB(mp, mp->m_rbmip->i_disk_size);
- rsumblocks = XFS_B_TO_FSB(mp, mp->m_rsumip->i_disk_size);
- /*
- * Allocate space to the bitmap and summary files, as necessary.
- */
- error = xfs_rtfile_initialize_blocks(mp->m_rbmip, rbmblocks,
- nrbmblocks, NULL);
- if (error)
- return error;
- error = xfs_rtfile_initialize_blocks(mp->m_rsumip, rsumblocks,
- nrsumblocks, NULL);
+ error = xfs_initialize_rtgroups(mp, new_rgcount);
if (error)
return error;
- rsum_cache = mp->m_rsum_cache;
- if (nrbmblocks != mp->m_sb.sb_rbmblocks) {
- error = xfs_alloc_rsum_cache(mp, nrbmblocks);
- if (error)
- return error;
- }
+ /*
+ * If the last RT group is completely full we can skip it.
+ */
+ if (xfs_rtgroup_extents(mp, last_rgno) == mp->m_sb.sb_rgextents)
+ last_rgno++;
- /* Initialize the free space bitmap one bitmap block at a time. */
- for (bmbno = xfs_last_rt_bmblock(mp); bmbno < nrbmblocks; bmbno++) {
- error = xfs_growfs_rt_bmblock(mp, in->newblocks, in->extsize,
- bmbno);
- if (error)
+ for_each_rtgroup_range(mp, last_rgno, new_rgcount - 1, rtg) {
+ unsigned int i;
+
+ for (i = 0; i < XFS_RTG_MAX; i++) {
+ error = xfs_rtginode_ensure(rtg, i);
+ if (error) {
+ xfs_rtgroup_rele(rtg);
+ goto out_free;
+ }
+ }
+
+ error = xfs_growfs_rtg(rtg, in->newblocks, in->extsize);
+ if (error) {
+ xfs_rtgroup_rele(rtg);
goto out_free;
+ }
}
/* Update secondary superblocks now the physical grow has completed */
error = xfs_rt_resv_init(mp);
if (error == -ENOSPC)
error = 0;
+ if (error)
+ goto out_free;
+
+ return 0;
out_free:
- /*
- * If we had to allocate a new rsum_cache, we either need to free the
- * old one (if we succeeded) or free the new one and restore the old one
- * (if there was an error).
- */
- if (rsum_cache != mp->m_rsum_cache) {
- if (error) {
- kvfree(mp->m_rsum_cache);
- mp->m_rsum_cache = rsum_cache;
- } else {
- kvfree(rsum_cache);
- }
+ rgno = mp->m_sb.sb_rgcount + 1;
+ for_each_rtgroup_range(mp, rgno, new_rgcount - 1, rtg) {
+ for (i = 0; i < XFS_RTG_MAX; i++)
+ xfs_rtginode_irele(&rtg->rtg_inodes[i]);
}
+ xfs_free_unused_rtgroup_range(mp, mp->m_sb.sb_rgcount + 1,
+ new_rgcount - 1);
return error;
}
"Filesystem has a realtime volume, use rtdev=device option");
return -ENODEV;
}
- mp->m_rsumlevels = sbp->sb_rextslog + 1;
+ mp->m_rsumlevels = xfs_compute_rsumlevels(mp, sbp->sb_rextents);
rsumblocks = xfs_rtsummary_blockcount(mp, mp->m_rsumlevels,
mp->m_sb.sb_rbmblocks);
mp->m_rsumsize = XFS_FSB_TO_B(mp, rsumblocks);
- mp->m_rbmip = mp->m_rsumip = NULL;
+
/*
* Check that the realtime section is an ok size.
*/
static int
xfs_rtalloc_count_frextent(
- struct xfs_mount *mp,
+ struct xfs_rtgroup *rtg,
struct xfs_trans *tp,
const struct xfs_rtalloc_rec *rec,
void *priv)
uint64_t val = 0;
int error;
- xfs_rtbitmap_lock_shared(mp, XFS_RBMLOCK_BITMAP);
- error = xfs_rtalloc_query_all(mp, NULL, xfs_rtalloc_count_frextent,
- &val);
- xfs_rtbitmap_unlock_shared(mp, XFS_RBMLOCK_BITMAP);
- if (error)
- return error;
+ struct xfs_rtgroup *rtg;
+ xfs_rgnumber_t rgno;
+
+ for_each_rtgroup(mp, rgno, rtg) {
+ xfs_rtgroup_lock(rtg, XFS_RTGLOCK_BITMAP_SHARED);
+ error = xfs_rtalloc_query_all(rtg, NULL, xfs_rtalloc_count_frextent,
+ &val);
+ xfs_rtgroup_unlock(rtg, XFS_RTGLOCK_BITMAP_SHARED);
+ if (error)
+ return error;
+ }
spin_lock(&mp->m_sb_lock);
mp->m_sb.sb_frextents = val;
* at runtime. This enables the use of shared ILOCKs for rtbitmap scans. Use
* an empty transaction to avoid deadlocking on loops in the bmbt.
*/
-static inline int
+static int
xfs_rtmount_iread_extents(
struct xfs_trans *tp,
struct xfs_inode *ip)
xfs_ilock(ip, XFS_ILOCK_EXCL);
- error = xfs_iread_extents(tp, ip, XFS_DATA_FORK);
- if (error)
- goto out_unlock;
+ /* No need to read the data for btree inodes */
+ if (ip->i_df.if_format != XFS_DINODE_FMT_RMAP &&
+ ip->i_df.if_format != XFS_DINODE_FMT_REFCOUNT) {
+ error = xfs_iread_extents(tp, ip, XFS_DATA_FORK);
+ if (error)
+ goto out_unlock;
+ }
if (xfs_inode_has_attr_fork(ip)) {
error = xfs_iread_extents(tp, ip, XFS_ATTR_FORK);
return error;
}
-static void
-xfs_rtgroup_unmount_inodes(
- struct xfs_mount *mp)
+static int
+xfs_rtmount_rtg(
+ struct xfs_mount *mp,
+ struct xfs_trans *tp,
+ struct xfs_rtgroup *rtg)
{
- struct xfs_rtgroup *rtg;
- xfs_rgnumber_t rgno;
- unsigned int i;
+ int error, i;
- for_each_rtgroup(mp, rgno, rtg) {
- for (i = 0; i < XFS_RTG_MAX; i++)
- xfs_rtginode_irele(&rtg->rtg_inodes[i]);
+ rtg->rtg_extents = xfs_rtgroup_extents(mp, rtg->rtg_rgno);
+
+ for (i = 0; i < XFS_RTG_MAX; i++) {
+ error = xfs_rtginode_load(rtg, i, tp);
+ if (error)
+ return error;
+
+ if (rtg->rtg_inodes[i]) {
+ error = xfs_rtmount_iread_extents(tp,
+ rtg->rtg_inodes[i]);
+ if (error)
+ return error;
+ }
}
+
+ xfs_alloc_rsum_cache(rtg, mp->m_sb.sb_rbmblocks);
+ return 0;
}
/*
struct xfs_mount *mp)
{
struct xfs_trans *tp;
- struct xfs_sb *sbp = &mp->m_sb;
struct xfs_rtgroup *rtg;
xfs_rgnumber_t rgno;
- unsigned int i;
int error;
error = xfs_trans_alloc_empty(mp, &tp);
if (error)
return error;
- error = xfs_metafile_iget(tp, mp->m_sb.sb_rbmino, S_IFREG, &mp->m_rbmip);
- if (xfs_metadata_is_sick(error))
- xfs_rt_mark_sick(mp, XFS_SICK_RT_BITMAP);
- if (error)
- goto out_trans;
- ASSERT(mp->m_rbmip != NULL);
-
- lockdep_set_class(&mp->m_rbmip->i_lock, &xfs_rtbitmap_key);
-
- error = xfs_rtmount_iread_extents(tp, mp->m_rbmip);
- if (error)
- goto out_rele_bitmap;
-
- error = xfs_metafile_iget(tp, mp->m_sb.sb_rsumino, S_IFREG, &mp->m_rsumip);
- if (xfs_metadata_is_sick(error))
- xfs_rt_mark_sick(mp, XFS_SICK_RT_SUMMARY);
- if (error)
- goto out_rele_bitmap;
- ASSERT(mp->m_rsumip != NULL);
-
- lockdep_set_class(&mp->m_rsumip->i_lock, &xfs_rtsummary_key);
-
- error = xfs_rtmount_iread_extents(tp, mp->m_rsumip);
- if (error)
- goto out_rele_summary;
-
if (xfs_has_rtgroups(mp) && mp->m_sb.sb_rgcount > 0) {
error = xfs_rtginode_load_parent(tp);
if (error)
- goto out_rele_rtdir;
+ goto out_cancel;
}
for_each_rtgroup(mp, rgno, rtg) {
- rtg->rtg_blockcount = xfs_rtgroup_block_count(mp,
- rtg->rtg_rgno);
-
- for (i = 0; i < XFS_RTG_MAX; i++) {
- error = xfs_rtginode_load(rtg, i, tp);
- if (error) {
- xfs_rtgroup_rele(rtg);
- goto out_rele_inodes;
- }
+ error = xfs_rtmount_rtg(mp, tp, rtg);
+ if (error) {
+ xfs_rtgroup_rele(rtg);
+ xfs_rtunmount_inodes(mp);
+ break;
}
}
- error = xfs_alloc_rsum_cache(mp, sbp->sb_rbmblocks);
- if (error)
- goto out_rele_summary;
- xfs_trans_cancel(tp);
- return 0;
-
-out_rele_inodes:
- xfs_rtgroup_unmount_inodes(mp);
-out_rele_rtdir:
- xfs_rtginode_irele(&mp->m_rtdirip);
-out_rele_summary:
- xfs_irele(mp->m_rsumip);
-out_rele_bitmap:
- xfs_irele(mp->m_rbmip);
-out_trans:
+out_cancel:
xfs_trans_cancel(tp);
return error;
}
xfs_rtunmount_inodes(
struct xfs_mount *mp)
{
- kvfree(mp->m_rsum_cache);
+ struct xfs_rtgroup *rtg;
+ xfs_rgnumber_t rgno;
+ int i;
+
+ for_each_rtgroup(mp, rgno, rtg) {
+ for (i = 0; i < XFS_RTG_MAX; i++)
+ xfs_rtginode_irele(&rtg->rtg_inodes[i]);
+ kvfree(rtg->rtg_rsum_cache);
+ }
- xfs_rtgroup_unmount_inodes(mp);
xfs_rtginode_irele(&mp->m_rtdirip);
- if (mp->m_rbmip)
- xfs_irele(mp->m_rbmip);
- if (mp->m_rsumip)
- xfs_irele(mp->m_rsumip);
}
/*
*/
static xfs_rtxnum_t
xfs_rtpick_extent(
- xfs_mount_t *mp, /* file system mount point */
- xfs_trans_t *tp, /* transaction pointer */
+ struct xfs_trans *tp,
+ struct xfs_rtgroup *rtg,
xfs_rtxlen_t len) /* allocation length (rtextents) */
{
- xfs_rtxnum_t b; /* result rtext */
+ struct xfs_mount *mp = rtg->rtg_mount;
+ struct xfs_inode *rbmip = rtg->rtg_inodes[XFS_RTG_BITMAP];
+ xfs_rtxnum_t b = 0; /* result rtext */
int log2; /* log of sequence number */
uint64_t resid; /* residual after log removed */
uint64_t seq; /* sequence number of file creation */
struct timespec64 ts; /* timespec in inode */
- xfs_assert_ilocked(mp->m_rbmip, XFS_ILOCK_EXCL);
-
- if (xfs_has_rtgroups(mp)) {
- xfs_rtblock_t rtbno;
-
- /* Pick the first usable rtx of the group. */
- rtbno = xfs_rgbno_to_rtb(mp, mp->m_rtgrotor, 0);
- mp->m_rtgrotor = (mp->m_rtgrotor + 1) % mp->m_sb.sb_rgcount;
- return xfs_rtb_to_rtx(mp, rtbno) + 1;
- }
+ xfs_assert_ilocked(rbmip, XFS_ILOCK_EXCL);
- ts = inode_get_atime(VFS_I(mp->m_rbmip));
- if (!(mp->m_rbmip->i_diflags & XFS_DIFLAG_NEWRTBM)) {
- mp->m_rbmip->i_diflags |= XFS_DIFLAG_NEWRTBM;
+ ts = inode_get_atime(VFS_I(rbmip));
+ if (!(rbmip->i_diflags & XFS_DIFLAG_NEWRTBM)) {
+ rbmip->i_diflags |= XFS_DIFLAG_NEWRTBM;
seq = 0;
} else {
seq = ts.tv_sec;
}
- if ((log2 = xfs_highbit64(seq)) == -1)
- b = 0;
- else {
+ log2 = xfs_highbit64(seq);
+ if (log2 != -1) {
resid = seq - (1ULL << log2);
b = (mp->m_sb.sb_rextents * ((resid << 1) + 1ULL)) >>
(log2 + 1);
b = mp->m_sb.sb_rextents - len;
}
ts.tv_sec = seq + 1;
- inode_set_atime_to_ts(VFS_I(mp->m_rbmip), ts);
- xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE);
+ inode_set_atime_to_ts(VFS_I(rbmip), ts);
+ xfs_trans_log_inode(tp, rbmip, XFS_ILOG_CORE);
return b;
}
}
static int
-xfs_rtallocate(
+xfs_rtallocate_rtg(
struct xfs_trans *tp,
- xfs_rtxnum_t start,
+ xfs_rgnumber_t rgno,
+ xfs_fsblock_t bno_hint,
xfs_rtxlen_t minlen,
xfs_rtxlen_t maxlen,
xfs_rtxlen_t prod,
.mp = tp->t_mountp,
.tp = tp,
};
+ xfs_rtxnum_t start = 0;
xfs_rtxnum_t rtx;
xfs_rtxlen_t len = 0;
int error = 0;
+ args.rtg = xfs_rtgroup_grab(args.mp, rgno);
+ if (!args.rtg)
+ return -ENOSPC;
+
/*
- * Lock out modifications to both the RT bitmap and summary inodes.
+ * We need to lock out modifications to both the RT bitmap and summary
+ * inodes for finding free space in xfs_rtallocate_extent_{near,size}
+ * and join the bitmap and summary inodes for the actual allocation
+ * down in xfs_rtallocate_range.
+ *
+ * For RTG-enabled file system we don't want to join the inodes to the
+ * transaction until we are committed to allocate to allocate from this
+ * RTG so that only one inode of each type is locked at a time.
+ *
+ * But for pre-RTG file systems we need to already to join the bitmap
+ * inode to the transaction for xfs_rtpick_extent, which bumps the
+ * sequence number in it, so we'll have to join the inode to the
+ * transaction early here.
+ *
+ * This is all a bit messy, but at least the mess is contained in
+ * this function.
*/
if (!*rtlocked) {
- xfs_rtbitmap_lock(args.mp);
- xfs_rtbitmap_trans_join(tp);
+ xfs_rtgroup_lock(args.rtg, XFS_RTGLOCK_BITMAP);
+ if (!xfs_has_rtgroups(args.mp))
+ xfs_rtgroup_trans_join(tp, args.rtg,
+ XFS_RTGLOCK_BITMAP);
*rtlocked = true;
}
* For an allocation to an empty file at offset 0, pick an extent that
* will space things out in the rt area.
*/
- if (!start && initial_user_data)
- start = xfs_rtpick_extent(args.mp, tp, maxlen);
+ if (bno_hint)
+ start = xfs_rtb_to_rtx(args.mp, bno_hint);
+ else if (!xfs_has_rtgroups(args.mp) && initial_user_data)
+ start = xfs_rtpick_extent(tp, args.rtg, maxlen);
if (start) {
error = xfs_rtallocate_extent_near(&args, start, minlen, maxlen,
prod, &rtx);
}
- if (error)
+ if (error) {
+ if (xfs_has_rtgroups(args.mp)) {
+ xfs_rtgroup_unlock(args.rtg, XFS_RTGLOCK_BITMAP);
+ *rtlocked = false;
+ }
goto out_release;
+ }
+
+ if (xfs_has_rtgroups(args.mp))
+ xfs_rtgroup_trans_join(tp, args.rtg, XFS_RTGLOCK_BITMAP);
error = xfs_rtallocate_range(&args, rtx, len);
if (error)
xfs_trans_mod_sb(tp, wasdel ?
XFS_TRANS_SB_RES_FREXTENTS : XFS_TRANS_SB_FREXTENTS,
-(long)len);
- *bno = xfs_rtx_to_rtb(args.mp, rtx);
+ *bno = xfs_rtx_to_rtb(args.rtg, rtx);
*blen = xfs_rtxlen_to_extlen(args.mp, len);
out_release:
+ xfs_rtgroup_rele(args.rtg);
xfs_rtbuf_cache_relse(&args);
return error;
}
+int
+xfs_rtallocate_rtgs(
+ struct xfs_trans *tp,
+ xfs_fsblock_t bno_hint,
+ xfs_rtxlen_t minlen,
+ xfs_rtxlen_t maxlen,
+ xfs_rtxlen_t prod,
+ bool wasdel,
+ bool initial_user_data,
+ xfs_rtblock_t *bno,
+ xfs_extlen_t *blen)
+{
+ struct xfs_mount *mp = tp->t_mountp;
+ xfs_rgnumber_t start_rgno, rgno;
+ int error;
+
+ /*
+ * For now this just blindly iterates over the RTGs for an initial
+ * allocation. We could try to keep an in-memory rtg_longest member
+ * to avoid the locking when just looking for big enough free space,
+ * but for now this keep things simple.
+ */
+ if (bno_hint != NULLFSBLOCK)
+ start_rgno = xfs_rtb_to_rgno(mp, bno_hint);
+ else
+ start_rgno = (atomic_inc_return(&mp->m_rtgrotor) - 1) %
+ mp->m_sb.sb_rgcount;
+
+ rgno = start_rgno;
+ do {
+ bool rtlocked = false;
+
+ error = xfs_rtallocate_rtg(tp, rgno, bno_hint, minlen, maxlen,
+ prod, wasdel, initial_user_data, &rtlocked,
+ bno, blen);
+ if (error != -ENOSPC)
+ return error;
+ ASSERT(!rtlocked);
+
+ if (++rgno == mp->m_sb.sb_rgcount)
+ rgno = 0;
+ bno_hint = NULLFSBLOCK;
+ } while (rgno != start_rgno);
+
+ return -ENOSPC;
+}
+
static int
xfs_rtallocate_align(
struct xfs_bmalloca *ap,
{
struct xfs_mount *mp = ap->ip->i_mount;
xfs_fileoff_t orig_offset = ap->offset;
- xfs_rtxnum_t start = 0; /* allocation hint rtextent no */
xfs_rtxlen_t prod = 0; /* product factor for allocators */
xfs_rtxlen_t ralen = 0; /* realtime allocation length */
+ xfs_fsblock_t bno_hint = NULLFSBLOCK;
xfs_extlen_t orig_length = ap->length;
xfs_rtxlen_t raminlen;
bool rtlocked = false;
bool noalign = false;
+ bool initial_user_data =
+ ap->datatype & XFS_ALLOC_INITIAL_USER_DATA;
int error;
retry:
return error;
if (xfs_bmap_adjacent(ap))
- start = xfs_rtb_to_rtx(mp, ap->blkno);
+ bno_hint = ap->blkno;
+
+ if (xfs_has_rtgroups(mp)) {
+ error = xfs_rtallocate_rtgs(ap->tp, bno_hint, raminlen, ralen,
+ prod, ap->wasdel, initial_user_data,
+ &ap->blkno, &ap->length);
+ } else {
+ error = xfs_rtallocate_rtg(ap->tp, 0, bno_hint, raminlen, ralen,
+ prod, ap->wasdel, initial_user_data,
+ &rtlocked, &ap->blkno, &ap->length);
+ }
- error = xfs_rtallocate(ap->tp, start, raminlen, ralen, prod, ap->wasdel,
- ap->datatype & XFS_ALLOC_INITIAL_USER_DATA, &rtlocked,
- &ap->blkno, &ap->length);
if (error == -ENOSPC) {
if (!noalign) {
/*
xfs_bmap_alloc_account(ap);
return 0;
}
-
-/*
- * Allocate an extent in the realtime subvolume.
- *
- * If @start is nonzero, try to allocate near that exact rtx. @maxlen should
- * be the maximum length to allocate; the allocated space can be as short as a
- * single rtx. If no free space was allocated, returns -ENOSPC without
- * touching @len or @rtx.
- */
-int
-xfs_rtallocate_extent(
- struct xfs_trans *tp,
- xfs_rtxnum_t start, /* starting rtext number to allocate */
- xfs_rtxlen_t maxlen, /* maximum length to allocate */
- xfs_rtxlen_t *len, /* out: actual length allocated */
- xfs_rtxnum_t *rtx) /* out: start rtext allocated */
-{
- struct xfs_rtalloc_args args = {
- .mp = tp->t_mountp,
- .tp = tp,
- };
- xfs_rtxnum_t r;
- xfs_rtxlen_t l;
- int error;
-
- xfs_assert_ilocked(args.mp->m_rbmip, XFS_ILOCK_EXCL);
-
- if (start == 0) {
- error = xfs_rtallocate_extent_size(&args, 1, maxlen, &l, 1, &r);
- } else {
- error = xfs_rtallocate_extent_near(&args, start, 1, maxlen,
- &l, 1, &r);
- }
- if (error)
- goto out_release;
-
- ASSERT(l <= maxlen);
- error = xfs_rtallocate_range(&args, r, l);
- if (error)
- goto out_release;
-
- xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, -(int64_t)l);
- *rtx = r;
- *len = l;
-
-out_release:
- xfs_rtbuf_cache_relse(&args);
- return error;
-}
int xfs_rtalloc_reinit_frextents(struct xfs_mount *mp);
int xfs_growfs_check_rtgeom(const struct xfs_mount *mp, xfs_rfsblock_t dblocks,
xfs_rfsblock_t rblocks, xfs_agblock_t rextsize);
-int xfs_rtallocate_extent(struct xfs_trans *tp, xfs_rtxnum_t start,
- xfs_rtxlen_t maxlen, xfs_rtxlen_t *len, xfs_rtxnum_t *rtx);
+int xfs_rtallocate_rtgs(struct xfs_trans *tp, xfs_fsblock_t bno_hint,
+ xfs_rtxlen_t minlen, xfs_rtxlen_t maxlen, xfs_rtxlen_t prod,
+ bool wasdel, bool initial_user_data, xfs_rtblock_t *bno,
+ xfs_extlen_t *blen);
#else
# define xfs_growfs_rt(mp,in) (-ENOSYS)
# define xfs_rtalloc_reinit_frextents(m) (0)
# define xfs_rtunmount_inodes(m)
# define xfs_rt_resv_free(mp) ((void)0)
# define xfs_rt_resv_init(mp) (0)
-# define xfs_rtallocate_extent(...) (-ENOSYS)
+
+static inline int
+xfs_rtallocate_rtgs(struct xfs_trans *tp, xfs_fsblock_t bno_hint,
+ xfs_rtxlen_t minlen, xfs_rtxlen_t maxlen, xfs_rtxlen_t prod,
+ bool wasdel, bool initial_user_data, xfs_rtblock_t *bno,
+ xfs_extlen_t *blen)
+{
+ return -EINVAL;
+}
static inline int
xfs_growfs_check_rtgeom(const struct xfs_mount *mp,
statp->f_blocks = sbp->sb_rblocks;
freertx = percpu_counter_sum_positive(&mp->m_frextents);
- statp->f_bavail = statp->f_bfree = xfs_rtx_to_rtb(mp, freertx);
+ statp->f_bavail = statp->f_bfree =
+ xfs_rtbxlen_to_blen(mp, freertx);
}
return 0;