From 2a01e3144379c008b9ee6322e8a449bd762f9a47 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 2 Jul 2007 20:12:21 +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 | 13 ++++++++++++- src/include/port/linux.h | 13 +++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/backend/port/sysv_shmem.c b/src/backend/port/sysv_shmem.c index b44f07c8ec5..5229ec9cf66 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 - * $Header: /cvsroot/pgsql/src/backend/port/sysv_shmem.c,v 1.24.2.2 2004/11/09 20:35:16 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/port/sysv_shmem.c,v 1.24.2.3 2007/07/02 20:12:21 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -208,6 +208,17 @@ 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 diff --git a/src/include/port/linux.h b/src/include/port/linux.h index 159db3194f1..7c5d0fbfd7d 100644 --- a/src/include/port/linux.h +++ b/src/include/port/linux.h @@ -49,3 +49,16 @@ typedef unsigned char slock_t; #define HAS_TEST_AND_SET #endif + +/* + * 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 -- 2.39.5