You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by zw...@apache.org on 2020/10/08 19:49:17 UTC

[trafficserver] branch 9.0.x updated: Stop crash on disk failure (#7218)

This is an automated email from the ASF dual-hosted git repository.

zwoop pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/9.0.x by this push:
     new fc1e930  Stop crash on disk failure (#7218)
fc1e930 is described below

commit fc1e930a707ca4addc0ad54dda51663864bd442b
Author: Susan Hinrichs <sh...@yahoo-inc.com>
AuthorDate: Mon Oct 5 10:25:42 2020 -0500

    Stop crash on disk failure (#7218)
    
    (cherry picked from commit ab378643b1decf53c51a0bcf52ff54bdf0d87504)
---
 iocore/cache/Cache.cc | 75 ++++++++++++++++++++++++++++++++-------------------
 1 file changed, 48 insertions(+), 27 deletions(-)

diff --git a/iocore/cache/Cache.cc b/iocore/cache/Cache.cc
index f84f50f..247689f 100644
--- a/iocore/cache/Cache.cc
+++ b/iocore/cache/Cache.cc
@@ -589,13 +589,22 @@ CacheProcessor::start_internal(int flags)
   fix                  = !!(flags & PROCESSOR_FIX);
   check                = (flags & PROCESSOR_CHECK) != 0;
   start_done           = 0;
-  Span *sd;
 
   /* read the config file and create the data structures corresponding
      to the file */
   gndisks = theCacheStore.n_disks;
   gdisks  = static_cast<CacheDisk **>(ats_malloc(gndisks * sizeof(CacheDisk *)));
 
+  // Temporaries to carry values between loops
+  char **paths = static_cast<char **>(alloca(sizeof(char *) * gndisks));
+  memset(paths, 0, sizeof(char *) * gndisks);
+  int *fds = static_cast<int *>(alloca(sizeof(int) * gndisks));
+  memset(fds, 0, sizeof(int) * gndisks);
+  int *sector_sizes = static_cast<int *>(alloca(sizeof(int) * gndisks));
+  memset(sector_sizes, 0, sizeof(int) * gndisks);
+  Span **sds = static_cast<Span **>(alloca(sizeof(Span *) * gndisks));
+  memset(sds, 0, sizeof(Span *) * gndisks);
+
   gndisks = 0;
   ink_aio_set_callback(new AIO_Callback_handler());
 
@@ -605,13 +614,15 @@ CacheProcessor::start_internal(int flags)
    create CacheDisk objects for each span in the configuration file and store in gdisks
    */
   for (unsigned i = 0; i < theCacheStore.n_disks; i++) {
-    sd = theCacheStore.disk[i];
-    char path[PATH_NAME_MAX];
+    Span *sd = theCacheStore.disk[i];
     int opts = DEFAULT_CACHE_OPTIONS;
 
-    ink_strlcpy(path, sd->pathname, sizeof(path));
+    if (!paths[gndisks]) {
+      paths[gndisks] = static_cast<char *>(alloca(PATH_NAME_MAX));
+    }
+    ink_strlcpy(paths[gndisks], sd->pathname, PATH_NAME_MAX);
     if (!sd->file_pathname) {
-      ink_strlcat(path, "/cache.db", sizeof(path));
+      ink_strlcat(paths[gndisks], "/cache.db", PATH_NAME_MAX);
       opts |= O_CREAT;
     }
 
@@ -626,11 +637,11 @@ CacheProcessor::start_internal(int flags)
       opts |= O_RDONLY;
     }
 
-    int fd         = open(path, opts, 0644);
+    int fd         = open(paths[gndisks], opts, 0644);
     int64_t blocks = sd->blocks;
 
     if (fd < 0 && (opts & O_CREAT)) { // Try without O_DIRECT if this is a file on filesystem, e.g. tmpfs.
-      fd = open(path, DEFAULT_CACHE_OPTIONS | O_CREAT, 0644);
+      fd = open(paths[gndisks], DEFAULT_CACHE_OPTIONS | O_CREAT, 0644);
     }
 
     if (fd >= 0) {
@@ -638,17 +649,17 @@ CacheProcessor::start_internal(int flags)
       if (!sd->file_pathname) {
         if (!check) {
           if (ftruncate(fd, blocks * STORE_BLOCK_SIZE) < 0) {
-            Warning("unable to truncate cache file '%s' to %" PRId64 " blocks", path, blocks);
+            Warning("unable to truncate cache file '%s' to %" PRId64 " blocks", paths[gndisks], blocks);
             diskok = false;
           }
         } else { // read-only mode checks
           struct stat sbuf;
           if (-1 == fstat(fd, &sbuf)) {
-            fprintf(stderr, "Failed to stat cache file for directory %s\n", path);
+            fprintf(stderr, "Failed to stat cache file for directory %s\n", paths[gndisks]);
             diskok = false;
           } else if (blocks != sbuf.st_size / STORE_BLOCK_SIZE) {
-            fprintf(stderr, "Cache file for directory %s is %" PRId64 " bytes, expected %" PRId64 "\n", path, sbuf.st_size,
-                    blocks * static_cast<int64_t>(STORE_BLOCK_SIZE));
+            fprintf(stderr, "Cache file for directory %s is %" PRId64 " bytes, expected %" PRId64 "\n", paths[gndisks],
+                    sbuf.st_size, blocks * static_cast<int64_t>(STORE_BLOCK_SIZE));
             diskok = false;
           }
         }
@@ -676,24 +687,17 @@ CacheProcessor::start_internal(int flags)
           Note("resetting hardware sector size from %d to %d", sector_size, STORE_BLOCK_SIZE);
           sector_size = STORE_BLOCK_SIZE;
         }
-
-        off_t skip = ROUND_TO_STORE_BLOCK((sd->offset < START_POS ? START_POS + sd->alignment : sd->offset));
-        blocks     = blocks - (skip >> STORE_BLOCK_SHIFT);
-#if AIO_MODE == AIO_MODE_NATIVE
-        eventProcessor.schedule_imm(new DiskInit(gdisks[gndisks], path, blocks, skip, sector_size, fd, clear));
-#else
-        gdisks[gndisks]->open(path, blocks, skip, sector_size, fd, clear);
-#endif
-
-        Debug("cache_hosting", "Disk: %d:%s, blocks: %" PRId64 "", gndisks, path, blocks);
-        fd = -1;
+        sector_sizes[gndisks] = sector_size;
+        fds[gndisks]          = fd;
+        sds[gndisks]          = sd;
+        fd                    = -1;
         gndisks++;
       }
     } else {
       if (errno == EINVAL) {
-        Warning("cache unable to open '%s': It must be placed on a file system that supports direct I/O.", path);
+        Warning("cache unable to open '%s': It must be placed on a file system that supports direct I/O.", paths[gndisks]);
       } else {
-        Warning("cache unable to open '%s': %s", path, strerror(errno));
+        Warning("cache unable to open '%s': %s", paths[gndisks], strerror(errno));
       }
     }
     if (fd >= 0) {
@@ -701,6 +705,8 @@ CacheProcessor::start_internal(int flags)
     }
   }
 
+  // Before we kick off asynchronous operations, make sure sufficient disks are available and we don't just shutdown
+  // Exiting with background threads in operation will likely cause a seg fault
   start_done = 1;
 
   if (gndisks == 0) {
@@ -711,7 +717,7 @@ CacheProcessor::start_internal(int flags)
     }
 
     if (this->waitForCache() > 1) {
-      Fatal("Cache initialization failed - no disks available but cache required");
+      Emergency("Cache initialization failed - no disks available but cache required");
     } else {
       Warning("unable to open cache disk(s): Cache Disabled\n");
       return -1; // pointless, AFAICT this is ignored.
@@ -721,8 +727,23 @@ CacheProcessor::start_internal(int flags)
     if (cb_after_init) {
       cb_after_init();
     }
-    Fatal("Cache initialization failed - only %d out of %d disks were valid and all were required.", gndisks,
-          theCacheStore.n_disks_in_config);
+    Emergency("Cache initialization failed - only %d out of %d disks were valid and all were required.", gndisks,
+              theCacheStore.n_disks_in_config);
+  }
+
+  // If we got here, we have enough disks to proceed
+  for (int j = 0; j < gndisks; j++) {
+    Span *sd = sds[j];
+    ink_release_assert(sds[j] != nullptr); // Defeat clang-analyzer
+    off_t skip     = ROUND_TO_STORE_BLOCK((sd->offset < START_POS ? START_POS + sd->alignment : sd->offset));
+    int64_t blocks = sd->blocks - (skip >> STORE_BLOCK_SHIFT);
+#if AIO_MODE == AIO_MODE_NATIVE
+    eventProcessor.schedule_imm(new DiskInit(gdisks[j], paths[j], blocks, skip, sector_sizes[j], fds[j], clear));
+#else
+    gdisks[j]->open(paths[j], blocks, skip, sector_sizes[j], fds[j], clear);
+#endif
+
+    Debug("cache_hosting", "Disk: %d:%s, blocks: %" PRId64 "", gndisks, paths[j], blocks);
   }
 
   return 0;