mirror of
https://github.com/postgres/postgres.git
synced 2025-10-27 00:12:01 +03:00
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
123 lines
3.2 KiB
C
123 lines
3.2 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* aio_target.c
|
|
* AIO - Functionality related to executing IO for different targets
|
|
*
|
|
* Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
* IDENTIFICATION
|
|
* src/backend/storage/aio/aio_target.c
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
#include "storage/aio.h"
|
|
#include "storage/aio_internal.h"
|
|
#include "storage/smgr.h"
|
|
|
|
|
|
/*
|
|
* Registry for entities that can be the target of AIO.
|
|
*/
|
|
static const PgAioTargetInfo *pgaio_target_info[] = {
|
|
[PGAIO_TID_INVALID] = &(PgAioTargetInfo) {
|
|
.name = "invalid",
|
|
},
|
|
[PGAIO_TID_SMGR] = &aio_smgr_target_info,
|
|
};
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------
|
|
* Public target related functions operating on IO Handles
|
|
* --------------------------------------------------------------------------------
|
|
*/
|
|
|
|
bool
|
|
pgaio_io_has_target(PgAioHandle *ioh)
|
|
{
|
|
return ioh->target != PGAIO_TID_INVALID;
|
|
}
|
|
|
|
/*
|
|
* Return the name for the target associated with the IO. Mostly useful for
|
|
* debugging/logging.
|
|
*/
|
|
const char *
|
|
pgaio_io_get_target_name(PgAioHandle *ioh)
|
|
{
|
|
/* explicitly allow INVALID here, function used by debug messages */
|
|
Assert(ioh->target >= PGAIO_TID_INVALID && ioh->target < PGAIO_TID_COUNT);
|
|
|
|
return pgaio_target_info[ioh->target]->name;
|
|
}
|
|
|
|
/*
|
|
* Assign a target to the IO.
|
|
*
|
|
* This has to be called exactly once before pgaio_io_start_*() is called.
|
|
*/
|
|
void
|
|
pgaio_io_set_target(PgAioHandle *ioh, PgAioTargetID targetid)
|
|
{
|
|
Assert(ioh->state == PGAIO_HS_HANDED_OUT);
|
|
Assert(ioh->target == PGAIO_TID_INVALID);
|
|
|
|
ioh->target = targetid;
|
|
}
|
|
|
|
PgAioTargetData *
|
|
pgaio_io_get_target_data(PgAioHandle *ioh)
|
|
{
|
|
return &ioh->target_data;
|
|
}
|
|
|
|
/*
|
|
* Return a stringified description of the IO's target.
|
|
*
|
|
* The string is localized and allocated in the current memory context.
|
|
*/
|
|
char *
|
|
pgaio_io_get_target_description(PgAioHandle *ioh)
|
|
{
|
|
/* disallow INVALID, there wouldn't be a description */
|
|
Assert(ioh->target > PGAIO_TID_INVALID && ioh->target < PGAIO_TID_COUNT);
|
|
|
|
return pgaio_target_info[ioh->target]->describe_identity(&ioh->target_data);
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------
|
|
* Internal target related functions operating on IO Handles
|
|
* --------------------------------------------------------------------------------
|
|
*/
|
|
|
|
/*
|
|
* Internal: Check if pgaio_io_reopen() is available for the IO.
|
|
*/
|
|
bool
|
|
pgaio_io_can_reopen(PgAioHandle *ioh)
|
|
{
|
|
Assert(ioh->target > PGAIO_TID_INVALID && ioh->target < PGAIO_TID_COUNT);
|
|
|
|
return pgaio_target_info[ioh->target]->reopen != NULL;
|
|
}
|
|
|
|
/*
|
|
* Internal: Before executing an IO outside of the context of the process the
|
|
* IO has been staged in, the file descriptor has to be reopened - any FD
|
|
* referenced in the IO itself, won't be valid in the separate process.
|
|
*/
|
|
void
|
|
pgaio_io_reopen(PgAioHandle *ioh)
|
|
{
|
|
Assert(ioh->target > PGAIO_TID_INVALID && ioh->target < PGAIO_TID_COUNT);
|
|
Assert(ioh->op > PGAIO_OP_INVALID && ioh->op < PGAIO_OP_COUNT);
|
|
|
|
pgaio_target_info[ioh->target]->reopen(ioh);
|
|
}
|