diff --git a/contrib/bloom/blinsert.c b/contrib/bloom/blinsert.c
new file mode 100644
index 330d7fd..9d2298b
*** a/contrib/bloom/blinsert.c
--- b/contrib/bloom/blinsert.c
*************** flushCachedPage(Relation index, BloomBui
*** 49,55 ****
  	GenericXLogState *state;
  
  	state = GenericXLogStart(index);
! 	page = GenericXLogRegister(state, buffer, true);
  	memcpy(page, buildstate->data, BLCKSZ);
  	GenericXLogFinish(state);
  	UnlockReleaseBuffer(buffer);
--- 49,55 ----
  	GenericXLogState *state;
  
  	state = GenericXLogStart(index);
! 	page = GenericXLogRegisterBuffer(state, buffer, true);
  	memcpy(page, buildstate->data, BLCKSZ);
  	GenericXLogFinish(state);
  	UnlockReleaseBuffer(buffer);
*************** blinsert(Relation index, Datum *values, 
*** 221,227 ****
  		LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
  
  		state = GenericXLogStart(index);
! 		page = GenericXLogRegister(state, buffer, false);
  
  		if (BloomPageAddItem(&blstate, page, itup))
  		{
--- 221,227 ----
  		LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
  
  		state = GenericXLogStart(index);
! 		page = GenericXLogRegisterBuffer(state, buffer, false);
  
  		if (BloomPageAddItem(&blstate, page, itup))
  		{
*************** blinsert(Relation index, Datum *values, 
*** 268,274 ****
  		state = GenericXLogStart(index);
  
  		/* get modifiable copy of metapage */
! 		metaPage = GenericXLogRegister(state, metaBuffer, false);
  		metaData = BloomPageGetMeta(metaPage);
  
  		if (nStart >= metaData->nEnd)
--- 268,274 ----
  		state = GenericXLogStart(index);
  
  		/* get modifiable copy of metapage */
! 		metaPage = GenericXLogRegisterBuffer(state, metaBuffer, false);
  		metaData = BloomPageGetMeta(metaPage);
  
  		if (nStart >= metaData->nEnd)
*************** blinsert(Relation index, Datum *values, 
*** 279,285 ****
  
  		buffer = ReadBuffer(index, blkno);
  		LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
! 		page = GenericXLogRegister(state, buffer, false);
  
  		if (BloomPageAddItem(&blstate, page, itup))
  		{
--- 279,285 ----
  
  		buffer = ReadBuffer(index, blkno);
  		LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
! 		page = GenericXLogRegisterBuffer(state, buffer, false);
  
  		if (BloomPageAddItem(&blstate, page, itup))
  		{
*************** blinsert(Relation index, Datum *values, 
*** 305,311 ****
  	 */
  	buffer = BloomNewBuffer(index);
  
! 	page = GenericXLogRegister(state, buffer, true);
  	BloomInitPage(page, 0);
  
  	if (!BloomPageAddItem(&blstate, page, itup))
--- 305,311 ----
  	 */
  	buffer = BloomNewBuffer(index);
  
! 	page = GenericXLogRegisterBuffer(state, buffer, true);
  	BloomInitPage(page, 0);
  
  	if (!BloomPageAddItem(&blstate, page, itup))
diff --git a/contrib/bloom/blutils.c b/contrib/bloom/blutils.c
new file mode 100644
index 6c7dc1d..be14fd7
*** a/contrib/bloom/blutils.c
--- b/contrib/bloom/blutils.c
*************** BloomInitMetapage(Relation index)
*** 417,423 ****
  
  	/* Initialize contents of meta page */
  	state = GenericXLogStart(index);
! 	metaPage = GenericXLogRegister(state, metaBuffer, true);
  
  	BloomInitPage(metaPage, BLOOM_META);
  	metadata = BloomPageGetMeta(metaPage);
--- 417,423 ----
  
  	/* Initialize contents of meta page */
  	state = GenericXLogStart(index);
! 	metaPage = GenericXLogRegisterBuffer(state, metaBuffer, true);
  
  	BloomInitPage(metaPage, BLOOM_META);
  	metadata = BloomPageGetMeta(metaPage);
diff --git a/contrib/bloom/blvacuum.c b/contrib/bloom/blvacuum.c
new file mode 100644
index ee40ebb..2a1e8a5
*** a/contrib/bloom/blvacuum.c
--- b/contrib/bloom/blvacuum.c
*************** blbulkdelete(IndexVacuumInfo *info, Inde
*** 65,71 ****
  
  		LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
  		gxlogState = GenericXLogStart(index);
! 		page = GenericXLogRegister(gxlogState, buffer, false);
  
  		if (BloomPageIsDeleted(page))
  		{
--- 65,71 ----
  
  		LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
  		gxlogState = GenericXLogStart(index);
! 		page = GenericXLogRegisterBuffer(gxlogState, buffer, false);
  
  		if (BloomPageIsDeleted(page))
  		{
*************** blbulkdelete(IndexVacuumInfo *info, Inde
*** 145,151 ****
  		LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
  
  		gxlogState = GenericXLogStart(index);
! 		page = GenericXLogRegister(gxlogState, buffer, false);
  
  		metaData = BloomPageGetMeta(page);
  		memcpy(metaData->notFullPage, notFullPage, sizeof(BlockNumber) * countPage);
--- 145,151 ----
  		LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
  
  		gxlogState = GenericXLogStart(index);
! 		page = GenericXLogRegisterBuffer(gxlogState, buffer, false);
  
  		metaData = BloomPageGetMeta(page);
  		memcpy(metaData->notFullPage, notFullPage, sizeof(BlockNumber) * countPage);
diff --git a/doc/src/sgml/generic-wal.sgml b/doc/src/sgml/generic-wal.sgml
new file mode 100644
index 2398d86..b644bfb
*** a/doc/src/sgml/generic-wal.sgml
--- b/doc/src/sgml/generic-wal.sgml
***************
*** 31,45 ****
  
      <listitem>
       <para>
!       <function>page = GenericXLogRegister(state, buffer, isNew)</> &mdash;
!       register a buffer to be modified within the current generic WAL
        record.  This function returns a pointer to a temporary copy of the
        buffer's page, where modifications should be made.  (Do not modify the
!       buffer's contents directly.)  The third argument indicates if the page
!       is new; if true, this will result in a full-page image rather than a
!       delta update being included in the WAL record.
!       <function>GenericXLogRegister</> can be repeated if the WAL-logged
!       action needs to modify multiple pages.
       </para>
      </listitem>
  
--- 31,46 ----
  
      <listitem>
       <para>
!       <function>page = GenericXLogRegisterBuffer(state, buffer, flags)</>
!       &mdash; register a buffer to be modified within the current generic WAL
        record.  This function returns a pointer to a temporary copy of the
        buffer's page, where modifications should be made.  (Do not modify the
!       buffer's contents directly.)  The third argument contains set of flags
!       indicating how buffer should be logged.  When
!       <literal>GENERIC_XLOG_FULL_IMAGE</> is set then a full-page image rather
!       than a delta update being included in the WAL record.  There could appear
!       more flags in future.  <function>GenericXLogRegisterBuffer</> can be
!       repeated if the WAL-logged action needs to modify multiple pages.
       </para>
      </listitem>
  
***************
*** 71,83 ****
     <itemizedlist>
      <listitem>
       <para>
!       No direct modifications of buffers are allowed!  All modifications
!       must be done in copies acquired from <function>GenericXLogRegister()</>.
        In other words, code that makes generic WAL records should never call
        <function>BufferGetPage()</> for itself.  However, it remains the
        caller's responsibility to pin/unpin and lock/unlock the buffers at
        appropriate times.  Exclusive lock must be held on each target buffer
!       from before <function>GenericXLogRegister()</> until after
        <function>GenericXLogFinish()</>.
       </para>
      </listitem>
--- 72,84 ----
     <itemizedlist>
      <listitem>
       <para>
!       No direct modifications of buffers are allowed!  All modifications must
!       be done in copies acquired from <function>GenericXLogRegisterBuffer()</>.
        In other words, code that makes generic WAL records should never call
        <function>BufferGetPage()</> for itself.  However, it remains the
        caller's responsibility to pin/unpin and lock/unlock the buffers at
        appropriate times.  Exclusive lock must be held on each target buffer
!       from before <function>GenericXLogRegisterBuffer()</> until after
        <function>GenericXLogFinish()</>.
       </para>
      </listitem>
diff --git a/src/backend/access/transam/generic_xlog.c b/src/backend/access/transam/generic_xlog.c
new file mode 100644
index 072838a..d2fc910
*** a/src/backend/access/transam/generic_xlog.c
--- b/src/backend/access/transam/generic_xlog.c
***************
*** 50,56 ****
  typedef struct
  {
  	Buffer		buffer;			/* registered buffer */
! 	bool		fullImage;		/* are we taking a full image of this page? */
  	int			deltaLen;		/* space consumed in delta field */
  	char		image[BLCKSZ];	/* copy of page image for modification */
  	char		delta[MAX_DELTA_SIZE];	/* delta between page images */
--- 50,56 ----
  typedef struct
  {
  	Buffer		buffer;			/* registered buffer */
! 	uint32		flags;			/* buffer flags  */
  	int			deltaLen;		/* space consumed in delta field */
  	char		image[BLCKSZ];	/* copy of page image for modification */
  	char		delta[MAX_DELTA_SIZE];	/* delta between page images */
*************** GenericXLogStart(Relation relation)
*** 282,288 ****
   * If the buffer is already registered, just return its existing entry.
   */
  Page
! GenericXLogRegister(GenericXLogState *state, Buffer buffer, bool isNew)
  {
  	int			block_id;
  
--- 282,288 ----
   * If the buffer is already registered, just return its existing entry.
   */
  Page
! GenericXLogRegisterBuffer(GenericXLogState *state, Buffer buffer, uint16 flags)
  {
  	int			block_id;
  
*************** GenericXLogRegister(GenericXLogState *st
*** 295,301 ****
  		{
  			/* Empty slot, so use it (there cannot be a match later) */
  			page->buffer = buffer;
! 			page->fullImage = isNew;
  			memcpy(page->image,
  				   BufferGetPage(buffer, NULL, NULL, BGP_NO_SNAPSHOT_TEST),
  				   BLCKSZ);
--- 295,301 ----
  		{
  			/* Empty slot, so use it (there cannot be a match later) */
  			page->buffer = buffer;
! 			page->flags = flags;
  			memcpy(page->image,
  				   BufferGetPage(buffer, NULL, NULL, BGP_NO_SNAPSHOT_TEST),
  				   BLCKSZ);
*************** GenericXLogFinish(GenericXLogState *stat
*** 345,351 ****
  			page = BufferGetPage(pageData->buffer, NULL, NULL,
  								 BGP_NO_SNAPSHOT_TEST);
  
! 			if (pageData->fullImage)
  			{
  				/* A full page image does not require anything special */
  				memcpy(page, pageData->image, BLCKSZ);
--- 345,351 ----
  			page = BufferGetPage(pageData->buffer, NULL, NULL,
  								 BGP_NO_SNAPSHOT_TEST);
  
! 			if (pageData->flags & GENERIC_XLOG_FULL_IMAGE)
  			{
  				/* A full page image does not require anything special */
  				memcpy(page, pageData->image, BLCKSZ);
diff --git a/src/include/access/generic_xlog.h b/src/include/access/generic_xlog.h
new file mode 100644
index 01743e3..c422955
*** a/src/include/access/generic_xlog.h
--- b/src/include/access/generic_xlog.h
***************
*** 22,35 ****
  
  #define MAX_GENERIC_XLOG_PAGES	XLR_NORMAL_MAX_BLOCK_ID
  
  /* state of generic xlog record construction */
  struct GenericXLogState;
  typedef struct GenericXLogState GenericXLogState;
  
  /* API for construction of generic xlog records */
  extern GenericXLogState *GenericXLogStart(Relation relation);
! extern Page GenericXLogRegister(GenericXLogState *state, Buffer buffer,
! 					bool isNew);
  extern XLogRecPtr GenericXLogFinish(GenericXLogState *state);
  extern void GenericXLogAbort(GenericXLogState *state);
  
--- 22,38 ----
  
  #define MAX_GENERIC_XLOG_PAGES	XLR_NORMAL_MAX_BLOCK_ID
  
+ /* Flags for GenericXLogRegisterBuffer */
+ #define GENERIC_XLOG_FULL_IMAGE	1
+ 
  /* state of generic xlog record construction */
  struct GenericXLogState;
  typedef struct GenericXLogState GenericXLogState;
  
  /* API for construction of generic xlog records */
  extern GenericXLogState *GenericXLogStart(Relation relation);
! extern Page GenericXLogRegisterBuffer(GenericXLogState *state, Buffer buffer,
! 					uint16 flags);
  extern XLogRecPtr GenericXLogFinish(GenericXLogState *state);
  extern void GenericXLogAbort(GenericXLogState *state);
  
