]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
xfs: error tag to force zeroing on debug kernels
authorBrian Foster <bfoster@redhat.com>
Fri, 3 Oct 2025 13:46:41 +0000 (09:46 -0400)
committerChristian Brauner <brauner@kernel.org>
Wed, 5 Nov 2025 11:57:25 +0000 (12:57 +0100)
iomap_zero_range() has to cover various corner cases that are
difficult to test on production kernels because it is used in fairly
limited use cases. For example, it is currently only used by XFS and
mostly only in partial block zeroing cases.

While it's possible to test most of these functional cases, we can
provide more robust test coverage by co-opting fallocate zero range
to invoke zeroing of the entire range instead of the more efficient
block punch/allocate sequence. Add an errortag to occasionally
invoke forced zeroing.

Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/xfs/libxfs/xfs_errortag.h
fs/xfs/xfs_file.c

index de840abc0bcd44e3e921fc335804020cc21b251c..57e47077c75a2a00b6fc55c069b0691d8b0a7371 100644 (file)
@@ -73,7 +73,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_FORCE_ZERO_RANGE                    46
+#define XFS_ERRTAG_MAX                                 47
 
 /*
  * Random factors for above tags, 1 means always, 2 means 1/2 time, etc.
@@ -133,7 +134,8 @@ XFS_ERRTAG(ATTR_LEAF_TO_NODE,       attr_leaf_to_node,      1) \
 XFS_ERRTAG(WB_DELAY_MS,                wb_delay_ms,            3000) \
 XFS_ERRTAG(WRITE_DELAY_MS,     write_delay_ms,         3000) \
 XFS_ERRTAG(EXCHMAPS_FINISH_ONE,        exchmaps_finish_one,    1) \
-XFS_ERRTAG(METAFILE_RESV_CRITICAL, metafile_resv_crit, 4)
+XFS_ERRTAG(METAFILE_RESV_CRITICAL, metafile_resv_crit, 4) \
+XFS_ERRTAG(FORCE_ZERO_RANGE,   force_zero_range,       4)
 #endif /* XFS_ERRTAG */
 
 #endif /* __XFS_ERRORTAG_H_ */
index 2702fef2c90cd28e2af2a69cf5485ca773195196..5b9864c8582e5314abbaf9573547d7abd358ecae 100644 (file)
@@ -27,6 +27,8 @@
 #include "xfs_file.h"
 #include "xfs_aops.h"
 #include "xfs_zone_alloc.h"
+#include "xfs_error.h"
+#include "xfs_errortag.h"
 
 #include <linux/dax.h>
 #include <linux/falloc.h>
@@ -1254,23 +1256,36 @@ xfs_falloc_zero_range(
        struct xfs_zone_alloc_ctx *ac)
 {
        struct inode            *inode = file_inode(file);
+       struct xfs_inode        *ip = XFS_I(inode);
        unsigned int            blksize = i_blocksize(inode);
        loff_t                  new_size = 0;
        int                     error;
 
-       trace_xfs_zero_file_space(XFS_I(inode));
+       trace_xfs_zero_file_space(ip);
 
        error = xfs_falloc_newsize(file, mode, offset, len, &new_size);
        if (error)
                return error;
 
-       error = xfs_free_file_space(XFS_I(inode), offset, len, ac);
-       if (error)
-               return error;
+       /*
+        * Zero range implements a full zeroing mechanism but is only used in
+        * limited situations. It is more efficient to allocate unwritten
+        * extents than to perform zeroing here, so use an errortag to randomly
+        * force zeroing on DEBUG kernels for added test coverage.
+        */
+       if (XFS_TEST_ERROR(ip->i_mount,
+                          XFS_ERRTAG_FORCE_ZERO_RANGE)) {
+               error = xfs_zero_range(ip, offset, len, ac, NULL);
+       } else {
+               error = xfs_free_file_space(ip, offset, len, ac);
+               if (error)
+                       return error;
 
-       len = round_up(offset + len, blksize) - round_down(offset, blksize);
-       offset = round_down(offset, blksize);
-       error = xfs_alloc_file_space(XFS_I(inode), offset, len);
+               len = round_up(offset + len, blksize) -
+                       round_down(offset, blksize);
+               offset = round_down(offset, blksize);
+               error = xfs_alloc_file_space(ip, offset, len);
+       }
        if (error)
                return error;
        return xfs_falloc_setsize(file, new_size);