Skip to content

Commit 0d9114b

Browse files
committed
aio: Fix crash potential for pg_aios views due to late state update
pgaio_io_reclaim() reset the fields in PgAioHandle before updating the state to IDLE or incrementing the generation. For most things that's OK, but for pg_get_aios() it is not - if it copied the PgAioHandle while fields were being reset, we wouldn't detect that and could call pgaio_io_get_target_description() with ioh->target == PGAIO_TID_INVALID, leading to a crash. Fix this issue by incrementing the generation and state earlier, before resetting. Also add an assertion to pgaio_io_get_target_description() for the target to be valid - that'd have made this case a bit easier to debug. While at it, add/update a few related assertions. Author: Alexander Lakhin <exclusion@gmail.com> Discussion: https://postgr.es/m/062daca9-dfad-4750-9da8-b13388301ad9@gmail.com
1 parent 76d52e7 commit 0d9114b

File tree

2 files changed

+24
-9
lines changed

2 files changed

+24
-9
lines changed

src/backend/storage/aio/aio.c

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,21 @@ pgaio_io_reclaim(PgAioHandle *ioh)
670670

671671
Assert(!ioh->resowner);
672672

673+
/*
674+
* Update generation & state first, before resetting the IO's fields,
675+
* otherwise a concurrent "viewer" could think the fields are valid, even
676+
* though they are being reset. Increment the generation first, so that
677+
* we can assert elsewhere that we never wait for an IDLE IO. While it's
678+
* a bit weird for the state to go backwards for a generation, it's OK
679+
* here, as there cannot be references to the "reborn" IO yet. Can't
680+
* update both at once, so something has to give.
681+
*/
682+
ioh->generation++;
683+
pgaio_io_update_state(ioh, PGAIO_HS_IDLE);
684+
685+
/* ensure the state update is visible before we reset fields */
686+
pg_write_barrier();
687+
673688
ioh->op = PGAIO_OP_INVALID;
674689
ioh->target = PGAIO_TID_INVALID;
675690
ioh->flags = 0;
@@ -679,12 +694,6 @@ pgaio_io_reclaim(PgAioHandle *ioh)
679694
ioh->result = 0;
680695
ioh->distilled_result.status = PGAIO_RS_UNKNOWN;
681696

682-
/* XXX: the barrier is probably superfluous */
683-
pg_write_barrier();
684-
ioh->generation++;
685-
686-
pgaio_io_update_state(ioh, PGAIO_HS_IDLE);
687-
688697
/*
689698
* We push the IO to the head of the idle IO list, that seems more cache
690699
* efficient in cases where only a few IOs are used.

src/backend/storage/aio/aio_target.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ pgaio_io_has_target(PgAioHandle *ioh)
4949
const char *
5050
pgaio_io_get_target_name(PgAioHandle *ioh)
5151
{
52-
Assert(ioh->target >= 0 && ioh->target < PGAIO_TID_COUNT);
52+
/* explicitly allow INVALID here, function used by debug messages */
53+
Assert(ioh->target >= PGAIO_TID_INVALID && ioh->target < PGAIO_TID_COUNT);
5354

5455
return pgaio_target_info[ioh->target]->name;
5556
}
@@ -82,6 +83,9 @@ pgaio_io_get_target_data(PgAioHandle *ioh)
8283
char *
8384
pgaio_io_get_target_description(PgAioHandle *ioh)
8485
{
86+
/* disallow INVALID, there wouldn't be a description */
87+
Assert(ioh->target > PGAIO_TID_INVALID && ioh->target < PGAIO_TID_COUNT);
88+
8589
return pgaio_target_info[ioh->target]->describe_identity(&ioh->target_data);
8690
}
8791

@@ -98,6 +102,8 @@ pgaio_io_get_target_description(PgAioHandle *ioh)
98102
bool
99103
pgaio_io_can_reopen(PgAioHandle *ioh)
100104
{
105+
Assert(ioh->target > PGAIO_TID_INVALID && ioh->target < PGAIO_TID_COUNT);
106+
101107
return pgaio_target_info[ioh->target]->reopen != NULL;
102108
}
103109

@@ -109,8 +115,8 @@ pgaio_io_can_reopen(PgAioHandle *ioh)
109115
void
110116
pgaio_io_reopen(PgAioHandle *ioh)
111117
{
112-
Assert(ioh->target >= 0 && ioh->target < PGAIO_TID_COUNT);
113-
Assert(ioh->op >= 0 && ioh->op < PGAIO_OP_COUNT);
118+
Assert(ioh->target > PGAIO_TID_INVALID && ioh->target < PGAIO_TID_COUNT);
119+
Assert(ioh->op > PGAIO_OP_INVALID && ioh->op < PGAIO_OP_COUNT);
114120

115121
pgaio_target_info[ioh->target]->reopen(ioh);
116122
}

0 commit comments

Comments
 (0)