|
10 | 10 | * Portions Copyright (c) 1994, Regents of the University of California
|
11 | 11 | *
|
12 | 12 | * IDENTIFICATION
|
13 |
| - * $PostgreSQL: pgsql/src/backend/port/sysv_shmem.c,v 1.55 2010/01/02 16:57:50 momjian Exp $ |
| 13 | + * $PostgreSQL: pgsql/src/backend/port/sysv_shmem.c,v 1.56 2010/05/01 22:46:30 tgl Exp $ |
14 | 14 | *
|
15 | 15 | *-------------------------------------------------------------------------
|
16 | 16 | */
|
@@ -92,6 +92,48 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size)
|
92 | 92 | )
|
93 | 93 | return NULL;
|
94 | 94 |
|
| 95 | + /* |
| 96 | + * Some BSD-derived kernels are known to return EINVAL, not EEXIST, |
| 97 | + * if there is an existing segment but it's smaller than "size" |
| 98 | + * (this is a result of poorly-thought-out ordering of error tests). |
| 99 | + * To distinguish between collision and invalid size in such cases, |
| 100 | + * we make a second try with size = 0. These kernels do not test |
| 101 | + * size against SHMMIN in the preexisting-segment case, so we will |
| 102 | + * not get EINVAL a second time if there is such a segment. |
| 103 | + */ |
| 104 | + if (errno == EINVAL) |
| 105 | + { |
| 106 | + int save_errno = errno; |
| 107 | + |
| 108 | + shmid = shmget(memKey, 0, IPC_CREAT | IPC_EXCL | IPCProtection); |
| 109 | + |
| 110 | + if (shmid < 0) |
| 111 | + { |
| 112 | + /* As above, fail quietly if we verify a collision */ |
| 113 | + if (errno == EEXIST || errno == EACCES |
| 114 | +#ifdef EIDRM |
| 115 | + || errno == EIDRM |
| 116 | +#endif |
| 117 | + ) |
| 118 | + return NULL; |
| 119 | + /* Otherwise, fall through to report the original error */ |
| 120 | + } |
| 121 | + else |
| 122 | + { |
| 123 | + /* |
| 124 | + * On most platforms we cannot get here because SHMMIN is |
| 125 | + * greater than zero. However, if we do succeed in creating |
| 126 | + * a zero-size segment, free it and then fall through to |
| 127 | + * report the original error. |
| 128 | + */ |
| 129 | + if (shmctl(shmid, IPC_RMID, NULL) < 0) |
| 130 | + elog(LOG, "shmctl(%d, %d, 0) failed: %m", |
| 131 | + (int) shmid, IPC_RMID); |
| 132 | + } |
| 133 | + |
| 134 | + errno = save_errno; |
| 135 | + } |
| 136 | + |
95 | 137 | /*
|
96 | 138 | * Else complain and abort
|
97 | 139 | */
|
|
0 commit comments