From d54a94b806825a119be86d5f73232b06dd9e9a16 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Fri, 30 Nov 2012 17:02:29 -0500
Subject: [PATCH] Take buffer lock while inspecting btree index pages in
 contrib/pageinspect.

It's not safe to examine a shared buffer without any lock.
---
 contrib/pageinspect/btreefuncs.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index dbb2158ba8d..bc34af9b3c7 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -156,9 +156,9 @@ GetBTPageStatistics(BlockNumber blkno, Buffer buffer, BTPageStat *stat)
 }
 
 /* -----------------------------------------------
- * bt_page()
+ * bt_page_stats()
  *
- * Usage: SELECT * FROM bt_page('t1_pkey', 1);
+ * Usage: SELECT * FROM bt_page_stats('t1_pkey', 1);
  * -----------------------------------------------
  */
 Datum
@@ -204,6 +204,7 @@ bt_page_stats(PG_FUNCTION_ARGS)
 	CHECK_RELATION_BLOCK_RANGE(rel, blkno);
 
 	buffer = ReadBuffer(rel, blkno);
+	LockBuffer(buffer, BUFFER_LOCK_SHARE);
 
 	/* keep compiler quiet */
 	stat.btpo_prev = stat.btpo_next = InvalidBlockNumber;
@@ -211,6 +212,9 @@ bt_page_stats(PG_FUNCTION_ARGS)
 
 	GetBTPageStatistics(blkno, buffer, &stat);
 
+	UnlockReleaseBuffer(buffer);
+	relation_close(rel, AccessShareLock);
+
 	/* Build a tuple descriptor for our result type */
 	if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
 		elog(ERROR, "return type must be a row type");
@@ -247,10 +251,6 @@ bt_page_stats(PG_FUNCTION_ARGS)
 
 	result = HeapTupleGetDatum(tuple);
 
-	ReleaseBuffer(buffer);
-
-	relation_close(rel, AccessShareLock);
-
 	PG_RETURN_DATUM(result);
 }
 
@@ -322,6 +322,7 @@ bt_page_items(PG_FUNCTION_ARGS)
 		CHECK_RELATION_BLOCK_RANGE(rel, blkno);
 
 		buffer = ReadBuffer(rel, blkno);
+		LockBuffer(buffer, BUFFER_LOCK_SHARE);
 
 		/*
 		 * We copy the page into local storage to avoid holding pin on the
@@ -335,7 +336,7 @@ bt_page_items(PG_FUNCTION_ARGS)
 		uargs->page = palloc(BLCKSZ);
 		memcpy(uargs->page, BufferGetPage(buffer), BLCKSZ);
 
-		ReleaseBuffer(buffer);
+		UnlockReleaseBuffer(buffer);
 		relation_close(rel, AccessShareLock);
 
 		uargs->offset = FirstOffsetNumber;
@@ -466,6 +467,8 @@ bt_metap(PG_FUNCTION_ARGS)
 				 errmsg("cannot access temporary tables of other sessions")));
 
 	buffer = ReadBuffer(rel, 0);
+	LockBuffer(buffer, BUFFER_LOCK_SHARE);
+
 	page = BufferGetPage(buffer);
 	metad = BTPageGetMeta(page);
 
@@ -492,8 +495,7 @@ bt_metap(PG_FUNCTION_ARGS)
 
 	result = HeapTupleGetDatum(tuple);
 
-	ReleaseBuffer(buffer);
-
+	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
 
 	PG_RETURN_DATUM(result);
-- 
GitLab