/* Start from the root */
        firststack.blkno = GIST_ROOT_BLKNO;
        firststack.lsn = 0;
+       firststack.retry_from_parent = false;
        firststack.parent = NULL;
        firststack.downlinkoffnum = InvalidOffsetNumber;
        state.stack = stack = &firststack;
         */
        for (;;)
        {
+               /*
+                * If we split an internal page while descending the tree, we have to
+                * retry at the parent. (Normally, the LSN-NSN interlock below would
+                * also catch this and cause us to retry. But LSNs are not updated
+                * during index build.)
+                */
+               while (stack->retry_from_parent)
+               {
+                       if (xlocked)
+                               LockBuffer(stack->buffer, GIST_UNLOCK);
+                       xlocked = false;
+                       ReleaseBuffer(stack->buffer);
+                       state.stack = stack = stack->parent;
+               }
+
                if (XLogRecPtrIsInvalid(stack->lsn))
                        stack->buffer = ReadBuffer(state.r, stack->blkno);
 
                                         unlockbuf      /* Unlock stack->buffer if caller wants that */
                );
        Assert(left->buf == stack->buffer);
+
+       /*
+        * If we split the page because we had to adjust the downlink on an
+        * internal page, while descending the tree for inserting a new tuple,
+        * then this might no longer be the correct page for the new tuple. The
+        * downlink to this page might not cover the new tuple anymore, it might
+        * need to go to the newly-created right sibling instead. Tell the caller
+        * to walk back up the stack, to re-check at the parent which page to
+        * insert to.
+        *
+        * Normally, the LSN-NSN interlock during the tree descend would also
+        * detect that a concurrent split happened (by ourselves), and cause us to
+        * retry at the parent. But that mechanism doesn't work during index
+        * build, because we don't do WAL-logging, and don't update LSNs, during
+        * index build.
+        */
+       stack->retry_from_parent = true;
 }
 
 /*
 
         */
        GistNSN         lsn;
 
+       /*
+        * If set, we split the page while descending the tree to find an
+        * insertion target. It means that we need to retry from the parent,
+        * because the downlink of this page might no longer cover the new key.
+        */
+       bool            retry_from_parent;
+
        /* offset of the downlink in the parent page, that points to this page */
        OffsetNumber downlinkoffnum;