Skip to content

Commit fc51a60

Browse files
committed
smgr: Hold interrupts in most smgr functions
We need to hold interrupts across most of the smgr.c/md.c functions, as otherwise interrupt processing, e.g. due to a < ERROR elog/ereport, can trigger procsignal processing, which in turn can trigger smgrreleaseall(). As the relevant code is not reentrant, we quickly end up in a bad situation. The only reason we haven't noticed this before is that there is only one non-error ereport called in affected routines, in register_dirty_segments(), and that one is extremely rarely reached. If one enables fd.c's FDDEBUG it's easy to reproduce crashes. It seems better to put the HOLD_INTERRUPTS()/RESUME_INTERRUPTS() in smgr.c, instead of trying to push them down to md.c where possible: For one, every smgr implementation would be vulnerable, for another, a good bit of smgr.c code itself is affected too. Eventually we might want a more targeted solution, allowing e.g. a networked smgr implementation to be interrupted, but many other, more complicated, problems would need to be fixed for that to be viable (e.g. smgr.c is often called with interrupts already held). One could argue this should be backpatched, but the existing < ERROR elog/ereports that can be reached with unmodified sources are unlikely to be reached. On balance the risk of backpatching seems higher than the gain - at least for now. Reviewed-by: Noah Misch <noah@leadboat.com> Reviewed-by: Thomas Munro <thomas.munro@gmail.com> Discussion: https://postgr.es/m/3vae7l5ozvqtxmd7rr7zaeq3qkuipz365u3rtim5t5wdkr6f4g@vkgf2fogjirl
1 parent fdb5dd6 commit fc51a60

File tree

1 file changed

+101
-3
lines changed
  • src/backend/storage/smgr

1 file changed

+101
-3
lines changed

src/backend/storage/smgr/smgr.c

Lines changed: 101 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,18 @@
4040
* themselves, as there could pointers to them in active use. See
4141
* smgrrelease() and smgrreleaseall().
4242
*
43+
* NB: We need to hold interrupts across most of the functions in this file,
44+
* as otherwise interrupt processing, e.g. due to a < ERROR elog/ereport, can
45+
* trigger procsignal processing, which in turn can trigger
46+
* smgrreleaseall(). Most of the relevant code is not reentrant. It seems
47+
* better to put the HOLD_INTERRUPTS()/RESUME_INTERRUPTS() here, instead of
48+
* trying to push them down to md.c where possible: For one, every smgr
49+
* implementation would be vulnerable, for another, a good bit of smgr.c code
50+
* itself is affected too. Eventually we might want a more targeted solution,
51+
* allowing e.g. a networked smgr implementation to be interrupted, but many
52+
* other, more complicated, problems would need to be fixed for that to be
53+
* viable (e.g. smgr.c is often called with interrupts already held).
54+
*
4355
* Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
4456
* Portions Copyright (c) 1994, Regents of the University of California
4557
*
@@ -53,6 +65,7 @@
5365

5466
#include "access/xlogutils.h"
5567
#include "lib/ilist.h"
68+
#include "miscadmin.h"
5669
#include "storage/bufmgr.h"
5770
#include "storage/ipc.h"
5871
#include "storage/md.h"
@@ -158,12 +171,16 @@ smgrinit(void)
158171
{
159172
int i;
160173

174+
HOLD_INTERRUPTS();
175+
161176
for (i = 0; i < NSmgr; i++)
162177
{
163178
if (smgrsw[i].smgr_init)
164179
smgrsw[i].smgr_init();
165180
}
166181

182+
RESUME_INTERRUPTS();
183+
167184
/* register the shutdown proc */
168185
on_proc_exit(smgrshutdown, 0);
169186
}
@@ -176,11 +193,15 @@ smgrshutdown(int code, Datum arg)
176193
{
177194
int i;
178195

196+
HOLD_INTERRUPTS();
197+
179198
for (i = 0; i < NSmgr; i++)
180199
{
181200
if (smgrsw[i].smgr_shutdown)
182201
smgrsw[i].smgr_shutdown();
183202
}
203+
204+
RESUME_INTERRUPTS();
184205
}
185206

186207
/*
@@ -206,6 +227,8 @@ smgropen(RelFileLocator rlocator, ProcNumber backend)
206227

207228
Assert(RelFileNumberIsValid(rlocator.relNumber));
208229

230+
HOLD_INTERRUPTS();
231+
209232
if (SMgrRelationHash == NULL)
210233
{
211234
/* First time through: initialize the hash table */
@@ -242,6 +265,8 @@ smgropen(RelFileLocator rlocator, ProcNumber backend)
242265
smgrsw[reln->smgr_which].smgr_open(reln);
243266
}
244267

268+
RESUME_INTERRUPTS();
269+
245270
return reln;
246271
}
247272

@@ -283,6 +308,8 @@ smgrdestroy(SMgrRelation reln)
283308

