blob: 6ad3e23832faa36e834b8a95a779e220b58edb60 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2018 Oracle. All Rights Reserved.
* Author: Darrick J. Wong <darrick.wong@oracle.com>
*/
#include "libxfs.h"
#include "command.h"
#include "init.h"
#include "output.h"
#include "libfrog/fsgeom.h"
#include "libfrog/logging.h"
static void
info_help(void)
{
dbprintf(_(
"\n"
" Pretty-prints the filesystem geometry as derived from the superblock.\n"
" The output has the same format as mkfs.xfs, xfs_info, and other utilities.\n"
"\n"
));
}
static int
info_f(
int argc,
char **argv)
{
struct xfs_fsop_geom geo;
libxfs_fs_geometry(mp, &geo, XFS_FS_GEOM_MAX_STRUCT_VER);
xfs_report_geom(&geo, x.data.name, x.log.name, x.rt.name);
return 0;
}
static const struct cmdinfo info_cmd = {
.name = "info",
.altname = "i",
.cfunc = info_f,
.argmin = 0,
.argmax = 0,
.canpush = 0,
.args = NULL,
.oneline = N_("pretty-print superblock info"),
.help = info_help,
};
static void
agresv_help(void)
{
dbprintf(_(
"\n"
" Print the size and per-AG reservation information some allocation groups.\n"
"\n"
" Specific allocation group numbers can be provided as command line arguments.\n"
" If no arguments are provided, all allocation groups are iterated.\n"
"\n"
));
}
static void
print_agresv_info(
struct xfs_perag *pag)
{
struct xfs_buf *bp;
struct xfs_agf *agf;
xfs_agnumber_t agno = pag_agno(pag);
xfs_extlen_t ask = 0;
xfs_extlen_t used = 0;
xfs_extlen_t free = 0;
xfs_extlen_t length = 0;
int error;
error = -libxfs_refcountbt_calc_reserves(mp, NULL, pag, &ask, &used);
if (error)
xfrog_perror(error, "refcountbt");
error = -libxfs_finobt_calc_reserves(pag, NULL, &ask, &used);
if (error)
xfrog_perror(error, "finobt");
error = -libxfs_rmapbt_calc_reserves(mp, NULL, pag, &ask, &used);
if (error)
xfrog_perror(error, "rmapbt");
error = -libxfs_read_agf(pag, NULL, 0, &bp);
if (error)
xfrog_perror(error, "AGF");
agf = bp->b_addr;
length = be32_to_cpu(agf->agf_length);
free = be32_to_cpu(agf->agf_freeblks) +
be32_to_cpu(agf->agf_flcount);
libxfs_buf_relse(bp);
printf("AG %d: length: %u free: %u reserved: %u used: %u",
agno, length, free, ask, used);
if (ask - used > free)
printf(" <not enough space>");
printf("\n");
}
static int
agresv_f(
int argc,
char **argv)
{
struct xfs_perag *pag = NULL;
int i;
if (argc > 1) {
for (i = 1; i < argc; i++) {
long a;
char *p;
errno = 0;
a = strtol(argv[i], &p, 0);
if (p == argv[i])
errno = ERANGE;
if (errno) {
perror(argv[i]);
continue;
}
if (a < 0 || a >= mp->m_sb.sb_agcount) {
fprintf(stderr, "%ld: Not a AG.\n", a);
continue;
}
pag = libxfs_perag_get(mp, a);
print_agresv_info(pag);
libxfs_perag_put(pag);
}
return 0;
}
while ((pag = xfs_perag_next(mp, pag)))
print_agresv_info(pag);
return 0;
}
static const struct cmdinfo agresv_cmd = {
.name = "agresv",
.altname = NULL,
.cfunc = agresv_f,
.argmin = 0,
.argmax = -1,
.canpush = 0,
.args = NULL,
.oneline = N_("print AG reservation stats"),
.help = agresv_help,
};
static void
rgresv_help(void)
{
dbprintf(_(
"\n"
" Print the size and per-rtgroup reservation information for some realtime allocation groups.\n"
"\n"
" Specific realtime allocation group numbers can be provided as command line\n"
" arguments. If no arguments are provided, all allocation groups are iterated.\n"
"\n"
));
}
static void
print_rgresv_info(
struct xfs_rtgroup *rtg)
{
struct xfs_trans *tp;
xfs_filblks_t ask = 0;
xfs_filblks_t used = 0;
int error;
error = -libxfs_trans_alloc_empty(mp, &tp);
if (error) {
dbprintf(
_("Cannot alloc transaction to look up rtgroup %u rmap inode\n"),
rtg_rgno(rtg));
return;
}
error = -libxfs_rtginode_load_parent(tp);
if (error) {
dbprintf(_("Cannot load realtime metadir, error %d\n"),
error);
goto out_trans;
}
/* rtrmapbt */
error = -libxfs_rtginode_load(rtg, XFS_RTGI_RMAP, tp);
if (error) {
dbprintf(_("Cannot load rtgroup %u rmap inode, error %d\n"),
rtg_rgno(rtg), error);
goto out_rele_dp;
}
if (rtg_rmap(rtg))
used += rtg_rmap(rtg)->i_nblocks;
libxfs_rtginode_irele(&rtg->rtg_inodes[XFS_RTGI_RMAP]);
ask += libxfs_rtrmapbt_calc_reserves(mp);
/* rtrefcount */
error = -libxfs_rtginode_load(rtg, XFS_RTGI_REFCOUNT, tp);
if (error) {
dbprintf(_("Cannot load rtgroup %u refcount inode, error %d\n"),
rtg_rgno(rtg), error);
goto out_rele_dp;
}
if (rtg_refcount(rtg))
used += rtg_refcount(rtg)->i_nblocks;
libxfs_rtginode_irele(&rtg->rtg_inodes[XFS_RTGI_REFCOUNT]);
ask += libxfs_rtrefcountbt_calc_reserves(mp);
printf(_("rtg %d: dblocks: %llu fdblocks: %llu reserved: %llu used: %llu"),
rtg_rgno(rtg),
(unsigned long long)mp->m_sb.sb_dblocks,
(unsigned long long)mp->m_sb.sb_fdblocks,
(unsigned long long)ask,
(unsigned long long)used);
if (ask - used > mp->m_sb.sb_fdblocks)
printf(_(" <not enough space>"));
printf("\n");
out_rele_dp:
libxfs_rtginode_irele(&mp->m_rtdirip);
out_trans:
libxfs_trans_cancel(tp);
}
static int
rgresv_f(
int argc,
char **argv)
{
struct xfs_rtgroup *rtg = NULL;
int i;
if (argc > 1) {
for (i = 1; i < argc; i++) {
long a;
char *p;
errno = 0;
a = strtol(argv[i], &p, 0);
if (p == argv[i])
errno = ERANGE;
if (errno) {
perror(argv[i]);
continue;
}
if (a < 0 || a >= mp->m_sb.sb_rgcount) {
fprintf(stderr, "%ld: Not a rtgroup.\n", a);
continue;
}
rtg = libxfs_rtgroup_get(mp, a);
print_rgresv_info(rtg);
libxfs_rtgroup_put(rtg);
}
return 0;
}
while ((rtg = xfs_rtgroup_next(mp, rtg)))
print_rgresv_info(rtg);
return 0;
}
static const struct cmdinfo rgresv_cmd = {
.name = "rgresv",
.altname = NULL,
.cfunc = rgresv_f,
.argmin = 0,
.argmax = -1,
.canpush = 0,
.args = NULL,
.oneline = N_("print rtgroup reservation stats"),
.help = rgresv_help,
};
void
info_init(void)
{
add_command(&info_cmd);
add_command(&agresv_cmd);
add_command(&rgresv_cmd);
}