From 419113dfdc4c729f6c763cc30a9b02ee68a7da94 Mon Sep 17 00:00:00 2001
From: Robert Haas <rhaas@postgresql.org>
Date: Tue, 20 Sep 2016 12:04:41 -0400
Subject: [PATCH] Retry DSM control segment creation if Windows indicates
 access denied.

Otherwise, attempts to run multiple postmasters running on the same
machine may fail, because Windows sometimes returns ERROR_ACCESS_DENIED
rather than ERROR_ALREADY_EXISTS when there is an existing segment.

Hitting this bug is much more likely because of another defect not
fixed by this patch, namely that dsm_postmaster_startup() uses
random() which returns the same value every time.  But that's not
a reason not to fix this.

Kyotaro Horiguchi and Amit Kapila, reviewed by Michael Paquier

Discussion: <CAA4eK1JyNdMeF-dgrpHozDecpDfsRZUtpCi+1AbtuEkfG3YooQ@mail.gmail.com>
---
 src/backend/storage/ipc/dsm_impl.c | 31 +++++++++++++++++-------------
 1 file changed, 18 insertions(+), 13 deletions(-)

diff --git a/src/backend/storage/ipc/dsm_impl.c b/src/backend/storage/ipc/dsm_impl.c
index 99051f02c8c..7122c4abe00 100644
--- a/src/backend/storage/ipc/dsm_impl.c
+++ b/src/backend/storage/ipc/dsm_impl.c
@@ -671,6 +671,7 @@ dsm_impl_windows(dsm_op op, dsm_handle handle, Size request_size,
 	{
 		DWORD		size_high;
 		DWORD		size_low;
+		DWORD		errcode;
 
 		/* Shifts >= the width of the type are undefined. */
 #ifdef _WIN64
@@ -686,27 +687,31 @@ dsm_impl_windows(dsm_op op, dsm_handle handle, Size request_size,
 								 size_high,		/* Upper 32 bits of size */
 								 size_low,		/* Lower 32 bits of size */
 								 name);
+
+		errcode = GetLastError();
+		if (errcode == ERROR_ALREADY_EXISTS || errcode == ERROR_ACCESS_DENIED)
+		{
+			/*
+			 * On Windows, when the segment already exists, a handle for the
+			 * existing segment is returned.  We must close it before
+			 * returning.  However, if the existing segment is created by a
+			 * service, then it returns ERROR_ACCESS_DENIED. We don't do
+			 * _dosmaperr here, so errno won't be modified.
+			 */
+			if (hmap)
+				CloseHandle(hmap);
+			return false;
+		}
+
 		if (!hmap)
 		{
-			_dosmaperr(GetLastError());
+			_dosmaperr(errcode);
 			ereport(elevel,
 					(errcode_for_dynamic_shared_memory(),
 				  errmsg("could not create shared memory segment \"%s\": %m",
 						 name)));
 			return false;
 		}
-		_dosmaperr(GetLastError());
-		if (errno == EEXIST)
-		{
-			/*
-			 * On Windows, when the segment already exists, a handle for the
-			 * existing segment is returned.  We must close it before
-			 * returning.  We don't do _dosmaperr here, so errno won't be
-			 * modified.
-			 */
-			CloseHandle(hmap);
-			return false;
-		}
 	}
 	else
 	{
-- 
GitLab