* [PATCH 1/5] gfs2: handle errors from __filemap_get_folio() with FGP_CREAT in gfs2_getbuf()
2026-09-08 21:16 [PATCH 0/5] gfs2: handle errors from __filemap_get_folio() with FGP_CREAT in gfs2_getbuf() and its caller chain Mauricio Faria de Oliveira
@ 2026-09-08 21:16 ` Mauricio Faria de Oliveira
2026-09-08 21:16 ` [PATCH 2/5] gfs2: handle NULL return value in callers of gfs2_getbuf() with CREATE Mauricio Faria de Oliveira
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Mauricio Faria de Oliveira @ 2026-09-08 21:16 UTC (permalink / raw)
To: Andreas Gruenbacher
Cc: kernel-dev, gfs2, linux-kernel, Mauricio Faria de Oliveira
Function __filemap_get_folio() with FGP_CREAT might fail, for example, with
ERR_PTR(-ENOMEM). This hits a kernel oops, as gfs2_getbuf() dereferences an
error pointer:
gfs2: fsid=loop0: Trying to join cluster "lock_nolock", "loop0"
gfs2: fsid=loop0: Now mounting FS (format 1802)...
Oops: general protection fault, probably for non-canonical address
0xdffffc0000000003: 0000 [#1] SMP KASAN NOPTI
KASAN: null-ptr-deref in range [0x0000000000000018-0x000000000000001f]
...
RIP: 0010:gfs2_getbuf+0x492/0x5a0
[ ...
Call Trace:
<TASK>
gfs2_meta_read+0x106/0x7a0
gfs2_meta_buffer+0x125/0x360
inode_go_instantiate+0xde/0x1510
gfs2_instantiate+0x102/0x1c0
gfs2_glock_wait+0x19a/0x2c0
gfs2_lookupi+0x2ba/0x570
gfs2_lookup_meta+0xad/0x160
init_inodes+0x350/0x20b0
gfs2_fill_super+0x19b6/0x2730
get_tree_bdev_flags+0x2f4/0x560
gfs2_get_tree+0x48/0x230
vfs_get_tree+0x87/0x2d0
vfs_cmd_create+0xb2/0x240
__do_sys_fsconfig+0x3d2/0x980
do_syscall_64+0xce/0x450
entry_SYSCALL_64_after_hwframe+0x77/0x7f
...
</TASK>
That is noted more clearly in convenience function filemap_grab_folio()
(snippet below) and checked by virtually all other callers in the kernel.
...
* Return: A found or created folio. ERR_PTR(-ENOMEM) if no folio is found
* and failed to create a folio.
...
static inline struct folio *filemap_grab_folio(...)
{
return __filemap_get_folio(...,
... | FGP_CREAT,
...);
}
Thus, if __filemap_get_folio() returns an error, log it (as it's lost) and
return NULL. Callers will be handled.
Signed-off-by: Mauricio Faria de Oliveira <mfo@igalia.com>
---
fs/gfs2/meta_io.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c
index a87cfbf0df38706e6b7c63cc55f5251765d6b398..51b1a2e2bfadea6dabfac5ecba983c615a1a69fa 100644
--- a/fs/gfs2/meta_io.c
+++ b/fs/gfs2/meta_io.c
@@ -145,6 +145,10 @@ struct buffer_head *gfs2_getbuf(struct gfs2_glock *gl, u64 blkno, int create)
folio = __filemap_get_folio(mapping, index,
FGP_LOCK | FGP_ACCESSED | FGP_CREAT,
mapping_gfp_mask(mapping) | __GFP_NOFAIL);
+ if (IS_ERR(folio)) {
+ fs_err(sdp, "Error %ld creating buffer\n", PTR_ERR(folio));
+ return NULL;
+ }
bh = folio_buffers(folio);
if (!bh)
bh = create_empty_buffers(folio,
--
2.47.3
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH 2/5] gfs2: handle NULL return value in callers of gfs2_getbuf() with CREATE
2026-09-08 21:16 [PATCH 0/5] gfs2: handle errors from __filemap_get_folio() with FGP_CREAT in gfs2_getbuf() and its caller chain Mauricio Faria de Oliveira
2026-09-08 21:16 ` [PATCH 1/5] gfs2: handle errors from __filemap_get_folio() with FGP_CREAT in gfs2_getbuf() Mauricio Faria de Oliveira
@ 2026-09-08 21:16 ` Mauricio Faria de Oliveira
2026-09-08 21:16 ` [PATCH 3/5] gfs2: handle NULL return value in callers of gfs2_meta_new() Mauricio Faria de Oliveira
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Mauricio Faria de Oliveira @ 2026-09-08 21:16 UTC (permalink / raw)
To: Andreas Gruenbacher
Cc: kernel-dev, gfs2, linux-kernel, Mauricio Faria de Oliveira
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@igalia.com>
---
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
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH 3/5] gfs2: handle NULL return value in callers of gfs2_meta_new()
2026-09-08 21:16 [PATCH 0/5] gfs2: handle errors from __filemap_get_folio() with FGP_CREAT in gfs2_getbuf() and its caller chain Mauricio Faria de Oliveira
2026-09-08 21:16 ` [PATCH 1/5] gfs2: handle errors from __filemap_get_folio() with FGP_CREAT in gfs2_getbuf() Mauricio Faria de Oliveira
2026-09-08 21:16 ` [PATCH 2/5] gfs2: handle NULL return value in callers of gfs2_getbuf() with CREATE Mauricio Faria de Oliveira
@ 2026-09-08 21:16 ` Mauricio Faria de Oliveira
2026-09-08 21:16 ` [PATCH 4/5] gfs2: handle NULL return value in callers of gfs2_meta_ra() Mauricio Faria de Oliveira
2026-09-08 21:16 ` [PATCH 5/5] gfs2: check for errors from filemap_get_folio() in gfs2_jhead_process_page() Mauricio Faria de Oliveira
4 siblings, 0 replies; 6+ messages in thread
From: Mauricio Faria de Oliveira @ 2026-09-08 21:16 UTC (permalink / raw)
To: Andreas Gruenbacher
Cc: kernel-dev, gfs2, linux-kernel, Mauricio Faria de Oliveira
Now that gfs2_meta_new() can return NULL (instead of hit a kernel oops),
update its callers to handle it (and not hit another kernel oops).
If gfs2_meta_new() returns NULL:
- new_leaf()
It currently checks for NULL and returns -EIO.
- gfs2_indirect_init()
Return -EIO. The only caller is __gfs2_iomap_alloc() (same file), twice.
Fail as currently done in other cases.
- gfs2_dir_get_new_buffer()
Return -EIO. The only two callers already check for errors.
- gfs2_init_xattr()
- init_dinode()
Return -EIO. The only caller is gfs2_create_inode() (same file).
Fail as currently done in the preceding error case.
- buf_lo_scan_elements()
- data_buf_lo_scan_elements()
Return -EIO after releasing the just acquired bh_log buffer.
- ea_alloc_blk()
- ea_write()
- ea_set_block()
Return -EIO. The function can currently return errors.
Signed-off-by: Mauricio Faria de Oliveira <mfo@igalia.com>
---
fs/gfs2/bmap.c | 25 +++++++++++++++++--------
fs/gfs2/dir.c | 2 ++
fs/gfs2/inode.c | 20 +++++++++++++++-----
fs/gfs2/lops.c | 8 ++++++++
fs/gfs2/xattr.c | 6 ++++++
5 files changed, 48 insertions(+), 13 deletions(-)
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index a766b5816634d360a4bbae89f8bcdd284071864a..1c14313acea084584ae5de69a1107b45e470606a 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -608,9 +608,9 @@ static int gfs2_hole_size(struct inode *inode, sector_t lblock, u64 len,
return ret;
}
-static inline void gfs2_indirect_init(struct metapath *mp,
- struct gfs2_glock *gl, unsigned int i,
- unsigned offset, u64 bn)
+static inline int gfs2_indirect_init(struct metapath *mp,
+ struct gfs2_glock *gl, unsigned int i,
+ unsigned int offset, u64 bn)
{
__be64 *ptr = (__be64 *)(mp->mp_bh[i - 1]->b_data +
((i > 1) ? sizeof(struct gfs2_meta_header) :
@@ -618,11 +618,14 @@ static inline void gfs2_indirect_init(struct metapath *mp,
BUG_ON(i < 1);
BUG_ON(mp->mp_bh[i] != NULL);
mp->mp_bh[i] = gfs2_meta_new(gl, bn);
+ if (!mp->mp_bh[i])
+ return -EIO;
gfs2_trans_add_meta(gl, mp->mp_bh[i]);
gfs2_metatype_set(mp->mp_bh[i], GFS2_METATYPE_IN, GFS2_FORMAT_IN);
gfs2_buffer_clear_tail(mp->mp_bh[i], sizeof(struct gfs2_meta_header));
ptr += offset;
*ptr = cpu_to_be64(bn);
+ return 0;
}
enum alloc_state {
@@ -723,8 +726,11 @@ static int __gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap,
zero_bn = *ptr;
}
for (; i - 1 < mp->mp_fheight - ip->i_height && n > 0;
- i++, n--)
- gfs2_indirect_init(mp, ip->i_gl, i, 0, bn++);
+ i++, n--) {
+ ret = gfs2_indirect_init(mp, ip->i_gl, i, 0, bn++);
+ if (ret)
+ goto out;
+ }
if (i - 1 == mp->mp_fheight - ip->i_height) {
i--;
gfs2_buffer_copy_tail(mp->mp_bh[i],
@@ -751,9 +757,12 @@ static int __gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap,
case ALLOC_GROW_DEPTH:
if (i > 1 && i < mp->mp_fheight)
gfs2_trans_add_meta(ip->i_gl, mp->mp_bh[i-1]);
- for (; i < mp->mp_fheight && n > 0; i++, n--)
- gfs2_indirect_init(mp, ip->i_gl, i,
- mp->mp_list[i-1], bn++);
+ for (; i < mp->mp_fheight && n > 0; i++, n--) {
+ ret = gfs2_indirect_init(mp, ip->i_gl, i,
+ mp->mp_list[i-1], bn++);
+ if (ret)
+ goto out;
+ }
if (i == mp->mp_fheight)
state = ALLOC_DATA;
if (n == 0)
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index 0d92f6c33dcb85dfa2a4b07f9f09575834e75e01..d1dc1e94b6c432d2ede504b04cb71959285a945d 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -93,6 +93,8 @@ int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block,
struct buffer_head *bh;
bh = gfs2_meta_new(ip->i_gl, block);
+ if (!bh)
+ return -EIO;
gfs2_trans_add_meta(ip->i_gl, bh);
gfs2_metatype_set(bh, GFS2_METATYPE_JD, GFS2_FORMAT_JD);
gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header));
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index f361876c5583353a1196ed35be1c95af33a90c02..dda51390fee49b56279161fdd755b3c2b6e7eac6 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -544,13 +544,15 @@ static void gfs2_init_dir(struct buffer_head *dibh,
* take any ACLs, LSM xattrs, etc.
*/
-static void gfs2_init_xattr(struct gfs2_inode *ip)
+static int gfs2_init_xattr(struct gfs2_inode *ip)
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct buffer_head *bh;
struct gfs2_ea_header *ea;
bh = gfs2_meta_new(ip->i_gl, ip->i_eattr);
+ if (!bh)
+ return -EIO;
gfs2_trans_add_meta(ip->i_gl, bh);
gfs2_metatype_set(bh, GFS2_METATYPE_EA, GFS2_FORMAT_EA);
gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header));
@@ -561,6 +563,7 @@ static void gfs2_init_xattr(struct gfs2_inode *ip)
ea->ea_flags = GFS2_EAFLAG_LAST;
brelse(bh);
+ return 0;
}
/**
@@ -571,13 +574,15 @@ static void gfs2_init_xattr(struct gfs2_inode *ip)
*
*/
-static void init_dinode(struct gfs2_inode *dip, struct gfs2_inode *ip,
- const char *symname)
+static int init_dinode(struct gfs2_inode *dip, struct gfs2_inode *ip,
+ const char *symname)
{
struct gfs2_dinode *di;
struct buffer_head *dibh;
dibh = gfs2_meta_new(ip->i_gl, ip->i_no_addr);
+ if (!dibh)
+ return -EIO;
gfs2_trans_add_meta(ip->i_gl, dibh);
di = (struct gfs2_dinode *)dibh->b_data;
gfs2_dinode_out(ip, di);
@@ -602,6 +607,7 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_inode *ip,
set_buffer_uptodate(dibh);
brelse(dibh);
+ return 0;
}
/**
@@ -864,10 +870,14 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
goto fail_gunlock3;
if (blocks > 1) {
- gfs2_init_xattr(ip);
+ error = gfs2_init_xattr(ip);
+ if (error)
+ goto fail_gunlock3;
xattr_initialized = true;
}
- init_dinode(dip, ip, symname);
+ error = init_dinode(dip, ip, symname);
+ if (error)
+ goto fail_gunlock3;
gfs2_trans_end(sdp);
glock_set_object(ip->i_gl, ip);
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index 6dabe73ad790d9cbf6f2725dd3e5e1c40c3781b8..192e71e630dce062361cc754f2ba878fa23c0a7f 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -801,6 +801,10 @@ static int buf_lo_scan_elements(struct gfs2_jdesc *jd, u32 start,
return error;
bh_ip = gfs2_meta_new(gl, blkno);
+ if (!bh_ip) {
+ brelse(bh_log);
+ return -EIO;
+ }
memcpy(bh_ip->b_data, bh_log->b_data, bh_log->b_size);
if (gfs2_meta_check(sdp, bh_ip))
@@ -1026,6 +1030,10 @@ static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, u32 start,
return error;
bh_ip = gfs2_meta_new(gl, blkno);
+ if (!bh_ip) {
+ brelse(bh_log);
+ return -EIO;
+ }
memcpy(bh_ip->b_data, bh_log->b_data, bh_log->b_size);
/* Unescape */
diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c
index b9f48d6f10a97a36365a2fe636ceb1cd476e4318..5aec4d0f240dc5beef18bc5619faf6b375152c03 100644
--- a/fs/gfs2/xattr.c
+++ b/fs/gfs2/xattr.c
@@ -648,6 +648,8 @@ static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp)
return error;
gfs2_trans_remove_revoke(sdp, block, 1);
*bhp = gfs2_meta_new(ip->i_gl, block);
+ if (!*bhp)
+ return -EIO;
gfs2_trans_add_meta(ip->i_gl, *bhp);
gfs2_metatype_set(*bhp, GFS2_METATYPE_EA, GFS2_FORMAT_EA);
gfs2_buffer_clear_tail(*bhp, sizeof(struct gfs2_meta_header));
@@ -710,6 +712,8 @@ static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea,
return error;
gfs2_trans_remove_revoke(sdp, block, 1);
bh = gfs2_meta_new(ip->i_gl, block);
+ if (!bh)
+ return -EIO;
gfs2_trans_add_meta(ip->i_gl, bh);
gfs2_metatype_set(bh, GFS2_METATYPE_ED, GFS2_FORMAT_ED);
@@ -1011,6 +1015,8 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er,
return error;
gfs2_trans_remove_revoke(sdp, blk, 1);
indbh = gfs2_meta_new(ip->i_gl, blk);
+ if (!indbh)
+ return -EIO;
gfs2_trans_add_meta(ip->i_gl, indbh);
gfs2_metatype_set(indbh, GFS2_METATYPE_IN, GFS2_FORMAT_IN);
gfs2_buffer_clear_tail(indbh, mh_size);
--
2.47.3
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH 4/5] gfs2: handle NULL return value in callers of gfs2_meta_ra()
2026-09-08 21:16 [PATCH 0/5] gfs2: handle errors from __filemap_get_folio() with FGP_CREAT in gfs2_getbuf() and its caller chain Mauricio Faria de Oliveira
` (2 preceding siblings ...)
2026-09-08 21:16 ` [PATCH 3/5] gfs2: handle NULL return value in callers of gfs2_meta_new() Mauricio Faria de Oliveira
@ 2026-09-08 21:16 ` Mauricio Faria de Oliveira
2026-09-08 21:16 ` [PATCH 5/5] gfs2: check for errors from filemap_get_folio() in gfs2_jhead_process_page() Mauricio Faria de Oliveira
4 siblings, 0 replies; 6+ messages in thread
From: Mauricio Faria de Oliveira @ 2026-09-08 21:16 UTC (permalink / raw)
To: Andreas Gruenbacher
Cc: kernel-dev, gfs2, linux-kernel, Mauricio Faria de Oliveira
Now that gfs2_meta_ra() can return NULL (instead of hit a kernel oops),
update its callers to handle it (and not hit another kernel oops).
If gfs2_meta_ra() returns NULL:
- gfs2_quota_init()
It currently checks for NULL and returns -EIO.
- gfs2_dir_read_data()
Return -EIO. Fail as currently done in other cases.
- gfs2_replay_read_block()
Return -EIO. It can currently return errors.
Signed-off-by: Mauricio Faria de Oliveira <mfo@igalia.com>
---
fs/gfs2/dir.c | 4 ++++
fs/gfs2/recovery.c | 2 ++
2 files changed, 6 insertions(+)
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index d1dc1e94b6c432d2ede504b04cb71959285a945d..d9e0b6b19567c8aa8518b9245e9bdfd3ccf7c1a7 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -302,6 +302,10 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, __be64 *buf,
goto fail;
BUG_ON(extlen < 1);
bh = gfs2_meta_ra(ip->i_gl, dblock, extlen);
+ if (!bh) {
+ error = -EIO;
+ goto fail;
+ }
} else {
error = gfs2_meta_read(ip->i_gl, dblock, DIO_WAIT, 0, &bh);
if (error)
diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c
index 616c46aa3434ae6ad84d10d678ca3f6dbe9492f5..e39754e08f44d67b460a47744f4276cd168e356c 100644
--- a/fs/gfs2/recovery.c
+++ b/fs/gfs2/recovery.c
@@ -48,6 +48,8 @@ int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk,
}
*bh = gfs2_meta_ra(gl, dblock, extlen);
+ if (!*bh)
+ error = -EIO;
return error;
}
--
2.47.3
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH 5/5] gfs2: check for errors from filemap_get_folio() in gfs2_jhead_process_page()
2026-09-08 21:16 [PATCH 0/5] gfs2: handle errors from __filemap_get_folio() with FGP_CREAT in gfs2_getbuf() and its caller chain Mauricio Faria de Oliveira
` (3 preceding siblings ...)
2026-09-08 21:16 ` [PATCH 4/5] gfs2: handle NULL return value in callers of gfs2_meta_ra() Mauricio Faria de Oliveira
@ 2026-09-08 21:16 ` Mauricio Faria de Oliveira
4 siblings, 0 replies; 6+ messages in thread
From: Mauricio Faria de Oliveira @ 2026-09-08 21:16 UTC (permalink / raw)
To: Andreas Gruenbacher
Cc: kernel-dev, gfs2, linux-kernel, Mauricio Faria de Oliveira
Let's check for a not-found folio pointer error, that is, ERR_PTR(-ENOENT),
just in case, even though it is not expected (due to a previously acquired
reference on the folio, per the function comment).
If filemap_get_folio() returns an error, log it and return -EIO. The only
caller is gfs2_chain_bio() (same file), twice, which can currently return
errors, thus propagate the error.
Signed-off-by: Mauricio Faria de Oliveira <mfo@igalia.com>
---
fs/gfs2/lops.c | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index 192e71e630dce062361cc754f2ba878fa23c0a7f..78cadde990182223978ddbde2be25cfe963beabe 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -459,14 +459,21 @@ static bool gfs2_jhead_folio_search(struct gfs2_jdesc *jd,
* our references to the folio.
*/
-static void gfs2_jhead_process_page(struct gfs2_jdesc *jd, unsigned long index,
- struct gfs2_log_header_host *head,
- bool *done)
+static int gfs2_jhead_process_page(struct gfs2_jdesc *jd, unsigned long index,
+ struct gfs2_log_header_host *head,
+ bool *done)
{
+ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
struct folio *folio;
folio = filemap_get_folio(jd->jd_inode->i_mapping, index);
+ /* This should not happen (see comment above), but check just in case */
+ if (IS_ERR(folio)) {
+ fs_err(sdp, "Error %ld getting folio.\n", PTR_ERR(folio));
+ return -EIO;
+ }
+
folio_wait_locked(folio);
if (!folio_test_uptodate(folio))
*done = true;
@@ -476,6 +483,7 @@ static void gfs2_jhead_process_page(struct gfs2_jdesc *jd, unsigned long index,
/* filemap_get_folio() and the earlier filemap_grab_folio() */
folio_put_refs(folio, 2);
+ return 0;
}
static struct bio *gfs2_chain_bio(struct bio *prev, unsigned int nr_iovecs,
@@ -572,7 +580,9 @@ int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head)
continue;
}
- gfs2_jhead_process_page(jd, blocks_read >> shift, head, &done);
+ ret = gfs2_jhead_process_page(jd, blocks_read >> shift, head, &done);
+ if (ret)
+ goto error;
blocks_read += PAGE_SIZE >> bsize_shift;
if (done)
goto out; /* found */
@@ -583,7 +593,9 @@ int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head)
if (bio)
submit_bio(bio);
while (blocks_read < block) {
- gfs2_jhead_process_page(jd, blocks_read >> shift, head, &done);
+ ret = gfs2_jhead_process_page(jd, blocks_read >> shift, head, &done);
+ if (ret)
+ goto error;
blocks_read += PAGE_SIZE >> bsize_shift;
}
@@ -592,6 +604,7 @@ int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head)
truncate_inode_pages(mapping, 0);
+error:
return ret;
}
--
2.47.3
^ permalink raw reply [flat|nested] 6+ messages in thread