From: "Darrick J. Wong" <djwong@kernel.org>
To: Dave Chinner <david@fromorbit.com>, Eric Sandeen <sandeen@redhat.com>
Cc: xfs <linux-xfs@vger.kernel.org>,
shrikanth hegde <sshegde@linux.vnet.ibm.com>,
Ritesh Harjani <ritesh.list@gmail.com>
Subject: [PATCH 1/2] xfs_db: dump unlinked buckets
Date: Wed, 30 Aug 2023 16:25:09 -0700 [thread overview]
Message-ID: <20230830232509.GK28186@frogsfrogsfrogs> (raw)
In-Reply-To: <20230830152659.GJ28186@frogsfrogsfrogs>
From: Darrick J. Wong <djwong@kernel.org>
Create a new command to dump the resource usage of files in the unlinked
buckets.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
db/Makefile | 2
db/command.c | 1
db/command.h | 1
db/iunlink.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++
libxfs/libxfs_api_defs.h | 1
man/man8/xfs_db.8 | 19 ++++
6 files changed, 227 insertions(+), 1 deletion(-)
create mode 100644 db/iunlink.c
diff --git a/db/Makefile b/db/Makefile
index 2f95f670..d00801ab 100644
--- a/db/Makefile
+++ b/db/Makefile
@@ -14,7 +14,7 @@ HFILES = addr.h agf.h agfl.h agi.h attr.h attrshort.h bit.h block.h bmap.h \
io.h logformat.h malloc.h metadump.h output.h print.h quit.h sb.h \
sig.h strvec.h text.h type.h write.h attrset.h symlink.h fsmap.h \
fuzz.h obfuscate.h
-CFILES = $(HFILES:.h=.c) btdump.c btheight.c convert.c info.c namei.c \
+CFILES = $(HFILES:.h=.c) btdump.c btheight.c convert.c info.c iunlink.c namei.c \
timelimit.c
LSRCFILES = xfs_admin.sh xfs_ncheck.sh xfs_metadump.sh
diff --git a/db/command.c b/db/command.c
index 02f778b9..b4021c86 100644
--- a/db/command.c
+++ b/db/command.c
@@ -127,6 +127,7 @@ init_commands(void)
info_init();
inode_init();
input_init();
+ iunlink_init();
logres_init();
logformat_init();
io_init();
diff --git a/db/command.h b/db/command.h
index 498983ff..a89e7150 100644
--- a/db/command.h
+++ b/db/command.h
@@ -34,3 +34,4 @@ extern void info_init(void);
extern void btheight_init(void);
extern void timelimit_init(void);
extern void namei_init(void);
+extern void iunlink_init(void);
diff --git a/db/iunlink.c b/db/iunlink.c
new file mode 100644
index 00000000..303b5daf
--- /dev/null
+++ b/db/iunlink.c
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022-2023 Oracle. All Rights Reserved.
+ * Author: Darrick J. Wong <djwong@kernel.org>
+ */
+#include "libxfs.h"
+#include "command.h"
+#include "output.h"
+#include "init.h"
+
+static xfs_filblks_t
+count_rtblocks(
+ struct xfs_inode *ip)
+{
+ struct xfs_iext_cursor icur;
+ struct xfs_bmbt_irec got;
+ xfs_filblks_t count = 0;
+ struct xfs_ifork *ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK);
+ int error;
+
+ error = -libxfs_iread_extents(NULL, ip, XFS_DATA_FORK);
+ if (error) {
+ dbprintf(
+_("could not read AG %u agino %u extents, err=%d\n"),
+ XFS_INO_TO_AGNO(ip->i_mount, ip->i_ino),
+ XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino),
+ error);
+ return 0;
+ }
+
+ for_each_xfs_iext(ifp, &icur, &got)
+ if (!isnullstartblock(got.br_startblock))
+ count += got.br_blockcount;
+ return count;
+}
+
+static xfs_agino_t
+get_next_unlinked(
+ xfs_agnumber_t agno,
+ xfs_agino_t agino,
+ bool verbose)
+{
+ struct xfs_buf *ino_bp;
+ struct xfs_dinode *dip;
+ struct xfs_inode *ip;
+ xfs_ino_t ino;
+ xfs_agino_t ret;
+ int error;
+
+ ino = XFS_AGINO_TO_INO(mp, agno, agino);
+ error = -libxfs_iget(mp, NULL, ino, 0, &ip);
+ if (error)
+ goto bad;
+
+ if (verbose) {
+ xfs_filblks_t blocks, rtblks = 0;
+
+ if (XFS_IS_REALTIME_INODE(ip))
+ rtblks = count_rtblocks(ip);
+ blocks = ip->i_nblocks - rtblks;
+
+ dbprintf(_(" blocks %llu rtblocks %llu\n"),
+ blocks, rtblks);
+ } else {
+ dbprintf("\n");
+ }
+
+ error = -libxfs_imap_to_bp(mp, NULL, &ip->i_imap, &ino_bp);
+ if (error)
+ goto bad;
+
+ dip = xfs_buf_offset(ino_bp, ip->i_imap.im_boffset);
+ ret = be32_to_cpu(dip->di_next_unlinked);
+ libxfs_buf_relse(ino_bp);
+
+ return ret;
+bad:
+ dbprintf(_("AG %u agino %u: %s\n"), agno, agino, strerror(error));
+ return NULLAGINO;
+}
+
+static void
+dump_unlinked_bucket(
+ xfs_agnumber_t agno,
+ struct xfs_buf *agi_bp,
+ unsigned int bucket,
+ bool quiet,
+ bool verbose)
+{
+ struct xfs_agi *agi = agi_bp->b_addr;
+ xfs_agino_t agino;
+ unsigned int i = 0;
+
+ agino = be32_to_cpu(agi->agi_unlinked[bucket]);
+ if (agino != NULLAGINO)
+ dbprintf(_("AG %u bucket %u agino %u"), agno, bucket, agino);
+ else if (!quiet && agino == NULLAGINO)
+ dbprintf(_("AG %u bucket %u agino NULL\n"), agno, bucket);
+
+ while (agino != NULLAGINO) {
+ agino = get_next_unlinked(agno, agino, verbose);
+ if (agino != NULLAGINO)
+ dbprintf(_(" [%u] agino %u"), i++, agino);
+ else if (!quiet && agino == NULLAGINO)
+ dbprintf(_(" [%u] agino NULL\n"), i++);
+ }
+}
+
+static void
+dump_unlinked(
+ struct xfs_perag *pag,
+ unsigned int bucket,
+ bool quiet,
+ bool verbose)
+{
+ struct xfs_buf *agi_bp;
+ xfs_agnumber_t agno = pag->pag_agno;
+ int error;
+
+ error = -libxfs_ialloc_read_agi(pag, NULL, &agi_bp);
+ if (error) {
+ dbprintf(_("AGI %u: %s\n"), agno, strerror(errno));
+ return;
+ }
+
+ if (bucket != -1U) {
+ dump_unlinked_bucket(agno, agi_bp, bucket, quiet, verbose);
+ goto relse;
+ }
+
+ for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) {
+ dump_unlinked_bucket(agno, agi_bp, bucket, quiet, verbose);
+ }
+
+relse:
+ libxfs_buf_relse(agi_bp);
+}
+
+static int
+dump_iunlinked_f(
+ int argc,
+ char **argv)
+{
+ struct xfs_perag *pag;
+ xfs_agnumber_t agno = NULLAGNUMBER;
+ unsigned int bucket = -1U;
+ bool quiet = false;
+ bool verbose = false;
+ int c;
+
+ while ((c = getopt(argc, argv, "a:b:qv")) != EOF) {
+ switch (c) {
+ case 'a':
+ agno = atoi(optarg);
+ if (agno >= mp->m_sb.sb_agcount) {
+ dbprintf(_("Unknown AG %u, agcount is %u.\n"),
+ agno, mp->m_sb.sb_agcount);
+ return 0;
+ }
+ break;
+ case 'b':
+ bucket = atoi(optarg);
+ if (bucket >= XFS_AGI_UNLINKED_BUCKETS) {
+ dbprintf(_("Unknown bucket %u, max is 63.\n"),
+ bucket);
+ return 0;
+ }
+ break;
+ case 'q':
+ quiet = true;
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ default:
+ dbprintf(_("Bad option for dump_iunlinked command.\n"));
+ return 0;
+ }
+ }
+
+ if (agno != NULLAGNUMBER) {
+ struct xfs_perag *pag = libxfs_perag_get(mp, agno);
+
+ dump_unlinked(pag, bucket, quiet, verbose);
+ libxfs_perag_put(pag);
+ return 0;
+ }
+
+ for_each_perag(mp, agno, pag)
+ dump_unlinked(pag, bucket, quiet, verbose);
+
+ return 0;
+}
+
+static const cmdinfo_t dump_iunlinked_cmd =
+ { "dump_iunlinked", NULL, dump_iunlinked_f, 0, -1, 0,
+ N_("[-a agno] [-b bucket] [-q] [-v]"),
+ N_("dump chain of unlinked inode buckets"), NULL };
+
+void
+iunlink_init(void)
+{
+ add_command(&dump_iunlinked_cmd);
+}
diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
index 026aa510..ddba5c7c 100644
--- a/libxfs/libxfs_api_defs.h
+++ b/libxfs/libxfs_api_defs.h
@@ -125,6 +125,7 @@
#define xfs_idestroy_fork libxfs_idestroy_fork
#define xfs_iext_lookup_extent libxfs_iext_lookup_extent
#define xfs_ifork_zap_attr libxfs_ifork_zap_attr
+#define xfs_imap_to_bp libxfs_imap_to_bp
#define xfs_initialize_perag libxfs_initialize_perag
#define xfs_initialize_perag_data libxfs_initialize_perag_data
#define xfs_init_local_fork libxfs_init_local_fork
diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
index 60dcdc52..2d6d0da4 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -579,6 +579,25 @@ print the current debug option bits. These are for the use of the implementor.
.BI "dquot [" \-g | \-p | \-u ] " id"
Set current address to a group, project or user quota block for the given ID. Defaults to user quota.
.TP
+.BI "dump_iunlinked [-a " agno " ] [-b " bucket " ] [-q] [-v]"
+Dump the contents of unlinked buckets.
+
+Options include:
+.RS 1.0i
+.TP 0.4i
+.B \-a
+Print only this AG's unlinked buckets.
+.TP 0.4i
+.B \-b
+Print only this bucket within each AGI.
+.TP 0.4i
+.B \-q
+Only print the essentials.
+.TP 0.4i
+.B \-v
+Print resource usage of each file on the unlinked lists.
+.RE
+.TP
.BI "echo [" arg "] ..."
Echo the arguments to the output.
.TP
next prev parent reply other threads:[~2023-08-30 23:25 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-08-30 15:26 [PATCH v2] xfs: load uncached unlinked inodes into memory on demand Darrick J. Wong
2023-08-30 22:29 ` Dave Chinner
2023-08-30 23:25 ` Darrick J. Wong [this message]
2023-08-31 20:01 ` [PATCH 1/2] xfs_db: dump unlinked buckets Bill O'Donnell
2023-08-30 23:25 ` [PATCH 2/2] xfs_db: create unlinked inodes Darrick J. Wong
2023-08-31 20:02 ` Bill O'Donnell
2023-08-30 23:26 ` [RFC PATCH] fstests: test unlinked inode list repair on demand Darrick J. Wong
2023-08-31 12:39 ` [PATCH v2] xfs: load uncached unlinked inodes into memory " Ritesh Harjani
2023-08-31 20:39 ` Eric Sandeen
2023-08-31 22:44 ` Darrick J. Wong
2023-08-31 17:43 ` Eric Sandeen
2023-08-31 18:10 ` Bill O'Donnell
2023-08-31 20:18 ` Bill O'Donnell
2023-09-01 14:31 ` Bill O'Donnell
-- strict thread matches above, loose matches on Subject: below --
2023-09-25 21:59 [PATCHSET 0/2] xfsprogs: reload the last iunlink item Darrick J. Wong
2023-09-25 21:59 ` [PATCH 1/2] xfs_db: dump unlinked buckets Darrick J. Wong
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230830232509.GK28186@frogsfrogsfrogs \
--to=djwong@kernel.org \
--cc=david@fromorbit.com \
--cc=linux-xfs@vger.kernel.org \
--cc=ritesh.list@gmail.com \
--cc=sandeen@redhat.com \
--cc=sshegde@linux.vnet.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox