diff -rcN postgresql_with_9fujii_patch/src/backend/access/transam/xlog.c postgresql_with_patch/src/backend/access/transam/xlog.c
*** postgresql_with_9fujii_patch/src/backend/access/transam/xlog.c	2011-10-06 06:06:19.000000000 +0900
--- postgresql_with_patch/src/backend/access/transam/xlog.c	2011-10-19 07:02:07.000000000 +0900
***************
*** 364,369 ****
--- 364,372 ----
  	bool		exclusiveBackup;
  	int			nonExclusiveBackups;
  	XLogRecPtr	lastBackupStart;
+ 
+ 	/* the startup or the walwriter is logged to its own FPW */
+ 	bool		fullPageWrites;
  } XLogCtlInsert;
  
  /*
***************
*** 453,458 ****
--- 456,464 ----
  	bool		recoveryPause;
  
  	slock_t		info_lck;		/* locks shared variables shown above */
+ 
+ 	/* latest LSN that has recovered a WAL which fpw is 'off' */
+ 	XLogRecPtr	lastFpwDisabledLSN;
  } XLogCtlData;
  
  static XLogCtlData *XLogCtl = NULL;
***************
*** 759,769 ****
  
  	/*
  	 * Decide if we need to do full-page writes in this XLOG record: true if
! 	 * full_page_writes is on or we have a PITR request for it.  Since we
! 	 * don't yet have the insert lock, forcePageWrites could change under us,
! 	 * but we'll recheck it once we have the lock.
  	 */
! 	doPageWrites = fullPageWrites || Insert->forcePageWrites;
  
  	INIT_CRC32(rdata_crc);
  	len = 0;
--- 765,776 ----
  
  	/*
  	 * Decide if we need to do full-page writes in this XLOG record: true if
! 	 * full_page_writes in shared-memory is on or we have a PITR request for
! 	 * it.  Since we don't yet have the insert lock, fullPageWrites or
! 	 * forcePageWrites could change under us, but we'll recheck it once we
! 	 * have the lock.
  	 */
! 	doPageWrites = Insert->fullPageWrites || Insert->forcePageWrites;
  
  	INIT_CRC32(rdata_crc);
  	len = 0;
***************
*** 904,915 ****
  	}
  
  	/*
! 	 * Also check to see if forcePageWrites was just turned on; if we weren't
! 	 * already doing full-page writes then go back and recompute. (If it was
! 	 * just turned off, we could recompute the record without full pages, but
! 	 * we choose not to bother.)
  	 */
! 	if (Insert->forcePageWrites && !doPageWrites)
  	{
  		/* Oops, must redo it with full-page data */
  		LWLockRelease(WALInsertLock);
--- 911,922 ----
  	}
  
  	/*
! 	 * Also check to see if fullPageWrites or forcePageWrites was just
! 	 * turned on; if we weren't already doing full-page writes then go back
! 	 * and recompute. (If it was just turned off, we could recompute the
! 	 * record without full pages, but we choose not to bother.)
  	 */
! 	if ((Insert->fullPageWrites || Insert->forcePageWrites) && !doPageWrites)
  	{
  		/* Oops, must redo it with full-page data */
  		LWLockRelease(WALInsertLock);
***************
*** 7001,7006 ****
--- 7008,7020 ----
  	XLogReportParameters();
  
  	/*
+ 	 * The startup updates FPW after REDO. ReportFpwParameters() is called
+ 	 * here because it is not called on checkpoint after REDO.
+ 	 * It is safe because we cannot update data during the startup running.
+ 	 */
+ 	ReportFpwParameters(REPORT_ON_STARTUP);
+ 
+ 	/*
  	 * All done.  Allow backends to write WAL.	(Although the bool flag is
  	 * probably atomic in itself, we use the info_lck here to ensure that
  	 * there are no race conditions concerning visibility of other recent
***************
*** 7856,7862 ****
--- 7870,7885 ----
  	 * Update checkPoint.nextXid since we have a later value
  	 */
  	if (!shutdown && XLogStandbyInfoActive())
+ 	{
  		LogStandbySnapshot(&checkPoint.oldestActiveXid, &checkPoint.nextXid);
+ 
+ 		/*
+ 		 * The bgwriter writes WAL of FPW at checkpoint. But does not at shutdown.
+ 		 * Because ReportFpwParameters() is always called at the end of startup
+ 		 * process, it does not need to be called at shutdown.
+ 		 */
+ 		ReportFpwParameters(REPORT_ON_BGWRITER);
+ 	}
  	else
  		checkPoint.oldestActiveXid = InvalidTransactionId;
  
***************
*** 8636,8641 ****
--- 8659,8681 ----
  		/* Check to see if any changes to max_connections give problems */
  		CheckRequiredParameterValues();
  	}
