linux-xfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] xfs: support on by default errortags
@ 2025-06-11 18:23 Brian Foster
  2025-06-11 18:23 ` [PATCH 1/3] " Brian Foster
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Brian Foster @ 2025-06-11 18:23 UTC (permalink / raw)
  To: linux-xfs

Hi all,

This is a quick side quest based on the discussion on the iomap folio
batch series here[1]. I could see this going a number of different ways
and/or being enhanced in the future. For example, we could have per-tag
warning state instead of the global op state, dynamic default
configuration, put this behind a kconfig option, etc. My goal here is
really just to implement enough to keep things simple and pretty close
to existing XFS_DEBUG behavior.

Ultimately if people are Ok with something like this, I'll change the
force zero tag in the iomap series to on by default. If not, I'll just
leave it as is and go with a custom test. Otherwise, this survives a
first run through fstests without any explosions or spurious failures.

Thoughts, reviews, flames appreciated.

Brian

[1] https://lore.kernel.org/linux-fsdevel/20250605173357.579720-8-bfoster@redhat.com/

Brian Foster (3):
  xfs: support on by default errortags
  xfs: convert extent alloc debug fallback to errortag
  xfs: convert sparse inode alloc debug fallback to errortag

 fs/xfs/libxfs/xfs_alloc.c    |  5 +---
 fs/xfs/libxfs/xfs_errortag.h |  6 ++++-
 fs/xfs/libxfs/xfs_ialloc.c   | 14 ++++-------
 fs/xfs/xfs_error.c           | 48 ++++++++++++++++++++++++++++++++++--
 fs/xfs/xfs_mount.h           |  3 +++
 5 files changed, 60 insertions(+), 16 deletions(-)

-- 
2.49.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/3] xfs: support on by default errortags
  2025-06-11 18:23 [PATCH 0/3] xfs: support on by default errortags Brian Foster
@ 2025-06-11 18:23 ` Brian Foster
  2025-06-11 18:23 ` [PATCH 2/3] xfs: convert extent alloc debug fallback to errortag Brian Foster
  2025-06-11 18:23 ` [PATCH 3/3] xfs: convert sparse inode " Brian Foster
  2 siblings, 0 replies; 4+ messages in thread
From: Brian Foster @ 2025-06-11 18:23 UTC (permalink / raw)
  To: linux-xfs

XFS has a couple places where atypical behavior is randomized in
DEBUG mode in order to facilitate testing and code coverage. For
example, DEBUG kernels randomly drop into different block and inode
allocation algorithms that on production kernels may only occur
under certain circumstances.

These hooks are essentially hardcoded errortags. Rather than add
more of such logic for similar things in the future, introduce the
ability to define errortags that are on by default. Since errortags
are somewhat noisy, also introduce a quiet mode opstate flag to
suppress logging warnings for such tags. Quiet mode is enabled when
at least one tag is enabled by default at mount time and then
disabled upon the first errortag configuration change from
userspace.

This generally mimics current XFS_DEBUG behavior with the exception
that logging is enabled for all tags once any other tag is
configured. This can be enhanced to support per-tag log state in the
future if needed, but for now is probably unnecessary as only a
handful of default enabled tags are expected.

Signed-off-by: Brian Foster <bfoster@redhat.com>
---
 fs/xfs/xfs_error.c | 42 ++++++++++++++++++++++++++++++++++++++++--
 fs/xfs/xfs_mount.h |  3 +++
 2 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
index dbd87e137694..62ac6debcb5e 100644
--- a/fs/xfs/xfs_error.c
+++ b/fs/xfs/xfs_error.c
@@ -69,6 +69,7 @@ static unsigned int xfs_errortag_random_default[] = {
 struct xfs_errortag_attr {
 	struct attribute	attr;
 	unsigned int		tag;
+	bool			enable_default;
 };
 
 static inline struct xfs_errortag_attr *
@@ -129,12 +130,15 @@ static const struct sysfs_ops xfs_errortag_sysfs_ops = {
 	.store = xfs_errortag_attr_store,
 };
 
-#define XFS_ERRORTAG_ATTR_RW(_name, _tag) \
+#define __XFS_ERRORTAG_ATTR_RW(_name, _tag, enable) \
 static struct xfs_errortag_attr xfs_errortag_attr_##_name = {		\
 	.attr = {.name = __stringify(_name),				\
 		 .mode = VERIFY_OCTAL_PERMISSIONS(S_IWUSR | S_IRUGO) },	\
 	.tag	= (_tag),						\
+	.enable_default = enable,					\
 }
