From 2fba69295b831fa76f51d1380522b603c8964d2d Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <akorotkov@postgresql.org>
Date: Mon, 7 Sep 2026 14:50:56 +0300
Subject: [PATCH v1 2/2] Say in the FSM README why its hint writes still need
 full page images

The Recovery section said we would "operate correctly without the full page
images that MarkBufferDirtyHint() provides", offering them only as a way to
lose less slot knowledge to RBM_ZERO_ON_ERROR.  That is true of freespace.c,
which passes RBM_ZERO_ON_ERROR on every read, and false of the system around
it, which reads the same files and does verify checksums.  Reading it as a
licence to dirty FSM pages without a full page image is what led to
c06d1a4ba6b, since reverted.

Say instead that RBM_ZERO_ON_ERROR is a property of this directory rather
than of the fork, name the readers that do not share it --
RelationCopyStorage(), RelationCopyStorageUsingBuffer(), base backups and
pg_checksums -- and note that the last two cannot be relaxed, because
a verification tool told to accept a tear we consider harmless can no longer
report one caused by failing storage.

Discussion: https://postgr.es/m/20260901211837.f6.noahmisch%40microsoft.com
---
 src/backend/storage/freespace/README | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/src/backend/storage/freespace/README b/src/backend/storage/freespace/README
index dc2a63a137b..f272d17b050 100644
--- a/src/backend/storage/freespace/README
+++ b/src/backend/storage/freespace/README
@@ -189,9 +189,26 @@ to propagate the new free-space info into the upper pages of the FSM tree.
 As a result when we write to the FSM we treat that as a hint and thus use
 MarkBufferDirtyHint() rather than MarkBufferDirty().  Every read here uses
 RBM_ZERO_ON_ERROR to bypass checksum mismatches and other verification
-failures.  We'd operate correctly without the full page images that
-MarkBufferDirtyHint() provides, but they do decrease the chance of losing slot
-knowledge to RBM_ZERO_ON_ERROR.
+failures.
+
+That RBM_ZERO_ON_ERROR is a property of this directory, not of the FSM fork
+itself.  The files themselves are ordinary relation files, and plenty of code
+outside freespace.c reads them and does verify checksums:
+RelationCopyStorage(), which ALTER TABLE ... SET TABLESPACE runs over every
+fork; the read stream in RelationCopyStorageUsingBuffer(), used by
+CREATE DATABASE ... STRATEGY = wal_log; and the checksum verification in base
+backups and in pg_checksums. The last two are the reason this cannot simply be
+relaxed: an external verification tool has no way to tell a tear that we
+consider harmless from one caused by failing storage, so making it accept
+the former blinds it to the latter.
+
+So the full page images MarkBufferDirtyHint() writes are not just an
+optimization that reduces how often RBM_ZERO_ON_ERROR loses knowledge.
+When checksums or wal_log_hints are enabled they are what keeps an FSM page
+that reaches disk either checksum-valid or repairable by a later FPI.  Do not
+replace MarkBufferDirtyHint() with MarkBufferDirty() here on the grounds that
+the FSM survives torn pages; it does, but the rest of the system is not
+promised the same.
 
 Relation extension is not WAL-logged.  Hence, after WAL replay, an on-disk FSM
 slot may indicate free space in PageIsNew() blocks that never reached disk.
-- 
2.55.0

