diff options
| author | Christoph Hellwig <hch@lst.de> | 2026-06-17 07:58:04 +0200 |
|---|---|---|
| committer | Carlos Maiolino <cem@kernel.org> | 2026-06-29 09:37:06 +0200 |
| commit | 0144bcf619602e82843a514431d3cf2cd13ec08a (patch) | |
| tree | 18fc9ab7380287fbc5f199a75b987b590fd7a4fe | |
| parent | 27d7d15184d701b6e4db2b7431e4cee67a041a1c (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.c | 49 |
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 |
