[PATCH 2/5] gfs2: handle NULL return value in callers of gfs2_getbuf() with CREATE

From: Mauricio Faria de Oliveira

Date: Tue Sep 08 2026 - 17:23:02 EST


Now that gfs2_getbuf() with CREATE can return NULL (instead of hit a kernel
oops), update its callers to handle it (and not hit another kernel oops).

If gfs2_getbuf() returns NULL:

- gfs2_metapath_ra()
- gfs2_dir_readahead()

Skip the rest of the loop. This should be OK as it's currently done if
!trylock_buffer() or buffer_uptodate(), anyway.
We can skip put_bh() as gfs2_getbuf() doesn't do get_bh() in this case.

- gfs2_meta_new()

Propagate NULL. Callers will be handled.

- gfs2_meta_read()

For either a block or read-ahead, fail as currently done by other cases.
(Factor out the error path used multiple times now.)

- gfs2_meta_ra()

- For the first buffer:

Popagate NULL. Callers will be handled.

- For remaining buffers:

Skip the rest of the loop. This should be OK as the condition to exit
the loop is based on the first buffer (not remaining buffers), anyway.

Signed-off-by: Mauricio Faria de Oliveira <mfo@xxxxxxxxxx>
---
fs/gfs2/bmap.c | 2 ++
fs/gfs2/dir.c | 2 ++
fs/gfs2/meta_io.c | 26 +++++++++++++++++++-------
3 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 73c62697116390f0f5f09f0b8fd267cc0790e953..a766b5816634d360a4bbae89f8bcdd284071864a 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -302,6 +302,8 @@ static void gfs2_metapath_ra(struct gfs2_glock *gl, __be64 *start, __be64 *end)
continue;

rabh = gfs2_getbuf(gl, be64_to_cpu(*t), CREATE);
+ if (!rabh)
+ continue;
if (trylock_buffer(rabh)) {
if (!buffer_uptodate(rabh)) {
bh_submit(rabh,
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index 0237b36b9eb16562ab3a3415b53547c43ab26f52..0d92f6c33dcb85dfa2a4b07f9f09575834e75e01 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -1502,6 +1502,8 @@ static void gfs2_dir_readahead(struct inode *inode, unsigned hsize, u32 index,
continue;

bh = gfs2_getbuf(gl, blocknr, 1);
+ if (!bh)
+ continue;
if (trylock_buffer(bh)) {
if (buffer_uptodate(bh)) {
unlock_buffer(bh);
diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c
index 51b1a2e2bfadea6dabfac5ecba983c615a1a69fa..daa38fc7c825cdb70349caa7b55ef333b10af7c2 100644
--- a/fs/gfs2/meta_io.c
+++ b/fs/gfs2/meta_io.c
@@ -199,6 +199,8 @@ struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno)
{
struct buffer_head *bh;
bh = gfs2_getbuf(gl, blkno, CREATE);
+ if (!bh)
+ return NULL;
meta_prep_new(bh);
return bh;
}
@@ -268,12 +270,13 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
struct buffer_head *bh, *bhs[2];
int num = 0;

- if (gfs2_withdrawn(sdp)) {
- *bhp = NULL;
- return -EIO;
- }
+ if (gfs2_withdrawn(sdp))
+ goto error;

- *bhp = bh = gfs2_getbuf(gl, blkno, CREATE);
+ bh = gfs2_getbuf(gl, blkno, CREATE);
+ if (!bh)
+ goto error;
+ *bhp = bh;

lock_buffer(bh);
if (buffer_uptodate(bh)) {
@@ -286,6 +289,8 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,

if (rahead) {
bh = gfs2_getbuf(gl, blkno + 1, CREATE);
+ if (!bh)
+ goto error;

lock_buffer(bh);
if (buffer_uptodate(bh)) {
@@ -307,11 +312,14 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
if (tr && test_bit(TR_TOUCHED, &tr->tr_flags))
gfs2_io_error_bh(sdp, bh);
brelse(bh);
- *bhp = NULL;
- return -EIO;
+ goto error;
}

return 0;
+
+error:
+ *bhp = NULL;
+ return -EIO;
}

/**
@@ -494,6 +502,8 @@ struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen)
extlen = max_ra;

first_bh = gfs2_getbuf(gl, dblock, CREATE);
+ if (!first_bh)
+ return NULL;

if (buffer_uptodate(first_bh))
goto out;
@@ -504,6 +514,8 @@ struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen)

while (extlen) {
bh = gfs2_getbuf(gl, dblock, CREATE);
+ if (!bh)
+ continue;

bh_readahead(bh, REQ_RAHEAD | REQ_META | REQ_PRIO);
brelse(bh);

--
2.47.3