summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2026-06-17 07:58:04 +0200
committerCarlos Maiolino <cem@kernel.org>2026-06-29 09:37:06 +0200
commit0144bcf619602e82843a514431d3cf2cd13ec08a (patch)
tree18fc9ab7380287fbc5f199a75b987b590fd7a4fe
parent27d7d15184d701b6e4db2b7431e4cee67a041a1c (diff)
xfs: fix incorrect use of gfp flags in xfs_buf_alloc_backing_mem
xfs_buf_alloc_backing_mem currently has two issues with how the GFP_ flags are set: - when aiming for a large folio allocation, the gfp mask is adjusted to try less hard, but these flags then persist for the vmalloc allocation, which is bogus. - the __GFP_NOFAIL for small allocations is also applied when readahead force __GFP_NORETRY which doesn't make any sense. Fix this by only applying __GFP_NOFAIL when __GFP_NORETRY is not set, and by reordering the code so that the large folio gfp adjustments are performed locally just for that allocation. Fixes: 94c78cfa3bd1 ("xfs: convert buffer cache to use high order folios") Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com> Signed-off-by: Carlos Maiolino <cem@kernel.org>
-rw-r--r--fs/xfs/xfs_buf.c49
1 files changed, 23 insertions, 26 deletions
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
index 538ae441e212..4cf2a154dba8 100644
--- a/fs/xfs/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
@@ -224,22 +224,6 @@ xfs_buf_alloc_backing_mem(
gfp_mask |= __GFP_NORETRY;
/*
- * For buffers smaller than PAGE_SIZE use a kmalloc allocation if that
- * is properly aligned. The slab allocator now guarantees an aligned
- * allocation for all power of two sizes, which matches most of the
- * smaller than PAGE_SIZE buffers used by XFS.
- */
- if (size < PAGE_SIZE && is_power_of_2(size))
- return xfs_buf_alloc_kmem(bp, size, gfp_mask | __GFP_NOFAIL);
-
- /*
- * Don't bother with the retry loop for single PAGE allocations: vmalloc
- * won't do any better.
- */
- if (size <= PAGE_SIZE)
- gfp_mask |= __GFP_NOFAIL;
-
- /*
* Optimistically attempt a single high order folio allocation for
* larger than PAGE_SIZE buffers.
*
@@ -251,18 +235,31 @@ xfs_buf_alloc_backing_mem(
* path for them instead of wasting memory here.
*/
if (size > PAGE_SIZE) {
- if (!is_power_of_2(size))
- return xfs_buf_alloc_vmalloc(bp, size, gfp_mask, flags);
- gfp_mask &= ~__GFP_DIRECT_RECLAIM;
- gfp_mask |= __GFP_NORETRY;
- }
- if (xfs_buf_alloc_folio(bp, size, gfp_mask) < 0) {
- if (size <= PAGE_SIZE)
- return -ENOMEM;
- trace_xfs_buf_backing_fallback(bp, _RET_IP_);
+ if (is_power_of_2(size)) {
+ gfp_t folio_gfp = gfp_mask;
+
+ folio_gfp &= ~__GFP_DIRECT_RECLAIM;
+ folio_gfp |= __GFP_NORETRY;
+ if (xfs_buf_alloc_folio(bp, size, folio_gfp) == 0)
+ return 0;
+ trace_xfs_buf_backing_fallback(bp, _RET_IP_);
+ }
return xfs_buf_alloc_vmalloc(bp, size, gfp_mask, flags);
}
- return 0;
+
+ /*
+ * The slab allocator now guarantees aligned allocations for all power
+ * of two sizes. This covers most smaller XFS buffers, so just use
+ * kmalloc in this case.
+ *
+ * Don't bother with the vmalloc fallback for allocations of page size
+ * or less: vmalloc won't do any better.
+ */
+ if (!(gfp_mask & __GFP_NORETRY))
+ gfp_mask |= __GFP_NOFAIL;
+ if (size < PAGE_SIZE && is_power_of_2(size))
+ return xfs_buf_alloc_kmem(bp, size, gfp_mask);
+ return xfs_buf_alloc_folio(bp, size, gfp_mask);
}
static int