Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit ffae5cc

Browse files
committed
Add a check to prevent overwriting valid data if smgrnblocks() gives a
wrong answer, as has been seen to occur with a buggy Linux kernel. Not really our bug, but it's a simple test in a seldom-used control path, so might as well have a defense.
1 parent 6575920 commit ffae5cc

File tree

1 file changed

+21
-4
lines changed

1 file changed

+21
-4
lines changed

src/backend/storage/buffer/bufmgr.c

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.210 2006/09/17 22:16:22 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.211 2006/09/25 22:01:10 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -175,9 +175,26 @@ ReadBuffer(Relation reln, BlockNumber blockNum)
175175
/*
176176
* We get here only in the corner case where we are trying to extend
177177
* the relation but we found a pre-existing buffer marked BM_VALID.
178-
* (This can happen because mdread doesn't complain about reads
179-
* beyond EOF --- which is arguably bogus, but changing it seems
180-
* tricky.) We *must* do smgrextend before succeeding, else the
178+
* This can happen because mdread doesn't complain about reads beyond
179+
* EOF --- which is arguably bogus, but changing it seems tricky ---
180+
* and so a previous attempt to read a block just beyond EOF could
181+
* have left a "valid" zero-filled buffer. Unfortunately, we have
182+
* also seen this case occurring because of buggy Linux kernels that
183+
* sometimes return an lseek(SEEK_END) result that doesn't account for
184+
* a recent write. In that situation, the pre-existing buffer would
185+
* contain valid data that we don't want to overwrite. Since the
186+
* legitimate cases should always have left a zero-filled buffer,
187+
* complain if not PageIsNew.
188+
*/
189+
bufBlock = isLocalBuf ? LocalBufHdrGetBlock(bufHdr) : BufHdrGetBlock(bufHdr);
190+
if (!PageIsNew((PageHeader) bufBlock))
191+
ereport(ERROR,
192+
(errmsg("unexpected data beyond EOF in block %u of relation \"%s\"",
193+
blockNum, RelationGetRelationName(reln)),
194+
errhint("This has been seen to occur with buggy kernels; consider updating your system.")));
195+
196+
/*
197+
* We *must* do smgrextend before succeeding, else the
181198
* page will not be reserved by the kernel, and the next P_NEW call
182199
* will decide to return the same page. Clear the BM_VALID bit,
183200
* do the StartBufferIO call that BufferAlloc didn't, and proceed.

0 commit comments

Comments
 (0)