aboutsummaryrefslogtreecommitdiff
path: root/src/backend/storage/buffer/bufmgr.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2006-09-25 22:01:10 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2006-09-25 22:01:10 +0000
commitffae5cc5a6024b4e25ec920ed5c4dfac649605f8 (patch)
treec2c8127bf7b3a1f23b757cc206c7f69dda61825a /src/backend/storage/buffer/bufmgr.c
parent6575920fa565419471b4a0ca6c1a6ec87ff8c838 (diff)
downloadpostgresql-ffae5cc5a6024b4e25ec920ed5c4dfac649605f8.tar.gz
postgresql-ffae5cc5a6024b4e25ec920ed5c4dfac649605f8.zip
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.
Diffstat (limited to 'src/backend/storage/buffer/bufmgr.c')
-rw-r--r--src/backend/storage/buffer/bufmgr.c25
1 files changed, 21 insertions, 4 deletions
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 147b2ef8d8b..aaa0dff6843 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.210 2006/09/17 22:16:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.211 2006/09/25 22:01:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -175,9 +175,26 @@ ReadBuffer(Relation reln, BlockNumber blockNum)
/*
* We get here only in the corner case where we are trying to extend
* the relation but we found a pre-existing buffer marked BM_VALID.
- * (This can happen because mdread doesn't complain about reads
- * beyond EOF --- which is arguably bogus, but changing it seems
- * tricky.) We *must* do smgrextend before succeeding, else the
+ * This can happen because mdread doesn't complain about reads beyond
+ * EOF --- which is arguably bogus, but changing it seems tricky ---
+ * and so a previous attempt to read a block just beyond EOF could
+ * have left a "valid" zero-filled buffer. Unfortunately, we have
+ * also seen this case occurring because of buggy Linux kernels that
+ * sometimes return an lseek(SEEK_END) result that doesn't account for
+ * a recent write. In that situation, the pre-existing buffer would
+ * contain valid data that we don't want to overwrite. Since the
+ * legitimate cases should always have left a zero-filled buffer,
+ * complain if not PageIsNew.
+ */
+ bufBlock = isLocalBuf ? LocalBufHdrGetBlock(bufHdr) : BufHdrGetBlock(bufHdr);
+ if (!PageIsNew((PageHeader) bufBlock))
+ ereport(ERROR,
+ (errmsg("unexpected data beyond EOF in block %u of relation \"%s\"",
+ blockNum, RelationGetRelationName(reln)),
+ errhint("This has been seen to occur with buggy kernels; consider updating your system.")));
+
+ /*
+ * We *must* do smgrextend before succeeding, else the
* page will not be reserved by the kernel, and the next P_NEW call
* will decide to return the same page. Clear the BM_VALID bit,
* do the StartBufferIO call that BufferAlloc didn't, and proceed.