diff --git a/src/backend/access/spgist/spgdoinsert.c b/src/backend/access/spgist/spgdoinsert.c
index 5f6bcdd..8f0cfae 100644
--- a/src/backend/access/spgist/spgdoinsert.c
+++ b/src/backend/access/spgist/spgdoinsert.c
@@ -1836,9 +1836,11 @@ spgSplitNodeAction(Relation index, SpGistState *state,
 }
 
 /*
- * Insert one item into the index
+ * Insert one item into the index. Returns false if
+ * it's not currrently possible. Caller should re-call
+ * spgdoinsert() with the same args. Explanation see below.
  */
-void
+bool
 spgdoinsert(Relation index, SpGistState *state,
 			ItemPointer heapPtr, Datum datum, bool isnull)
 {
@@ -1927,12 +1929,37 @@ spgdoinsert(Relation index, SpGistState *state,
 								&isNew);
 			current.blkno = BufferGetBlockNumber(current.buffer);
 		}
-		else if (parent.buffer == InvalidBuffer ||
-				 current.blkno != parent.blkno)
+		else if (parent.buffer == InvalidBuffer)
 		{
+			/* read root, no dead lock is possible */
 			current.buffer = ReadBuffer(index, current.blkno);
 			LockBuffer(current.buffer, BUFFER_LOCK_EXCLUSIVE);
 		}
+		else if (current.blkno != parent.blkno)
+		{
+			current.buffer = ReadBuffer(index, current.blkno);
+			
+			if (ConditionalLockBuffer(current.buffer) == false)
+			{
+				/*
+				 * Possible deadlock prevention:
+				 * In a chain of parent->child->child_of_child on one page
+				 * someday child could be moved to new page before
+				 * child_of_child moving and this violates page number rule 
+				 * for child->child_of_child link. This violation could
+				 * cause a deadlock between concurrent insertion.
+				 * Another possible reason is a three or more concurrent
+				 * inserts: they could wait each other in a chain of 3 pages.
+				 * For now it's used simplest way to prevent dead lock:
+				 * just break insertion process and begin it from the scratch.
+				 * Main disadvantage is a possible interference with
+				 * selects and reinsertion even it was enough to sleep a bit.
+				 */
+				ReleaseBuffer(current.buffer);
+				UnlockReleaseBuffer(parent.buffer);
+				return false;
+			}
+		}
 		else
 		{
 			/* inner tuple can be stored on the same page as parent one */
@@ -2131,4 +2158,6 @@ spgdoinsert(Relation index, SpGistState *state,
 		SpGistSetLastUsedPage(index, parent.buffer);
 		UnlockReleaseBuffer(parent.buffer);
 	}
+
+	return true;
 }
diff --git a/src/backend/access/spgist/spginsert.c b/src/backend/access/spgist/spginsert.c
index 94384ac..3390a33 100644
--- a/src/backend/access/spgist/spginsert.c
+++ b/src/backend/access/spgist/spginsert.c
@@ -45,7 +45,8 @@ spgistBuildCallback(Relation index, HeapTuple htup, Datum *values,
 	/* Work in temp context, and reset it after each tuple */
 	oldCtx = MemoryContextSwitchTo(buildstate->tmpCtx);
 
-	spgdoinsert(index, &buildstate->spgstate, &htup->t_self, *values, *isnull);
+	if (!spgdoinsert(index, &buildstate->spgstate, &htup->t_self, *values, *isnull))
+		elog(PANIC, "Impossible concurrent insertion");
 
 	MemoryContextSwitchTo(oldCtx);
 	MemoryContextReset(buildstate->tmpCtx);
@@ -217,9 +218,15 @@ spginsert(PG_FUNCTION_ARGS)
 									  ALLOCSET_DEFAULT_MAXSIZE);
 	oldCtx = MemoryContextSwitchTo(insertCtx);
 
-	initSpGistState(&spgstate, index);
+	for(;;)
+	{
+		initSpGistState(&spgstate, index);
+
+		if (spgdoinsert(index, &spgstate, ht_ctid, *values, *isnull))
+			break;
 
-	spgdoinsert(index, &spgstate, ht_ctid, *values, *isnull);
+		MemoryContextReset(insertCtx);
+	}
 
 	SpGistUpdateMetaPage(index);
 
diff --git a/src/include/access/spgist_private.h b/src/include/access/spgist_private.h
index 7dc7941..e8bc898 100644
--- a/src/include/access/spgist_private.h
+++ b/src/include/access/spgist_private.h
@@ -652,7 +652,7 @@ extern void spgPageIndexMultiDelete(SpGistState *state, Page page,
 						OffsetNumber *itemnos, int nitems,
 						int firststate, int reststate,
 						BlockNumber blkno, OffsetNumber offnum);
-extern void spgdoinsert(Relation index, SpGistState *state,
+extern bool spgdoinsert(Relation index, SpGistState *state,
 			ItemPointer heapPtr, Datum datum, bool isnull);
 
 #endif   /* SPGIST_PRIVATE_H */
