blob: d0a171020c4b49091aca763d26047eecfb8dfd58 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
* All Rights Reserved.
*/
#include "libxfs.h"
#include "avl.h"
#include "globals.h"
#include "agheader.h"
#include "incore.h"
#include "dinode.h"
#include "protos.h"
#include "err_protos.h"
#include "rt.h"
/* Computed rt bitmap/summary data */
static union xfs_rtword_raw *btmcompute;
static union xfs_suminfo_raw *sumcompute;
static inline void
set_rtword(
struct xfs_mount *mp,
union xfs_rtword_raw *word,
xfs_rtword_t value)
{
word->old = value;
}
static inline void
inc_sumcount(
struct xfs_mount *mp,
union xfs_suminfo_raw *info,
xfs_rtsumoff_t index)
{
union xfs_suminfo_raw *p = info + index;
p->old++;
}
/*
* generate the real-time bitmap and summary info based on the
* incore realtime extent map.
*/
void
generate_rtinfo(
struct xfs_mount *mp)
{
unsigned int bitsperblock =
mp->m_blockwsize << XFS_NBWORDLOG;
xfs_rtxnum_t extno = 0;
xfs_rtxnum_t start_ext = 0;
int bmbno = 0;
int start_bmbno = 0;
bool in_extent = false;
unsigned long long wordcnt;
union xfs_rtword_raw *words;
wordcnt = XFS_FSB_TO_B(mp, mp->m_sb.sb_rbmblocks) >> XFS_WORDLOG;
btmcompute = calloc(wordcnt, sizeof(union xfs_rtword_raw));
if (!btmcompute)
do_error(
_("couldn't allocate memory for incore realtime bitmap.\n"));
words = btmcompute;
wordcnt = XFS_FSB_TO_B(mp, mp->m_rsumblocks) >> XFS_WORDLOG;
sumcompute = calloc(wordcnt, sizeof(union xfs_suminfo_raw));
if (!sumcompute)
do_error(
_("couldn't allocate memory for incore realtime summary info.\n"));
ASSERT(mp->m_rbmip == NULL);
/*
* Slower but simple, don't play around with trying to set things one
* word at a time, just set bit as required. Have to track start and
* end (size) of each range of free extents to set the summary info
* properly.
*/
while (extno < mp->m_sb.sb_rextents) {
xfs_rtword_t freebit = 1;
xfs_rtword_t bits = 0;
int i;
set_rtword(mp, words, 0);
for (i = 0; i < sizeof(xfs_rtword_t) * NBBY &&
extno < mp->m_sb.sb_rextents; i++, extno++) {
if (get_rtbmap(extno) == XR_E_FREE) {
sb_frextents++;
bits |= freebit;
if (!in_extent) {
start_ext = extno;
start_bmbno = bmbno;
in_extent = true;
}
} else if (in_extent) {
uint64_t len = extno - start_ext;
xfs_rtsumoff_t offs;
offs = xfs_rtsumoffs(mp, libxfs_highbit64(len),
start_bmbno);
inc_sumcount(mp, sumcompute, offs);
in_extent = false;
}
freebit <<= 1;
}
set_rtword(mp, words, bits);
words++;
if (extno % bitsperblock == 0)
bmbno++;
}
if (in_extent) {
uint64_t len = extno - start_ext;
xfs_rtsumoff_t offs;
offs = xfs_rtsumoffs(mp, libxfs_highbit64(len), start_bmbno);
inc_sumcount(mp, sumcompute, offs);
}
if (mp->m_sb.sb_frextents != sb_frextents) {
do_warn(_("sb_frextents %" PRIu64 ", counted %" PRIu64 "\n"),
mp->m_sb.sb_frextents, sb_frextents);
}
}
static void
check_rtfile_contents(
struct xfs_mount *mp,
enum xfs_metafile_type metafile_type,
xfs_fileoff_t filelen)
{
struct xfs_bmbt_irec map;
struct xfs_buf *bp;
struct xfs_inode *ip;
const char *filename;
void *buf;
xfs_ino_t ino;
xfs_fileoff_t bno = 0;
int error;
switch (metafile_type) {
case XFS_METAFILE_RTBITMAP:
ino = mp->m_sb.sb_rbmino;
filename = "rtbitmap";
buf = btmcompute;
break;
case XFS_METAFILE_RTSUMMARY:
ino = mp->m_sb.sb_rsumino;
filename = "rtsummary";
buf = sumcompute;
break;
default:
return;
}
error = -libxfs_metafile_iget(mp, ino, metafile_type, &ip);
if (error) {
do_warn(_("unable to open %s file, err %d\n"), filename, error);
return;
}
if (ip->i_disk_size != XFS_FSB_TO_B(mp, filelen)) {
do_warn(_("expected %s file size %llu, found %llu\n"),
filename,
(unsigned long long)XFS_FSB_TO_B(mp, filelen),
(unsigned long long)ip->i_disk_size);
}
while (bno < filelen) {
xfs_filblks_t maplen;
int nmap = 1;
/* Read up to 1MB at a time. */
maplen = min(filelen - bno, XFS_B_TO_FSBT(mp, 1048576));
error = -libxfs_bmapi_read(ip, bno, maplen, &map, &nmap, 0);
if (error) {
do_warn(_("unable to read %s mapping, err %d\n"),
filename, error);
break;
}
if (map.br_startblock == HOLESTARTBLOCK) {
do_warn(_("hole in %s file at dblock 0x%llx\n"),
filename, (unsigned long long)bno);
break;
}
error = -libxfs_buf_read_uncached(mp->m_dev,
XFS_FSB_TO_DADDR(mp, map.br_startblock),
XFS_FSB_TO_BB(mp, map.br_blockcount),
0, &bp, NULL);
if (error) {
do_warn(_("unable to read %s at dblock 0x%llx, err %d\n"),
filename, (unsigned long long)bno, error);
break;
}
if (memcmp(bp->b_addr, buf, mp->m_blockwsize << XFS_WORDLOG))
do_warn(_("discrepancy in %s at dblock 0x%llx\n"),
filename, (unsigned long long)bno);
buf += XFS_FSB_TO_B(mp, map.br_blockcount);
bno += map.br_blockcount;
libxfs_buf_relse(bp);
}
libxfs_irele(ip);
}
void
check_rtbitmap(
struct xfs_mount *mp)
{
if (need_rbmino)
return;
check_rtfile_contents(mp, XFS_METAFILE_RTBITMAP,
mp->m_sb.sb_rbmblocks);
}
void
check_rtsummary(
struct xfs_mount *mp)
{
if (need_rsumino)
return;
check_rtfile_contents(mp, XFS_METAFILE_RTSUMMARY, mp->m_rsumblocks);
}
void
fill_rtbitmap(
struct xfs_mount *mp)
{
struct xfs_inode *ip;
int error;
error = -libxfs_metafile_iget(mp, mp->m_sb.sb_rbmino,
XFS_METAFILE_RTBITMAP, &ip);
if (error)
do_error(
_("couldn't iget realtime bitmap inode, error %d\n"), error);
error = -libxfs_rtfile_initialize_blocks(ip, 0, mp->m_sb.sb_rbmblocks,
btmcompute);
if (error)
do_error(
_("couldn't re-initialize realtime bitmap inode, error %d\n"), error);
libxfs_irele(ip);
}
void
fill_rtsummary(
struct xfs_mount *mp)
{
struct xfs_inode *ip;
int error;
error = -libxfs_metafile_iget(mp, mp->m_sb.sb_rsumino,
XFS_METAFILE_RTSUMMARY, &ip);
if (error)
do_error(
_("couldn't iget realtime summary inode, error %d\n"), error);
mp->m_rsumip = ip;
error = -libxfs_rtfile_initialize_blocks(ip, 0, mp->m_rsumblocks,
sumcompute);
mp->m_rsumip = NULL;
if (error)
do_error(
_("couldn't re-initialize realtime summary inode, error %d\n"), error);
libxfs_irele(ip);
}