1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-11 04:22:52 +03:00

Back-patch changes to validate page header fields immediately after

reading in any page.  Also back-port the zero_damaged_pages boolean
that determines what to do about it.
This commit is contained in:
Tom Lane
2003-04-04 00:32:57 +00:00
parent a880697f09
commit 8fe728b009
6 changed files with 101 additions and 11 deletions

View File

@@ -1,5 +1,5 @@
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.147.2.6 2003/01/11 05:04:26 momjian Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.147.2.7 2003/04/04 00:32:57 tgl Exp $
--> -->
<Chapter Id="runtime"> <Chapter Id="runtime">
@@ -1525,10 +1525,10 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir'
</para> </para>
<para> <para>
It should be noted that the performance penalty of doing It should be noted that the performance penalty of having
<function>fsync</>s is considerably less in <function>fsync</> on is considerably less in
<productname>PostgreSQL</> version 7.1 and later. If you <productname>PostgreSQL</> version 7.1 and later. If you
previously suppressed <function>fsync</>s for performance previously suppressed <function>fsync</> for performance
reasons, you may wish to reconsider your choice. reasons, you may wish to reconsider your choice.
</para> </para>
@@ -2057,6 +2057,26 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir'
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>ZERO_DAMAGED_PAGES</varname> (<type>boolean</type>)</term>
<listitem>
<para>
Detection of a damaged page header normally causes
<productname>PostgreSQL</> to report an error, aborting the current
transaction. Setting <varname>zero_damaged_pages</> to true causes
the system to instead report a warning, zero out the damaged page,
and continue processing. This behavior <emphasis>will destroy data</>,
namely all the rows on the damaged page. But it allows you to get
past the error and retrieve rows from any undamaged pages that may
be present in the table. So it is useful for recovering data if
corruption has occurred due to hardware or software error. You should
generally not set this true until you have given up hope of recovering
data from the damaged page(s) of a table. The
default setting is off, and it can only be changed by a superuser.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</para> </para>
</sect2> </sect2>

View File

