mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-01-18 04:58:51 +02:00
Add validation for page checksum version in pg_control.
This serves as an additional sanity check to be sure the pg_control format is as expected. The field is useful for being all the way at the end and being four bytes that can only have one of two values. Something more distinctive than 0 and 1 would be better, but this is what we have to work with. Convert PgControl.pageChecksum to unsigned int and rename to PgControl.pageChecksumVersion and make all downstream changes required for the new datatype.
This commit is contained in:
parent
7448fde157
commit
63541b2273
@ -248,7 +248,7 @@ backupInit(const InfoBackup *const infoBackup)
|
||||
// If online then use the value in pg_control to set checksum-page
|
||||
if (cfgOptionBool(cfgOptOnline))
|
||||
{
|
||||
cfgOptionSet(cfgOptChecksumPage, cfgSourceParam, VARBOOL(pgControl.pageChecksum));
|
||||
cfgOptionSet(cfgOptChecksumPage, cfgSourceParam, VARBOOL(pgControl.pageChecksumVersion != 0));
|
||||
}
|
||||
// Else set to false. An offline cluster is likely to have false positives so better if the user enables manually.
|
||||
else
|
||||
@ -256,7 +256,7 @@ backupInit(const InfoBackup *const infoBackup)
|
||||
}
|
||||
// Else if checksums have been explicitly enabled but are not available then warn and reset. ??? We should be able to make this
|
||||
// determination when offline as well, but the integration tests don't write pg_control accurately enough to support it.
|
||||
else if (cfgOptionBool(cfgOptOnline) && !pgControl.pageChecksum && cfgOptionBool(cfgOptChecksumPage))
|
||||
else if (cfgOptionBool(cfgOptOnline) && pgControl.pageChecksumVersion == 0 && cfgOptionBool(cfgOptChecksumPage))
|
||||
{
|
||||
LOG_WARN(CFGOPT_CHECKSUM_PAGE " option set to true but checksums are not enabled on the cluster, resetting to false");
|
||||
cfgOptionSet(cfgOptChecksumPage, cfgSourceParam, BOOL_FALSE_VAR);
|
||||
|
@ -276,6 +276,14 @@ pgControlFromBuffer(const Buffer *controlFile, const String *const pgVersionForc
|
||||
// Check the page size
|
||||
pgPageSizeCheck(result.pageSize);
|
||||
|
||||
// Check the checksum version
|
||||
if (result.pageChecksumVersion != 0 && result.pageChecksumVersion != PG_DATA_CHECKSUM_VERSION)
|
||||
{
|
||||
THROW_FMT(
|
||||
FormatError, "page checksum version is %u but only 0 and " STRINGIFY(PG_DATA_CHECKSUM_VERSION) " are valid",
|
||||
result.pageChecksumVersion);
|
||||
}
|
||||
|
||||
FUNCTION_LOG_RETURN(PG_CONTROL, result);
|
||||
}
|
||||
|
||||
@ -700,8 +708,8 @@ FN_EXTERN void
|
||||
pgControlToLog(const PgControl *const pgControl, StringStatic *const debugLog)
|
||||
{
|
||||
strStcFmt(
|
||||
debugLog, "{version: %u, systemId: %" PRIu64 ", walSegmentSize: %u, pageChecksum: %s}", pgControl->version,
|
||||
pgControl->systemId, pgControl->walSegmentSize, cvtBoolToConstZ(pgControl->pageChecksum));
|
||||
debugLog, "{version: %u, systemId: %" PRIu64 ", walSegmentSize: %u, pageChecksumVersion: %u}", pgControl->version,
|
||||
pgControl->systemId, pgControl->walSegmentSize, pgControl->pageChecksumVersion);
|
||||
}
|
||||
|
||||
FN_EXTERN void
|
||||
|
@ -109,7 +109,7 @@ typedef struct PgControl
|
||||
PgPageSize pageSize;
|
||||
unsigned int walSegmentSize;
|
||||
|
||||
bool pageChecksum;
|
||||
unsigned int pageChecksumVersion; // Page checksum version (0 if no checksum, 1 if checksum)
|
||||
} PgControl;
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
|
@ -124,6 +124,14 @@ typedef struct
|
||||
uint32 xrecoff; /* low bits */
|
||||
} PageXLogRecPtr;
|
||||
|
||||
// PG_DATA_CHECKSUM_VERSION define
|
||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
||||
/*
|
||||
* As of Release 9.3, the checksum version must also be considered when
|
||||
* handling pages.
|
||||
*/
|
||||
#define PG_DATA_CHECKSUM_VERSION 1
|
||||
|
||||
// PageHeaderData type
|
||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
||||
/*
|
||||
|
@ -70,7 +70,7 @@ Read the version specific pg_control into a general data structure
|
||||
.timeline = ((ControlFileData *)controlFile)->checkPointCopy.ThisTimeLineID, \
|
||||
.pageSize = ((ControlFileData *)controlFile)->blcksz, \
|
||||
.walSegmentSize = ((ControlFileData *)controlFile)->xlog_seg_size, \
|
||||
.pageChecksum = ((ControlFileData *)controlFile)->data_checksum_version != 0, \
|
||||
.pageChecksumVersion = ((ControlFileData *)controlFile)->data_checksum_version, \
|
||||
}; \
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ Create a pg_control file
|
||||
}, \
|
||||
.blcksz = pgControl.pageSize, \
|
||||
.xlog_seg_size = pgControl.walSegmentSize, \
|
||||
.data_checksum_version = pgControl.pageChecksum, \
|
||||
.data_checksum_version = pgControl.pageChecksumVersion, \
|
||||
}; \
|
||||
\
|
||||
((ControlFileData *)buffer)->crc = \
|
||||
|
@ -1570,7 +1570,7 @@ testRun(void)
|
||||
TEST_TITLE("ok if cluster checksums are enabled and checksum-page is any value");
|
||||
|
||||
// Create pg_control with page checksums
|
||||
HRN_PG_CONTROL_PUT(storagePgWrite(), PG_VERSION_94, .pageChecksum = true);
|
||||
HRN_PG_CONTROL_PUT(storagePgWrite(), PG_VERSION_94, .pageChecksumVersion = 1);
|
||||
|
||||
argList = strLstNew();
|
||||
hrnCfgArgRawZ(argList, cfgOptStanza, "test1");
|
||||
@ -2700,7 +2700,7 @@ testRun(void)
|
||||
|
||||
{
|
||||
// Update pg_control
|
||||
HRN_PG_CONTROL_PUT(storagePgWrite(), PG_VERSION_11, .pageChecksum = true, .walSegmentSize = 1024 * 1024);
|
||||
HRN_PG_CONTROL_PUT(storagePgWrite(), PG_VERSION_11, .pageChecksumVersion = 1, .walSegmentSize = 1024 * 1024);
|
||||
|
||||
// Update version
|
||||
HRN_STORAGE_PUT_Z(storagePgWrite(), PG_FILE_PGVERSION, PG_VERSION_11_Z, .timeModified = backupTimeStart);
|
||||
@ -3025,7 +3025,7 @@ testRun(void)
|
||||
|
||||
// Create pg_control with unexpected catalog and control version
|
||||
HRN_PG_CONTROL_OVERRIDE_VERSION_PUT(
|
||||
storagePgWrite(), PG_VERSION_11, 1501, .catalogVersion = 202211110, .pageChecksum = true,
|
||||
storagePgWrite(), PG_VERSION_11, 1501, .catalogVersion = 202211110, .pageChecksumVersion = 1,
|
||||
.walSegmentSize = 1024 * 1024);
|
||||
|
||||
// Set to a smaller values than the defaults allow
|
||||
@ -3123,7 +3123,7 @@ testRun(void)
|
||||
HRN_STORAGE_REMOVE(storageTest, "pg1");
|
||||
|
||||
// Update pg_control
|
||||
HRN_PG_CONTROL_PUT(storagePgWrite(), PG_VERSION_11, .pageChecksum = false, .walSegmentSize = 2 * 1024 * 1024);
|
||||
HRN_PG_CONTROL_PUT(storagePgWrite(), PG_VERSION_11, .walSegmentSize = 2 * 1024 * 1024);
|
||||
|
||||
// Update version
|
||||
HRN_STORAGE_PUT_Z(storagePgWrite(), PG_FILE_PGVERSION, PG_VERSION_11_Z, .timeModified = backupTimeStart);
|
||||
@ -3193,7 +3193,7 @@ testRun(void)
|
||||
HRN_STORAGE_PATH_REMOVE(storageTest, "pg1", .recurse = true);
|
||||
|
||||
// Update pg_control
|
||||
HRN_PG_CONTROL_PUT(storagePgWrite(), PG_VERSION_11, .pageChecksum = false, .walSegmentSize = 2 * 1024 * 1024);
|
||||
HRN_PG_CONTROL_PUT(storagePgWrite(), PG_VERSION_11, .pageChecksumVersion = 0, .walSegmentSize = 2 * 1024 * 1024);
|
||||
|
||||
// Update version
|
||||
HRN_STORAGE_PUT_Z(storagePgWrite(), PG_FILE_PGVERSION, PG_VERSION_11_Z, .timeModified = backupTimeStart);
|
||||
@ -3276,7 +3276,7 @@ testRun(void)
|
||||
"P00 INFO: check archive for segment 0000000105DBF06000000000\n"
|
||||
"P01 DETAIL: backup file " TEST_PATH "/pg1/block-incr-grow (24KB, [PCT]) checksum [SHA1]");
|
||||
|
||||
HRN_PG_CONTROL_PUT(storagePgWrite(), PG_VERSION_11, .pageChecksum = false, .walSegmentSize = 2 * 1024 * 1024);
|
||||
HRN_PG_CONTROL_PUT(storagePgWrite(), PG_VERSION_11, .walSegmentSize = 2 * 1024 * 1024);
|
||||
|
||||
// Run backup
|
||||
hrnBackupPqScriptP(PG_VERSION_11, backupTimeStart, .walCompressType = compressTypeGz, .walTotal = 2, .walSwitch = true);
|
||||
@ -3663,7 +3663,8 @@ testRun(void)
|
||||
|
||||
// Update pg_control
|
||||
HRN_PG_CONTROL_PUT(
|
||||
storagePgWrite(), PG_VERSION_11, .pageChecksum = true, .walSegmentSize = 2 * 1024 * 1024, .pageSize = pgPageSize4);
|
||||
storagePgWrite(), PG_VERSION_11, .pageChecksumVersion = 1, .walSegmentSize = 2 * 1024 * 1024,
|
||||
.pageSize = pgPageSize4);
|
||||
|
||||
// Update version
|
||||
HRN_STORAGE_PUT_Z(storagePgWrite(), PG_FILE_PGVERSION, PG_VERSION_11_Z, .timeModified = backupTimeStart);
|
||||
|
@ -73,7 +73,7 @@ testRun(void)
|
||||
HRN_CFG_LOAD(cfgCmdStanzaCreate, argList);
|
||||
|
||||
// Create pg_control and run stanza-create
|
||||
HRN_PG_CONTROL_PUT(storagePgWrite(), PG_VERSION_95, .pageChecksum = false);
|
||||
HRN_PG_CONTROL_PUT(storagePgWrite(), PG_VERSION_95);
|
||||
TEST_RESULT_VOID(cmdStanzaCreate(), "stanza create");
|
||||
}
|
||||
|
||||
|
@ -3138,7 +3138,7 @@ testRun(void)
|
||||
const String *repoPath = STRDEF(TEST_PATH "/repo");
|
||||
|
||||
// Created pg_control and PG_VERSION
|
||||
HRN_PG_CONTROL_PUT(storagePgWrite(), PG_VERSION_15, .pageChecksum = false);
|
||||
HRN_PG_CONTROL_PUT(storagePgWrite(), PG_VERSION_15);
|
||||
HRN_STORAGE_PUT_Z(storagePgWrite(), PG_FILE_PGVERSION, PG_VERSION_15_Z);
|
||||
|
||||
// Create encrypted stanza
|
||||
|
@ -134,6 +134,12 @@ testRun(void)
|
||||
pgControlFromFile(storageTest, NULL), FormatError,
|
||||
"page size is 65536 but only 1024, 2048, 4096, 8192, 16384, and 32768 are supported");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
HRN_PG_CONTROL_PUT(storageTest, PG_VERSION_11, .pageChecksumVersion = 2);
|
||||
|
||||
TEST_ERROR(
|
||||
pgControlFromFile(storageTest, NULL), FormatError, "page checksum version is 2 but only 0 and 1 are valid");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
HRN_PG_CONTROL_PUT(
|
||||
storageTest, PG_VERSION_94, .systemId = 0xEFEFEFEFEF, .catalogVersion = hrnPgCatalogVersion(PG_VERSION_94),
|
||||
@ -146,11 +152,12 @@ testRun(void)
|
||||
TEST_RESULT_UINT(info.checkpoint, 0xAABBAABBEEFFEEFF, "check checkpoint");
|
||||
TEST_RESULT_UINT(info.timeline, 88, "check timeline");
|
||||
TEST_RESULT_UINT(info.pageSize, pgPageSize8, "check page size");
|
||||
TEST_RESULT_UINT(info.pageChecksumVersion, 0, "check page checksum");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
HRN_PG_CONTROL_PUT(
|
||||
storageTest, PG_VERSION_16, .systemId = 0xEFEFEFEFEF, .catalogVersion = hrnPgCatalogVersion(PG_VERSION_16),
|
||||
.checkpoint = 0xAABBAABBEEFFEEFF, .timeline = 88, .pageSize = pgPageSize1);
|
||||
.checkpoint = 0xAABBAABBEEFFEEFF, .timeline = 88, .pageSize = pgPageSize1, .pageChecksumVersion = 1);
|
||||
|
||||
TEST_ASSIGN(info, pgControlFromFile(storageTest, NULL), "get control info v90");
|
||||
TEST_RESULT_UINT(info.systemId, 0xEFEFEFEFEF, " check system id");
|
||||
@ -159,6 +166,7 @@ testRun(void)
|
||||
TEST_RESULT_UINT(info.checkpoint, 0xAABBAABBEEFFEEFF, "check checkpoint");
|
||||
TEST_RESULT_UINT(info.timeline, 88, "check timeline");
|
||||
TEST_RESULT_UINT(info.pageSize, pgPageSize1, "check page size");
|
||||
TEST_RESULT_UINT(info.pageChecksumVersion, 1, "check page checksum");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
HRN_PG_CONTROL_PUT(
|
||||
@ -473,12 +481,12 @@ testRun(void)
|
||||
.version = PG_VERSION_11,
|
||||
.systemId = 0xEFEFEFEFEF,
|
||||
.walSegmentSize = 16 * 1024 * 1024,
|
||||
.pageChecksum = true
|
||||
.pageChecksumVersion = 1,
|
||||
};
|
||||
|
||||
TEST_RESULT_VOID(FUNCTION_LOG_OBJECT_FORMAT(&pgControl, pgControlToLog, logBuf, sizeof(logBuf)), "pgControlToLog");
|
||||
TEST_RESULT_Z(
|
||||
logBuf, "{version: 110000, systemId: 1030522662895, walSegmentSize: 16777216, pageChecksum: true}", "check log");
|
||||
logBuf, "{version: 110000, systemId: 1030522662895, walSegmentSize: 16777216, pageChecksumVersion: 1}", "check log");
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
|
Loading…
x
Reference in New Issue
Block a user