+ 	else if (info == XLOG_FPW_CHANGE)
+ 	{
+ 		/* use volatile pointer to prevent code rearrangement */
+ 		volatile XLogCtlData *xlogctl = XLogCtl;
+ 
+ 		bool fpw;
+ 
+ 		memcpy(&fpw, XLogRecGetData(record), sizeof(fpw));
+ 
+ 		/* record the LSN when FPW is false on master */
+ 		if (!fpw)
+ 		{
+ 			SpinLockAcquire(&xlogctl->info_lck);
+ 			xlogctl->lastFpwDisabledLSN = lsn;
+ 			SpinLockRelease(&xlogctl->info_lck);
+ 		}
+ 	}
  }
  
  void
***************
*** 8717,8722 ****
--- 8757,8770 ----
  						 xlrec.max_locks_per_xact,
  						 wal_level_str);
  	}
+ 	else if (info == XLOG_FPW_CHANGE)
+ 	{
+ 		bool fpw;
+ 
+ 		memcpy(&fpw, rec, sizeof(fpw));
+ 		appendStringInfo(buf, "fpw change: full_page_writes=%s",
+ 						 fpw ? "true" : "false");
+ 	}
  	else
  		appendStringInfo(buf, "UNKNOWN");
  }
***************
*** 8933,8938 ****
--- 8981,8987 ----
  	bool		recovery_in_progress = false;
  	XLogRecPtr	checkpointloc;
  	XLogRecPtr	startpoint;
+ 	XLogRecPtr	lastFpwDisabledLSN;
  	pg_time_t	stamp_time;
  	char		strfbuf[128];
  	char		xlogfilename[MAXFNAMELEN];
***************
*** 9089,9094 ****
--- 9138,9161 ----
  				gotUniqueStartpoint = true;
  		} while (!gotUniqueStartpoint);
  
+ 		/*
+ 		 * check whether the master's FPW is 'off' since latest CHECKPOINT.
+ 		 */
+ 		if (recovery_in_progress)
+ 		{
+ 			/* use volatile pointer to prevent code rearrangement */
+ 			volatile XLogCtlData *xlogctl = XLogCtl;
+ 
+ 			SpinLockAcquire(&xlogctl->info_lck);
+ 			lastFpwDisabledLSN = xlogctl->lastFpwDisabledLSN;
+ 			SpinLockRelease(&xlogctl->info_lck);
+ 
+ 			if (XLByteLE(startpoint, lastFpwDisabledLSN))
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ 						 errmsg("WAL generated with full_page_writes=off was replayed since latest checkpoint")));
+ 		}
+ 
  		XLByteToSeg(startpoint, _logId, _logSeg);
  		XLogFileName(xlogfilename, ThisTimeLineID, _logId, _logSeg);
  
***************
*** 9233,9238 ****
--- 9300,9306 ----
  	bool		recovery_in_progress = false;
  	XLogRecPtr	startpoint;
  	XLogRecPtr	stoppoint;
+ 	XLogRecPtr	lastFpwDisabledLSN;
  	XLogRecData rdata;
  	pg_time_t	stamp_time;
  	char		strfbuf[128];
***************
*** 9372,9377 ****
--- 9440,9461 ----
  						"though pg_start_backup() was executed during recovery"),
  				 errhint("The database backup will not be usable.")));
  