+#define XFS_ERRORTAG_ATTR_RW(_name, _tag) \
+	__XFS_ERRORTAG_ATTR_RW(_name, _tag, false)
 
 #define XFS_ERRORTAG_ATTR_LIST(_name) &xfs_errortag_attr_##_name.attr
 
@@ -240,6 +244,35 @@ static const struct kobj_type xfs_errortag_ktype = {
 	.default_groups = xfs_errortag_groups,
 };
 
+/*
+ * Enable tags that are defined to be on by default. This is typically limited
+ * to tags that don't necessarily inject errors, but rather modify control paths
+ * for improved code coverage testing on DEBUG kernels.
+ */
+static void
+xfs_errortag_enable_defaults(
+	struct xfs_mount	*mp)
+{
+	int i;
+
+	for (i = 0; xfs_errortag_attrs[i]; i++) {
+		struct xfs_errortag_attr *xfs_attr =
+				to_attr(xfs_errortag_attrs[i]);
+
+		if (!xfs_attr->enable_default)
+			continue;
+
+		/*
+		 * Suppress log noise unless userspace makes configuration
+		 * changes. Open code the assignment to avoid clearing the quiet
+		 * flag.
+		 */
+		xfs_set_quiet_errtag(mp);
+		mp->m_errortag[xfs_attr->tag] =
+			xfs_errortag_random_default[xfs_attr->tag];
+	}
+}
+
 int
 xfs_errortag_init(
 	struct xfs_mount	*mp)
