Print this page
9525 kmem_dump_size is a corrupting influence
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Richard Lowe <richlowe@richlowe.net>
Approved by: Dan McDonald <danmcd@joyent.com>
        
*** 2209,2245 ****
  
  #define KMEM_DUMPCTL(cp, buf)   \
          ((kmem_dumpctl_t *)P2ROUNDUP((uintptr_t)(buf) + (cp)->cache_bufsize, \
              sizeof (void *)))
  
- /* Keep some simple stats. */
- #define KMEM_DUMP_LOGS  (100)
- 
- typedef struct kmem_dump_log {
-         kmem_cache_t    *kdl_cache;
-         uint_t          kdl_allocs;             /* # of dump allocations */
-         uint_t          kdl_frees;              /* # of dump frees */
-         uint_t          kdl_alloc_fails;        /* # of allocation failures */
-         uint_t          kdl_free_nondump;       /* # of non-dump frees */
-         uint_t          kdl_unsafe;             /* cache was used, but unsafe */
- } kmem_dump_log_t;
- 
- static kmem_dump_log_t *kmem_dump_log;
- static int kmem_dump_log_idx;
- 
- #define KDI_LOG(cp, stat) {                                             \
-         kmem_dump_log_t *kdl;                                           \
-         if ((kdl = (kmem_dump_log_t *)((cp)->cache_dumplog)) != NULL) { \
-                 kdl->stat++;                                            \
-         } else if (kmem_dump_log_idx < KMEM_DUMP_LOGS) {                \
-                 kdl = &kmem_dump_log[kmem_dump_log_idx++];              \
-                 kdl->stat++;                                            \
-                 kdl->kdl_cache = (cp);                                  \
-                 (cp)->cache_dumplog = kdl;                              \
-         }                                                               \
- }
- 
  /* set non zero for full report */
  uint_t kmem_dump_verbose = 0;
  
  /* stats for overize heap */
  uint_t kmem_dump_oversize_allocs = 0;