284309
Assert(reln->pincount == 0);
285310

311+
HOLD_INTERRUPTS();
312+
286313
for (forknum = 0; forknum <= MAX_FORKNUM; forknum++)
287314
smgrsw[reln->smgr_which].smgr_close(reln, forknum);
288315

@@ -292,6 +319,8 @@ smgrdestroy(SMgrRelation reln)
292319
&(reln->smgr_rlocator),
293320
HASH_REMOVE, NULL) == NULL)
294321
elog(ERROR, "SMgrRelation hashtable corrupted");
322+
323+
RESUME_INTERRUPTS();
295324
}
296325

297326
/*
@@ -302,12 +331,16 @@ smgrdestroy(SMgrRelation reln)
302331
void
303332
smgrrelease(SMgrRelation reln)
304333
{
334+
HOLD_INTERRUPTS();
335+
305336
for (ForkNumber forknum = 0; forknum <= MAX_FORKNUM; forknum++)
306337
{
307338
smgrsw[reln->smgr_which].smgr_close(reln, forknum);
308339
reln->smgr_cached_nblocks[forknum] = InvalidBlockNumber;
309340
}
310341
reln->smgr_targblock = InvalidBlockNumber;
342+
343+
RESUME_INTERRUPTS();
311344
}
312345

313346
/*
@@ -336,6 +369,9 @@ smgrdestroyall(void)
336369
{
337370
dlist_mutable_iter iter;
338371

372+
/* seems unsafe to accept interrupts while in a dlist_foreach_modify() */
373+
HOLD_INTERRUPTS();
374+
339375
/*
340376
* Zap all unpinned SMgrRelations. We rely on smgrdestroy() to remove
341377
* each one from the list.
@@ -347,6 +383,8 @@ smgrdestroyall(void)
347383

348384
smgrdestroy(rel);
349385
}
386+
387+
RESUME_INTERRUPTS();
350388
}
351389

352390
/*
@@ -362,12 +400,17 @@ smgrreleaseall(void)
362400
if (SMgrRelationHash == NULL)
363401
return;
364402

403+
/* seems unsafe to accept interrupts while iterating */
404+
HOLD_INTERRUPTS();
405+
365406
hash_seq_init(&status, SMgrRelationHash);
366407

367408
while ((reln = (SMgrRelation) hash_seq_search(&status)) != NULL)
368409
{
369410
smgrrelease(reln);
370411
}
412+
413+
RESUME_INTERRUPTS();
371414
}
372415

373416
/*
@@ -400,7 +443,13 @@ smgrreleaserellocator(RelFileLocatorBackend rlocator)
400443
bool
401444
smgrexists(SMgrRelation reln, ForkNumber forknum)
402445
{
403-
return smgrsw[reln->smgr_which].smgr_exists(reln, forknum);
446+
bool ret;
447+
448+
HOLD_INTERRUPTS();
449+
ret = smgrsw[reln->smgr_which].smgr_exists(reln, forknum);
450+
RESUME_INTERRUPTS();
451+
452+
return ret;
404453
}
405454

406455
/*
@@ -413,7 +462,9 @@ smgrexists(SMgrRelation reln, ForkNumber forknum)
413462
void
414463
smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
415464
{
465+
HOLD_INTERRUPTS();
416466
smgrsw[reln->smgr_which].smgr_create(reln, forknum, isRedo);
467+
RESUME_INTERRUPTS();
417468
}
418469

419470
/*
@@ -436,6 +487,8 @@ smgrdosyncall(SMgrRelation *rels, int nrels)
436487

437488
FlushRelationsAllBuffers(rels, nrels);
438489

490+
HOLD_INTERRUPTS();
491+
439492
/*
440493
* Sync the physical file(s).
441494
*/
@@ -449,6 +502,8 @@ smgrdosyncall(SMgrRelation *rels, int nrels)
449502
smgrsw[which].smgr_immedsync(rels[i], forknum);
450503
}
451504
}
505+
506+
RESUME_INTERRUPTS();
452507
}
453508

