From b24e433e5aff210abeb04675a5c47b5154fc6dda Mon Sep 17 00:00:00 2001 From: Dianjin Wang Date: Thu, 3 Sep 2026 15:56:04 +0800 Subject: [PATCH] Fix smgr_hook bypass in zeroextend and release smgrrelease() and smgrzeroextend() dispatch through smgrsw[reln->smgr_which] instead of reln->smgr, so an f_smgr installed by smgr_hook is silently bypassed. Both arrived with the REL_16_9 merge in upstream form; every other entry point in smgr.c already goes through reln->smgr. smgrrelease() is harmless for the in-tree managers. smgrzeroextend() is not: it is the bulk-extension path from ExtendBufferedRelShared(), and reaching mdzeroextend() unhooked makes register_dirty_segment() tag the checkpointer fsync request with the un-redirected path. That file never exists, so the next checkpoint PANICs with "could not fsync file ...: No such file or directory" and the segment enters a crash/restart loop. Nothing changes when no hook is installed, since smgropen() sets reln->smgr to &smgrsw[reln->smgr_which]. Assisted-by: Claude Code --- src/backend/storage/smgr/smgr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c index f69eb7bfcc8..63d9dddb314 100644 --- a/src/backend/storage/smgr/smgr.c +++ b/src/backend/storage/smgr/smgr.c @@ -438,7 +438,7 @@ smgrrelease(SMgrRelation reln) { for (ForkNumber forknum = 0; forknum <= MAX_FORKNUM; forknum++) { - smgrsw[reln->smgr_which].smgr_close(reln, forknum); + (*reln->smgr).smgr_close(reln, forknum); reln->smgr_cached_nblocks[forknum] = InvalidBlockNumber; } reln->smgr_targblock = InvalidBlockNumber; @@ -696,8 +696,8 @@ void smgrzeroextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, int nblocks, bool skipFsync) { - smgrsw[reln->smgr_which].smgr_zeroextend(reln, forknum, blocknum, - nblocks, skipFsync); + (*reln->smgr).smgr_zeroextend(reln, forknum, blocknum, + nblocks, skipFsync); /* * Normally we expect this to increase the fork size by nblocks, but if