8000 Fix failure to restart Postgres when Linux kernel returns EIDRM for s… · danielcode/postgres@7ca6422 · GitHub
[go: up one dir, main page]

Skip to content

Commit 7ca6422

Browse files
committed
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.
1 parent 175c3b8 commit 7ca6422

File tree

2 files changed

+37
-6
lines changed

2 files changed

+37
-6
lines changed

src/backend/port/sysv_shmem.c

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* Portions Copyright (c) 1994, Regents of the University of California
1111
*
1212
* IDENTIFICATION
13-
* $Header: /cvsroot/pgsql/src/backend/port/sysv_shmem.c,v 1.4.2.1 2003/11/30 21:56:36 tgl Exp $
13+
* $Header: /cvsroot/pgsql/src/backend/port/sysv_shmem.c,v 1.4.2.2 2007/07/02 20:12:26 tgl Exp $
1414
*
1515
*-------------------------------------------------------------------------
1616
*/
@@ -219,10 +219,6 @@ PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2)
219219
/*
220220
* We detect whether a shared memory segment is in use by seeing
221221
* whether it (a) exists and (b) has any processes are attached to it.
222-
*
223-
* If we are unable to perform the stat operation for a reason other than
224-
* nonexistence of the segment (most likely, because it doesn't belong
225-
* to our userid), assume it is in use.
226222
*/
227223
if (shmctl(shmId, IPC_STAT, &shmStat) < 0)
228224
{
@@ -233,7 +229,29 @@ PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2)
233229
*/
234230
if (errno == EINVAL)
235231
return false;
236-
/* Else assume segment is in use */
232+
/*
233+
* EACCES implies that the segment belongs to some other userid,
234+
* which means it is not a Postgres shmem segment (or at least,
235+
* not one that is relevant to our data directory).
236+
*/
237+
if (errno == EACCES)
238+
return false;
239+
/*
240+
* Some Linux kernel versions (in fact, all of them as of July 2007)
241+
* sometimes return EIDRM when EINVAL is correct. The Linux kernel
242+
* actually does not have any internal state that would justify
243+
* returning EIDRM, so we can get away with assuming that EIDRM is
244+
* equivalent to EINVAL on that platform.
245+
*/
246+
#ifdef HAVE_LINUX_EIDRM_BUG
247+
if (errno == EIDRM)
248+
return false;
249+
#endif
250+
/*
251+
* Otherwise, we had better assume that the segment is in use.
252+
* The only likely case is EIDRM, which implies that the segment
253+
* has been IPC_RMID'd but there are still processes attached to it.
254+
*/
237255
return true;
238256
}
239257
/* If it has attached processes, it's in use */

src/include/port/linux.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,16 @@ typedef unsigned char slock_t;
5555
#define HAS_TEST_AND_SET
5656

5757
#endif
58+
59+
/*
60+
* As of July 2007, all known versions of the Linux kernel will sometimes
61+
* return EIDRM for a shmctl() operation when EINVAL is correct (it happens
62+
* when the low-order 15 bits of the supplied shm ID match the slot number
63+
* assigned to a newer shmem segment). We deal with this by assuming that
64+
* EIDRM means EINVAL in PGSharedMemoryIsInUse(). This is reasonably safe
65+
* since in fact Linux has no excuse for ever returning EIDRM; it doesn't
66+
* track removed segments in a way that would allow distinguishing them from
67+
* private ones. But someday that code might get upgraded, and we'd have
68+
* to have a kernel version test here.
69+
*/
70+
#define HAVE_LINUX_EIDRM_BUG

0 commit comments

Comments
 (0)
0