]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Fixed handling of shared memory left over by Squid crashes or bugs.
authorMarkus Mayer <code@mmayer.net>
Thu, 28 Jan 2016 01:30:37 +0000 (18:30 -0700)
committerAlex Rousskov <rousskov@measurement-factory.com>
Thu, 28 Jan 2016 01:30:37 +0000 (18:30 -0700)
A Squid instance may inherit an old shared memory segment from the
previous instance as the result of either a Squid crash or an at-exit
cleanup bug. This change fixes two problems triggered by old segments:

1. After an earlier OS X fix (bug 3805; trunk r13947), Squid stopped
   initializing previously used shared memory. Uninitialzed memory
   resulted in subtle bugs and crashes.

2. When called for an old Squid shared memory segment, OS X
   ftruncate() fails with EINVAL, preventing Squid from starting when
   the old segment is still around.

   More specifically: Darwin ftruncate() calls pshm_truncate().
   pshm_truncate() checks if the PSHM_ALLOCATED flag is already set on
   the memory region. If the flag is set, the call fails with EINVAL.
   Otherwise, pshm_truncate() sets PSHM_ALLOCATED for the region.
   Since Squid must call ftruncate() to size every new segment, all
   old Squid segments have that flag set, preventing ftruncate() calls
   for old segments in newer Sqid instances from succeeding.

   [1] http://www.opensource.apple.com/source/xnu/xnu-3248.20.55/bsd/kern/posix_shm.c

To fix both problems, Squid now uses shm_open(O_EXCL) to detect the
existence of an old segment and remove/recreate it as needed.

src/ipc/mem/Segment.cc
src/ipc/mem/Segment.h

index 8498ac51ea2f9d039e1794078e3222b71d89e15f..dfc363d7de1b88bd838522ed2c7e1a75ace9a3f0 100644 (file)
@@ -88,9 +88,15 @@ Ipc::Mem::Segment::create(const off_t aSize)
     assert(aSize > 0);
     assert(theFD < 0);
 
-    // OS X does not allow using O_TRUNC here.
-    theFD = shm_open(theName.termedBuf(), O_CREAT | O_RDWR,
-                     S_IRUSR | S_IWUSR);
+    // Why a brand new segment? A Squid crash may leave a reusable segment, but
+    // our placement-new code requires an all-0s segment. We could truncate and
+    // resize the old segment, but OS X does not allow using O_TRUNC with
+    // shm_open() and does not support ftruncate() for old segments.
+    if (!createFresh() && errno == EEXIST) {
+        unlink();
+        createFresh();
+    }
+
     if (theFD < 0) {
         debugs(54, 5, HERE << "shm_open " << theName << ": " << xstrerror());
         fatalf("Ipc::Mem::Segment::create failed to shm_open(%s): %s\n",
@@ -138,6 +144,17 @@ Ipc::Mem::Segment::open()
     attach();
 }
 
+/// Creates a brand new shared memory segment and returns true.
+/// Fails and returns false if there exist an old segment with the same name.
+bool
+Ipc::Mem::Segment::createFresh()
+{
+    theFD = shm_open(theName.termedBuf(),
+                     O_EXCL | O_CREAT | O_RDWR,
+                     S_IRUSR | S_IWUSR);
+    return theFD >= 0;
+}
+
 /// Map the shared memory segment to the process memory space.
 void
 Ipc::Mem::Segment::attach()
index f62261332272f6b7d5776c6d8a885a6b74d675be..e62171ca33c83e6c32ce9ff82a8b11ede6bff6a8 100644 (file)
@@ -54,6 +54,7 @@ private:
 
 #if HAVE_SHM
 
+    bool createFresh();
     void attach();
     void detach();
     void unlink(); ///< unlink the segment