mirror of
https://github.com/postgres/postgres.git
synced 2026-10-29 10:44:45 +08:00
Avoid torn copy of the control file in base backups
Base backups read the control file (pg_control) from disk without any
protection against concurrent writes by the server, making it exposed to
torn copies. Attempting to use such a control file at startup would
cause a failure with a CRC not matching.
Base backups now read the control file while holding ControlFileLock.
c558e6fd92 has done the same for some SQL functions. The contents of
the file are saved in memory and sent over the wire as-is.
Backpatch down to v15. This issue is older than v15 but v14 is left out
of the picture as it is going to be EOL soon, so it does not seem worth
taking a risk for.
Author: David Steele <david@pgbackrest.org>
Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi>
Discussion: https://postgr.es/m/d1697de1-eb7f-41bf-a4b7-bba7203df11f@pgbackrest.org
Backpatch-through: 15
This commit is contained in:
1 parent
227de22095
commit
4a92c8c29b
1 file changed
+21
-8
@@ -23,9 +23,11 @@
|
||||
#include "backup/basebackup_incremental.h"
|
||||
#include "backup/basebackup_sink.h"
|
||||
#include "backup/basebackup_target.h"
|
||||
#include "catalog/pg_control.h"
|
||||
#include "catalog/pg_tablespace_d.h"
|
||||
#include "commands/defrem.h"
|
||||
#include "common/compression.h"
|
||||
#include "common/controldata_utils.h"
|
||||
#include "common/file_perm.h"
|
||||
#include "common/file_utils.h"
|
||||
#include "lib/stringinfo.h"
|
||||
@@ -42,6 +44,7 @@
|
||||
#include "storage/checksum.h"
|
||||
#include "storage/dsm_impl.h"
|
||||
#include "storage/ipc.h"
|
||||
#include "storage/lwlock.h"
|
||||
#include "storage/reinit.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/guc.h"
|
||||
@@ -340,9 +343,11 @@ perform_base_backup(basebackup_options *opt, bbsink *sink,
|
||||
|
||||
if (ti->path == NULL)
|
||||
{
|
||||
struct stat statbuf;
|
||||
bool sendtblspclinks = true;
|
||||
char *backup_label;
|
||||
ControlFileData *controlData;
|
||||
bool crc_ok;
|
||||
char controlFile[PG_CONTROL_FILE_SIZE];
|
||||
|
||||
bbsink_begin_archive(sink, "base.tar");
|
||||
|
||||
@@ -365,14 +370,22 @@ perform_base_backup(basebackup_options *opt, bbsink *sink,
|
||||
sendtblspclinks, &manifest, InvalidOid, ib);
|
||||
|
||||
/* ... and pg_control after everything else. */
|
||||
if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
|
||||
LWLockAcquire(ControlFileLock, LW_SHARED);
|
||||
controlData = get_controlfile(DataDir, &crc_ok);
|
||||
LWLockRelease(ControlFileLock);
|
||||
|
||||
if (!crc_ok)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not stat file \"%s\": %m",
|
||||
XLOG_CONTROL_FILE)));
|
||||
sendFile(sink, XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf,
|
||||
false, InvalidOid, InvalidOid,
|
||||
InvalidRelFileNumber, 0, &manifest, 0, NULL, 0);
|
||||
(errmsg("calculated CRC checksum does not match value stored in file")));
|
||||
|
||||
/* Send the full file, zero-padded as it is on disk */
|
||||
memset(controlFile, 0, PG_CONTROL_FILE_SIZE);
|
||||
memcpy(controlFile, controlData, sizeof(ControlFileData));
|
||||
pfree(controlData);
|
||||
|
||||
sendFileWithContent(sink, XLOG_CONTROL_FILE,
|
||||
controlFile, PG_CONTROL_FILE_SIZE,
|
||||
&manifest);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user