--- 2209,2218 ----
*** 2265,2293 ****
   * Called when dumpadm(1M) configures dump parameters.
   */
  void
  kmem_dump_init(size_t size)
  {
          if (kmem_dump_start != NULL)
                  kmem_free(kmem_dump_start, kmem_dump_size);
  
-         if (kmem_dump_log == NULL)
-                 kmem_dump_log = (kmem_dump_log_t *)kmem_zalloc(KMEM_DUMP_LOGS *
-                     sizeof (kmem_dump_log_t), KM_SLEEP);
- 
          kmem_dump_start = kmem_alloc(size, KM_SLEEP);
- 
-         if (kmem_dump_start != NULL) {
                  kmem_dump_size = size;
                  kmem_dump_curr = kmem_dump_start;
                  kmem_dump_end = (void *)((char *)kmem_dump_start + size);
                  copy_pattern(KMEM_UNINITIALIZED_PATTERN, kmem_dump_start, size);
-         } else {
-                 kmem_dump_size = 0;
-                 kmem_dump_curr = NULL;
-                 kmem_dump_end = NULL;
-         }
  }
  
  /*
   * Set flag for each kmem_cache_t if is safe to use alternate dump
   * memory. Called just before panic crash dump starts. Set the flag
--- 2238,2258 ----
   * Called when dumpadm(1M) configures dump parameters.
   */
  void
  kmem_dump_init(size_t size)
  {
+         /* Our caller ensures size is always set. */
+         ASSERT3U(size, >, 0);
+ 
          if (kmem_dump_start != NULL)
                  kmem_free(kmem_dump_start, kmem_dump_size);
  
          kmem_dump_start = kmem_alloc(size, KM_SLEEP);
          kmem_dump_size = size;
          kmem_dump_curr = kmem_dump_start;
          kmem_dump_end = (void *)((char *)kmem_dump_start + size);
          copy_pattern(KMEM_UNINITIALIZED_PATTERN, kmem_dump_start, size);
  }
  
  /*
   * Set flag for each kmem_cache_t if is safe to use alternate dump
   * memory. Called just before panic crash dump starts. Set the flag
*** 2294,2307 ****
   * for the calling CPU.
   */
  void
  kmem_dump_begin(void)
  {
-         ASSERT(panicstr != NULL);
-         if (kmem_dump_start != NULL) {
                  kmem_cache_t *cp;
  
                  for (cp = list_head(&kmem_caches); cp != NULL;
                      cp = list_next(&kmem_caches, cp)) {
                          kmem_cpu_cache_t *ccp = KMEM_CPU_CACHE(cp);
  
                          if (cp->cache_arena->vm_cflags & VMC_DUMPSAFE) {
--- 2259,2272 ----
   * for the calling CPU.
   */
  void
  kmem_dump_begin(void)
  {
          kmem_cache_t *cp;
  
+         ASSERT(panicstr != NULL);
+ 
          for (cp = list_head(&kmem_caches); cp != NULL;
              cp = list_next(&kmem_caches, cp)) {
                  kmem_cpu_cache_t *ccp = KMEM_CPU_CACHE(cp);
  
                  if (cp->cache_arena->vm_cflags & VMC_DUMPSAFE) {
*** 2313,2323 ****
                          } else {
                                  cp->cache_flags |= KMF_DUMPUNSAFE;
                                  ccp->cc_flags |= KMF_DUMPUNSAFE;
                          }
                  }
-         }
  }
  
  /*
   * finished dump intercept
   * print any warnings on the console
--- 2278,2287 ----
*** 2324,2345 ****
   * return verbose information to dumpsys() in the given buffer
   */
  size_t
  kmem_dump_finish(char *buf, size_t size)
  {
-         int kdi_idx;
-         int kdi_end = kmem_dump_log_idx;
          int percent = 0;
-         int header = 0;
-         int warn = 0;
          size_t used;
-         kmem_cache_t *cp;
-         kmem_dump_log_t *kdl;
          char *e = buf + size;
          char *p = buf;
  
!         if (kmem_dump_size == 0 || kmem_dump_verbose == 0)
                  return (0);
  
          used = (char *)kmem_dump_curr - (char *)kmem_dump_start;
          percent = (used * 100) / kmem_dump_size;
  
--- 2288,2309 ----
   * return verbose information to dumpsys() in the given buffer
   */
  size_t
  kmem_dump_finish(char *buf, size_t size)
  {
          int percent = 0;
          size_t used;
          char *e = buf + size;
          char *p = buf;
  
!         if (kmem_dump_curr == kmem_dump_end) {
!                 cmn_err(CE_WARN, "exceeded kmem_dump space of %lu "
!                     "bytes: kmem state in dump may be inconsistent",
!                     kmem_dump_size);
!         }
! 
!         if (kmem_dump_verbose == 0)
                  return (0);
  
          used = (char *)kmem_dump_curr - (char *)kmem_dump_start;
          percent = (used * 100) / kmem_dump_size;
  
*** 2349,2377 ****
          kmem_dumppr(&p, e, "Oversize allocs,%d\n",
              kmem_dump_oversize_allocs);
          kmem_dumppr(&p, e, "Oversize max size,%ld\n",
              kmem_dump_oversize_max);
  
-         for (kdi_idx = 0; kdi_idx < kdi_end; kdi_idx++) {
-                 kdl = &kmem_dump_log[kdi_idx];
-                 cp = kdl->kdl_cache;
-                 if (cp == NULL)
-                         break;
-                 if (kdl->kdl_alloc_fails)
-                         ++warn;
-                 if (header == 0) {
-                         kmem_dumppr(&p, e,
-                             "Cache Name,Allocs,Frees,Alloc Fails,"
-                             "Nondump Frees,Unsafe Allocs/Frees\n");
-                         header = 1;
-                 }
-                 kmem_dumppr(&p, e, "%s,%d,%d,%d,%d,%d\n",
-                     cp->cache_name, kdl->kdl_allocs, kdl->kdl_frees,
-                     kdl->kdl_alloc_fails, kdl->kdl_free_nondump,
-                     kdl->kdl_unsafe);
-         }
- 
          /* return buffer size used */
          if (p < e)
                  bzero(p, e - p);
          return (p - buf);
  }
--- 2313,2322 ----
*** 2385,2397 ****
          void *buf;
          void *curr;
          char *bufend;
  
          /* return a constructed object */
!         if ((buf = cp->cache_dumpfreelist) != NULL) {
!                 cp->cache_dumpfreelist = KMEM_DUMPCTL(cp, buf)->kdc_next;
!                 KDI_LOG(cp, kdl_allocs);
                  return (buf);
          }
  
          /* create a new constructed object */
          curr = kmem_dump_curr;
--- 2330,2341 ----
          void *buf;
          void *curr;
          char *bufend;
  
          /* return a constructed object */
!         if ((buf = cp->cache_dump.kd_freelist) != NULL) {
!                 cp->cache_dump.kd_freelist = KMEM_DUMPCTL(cp, buf)->kdc_next;
                  return (buf);
          }
  
          /* create a new constructed object */
          curr = kmem_dump_curr;
*** 2408,2418 ****
          }
  
          /* fall back to normal alloc if reserved area is used up */
          if (bufend > (char *)kmem_dump_end) {
                  kmem_dump_curr = kmem_dump_end;
!                 KDI_LOG(cp, kdl_alloc_fails);
                  return (NULL);
          }
  
          /*
           * Must advance curr pointer before calling a constructor that
--- 2352,2362 ----
          }
  
          /* fall back to normal alloc if reserved area is used up */
          if (bufend > (char *)kmem_dump_end) {
                  kmem_dump_curr = kmem_dump_end;
!                 cp->cache_dump.kd_alloc_fails++;
                  return (NULL);
          }
  
          /*
           * Must advance curr pointer before calling a constructor that
*** 2430,2445 ****
  #endif
                  /* reset curr pointer iff no allocs were done */
                  if (kmem_dump_curr == bufend)
                          kmem_dump_curr = curr;
  
                  /* fall back to normal alloc if the constructor fails */
-                 KDI_LOG(cp, kdl_alloc_fails);
                  return (NULL);
          }
  
-         KDI_LOG(cp, kdl_allocs);
          return (buf);
  }
  
  /*
   * Free a constructed object in alternate dump memory.
--- 2374,2388 ----
  #endif
                  /* reset curr pointer iff no allocs were done */
                  if (kmem_dump_curr == bufend)
                          kmem_dump_curr = curr;
  
+                 cp->cache_dump.kd_alloc_fails++;
                  /* fall back to normal alloc if the constructor fails */
                  return (NULL);
          }
  
          return (buf);
  }
  
  /*
   * Free a constructed object in alternate dump memory.
*** 2448,2466 ****
  kmem_cache_free_dump(kmem_cache_t *cp, void *buf)
  {
          /* save constructed buffers for next time */
          if ((char *)buf >= (char *)kmem_dump_start &&
              (char *)buf < (char *)kmem_dump_end) {
!                 KMEM_DUMPCTL(cp, buf)->kdc_next = cp->cache_dumpfreelist;
!                 cp->cache_dumpfreelist = buf;
!                 KDI_LOG(cp, kdl_frees);
                  return (0);
          }
  
