diff -cr pgsql/src/backend/storage/buffer/bufmgr.c pgsql-blkcrc/src/backend/storage/buffer/bufmgr.c
*** pgsql/src/backend/storage/buffer/bufmgr.c	Wed Sep 17 09:15:55 2008
--- pgsql-blkcrc/src/backend/storage/buffer/bufmgr.c	Thu Oct  2 00:34:37 2008
***************
*** 48,54 ****
  
  /* Note: these two macros only work on shared buffers, not local ones! */
  #define BufHdrGetBlock(bufHdr)	((Block) (BufferBlocks + ((Size) (bufHdr)->buf_id) * BLCKSZ))
! #define BufferGetLSN(bufHdr)	(*((XLogRecPtr*) BufHdrGetBlock(bufHdr)))
  
  /* Note: this macro only works on local buffers, not shared ones! */
  #define LocalBufHdrGetBlock(bufHdr) \
--- 48,54 ----
  
  /* Note: these two macros only work on shared buffers, not local ones! */
  #define BufHdrGetBlock(bufHdr)	((Block) (BufferBlocks + ((Size) (bufHdr)->buf_id) * BLCKSZ))
! #define BufferGetLSN(bufHdr)	(PageGetLSN(BufHdrGetBlock(bufHdr)))
  
  /* Note: this macro only works on local buffers, not shared ones! */
  #define LocalBufHdrGetBlock(bufHdr) \
diff -cr pgsql/src/backend/storage/page/bufpage.c pgsql-blkcrc/src/backend/storage/page/bufpage.c
*** pgsql/src/backend/storage/page/bufpage.c	Sun Jul 13 17:50:04 2008
--- pgsql-blkcrc/src/backend/storage/page/bufpage.c	Thu Oct  2 01:57:46 2008
***************
*** 41,46 ****
--- 41,47 ----
  	MemSet(p, 0, pageSize);
  
  	/* p->pd_flags = 0;								done by above MemSet */
+ 	p->pd_checksum = 0xdeadbeef;
  	p->pd_lower = SizeOfPageHeaderData;
  	p->pd_upper = pageSize - specialSize;
  	p->pd_special = pageSize - specialSize;
***************
*** 86,92 ****
  
  	/* Check all-zeroes case */
  	pagebytes = (char *) page;
! 	for (i = 0; i < BLCKSZ; i++)
  	{
  		if (pagebytes[i] != 0)
  			return false;
--- 87,93 ----
  
  	/* Check all-zeroes case */
  	pagebytes = (char *) page;
! 	for (i = sizeof(pg_crc32); i < BLCKSZ; i++)
  	{
  		if (pagebytes[i] != 0)
  			return false;
diff -cr pgsql/src/backend/storage/smgr/smgr.c pgsql-blkcrc/src/backend/storage/smgr/smgr.c
*** pgsql/src/backend/storage/smgr/smgr.c	Tue Sep 30 06:52:13 2008
--- pgsql-blkcrc/src/backend/storage/smgr/smgr.c	Thu Oct  2 01:13:50 2008
***************
*** 26,31 ****
--- 26,42 ----
  #include "utils/hsearch.h"
  #include "utils/memutils.h"
  
+ #define SetPageChecksum(buffer)	\
+ 	{										\
+ 		pg_crc32    calc_crc;				\
+ 											\
+ 		INIT_CRC32(calc_crc);				\
+ 		COMP_CRC32(calc_crc, &buffer[sizeof(pg_crc32)], BLCKSZ - sizeof(pg_crc32)); \
+ 		PageSetChecksum(buffer, calc_crc); \
+ 	}
+ 
+ /* Perform block checksumming for corruption detection */
+ bool enable_block_checksums = false;
  
  /*
   * This struct of function pointers defines the API between smgr.c and
***************
*** 503,508 ****
--- 514,525 ----
  smgrextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, 
  		   char *buffer, bool isTemp)
  {
+ 	/* Perform block checksumming for corruption detection */
+ 	if (enable_block_checksums)
+ 	{
+ 		SetPageChecksum(buffer);
+ 	}
+ 
  	(*(smgrsw[reln->smgr_which].smgr_extend)) (reln, forknum, blocknum,
  											   buffer, isTemp);
  }
***************
*** 520,525 ****
--- 537,564 ----
  		 char *buffer)
  {
  	(*(smgrsw[reln->smgr_which].smgr_read)) (reln, forknum, blocknum, buffer);
+ 
+ 	/* Perform block checksumming for corruption detection */
+ 	if (enable_block_checksums)
+ 	{
+ 		pg_crc32    calc_crc;
+ 
+ 		if (PageGetChecksum(buffer) != 0xdeadbeef)
+ 		{
+ 			INIT_CRC32(calc_crc);
+ 			COMP_CRC32(calc_crc, &buffer[sizeof(pg_crc32)], BLCKSZ - sizeof(pg_crc32));
+ 			if (calc_crc != PageGetChecksum(buffer))
+ 			{
+ 				ereport(ERROR,
+ 					(errcode(ERRCODE_DATA_CORRUPTED),
+ 					 errmsg("invalid checksum on read of block %u of relation %u/%u/%u",
+ 							blocknum,
+ 							reln->smgr_rnode.spcNode,
+ 							reln->smgr_rnode.dbNode,
+ 							reln->smgr_rnode.relNode)));
+ 			}
+ 		}
+ 	}
  }
  
  /*
***************
*** 541,546 ****
--- 580,591 ----
  smgrwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, 
  		  char *buffer, bool isTemp)
  {
+ 	/* Perform block checksumming for corruption detection */
+ 	if (enable_block_checksums)
+ 	{
+ 		SetPageChecksum(buffer);
+ 	}
+ 
  	(*(smgrsw[reln->smgr_which].smgr_write)) (reln, forknum, blocknum,
  											  buffer, isTemp);
  }