454509
/*
@@ -471,6 +526,13 @@ smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo)
471526
if (nrels == 0)
472527
return;
473528

529+
/*
530+
* It would be unsafe to process interrupts between DropRelationBuffers()
531+
* and unlinking the underlying files. This probably should be a critical
532+
* section, but we're not there yet.
533+
*/
534+
HOLD_INTERRUPTS();
535+
474536
/*
475537
* Get rid of any remaining buffers for the relations. bufmgr will just
476538
* drop them without bothering to write the contents.
@@ -522,6 +584,8 @@ smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo)
522584
}
523585

524586
pfree(rlocators);
587+
588+
RESUME_INTERRUPTS();
525589
}
526590

527591

@@ -538,6 +602,8 @@ void
538602
smgrextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
539603
const void *buffer, bool skipFsync)
540604
{
605+
HOLD_INTERRUPTS();
606+
541607
smgrsw[reln->smgr_which].smgr_extend(reln, forknum, blocknum,
542608
buffer, skipFsync);
543609

@@ -550,6 +616,8 @@ smgrextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
550616
reln->smgr_cached_nblocks[forknum] = blocknum + 1;
551617
else
552618
reln->smgr_cached_nblocks[forknum] = InvalidBlockNumber;
619+
620+
RESUME_INTERRUPTS();
553621
}
554622

555623
/*
@@ -563,6 +631,8 @@ void
563631
smgrzeroextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
564632
int nblocks, bool skipFsync)
565633
{
634+
HOLD_INTERRUPTS();
635+
566636
smgrsw[reln->smgr_which].smgr_zeroextend(reln, forknum, blocknum,
567637
nblocks, skipFsync);
568638

@@ -575,6 +645,8 @@ smgrzeroextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
575645
reln->smgr_cached_nblocks[forknum] = blocknum + nblocks;
576646
else
577647
reln->smgr_cached_nblocks[forknum] = InvalidBlockNumber;
648+
649+
RESUME_INTERRUPTS();
578650
}
579651

580652
/*
@@ -588,7 +660,13 @@ bool
588660
smgrprefetch(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
589661
int nblocks)
590662
{
591-
return smgrsw[reln->smgr_which].smgr_prefetch(reln, forknum, blocknum, nblocks);
663+
bool ret;
664+
665+
HOLD_INTERRUPTS();
666+
ret = smgrsw[reln->smgr_which].smgr_prefetch(reln, forknum, blocknum, nblocks);
667+
RESUME_INTERRUPTS();
668+
669+
return ret;
592670
}
593671

594672
/*
@@ -601,7 +679,13 @@ uint32
601679
smgrmaxcombine(SMgrRelation reln, ForkNumber forknum,
602680
BlockNumber blocknum)
603681
{
604-
return smgrsw[reln->smgr_which].smgr_maxcombine(reln, forknum, blocknum);
682+
uint32 ret;
683+
684+
HOLD_INTERRUPTS();
685+
ret = smgrsw[reln->smgr_which].smgr_maxcombine(reln, forknum, blocknum);
686+
RESUME_INTERRUPTS();
687+
688+
return ret;
605689
}
606690

607691
/*
@@ -619,8 +703,10 @@ void
619703
smgrreadv(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
620704
void **buffers, BlockNumber nblocks)
621705
{
706+
HOLD_INTERRUPTS();
622707
smgrsw[reln->smgr_which].smgr_readv(reln, forknum, blocknum, buffers,
623708
nblocks);
709+
RESUME_INTERRUPTS();
624710
}
625711

626712
/*
@@ -653,8 +739,10 @@ void
653739
smgrwritev(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
654740
const void **buffers, BlockNumber nblocks, bool skipFsync)
655741
{
742+
HOLD_INTERRUPTS();
656743
smgrsw[reln->smgr_which].smgr_writev(reln, forknum, blocknum,
657744
buffers, nblocks, skipFsync);
745+
RESUME_INTERRUPTS();
658746
}
659747

660748
/*
@@ -665,8 +753,10 @@ void
665753
smgrwriteback(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
666754
BlockNumber nblocks)
667755
{
756+
HOLD_INTERRUPTS();
668757
smgrsw[reln->smgr_which].smgr_writeback(reln, forknum, blocknum,
669758
nblocks);
759+
RESUME_INTERRUPTS();
670760
}
671761

672762
/*
@@ -683,10 +773,14 @@ smgrnblocks(SMgrRelation reln, ForkNumber forknum)
683773
if (result != InvalidBlockNumber)
684774
return result;
685775

776+
HOLD_INTERRUPTS();
777+
686778
result = smgrsw[reln->smgr_which].smgr_nblocks(reln, forknum);
687779

688780
reln->smgr_cached_nblocks[forknum] = result;
689781

782+
RESUME_INTERRUPTS();
783+
690784
return result;
691785
}
692786

@@ -784,7 +878,9 @@ smgrtruncate(SMgrRelation reln, ForkNumber *forknum, int nforks,
784878
void
785879
smgrregistersync(SMgrRelation reln, ForkNumber forknum)
786880
{
881+
HOLD_INTERRUPTS();
787882
smgrsw[reln->smgr_which].smgr_registersync(reln, forknum);
883+
RESUME_INTERRUPTS();
788884
}
789885

790886
/*
@@ -816,7 +912,9 @@ smgrregistersync(SMgrRelation reln, ForkNumber forknum)
816912
void
817913
smgrimmedsync(SMgrRelation reln, ForkNumber forknum)
818914
{
915+
HOLD_INTERRUPTS();
819916
smgrsw[reln->smgr_which].smgr_immedsync(reln, forknum);
917+
RESUME_INTERRUPTS();
820918
}
821919

822920
/*

0 commit comments

Comments
 (0)