From 1c7fe33fdb443f1950a7b019c7e0793c848948c6 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Mon, 2 Jul 2007 20:11:55 +0000
Subject: [PATCH] Fix failure to restart Postgres when Linux kernel returns
 EIDRM for shmctl().

This is a Linux kernel bug that apparently exists in every extant kernel
version: sometimes shmctl() will fail with EIDRM when EINVAL is correct.
We were assuming that EIDRM indicates a possible conflict with pre-existing
backends, and refusing to start the postmaster when this happens.  Fortunately,
there does not seem to be any case where Linux can legitimately return EIDRM
(it doesn't track shmem segments in a way that would allow that), so we can
get away with just assuming that EIDRM means EINVAL on this platform.

Per reports from Michael Fuhr and Jon Lapham --- it's a bit surprising
we have not seen more reports, actually.
---
 src/backend/port/sysv_shmem.c | 14 +++++++++++++-
 src/include/port/linux.h      | 15 ++++++++++++++-
 2 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/src/backend/port/sysv_shmem.c b/src/backend/port/sysv_shmem.c
index 8677752e30d..08662d1fb37 100644
--- a/src/backend/port/sysv_shmem.c
+++ b/src/backend/port/sysv_shmem.c
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/port/sysv_shmem.c,v 1.50 2007/03/21 14:39:23 mha Exp $
+ *	  $PostgreSQL: pgsql/src/backend/port/sysv_shmem.c,v 1.51 2007/07/02 20:11:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -220,6 +220,18 @@ PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2)
 		if (errno == EACCES)
 			return false;
 
+		/*
+		 * Some Linux kernel versions (in fact, all of them as of July 2007)
+		 * sometimes return EIDRM when EINVAL is correct.  The Linux kernel
+		 * actually does not have any internal state that would justify
+		 * returning EIDRM, so we can get away with assuming that EIDRM is
+		 * equivalent to EINVAL on that platform.
+		 */
+#ifdef HAVE_LINUX_EIDRM_BUG
+		if (errno == EIDRM)
+			return false;
+#endif
+
 		/*
 		 * Otherwise, we had better assume that the segment is in use. The
 		 * only likely case is EIDRM, which implies that the segment has been
diff --git a/src/include/port/linux.h b/src/include/port/linux.h
index 05cba063a91..c0dab3ea21b 100644
--- a/src/include/port/linux.h
+++ b/src/include/port/linux.h
@@ -1 +1,14 @@
-/* $PostgreSQL: pgsql/src/include/port/linux.h,v 1.42 2006/10/04 00:30:09 momjian Exp $ */
+/* $PostgreSQL: pgsql/src/include/port/linux.h,v 1.43 2007/07/02 20:11:55 tgl Exp $ */
+
+/*
+ * As of July 2007, all known versions of the Linux kernel will sometimes
+ * return EIDRM for a shmctl() operation when EINVAL is correct (it happens
+ * when the low-order 15 bits of the supplied shm ID match the slot number
+ * assigned to a newer shmem segment).  We deal with this by assuming that
+ * EIDRM means EINVAL in PGSharedMemoryIsInUse().  This is reasonably safe
+ * since in fact Linux has no excuse for ever returning EIDRM; it doesn't
+ * track removed segments in a way that would allow distinguishing them from
+ * private ones.  But someday that code might get upgraded, and we'd have
+ * to have a kernel version test here.
+ */
+#define HAVE_LINUX_EIDRM_BUG
-- 
GitLab