diff -cr pgsql/src/backend/utils/misc/guc.c pgsql-blkcrc/src/backend/utils/misc/guc.c
*** pgsql/src/backend/utils/misc/guc.c	Tue Sep 30 06:52:13 2008
--- pgsql-blkcrc/src/backend/utils/misc/guc.c	Thu Oct  2 01:10:25 2008
***************
*** 57,62 ****
--- 57,63 ----
  #include "regex/regex.h"
  #include "storage/bufmgr.h"
  #include "storage/fd.h"
+ #include "storage/smgr.h"
  #include "tcop/tcopprot.h"
  #include "tsearch/ts_cache.h"
  #include "utils/builtins.h"
***************
*** 762,767 ****
--- 763,778 ----
  		false, NULL, NULL
  	},
  	{
+ 		{"perform_checksum", PGC_SIGHUP, UNGROUPED,
+ 			gettext_noop("Forces checksumming of blocks to/from disk."),
+ 			gettext_noop("The server will perform a checksum on the block "
+ 				"when read from or written to disk in order to detect storage-related "
+ 				"corruptions.")
+ 		},
+ 		&enable_block_checksums,
+ 		false, NULL, NULL
+ 	},
+ 	{
  		{"log_duration", PGC_SUSET, LOGGING_WHAT,
  			gettext_noop("Logs the duration of each completed SQL statement."),
  			NULL
diff -cr pgsql/src/backend/utils/misc/postgresql.conf.sample pgsql-blkcrc/src/backend/utils/misc/postgresql.conf.sample
*** pgsql/src/backend/utils/misc/postgresql.conf.sample	Tue Sep 30 06:52:13 2008
--- pgsql-blkcrc/src/backend/utils/misc/postgresql.conf.sample	Thu Oct  2 01:06:24 2008
***************
*** 480,485 ****
--- 480,490 ----
  
  #transform_null_equals = off
  
+ #------------------------------------------------------------------------------
+ # CORRUPTION DETECTION
+ #------------------------------------------------------------------------------
+ 
+ #perform_checksum = off		# Perform block checksumming to/from disk
  
  #------------------------------------------------------------------------------
  # CUSTOMIZED OPTIONS
diff -cr pgsql/src/include/storage/bufpage.h pgsql-blkcrc/src/include/storage/bufpage.h
*** pgsql/src/include/storage/bufpage.h	Sun Jul 13 23:22:32 2008
--- pgsql-blkcrc/src/include/storage/bufpage.h	Thu Oct  2 01:01:33 2008
***************
*** 17,22 ****
--- 17,23 ----
  #include "access/xlogdefs.h"
  #include "storage/item.h"
  #include "storage/off.h"
+ #include "utils/pg_crc.h"
  
  /*
   * A postgres disk page is an abstraction layered on top of a postgres
***************
*** 87,92 ****
--- 88,94 ----
   *
   * space management information generic to any page
   *
+  *		pd_checksum	- the checksum of the page
   *		pd_lsn		- identifies xlog record for last change to this page.
   *		pd_tli		- ditto.
   *		pd_flags	- flag bits.
***************
*** 121,127 ****
   */
  typedef struct PageHeaderData
  {
! 	/* XXX LSN is member of *any* block, not only page-organized ones */
  	XLogRecPtr	pd_lsn;			/* LSN: next byte after last byte of xlog
  								 * record for last change to this page */
  	uint16		pd_tli;			/* least significant bits of the TimeLineID
--- 123,130 ----
   */
  typedef struct PageHeaderData
  {
! 	/* XXX CRC & LSN are members of *any* block, not only page-organized ones */
! 	pg_crc32	pd_checksum;    /* The block-level checksum */
  	XLogRecPtr	pd_lsn;			/* LSN: next byte after last byte of xlog
  								 * record for last change to this page */
  	uint16		pd_tli;			/* least significant bits of the TimeLineID
***************
*** 311,316 ****
--- 314,323 ----
  /*
   * Additional macros for access to page headers
   */
+ #define PageGetChecksum(page) \
+ 	(((PageHeader) (page))->pd_checksum)
+ #define PageSetChecksum(page, checksum) \
+ 	(((PageHeader) (page))->pd_checksum = (checksum))
  #define PageGetLSN(page) \
  	(((PageHeader) (page))->pd_lsn)
  #define PageSetLSN(page, lsn) \
diff -cr pgsql/src/include/storage/smgr.h pgsql-blkcrc/src/include/storage/smgr.h
*** pgsql/src/include/storage/smgr.h	Mon Aug 11 07:05:11 2008
--- pgsql-blkcrc/src/include/storage/smgr.h	Thu Oct  2 00:58:09 2008
***************
*** 19,24 ****
--- 19,26 ----
  #include "storage/block.h"
  #include "storage/relfilenode.h"
  
+ /* Perform block checksumming for corruption detection */
+ bool enable_block_checksums;
  
  /*
   * smgr.c maintains a table of SMgrRelation objects, which are essentially