+ 	/* check whether the master's FPW is 'off' since pg_start_backup. */
+ 	if (recovery_in_progress)
+ 	{
+ 		/* use volatile pointer to prevent code rearrangement */
+ 		volatile XLogCtlData *xlogctl = XLogCtl;
+ 
+ 		SpinLockAcquire(&xlogctl->info_lck);
+ 		lastFpwDisabledLSN = xlogctl->lastFpwDisabledLSN;
+ 		SpinLockRelease(&xlogctl->info_lck);
+ 
+ 		if (XLByteLE(startpoint, lastFpwDisabledLSN))
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ 					  errmsg("WAL generated with full_page_writes=off was replayed during online backup")));
+ 	}
+ 
  	/*
  	 * During recovery, we don't write an end-of-backup record. We can
  	 * assume that pg_control was backed up just before pg_stop_backup()
***************
*** 10743,10745 ****
--- 10827,10879 ----
  {
  	SetLatch(&XLogCtl->recoveryWakeupLatch);
  }
+ 
+ /*
+  * Insert a WAL of XLOG_FPW_CHANGE or update to the shared memory.
+  * The called timing is at checkpoint, at the end of startup or at receiving
+  * SIGHUP on walwriter.
+  * checkpoint: insert, but not update.
+  * startup: insert and update.
+  * walwriter: insert and update if FPW was changed.
+  */
+ void
+ ReportFpwParameters(int updatetiming)
+ {
+ 	bool fpw = fullPageWrites;
+ 
+ 	if (updatetiming == REPORT_ON_BGWRITER)
+ 	{
+ 		LWLockAcquire(WALInsertLock, LW_EXCLUSIVE);
+ 		fpw = XLogCtl->Insert.fullPageWrites;
+ 		LWLockRelease(WALInsertLock);
+ 	}
+ 
+ 	if (updatetiming <= REPORT_ON_STARTUP ||
+ 		(updatetiming == REPORT_ON_WALWRITER && fpw != XLogCtl->Insert.fullPageWrites))
+ 	{
+ 		/*
+ 		 * insert own fpw to a WAL. However, it does not perform
+ 		 * when wal_level is not 'hotstandby' or fpw is same as shared-memory.
+ 		 */
+ 		if (XLogStandbyInfoActive())
+ 		{
+ 			XLogRecData rdata;
+ 			bool record = fullPageWrites;
+ 
+ 			rdata.buffer = InvalidBuffer;
+ 			rdata.data = (char *) &record;
+ 			rdata.len = sizeof(record);
+ 			rdata.next = NULL;
+ 
+ 			XLogInsert(RM_XLOG_ID, XLOG_FPW_CHANGE, &rdata);
+ 		}
+ 
+ 		/* update own fpw in shared-memory when it has managed fpw */
+ 		if (updatetiming >= REPORT_ON_STARTUP)
+ 		{
+ 			LWLockAcquire(WALInsertLock, LW_EXCLUSIVE);
+ 			XLogCtl->Insert.fullPageWrites = fullPageWrites;
+ 			LWLockRelease(WALInsertLock);
+ 		}
+ 	}
+ }
diff -rcN postgresql_with_9fujii_patch/src/backend/postmaster/walwriter.c postgresql_with_patch/src/backend/postmaster/walwriter.c
*** postgresql_with_9fujii_patch/src/backend/postmaster/walwriter.c	2011-10-06 06:05:45.000000000 +0900
--- postgresql_with_patch/src/backend/postmaster/walwriter.c	2011-10-19 07:02:07.000000000 +0900
***************
*** 216,221 ****
--- 216,228 ----
  	PG_SETMASK(&UnBlockSig);
  
  	/*
+ 	 * After the startup process, the walwriter manages the FPW. Because
+ 	 * the walwriter may have not received a SIGHUP then, it updates the FPW
+ 	 * when wal_level is hotstandby.
+ 	 */
+ 	ReportFpwParameters(REPORT_ON_WALWRITER);
+ 
+ 	/*
  	 * Loop forever
  	 */
  	for (;;)
***************
*** 236,241 ****
--- 243,254 ----
  		{
  			got_SIGHUP = false;
  			ProcessConfigFile(PGC_SIGHUP);
+ 
+ 			/*
+ 			 * The walwriter manages the FPW. When the walwriter has received
+ 			 * a SIGHUP, when wal_level is hotstandby, it updates the FPW.
+ 			 */
+ 			ReportFpwParameters(REPORT_ON_WALWRITER);
  		}
  		if (shutdown_requested)
  		{
diff -rcN postgresql_with_9fujii_patch/src/include/access/xlog.h postgresql_with_patch/src/include/access/xlog.h
*** postgresql_with_9fujii_patch/src/include/access/xlog.h	2011-10-06 06:05:45.000000000 +0900
--- postgresql_with_patch/src/include/access/xlog.h	2011-10-19 07:02:07.000000000 +0900
***************
*** 208,213 ****
--- 208,224 ----
  } WalLevel;
  extern int	wal_level;
  
+ /*
+  * The place of updating xlog parameter.
+  * If it is backend then this means a timing for CHECKPOINT.
+  */
+ typedef enum
+ {
+ 	REPORT_ON_BGWRITER = 0,
+ 	REPORT_ON_STARTUP,
+ 	REPORT_ON_WALWRITER
+ } XLogParemeterUpdate;
+ 
  #define XLogArchivingActive()	(XLogArchiveMode && wal_level >= WAL_LEVEL_ARCHIVE)
  #define XLogArchiveCommandSet() (XLogArchiveCommand[0] != '\0')
  
***************
*** 316,321 ****
--- 327,333 ----
  extern void StartupProcessMain(void);
  extern bool CheckPromoteSignal(void);
  extern void WakeupRecovery(void);
+ extern void ReportFpwParameters(int updatetiming);
  
  /*
   * Starting/stopping a base backup
diff -rcN postgresql_with_9fujii_patch/src/include/catalog/pg_control.h postgresql_with_patch/src/include/catalog/pg_control.h
*** postgresql_with_9fujii_patch/src/include/catalog/pg_control.h	2011-10-06 06:06:19.000000000 +0900
--- postgresql_with_patch/src/include/catalog/pg_control.h	2011-10-19 07:02:07.000000000 +0900
***************
*** 60,65 ****
--- 60,66 ----
  #define XLOG_BACKUP_END					0x50
  #define XLOG_PARAMETER_CHANGE			0x60
  #define XLOG_RESTORE_POINT				0x70
+ #define XLOG_FPW_CHANGE					0x80
  
  
  /*