@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.133 2002/09/14 19:59:20 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.133.2.1 2003/04/04 00:32:57 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@@ -49,6 +49,7 @@
#include "miscadmin.h" #include "miscadmin.h"
#include "storage/buf_internals.h" #include "storage/buf_internals.h"
#include "storage/bufmgr.h" #include "storage/bufmgr.h"
#include "storage/bufpage.h"
#include "storage/proc.h" #include "storage/proc.h"
#include "storage/smgr.h" #include "storage/smgr.h"
#include "utils/relcache.h" #include "utils/relcache.h"
@@ -59,6 +60,10 @@
(*((XLogRecPtr*) MAKE_PTR((bufHdr)->data))) (*((XLogRecPtr*) MAKE_PTR((bufHdr)->data)))
/* GUC variable */
bool zero_damaged_pages = false;
static void WaitIO(BufferDesc *buf); static void WaitIO(BufferDesc *buf);
static void StartBufferIO(BufferDesc *buf, bool forInput); static void StartBufferIO(BufferDesc *buf, bool forInput);
static void TerminateBufferIO(BufferDesc *buf); static void TerminateBufferIO(BufferDesc *buf);
@@ -217,6 +222,20 @@ ReadBufferInternal(Relation reln, BlockNumber blockNum,
{ {
status = smgrread(DEFAULT_SMGR, reln, blockNum, status = smgrread(DEFAULT_SMGR, reln, blockNum,
(char *) MAKE_PTR(bufHdr->data)); (char *) MAKE_PTR(bufHdr->data));
/* check for garbage data */
if (status == SM_SUCCESS &&
!PageHeaderIsValid((PageHeader) MAKE_PTR(bufHdr->data)))
{
if (zero_damaged_pages)
{
elog(WARNING, "Invalid page header in block %u of %s; zeroing out page",
blockNum, RelationGetRelationName(reln));
MemSet((char *) MAKE_PTR(bufHdr->data), 0, BLCKSZ);
}
else
elog(ERROR, "Invalid page header in block %u of %s",
blockNum, RelationGetRelationName(reln));
}
} }
if (isLocalBuf) if (isLocalBuf)

View File

@@ -8,14 +8,12 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/page/bufpage.c,v 1.50 2002/09/04 20:31:26 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/page/bufpage.c,v 1.50.2.1 2003/04/04 00:32:57 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
#include <sys/file.h>
#include "storage/bufpage.h" #include "storage/bufpage.h"
@@ -48,6 +46,51 @@ PageInit(Page page, Size pageSize, Size specialSize)
} }
/*
* PageHeaderIsValid
* Check that the header fields of a page appear valid.
*
* This is called when a page has just been read in from disk. The idea is
* to cheaply detect trashed pages before we go nuts following bogus item
* pointers, testing invalid transaction identifiers, etc.
*
* It turns out to be necessary to allow zeroed pages here too. Even though
* this routine is *not* called when deliberately adding a page to a relation,
* there are scenarios in which a zeroed page might be found in a table.
* (Example: a backend extends a relation, then crashes before it can write
* any WAL entry about the new page. The kernel will already have the
* zeroed page in the file, and it will stay that way after restart.) So we
* allow zeroed pages here, and are careful that the page access macros
* treat such a page as empty and without free space. Eventually, VACUUM
* will clean up such a page and make it usable.
*/
bool
PageHeaderIsValid(PageHeader page)
{
char *pagebytes;
int i;
/* Check normal case */
if (PageGetPageSize(page) == BLCKSZ &&
PageGetPageLayoutVersion(page) == PG_PAGE_LAYOUT_VERSION &&
page->pd_lower >= SizeOfPageHeaderData &&
page->pd_lower <= page->pd_upper &&
page->pd_upper <= page->pd_special &&
page->pd_special <= BLCKSZ &&
page->pd_special == MAXALIGN(page->pd_special))
return true;
/* Check all-zeroes case */
pagebytes = (char *) page;
for (i = 0; i < BLCKSZ; i++)
{
if (pagebytes[i] != 0)
return false;
}
return true;
}
/* ---------------- /* ----------------
* PageAddItem * PageAddItem
* *

View File

@@ -5,7 +5,7 @@
* command, configuration file, and command line options. * command, configuration file, and command line options.
* See src/backend/utils/misc/README for more information. * See src/backend/utils/misc/README for more information.
* *
* $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.99.2.4 2003/01/28 18:04:13 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.99.2.5 2003/04/04 00:32:57 tgl Exp $
* *
* Copyright 2000 by PostgreSQL Global Development Group * Copyright 2000 by PostgreSQL Global Development Group
* Written by Peter Eisentraut <peter_e@gmx.net>. * Written by Peter Eisentraut <peter_e@gmx.net>.
@@ -352,6 +352,10 @@ static struct config_bool
{"fsync", PGC_SIGHUP}, &enableFsync, {"fsync", PGC_SIGHUP}, &enableFsync,
true, NULL, NULL true, NULL, NULL
}, },
{
{"zero_damaged_pages", PGC_SUSET}, &zero_damaged_pages,
false, NULL, NULL
},
{ {
{"silent_mode", PGC_POSTMASTER}, &SilentMode, {"silent_mode", PGC_POSTMASTER}, &SilentMode,
false, NULL, NULL false, NULL, NULL

View File

@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: bufmgr.h,v 1.66 2002/10/22 20:00:48 petere Exp $ * $Id: bufmgr.h,v 1.66.2.1 2003/04/04 00:32:57 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@@ -25,6 +25,9 @@ typedef void *Block;
/* in globals.c ... this duplicates miscadmin.h */ /* in globals.c ... this duplicates miscadmin.h */
extern DLLIMPORT int NBuffers; extern DLLIMPORT int NBuffers;
/* in bufmgr.c */
extern bool zero_damaged_pages;
/* in buf_init.c */ /* in buf_init.c */
extern DLLIMPORT Block *BufferBlockPointers; extern DLLIMPORT Block *BufferBlockPointers;
extern long *PrivateRefCount; extern long *PrivateRefCount;

View File

@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: bufpage.h,v 1.53 2002/09/04 20:31:45 momjian Exp $ * $Id: bufpage.h,v 1.53.2.1 2003/04/04 00:32:57 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@@ -339,6 +339,7 @@ typedef PageHeaderData *PageHeader;
*/ */
extern void PageInit(Page page, Size pageSize, Size specialSize); extern void PageInit(Page page, Size pageSize, Size specialSize);
extern bool PageHeaderIsValid(PageHeader page);
extern OffsetNumber PageAddItem(Page page, Item item, Size size, extern OffsetNumber PageAddItem(Page page, Item item, Size size,
OffsetNumber offsetNumber, ItemIdFlags flags); OffsetNumber offsetNumber, ItemIdFlags flags);
extern Page PageGetTempPage(Page page, Size specialSize); extern Page PageGetTempPage(Page page, Size specialSize);