[PATCH 5/8] xfs_db: dump per-AG reservations

Darrick J. Wong
2020-01-24T00:17:12Z

From: Darrick J. Wong <darrick.wong@oracle.com>

Add a new 'agresv' command to print the size and free blocks count of an
AG along with the size and usage of the per-AG reservation. This
command can be used to aid in diagnosing why a particular filesystem
fails the mount time per-AG space reservation, and to figure out how
much space needs to be freed from a given AG to fix the problem.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
db/info.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++
libxfs/libxfs_api_defs.h | 5 ++
man/man8/xfs_db.8 | 5 ++
3 files changed, 114 insertions(+)

diff --git a/db/info.c b/db/info.c
index e5f1c2dd..fc5ccfe7 100644
--- a/db/info.c
+++ b/db/info.c
@@ -8,6 +8,7 @@
#include "init.h"
#include "output.h"
#include "libfrog/fsgeom.h"
+#include "libfrog/logging.h"

static void
info_help(void)
@@ -45,8 +46,111 @@ static const struct cmdinfo info_cmd = {
.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(
+ xfs_agnumber_t agno)
+{
+ struct xfs_buf *bp;
+ struct xfs_agf *agf;
+ 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, agno, &ask, &used);
+ if (error)
+ xfrog_perror(error, "refcountbt");
+ error = -libxfs_finobt_calc_reserves(mp, NULL, agno, &ask, &used);
+ if (error)
+ xfrog_perror(error, "finobt");
+ error = -libxfs_rmapbt_calc_reserves(mp, NULL, agno, &ask, &used);
+ if (error)
+ xfrog_perror(error, "rmapbt");
+
+ error = -libxfs_read_agf(mp, NULL, agno, 0, &bp);
+ if (error)
+ xfrog_perror(error, "AGF");
+ agf = XFS_BUF_TO_AGF(bp);
+ length = be32_to_cpu(agf->agf_length);
+ free = be32_to_cpu(agf->agf_freeblks) +
+ be32_to_cpu(agf->agf_flcount);
+ libxfs_putbuf(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)
+{
+ xfs_agnumber_t agno;
+ 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;
+ }
+
+ print_agresv_info(a);
+ }
+ return 0;
+ }
+
+ for (agno = 0; agno < mp->m_sb.sb_agcount; agno++)
+ print_agresv_info(agno);
+
+ 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,
+};
+
void
info_init(void)
{
add_command(&info_cmd);
+ add_command(&agresv_cmd);
}
diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
index eed63ace..cc7304ad 100644
--- a/libxfs/libxfs_api_defs.h
+++ b/libxfs/libxfs_api_defs.h
@@ -173,4 +173,9 @@
#define xfs_ag_init_headers libxfs_ag_init_headers
#define xfs_buf_delwri_submit libxfs_buf_delwri_submit

+#define xfs_refcountbt_calc_reserves libxfs_refcountbt_calc_reserves
+#define xfs_finobt_calc_reserves libxfs_finobt_calc_reserves
+#define xfs_rmapbt_calc_reserves libxfs_rmapbt_calc_reserves
+#define xfs_read_agf libxfs_read_agf
+
#endif /* __LIBXFS_API_DEFS_H__ */
diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
index 9f1ff761..7f73d458 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -179,6 +179,11 @@ Set current address to the AGI block for allocation group
.IR agno .
If no argument is given, use the current allocation group.
.TP
+.BI "agresv [" agno ]
+Displays the length, free block count, per-AG reservation size, and per-AG
+reservation usage for a given AG.
+If no argument is given, display information for all AGs.
+.TP
.BI "attr_remove [\-r|\-u|\-s] [\-n] " name
Remove the specified extended attribute from the current file.
.RS 1.0i