From d0d30d13e8dacbfc837386db83cbd585b3885ccd Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@enterprisedb.com>
Date: Tue, 25 Sep 2018 15:39:28 +1200
Subject: [PATCH 1/2] Desupport dsm_resize() and dsm_remap().

dsm_resize() was not used, had a subtle bug on one platform, and
wasn't supported on all platforms.  If there are any external users
of the interface, they should be calling dsm_impl_can_resize() and
falling back to different behavior when it's not available.  Update
that function to return false always.  Later we'll remove the
interface completely.

Back-patch to 9.4 where DSM first landed.

Author: Thomas Munro
Reported-by: Andres Freund
Reviewed-by:
Discussion: https://postgr.es/m/CAA4eK1%2B%3DyAFUvpFoHXFi_gm8YqmXN-TtkFH%2BVYjvDLS6-SFq-Q%40mail.gmail.com
---
 src/backend/storage/ipc/dsm.c      |  20 +---
 src/backend/storage/ipc/dsm_impl.c | 145 ++++-------------------------
 src/include/storage/dsm_impl.h     |   1 -
 3 files changed, 21 insertions(+), 145 deletions(-)

diff --git a/src/backend/storage/ipc/dsm.c b/src/backend/storage/ipc/dsm.c
index 9629f22f7a..af1162c6e8 100644
--- a/src/backend/storage/ipc/dsm.c
+++ b/src/backend/storage/ipc/dsm.c
@@ -655,34 +655,22 @@ dsm_detach_all(void)
 
 /*
  * Resize an existing shared memory segment.
- *
- * This may cause the shared memory segment to be remapped at a different
- * address.  For the caller's convenience, we return the mapped address.
  */
 void *
 dsm_resize(dsm_segment *seg, Size size)
 {
-	Assert(seg->control_slot != INVALID_CONTROL_SLOT);
-	dsm_impl_op(DSM_OP_RESIZE, seg->handle, size, &seg->impl_private,
-				&seg->mapped_address, &seg->mapped_size, ERROR);
-	return seg->mapped_address;
+	elog(ERROR, "dsm_resize not supported");
+	return NULL;
 }
 
 /*
  * Remap an existing shared memory segment.
- *
- * This is intended to be used when some other process has extended the
- * mapping using dsm_resize(), but we've still only got the initial
- * portion mapped.  Since this might change the address at which the
- * segment is mapped, we return the new mapped address.
  */
 void *
 dsm_remap(dsm_segment *seg)
 {
-	dsm_impl_op(DSM_OP_ATTACH, seg->handle, 0, &seg->impl_private,
-				&seg->mapped_address, &seg->mapped_size, ERROR);
-
-	return seg->mapped_address;
+	elog(ERROR, "dsm_remap not supported");
+	return NULL;
 }
 
 /*
diff --git a/src/backend/storage/ipc/dsm_impl.c b/src/backend/storage/ipc/dsm_impl.c
index 70f899e765..fe581afffb 100644
--- a/src/backend/storage/ipc/dsm_impl.c
+++ b/src/backend/storage/ipc/dsm_impl.c
@@ -127,14 +127,9 @@ int			dynamic_shared_memory_type;
  * map it.
  *
  * DSM_OP_ATTACH.  Map the segment, whose size must be the request_size.
- * The segment may already be mapped; any existing mapping should be removed
- * before creating a new one.
  *
  * DSM_OP_DETACH.  Unmap the segment.
  *
- * DSM_OP_RESIZE.  Resize the segment to the given request_size and
- * remap the segment at that new size.
- *
  * DSM_OP_DESTROY.  Unmap the segment, if it is mapped.  Destroy the
  * segment.
  *
@@ -142,8 +137,7 @@ int			dynamic_shared_memory_type;
  *	 op: The operation to be performed.
  *	 handle: The handle of an existing object, or for DSM_OP_CREATE, the
  *	   a new handle the caller wants created.
- *	 request_size: For DSM_OP_CREATE, the requested size.  For DSM_OP_RESIZE,
- *	   the new size.  Otherwise, 0.
+ *	 request_size: For DSM_OP_CREATE, the requested size.  Otherwise, 0.
  *	 impl_private: Private, implementation-specific data.  Will be a pointer
  *	   to NULL for the first operation on a shared memory segment within this
  *	   backend; thereafter, it will point to the value to which it was set
@@ -165,7 +159,7 @@ dsm_impl_op(dsm_op op, dsm_handle handle, Size request_size,
 			void **impl_private, void **mapped_address, Size *mapped_size,
 			int elevel)
 {
-	Assert(op == DSM_OP_CREATE || op == DSM_OP_RESIZE || request_size == 0);
+	Assert(op == DSM_OP_CREATE || request_size == 0);
 	Assert((op != DSM_OP_CREATE && op != DSM_OP_ATTACH) ||
 		   (*mapped_address == NULL && *mapped_size == 0));
 
@@ -199,28 +193,16 @@ dsm_impl_op(dsm_op op, dsm_handle handle, Size request_size,
 }
 
 /*
- * Does the current dynamic shared memory implementation support resizing
- * segments?  (The answer here could be platform-dependent in the future,
- * since AIX allows shmctl(shmid, SHM_RESIZE, &buffer), though you apparently
- * can't resize segments to anything larger than 256MB that way.  For now,
- * we keep it simple.)
+ * Previously we supported resizing DSM segments on some platforms.  Since
+ * the work was never extended to all platforms so that it couldn't be relied
+ * on in general, and potential bugs were discovered on one one platform
+ * where we did support it, we decided to remove this.  The interface will
+ * disappear completely in a later release.
  */
 bool
 dsm_impl_can_resize(void)
 {
-	switch (dynamic_shared_memory_type)
-	{
-		case DSM_IMPL_POSIX:
-			return true;
-		case DSM_IMPL_SYSV:
-			return false;
-		case DSM_IMPL_WINDOWS:
-			return false;
-		case DSM_IMPL_MMAP:
-			return true;
-		default:
-			return false;		/* should not happen */
-	}
+	return false;
 }
 
 #ifdef USE_DSM_POSIX