-         /* count all non-dump buf frees */
-         KDI_LOG(cp, kdl_free_nondump);
- 
          /* just drop buffers that were allocated before dump started */
          if (kmem_dump_curr < kmem_dump_end)
                  return (0);
  
          /* fall back to normal free if reserved area is used up */
--- 2391,2405 ----
  kmem_cache_free_dump(kmem_cache_t *cp, void *buf)
  {
          /* save constructed buffers for next time */
          if ((char *)buf >= (char *)kmem_dump_start &&
              (char *)buf < (char *)kmem_dump_end) {
!                 KMEM_DUMPCTL(cp, buf)->kdc_next = cp->cache_dump.kd_freelist;
!                 cp->cache_dump.kd_freelist = buf;
                  return (0);
          }
  
          /* just drop buffers that were allocated before dump started */
          if (kmem_dump_curr < kmem_dump_end)
                  return (0);
  
          /* fall back to normal free if reserved area is used up */
*** 2489,2499 ****
                          mutex_exit(&ccp->cc_lock);
                          if (ccp->cc_flags & (KMF_BUFTAG | KMF_DUMPUNSAFE)) {
                                  if (ccp->cc_flags & KMF_DUMPUNSAFE) {
                                          ASSERT(!(ccp->cc_flags &
                                              KMF_DUMPDIVERT));
!                                         KDI_LOG(cp, kdl_unsafe);
                                  }
                                  if ((ccp->cc_flags & KMF_BUFTAG) &&
                                      kmem_cache_alloc_debug(cp, buf, kmflag, 0,
                                      caller()) != 0) {
                                          if (kmflag & KM_NOSLEEP)
--- 2428,2438 ----
                          mutex_exit(&ccp->cc_lock);
                          if (ccp->cc_flags & (KMF_BUFTAG | KMF_DUMPUNSAFE)) {
                                  if (ccp->cc_flags & KMF_DUMPUNSAFE) {
                                          ASSERT(!(ccp->cc_flags &
                                              KMF_DUMPDIVERT));
!                                         cp->cache_dump.kd_unsafe++;
                                  }
                                  if ((ccp->cc_flags & KMF_BUFTAG) &&
                                      kmem_cache_alloc_debug(cp, buf, kmflag, 0,
                                      caller()) != 0) {
                                          if (kmflag & KM_NOSLEEP)
*** 2520,2530 ****
                   */
                  if (ccp->cc_flags & (KMF_DUMPDIVERT | KMF_DUMPUNSAFE)) {
                          if (ccp->cc_flags & KMF_DUMPUNSAFE) {
                                  ASSERT(!(ccp->cc_flags & KMF_DUMPDIVERT));
                                  /* log it so that we can warn about it */
!                                 KDI_LOG(cp, kdl_unsafe);
                          } else {
                                  if ((buf = kmem_cache_alloc_dump(cp, kmflag)) !=
                                      NULL) {
                                          mutex_exit(&ccp->cc_lock);
                                          return (buf);
--- 2459,2469 ----
                   */
                  if (ccp->cc_flags & (KMF_DUMPDIVERT | KMF_DUMPUNSAFE)) {
                          if (ccp->cc_flags & KMF_DUMPUNSAFE) {
                                  ASSERT(!(ccp->cc_flags & KMF_DUMPDIVERT));
                                  /* log it so that we can warn about it */
!                                 cp->cache_dump.kd_unsafe++;
                          } else {
                                  if ((buf = kmem_cache_alloc_dump(cp, kmflag)) !=
                                      NULL) {
                                          mutex_exit(&ccp->cc_lock);
                                          return (buf);
*** 2716,2726 ****
  
          if (ccp->cc_flags & (KMF_BUFTAG | KMF_DUMPDIVERT | KMF_DUMPUNSAFE)) {
                  if (ccp->cc_flags & KMF_DUMPUNSAFE) {
                          ASSERT(!(ccp->cc_flags & KMF_DUMPDIVERT));
                          /* log it so that we can warn about it */
!                         KDI_LOG(cp, kdl_unsafe);
                  } else if (KMEM_DUMPCC(ccp) && !kmem_cache_free_dump(cp, buf)) {
                          return;
                  }
                  if (ccp->cc_flags & KMF_BUFTAG) {
                          if (kmem_cache_free_debug(cp, buf, caller()) == -1)
--- 2655,2665 ----
  
          if (ccp->cc_flags & (KMF_BUFTAG | KMF_DUMPDIVERT | KMF_DUMPUNSAFE)) {
                  if (ccp->cc_flags & KMF_DUMPUNSAFE) {
                          ASSERT(!(ccp->cc_flags & KMF_DUMPDIVERT));
                          /* log it so that we can warn about it */
!                         cp->cache_dump.kd_unsafe++;
                  } else if (KMEM_DUMPCC(ccp) && !kmem_cache_free_dump(cp, buf)) {
                          return;
                  }
                  if (ccp->cc_flags & KMF_BUFTAG) {
                          if (kmem_cache_free_debug(cp, buf, caller()) == -1)