diff --git a/src/backend/access/nbtree/nbtxlog.c b/src/backend/access/nbtree/nbtxlog.c
index da28e21..33fc022 100644
--- a/src/backend/access/nbtree/nbtxlog.c
+++ b/src/backend/access/nbtree/nbtxlog.c
@@ -423,6 +423,15 @@ btree_xlog_vacuum(XLogReaderState *record)
 		for (blkno = xlrec->lastBlockVacuumed + 1; blkno < thisblkno; blkno++)
 		{
 			/*
+			 * First we try to know if the page is already in buffer cache.
+			 * If not, it is definitely unpinned. If it's already there,
+			 * we read it.
+			 *
+			 */
+			if (!BufferInCache(thisrnode, MAIN_FORKNUM, blkno))
+				continue;
+
+			/*
 			 * We use RBM_NORMAL_NO_LOG mode because it's not an error
 			 * condition to see all-zero pages.  The original btvacuumpage
 			 * scan would have skipped over all-zero pages, noting them in FSM
@@ -430,10 +439,6 @@ btree_xlog_vacuum(XLogReaderState *record)
 			 * throw an error here.  (We could skip acquiring the cleanup lock
 			 * if PageIsNew, but it's probably not worth the cycles to test.)
 			 *
-			 * XXX we don't actually need to read the block, we just need to
-			 * confirm it is unpinned. If we had a special call into the
-			 * buffer manager we could optimise this so that if the block is
-			 * not in shared_buffers we confirm it as unpinned.
 			 */
 			buffer = XLogReadBufferExtended(thisrnode, MAIN_FORKNUM, blkno,
 											RBM_NORMAL_NO_LOG);
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index cd3aaad..eb74da3 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -3640,3 +3640,34 @@ rnode_comparator(const void *p1, const void *p2)
 	else
 		return 0;
 }
+
+/*
+ * BufferInCache -- returns true if buffer is already in buffer cache and
+ * false otherwise.
+ *
+ * No locks are held either at entry or exit.
+ */
+bool
+BufferInCache(RelFileNode rnode, ForkNumber forkNum, BlockNumber blockNum)
+{
+	BufferTag	Tag;				/* identity of requested block */
+	uint32		Hash;				/* hash value for newTag */
+	LWLock	   *PartitionLock;		/* buffer partition lock for it */
+	int			buf_id;
+
+	SMgrRelation smgr = smgropen(rnode, InvalidBackendId);
+
+	/* create a tag so we can lookup the buffer */
+	INIT_BUFFERTAG(Tag, smgr->smgr_rnode.node, forkNum, blockNum);
+
+	/* determine its hash code and partition lock ID */
+	Hash = BufTableHashCode(&Tag);
+	PartitionLock = BufMappingPartitionLock(Hash);
+
+	/* see if the block is in the buffer pool already */
+	LWLockAcquire(PartitionLock, LW_SHARED);
+	buf_id = BufTableLookup(&Tag, Hash);
+	LWLockRelease(PartitionLock);
+
+	return buf_id != -1;
+}
diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
index ec0a254..ced564f 100644
--- a/src/include/storage/bufmgr.h
+++ b/src/include/storage/bufmgr.h
@@ -159,6 +159,8 @@ extern void MarkBufferDirty(Buffer buffer);
 extern void IncrBufferRefCount(Buffer buffer);
 extern Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation,
 					 BlockNumber blockNum);
+extern bool BufferInCache(RelFileNode rnode, ForkNumber forkNum,
+					 BlockNumber blockNum);
 
 extern void InitBufferPool(void);
 extern void InitBufferPoolAccess(void);