@@ -296,7 +278,7 @@ dsm_impl_posix(dsm_op op, dsm_handle handle, Size request_size,
 
 	/*
 	 * If we're attaching the segment, determine the current size; if we are
-	 * creating or resizing the segment, set the size to the requested value.
+	 * creating the segment, set the size to the requested value.
 	 */
 	if (op == DSM_OP_ATTACH)
 	{
@@ -319,16 +301,14 @@ dsm_impl_posix(dsm_op op, dsm_handle handle, Size request_size,
 		}
 		request_size = st.st_size;
 	}
-	else if (*mapped_size != request_size &&
-			 dsm_impl_posix_resize(fd, request_size) != 0)
+	else if (dsm_impl_posix_resize(fd, request_size) != 0)
 	{
 		int			save_errno;
 
 		/* Back out what's already been done. */
 		save_errno = errno;
 		close(fd);
-		if (op == DSM_OP_CREATE)
-			shm_unlink(name);
+		shm_unlink(name);
 		errno = save_errno;
 
 		/*
@@ -346,35 +326,6 @@ dsm_impl_posix(dsm_op op, dsm_handle handle, Size request_size,
 		return false;
 	}
 
-	/*
-	 * If we're reattaching or resizing, we must remove any existing mapping,
-	 * unless we've already got the right thing mapped.
-	 */
-	if (*mapped_address != NULL)
-	{
-		if (*mapped_size == request_size)
-			return true;
-		if (munmap(*mapped_address, *mapped_size) != 0)
-		{
-			int			save_errno;
-
-			/* Back out what's already been done. */
-			save_errno = errno;
-			close(fd);
-			if (op == DSM_OP_CREATE)
-				shm_unlink(name);
-			errno = save_errno;
-
-			ereport(elevel,
-					(errcode_for_dynamic_shared_memory(),
-					 errmsg("could not unmap shared memory segment \"%s\": %m",
-							name)));
-			return false;
-		}
-		*mapped_address = NULL;
-		*mapped_size = 0;
-	}
-
 	/* Map it. */
 	address = mmap(NULL, request_size, PROT_READ | PROT_WRITE,
 				   MAP_SHARED | MAP_HASSEMAPHORE | MAP_NOSYNC, fd, 0);
@@ -457,10 +408,9 @@ dsm_impl_posix_resize(int fd, off_t size)
  * Operating system primitives to support System V shared memory.
  *
  * System V shared memory segments are manipulated using shmget(), shmat(),
- * shmdt(), and shmctl().  There's no portable way to resize such
- * segments.  As the default allocation limits for System V shared memory
- * are usually quite low, the POSIX facilities may be preferable; but
- * those are not supported everywhere.
+ * shmdt(), and shmctl().  As the default allocation limits for System V
+ * shared memory are usually quite low, the POSIX facilities may be
+ * preferable; but those are not supported everywhere.
  */
 static bool
 dsm_impl_sysv(dsm_op op, dsm_handle handle, Size request_size,
@@ -473,13 +423,6 @@ dsm_impl_sysv(dsm_op op, dsm_handle handle, Size request_size,
 	char		name[64];
 	int		   *ident_cache;
 
-	/* Resize is not supported for System V shared memory. */
-	if (op == DSM_OP_RESIZE)
-	{
-		elog(elevel, "System V shared memory segments cannot be resized");
-		return false;
-	}
-
 	/* Since resize isn't supported, reattach is a no-op. */
 	if (op == DSM_OP_ATTACH && *mapped_address != NULL)
 		return true;
@@ -670,13 +613,6 @@ dsm_impl_windows(dsm_op op, dsm_handle handle, Size request_size,
 	char		name[64];
 	MEMORY_BASIC_INFORMATION info;
 
-	/* Resize is not supported for Windows shared memory. */
-	if (op == DSM_OP_RESIZE)
-	{
-		elog(elevel, "Windows shared memory segments cannot be resized");
-		return false;
-	}
-
 	/* Since resize isn't supported, reattach is a no-op. */
 	if (op == DSM_OP_ATTACH && *mapped_address != NULL)
 		return true;
@@ -905,7 +841,7 @@ dsm_impl_mmap(dsm_op op, dsm_handle handle, Size request_size,
 
 	/*
 	 * If we're attaching the segment, determine the current size; if we are
-	 * creating or resizing the segment, set the size to the requested value.
+	 * creating the segment, set the size to the requested value.
 	 */
 	if (op == DSM_OP_ATTACH)
 	{
@@ -928,24 +864,7 @@ dsm_impl_mmap(dsm_op op, dsm_handle handle, Size request_size,
 		}
 		request_size = st.st_size;
 	}
-	else if (*mapped_size > request_size && ftruncate(fd, request_size))
-	{
-		int			save_errno;
-
-		/* Back out what's already been done. */
-		save_errno = errno;
-		CloseTransientFile(fd);
-		if (op == DSM_OP_CREATE)
-			unlink(name);
-		errno = save_errno;
-
-		ereport(elevel,
-				(errcode_for_dynamic_shared_memory(),
-				 errmsg("could not resize shared memory segment \"%s\" to %zu bytes: %m",
-						name, request_size)));
-		return false;
-	}
-	else if (*mapped_size < request_size)
+	else
 	{
 		/*
 		 * Allocate a buffer full of zeros.
@@ -985,8 +904,7 @@ dsm_impl_mmap(dsm_op op, dsm_handle handle, Size request_size,
 			/* Back out what's already been done. */
 			save_errno = errno;
 			CloseTransientFile(fd);
-			if (op == DSM_OP_CREATE)
-				unlink(name);
+			unlink(name);
 			errno = save_errno ? save_errno : ENOSPC;
 
 			ereport(elevel,
@@ -997,35 +915,6 @@ dsm_impl_mmap(dsm_op op, dsm_handle handle, Size request_size,
 		}
 	}
 
-	/*
-	 * If we're reattaching or resizing, we must remove any existing mapping,
-	 * unless we've already got the right thing mapped.
-	 */
-	if (*mapped_address != NULL)
-	{
-		if (*mapped_size == request_size)
-			return true;
-		if (munmap(*mapped_address, *mapped_size) != 0)
-		{
-			int			save_errno;
-
-			/* Back out what's already been done. */
-			save_errno = errno;
-			CloseTransientFile(fd);
-			if (op == DSM_OP_CREATE)
-				unlink(name);
-			errno = save_errno;
-
-			ereport(elevel,
-					(errcode_for_dynamic_shared_memory(),
-					 errmsg("could not unmap shared memory segment \"%s\": %m",
-							name)));
-			return false;
-		}
-		*mapped_address = NULL;
-		*mapped_size = 0;
-	}
-
 	/* Map it. */
 	address = mmap(NULL, request_size, PROT_READ | PROT_WRITE,
 				   MAP_SHARED | MAP_HASSEMAPHORE | MAP_NOSYNC, fd, 0);
diff --git a/src/include/storage/dsm_impl.h b/src/include/storage/dsm_impl.h
index e7acdff355..c8adc425fd 100644
--- a/src/include/storage/dsm_impl.h
+++ b/src/include/storage/dsm_impl.h
@@ -59,7 +59,6 @@ typedef enum
 	DSM_OP_CREATE,
 	DSM_OP_ATTACH,
 	DSM_OP_DETACH,
-	DSM_OP_RESIZE,
 	DSM_OP_DESTROY
 } dsm_op;
 
-- 
2.17.0

