v4-0003-Fix-race-in-SSI-interaction-with-gin-fast-path.patch
text/x-patch
Filename: v4-0003-Fix-race-in-SSI-interaction-with-gin-fast-path.patch
Type: text/x-patch
Part: 2
Patch
Format: format-patch
Series: patch v4-0003
Subject: Fix race in SSI interaction with gin fast path.
| File | + | − |
|---|---|---|
| src/backend/access/gin/ginfast.c | 8 | 2 |
| src/backend/access/gin/ginget.c | 3 | 1 |
From 8614733376bc9f3786218006a23716fe64f917ef Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Mon, 26 Jun 2023 11:43:37 +1200
Subject: [PATCH v4 3/3] Fix race in SSI interaction with gin fast path.
The ginfast.c code previously checked for conflicts in before locking
the relevant buffer, leaving a window where a RW conflict could be
missed.
There was also a place where buffer ID and block number were confused
while trying to predicate-lock a page, noted by visual inspection.
Back-patch to all supported releases. Fixes one more problem discovered
by Dmitry with the reproducer from bug #17949 against other index types.
Reported-by: Artem Anisimov <artem.anisimov.255@gmail.com>
Reported-by: Dmitry Dolgov <9erthalion6@gmail.com>
Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi>
Discussion: https://postgr.es/m/17949-a0f17035294a55e2%40postgresql.org
---
src/backend/access/gin/ginfast.c | 10 ++++++++--
src/backend/access/gin/ginget.c | 4 +++-
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/src/backend/access/gin/ginfast.c b/src/backend/access/gin/ginfast.c
index ca7d770d86..c6524f759c 100644
--- a/src/backend/access/gin/ginfast.c
+++ b/src/backend/access/gin/ginfast.c
@@ -245,9 +245,10 @@ ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
/*
* An insertion to the pending list could logically belong anywhere in the
* tree, so it conflicts with all serializable scans. All scans acquire a
- * predicate lock on the metabuffer to represent that.
+ * predicate lock on the metabuffer to represent that. Therefore we'll
+ * check for conflicts in, but not until we have the page locked and are
+ * ready to modify the page.
*/
- CheckForSerializableConflictIn(index, NULL, GIN_METAPAGE_BLKNO);
if (collector->sumsize + collector->ntuples * sizeof(ItemIdData) > GinListPageSize)
{
@@ -291,6 +292,8 @@ ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
LockBuffer(metabuffer, GIN_EXCLUSIVE);
metadata = GinPageGetMeta(metapage);
+ CheckForSerializableConflictIn(index, NULL, GIN_METAPAGE_BLKNO);
+
if (metadata->head == InvalidBlockNumber)
{
/*
@@ -310,6 +313,7 @@ ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
}
else
{
+
/*
* Merge lists
*/
@@ -353,6 +357,8 @@ ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
char *ptr;
char *collectordata;
+ CheckForSerializableConflictIn(index, NULL, GIN_METAPAGE_BLKNO);
+
buffer = ReadBuffer(index, metadata->tail);
LockBuffer(buffer, GIN_EXCLUSIVE);
page = BufferGetPage(buffer);
diff --git a/src/backend/access/gin/ginget.c b/src/backend/access/gin/ginget.c
index cb676a710f..1f0214498c 100644
--- a/src/backend/access/gin/ginget.c
+++ b/src/backend/access/gin/ginget.c
@@ -140,7 +140,9 @@ collectMatchBitmap(GinBtreeData *btree, GinBtreeStack *stack,
* Predicate lock entry leaf page, following pages will be locked by
* moveRightIfItNeeded()
*/
- PredicateLockPage(btree->index, stack->buffer, snapshot);
+ PredicateLockPage(btree->index,
+ BufferGetBlockNumber(stack->buffer),
+ snapshot);
for (;;)
{
--
2.39.2