OSDN Git Service

Fix failure to restart Postgres when Linux kernel returns EIDRM for shmctl().
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 2 Jul 2007 20:11:55 +0000 (20:11 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 2 Jul 2007 20:11:55 +0000 (20:11 +0000)
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
src/include/port/linux.h

index 8677752..08662d1 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -221,6 +221,18 @@ PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2)
                        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
                 * IPC_RMID'd but there are still processes attached to it.
index 05cba06..c0dab3e 100644 (file)
@@ -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