]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix locking bugs that could corrupt pg_control.
authorThomas Munro <tmunro@postgresql.org>
Mon, 8 Jun 2020 01:57:24 +0000 (13:57 +1200)
committerThomas Munro <tmunro@postgresql.org>
Mon, 8 Jun 2020 02:01:07 +0000 (14:01 +1200)
The redo routines for XLOG_CHECKPOINT_{ONLINE,SHUTDOWN} must acquire
ControlFileLock before modifying ControlFile->checkPointCopy, or the
checkpointer could write out a control file with a bad checksum.

Likewise, XLogReportParameters() must acquire ControlFileLock before
modifying ControlFile and calling UpdateControlFile().

Back-patch to all supported releases.

Author: Nathan Bossart <bossartn@amazon.com>
Author: Fujii Masao <masao.fujii@oss.nttdata.com>
Reviewed-by: Fujii Masao <masao.fujii@oss.nttdata.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Thomas Munro <thomas.munro@gmail.com>
Discussion: https://postgr.es/m/70BF24D6-DC51-443F-B55A-95735803842A%40amazon.com

src/backend/access/transam/xlog.c

index 7c40b1a5111f9f91ca9e3b0442b0639c19ab2203..7ab920a55d015623242c5738a2f8d388cb4e1319 100644 (file)
@@ -9647,6 +9647,8 @@ XLogReportParameters(void)
                        XLogFlush(recptr);
                }
 
+               LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
+
                ControlFile->MaxConnections = MaxConnections;
                ControlFile->max_worker_processes = max_worker_processes;
                ControlFile->max_prepared_xacts = max_prepared_xacts;
@@ -9655,6 +9657,8 @@ XLogReportParameters(void)
                ControlFile->wal_log_hints = wal_log_hints;
                ControlFile->track_commit_timestamp = track_commit_timestamp;
                UpdateControlFile();
+
+               LWLockRelease(ControlFileLock);
        }
 }
 
@@ -9879,8 +9883,10 @@ xlog_redo(XLogReaderState *record)
                }
 
                /* ControlFile->checkPointCopy always tracks the latest ckpt XID */
+               LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
                ControlFile->checkPointCopy.nextXidEpoch = checkPoint.nextXidEpoch;
                ControlFile->checkPointCopy.nextXid = checkPoint.nextXid;
+               LWLockRelease(ControlFileLock);
 
                /* Update shared-memory copy of checkpoint XID/epoch */
                SpinLockAcquire(&XLogCtl->info_lck);
@@ -9938,8 +9944,10 @@ xlog_redo(XLogReaderState *record)
                        SetTransactionIdLimit(checkPoint.oldestXid,
                                                                  checkPoint.oldestXidDB);
                /* ControlFile->checkPointCopy always tracks the latest ckpt XID */
+               LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
                ControlFile->checkPointCopy.nextXidEpoch = checkPoint.nextXidEpoch;
                ControlFile->checkPointCopy.nextXid = checkPoint.nextXid;
+               LWLockRelease(ControlFileLock);
 
                /* Update shared-memory copy of checkpoint XID/epoch */
                SpinLockAcquire(&XLogCtl->info_lck);