@@ -251,6 +284,8 @@ xfs_errortag_init(
 	if (!mp->m_errortag)
 		return -ENOMEM;
 
+	xfs_errortag_enable_defaults(mp);
+
 	ret = xfs_sysfs_init(&mp->m_errortag_kobj, &xfs_errortag_ktype,
 				&mp->m_kobj, "errortag");
 	if (ret)
@@ -320,9 +355,11 @@ xfs_errortag_test(
 	if (!randfactor || get_random_u32_below(randfactor))
 		return false;
 
-	xfs_warn_ratelimited(mp,
+	if (!xfs_is_quiet_errtag(mp)) {
+		xfs_warn_ratelimited(mp,
 "Injecting error (%s) at file %s, line %d, on filesystem \"%s\"",
 			expression, file, line, mp->m_super->s_id);
+	}
 	return true;
 }
 
@@ -346,6 +383,7 @@ xfs_errortag_set(
 	if (!xfs_errortag_valid(error_tag))
 		return -EINVAL;
 
+	xfs_clear_quiet_errtag(mp);
 	mp->m_errortag[error_tag] = tag_value;
 	return 0;
 }
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index d85084f9f317..44b02728056f 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -558,6 +558,8 @@ __XFS_HAS_FEAT(nouuid, NOUUID)
  */
 #define XFS_OPSTATE_BLOCKGC_ENABLED	6
 
+/* Debug kernel skips warning on errtag event triggers */
+#define XFS_OPSTATE_QUIET_ERRTAG	7
 /* Kernel has logged a warning about shrink being used on this fs. */
 #define XFS_OPSTATE_WARNED_SHRINK	9
 /* Kernel has logged a warning about logged xattr updates being used. */
@@ -600,6 +602,7 @@ __XFS_IS_OPSTATE(inode32, INODE32)
 __XFS_IS_OPSTATE(readonly, READONLY)
 __XFS_IS_OPSTATE(inodegc_enabled, INODEGC_ENABLED)
 __XFS_IS_OPSTATE(blockgc_enabled, BLOCKGC_ENABLED)
+__XFS_IS_OPSTATE(quiet_errtag, QUIET_ERRTAG)
 #ifdef CONFIG_XFS_QUOTA
 __XFS_IS_OPSTATE(quotacheck_running, QUOTACHECK_RUNNING)
 __XFS_IS_OPSTATE(resuming_quotaon, RESUMING_QUOTAON)
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/3] xfs: convert extent alloc debug fallback to errortag
  2025-06-11 18:23 [PATCH 0/3] xfs: support on by default errortags Brian Foster
  2025-06-11 18:23 ` [PATCH 1/3] " Brian Foster
@ 2025-06-11 18:23 ` Brian Foster
  2025-06-11 18:23 ` [PATCH 3/3] xfs: convert sparse inode " Brian Foster
  2 siblings, 0 replies; 4+ messages in thread
From: Brian Foster @ 2025-06-11 18:23 UTC (permalink / raw)
  To: linux-xfs

Extent allocation includes multiple algorithms depending on on-disk
state to maintain performance and efficiency. The likely first
candidate is to simply use the rightmost block in the cntbt if
that's where initial lookup landed.

Since this is a common path for larger allocations on freshly
created filesystems, we include some DEBUG mode logic to randomly
fall out of the this algorithm and exercise fallback behavior. Now
that errortags can be enabled by default, convert this logic to an
errortag and drop the unnecessary DEBUG ifdef.

Signed-off-by: Brian Foster <bfoster@redhat.com>
---
 fs/xfs/libxfs/xfs_alloc.c    | 5 +----
 fs/xfs/libxfs/xfs_errortag.h | 4 +++-
 fs/xfs/xfs_error.c           | 3 +++
 3 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
index 7839efe050bf..129c9f690afc 100644
--- a/fs/xfs/libxfs/xfs_alloc.c
+++ b/fs/xfs/libxfs/xfs_alloc.c
@@ -1615,11 +1615,8 @@ xfs_alloc_ag_vextent_lastblock(
 	int			error;
 	int			i;
 
-#ifdef DEBUG
-	/* Randomly don't execute the first algorithm. */
-	if (get_random_u32_below(2))
+	if (XFS_TEST_ERROR(false, args->mp, XFS_ERRTAG_AG_ALLOC_SKIP))
 		return 0;
-#endif
 
 	/*
 	 * Start from the entry that lookup found, sequence through all larger
diff --git a/fs/xfs/libxfs/xfs_errortag.h b/fs/xfs/libxfs/xfs_errortag.h
index a53c5d40e084..c57d26619817 100644
--- a/fs/xfs/libxfs/xfs_errortag.h
+++ b/fs/xfs/libxfs/xfs_errortag.h
@@ -65,7 +65,8 @@
 #define XFS_ERRTAG_WRITE_DELAY_MS			43
 #define XFS_ERRTAG_EXCHMAPS_FINISH_ONE			44
 #define XFS_ERRTAG_METAFILE_RESV_CRITICAL		45
-#define XFS_ERRTAG_MAX					46
+#define XFS_ERRTAG_AG_ALLOC_SKIP			46
+#define XFS_ERRTAG_MAX					47
 
 /*
  * Random factors for above tags, 1 means always, 2 means 1/2 time, etc.
@@ -115,5 +116,6 @@
 #define XFS_RANDOM_WRITE_DELAY_MS			3000
 #define XFS_RANDOM_EXCHMAPS_FINISH_ONE			1
 #define XFS_RANDOM_METAFILE_RESV_CRITICAL		4
+#define XFS_RANDOM_AG_ALLOC_SKIP			2
 
 #endif /* __XFS_ERRORTAG_H_ */
diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
index 62ac6debcb5e..f1222e4e8c5f 100644
--- a/fs/xfs/xfs_error.c
+++ b/fs/xfs/xfs_error.c
@@ -64,6 +64,7 @@ static unsigned int xfs_errortag_random_default[] = {
 	XFS_RANDOM_WRITE_DELAY_MS,
 	XFS_RANDOM_EXCHMAPS_FINISH_ONE,
 	XFS_RANDOM_METAFILE_RESV_CRITICAL,
+	XFS_RANDOM_AG_ALLOC_SKIP,
 };
 
 struct xfs_errortag_attr {
@@ -187,6 +188,7 @@ XFS_ERRORTAG_ATTR_RW(wb_delay_ms,	XFS_ERRTAG_WB_DELAY_MS);
 XFS_ERRORTAG_ATTR_RW(write_delay_ms,	XFS_ERRTAG_WRITE_DELAY_MS);
 XFS_ERRORTAG_ATTR_RW(exchmaps_finish_one, XFS_ERRTAG_EXCHMAPS_FINISH_ONE);
 XFS_ERRORTAG_ATTR_RW(metafile_resv_crit, XFS_ERRTAG_METAFILE_RESV_CRITICAL);
+__XFS_ERRORTAG_ATTR_RW(ag_alloc_skip,	XFS_ERRTAG_AG_ALLOC_SKIP,	true);
 
 static struct attribute *xfs_errortag_attrs[] = {
 	XFS_ERRORTAG_ATTR_LIST(noerror),
@@ -234,6 +236,7 @@ static struct attribute *xfs_errortag_attrs[] = {
 	XFS_ERRORTAG_ATTR_LIST(write_delay_ms),
 	XFS_ERRORTAG_ATTR_LIST(exchmaps_finish_one),
 	XFS_ERRORTAG_ATTR_LIST(metafile_resv_crit),
+	XFS_ERRORTAG_ATTR_LIST(ag_alloc_skip),
 	NULL,
 };
 ATTRIBUTE_GROUPS(xfs_errortag);
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 3/3] xfs: convert sparse inode alloc debug fallback to errortag
  2025-06-11 18:23 [PATCH 0/3] xfs: support on by default errortags Brian Foster
  2025-06-11 18:23 ` [PATCH 1/3] " Brian Foster
  2025-06-11 18:23 ` [PATCH 2/3] xfs: convert extent alloc debug fallback to errortag Brian Foster
@ 2025-06-11 18:23 ` Brian Foster
  2 siblings, 0 replies; 4+ messages in thread
From: Brian Foster @ 2025-06-11 18:23 UTC (permalink / raw)
  To: linux-xfs

XFS includes DEBUG logic to randomly fall into sparse inode chunk
allocation. This is to facilitate code coverage testing as sparse
allocation is really only required once an AG has insufficiently
large free extents to allocate a full inode chunk.

Similar to for the extent allocation path, convert this into an
errortag that is enabled by default to maintain current DEBUG mode
behavior.

Signed-off-by: Brian Foster <bfoster@redhat.com>
---
 fs/xfs/libxfs/xfs_errortag.h |  4 +++-
 fs/xfs/libxfs/xfs_ialloc.c   | 14 +++++---------
 fs/xfs/xfs_error.c           |  3 +++
 3 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_errortag.h b/fs/xfs/libxfs/xfs_errortag.h
index c57d26619817..3a1404a24584 100644
--- a/fs/xfs/libxfs/xfs_errortag.h
+++ b/fs/xfs/libxfs/xfs_errortag.h
@@ -66,7 +66,8 @@
 #define XFS_ERRTAG_EXCHMAPS_FINISH_ONE			44
 #define XFS_ERRTAG_METAFILE_RESV_CRITICAL		45
 #define XFS_ERRTAG_AG_ALLOC_SKIP			46
-#define XFS_ERRTAG_MAX					47
+#define XFS_ERRTAG_SPARSE_IALLOC			47
+#define XFS_ERRTAG_MAX					48
 
 /*
  * Random factors for above tags, 1 means always, 2 means 1/2 time, etc.
@@ -117,5 +118,6 @@
 #define XFS_RANDOM_EXCHMAPS_FINISH_ONE			1
 #define XFS_RANDOM_METAFILE_RESV_CRITICAL		4
 #define XFS_RANDOM_AG_ALLOC_SKIP			2
+#define XFS_RANDOM_SPARSE_IALLOC			2
 
 #endif /* __XFS_ERRORTAG_H_ */
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index 0c47b5c6ca7d..9901e09e7a5d 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -707,7 +707,6 @@ xfs_ialloc_ag_alloc(
 	struct xfs_inobt_rec_incore rec;
 	struct xfs_ino_geometry	*igeo = M_IGEO(tp->t_mountp);
 	uint16_t		allocmask = (uint16_t) -1;
-	int			do_sparse = 0;
 
 	memset(&args, 0, sizeof(args));
 	args.tp = tp;
@@ -716,13 +715,6 @@ xfs_ialloc_ag_alloc(
 	args.oinfo = XFS_RMAP_OINFO_INODES;
 	args.pag = pag;
 
-#ifdef DEBUG
-	/* randomly do sparse inode allocations */
-	if (xfs_has_sparseinodes(tp->t_mountp) &&
-	    igeo->ialloc_min_blks < igeo->ialloc_blks)
-		do_sparse = get_random_u32_below(2);
-#endif
-
 	/*
 	 * Locking will ensure that we don't have two callers in here
 	 * at one time.
@@ -742,8 +734,12 @@ xfs_ialloc_ag_alloc(
 	newino = be32_to_cpu(agi->agi_newino);
 	args.agbno = XFS_AGINO_TO_AGBNO(args.mp, newino) +
 		     igeo->ialloc_blks;
-	if (do_sparse)
+
+	if (xfs_has_sparseinodes(args.mp) &&
+	    igeo->ialloc_min_blks < igeo->ialloc_blks &&
+	    XFS_TEST_ERROR(false, args.mp, XFS_ERRTAG_SPARSE_IALLOC))
 		goto sparse_alloc;
+
 	if (likely(newino != NULLAGINO &&
 		  (args.agbno < be32_to_cpu(agi->agi_length)))) {
 		args.prod = 1;
diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
index f1222e4e8c5f..480fabfadf39 100644
--- a/fs/xfs/xfs_error.c
+++ b/fs/xfs/xfs_error.c
@@ -65,6 +65,7 @@ static unsigned int xfs_errortag_random_default[] = {
 	XFS_RANDOM_EXCHMAPS_FINISH_ONE,
 	XFS_RANDOM_METAFILE_RESV_CRITICAL,
 	XFS_RANDOM_AG_ALLOC_SKIP,
+	XFS_RANDOM_SPARSE_IALLOC,
 };
 
 struct xfs_errortag_attr {
@@ -189,6 +190,7 @@ XFS_ERRORTAG_ATTR_RW(write_delay_ms,	XFS_ERRTAG_WRITE_DELAY_MS);
 XFS_ERRORTAG_ATTR_RW(exchmaps_finish_one, XFS_ERRTAG_EXCHMAPS_FINISH_ONE);
 XFS_ERRORTAG_ATTR_RW(metafile_resv_crit, XFS_ERRTAG_METAFILE_RESV_CRITICAL);
 __XFS_ERRORTAG_ATTR_RW(ag_alloc_skip,	XFS_ERRTAG_AG_ALLOC_SKIP,	true);
+__XFS_ERRORTAG_ATTR_RW(sparse_ialloc,	XFS_ERRTAG_SPARSE_IALLOC,	true);
 
 static struct attribute *xfs_errortag_attrs[] = {
 	XFS_ERRORTAG_ATTR_LIST(noerror),
@@ -237,6 +239,7 @@ static struct attribute *xfs_errortag_attrs[] = {
 	XFS_ERRORTAG_ATTR_LIST(exchmaps_finish_one),
 	XFS_ERRORTAG_ATTR_LIST(metafile_resv_crit),
 	XFS_ERRORTAG_ATTR_LIST(ag_alloc_skip),
+	XFS_ERRORTAG_ATTR_LIST(sparse_ialloc),
 	NULL,
 };
 ATTRIBUTE_GROUPS(xfs_errortag);
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2025-06-11 18:19 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-11 18:23 [PATCH 0/3] xfs: support on by default errortags Brian Foster
2025-06-11 18:23 ` [PATCH 1/3] " Brian Foster
2025-06-11 18:23 ` [PATCH 2/3] xfs: convert extent alloc debug fallback to errortag Brian Foster
2025-06-11 18:23 ` [PATCH 3/3] xfs: convert sparse inode " Brian Foster

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).