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
↓ 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>
↓ 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 */
↓ 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.
↓ 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);
↓ 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,
↓ 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  {
↓ 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;
↓ 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 {
↓ 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;
↓ 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                  }
↓ 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)
↓ 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;
↓ 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          /*
↓ 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);
↓ 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");
↓ 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           */
↓ 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;
↓ 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           */
↓ 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);
↓ 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  
↓ 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");
↓ open down ↓ 21 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX