Print this page
    
NEX-17845 Remove support for BZIP2 from dump
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-14185 savecore -f vmdump.1 tries to unpack this to unix.0 and vmcore.0 and other nits
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-9338 improve the layout of the crash directory (follow-up)
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-9338 improve the layout of the crash directory
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Steve Peng <steve.peng@nexenta.com>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/savecore/savecore.c
          +++ new/usr/src/cmd/savecore/savecore.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  
    | 
      ↓ open down ↓ | 
    15 lines elided | 
    
      ↑ open up ↑ | 
  
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 1983, 2010, Oracle and/or its affiliates. All rights reserved.
  23   23   * Copyright 2016 Joyent, Inc.
  24   24   */
  25   25  /*
  26      - * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
       26 + * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
  27   27   */
  28   28  
  29   29  #include <stdio.h>
  30   30  #include <stdlib.h>
  31   31  #include <stdarg.h>
  32   32  #include <unistd.h>
  33   33  #include <fcntl.h>
  34   34  #include <errno.h>
  35   35  #include <string.h>
  36   36  #include <deflt.h>
  37   37  #include <time.h>
  38   38  #include <syslog.h>
  39   39  #include <stropts.h>
  40   40  #include <pthread.h>
  41   41  #include <limits.h>
  42   42  #include <atomic.h>
  43   43  #include <libnvpair.h>
  
    | 
      ↓ open down ↓ | 
    7 lines elided | 
    
      ↑ open up ↑ | 
  
  44   44  #include <libintl.h>
  45   45  #include <sys/mem.h>
  46   46  #include <sys/statvfs.h>
  47   47  #include <sys/dumphdr.h>
  48   48  #include <sys/dumpadm.h>
  49   49  #include <sys/compress.h>
  50   50  #include <sys/panic.h>
  51   51  #include <sys/sysmacros.h>
  52   52  #include <sys/stat.h>
  53   53  #include <sys/resource.h>
  54      -#include <bzip2/bzlib.h>
  55   54  #include <sys/fm/util.h>
  56   55  #include <fm/libfmevent.h>
  57   56  #include <sys/int_fmtio.h>
       57 +#include <uuid/uuid.h>
       58 +#include <libgen.h>
  58   59  
  59   60  
  60   61  /* fread/fwrite buffer size */
  61   62  #define FBUFSIZE                (1ULL << 20)
  62   63  
  63   64  /* minimum size for output buffering */
  64   65  #define MINCOREBLKSIZE          (1ULL << 17)
  65   66  
  66   67  /* create this file if metrics collection is enabled in the kernel */
  67   68  #define METRICSFILE "METRICS.csv"
  68   69  
  69   70  static char     progname[9] = "savecore";
  70   71  static char     *savedir;               /* savecore directory */
       72 +static char     uuiddir[MAXPATHLEN];    /* UUID directory */
  71   73  static char     *dumpfile;              /* source of raw crash dump */
  72   74  static long     bounds = -1;            /* numeric suffix */
  73   75  static long     pagesize;               /* dump pagesize */
  74   76  static int      dumpfd = -1;            /* dumpfile descriptor */
       77 +static boolean_t skip_event = B_FALSE;  /* do not raise an event */
  75   78  static boolean_t have_dumpfile = B_TRUE;        /* dumpfile existence */
  76   79  static dumphdr_t corehdr, dumphdr;      /* initial and terminal dumphdrs */
  77   80  static boolean_t dump_incomplete;       /* dumphdr indicates incomplete */
  78   81  static boolean_t fm_panic;              /* dump is the result of fm_panic */
  79   82  static offset_t endoff;                 /* offset of end-of-dump header */
  80   83  static int      verbose;                /* chatty mode */
  81   84  static int      disregard_valid_flag;   /* disregard valid flag */
  82   85  static int      livedump;               /* dump the current running system */
  83   86  static int      interactive;            /* user invoked; no syslog */
  84   87  static int      csave;                  /* save dump compressed */
  85   88  static int      filemode;               /* processing file, not dump device */
  86   89  static int      percent_done;           /* progress indicator */
  87   90  static int      sec_done;               /* progress last report time */
  88   91  static hrtime_t startts;                /* timestamp at start */
  89   92  static volatile uint64_t saved;         /* count of pages written */
  90   93  static volatile uint64_t zpages;        /* count of zero pages not written */
  91   94  static dumpdatahdr_t datahdr;           /* compression info */
  92   95  static long     coreblksize;            /* preferred write size (st_blksize) */
  93   96  static int      cflag;                  /* run as savecore -c */
  94   97  static int      mflag;                  /* run as savecore -m */
       98 +static int      fflag;                  /* -f option used */
  95   99  
  96  100  /*
  97  101   * Payload information for the events we raise.  These are used
  98  102   * in raise_event to determine what payload to include.
  99  103   */
 100  104  #define SC_PAYLOAD_SAVEDIR      0x0001  /* Include savedir in event */
 101  105  #define SC_PAYLOAD_INSTANCE     0x0002  /* Include bounds instance number */
 102  106  #define SC_PAYLOAD_IMAGEUUID    0x0004  /* Include dump OS instance uuid */
 103  107  #define SC_PAYLOAD_CRASHTIME    0x0008  /* Include epoch crashtime */
 104  108  #define SC_PAYLOAD_PANICSTR     0x0010  /* Include panic string */
 105  109  #define SC_PAYLOAD_PANICSTACK   0x0020  /* Include panic string */
 106  110  #define SC_PAYLOAD_FAILREASON   0x0040  /* Include failure reason */
 107  111  #define SC_PAYLOAD_DUMPCOMPLETE 0x0080  /* Include completeness indicator */
 108  112  #define SC_PAYLOAD_ISCOMPRESSED 0x0100  /* Dump is in vmdump.N form */
 109  113  #define SC_PAYLOAD_DUMPADM_EN   0x0200  /* Is dumpadm enabled or not? */
 110  114  #define SC_PAYLOAD_FM_PANIC     0x0400  /* Panic initiated by FMA */
 111  115  #define SC_PAYLOAD_JUSTCHECKING 0x0800  /* Run with -c flag? */
 112  116  
 113  117  enum sc_event_type {
 114  118          SC_EVENT_DUMP_PENDING,
 115  119          SC_EVENT_SAVECORE_FAILURE,
 116  120          SC_EVENT_DUMP_AVAILABLE
 117  121  };
 118  122  
 119  123  /*
 120  124   * Common payload
 121  125   */
 122  126  #define _SC_PAYLOAD_CMN \
 123  127      SC_PAYLOAD_IMAGEUUID | \
 124  128      SC_PAYLOAD_CRASHTIME | \
 125  129      SC_PAYLOAD_PANICSTR | \
 126  130      SC_PAYLOAD_PANICSTACK | \
 127  131      SC_PAYLOAD_DUMPCOMPLETE | \
 128  132      SC_PAYLOAD_FM_PANIC | \
 129  133      SC_PAYLOAD_SAVEDIR
 130  134  
 131  135  static const struct {
 132  136          const char *sce_subclass;
 133  137          uint32_t sce_payload;
 134  138  } sc_event[] = {
 135  139          /*
 136  140           * SC_EVENT_DUMP_PENDING
 137  141           */
 138  142          {
 139  143                  "dump_pending_on_device",
 140  144                  _SC_PAYLOAD_CMN | SC_PAYLOAD_DUMPADM_EN |
 141  145                      SC_PAYLOAD_JUSTCHECKING
 142  146          },
 143  147  
 144  148          /*
 145  149           * SC_EVENT_SAVECORE_FAILURE
 146  150           */
 147  151          {
 148  152                  "savecore_failure",
 149  153                  _SC_PAYLOAD_CMN | SC_PAYLOAD_INSTANCE | SC_PAYLOAD_FAILREASON
 150  154          },
 151  155  
 152  156          /*
 153  157           * SC_EVENT_DUMP_AVAILABLE
 154  158           */
 155  159          {
 156  160                  "dump_available",
 157  161                  _SC_PAYLOAD_CMN | SC_PAYLOAD_INSTANCE | SC_PAYLOAD_ISCOMPRESSED
 158  162          },
 159  163  };
 160  164  
 161  165  static void raise_event(enum sc_event_type, char *);
 162  166  
 163  167  static void
 164  168  usage(void)
 165  169  {
 166  170          (void) fprintf(stderr,
 167  171              "usage: %s [-Lvd] [-f dumpfile] [dirname]\n", progname);
 168  172          exit(1);
 169  173  }
 170  174  
 171  175  #define SC_SL_NONE      0x0001  /* no syslog */
 172  176  #define SC_SL_ERR       0x0002  /* syslog if !interactive, LOG_ERR */
 173  177  #define SC_SL_WARN      0x0004  /* syslog if !interactive, LOG_WARNING */
 174  178  #define SC_IF_VERBOSE   0x0008  /* message only if -v */
 175  179  #define SC_IF_ISATTY    0x0010  /* message only if interactive */
 176  180  #define SC_EXIT_OK      0x0020  /* exit(0) */
 177  181  #define SC_EXIT_ERR     0x0040  /* exit(1) */
 178  182  #define SC_EXIT_PEND    0x0080  /* exit(2) */
 179  183  #define SC_EXIT_FM      0x0100  /* exit(3) */
 180  184  
 181  185  #define _SC_ALLEXIT     (SC_EXIT_OK | SC_EXIT_ERR | SC_EXIT_PEND | SC_EXIT_FM)
 182  186  
 183  187  static void
 184  188  logprint(uint32_t flags, char *message, ...)
 185  189  {
 186  190          va_list args;
 187  191          char buf[1024];
 188  192          int do_always = ((flags & (SC_IF_VERBOSE | SC_IF_ISATTY)) == 0);
 189  193          int do_ifverb = (flags & SC_IF_VERBOSE) && verbose;
 190  194          int do_ifisatty = (flags & SC_IF_ISATTY) && interactive;
 191  195          int code;
 192  196          static int logprint_raised = 0;
 193  197  
 194  198          if (do_always || do_ifverb || do_ifisatty) {
 195  199                  va_start(args, message);
 196  200                  /*LINTED: E_SEC_PRINTF_VAR_FMT*/
 197  201                  (void) vsnprintf(buf, sizeof (buf), message, args);
 198  202                  (void) fprintf(stderr, "%s: %s\n", progname, buf);
 199  203                  if (!interactive) {
 200  204                          switch (flags & (SC_SL_NONE | SC_SL_ERR | SC_SL_WARN)) {
 201  205                          case SC_SL_ERR:
 202  206                                  /*LINTED: E_SEC_PRINTF_VAR_FMT*/
 203  207                                  syslog(LOG_ERR, buf);
 204  208                                  break;
 205  209  
 206  210                          case SC_SL_WARN:
 207  211                                  /*LINTED: E_SEC_PRINTF_VAR_FMT*/
 208  212                                  syslog(LOG_WARNING, buf);
 209  213                                  break;
 210  214  
 211  215                          default:
 212  216                                  break;
 213  217                          }
 214  218                  }
 215  219                  va_end(args);
 216  220          }
 217  221  
 218  222          switch (flags & _SC_ALLEXIT) {
 219  223          case 0:
 220  224                  return;
 221  225  
 222  226          case SC_EXIT_OK:
 223  227                  code = 0;
 224  228                  break;
 225  229  
 226  230          case SC_EXIT_PEND:
 227  231                  /*
 228  232                   * Raise an ireport saying why we are exiting.  Do not
 229  233                   * raise if run as savecore -m.  If something in the
 230  234                   * raise_event codepath calls logprint avoid recursion.
 231  235                   */
 232  236                  if (!mflag && logprint_raised++ == 0)
  
    | 
      ↓ open down ↓ | 
    128 lines elided | 
    
      ↑ open up ↑ | 
  
 233  237                          raise_event(SC_EVENT_SAVECORE_FAILURE, buf);
 234  238                  code = 2;
 235  239                  break;
 236  240  
 237  241          case SC_EXIT_FM:
 238  242                  code = 3;
 239  243                  break;
 240  244  
 241  245          case SC_EXIT_ERR:
 242  246          default:
 243      -                if (!mflag && logprint_raised++ == 0 && have_dumpfile)
      247 +                if (!mflag && logprint_raised++ == 0 && !skip_event &&
      248 +                    have_dumpfile)
 244  249                          raise_event(SC_EVENT_SAVECORE_FAILURE, buf);
 245  250                  code = 1;
 246  251                  break;
 247  252          }
 248  253  
 249  254          exit(code);
 250  255  }
 251  256  
 252  257  /*
 253  258   * System call / libc wrappers that exit on error.
 254  259   */
 255  260  static int
 256  261  Open(const char *name, int oflags, mode_t mode)
 257  262  {
 258  263          int fd;
 259  264  
 260  265          if ((fd = open64(name, oflags, mode)) == -1)
 261  266                  logprint(SC_SL_ERR | SC_EXIT_ERR, "open(\"%s\"): %s",
 262  267                      name, strerror(errno));
 263  268          return (fd);
 264  269  }
 265  270  
 266  271  static void
 267  272  Fread(void *buf, size_t size, FILE *f)
 268  273  {
 269  274          if (fread(buf, size, 1, f) != 1)
 270  275                  logprint(SC_SL_ERR | SC_EXIT_ERR, "fread: %s",
 271  276                      strerror(errno));
 272  277  }
 273  278  
 274  279  static void
 275  280  Fwrite(void *buf, size_t size, FILE *f)
 276  281  {
 277  282          if (fwrite(buf, size, 1, f) != 1)
 278  283                  logprint(SC_SL_ERR | SC_EXIT_ERR, "fwrite: %s",
 279  284                      strerror(errno));
 280  285  }
 281  286  
 282  287  static void
 283  288  Fseek(offset_t off, FILE *f)
 284  289  {
 285  290          if (fseeko64(f, off, SEEK_SET) != 0)
 286  291                  logprint(SC_SL_ERR | SC_EXIT_ERR, "fseeko64: %s",
 287  292                      strerror(errno));
 288  293  }
 289  294  
 290  295  typedef struct stat64 Stat_t;
 291  296  
 292  297  static void
 293  298  Fstat(int fd, Stat_t *sb, const char *fname)
  
    | 
      ↓ open down ↓ | 
    40 lines elided | 
    
      ↑ open up ↑ | 
  
 294  299  {
 295  300          if (fstat64(fd, sb) != 0)
 296  301                  logprint(SC_SL_ERR | SC_EXIT_ERR, "fstat(\"%s\"): %s", fname,
 297  302                      strerror(errno));
 298  303  }
 299  304  
 300  305  static void
 301  306  Stat(const char *fname, Stat_t *sb)
 302  307  {
 303  308          if (stat64(fname, sb) != 0) {
      309 +                /*
      310 +                 * If dump/core file doesn't exist, then best
      311 +                 * to not go further (raise an event).
      312 +                 */
      313 +                skip_event = B_TRUE;
 304  314                  have_dumpfile = B_FALSE;
 305  315                  logprint(SC_SL_ERR | SC_EXIT_ERR, "failed to get status "
 306  316                      "of file %s", fname);
 307  317          }
 308  318  }
 309  319  
 310  320  static void
 311  321  Pread(int fd, void *buf, size_t size, offset_t off)
 312  322  {
 313  323          ssize_t sz = pread64(fd, buf, size, off);
 314  324  
 315  325          if (sz < 0)
 316  326                  logprint(SC_SL_ERR | SC_EXIT_ERR,
 317  327                      "pread: %s", strerror(errno));
 318  328          else if (sz != size)
 319  329                  logprint(SC_SL_ERR | SC_EXIT_ERR,
 320  330                      "pread: size %ld != %ld", sz, size);
 321  331  }
 322  332  
 323  333  static void
 324  334  Pwrite(int fd, void *buf, size_t size, off64_t off)
 325  335  {
 326  336          if (pwrite64(fd, buf, size, off) != size)
 327  337                  logprint(SC_SL_ERR | SC_EXIT_ERR, "pwrite: %s",
 328  338                      strerror(errno));
 329  339  }
 330  340  
 331  341  static void *
 332  342  Zalloc(size_t size)
 333  343  {
 334  344          void *buf;
 335  345  
 336  346          if ((buf = calloc(size, 1)) == NULL)
 337  347                  logprint(SC_SL_ERR | SC_EXIT_ERR, "calloc: %s",
 338  348                      strerror(errno));
 339  349          return (buf);
 340  350  }
 341  351  
 342  352  static long
 343  353  read_number_from_file(const char *filename, long default_value)
 344  354  {
 345  355          long file_value = -1;
 346  356          FILE *fp;
 347  357  
 348  358          if ((fp = fopen(filename, "r")) != NULL) {
 349  359                  (void) fscanf(fp, "%ld", &file_value);
 350  360                  (void) fclose(fp);
 351  361          }
 352  362          return (file_value < 0 ? default_value : file_value);
 353  363  }
 354  364  
 355  365  static void
 356  366  read_dumphdr(void)
 357  367  {
 358  368          if (filemode)
 359  369                  dumpfd = Open(dumpfile, O_RDONLY, 0644);
 360  370          else
 361  371                  dumpfd = Open(dumpfile, O_RDWR | O_DSYNC, 0644);
 362  372          endoff = llseek(dumpfd, -DUMP_OFFSET, SEEK_END) & -DUMP_OFFSET;
 363  373          Pread(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
 364  374          Pread(dumpfd, &datahdr, sizeof (datahdr), endoff + sizeof (dumphdr));
 365  375  
 366  376          pagesize = dumphdr.dump_pagesize;
 367  377  
 368  378          if (dumphdr.dump_magic != DUMP_MAGIC)
 369  379                  logprint(SC_SL_NONE | SC_EXIT_PEND, "bad magic number %x",
 370  380                      dumphdr.dump_magic);
  
    | 
      ↓ open down ↓ | 
    57 lines elided | 
    
      ↑ open up ↑ | 
  
 371  381  
 372  382          if ((dumphdr.dump_flags & DF_VALID) == 0 && !disregard_valid_flag)
 373  383                  logprint(SC_SL_NONE | SC_IF_VERBOSE | SC_EXIT_OK,
 374  384                      "dump already processed");
 375  385  
 376  386          if (dumphdr.dump_version != DUMP_VERSION)
 377  387                  logprint(SC_SL_NONE | SC_IF_VERBOSE | SC_EXIT_PEND,
 378  388                      "dump version (%d) != %s version (%d)",
 379  389                      dumphdr.dump_version, progname, DUMP_VERSION);
 380  390  
      391 +        if (datahdr.dump_clevel > DUMP_CLEVEL_LZJB)
      392 +                logprint(SC_SL_NONE | SC_EXIT_PEND,
      393 +                    "unsupported compression format (%d)", datahdr.dump_clevel);
      394 +
 381  395          if (dumphdr.dump_wordsize != DUMP_WORDSIZE)
 382  396                  logprint(SC_SL_NONE | SC_EXIT_PEND,
 383  397                      "dump is from %u-bit kernel - cannot save on %u-bit kernel",
 384  398                      dumphdr.dump_wordsize, DUMP_WORDSIZE);
 385  399  
 386  400          if (datahdr.dump_datahdr_magic == DUMP_DATAHDR_MAGIC) {
 387  401                  if (datahdr.dump_datahdr_version != DUMP_DATAHDR_VERSION)
 388  402                          logprint(SC_SL_NONE | SC_IF_VERBOSE | SC_EXIT_PEND,
 389  403                              "dump data version (%d) != %s data version (%d)",
 390  404                              datahdr.dump_datahdr_version, progname,
 391  405                              DUMP_DATAHDR_VERSION);
 392  406          } else {
 393  407                  (void) memset(&datahdr, 0, sizeof (datahdr));
 394  408                  datahdr.dump_maxcsize = pagesize;
 395  409          }
 396  410  
 397  411          /*
 398  412           * Read the initial header, clear the valid bits, and compare headers.
 399  413           * The main header may have been overwritten by swapping if we're
 400  414           * using a swap partition as the dump device, in which case we bail.
 401  415           */
 402  416          Pread(dumpfd, &corehdr, sizeof (dumphdr_t), dumphdr.dump_start);
 403  417  
 404  418          corehdr.dump_flags &= ~DF_VALID;
 405  419          dumphdr.dump_flags &= ~DF_VALID;
 406  420  
 407  421          if (memcmp(&corehdr, &dumphdr, sizeof (dumphdr_t)) != 0) {
 408  422                  /*
 409  423                   * Clear valid bit so we don't complain on every invocation.
 410  424                   */
 411  425                  if (!filemode)
 412  426                          Pwrite(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
  
    | 
      ↓ open down ↓ | 
    22 lines elided | 
    
      ↑ open up ↑ | 
  
 413  427                  logprint(SC_SL_ERR | SC_EXIT_ERR,
 414  428                      "initial dump header corrupt");
 415  429          }
 416  430  }
 417  431  
 418  432  static void
 419  433  check_space(int csave)
 420  434  {
 421  435          struct statvfs fsb;
 422  436          int64_t spacefree, dumpsize, minfree, datasize;
      437 +        char minfreefile[MAXPATHLEN];
 423  438  
 424  439          if (statvfs(".", &fsb) < 0)
 425  440                  logprint(SC_SL_ERR | SC_EXIT_ERR, "statvfs: %s",
 426  441                      strerror(errno));
 427  442  
      443 +        (void) snprintf(minfreefile, MAXPATHLEN, "%s/minfree", savedir);
      444 +
 428  445          dumpsize = dumphdr.dump_data - dumphdr.dump_start;
 429  446          datasize = dumphdr.dump_npages * pagesize;
 430  447          if (!csave)
 431  448                  dumpsize += datasize;
 432  449          else
 433  450                  dumpsize += datahdr.dump_data_csize;
 434  451  
 435  452          spacefree = (int64_t)fsb.f_bavail * fsb.f_frsize;
 436      -        minfree = 1024LL * read_number_from_file("minfree", 1024);
      453 +        minfree = 1024LL * read_number_from_file(minfreefile, 1024);
 437  454          if (spacefree < minfree + dumpsize) {
 438  455                  logprint(SC_SL_ERR | SC_EXIT_ERR,
 439  456                      "not enough space in %s (%lld MB avail, %lld MB needed)",
 440  457                      savedir, spacefree >> 20, (minfree + dumpsize) >> 20);
 441  458          }
 442  459  }
 443  460  
 444  461  static void
 445  462  build_dump_map(int corefd, const pfn_t *pfn_table)
 446  463  {
 447  464          long i;
 448  465          static long misses = 0;
 449  466          size_t dump_mapsize = (corehdr.dump_hashmask + 1) * sizeof (dump_map_t);
 450  467          mem_vtop_t vtop;
 451  468          dump_map_t *dmp = Zalloc(dump_mapsize);
 452  469          char *inbuf = Zalloc(FBUFSIZE);
 453  470          FILE *in = fdopen(dup(dumpfd), "rb");
 454  471  
 455  472          (void) setvbuf(in, inbuf, _IOFBF, FBUFSIZE);
 456  473          Fseek(dumphdr.dump_map, in);
 457  474  
 458  475          corehdr.dump_data = corehdr.dump_map + roundup(dump_mapsize, pagesize);
 459  476  
 460  477          for (i = 0; i < corehdr.dump_nvtop; i++) {
 461  478                  long first = 0;
 462  479                  long last = corehdr.dump_npages - 1;
 463  480                  long middle = 0;
 464  481                  pfn_t pfn = 0;
 465  482                  uintptr_t h;
 466  483  
 467  484                  Fread(&vtop, sizeof (mem_vtop_t), in);
 468  485                  while (last >= first) {
 469  486                          middle = (first + last) / 2;
 470  487                          pfn = pfn_table[middle];
 471  488                          if (pfn == vtop.m_pfn)
 472  489                                  break;
 473  490                          if (pfn < vtop.m_pfn)
 474  491                                  first = middle + 1;
 475  492                          else
 476  493                                  last = middle - 1;
 477  494                  }
 478  495                  if (pfn != vtop.m_pfn) {
 479  496                          if (++misses <= 10)
 480  497                                  (void) fprintf(stderr,
 481  498                                      "pfn %ld not found for as=%p, va=%p\n",
 482  499                                      vtop.m_pfn, (void *)vtop.m_as, vtop.m_va);
 483  500                          continue;
 484  501                  }
 485  502  
 486  503                  dmp[i].dm_as = vtop.m_as;
 487  504                  dmp[i].dm_va = (uintptr_t)vtop.m_va;
 488  505                  dmp[i].dm_data = corehdr.dump_data +
 489  506                      ((uint64_t)middle << corehdr.dump_pageshift);
 490  507  
 491  508                  h = DUMP_HASH(&corehdr, dmp[i].dm_as, dmp[i].dm_va);
 492  509                  dmp[i].dm_next = dmp[h].dm_first;
 493  510                  dmp[h].dm_first = corehdr.dump_map + i * sizeof (dump_map_t);
 494  511          }
 495  512  
 496  513          Pwrite(corefd, dmp, dump_mapsize, corehdr.dump_map);
 497  514          free(dmp);
 498  515          (void) fclose(in);
 499  516          free(inbuf);
 500  517  }
 501  518  
 502  519  /*
 503  520   * Copy whole sections of the dump device to the file.
 504  521   */
 505  522  static void
 506  523  Copy(offset_t dumpoff, len_t nb, offset_t *offp, int fd, char *buf,
 507  524      size_t sz)
 508  525  {
 509  526          size_t nr;
 510  527          offset_t off = *offp;
 511  528  
 512  529          while (nb > 0) {
 513  530                  nr = sz < nb ? sz : (size_t)nb;
 514  531                  Pread(dumpfd, buf, nr, dumpoff);
 515  532                  Pwrite(fd, buf, nr, off);
 516  533                  off += nr;
 517  534                  dumpoff += nr;
 518  535                  nb -= nr;
 519  536          }
 520  537          *offp = off;
 521  538  }
 522  539  
 523  540  /*
 524  541   * Copy pages when the dump data header is missing.
 525  542   * This supports older kernels with latest savecore.
 526  543   */
 527  544  static void
 528  545  CopyPages(offset_t *offp, int fd, char *buf, size_t sz)
 529  546  {
 530  547          uint32_t csize;
 531  548          FILE *in = fdopen(dup(dumpfd), "rb");
 532  549          FILE *out = fdopen(dup(fd), "wb");
 533  550          char *cbuf = Zalloc(pagesize);
 534  551          char *outbuf = Zalloc(FBUFSIZE);
 535  552          pgcnt_t np = dumphdr.dump_npages;
 536  553  
 537  554          (void) setvbuf(out, outbuf, _IOFBF, FBUFSIZE);
 538  555          (void) setvbuf(in, buf, _IOFBF, sz);
 539  556          Fseek(dumphdr.dump_data, in);
 540  557  
 541  558          Fseek(*offp, out);
 542  559          while (np > 0) {
 543  560                  Fread(&csize, sizeof (uint32_t), in);
 544  561                  Fwrite(&csize, sizeof (uint32_t), out);
 545  562                  *offp += sizeof (uint32_t);
 546  563                  if (csize > pagesize || csize == 0) {
 547  564                          logprint(SC_SL_ERR,
 548  565                              "CopyPages: page %lu csize %d (0x%x) pagesize %d",
 549  566                              dumphdr.dump_npages - np, csize, csize,
 550  567                              pagesize);
 551  568                          break;
 552  569                  }
 553  570                  Fread(cbuf, csize, in);
 554  571                  Fwrite(cbuf, csize, out);
 555  572                  *offp += csize;
 556  573                  np--;
 557  574          }
 558  575          (void) fclose(in);
 559  576          (void) fclose(out);
 560  577          free(outbuf);
 561  578          free(buf);
 562  579  }
 563  580  
 564  581  /*
 565  582   * Concatenate dump contents into a new file.
 566  583   * Update corehdr with new offsets.
 567  584   */
  
    | 
      ↓ open down ↓ | 
    121 lines elided | 
    
      ↑ open up ↑ | 
  
 568  585  static void
 569  586  copy_crashfile(const char *corefile)
 570  587  {
 571  588          int corefd = Open(corefile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
 572  589          size_t bufsz = FBUFSIZE;
 573  590          char *inbuf = Zalloc(bufsz);
 574  591          offset_t coreoff;
 575  592          size_t nb;
 576  593  
 577  594          logprint(SC_SL_ERR | SC_IF_VERBOSE,
 578      -            "Copying %s to %s/%s\n", dumpfile, savedir, corefile);
      595 +            "Copying %s to %s/%s\n", dumpfile, uuiddir, corefile);
 579  596  
 580  597          /*
 581  598           * This dump file is still compressed
 582  599           */
 583  600          corehdr.dump_flags |= DF_COMPRESSED | DF_VALID;
 584  601  
 585  602          /*
 586  603           * Leave room for corehdr, it is updated and written last
 587  604           */
 588  605          corehdr.dump_start = 0;
 589  606          coreoff = sizeof (corehdr);
 590  607  
 591  608          /*
 592  609           * Read in the compressed symbol table, copy it to corefile.
 593  610           */
 594  611          coreoff = roundup(coreoff, pagesize);
 595  612          corehdr.dump_ksyms = coreoff;
 596  613          Copy(dumphdr.dump_ksyms, dumphdr.dump_ksyms_csize, &coreoff, corefd,
 597  614              inbuf, bufsz);
 598  615  
 599  616          /*
 600  617           * Save the pfn table.
 601  618           */
 602  619          coreoff = roundup(coreoff, pagesize);
 603  620          corehdr.dump_pfn = coreoff;
 604  621          Copy(dumphdr.dump_pfn, dumphdr.dump_npages * sizeof (pfn_t), &coreoff,
 605  622              corefd, inbuf, bufsz);
 606  623  
 607  624          /*
 608  625           * Save the dump map.
 609  626           */
 610  627          coreoff = roundup(coreoff, pagesize);
 611  628          corehdr.dump_map = coreoff;
 612  629          Copy(dumphdr.dump_map, dumphdr.dump_nvtop * sizeof (mem_vtop_t),
 613  630              &coreoff, corefd, inbuf, bufsz);
 614  631  
 615  632          /*
 616  633           * Save the data pages.
 617  634           */
 618  635          coreoff = roundup(coreoff, pagesize);
 619  636          corehdr.dump_data = coreoff;
 620  637          if (datahdr.dump_data_csize != 0)
 621  638                  Copy(dumphdr.dump_data, datahdr.dump_data_csize, &coreoff,
 622  639                      corefd, inbuf, bufsz);
 623  640          else
 624  641                  CopyPages(&coreoff, corefd, inbuf, bufsz);
 625  642  
 626  643          /*
 627  644           * Now write the modified dump header to front and end of the copy.
 628  645           * Make it look like a valid dump device.
 629  646           *
 630  647           * From dumphdr.h: Two headers are written out: one at the
 631  648           * beginning of the dump, and the other at the very end of the
 632  649           * dump device. The terminal header is at a known location
 633  650           * (end of device) so we can always find it.
 634  651           *
 635  652           * Pad with zeros to each DUMP_OFFSET boundary.
 636  653           */
 637  654          (void) memset(inbuf, 0, DUMP_OFFSET);
 638  655  
 639  656          nb = DUMP_OFFSET - (coreoff & (DUMP_OFFSET - 1));
 640  657          if (nb > 0) {
 641  658                  Pwrite(corefd, inbuf, nb, coreoff);
 642  659                  coreoff += nb;
 643  660          }
 644  661  
 645  662          Pwrite(corefd, &corehdr, sizeof (corehdr), coreoff);
 646  663          coreoff += sizeof (corehdr);
 647  664  
 648  665          Pwrite(corefd, &datahdr, sizeof (datahdr), coreoff);
 649  666          coreoff += sizeof (datahdr);
 650  667  
 651  668          nb = DUMP_OFFSET - (coreoff & (DUMP_OFFSET - 1));
 652  669          if (nb > 0) {
 653  670                  Pwrite(corefd, inbuf, nb, coreoff);
 654  671          }
 655  672  
 656  673          free(inbuf);
 657  674          Pwrite(corefd, &corehdr, sizeof (corehdr), corehdr.dump_start);
 658  675  
 659  676          /*
 660  677           * Write out the modified dump header to the dump device.
 661  678           * The dump device has been processed, so DF_VALID is clear.
 662  679           */
 663  680          if (!filemode)
 664  681                  Pwrite(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
 665  682  
 666  683          (void) close(corefd);
 667  684  }
 668  685  
 669  686  /*
 670  687   * compressed streams
 671  688   */
 672  689  typedef struct blockhdr blockhdr_t;
 673  690  typedef struct block block_t;
 674  691  
 675  692  struct blockhdr {
 676  693          block_t *head;
 677  694          block_t *tail;
 678  695  };
 679  696  
 680  697  struct block {
 681  698          block_t *next;
 682  699          char *block;
 683  700          int size;
 684  701  };
 685  702  
 686  703  typedef enum streamstate {
 687  704          STREAMSTART,
 688  705          STREAMPAGES
 689  706  } streamstate_t;
 690  707  
 691  708  typedef struct stream {
 692  709          streamstate_t state;
  
    | 
      ↓ open down ↓ | 
    104 lines elided | 
    
      ↑ open up ↑ | 
  
 693  710          int init;
 694  711          int tag;
 695  712          int bound;
 696  713          int nout;
 697  714          char *blkbuf;
 698  715          blockhdr_t blocks;
 699  716          pgcnt_t pagenum;
 700  717          pgcnt_t curpage;
 701  718          pgcnt_t npages;
 702  719          pgcnt_t done;
 703      -        bz_stream strm;
 704  720          dumpcsize_t sc;
 705  721          dumpstreamhdr_t sh;
 706  722  } stream_t;
 707  723  
 708  724  static stream_t *streams;
 709  725  static stream_t *endstreams;
 710  726  
 711  727  const int cs = sizeof (dumpcsize_t);
 712  728  
 713  729  typedef struct tinfo {
 714  730          pthread_t tid;
 715  731          int corefd;
 716  732  } tinfo_t;
 717  733  
 718  734  static int threads_stop;
 719  735  static int threads_active;
 720  736  static tinfo_t *tinfo;
 721  737  static tinfo_t *endtinfo;
 722  738  
 723  739  static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
 724  740  static pthread_cond_t cvfree = PTHREAD_COND_INITIALIZER;
 725  741  static pthread_cond_t cvwork = PTHREAD_COND_INITIALIZER;
 726  742  static pthread_cond_t cvbarrier = PTHREAD_COND_INITIALIZER;
 727  743  
 728  744  static blockhdr_t freeblocks;
 729  745  
 730  746  static void
 731  747  enqt(blockhdr_t *h, block_t *b)
 732  748  {
 733  749          b->next = NULL;
 734  750          if (h->tail == NULL)
 735  751                  h->head = b;
 736  752          else
 737  753                  h->tail->next = b;
 738  754          h->tail = b;
 739  755  }
 740  756  
 741  757  static block_t *
 742  758  deqh(blockhdr_t *h)
 743  759  {
 744  760          block_t *b = h->head;
 745  761  
 746  762          if (b != NULL) {
 747  763                  h->head = b->next;
 748  764                  if (h->head == NULL)
 749  765                          h->tail = NULL;
 750  766          }
 751  767          return (b);
 752  768  }
 753  769  
 754  770  static void *runstreams(void *arg);
 755  771  
 756  772  static void
 757  773  initstreams(int corefd, int nstreams, int maxcsize)
 758  774  {
 759  775          int nthreads;
 760  776          int nblocks;
 761  777          int i;
 762  778          block_t *b;
 763  779          tinfo_t *t;
 764  780  
 765  781          nthreads = sysconf(_SC_NPROCESSORS_ONLN);
 766  782          if (nstreams < nthreads)
 767  783                  nthreads = nstreams;
 768  784          if (nthreads < 1)
 769  785                  nthreads = 1;
 770  786          nblocks = nthreads * 2;
 771  787  
 772  788          tinfo = Zalloc(nthreads * sizeof (tinfo_t));
 773  789          endtinfo = &tinfo[nthreads];
 774  790  
 775  791          /* init streams */
 776  792          streams = Zalloc(nstreams * sizeof (stream_t));
 777  793          endstreams = &streams[nstreams];
 778  794  
 779  795          /* init stream block buffers */
 780  796          for (i = 0; i < nblocks; i++) {
 781  797                  b = Zalloc(sizeof (block_t));
 782  798                  b->block = Zalloc(maxcsize);
 783  799                  enqt(&freeblocks, b);
 784  800          }
 785  801  
 786  802          /* init worker threads */
 787  803          (void) pthread_mutex_lock(&lock);
 788  804          threads_active = 1;
 789  805          threads_stop = 0;
 790  806          for (t = tinfo; t != endtinfo; t++) {
 791  807                  t->corefd = dup(corefd);
 792  808                  if (t->corefd < 0) {
 793  809                          nthreads = t - tinfo;
 794  810                          endtinfo = t;
 795  811                          break;
 796  812                  }
 797  813                  if (pthread_create(&t->tid, NULL, runstreams, t) != 0)
 798  814                          logprint(SC_SL_ERR | SC_EXIT_ERR, "pthread_create: %s",
 799  815                              strerror(errno));
 800  816          }
 801  817          (void) pthread_mutex_unlock(&lock);
 802  818  }
 803  819  
 804  820  static void
 805  821  sbarrier()
 806  822  {
 807  823          stream_t *s;
 808  824  
 809  825          (void) pthread_mutex_lock(&lock);
 810  826          for (s = streams; s != endstreams; s++) {
 811  827                  while (s->bound || s->blocks.head != NULL)
 812  828                          (void) pthread_cond_wait(&cvbarrier, &lock);
 813  829          }
 814  830          (void) pthread_mutex_unlock(&lock);
 815  831  }
 816  832  
 817  833  static void
 818  834  stopstreams()
 819  835  {
 820  836          tinfo_t *t;
 821  837  
 822  838          if (threads_active) {
 823  839                  sbarrier();
 824  840                  (void) pthread_mutex_lock(&lock);
 825  841                  threads_stop = 1;
 826  842                  (void) pthread_cond_signal(&cvwork);
 827  843                  (void) pthread_mutex_unlock(&lock);
 828  844                  for (t = tinfo; t != endtinfo; t++)
 829  845                          (void) pthread_join(t->tid, NULL);
 830  846                  free(tinfo);
 831  847                  tinfo = NULL;
 832  848                  threads_active = 0;
 833  849          }
 834  850  }
 835  851  
 836  852  static block_t *
 837  853  getfreeblock()
 838  854  {
 839  855          block_t *b;
 840  856  
 841  857          (void) pthread_mutex_lock(&lock);
 842  858          while ((b = deqh(&freeblocks)) == NULL)
 843  859                  (void) pthread_cond_wait(&cvfree, &lock);
 844  860          (void) pthread_mutex_unlock(&lock);
 845  861          return (b);
 846  862  }
 847  863  
 848  864  /* data page offset from page number */
 849  865  #define BTOP(b)         ((b) >> dumphdr.dump_pageshift)
 850  866  #define PTOB(p)         ((p) << dumphdr.dump_pageshift)
 851  867  #define DATAOFF(p)      (corehdr.dump_data + PTOB(p))
 852  868  
 853  869  /* check for coreblksize boundary */
 854  870  static int
 855  871  isblkbnd(pgcnt_t pgnum)
 856  872  {
 857  873          return (P2PHASE(DATAOFF(pgnum), coreblksize) == 0);
 858  874  }
 859  875  
 860  876  static int
 861  877  iszpage(char *buf)
 862  878  {
 863  879          size_t sz;
 864  880          uint64_t *pl;
 865  881  
 866  882          /*LINTED:E_BAD_PTR_CAST_ALIGN*/
 867  883          pl = (uint64_t *)(buf);
 868  884          for (sz = 0; sz < pagesize; sz += sizeof (*pl))
 869  885                  if (*pl++ != 0)
 870  886                          return (0);
 871  887          return (1);
 872  888  }
 873  889  
 874  890  volatile uint_t *hist;
 875  891  
 876  892  /* write pages to the core file */
 877  893  static void
 878  894  putpage(int corefd, char *buf, pgcnt_t pgnum, pgcnt_t np)
 879  895  {
 880  896          atomic_inc_uint(&hist[np]);
 881  897          if (np > 0)
 882  898                  Pwrite(corefd, buf, PTOB(np), DATAOFF(pgnum));
 883  899  }
 884  900  
 885  901  /*
 886  902   * Process one lzjb block.
 887  903   * No object (stream header or page) will be split over a block boundary.
 888  904   */
 889  905  static void
 890  906  lzjbblock(int corefd, stream_t *s, char *block, size_t blocksz)
 891  907  {
 892  908          int in = 0;
 893  909          int csize;
 894  910          int doflush;
 895  911          char *out;
 896  912          size_t dsize;
 897  913          dumpcsize_t sc;
 898  914          dumpstreamhdr_t sh;
 899  915  
 900  916          if (!s->init) {
 901  917                  s->init = 1;
 902  918                  if (s->blkbuf == NULL)
 903  919                          s->blkbuf = Zalloc(coreblksize);
 904  920                  s->state = STREAMSTART;
 905  921          }
 906  922          while (in < blocksz) {
 907  923                  switch (s->state) {
 908  924                  case STREAMSTART:
 909  925                          (void) memcpy(&sh, block + in, sizeof (sh));
 910  926                          in += sizeof (sh);
 911  927                          if (strcmp(DUMP_STREAM_MAGIC, sh.stream_magic) != 0)
 912  928                                  logprint(SC_SL_ERR | SC_EXIT_ERR,
 913  929                                      "LZJB STREAMSTART: bad stream header");
 914  930                          if (sh.stream_npages > datahdr.dump_maxrange)
 915  931                                  logprint(SC_SL_ERR | SC_EXIT_ERR,
 916  932                                      "LZJB STREAMSTART: bad range: %d > %d",
 917  933                                      sh.stream_npages, datahdr.dump_maxrange);
 918  934                          s->pagenum = sh.stream_pagenum;
 919  935                          s->npages = sh.stream_npages;
 920  936                          s->curpage = s->pagenum;
 921  937                          s->nout = 0;
 922  938                          s->done = 0;
 923  939                          s->state = STREAMPAGES;
 924  940                          break;
 925  941                  case STREAMPAGES:
 926  942                          (void) memcpy(&sc, block + in, cs);
 927  943                          in += cs;
 928  944                          csize = DUMP_GET_CSIZE(sc);
 929  945                          if (csize > pagesize)
 930  946                                  logprint(SC_SL_ERR | SC_EXIT_ERR,
 931  947                                      "LZJB STREAMPAGES: bad csize=%d", csize);
 932  948  
 933  949                          out =  s->blkbuf + PTOB(s->nout);
 934  950                          dsize = decompress(block + in, out, csize, pagesize);
 935  951  
 936  952                          if (dsize != pagesize)
 937  953                                  logprint(SC_SL_ERR | SC_EXIT_ERR,
 938  954                                      "LZJB STREAMPAGES: dsize %d != pagesize %d",
 939  955                                      dsize, pagesize);
 940  956  
 941  957                          in += csize;
 942  958                          atomic_inc_64(&saved);
 943  959  
 944  960                          doflush = 0;
 945  961                          if (s->nout == 0 && iszpage(out)) {
 946  962                                  doflush = 1;
 947  963                                  atomic_inc_64(&zpages);
 948  964                          } else if (++s->nout >= BTOP(coreblksize) ||
 949  965                              isblkbnd(s->curpage + s->nout)) {
 950  966                                  doflush = 1;
 951  967                          }
 952  968                          if (++s->done >= s->npages) {
 953  969                                  s->state = STREAMSTART;
 954  970                                  doflush = 1;
 955  971                          }
  
    | 
      ↓ open down ↓ | 
    242 lines elided | 
    
      ↑ open up ↑ | 
  
 956  972                          if (doflush) {
 957  973                                  putpage(corefd, s->blkbuf, s->curpage, s->nout);
 958  974                                  s->nout = 0;
 959  975                                  s->curpage = s->pagenum + s->done;
 960  976                          }
 961  977                          break;
 962  978                  }
 963  979          }
 964  980  }
 965  981  
 966      -/* bzlib library reports errors with this callback */
 967      -void
 968      -bz_internal_error(int errcode)
 969      -{
 970      -        logprint(SC_SL_ERR | SC_EXIT_ERR, "bz_internal_error: err %s\n",
 971      -            BZ2_bzErrorString(errcode));
 972      -}
 973      -
 974      -/*
 975      - * Return one object in the stream.
 976      - *
 977      - * An object (stream header or page) will likely span an input block
 978      - * of compression data. Return non-zero when an entire object has been
 979      - * retrieved from the stream.
 980      - */
 981      -static int
 982      -bz2decompress(stream_t *s, void *buf, size_t size)
 983      -{
 984      -        int rc;
 985      -
 986      -        if (s->strm.avail_out == 0) {
 987      -                s->strm.next_out = buf;
 988      -                s->strm.avail_out = size;
 989      -        }
 990      -        while (s->strm.avail_in > 0) {
 991      -                rc = BZ2_bzDecompress(&s->strm);
 992      -                if (rc == BZ_STREAM_END) {
 993      -                        rc = BZ2_bzDecompressReset(&s->strm);
 994      -                        if (rc != BZ_OK)
 995      -                                logprint(SC_SL_ERR | SC_EXIT_ERR,
 996      -                                    "BZ2_bzDecompressReset: %s",
 997      -                                    BZ2_bzErrorString(rc));
 998      -                        continue;
 999      -                }
1000      -
1001      -                if (s->strm.avail_out == 0)
1002      -                        break;
1003      -        }
1004      -        return (s->strm.avail_out == 0);
1005      -}
1006      -
1007      -/*
1008      - * Process one bzip2 block.
1009      - * The interface is documented here:
1010      - * http://www.bzip.org/1.0.5/bzip2-manual-1.0.5.html
1011      - */
1012      -static void
1013      -bz2block(int corefd, stream_t *s, char *block, size_t blocksz)
1014      -{
1015      -        int rc = 0;
1016      -        int doflush;
1017      -        char *out;
1018      -
1019      -        if (!s->init) {
1020      -                s->init = 1;
1021      -                rc = BZ2_bzDecompressInit(&s->strm, 0, 0);
1022      -                if (rc != BZ_OK)
1023      -                        logprint(SC_SL_ERR | SC_EXIT_ERR,
1024      -                            "BZ2_bzDecompressInit: %s", BZ2_bzErrorString(rc));
1025      -                if (s->blkbuf == NULL)
1026      -                        s->blkbuf = Zalloc(coreblksize);
1027      -                s->strm.avail_out = 0;
1028      -                s->state = STREAMSTART;
1029      -        }
1030      -        s->strm.next_in = block;
1031      -        s->strm.avail_in = blocksz;
1032      -
1033      -        while (s->strm.avail_in > 0) {
1034      -                switch (s->state) {
1035      -                case STREAMSTART:
1036      -                        if (!bz2decompress(s, &s->sh, sizeof (s->sh)))
1037      -                                return;
1038      -                        if (strcmp(DUMP_STREAM_MAGIC, s->sh.stream_magic) != 0)
1039      -                                logprint(SC_SL_ERR | SC_EXIT_ERR,
1040      -                                    "BZ2 STREAMSTART: bad stream header");
1041      -                        if (s->sh.stream_npages > datahdr.dump_maxrange)
1042      -                                logprint(SC_SL_ERR | SC_EXIT_ERR,
1043      -                                    "BZ2 STREAMSTART: bad range: %d > %d",
1044      -                                    s->sh.stream_npages, datahdr.dump_maxrange);
1045      -                        s->pagenum = s->sh.stream_pagenum;
1046      -                        s->npages = s->sh.stream_npages;
1047      -                        s->curpage = s->pagenum;
1048      -                        s->nout = 0;
1049      -                        s->done = 0;
1050      -                        s->state = STREAMPAGES;
1051      -                        break;
1052      -                case STREAMPAGES:
1053      -                        out = s->blkbuf + PTOB(s->nout);
1054      -                        if (!bz2decompress(s, out, pagesize))
1055      -                                return;
1056      -
1057      -                        atomic_inc_64(&saved);
1058      -
1059      -                        doflush = 0;
1060      -                        if (s->nout == 0 && iszpage(out)) {
1061      -                                doflush = 1;
1062      -                                atomic_inc_64(&zpages);
1063      -                        } else if (++s->nout >= BTOP(coreblksize) ||
1064      -                            isblkbnd(s->curpage + s->nout)) {
1065      -                                doflush = 1;
1066      -                        }
1067      -                        if (++s->done >= s->npages) {
1068      -                                s->state = STREAMSTART;
1069      -                                doflush = 1;
1070      -                        }
1071      -                        if (doflush) {
1072      -                                putpage(corefd, s->blkbuf, s->curpage, s->nout);
1073      -                                s->nout = 0;
1074      -                                s->curpage = s->pagenum + s->done;
1075      -                        }
1076      -                        break;
1077      -                }
1078      -        }
1079      -}
1080      -
1081  982  /* report progress */
1082  983  static void
1083  984  report_progress()
1084  985  {
1085  986          int sec, percent;
1086  987  
1087  988          if (!interactive)
1088  989                  return;
1089  990  
1090  991          percent = saved * 100LL / corehdr.dump_npages;
1091  992          sec = (gethrtime() - startts) / NANOSEC;
1092  993          if (percent > percent_done || sec > sec_done) {
1093  994                  (void) printf("\r%2d:%02d %3d%% done", sec / 60, sec % 60,
1094  995                      percent);
1095  996                  (void) fflush(stdout);
1096  997                  sec_done = sec;
1097  998                  percent_done = percent;
1098  999          }
1099 1000  }
1100 1001  
1101 1002  /* thread body */
1102 1003  static void *
1103 1004  runstreams(void *arg)
1104 1005  {
1105 1006          tinfo_t *t = arg;
1106 1007          stream_t *s;
1107 1008          block_t *b;
1108 1009          int bound;
1109 1010  
1110 1011          (void) pthread_mutex_lock(&lock);
1111 1012          while (!threads_stop) {
1112 1013                  bound = 0;
  
    | 
      ↓ open down ↓ | 
    22 lines elided | 
    
      ↑ open up ↑ | 
  
1113 1014                  for (s = streams; s != endstreams; s++) {
1114 1015                          if (s->bound || s->blocks.head == NULL)
1115 1016                                  continue;
1116 1017                          s->bound = 1;
1117 1018                          bound = 1;
1118 1019                          (void) pthread_cond_signal(&cvwork);
1119 1020                          while (s->blocks.head != NULL) {
1120 1021                                  b = deqh(&s->blocks);
1121 1022                                  (void) pthread_mutex_unlock(&lock);
1122 1023  
1123      -                                if (datahdr.dump_clevel < DUMP_CLEVEL_BZIP2)
1124      -                                        lzjbblock(t->corefd, s, b->block,
1125      -                                            b->size);
1126      -                                else
1127      -                                        bz2block(t->corefd, s, b->block,
1128      -                                            b->size);
     1024 +                                lzjbblock(t->corefd, s, b->block,
     1025 +                                    b->size);
1129 1026  
1130 1027                                  (void) pthread_mutex_lock(&lock);
1131 1028                                  enqt(&freeblocks, b);
1132 1029                                  (void) pthread_cond_signal(&cvfree);
1133 1030  
1134 1031                                  report_progress();
1135 1032                          }
1136 1033                          s->bound = 0;
1137 1034                          (void) pthread_cond_signal(&cvbarrier);
1138 1035                  }
1139 1036                  if (!bound && !threads_stop)
1140 1037                          (void) pthread_cond_wait(&cvwork, &lock);
1141 1038          }
1142 1039          (void) close(t->corefd);
1143 1040          (void) pthread_cond_signal(&cvwork);
1144 1041          (void) pthread_mutex_unlock(&lock);
1145 1042          return (arg);
1146 1043  }
1147 1044  
1148 1045  /*
1149 1046   * Process compressed pages.
1150 1047   *
1151 1048   * The old format, now called single-threaded lzjb, is a 32-bit size
1152 1049   * word followed by 'size' bytes of lzjb compression data for one
1153 1050   * page. The new format extends this by storing a 12-bit "tag" in the
1154 1051   * upper bits of the size word. When the size word is pagesize or
1155 1052   * less, it is assumed to be one lzjb page. When the size word is
1156 1053   * greater than pagesize, it is assumed to be a "stream block",
  
    | 
      ↓ open down ↓ | 
    18 lines elided | 
    
      ↑ open up ↑ | 
  
1157 1054   * belonging to up to 4095 streams. In practice, the number of streams
1158 1055   * is set to one less than the number of CPUs running at crash
1159 1056   * time. One CPU processes the crash dump, the remaining CPUs
1160 1057   * separately process groups of data pages.
1161 1058   *
1162 1059   * savecore creates a thread per stream, but never more threads than
1163 1060   * the number of CPUs running savecore. This is because savecore can
1164 1061   * be processing a crash file from a remote machine, which may have
1165 1062   * more CPUs.
1166 1063   *
1167      - * When the kernel uses parallel lzjb or parallel bzip2, we expect a
1168      - * series of 128KB blocks of compression data. In this case, each
1169      - * block has a "tag", in the range 1-4095. Each block is handed off to
1170      - * to the threads running "runstreams". The dump format is either lzjb
1171      - * or bzip2, never a mixture. These threads, in turn, process the
1172      - * compression data for groups of pages. Groups of pages are delimited
1173      - * by a "stream header", which indicates a starting pfn and number of
1174      - * pages. When a stream block has been read, the condition variable
1175      - * "cvwork" is signalled, which causes one of the avaiable threads to
1176      - * wake up and process the stream.
     1064 + * When the kernel uses parallel compression we expect a series of 128KB
     1065 + * blocks of compression data. In this case, each block has a "tag" in
     1066 + * the range 1-4095. Each block is handed off to the threads running
     1067 + * "runstreams". These threads, in turn, process the compression data
     1068 + * for groups of pages. Groups of pages are delimited by a "stream header",
     1069 + * which indicates a starting pfn and number of pages. When a stream block
     1070 + * has been read, the condition variable "cvwork" is signalled, which causes
     1071 + * one of the available threads to wake up and process the stream.
1177 1072   *
1178 1073   * In the parallel case there will be streams blocks encoding all data
1179 1074   * pages. The stream of blocks is terminated by a zero size
1180 1075   * word. There can be a few lzjb pages tacked on the end, depending on
1181 1076   * the architecture. The sbarrier function ensures that all stream
1182 1077   * blocks have been processed so that the page number for the few
1183 1078   * single pages at the end can be known.
1184 1079   */
1185 1080  static void
1186 1081  decompress_pages(int corefd)
1187 1082  {
1188 1083          char *cpage = NULL;
1189 1084          char *dpage = NULL;
1190 1085          char *out;
1191 1086          pgcnt_t curpage = 0;
1192 1087          block_t *b;
1193 1088          FILE *dumpf;
1194 1089          FILE *tracef = NULL;
1195 1090          stream_t *s;
1196 1091          size_t dsize;
1197 1092          size_t insz = FBUFSIZE;
1198 1093          char *inbuf = Zalloc(insz);
1199 1094          uint32_t csize;
1200 1095          dumpcsize_t dcsize;
1201 1096          int nstreams = datahdr.dump_nstreams;
1202 1097          int maxcsize = datahdr.dump_maxcsize;
1203 1098          int nout = 0, tag, doflush;
1204 1099  
1205 1100          dumpf = fdopen(dup(dumpfd), "rb");
1206 1101          if (dumpf == NULL)
1207 1102                  logprint(SC_SL_ERR | SC_EXIT_ERR, "fdopen: %s",
1208 1103                      strerror(errno));
1209 1104  
1210 1105          (void) setvbuf(dumpf, inbuf, _IOFBF, insz);
1211 1106          Fseek(dumphdr.dump_data, dumpf);
1212 1107  
1213 1108          /*LINTED: E_CONSTANT_CONDITION*/
1214 1109          while (1) {
1215 1110  
1216 1111                  /*
1217 1112                   * The csize word delimits stream blocks.
1218 1113                   * See dumphdr.h for a description.
1219 1114                   */
1220 1115                  Fread(&dcsize, sizeof (dcsize), dumpf);
1221 1116  
1222 1117                  tag = DUMP_GET_TAG(dcsize);
1223 1118                  csize = DUMP_GET_CSIZE(dcsize);
1224 1119  
1225 1120                  if (tag != 0) {         /* a stream block */
1226 1121  
1227 1122                          if (nstreams == 0)
1228 1123                                  logprint(SC_SL_ERR | SC_EXIT_ERR,
1229 1124                                      "starting data header is missing");
1230 1125  
1231 1126                          if (tag > nstreams)
1232 1127                                  logprint(SC_SL_ERR | SC_EXIT_ERR,
1233 1128                                      "stream tag %d not in range 1..%d",
1234 1129                                      tag, nstreams);
1235 1130  
1236 1131                          if (csize > maxcsize)
1237 1132                                  logprint(SC_SL_ERR | SC_EXIT_ERR,
1238 1133                                      "block size 0x%x > max csize 0x%x",
1239 1134                                      csize, maxcsize);
1240 1135  
1241 1136                          if (streams == NULL)
1242 1137                                  initstreams(corefd, nstreams, maxcsize);
1243 1138                          s = &streams[tag - 1];
1244 1139                          s->tag = tag;
1245 1140  
1246 1141                          b = getfreeblock();
1247 1142                          b->size = csize;
1248 1143                          Fread(b->block, csize, dumpf);
1249 1144  
1250 1145                          (void) pthread_mutex_lock(&lock);
1251 1146                          enqt(&s->blocks, b);
1252 1147                          if (!s->bound)
1253 1148                                  (void) pthread_cond_signal(&cvwork);
1254 1149                          (void) pthread_mutex_unlock(&lock);
1255 1150  
1256 1151                  } else if (csize > 0) {         /* one lzjb page */
1257 1152  
1258 1153                          if (csize > pagesize)
1259 1154                                  logprint(SC_SL_ERR | SC_EXIT_ERR,
1260 1155                                      "csize 0x%x > pagesize 0x%x",
1261 1156                                      csize, pagesize);
1262 1157  
1263 1158                          if (cpage == NULL)
1264 1159                                  cpage = Zalloc(pagesize);
1265 1160                          if (dpage == NULL) {
1266 1161                                  dpage = Zalloc(coreblksize);
1267 1162                                  nout = 0;
1268 1163                          }
1269 1164  
1270 1165                          Fread(cpage, csize, dumpf);
1271 1166  
1272 1167                          out = dpage + PTOB(nout);
1273 1168                          dsize = decompress(cpage, out, csize, pagesize);
1274 1169  
1275 1170                          if (dsize != pagesize)
1276 1171                                  logprint(SC_SL_ERR | SC_EXIT_ERR,
1277 1172                                      "dsize 0x%x != pagesize 0x%x",
1278 1173                                      dsize, pagesize);
1279 1174  
1280 1175                          /*
1281 1176                           * wait for streams to flush so that 'saved' is correct
1282 1177                           */
1283 1178                          if (threads_active)
1284 1179                                  sbarrier();
1285 1180  
1286 1181                          doflush = 0;
1287 1182                          if (nout == 0)
1288 1183                                  curpage = saved;
1289 1184  
1290 1185                          atomic_inc_64(&saved);
1291 1186  
1292 1187                          if (nout == 0 && iszpage(dpage)) {
1293 1188                                  doflush = 1;
1294 1189                                  atomic_inc_64(&zpages);
1295 1190                          } else if (++nout >= BTOP(coreblksize) ||
1296 1191                              isblkbnd(curpage + nout) ||
1297 1192                              saved >= dumphdr.dump_npages) {
1298 1193                                  doflush = 1;
1299 1194                          }
1300 1195  
1301 1196                          if (doflush) {
1302 1197                                  putpage(corefd, dpage, curpage, nout);
1303 1198                                  nout = 0;
1304 1199                          }
1305 1200  
1306 1201                          report_progress();
1307 1202  
1308 1203                          /*
1309 1204                           * Non-streams lzjb does not use blocks.  Stop
1310 1205                           * here if all the pages have been decompressed.
1311 1206                           */
1312 1207                          if (saved >= dumphdr.dump_npages)
1313 1208                                  break;
1314 1209  
1315 1210                  } else {
1316 1211                          break;                  /* end of data */
1317 1212                  }
1318 1213          }
1319 1214  
1320 1215          stopstreams();
1321 1216          if (tracef != NULL)
1322 1217                  (void) fclose(tracef);
1323 1218          (void) fclose(dumpf);
1324 1219          if (inbuf)
1325 1220                  free(inbuf);
1326 1221          if (cpage)
1327 1222                  free(cpage);
1328 1223          if (dpage)
1329 1224                  free(dpage);
1330 1225          if (streams)
1331 1226                  free(streams);
1332 1227  }
1333 1228  
1334 1229  static void
1335 1230  build_corefile(const char *namelist, const char *corefile)
1336 1231  {
1337 1232          size_t pfn_table_size = dumphdr.dump_npages * sizeof (pfn_t);
  
    | 
      ↓ open down ↓ | 
    151 lines elided | 
    
      ↑ open up ↑ | 
  
1338 1233          size_t ksyms_size = dumphdr.dump_ksyms_size;
1339 1234          size_t ksyms_csize = dumphdr.dump_ksyms_csize;
1340 1235          pfn_t *pfn_table;
1341 1236          char *ksyms_base = Zalloc(ksyms_size);
1342 1237          char *ksyms_cbase = Zalloc(ksyms_csize);
1343 1238          size_t ksyms_dsize;
1344 1239          Stat_t st;
1345 1240          int corefd = Open(corefile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1346 1241          int namefd = Open(namelist, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1347 1242  
1348      -        (void) printf("Constructing namelist %s/%s\n", savedir, namelist);
     1243 +        (void) printf("Constructing namelist %s/%s\n", uuiddir, namelist);
1349 1244  
1350 1245          /*
1351 1246           * Determine the optimum write size for the core file
1352 1247           */
1353 1248          Fstat(corefd, &st, corefile);
1354 1249  
1355 1250          if (verbose > 1)
1356 1251                  (void) printf("%s: %ld block size\n", corefile,
1357 1252                      (long)st.st_blksize);
1358 1253          coreblksize = st.st_blksize;
1359 1254          if (coreblksize < MINCOREBLKSIZE || !ISP2(coreblksize))
1360 1255                  coreblksize = MINCOREBLKSIZE;
1361 1256  
1362 1257          hist = Zalloc((sizeof (uint64_t) * BTOP(coreblksize)) + 1);
1363 1258  
1364 1259          /*
1365 1260           * This dump file is now uncompressed
1366 1261           */
1367 1262          corehdr.dump_flags &= ~DF_COMPRESSED;
1368 1263  
1369 1264          /*
1370 1265           * Read in the compressed symbol table, copy it to corefile,
1371 1266           * decompress it, and write the result to namelist.
1372 1267           */
1373 1268          corehdr.dump_ksyms = pagesize;
1374 1269          Pread(dumpfd, ksyms_cbase, ksyms_csize, dumphdr.dump_ksyms);
1375 1270          Pwrite(corefd, ksyms_cbase, ksyms_csize, corehdr.dump_ksyms);
1376 1271  
1377 1272          ksyms_dsize = decompress(ksyms_cbase, ksyms_base, ksyms_csize,
1378 1273              ksyms_size);
  
    | 
      ↓ open down ↓ | 
    20 lines elided | 
    
      ↑ open up ↑ | 
  
1379 1274          if (ksyms_dsize != ksyms_size)
1380 1275                  logprint(SC_SL_WARN,
1381 1276                      "bad data in symbol table, %lu of %lu bytes saved",
1382 1277                      ksyms_dsize, ksyms_size);
1383 1278  
1384 1279          Pwrite(namefd, ksyms_base, ksyms_size, 0);
1385 1280          (void) close(namefd);
1386 1281          free(ksyms_cbase);
1387 1282          free(ksyms_base);
1388 1283  
1389      -        (void) printf("Constructing corefile %s/%s\n", savedir, corefile);
     1284 +        (void) printf("Constructing corefile %s/%s\n", uuiddir, corefile);
1390 1285  
1391 1286          /*
1392 1287           * Read in and write out the pfn table.
1393 1288           */
1394 1289          pfn_table = Zalloc(pfn_table_size);
1395 1290          corehdr.dump_pfn = corehdr.dump_ksyms + roundup(ksyms_size, pagesize);
1396 1291          Pread(dumpfd, pfn_table, pfn_table_size, dumphdr.dump_pfn);
1397 1292          Pwrite(corefd, pfn_table, pfn_table_size, corehdr.dump_pfn);
1398 1293  
1399 1294          /*
1400 1295           * Convert the raw translation data into a hashed dump map.
1401 1296           */
1402 1297          corehdr.dump_map = corehdr.dump_pfn + roundup(pfn_table_size, pagesize);
1403 1298          build_dump_map(corefd, pfn_table);
1404 1299          free(pfn_table);
1405 1300  
1406 1301          /*
1407 1302           * Decompress the pages
1408 1303           */
1409 1304          decompress_pages(corefd);
1410 1305          (void) printf(": %ld of %ld pages saved\n", (pgcnt_t)saved,
1411 1306              dumphdr.dump_npages);
1412 1307  
1413 1308          if (verbose)
1414 1309                  (void) printf("%ld (%ld%%) zero pages were not written\n",
1415 1310                      (pgcnt_t)zpages, (pgcnt_t)zpages * 100 /
1416 1311                      dumphdr.dump_npages);
1417 1312  
1418 1313          if (saved != dumphdr.dump_npages)
1419 1314                  logprint(SC_SL_WARN, "bad data after page %ld", saved);
1420 1315  
1421 1316          /*
1422 1317           * Write out the modified dump headers.
1423 1318           */
1424 1319          Pwrite(corefd, &corehdr, sizeof (corehdr), 0);
1425 1320          if (!filemode)
1426 1321                  Pwrite(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
1427 1322  
1428 1323          (void) close(corefd);
1429 1324  }
1430 1325  
1431 1326  /*
1432 1327   * When the system panics, the kernel saves all undelivered messages (messages
1433 1328   * that never made it out to syslogd(1M)) in the dump.  At a mimimum, the
1434 1329   * panic message itself will always fall into this category.  Upon reboot,
1435 1330   * the syslog startup script runs savecore -m to recover these messages.
1436 1331   *
1437 1332   * To do this, we read the unsent messages from the dump and send them to
1438 1333   * /dev/conslog on priority band 1.  This has the effect of prepending them
1439 1334   * to any already-accumulated messages in the console backlog, thus preserving
1440 1335   * temporal ordering across the reboot.
1441 1336   *
1442 1337   * Note: since savecore -m is used *only* for this purpose, it does *not*
1443 1338   * attempt to save the crash dump.  The dump will be saved later, after
1444 1339   * syslogd(1M) starts, by the savecore startup script.
1445 1340   */
1446 1341  static int
1447 1342  message_save(void)
1448 1343  {
1449 1344          offset_t dumpoff = -(DUMP_OFFSET + DUMP_LOGSIZE);
1450 1345          offset_t ldoff;
1451 1346          log_dump_t ld;
1452 1347          log_ctl_t lc;
1453 1348          struct strbuf ctl, dat;
1454 1349          int logfd;
1455 1350  
1456 1351          logfd = Open("/dev/conslog", O_WRONLY, 0644);
1457 1352          dumpfd = Open(dumpfile, O_RDWR | O_DSYNC, 0644);
1458 1353          dumpoff = llseek(dumpfd, dumpoff, SEEK_END) & -DUMP_OFFSET;
1459 1354  
1460 1355          ctl.buf = (void *)&lc;
1461 1356          ctl.len = sizeof (log_ctl_t);
1462 1357  
1463 1358          dat.buf = Zalloc(DUMP_LOGSIZE);
1464 1359  
1465 1360          for (;;) {
1466 1361                  ldoff = dumpoff;
1467 1362  
1468 1363                  Pread(dumpfd, &ld, sizeof (log_dump_t), dumpoff);
1469 1364                  dumpoff += sizeof (log_dump_t);
1470 1365                  dat.len = ld.ld_msgsize;
1471 1366  
1472 1367                  if (ld.ld_magic == 0)
1473 1368                          break;
1474 1369  
1475 1370                  if (ld.ld_magic != LOG_MAGIC)
1476 1371                          logprint(SC_SL_ERR | SC_IF_VERBOSE | SC_EXIT_ERR,
1477 1372                              "bad magic %x", ld.ld_magic);
1478 1373  
1479 1374                  if (dat.len >= DUMP_LOGSIZE)
1480 1375                          logprint(SC_SL_ERR | SC_IF_VERBOSE | SC_EXIT_ERR,
1481 1376                              "bad size %d", ld.ld_msgsize);
1482 1377  
1483 1378                  Pread(dumpfd, ctl.buf, ctl.len, dumpoff);
1484 1379                  dumpoff += ctl.len;
1485 1380  
1486 1381                  if (ld.ld_csum != checksum32(ctl.buf, ctl.len))
1487 1382                          logprint(SC_SL_ERR | SC_IF_VERBOSE | SC_EXIT_OK,
1488 1383                              "bad log_ctl checksum");
1489 1384  
1490 1385                  lc.flags |= SL_LOGONLY;
1491 1386  
1492 1387                  Pread(dumpfd, dat.buf, dat.len, dumpoff);
1493 1388                  dumpoff += dat.len;
1494 1389  
1495 1390                  if (ld.ld_msum != checksum32(dat.buf, dat.len))
1496 1391                          logprint(SC_SL_ERR | SC_IF_VERBOSE | SC_EXIT_OK,
1497 1392                              "bad message checksum");
1498 1393  
1499 1394                  if (putpmsg(logfd, &ctl, &dat, 1, MSG_BAND) == -1)
1500 1395                          logprint(SC_SL_ERR | SC_EXIT_ERR, "putpmsg: %s",
1501 1396                              strerror(errno));
1502 1397  
1503 1398                  ld.ld_magic = 0;        /* clear magic so we never save twice */
1504 1399                  Pwrite(dumpfd, &ld, sizeof (log_dump_t), ldoff);
1505 1400          }
1506 1401          return (0);
1507 1402  }
1508 1403  
1509 1404  static long
1510 1405  getbounds(const char *f)
1511 1406  {
1512 1407          long b = -1;
1513 1408          const char *p = strrchr(f, '/');
1514 1409  
1515 1410          if (p == NULL || strncmp(p, "vmdump", 6) != 0)
1516 1411                  p = strstr(f, "vmdump");
1517 1412  
1518 1413          if (p != NULL && *p == '/')
1519 1414                  p++;
1520 1415  
1521 1416          (void) sscanf(p ? p : f, "vmdump.%ld", &b);
1522 1417  
1523 1418          return (b);
1524 1419  }
1525 1420  
1526 1421  static void
1527 1422  stack_retrieve(char *stack)
1528 1423  {
1529 1424          summary_dump_t sd;
1530 1425          offset_t dumpoff = -(DUMP_OFFSET + DUMP_LOGSIZE +
1531 1426              DUMP_ERPTSIZE);
1532 1427          dumpoff -= DUMP_SUMMARYSIZE;
1533 1428  
1534 1429          dumpfd = Open(dumpfile, O_RDWR | O_DSYNC, 0644);
1535 1430          dumpoff = llseek(dumpfd, dumpoff, SEEK_END) & -DUMP_OFFSET;
1536 1431  
1537 1432          Pread(dumpfd, &sd, sizeof (summary_dump_t), dumpoff);
1538 1433          dumpoff += sizeof (summary_dump_t);
1539 1434  
1540 1435          if (sd.sd_magic == 0) {
1541 1436                  *stack = '\0';
1542 1437                  return;
1543 1438          }
1544 1439  
1545 1440          if (sd.sd_magic != SUMMARY_MAGIC) {
1546 1441                  *stack = '\0';
1547 1442                  logprint(SC_SL_NONE | SC_IF_VERBOSE,
1548 1443                      "bad summary magic %x", sd.sd_magic);
1549 1444                  return;
1550 1445          }
1551 1446          Pread(dumpfd, stack, STACK_BUF_SIZE, dumpoff);
  
    | 
      ↓ open down ↓ | 
    152 lines elided | 
    
      ↑ open up ↑ | 
  
1552 1447          if (sd.sd_ssum != checksum32(stack, STACK_BUF_SIZE))
1553 1448                  logprint(SC_SL_NONE | SC_IF_VERBOSE, "bad stack checksum");
1554 1449  }
1555 1450  
1556 1451  static void
1557 1452  raise_event(enum sc_event_type evidx, char *warn_string)
1558 1453  {
1559 1454          uint32_t pl = sc_event[evidx].sce_payload;
1560 1455          char panic_stack[STACK_BUF_SIZE];
1561 1456          nvlist_t *attr = NULL;
1562      -        char uuidbuf[36 + 1];
     1457 +        char uuidbuf[UUID_PRINTABLE_STRING_LENGTH];
1563 1458          int err = 0;
1564 1459  
1565 1460          if (nvlist_alloc(&attr, NV_UNIQUE_NAME, 0) != 0)
1566 1461                  goto publish;   /* try to send payload-free event */
1567 1462  
1568 1463          if (pl & SC_PAYLOAD_SAVEDIR && savedir != NULL)
1569 1464                  err |= nvlist_add_string(attr, "dumpdir", savedir);
1570 1465  
1571 1466          if (pl & SC_PAYLOAD_INSTANCE && bounds != -1)
1572 1467                  err |= nvlist_add_int64(attr, "instance", bounds);
1573 1468  
1574 1469          if (pl & SC_PAYLOAD_ISCOMPRESSED) {
1575 1470                  err |= nvlist_add_boolean_value(attr, "compressed",
1576 1471                      csave ? B_TRUE : B_FALSE);
1577 1472          }
1578 1473  
1579 1474          if (pl & SC_PAYLOAD_DUMPADM_EN) {
1580 1475                  char *disabled = defread("DUMPADM_ENABLE=no");
1581 1476  
1582 1477                  err |= nvlist_add_boolean_value(attr, "savecore-enabled",
1583 1478                      disabled ? B_FALSE : B_TRUE);
1584 1479          }
1585 1480  
1586 1481          if (pl & SC_PAYLOAD_IMAGEUUID) {
1587 1482                  (void) strncpy(uuidbuf, corehdr.dump_uuid, 36);
1588 1483                  uuidbuf[36] = '\0';
1589 1484                  err |= nvlist_add_string(attr, "os-instance-uuid", uuidbuf);
1590 1485          }
1591 1486  
1592 1487          if (pl & SC_PAYLOAD_CRASHTIME) {
1593 1488                  err |= nvlist_add_int64(attr, "crashtime",
1594 1489                      (int64_t)corehdr.dump_crashtime);
1595 1490          }
1596 1491  
1597 1492          if (pl & SC_PAYLOAD_PANICSTR && corehdr.dump_panicstring[0] != '\0') {
1598 1493                  err |= nvlist_add_string(attr, "panicstr",
1599 1494                      corehdr.dump_panicstring);
1600 1495          }
1601 1496  
1602 1497          if (pl & SC_PAYLOAD_PANICSTACK) {
1603 1498                  stack_retrieve(panic_stack);
1604 1499  
1605 1500                  if (panic_stack[0] != '\0') {
1606 1501                          /*
1607 1502                           * The summary page may not be present if the dump
1608 1503                           * was previously recorded compressed.
1609 1504                           */
1610 1505                          (void) nvlist_add_string(attr, "panicstack",
1611 1506                              panic_stack);
1612 1507                  }
1613 1508          }
1614 1509  
1615 1510          /* add warning string if this is an ireport for dump failure */
1616 1511          if (pl & SC_PAYLOAD_FAILREASON && warn_string != NULL)
1617 1512                  (void) nvlist_add_string(attr, "failure-reason", warn_string);
1618 1513  
1619 1514          if (pl & SC_PAYLOAD_DUMPCOMPLETE)
1620 1515                  err |= nvlist_add_boolean_value(attr, "dump-incomplete",
1621 1516                      dump_incomplete ? B_TRUE : B_FALSE);
1622 1517  
1623 1518          if (pl & SC_PAYLOAD_FM_PANIC) {
1624 1519                  err |= nvlist_add_boolean_value(attr, "fm-panic",
1625 1520                      fm_panic ? B_TRUE : B_FALSE);
1626 1521          }
1627 1522  
1628 1523          if (pl & SC_PAYLOAD_JUSTCHECKING) {
1629 1524                  err |= nvlist_add_boolean_value(attr, "will-attempt-savecore",
1630 1525                      cflag ? B_FALSE : B_TRUE);
1631 1526          }
1632 1527  
1633 1528          if (err)
1634 1529                  logprint(SC_SL_WARN, "Errors while constructing '%s' "
1635 1530                      "event payload; will try to publish anyway.");
1636 1531  publish:
1637 1532          if (fmev_rspublish_nvl(FMEV_RULESET_ON_SUNOS,
1638 1533              "panic", sc_event[evidx].sce_subclass, FMEV_HIPRI,
1639 1534              attr) != FMEV_SUCCESS) {
1640 1535                  logprint(SC_SL_ERR, "failed to publish '%s' event: %s",
1641 1536                      sc_event[evidx].sce_subclass, fmev_strerror(fmev_errno));
1642 1537                  nvlist_free(attr);
1643 1538          }
  
    | 
      ↓ open down ↓ | 
    71 lines elided | 
    
      ↑ open up ↑ | 
  
1644 1539  
1645 1540  }
1646 1541  
1647 1542  
1648 1543  int
1649 1544  main(int argc, char *argv[])
1650 1545  {
1651 1546          int i, c, bfd;
1652 1547          Stat_t st;
1653 1548          struct rlimit rl;
     1549 +        struct stat sc, sd;
1654 1550          long filebounds = -1;
1655 1551          char namelist[30], corefile[30], boundstr[30];
1656 1552          dumpfile = NULL;
     1553 +        char uuidstr[UUID_PRINTABLE_STRING_LENGTH];
     1554 +        uuid_t uu;
     1555 +        static char boundsfile[MAXPATHLEN];
     1556 +        static char boundslink[MAXPATHLEN];
     1557 +        static boolean_t fma_layout = B_TRUE;
     1558 +        char *slash;
1657 1559  
1658 1560          startts = gethrtime();
1659 1561  
1660 1562          (void) getrlimit(RLIMIT_NOFILE, &rl);
1661 1563          rl.rlim_cur = rl.rlim_max;
1662 1564          (void) setrlimit(RLIMIT_NOFILE, &rl);
1663 1565  
1664 1566          openlog(progname, LOG_ODELAY, LOG_AUTH);
1665 1567  
1666 1568          (void) defopen("/etc/dumpadm.conf");
1667 1569          savedir = defread("DUMPADM_SAVDIR=");
1668 1570          if (savedir != NULL)
1669 1571                  savedir = strdup(savedir);
1670 1572  
1671 1573          while ((c = getopt(argc, argv, "Lvcdmf:")) != EOF) {
1672 1574                  switch (c) {
1673 1575                  case 'L':
1674 1576                          livedump++;
1675 1577                          break;
1676 1578                  case 'v':
1677 1579                          verbose++;
1678 1580                          break;
1679 1581                  case 'c':
1680 1582                          cflag++;
  
    | 
      ↓ open down ↓ | 
    14 lines elided | 
    
      ↑ open up ↑ | 
  
1681 1583                          break;
1682 1584                  case 'd':
1683 1585                          disregard_valid_flag++;
1684 1586                          break;
1685 1587                  case 'm':
1686 1588                          mflag++;
1687 1589                          break;
1688 1590                  case 'f':
1689 1591                          dumpfile = optarg;
1690 1592                          filebounds = getbounds(dumpfile);
     1593 +                        fflag++;
1691 1594                          break;
1692 1595                  case '?':
1693 1596                          usage();
1694 1597                  }
1695 1598          }
1696 1599  
1697 1600          /*
1698 1601           * If doing something other than extracting an existing dump (i.e.
1699 1602           * dumpfile has been provided as an option), the user must be root.
1700 1603           */
1701 1604          if (geteuid() != 0 && dumpfile == NULL) {
1702 1605                  (void) fprintf(stderr, "%s: %s %s\n", progname,
1703 1606                      gettext("you must be root to use"), progname);
1704 1607                  exit(1);
1705 1608          }
1706 1609  
1707 1610          interactive = isatty(STDOUT_FILENO);
  
    | 
      ↓ open down ↓ | 
    7 lines elided | 
    
      ↑ open up ↑ | 
  
1708 1611  
1709 1612          if (cflag && livedump)
1710 1613                  usage();
1711 1614  
1712 1615          if (dumpfile == NULL || livedump)
1713 1616                  dumpfd = Open("/dev/dump", O_RDONLY, 0444);
1714 1617  
1715 1618          if (dumpfile == NULL) {
1716 1619                  dumpfile = Zalloc(MAXPATHLEN);
1717 1620                  if (ioctl(dumpfd, DIOCGETDEV, dumpfile) == -1) {
     1621 +                        skip_event = B_TRUE;
1718 1622                          have_dumpfile = B_FALSE;
1719 1623                          logprint(SC_SL_NONE | SC_IF_ISATTY | SC_EXIT_ERR,
1720 1624                              "no dump device configured");
1721 1625                  }
1722 1626          }
1723 1627  
1724 1628          if (mflag)
1725 1629                  return (message_save());
1726 1630  
1727      -        if (optind == argc - 1)
     1631 +        if (optind == argc - 1) {
     1632 +                /*
     1633 +                 * Use the default layout if directory was specified.
     1634 +                 * If the directory path matches value configured (by dumpadm),
     1635 +                 * then revert to fma layout.
     1636 +                 */
     1637 +                fma_layout = B_FALSE;
     1638 +                if (savedir != NULL && (stat(savedir, &sc) >= 0 &&
     1639 +                    stat(argv[optind], &sd) >= 0)) {
     1640 +                        if (sc.st_ino == sd.st_ino &&
     1641 +                            sc.st_dev == sd.st_dev) {
     1642 +                                fma_layout = B_TRUE;
     1643 +                        }
     1644 +                }
1728 1645                  savedir = argv[optind];
     1646 +        }
1729 1647  
1730 1648          if (savedir == NULL || optind < argc - 1)
1731 1649                  usage();
1732 1650  
1733      -        if (livedump && ioctl(dumpfd, DIOCDUMP, NULL) == -1)
1734      -                logprint(SC_SL_NONE | SC_EXIT_ERR,
1735      -                    "dedicated dump device required");
     1651 +        if (livedump) {
     1652 +                /*
     1653 +                 * For livedump we must update the dump header with
     1654 +                 * newly generated uuid.
     1655 +                 */
     1656 +                uuid_generate(uu);
     1657 +                uuid_unparse(uu, uuidstr);
     1658 +                if (ioctl(dumpfd, DIOCDUMP, uuidstr) == -1)
     1659 +                        logprint(SC_SL_NONE | SC_EXIT_ERR,
     1660 +                            "dedicated dump device required");
     1661 +        }
1736 1662  
1737 1663          (void) close(dumpfd);
1738 1664          dumpfd = -1;
1739 1665  
1740 1666          Stat(dumpfile, &st);
1741 1667  
1742 1668          filemode = S_ISREG(st.st_mode);
1743 1669  
1744 1670          if (!filemode && defread("DUMPADM_CSAVE=off") == NULL)
1745 1671                  csave = 1;
1746 1672  
1747 1673          read_dumphdr();
1748 1674  
1749 1675          /*
1750 1676           * We want this message to go to the log file, but not the console.
1751 1677           * There's no good way to do that with the existing syslog facility.
1752 1678           * We could extend it to handle this, but there doesn't seem to be
1753 1679           * a general need for it, so we isolate the complexity here instead.
1754 1680           */
1755 1681          if (dumphdr.dump_panicstring[0] != '\0') {
1756 1682                  int logfd = Open("/dev/conslog", O_WRONLY, 0644);
1757 1683                  log_ctl_t lc;
1758 1684                  struct strbuf ctl, dat;
1759 1685                  char msg[DUMP_PANICSIZE + 100];
1760 1686                  char fmt[] = "reboot after panic: %s";
1761 1687                  uint32_t msgid;
1762 1688  
1763 1689                  STRLOG_MAKE_MSGID(fmt, msgid);
1764 1690  
1765 1691                  /* LINTED: E_SEC_SPRINTF_UNBOUNDED_COPY */
1766 1692                  (void) sprintf(msg, "%s: [ID %u FACILITY_AND_PRIORITY] ",
1767 1693                      progname, msgid);
1768 1694                  /* LINTED: E_SEC_PRINTF_VAR_FMT */
1769 1695                  (void) sprintf(msg + strlen(msg), fmt,
1770 1696                      dumphdr.dump_panicstring);
1771 1697  
1772 1698                  lc.pri = LOG_AUTH | LOG_ERR;
1773 1699                  lc.flags = SL_CONSOLE | SL_LOGONLY;
1774 1700                  lc.level = 0;
1775 1701  
1776 1702                  ctl.buf = (void *)&lc;
1777 1703                  ctl.len = sizeof (log_ctl_t);
1778 1704  
1779 1705                  dat.buf = (void *)msg;
1780 1706                  dat.len = strlen(msg) + 1;
1781 1707  
1782 1708                  (void) putmsg(logfd, &ctl, &dat, 0);
1783 1709                  (void) close(logfd);
  
    | 
      ↓ open down ↓ | 
    38 lines elided | 
    
      ↑ open up ↑ | 
  
1784 1710          }
1785 1711  
1786 1712          if ((dumphdr.dump_flags & DF_COMPLETE) == 0) {
1787 1713                  logprint(SC_SL_WARN, "incomplete dump on dump device");
1788 1714                  dump_incomplete = B_TRUE;
1789 1715          }
1790 1716  
1791 1717          if (dumphdr.dump_fm_panic)
1792 1718                  fm_panic = B_TRUE;
1793 1719  
     1720 +        /* remove last slash */
     1721 +        slash = strrchr(savedir, '\0');
     1722 +        while (--slash > savedir && *slash == '/') {
     1723 +                *slash = '\0';
     1724 +        }
     1725 +
     1726 +        if (fma_layout) {
     1727 +                (void) snprintf(uuiddir, sizeof (uuiddir), "%s/data/%s",
     1728 +                    savedir, dumphdr.dump_uuid);
     1729 +        } else {
     1730 +                (void) strncpy(uuiddir, savedir, sizeof (uuiddir));
     1731 +        }
     1732 +
1794 1733          /*
1795 1734           * We have a valid dump on a dump device and know as much about
1796 1735           * it as we're going to at this stage.  Raise an event for
1797 1736           * logging and so that FMA can open a case for this panic.
1798 1737           * Avoid this step for FMA-initiated panics - FMA will replay
1799 1738           * ereports off the dump device independently of savecore and
1800 1739           * will make a diagnosis, so we don't want to open two cases
1801 1740           * for the same event.  Also avoid raising an event for a
1802 1741           * livedump, or when we inflating a compressed dump.
1803 1742           */
1804 1743          if (!fm_panic && !livedump && !filemode)
1805 1744                  raise_event(SC_EVENT_DUMP_PENDING, NULL);
1806 1745  
1807 1746          logprint(SC_SL_WARN, "System dump time: %s",
1808 1747              ctime(&dumphdr.dump_crashtime));
1809 1748  
1810 1749          /*
1811 1750           * Option -c is designed for use from svc-dumpadm where we know
1812 1751           * that dumpadm -n is in effect but run savecore -c just to
1813 1752           * get the above dump_pending_on_device event raised.  If it is run
1814 1753           * interactively then just print further panic details.
1815 1754           */
1816 1755          if (cflag) {
1817 1756                  char *disabled = defread("DUMPADM_ENABLE=no");
1818 1757                  int lvl = interactive ? SC_SL_WARN : SC_SL_ERR;
1819 1758                  int ec = fm_panic ? SC_EXIT_FM : SC_EXIT_PEND;
1820 1759  
  
    | 
      ↓ open down ↓ | 
    17 lines elided | 
    
      ↑ open up ↑ | 
  
1821 1760                  logprint(lvl | ec,
1822 1761                      "Panic crashdump pending on dump device%s "
1823 1762                      "run savecore(1M) manually to extract. "
1824 1763                      "Image UUID %s%s.",
1825 1764                      disabled ? " but dumpadm -n in effect;" : ";",
1826 1765                      corehdr.dump_uuid,
1827 1766                      fm_panic ?  "(fault-management initiated)" : "");
1828 1767                  /*NOTREACHED*/
1829 1768          }
1830 1769  
1831      -        if (chdir(savedir) == -1)
     1770 +        if (fma_layout && mkdirp(uuiddir, 0755) != 0) {
     1771 +                if (errno != EEXIST)
     1772 +                        logprint(SC_SL_ERR | SC_EXIT_ERR,
     1773 +                            "mkdirp(\"%s\"): %s",
     1774 +                            uuiddir, strerror(errno));
     1775 +        }
     1776 +
     1777 +        if (chdir(uuiddir) == -1)
1832 1778                  logprint(SC_SL_ERR | SC_EXIT_ERR, "chdir(\"%s\"): %s",
1833      -                    savedir, strerror(errno));
     1779 +                    uuiddir, strerror(errno));
1834 1780  
1835 1781          check_space(csave);
1836 1782  
     1783 +        (void) snprintf(boundsfile, MAXPATHLEN, "%s/bounds", savedir);
     1784 +
1837 1785          if (filebounds < 0)
1838      -                bounds = read_number_from_file("bounds", 0);
     1786 +                bounds = read_number_from_file(boundsfile, 0);
1839 1787          else
1840 1788                  bounds = filebounds;
1841 1789  
     1790 +        if (!fflag && disregard_valid_flag && bounds > 0)
     1791 +                bounds--;
     1792 +
     1793 +        (void) snprintf(boundslink, MAXPATHLEN, "%s/%d", savedir, bounds);
     1794 +
     1795 +        /*
     1796 +         * Create a symbolic link to easily maintain the sequential ordering.
     1797 +         */
     1798 +        if (!fflag && fma_layout && symlink(uuiddir, boundslink) != 0) {
     1799 +                if (errno == EEXIST) {
     1800 +                        char symbuf[MAXPATHLEN] = {'\0'};
     1801 +
     1802 +                        if (readlink(boundslink, symbuf, sizeof (symbuf)) < 0)
     1803 +                                logprint(SC_SL_ERR | SC_EXIT_ERR,
     1804 +                                "readlink: %s", strerror(errno));
     1805 +                        if (strcmp(symbuf, uuiddir) != 0) {
     1806 +                                logprint(SC_SL_ERR,
     1807 +                                    "Symbolic link %s already exists but "
     1808 +                                    "specifies a wrong UUID directory, "
     1809 +                                    "new symbolic link will be created "
     1810 +                                    "instead", boundslink);
     1811 +                                (void) unlink(boundslink);
     1812 +                                if (symlink(uuiddir, boundslink) != 0)
     1813 +                                        logprint(SC_SL_ERR | SC_EXIT_ERR,
     1814 +                                            "symlink: %s", strerror(errno));
     1815 +                        }
     1816 +                } else {
     1817 +                        logprint(SC_SL_ERR | SC_EXIT_ERR, "symlink: %s",
     1818 +                            strerror(errno));
     1819 +                }
     1820 +        }
     1821 +
1842 1822          if (csave) {
1843 1823                  size_t metrics_size = datahdr.dump_metrics;
1844 1824  
1845 1825                  (void) sprintf(corefile, "vmdump.%ld", bounds);
1846 1826  
     1827 +                if (interactive && bounds >= 0 && access(corefile, F_OK)
     1828 +                    == 0) {
     1829 +                        skip_event = B_TRUE;
     1830 +                        logprint(SC_SL_NONE | SC_EXIT_ERR,
     1831 +                            "%s already exists: remove with "
     1832 +                            "'rm -f %s/{unix,vmcore}.%ld'",
     1833 +                            corefile, uuiddir, bounds);
     1834 +                }
     1835 +
1847 1836                  datahdr.dump_metrics = 0;
1848 1837  
1849 1838                  logprint(SC_SL_ERR,
1850 1839                      "Saving compressed system crash dump in %s/%s",
1851      -                    savedir, corefile);
     1840 +                    uuiddir, corefile);
1852 1841  
1853 1842                  copy_crashfile(corefile);
1854 1843  
1855 1844                  /*
1856 1845                   * Raise a fault management event that indicates the system
1857 1846                   * has panicked. We know a reasonable amount about the
1858 1847                   * condition at this time, but the dump is still compressed.
1859 1848                   */
1860 1849                  if (!livedump && !fm_panic)
1861 1850                          raise_event(SC_EVENT_DUMP_AVAILABLE, NULL);
1862 1851  
1863 1852                  if (metrics_size > 0) {
1864 1853                          int sec = (gethrtime() - startts) / 1000 / 1000 / 1000;
1865 1854                          FILE *mfile = fopen(METRICSFILE, "a");
1866 1855                          char *metrics = Zalloc(metrics_size + 1);
1867 1856  
1868 1857                          Pread(dumpfd, metrics, metrics_size, endoff +
1869 1858                              sizeof (dumphdr) + sizeof (datahdr));
1870 1859  
1871 1860                          if (sec < 1)
1872 1861                                  sec = 1;
1873 1862  
1874 1863                          if (mfile == NULL) {
1875 1864                                  logprint(SC_SL_WARN,
1876 1865                                      "Can't create %s:\n%s",
1877 1866                                      METRICSFILE, metrics);
1878 1867                          } else {
1879 1868                                  (void) fprintf(mfile, "[[[[,,,");
1880 1869                                  for (i = 0; i < argc; i++)
1881 1870                                          (void) fprintf(mfile, "%s ", argv[i]);
1882 1871                                  (void) fprintf(mfile, "\n");
1883 1872                                  (void) fprintf(mfile, ",,,%s %s %s %s %s\n",
1884 1873                                      dumphdr.dump_utsname.sysname,
1885 1874                                      dumphdr.dump_utsname.nodename,
1886 1875                                      dumphdr.dump_utsname.release,
1887 1876                                      dumphdr.dump_utsname.version,
1888 1877                                      dumphdr.dump_utsname.machine);
1889 1878                                  (void) fprintf(mfile, ",,,%s dump time %s\n",
1890 1879                                      dumphdr.dump_flags & DF_LIVE ? "Live" :
1891 1880                                      "Crash", ctime(&dumphdr.dump_crashtime));
1892 1881                                  (void) fprintf(mfile, ",,,%s/%s\n", savedir,
1893 1882                                      corefile);
1894 1883                                  (void) fprintf(mfile, "Metrics:\n%s\n",
1895 1884                                      metrics);
1896 1885                                  (void) fprintf(mfile, "Copy pages,%ld\n",
1897 1886                                      dumphdr.  dump_npages);
1898 1887                                  (void) fprintf(mfile, "Copy time,%d\n", sec);
1899 1888                                  (void) fprintf(mfile, "Copy pages/sec,%ld\n",
  
    | 
      ↓ open down ↓ | 
    38 lines elided | 
    
      ↑ open up ↑ | 
  
1900 1889                                      dumphdr.dump_npages / sec);
1901 1890                                  (void) fprintf(mfile, "]]]]\n");
1902 1891                                  (void) fclose(mfile);
1903 1892                          }
1904 1893                          free(metrics);
1905 1894                  }
1906 1895  
1907 1896                  logprint(SC_SL_ERR,
1908 1897                      "Decompress the crash dump with "
1909 1898                      "\n'savecore -vf %s/%s'",
1910      -                    savedir, corefile);
     1899 +                    uuiddir, corefile);
1911 1900  
1912 1901          } else {
1913 1902                  (void) sprintf(namelist, "unix.%ld", bounds);
1914 1903                  (void) sprintf(corefile, "vmcore.%ld", bounds);
1915 1904  
1916      -                if (interactive && filebounds >= 0 && access(corefile, F_OK)
1917      -                    == 0)
     1905 +                if (interactive && bounds >= 0 && access(corefile, F_OK)
     1906 +                    == 0) {
     1907 +                        skip_event = B_TRUE;
1918 1908                          logprint(SC_SL_NONE | SC_EXIT_ERR,
1919 1909                              "%s already exists: remove with "
1920 1910                              "'rm -f %s/{unix,vmcore}.%ld'",
1921      -                            corefile, savedir, bounds);
     1911 +                            corefile, uuiddir, bounds);
     1912 +                }
1922 1913  
1923 1914                  logprint(SC_SL_ERR,
1924 1915                      "saving system crash dump in %s/{unix,vmcore}.%ld",
1925      -                    savedir, bounds);
     1916 +                    uuiddir, bounds);
1926 1917  
1927 1918                  build_corefile(namelist, corefile);
1928 1919  
1929 1920                  if (!livedump && !filemode && !fm_panic)
1930 1921                          raise_event(SC_EVENT_DUMP_AVAILABLE, NULL);
1931 1922  
1932 1923                  if (access(METRICSFILE, F_OK) == 0) {
1933 1924                          int sec = (gethrtime() - startts) / 1000 / 1000 / 1000;
1934 1925                          FILE *mfile = fopen(METRICSFILE, "a");
1935 1926  
1936 1927                          if (sec < 1)
1937 1928                                  sec = 1;
1938 1929  
1939 1930                          if (mfile == NULL) {
1940 1931                                  logprint(SC_SL_WARN,
1941 1932                                      "Can't create %s: %s",
1942 1933                                      METRICSFILE, strerror(errno));
1943 1934                          } else {
1944 1935                                  (void) fprintf(mfile, "[[[[,,,");
1945 1936                                  for (i = 0; i < argc; i++)
1946 1937                                          (void) fprintf(mfile, "%s ", argv[i]);
1947 1938                                  (void) fprintf(mfile, "\n");
1948 1939                                  (void) fprintf(mfile, ",,,%s/%s\n", savedir,
1949 1940                                      corefile);
1950 1941                                  (void) fprintf(mfile, ",,,%s %s %s %s %s\n",
1951 1942                                      dumphdr.dump_utsname.sysname,
1952 1943                                      dumphdr.dump_utsname.nodename,
1953 1944                                      dumphdr.dump_utsname.release,
1954 1945                                      dumphdr.dump_utsname.version,
1955 1946                                      dumphdr.dump_utsname.machine);
1956 1947                                  (void) fprintf(mfile,
1957 1948                                      "Uncompress pages,%"PRIu64"\n", saved);
1958 1949                                  (void) fprintf(mfile, "Uncompress time,%d\n",
1959 1950                                      sec);
  
    | 
      ↓ open down ↓ | 
    24 lines elided | 
    
      ↑ open up ↑ | 
  
1960 1951                                  (void) fprintf(mfile, "Uncompress pages/sec,%"
1961 1952                                      PRIu64"\n", saved / sec);
1962 1953                                  (void) fprintf(mfile, "]]]]\n");
1963 1954                                  (void) fclose(mfile);
1964 1955                          }
1965 1956                  }
1966 1957          }
1967 1958  
1968 1959          if (filebounds < 0) {
1969 1960                  (void) sprintf(boundstr, "%ld\n", bounds + 1);
1970      -                bfd = Open("bounds", O_WRONLY | O_CREAT | O_TRUNC, 0644);
     1961 +                bfd = Open(boundsfile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1971 1962                  Pwrite(bfd, boundstr, strlen(boundstr), 0);
1972 1963                  (void) close(bfd);
1973 1964          }
1974 1965  
1975 1966          if (verbose) {
1976 1967                  int sec = (gethrtime() - startts) / 1000 / 1000 / 1000;
1977 1968  
1978 1969                  (void) printf("%d:%02d dump %s is done\n",
1979 1970                      sec / 60, sec % 60,
1980 1971                      csave ? "copy" : "decompress");
1981 1972          }
1982 1973  
1983 1974          if (verbose > 1 && hist != NULL) {
1984 1975                  int i, nw;
1985 1976  
1986 1977                  for (i = 1, nw = 0; i <= BTOP(coreblksize); ++i)
1987 1978                          nw += hist[i] * i;
1988 1979                  (void) printf("pages count     %%\n");
1989 1980                  for (i = 0; i <= BTOP(coreblksize); ++i) {
1990 1981                          if (hist[i] == 0)
1991 1982                                  continue;
1992 1983                          (void) printf("%3d   %5u  %6.2f\n",
1993 1984                              i, hist[i], 100.0 * hist[i] * i / nw);
1994 1985                  }
1995 1986          }
1996 1987  
1997 1988          (void) close(dumpfd);
1998 1989          dumpfd = -1;
1999 1990  
2000 1991          return (0);
2001 1992  }
  
    | 
      ↓ open down ↓ | 
    21 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX