blob: 15fa7de1f10bd26903122923db9849668fbdb774 [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;
union xfs_rtword_raw *words;
btmcompute = calloc(libxfs_rtbitmap_wordcount(mp, mp->m_sb.sb_rextents),
sizeof(union xfs_rtword_raw));
if (!btmcompute)
do_error(
_("couldn't allocate memory for incore realtime bitmap.\n"));
words = btmcompute;
sumcompute = calloc(libxfs_rtsummary_wordcount(mp, mp->m_rsumlevels,
mp->m_sb.sb_rbmblocks), 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,
const char *filename,
xfs_ino_t ino,
void *buf,
xfs_fileoff_t filelen)
{
struct xfs_bmbt_irec map;
struct xfs_buf *bp;
struct xfs_inode *ip;
xfs_fileoff_t bno = 0;
int error;
error = -libxfs_iget(mp, NULL, ino, 0, &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, "rtbitmap", mp->m_sb.sb_rbmino, btmcompute,
mp->m_sb.sb_rbmblocks);
}
void
check_rtsummary(
struct xfs_mount *mp)
{
if (need_rsumino)
return;
check_rtfile_contents(mp, "rtsummary", mp->m_sb.sb_rsumino, sumcompute,
XFS_B_TO_FSB(mp, mp->m_rsumsize));
}
void
fill_rtbitmap(
struct xfs_mount *mp)
{
struct xfs_trans *tp;
struct xfs_inode *ip;
int error;
error = -libxfs_trans_alloc_empty(mp, &tp);
if (error)
do_error(
_("couldn't allocate empty transaction, error %d\n"), error);
error = -libxfs_iget(mp, tp, mp->m_sb.sb_rbmino, 0, &ip);
if (error)
do_error(
_("couldn't iget realtime bitmap inode, error %d\n"), error);
libxfs_trans_cancel(tp);
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_trans *tp;
struct xfs_inode *ip;
int error;
error = -libxfs_trans_alloc_empty(mp, &tp);
if (error)
do_error(
_("couldn't allocate empty transaction, error %d\n"), error);
error = -libxfs_iget(mp, tp, mp->m_sb.sb_rsumino, 0, &ip);
if (error) {
do_error(
_("couldn't iget realtime summary inode, error - %d\n"), error);
}
libxfs_trans_cancel(tp);
mp->m_rsumip = ip;
error = -libxfs_rtfile_initialize_blocks(ip, 0,
mp->m_rsumsize >> mp->m_sb.sb_blocklog,
sumcompute);
mp->m_rsumip = NULL;
if (error)
do_error(
_("couldn't re-initialize realtime summary inode, error %d\n"), error);
libxfs_irele(ip);
}