4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 1983, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
26 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
43 #include <libnvpair.h>
46 #include <sys/statvfs.h>
47 #include <sys/dumphdr.h>
48 #include <sys/dumpadm.h>
49 #include <sys/compress.h>
50 #include <sys/panic.h>
51 #include <sys/sysmacros.h>
53 #include <sys/resource.h>
54 #include <bzip2/bzlib.h>
55 #include <sys/fm/util.h>
56 #include <fm/libfmevent.h>
57 #include <sys/int_fmtio.h>
60 /* fread/fwrite buffer size */
61 #define FBUFSIZE (1ULL << 20)
63 /* minimum size for output buffering */
64 #define MINCOREBLKSIZE (1ULL << 17)
66 /* create this file if metrics collection is enabled in the kernel */
67 #define METRICSFILE "METRICS.csv"
69 static char progname
[9] = "savecore";
70 static char *savedir
; /* savecore directory */
71 static char *dumpfile
; /* source of raw crash dump */
72 static long bounds
= -1; /* numeric suffix */
73 static long pagesize
; /* dump pagesize */
74 static int dumpfd
= -1; /* dumpfile descriptor */
75 static dumphdr_t corehdr
, dumphdr
; /* initial and terminal dumphdrs */
76 static boolean_t dump_incomplete
; /* dumphdr indicates incomplete */
77 static boolean_t fm_panic
; /* dump is the result of fm_panic */
78 static offset_t endoff
; /* offset of end-of-dump header */
79 static int verbose
; /* chatty mode */
80 static int disregard_valid_flag
; /* disregard valid flag */
81 static int livedump
; /* dump the current running system */
82 static int interactive
; /* user invoked; no syslog */
83 static int csave
; /* save dump compressed */
84 static int filemode
; /* processing file, not dump device */
85 static int percent_done
; /* progress indicator */
86 static hrtime_t startts
; /* timestamp at start */
87 static volatile uint64_t saved
; /* count of pages written */
88 static volatile uint64_t zpages
; /* count of zero pages not written */
89 static dumpdatahdr_t datahdr
; /* compression info */
90 static long coreblksize
; /* preferred write size (st_blksize) */
91 static int cflag
; /* run as savecore -c */
92 static int mflag
; /* run as savecore -m */
95 * Payload information for the events we raise. These are used
96 * in raise_event to determine what payload to include.
98 #define SC_PAYLOAD_SAVEDIR 0x0001 /* Include savedir in event */
99 #define SC_PAYLOAD_INSTANCE 0x0002 /* Include bounds instance number */
100 #define SC_PAYLOAD_IMAGEUUID 0x0004 /* Include dump OS instance uuid */
101 #define SC_PAYLOAD_CRASHTIME 0x0008 /* Include epoch crashtime */
102 #define SC_PAYLOAD_PANICSTR 0x0010 /* Include panic string */
103 #define SC_PAYLOAD_PANICSTACK 0x0020 /* Include panic string */
104 #define SC_PAYLOAD_FAILREASON 0x0040 /* Include failure reason */
105 #define SC_PAYLOAD_DUMPCOMPLETE 0x0080 /* Include completeness indicator */
106 #define SC_PAYLOAD_ISCOMPRESSED 0x0100 /* Dump is in vmdump.N form */
107 #define SC_PAYLOAD_DUMPADM_EN 0x0200 /* Is dumpadm enabled or not? */
108 #define SC_PAYLOAD_FM_PANIC 0x0400 /* Panic initiated by FMA */
109 #define SC_PAYLOAD_JUSTCHECKING 0x0800 /* Run with -c flag? */
112 SC_EVENT_DUMP_PENDING
,
113 SC_EVENT_SAVECORE_FAILURE
,
114 SC_EVENT_DUMP_AVAILABLE
120 #define _SC_PAYLOAD_CMN \
121 SC_PAYLOAD_IMAGEUUID | \
122 SC_PAYLOAD_CRASHTIME | \
123 SC_PAYLOAD_PANICSTR | \
124 SC_PAYLOAD_PANICSTACK | \
125 SC_PAYLOAD_DUMPCOMPLETE | \
126 SC_PAYLOAD_FM_PANIC | \
129 static const struct {
130 const char *sce_subclass
;
131 uint32_t sce_payload
;
134 * SC_EVENT_DUMP_PENDING
137 "dump_pending_on_device",
138 _SC_PAYLOAD_CMN
| SC_PAYLOAD_DUMPADM_EN
|
139 SC_PAYLOAD_JUSTCHECKING
143 * SC_EVENT_SAVECORE_FAILURE
147 _SC_PAYLOAD_CMN
| SC_PAYLOAD_INSTANCE
| SC_PAYLOAD_FAILREASON
151 * SC_EVENT_DUMP_AVAILABLE
155 _SC_PAYLOAD_CMN
| SC_PAYLOAD_INSTANCE
| SC_PAYLOAD_ISCOMPRESSED
159 static void raise_event(enum sc_event_type
, char *);
164 (void) fprintf(stderr
,
165 "usage: %s [-Lvd] [-f dumpfile] [dirname]\n", progname
);
169 #define SC_SL_NONE 0x0001 /* no syslog */
170 #define SC_SL_ERR 0x0002 /* syslog if !interactive, LOG_ERR */
171 #define SC_SL_WARN 0x0004 /* syslog if !interactive, LOG_WARNING */
172 #define SC_IF_VERBOSE 0x0008 /* message only if -v */
173 #define SC_IF_ISATTY 0x0010 /* message only if interactive */
174 #define SC_EXIT_OK 0x0020 /* exit(0) */
175 #define SC_EXIT_ERR 0x0040 /* exit(1) */
176 #define SC_EXIT_PEND 0x0080 /* exit(2) */
177 #define SC_EXIT_FM 0x0100 /* exit(3) */
179 #define _SC_ALLEXIT (SC_EXIT_OK | SC_EXIT_ERR | SC_EXIT_PEND | SC_EXIT_FM)
182 logprint(uint32_t flags
, char *message
, ...)
186 int do_always
= ((flags
& (SC_IF_VERBOSE
| SC_IF_ISATTY
)) == 0);
187 int do_ifverb
= (flags
& SC_IF_VERBOSE
) && verbose
;
188 int do_ifisatty
= (flags
& SC_IF_ISATTY
) && interactive
;
190 static int logprint_raised
= 0;
192 if (do_always
|| do_ifverb
|| do_ifisatty
) {
193 va_start(args
, message
);
194 /*LINTED: E_SEC_PRINTF_VAR_FMT*/
195 (void) vsnprintf(buf
, sizeof (buf
), message
, args
);
196 (void) fprintf(stderr
, "%s: %s\n", progname
, buf
);
198 switch (flags
& (SC_SL_NONE
| SC_SL_ERR
| SC_SL_WARN
)) {
200 /*LINTED: E_SEC_PRINTF_VAR_FMT*/
201 syslog(LOG_ERR
, buf
);
205 /*LINTED: E_SEC_PRINTF_VAR_FMT*/
206 syslog(LOG_WARNING
, buf
);
216 switch (flags
& _SC_ALLEXIT
) {
226 * Raise an ireport saying why we are exiting. Do not
227 * raise if run as savecore -m. If something in the
228 * raise_event codepath calls logprint avoid recursion.
230 if (!mflag
&& logprint_raised
++ == 0)
231 raise_event(SC_EVENT_SAVECORE_FAILURE
, buf
);
241 if (!mflag
&& logprint_raised
++ == 0)
242 raise_event(SC_EVENT_SAVECORE_FAILURE
, buf
);
251 * System call / libc wrappers that exit on error.
254 Open(const char *name
, int oflags
, mode_t mode
)
258 if ((fd
= open64(name
, oflags
, mode
)) == -1)
259 logprint(SC_SL_ERR
| SC_EXIT_ERR
, "open(\"%s\"): %s",
260 name
, strerror(errno
));
265 Fread(void *buf
, size_t size
, FILE *f
)
267 if (fread(buf
, size
, 1, f
) != 1)
268 logprint(SC_SL_ERR
| SC_EXIT_ERR
, "fread: ferror %d feof %d",
273 Fwrite(void *buf
, size_t size
, FILE *f
)
275 if (fwrite(buf
, size
, 1, f
) != 1)
276 logprint(SC_SL_ERR
| SC_EXIT_ERR
, "fwrite: %s",
281 Fseek(offset_t off
, FILE *f
)
283 if (fseeko64(f
, off
, SEEK_SET
) != 0)
284 logprint(SC_SL_ERR
| SC_EXIT_ERR
, "fseeko64: %s",
288 typedef struct stat64 Stat_t
;
291 Fstat(int fd
, Stat_t
*sb
, const char *fname
)
293 if (fstat64(fd
, sb
) != 0)
294 logprint(SC_SL_ERR
| SC_EXIT_ERR
, "fstat(\"%s\"): %s", fname
,
299 Stat(const char *fname
, Stat_t
*sb
)
301 if (stat64(fname
, sb
) != 0)
302 logprint(SC_SL_ERR
| SC_EXIT_ERR
, "stat(\"%s\"): %s", fname
,
307 Pread(int fd
, void *buf
, size_t size
, offset_t off
)
309 ssize_t sz
= pread64(fd
, buf
, size
, off
);
312 logprint(SC_SL_ERR
| SC_EXIT_ERR
,
313 "pread: %s", strerror(errno
));
315 logprint(SC_SL_ERR
| SC_EXIT_ERR
,
316 "pread: size %ld != %ld", sz
, size
);
320 Pwrite(int fd
, void *buf
, size_t size
, off64_t off
)
322 if (pwrite64(fd
, buf
, size
, off
) != size
)
323 logprint(SC_SL_ERR
| SC_EXIT_ERR
, "pwrite: %s",
332 if ((buf
= calloc(size
, 1)) == NULL
)
333 logprint(SC_SL_ERR
| SC_EXIT_ERR
, "calloc: %s",
339 read_number_from_file(const char *filename
, long default_value
)
341 long file_value
= -1;
344 if ((fp
= fopen(filename
, "r")) != NULL
) {
345 (void) fscanf(fp
, "%ld", &file_value
);
348 return (file_value
< 0 ? default_value
: file_value
);
355 dumpfd
= Open(dumpfile
, O_RDONLY
, 0644);
357 dumpfd
= Open(dumpfile
, O_RDWR
| O_DSYNC
, 0644);
358 endoff
= llseek(dumpfd
, -DUMP_OFFSET
, SEEK_END
) & -DUMP_OFFSET
;
359 Pread(dumpfd
, &dumphdr
, sizeof (dumphdr
), endoff
);
360 Pread(dumpfd
, &datahdr
, sizeof (datahdr
), endoff
+ sizeof (dumphdr
));
362 pagesize
= dumphdr
.dump_pagesize
;
364 if (dumphdr
.dump_magic
!= DUMP_MAGIC
)
365 logprint(SC_SL_NONE
| SC_EXIT_PEND
, "bad magic number %x",
368 if ((dumphdr
.dump_flags
& DF_VALID
) == 0 && !disregard_valid_flag
)
369 logprint(SC_SL_NONE
| SC_IF_VERBOSE
| SC_EXIT_OK
,
370 "dump already processed");
372 if (dumphdr
.dump_version
!= DUMP_VERSION
)
373 logprint(SC_SL_NONE
| SC_IF_VERBOSE
| SC_EXIT_PEND
,
374 "dump version (%d) != %s version (%d)",
375 dumphdr
.dump_version
, progname
, DUMP_VERSION
);
377 if (dumphdr
.dump_wordsize
!= DUMP_WORDSIZE
)
378 logprint(SC_SL_NONE
| SC_EXIT_PEND
,
379 "dump is from %u-bit kernel - cannot save on %u-bit kernel",
380 dumphdr
.dump_wordsize
, DUMP_WORDSIZE
);
382 if (datahdr
.dump_datahdr_magic
== DUMP_DATAHDR_MAGIC
) {
383 if (datahdr
.dump_datahdr_version
!= DUMP_DATAHDR_VERSION
)
384 logprint(SC_SL_NONE
| SC_IF_VERBOSE
| SC_EXIT_PEND
,
385 "dump data version (%d) != %s data version (%d)",
386 datahdr
.dump_datahdr_version
, progname
,
387 DUMP_DATAHDR_VERSION
);
389 (void) memset(&datahdr
, 0, sizeof (datahdr
));
390 datahdr
.dump_maxcsize
= pagesize
;
394 * Read the initial header, clear the valid bits, and compare headers.
395 * The main header may have been overwritten by swapping if we're
396 * using a swap partition as the dump device, in which case we bail.
398 Pread(dumpfd
, &corehdr
, sizeof (dumphdr_t
), dumphdr
.dump_start
);
400 corehdr
.dump_flags
&= ~DF_VALID
;
401 dumphdr
.dump_flags
&= ~DF_VALID
;
403 if (memcmp(&corehdr
, &dumphdr
, sizeof (dumphdr_t
)) != 0) {
405 * Clear valid bit so we don't complain on every invocation.
408 Pwrite(dumpfd
, &dumphdr
, sizeof (dumphdr
), endoff
);
409 logprint(SC_SL_ERR
| SC_EXIT_ERR
,
410 "initial dump header corrupt");
415 check_space(int csave
)
418 int64_t spacefree
, dumpsize
, minfree
, datasize
;
420 if (statvfs(".", &fsb
) < 0)
421 logprint(SC_SL_ERR
| SC_EXIT_ERR
, "statvfs: %s",
424 dumpsize
= dumphdr
.dump_data
- dumphdr
.dump_start
;
425 datasize
= dumphdr
.dump_npages
* pagesize
;
427 dumpsize
+= datasize
;
429 dumpsize
+= datahdr
.dump_data_csize
;
431 spacefree
= (int64_t)fsb
.f_bavail
* fsb
.f_frsize
;
432 minfree
= 1024LL * read_number_from_file("minfree", 1024);
433 if (spacefree
< minfree
+ dumpsize
) {
434 logprint(SC_SL_ERR
| SC_EXIT_ERR
,
435 "not enough space in %s (%lld MB avail, %lld MB needed)",
436 savedir
, spacefree
>> 20, (minfree
+ dumpsize
) >> 20);
441 build_dump_map(int corefd
, const pfn_t
*pfn_table
)
444 static long misses
= 0;
445 size_t dump_mapsize
= (corehdr
.dump_hashmask
+ 1) * sizeof (dump_map_t
);
447 dump_map_t
*dmp
= Zalloc(dump_mapsize
);
448 char *inbuf
= Zalloc(FBUFSIZE
);
449 FILE *in
= fdopen(dup(dumpfd
), "rb");
451 (void) setvbuf(in
, inbuf
, _IOFBF
, FBUFSIZE
);
452 Fseek(dumphdr
.dump_map
, in
);
454 corehdr
.dump_data
= corehdr
.dump_map
+ roundup(dump_mapsize
, pagesize
);
456 for (i
= 0; i
< corehdr
.dump_nvtop
; i
++) {
458 long last
= corehdr
.dump_npages
- 1;
463 Fread(&vtop
, sizeof (mem_vtop_t
), in
);
464 while (last
>= first
) {
465 middle
= (first
+ last
) / 2;
466 pfn
= pfn_table
[middle
];
467 if (pfn
== vtop
.m_pfn
)
469 if (pfn
< vtop
.m_pfn
)
474 if (pfn
!= vtop
.m_pfn
) {
476 (void) fprintf(stderr
,
477 "pfn %ld not found for as=%p, va=%p\n",
478 vtop
.m_pfn
, (void *)vtop
.m_as
, vtop
.m_va
);
482 dmp
[i
].dm_as
= vtop
.m_as
;
483 dmp
[i
].dm_va
= (uintptr_t)vtop
.m_va
;
484 dmp
[i
].dm_data
= corehdr
.dump_data
+
485 ((uint64_t)middle
<< corehdr
.dump_pageshift
);
487 h
= DUMP_HASH(&corehdr
, dmp
[i
].dm_as
, dmp
[i
].dm_va
);
488 dmp
[i
].dm_next
= dmp
[h
].dm_first
;
489 dmp
[h
].dm_first
= corehdr
.dump_map
+ i
* sizeof (dump_map_t
);
492 Pwrite(corefd
, dmp
, dump_mapsize
, corehdr
.dump_map
);
499 * Copy whole sections of the dump device to the file.
502 Copy(offset_t dumpoff
, len_t nb
, offset_t
*offp
, int fd
, char *buf
,
506 offset_t off
= *offp
;
509 nr
= sz
< nb
? sz
: (size_t)nb
;
510 Pread(dumpfd
, buf
, nr
, dumpoff
);
511 Pwrite(fd
, buf
, nr
, off
);
520 * Copy pages when the dump data header is missing.
521 * This supports older kernels with latest savecore.
524 CopyPages(offset_t
*offp
, int fd
, char *buf
, size_t sz
)
527 FILE *in
= fdopen(dup(dumpfd
), "rb");
528 FILE *out
= fdopen(dup(fd
), "wb");
529 char *cbuf
= Zalloc(pagesize
);
530 char *outbuf
= Zalloc(FBUFSIZE
);
531 pgcnt_t np
= dumphdr
.dump_npages
;
533 (void) setvbuf(out
, outbuf
, _IOFBF
, FBUFSIZE
);
534 (void) setvbuf(in
, buf
, _IOFBF
, sz
);
535 Fseek(dumphdr
.dump_data
, in
);
539 Fread(&csize
, sizeof (uint32_t), in
);
540 Fwrite(&csize
, sizeof (uint32_t), out
);
541 *offp
+= sizeof (uint32_t);
542 if (csize
> pagesize
|| csize
== 0) {
544 "CopyPages: page %lu csize %d (0x%x) pagesize %d",
545 dumphdr
.dump_npages
- np
, csize
, csize
,
549 Fread(cbuf
, csize
, in
);
550 Fwrite(cbuf
, csize
, out
);
561 * Concatenate dump contents into a new file.
562 * Update corehdr with new offsets.
565 copy_crashfile(const char *corefile
)
567 int corefd
= Open(corefile
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0644);
568 size_t bufsz
= FBUFSIZE
;
569 char *inbuf
= Zalloc(bufsz
);
573 logprint(SC_SL_ERR
| SC_IF_VERBOSE
,
574 "Copying %s to %s/%s\n", dumpfile
, savedir
, corefile
);
577 * This dump file is still compressed
579 corehdr
.dump_flags
|= DF_COMPRESSED
| DF_VALID
;
582 * Leave room for corehdr, it is updated and written last
584 corehdr
.dump_start
= 0;
585 coreoff
= sizeof (corehdr
);
588 * Read in the compressed symbol table, copy it to corefile.
590 coreoff
= roundup(coreoff
, pagesize
);
591 corehdr
.dump_ksyms
= coreoff
;
592 Copy(dumphdr
.dump_ksyms
, dumphdr
.dump_ksyms_csize
, &coreoff
, corefd
,
596 * Save the pfn table.
598 coreoff
= roundup(coreoff
, pagesize
);
599 corehdr
.dump_pfn
= coreoff
;
600 Copy(dumphdr
.dump_pfn
, dumphdr
.dump_npages
* sizeof (pfn_t
), &coreoff
,
601 corefd
, inbuf
, bufsz
);
606 coreoff
= roundup(coreoff
, pagesize
);
607 corehdr
.dump_map
= coreoff
;
608 Copy(dumphdr
.dump_map
, dumphdr
.dump_nvtop
* sizeof (mem_vtop_t
),
609 &coreoff
, corefd
, inbuf
, bufsz
);
612 * Save the data pages.
614 coreoff
= roundup(coreoff
, pagesize
);
615 corehdr
.dump_data
= coreoff
;
616 if (datahdr
.dump_data_csize
!= 0)
617 Copy(dumphdr
.dump_data
, datahdr
.dump_data_csize
, &coreoff
,
618 corefd
, inbuf
, bufsz
);
620 CopyPages(&coreoff
, corefd
, inbuf
, bufsz
);
623 * Now write the modified dump header to front and end of the copy.
624 * Make it look like a valid dump device.
626 * From dumphdr.h: Two headers are written out: one at the
627 * beginning of the dump, and the other at the very end of the
628 * dump device. The terminal header is at a known location
629 * (end of device) so we can always find it.
631 * Pad with zeros to each DUMP_OFFSET boundary.
633 (void) memset(inbuf
, 0, DUMP_OFFSET
);
635 nb
= DUMP_OFFSET
- (coreoff
& (DUMP_OFFSET
- 1));
637 Pwrite(corefd
, inbuf
, nb
, coreoff
);
641 Pwrite(corefd
, &corehdr
, sizeof (corehdr
), coreoff
);
642 coreoff
+= sizeof (corehdr
);
644 Pwrite(corefd
, &datahdr
, sizeof (datahdr
), coreoff
);
645 coreoff
+= sizeof (datahdr
);
647 nb
= DUMP_OFFSET
- (coreoff
& (DUMP_OFFSET
- 1));
649 Pwrite(corefd
, inbuf
, nb
, coreoff
);
653 Pwrite(corefd
, &corehdr
, sizeof (corehdr
), corehdr
.dump_start
);
656 * Write out the modified dump header to the dump device.
657 * The dump device has been processed, so DF_VALID is clear.
660 Pwrite(dumpfd
, &dumphdr
, sizeof (dumphdr
), endoff
);
662 (void) close(corefd
);
668 typedef struct blockhdr blockhdr_t
;
669 typedef struct block block_t
;
682 typedef enum streamstate
{
687 typedef struct stream
{
704 static stream_t
*streams
;
705 static stream_t
*endstreams
;
707 const int cs
= sizeof (dumpcsize_t
);
709 typedef struct tinfo
{
714 static int threads_stop
;
715 static int threads_active
;
716 static tinfo_t
*tinfo
;
717 static tinfo_t
*endtinfo
;
719 static pthread_mutex_t lock
= PTHREAD_MUTEX_INITIALIZER
;
720 static pthread_cond_t cvfree
= PTHREAD_COND_INITIALIZER
;
721 static pthread_cond_t cvwork
= PTHREAD_COND_INITIALIZER
;
722 static pthread_cond_t cvbarrier
= PTHREAD_COND_INITIALIZER
;
724 static blockhdr_t freeblocks
;
727 enqt(blockhdr_t
*h
, block_t
*b
)
740 block_t
*b
= h
->head
;
750 static void *runstreams(void *arg
);
753 initstreams(int corefd
, int nstreams
, int maxcsize
)
761 nthreads
= sysconf(_SC_NPROCESSORS_ONLN
);
762 if (nstreams
< nthreads
)
766 nblocks
= nthreads
* 2;
768 tinfo
= Zalloc(nthreads
* sizeof (tinfo_t
));
769 endtinfo
= &tinfo
[nthreads
];
772 streams
= Zalloc(nstreams
* sizeof (stream_t
));
773 endstreams
= &streams
[nstreams
];
775 /* init stream block buffers */
776 for (i
= 0; i
< nblocks
; i
++) {
777 b
= Zalloc(sizeof (block_t
));
778 b
->block
= Zalloc(maxcsize
);
779 enqt(&freeblocks
, b
);
782 /* init worker threads */
783 (void) pthread_mutex_lock(&lock
);
786 for (t
= tinfo
; t
!= endtinfo
; t
++) {
787 t
->corefd
= dup(corefd
);
789 nthreads
= t
- tinfo
;
793 if (pthread_create(&t
->tid
, NULL
, runstreams
, t
) != 0)
794 logprint(SC_SL_ERR
| SC_EXIT_ERR
, "pthread_create: %s",
797 (void) pthread_mutex_unlock(&lock
);
805 (void) pthread_mutex_lock(&lock
);
806 for (s
= streams
; s
!= endstreams
; s
++) {
807 while (s
->bound
|| s
->blocks
.head
!= NULL
)
808 (void) pthread_cond_wait(&cvbarrier
, &lock
);
810 (void) pthread_mutex_unlock(&lock
);
818 if (threads_active
) {
820 (void) pthread_mutex_lock(&lock
);
822 (void) pthread_cond_signal(&cvwork
);
823 (void) pthread_mutex_unlock(&lock
);
824 for (t
= tinfo
; t
!= endtinfo
; t
++)
825 (void) pthread_join(t
->tid
, NULL
);
837 (void) pthread_mutex_lock(&lock
);
838 while ((b
= deqh(&freeblocks
)) == NULL
)
839 (void) pthread_cond_wait(&cvfree
, &lock
);
840 (void) pthread_mutex_unlock(&lock
);
844 /* data page offset from page number */
845 #define BTOP(b) ((b) >> dumphdr.dump_pageshift)
846 #define PTOB(p) ((p) << dumphdr.dump_pageshift)
847 #define DATAOFF(p) (corehdr.dump_data + PTOB(p))
849 /* check for coreblksize boundary */
851 isblkbnd(pgcnt_t pgnum
)
853 return (P2PHASE(DATAOFF(pgnum
), coreblksize
) == 0);
862 /*LINTED:E_BAD_PTR_CAST_ALIGN*/
863 pl
= (uint64_t *)(buf
);
864 for (sz
= 0; sz
< pagesize
; sz
+= sizeof (*pl
))
870 volatile uint_t
*hist
;
872 /* write pages to the core file */
874 putpage(int corefd
, char *buf
, pgcnt_t pgnum
, pgcnt_t np
)
876 atomic_inc_uint(&hist
[np
]);
878 Pwrite(corefd
, buf
, PTOB(np
), DATAOFF(pgnum
));
882 * Process one lzjb block.
883 * No object (stream header or page) will be split over a block boundary.
886 lzjbblock(int corefd
, stream_t
*s
, char *block
, size_t blocksz
)
898 if (s
->blkbuf
== NULL
)
899 s
->blkbuf
= Zalloc(coreblksize
);
900 s
->state
= STREAMSTART
;
902 while (in
< blocksz
) {
905 (void) memcpy(&sh
, block
+ in
, sizeof (sh
));
907 if (strcmp(DUMP_STREAM_MAGIC
, sh
.stream_magic
) != 0)
908 logprint(SC_SL_ERR
| SC_EXIT_ERR
,
909 "LZJB STREAMSTART: bad stream header");
910 if (sh
.stream_npages
> datahdr
.dump_maxrange
)
911 logprint(SC_SL_ERR
| SC_EXIT_ERR
,
912 "LZJB STREAMSTART: bad range: %d > %d",
913 sh
.stream_npages
, datahdr
.dump_maxrange
);
914 s
->pagenum
= sh
.stream_pagenum
;
915 s
->npages
= sh
.stream_npages
;
916 s
->curpage
= s
->pagenum
;
919 s
->state
= STREAMPAGES
;
922 (void) memcpy(&sc
, block
+ in
, cs
);
924 csize
= DUMP_GET_CSIZE(sc
);
925 if (csize
> pagesize
)
926 logprint(SC_SL_ERR
| SC_EXIT_ERR
,
927 "LZJB STREAMPAGES: bad csize=%d", csize
);
929 out
= s
->blkbuf
+ PTOB(s
->nout
);
930 dsize
= decompress(block
+ in
, out
, csize
, pagesize
);
932 if (dsize
!= pagesize
)
933 logprint(SC_SL_ERR
| SC_EXIT_ERR
,
934 "LZJB STREAMPAGES: dsize %d != pagesize %d",
938 atomic_inc_64(&saved
);
941 if (s
->nout
== 0 && iszpage(out
)) {
943 atomic_inc_64(&zpages
);
944 } else if (++s
->nout
>= BTOP(coreblksize
) ||
945 isblkbnd(s
->curpage
+ s
->nout
)) {
948 if (++s
->done
>= s
->npages
) {
949 s
->state
= STREAMSTART
;
953 putpage(corefd
, s
->blkbuf
, s
->curpage
, s
->nout
);
955 s
->curpage
= s
->pagenum
+ s
->done
;
962 /* bzlib library reports errors with this callback */
964 bz_internal_error(int errcode
)
966 logprint(SC_SL_ERR
| SC_EXIT_ERR
, "bz_internal_error: err %s\n",
967 BZ2_bzErrorString(errcode
));
971 * Return one object in the stream.
973 * An object (stream header or page) will likely span an input block
974 * of compression data. Return non-zero when an entire object has been
975 * retrieved from the stream.
978 bz2decompress(stream_t
*s
, void *buf
, size_t size
)
982 if (s
->strm
.avail_out
== 0) {
983 s
->strm
.next_out
= buf
;
984 s
->strm
.avail_out
= size
;
986 while (s
->strm
.avail_in
> 0) {
987 rc
= BZ2_bzDecompress(&s
->strm
);
988 if (rc
== BZ_STREAM_END
) {
989 rc
= BZ2_bzDecompressReset(&s
->strm
);
991 logprint(SC_SL_ERR
| SC_EXIT_ERR
,
992 "BZ2_bzDecompressReset: %s",
993 BZ2_bzErrorString(rc
));
997 if (s
->strm
.avail_out
== 0)
1000 return (s
->strm
.avail_out
== 0);
1004 * Process one bzip2 block.
1005 * The interface is documented here:
1006 * http://www.bzip.org/1.0.5/bzip2-manual-1.0.5.html
1009 bz2block(int corefd
, stream_t
*s
, char *block
, size_t blocksz
)
1017 rc
= BZ2_bzDecompressInit(&s
->strm
, 0, 0);
1019 logprint(SC_SL_ERR
| SC_EXIT_ERR
,
1020 "BZ2_bzDecompressInit: %s", BZ2_bzErrorString(rc
));
1021 if (s
->blkbuf
== NULL
)
1022 s
->blkbuf
= Zalloc(coreblksize
);
1023 s
->strm
.avail_out
= 0;
1024 s
->state
= STREAMSTART
;
1026 s
->strm
.next_in
= block
;
1027 s
->strm
.avail_in
= blocksz
;
1029 while (s
->strm
.avail_in
> 0) {
1032 if (!bz2decompress(s
, &s
->sh
, sizeof (s
->sh
)))
1034 if (strcmp(DUMP_STREAM_MAGIC
, s
->sh
.stream_magic
) != 0)
1035 logprint(SC_SL_ERR
| SC_EXIT_ERR
,
1036 "BZ2 STREAMSTART: bad stream header");
1037 if (s
->sh
.stream_npages
> datahdr
.dump_maxrange
)
1038 logprint(SC_SL_ERR
| SC_EXIT_ERR
,
1039 "BZ2 STREAMSTART: bad range: %d > %d",
1040 s
->sh
.stream_npages
, datahdr
.dump_maxrange
);
1041 s
->pagenum
= s
->sh
.stream_pagenum
;
1042 s
->npages
= s
->sh
.stream_npages
;
1043 s
->curpage
= s
->pagenum
;
1046 s
->state
= STREAMPAGES
;
1049 out
= s
->blkbuf
+ PTOB(s
->nout
);
1050 if (!bz2decompress(s
, out
, pagesize
))
1053 atomic_inc_64(&saved
);
1056 if (s
->nout
== 0 && iszpage(out
)) {
1058 atomic_inc_64(&zpages
);
1059 } else if (++s
->nout
>= BTOP(coreblksize
) ||
1060 isblkbnd(s
->curpage
+ s
->nout
)) {
1063 if (++s
->done
>= s
->npages
) {
1064 s
->state
= STREAMSTART
;
1068 putpage(corefd
, s
->blkbuf
, s
->curpage
, s
->nout
);
1070 s
->curpage
= s
->pagenum
+ s
->done
;
1077 /* report progress */
1086 percent
= saved
* 100LL / corehdr
.dump_npages
;
1087 if (percent
> percent_done
) {
1088 sec
= (gethrtime() - startts
) / 1000 / 1000 / 1000;
1089 (void) printf("\r%2d:%02d %3d%% done", sec
/ 60, sec
% 60,
1091 (void) fflush(stdout
);
1092 percent_done
= percent
;
1098 runstreams(void *arg
)
1105 (void) pthread_mutex_lock(&lock
);
1106 while (!threads_stop
) {
1108 for (s
= streams
; s
!= endstreams
; s
++) {
1109 if (s
->bound
|| s
->blocks
.head
== NULL
)
1113 (void) pthread_cond_signal(&cvwork
);
1114 while (s
->blocks
.head
!= NULL
) {
1115 b
= deqh(&s
->blocks
);
1116 (void) pthread_mutex_unlock(&lock
);
1118 if (datahdr
.dump_clevel
< DUMP_CLEVEL_BZIP2
)
1119 lzjbblock(t
->corefd
, s
, b
->block
,
1122 bz2block(t
->corefd
, s
, b
->block
,
1125 (void) pthread_mutex_lock(&lock
);
1126 enqt(&freeblocks
, b
);
1127 (void) pthread_cond_signal(&cvfree
);
1132 (void) pthread_cond_signal(&cvbarrier
);
1134 if (!bound
&& !threads_stop
)
1135 (void) pthread_cond_wait(&cvwork
, &lock
);
1137 (void) close(t
->corefd
);
1138 (void) pthread_cond_signal(&cvwork
);
1139 (void) pthread_mutex_unlock(&lock
);
1144 * Process compressed pages.
1146 * The old format, now called single-threaded lzjb, is a 32-bit size
1147 * word followed by 'size' bytes of lzjb compression data for one
1148 * page. The new format extends this by storing a 12-bit "tag" in the
1149 * upper bits of the size word. When the size word is pagesize or
1150 * less, it is assumed to be one lzjb page. When the size word is
1151 * greater than pagesize, it is assumed to be a "stream block",
1152 * belonging to up to 4095 streams. In practice, the number of streams
1153 * is set to one less than the number of CPUs running at crash
1154 * time. One CPU processes the crash dump, the remaining CPUs
1155 * separately process groups of data pages.
1157 * savecore creates a thread per stream, but never more threads than
1158 * the number of CPUs running savecore. This is because savecore can
1159 * be processing a crash file from a remote machine, which may have
1162 * When the kernel uses parallel lzjb or parallel bzip2, we expect a
1163 * series of 128KB blocks of compression data. In this case, each
1164 * block has a "tag", in the range 1-4095. Each block is handed off to
1165 * to the threads running "runstreams". The dump format is either lzjb
1166 * or bzip2, never a mixture. These threads, in turn, process the
1167 * compression data for groups of pages. Groups of pages are delimited
1168 * by a "stream header", which indicates a starting pfn and number of
1169 * pages. When a stream block has been read, the condition variable
1170 * "cvwork" is signalled, which causes one of the avaiable threads to
1171 * wake up and process the stream.
1173 * In the parallel case there will be streams blocks encoding all data
1174 * pages. The stream of blocks is terminated by a zero size
1175 * word. There can be a few lzjb pages tacked on the end, depending on
1176 * the architecture. The sbarrier function ensures that all stream
1177 * blocks have been processed so that the page number for the few
1178 * single pages at the end can be known.
1181 decompress_pages(int corefd
)
1186 pgcnt_t curpage
= 0;
1189 FILE *tracef
= NULL
;
1192 size_t insz
= FBUFSIZE
;
1193 char *inbuf
= Zalloc(insz
);
1196 int nstreams
= datahdr
.dump_nstreams
;
1197 int maxcsize
= datahdr
.dump_maxcsize
;
1198 int nout
= 0, tag
, doflush
;
1200 dumpf
= fdopen(dup(dumpfd
), "rb");
1202 logprint(SC_SL_ERR
| SC_EXIT_ERR
, "fdopen: %s",
1205 (void) setvbuf(dumpf
, inbuf
, _IOFBF
, insz
);
1206 Fseek(dumphdr
.dump_data
, dumpf
);
1208 /*LINTED: E_CONSTANT_CONDITION*/
1212 * The csize word delimits stream blocks.
1213 * See dumphdr.h for a description.
1215 Fread(&dcsize
, sizeof (dcsize
), dumpf
);
1217 tag
= DUMP_GET_TAG(dcsize
);
1218 csize
= DUMP_GET_CSIZE(dcsize
);
1220 if (tag
!= 0) { /* a stream block */
1223 logprint(SC_SL_ERR
| SC_EXIT_ERR
,
1224 "starting data header is missing");
1227 logprint(SC_SL_ERR
| SC_EXIT_ERR
,
1228 "stream tag %d not in range 1..%d",
1231 if (csize
> maxcsize
)
1232 logprint(SC_SL_ERR
| SC_EXIT_ERR
,
1233 "block size 0x%x > max csize 0x%x",
1236 if (streams
== NULL
)
1237 initstreams(corefd
, nstreams
, maxcsize
);
1238 s
= &streams
[tag
- 1];
1243 Fread(b
->block
, csize
, dumpf
);
1245 (void) pthread_mutex_lock(&lock
);
1246 enqt(&s
->blocks
, b
);
1248 (void) pthread_cond_signal(&cvwork
);
1249 (void) pthread_mutex_unlock(&lock
);
1251 } else if (csize
> 0) { /* one lzjb page */
1253 if (csize
> pagesize
)
1254 logprint(SC_SL_ERR
| SC_EXIT_ERR
,
1255 "csize 0x%x > pagesize 0x%x",
1259 cpage
= Zalloc(pagesize
);
1260 if (dpage
== NULL
) {
1261 dpage
= Zalloc(coreblksize
);
1265 Fread(cpage
, csize
, dumpf
);
1267 out
= dpage
+ PTOB(nout
);
1268 dsize
= decompress(cpage
, out
, csize
, pagesize
);
1270 if (dsize
!= pagesize
)
1271 logprint(SC_SL_ERR
| SC_EXIT_ERR
,
1272 "dsize 0x%x != pagesize 0x%x",
1276 * wait for streams to flush so that 'saved' is correct
1285 atomic_inc_64(&saved
);
1287 if (nout
== 0 && iszpage(dpage
)) {
1289 atomic_inc_64(&zpages
);
1290 } else if (++nout
>= BTOP(coreblksize
) ||
1291 isblkbnd(curpage
+ nout
) ||
1292 saved
>= dumphdr
.dump_npages
) {
1297 putpage(corefd
, dpage
, curpage
, nout
);
1304 * Non-streams lzjb does not use blocks. Stop
1305 * here if all the pages have been decompressed.
1307 if (saved
>= dumphdr
.dump_npages
)
1311 break; /* end of data */
1317 (void) fclose(tracef
);
1318 (void) fclose(dumpf
);
1330 build_corefile(const char *namelist
, const char *corefile
)
1332 size_t pfn_table_size
= dumphdr
.dump_npages
* sizeof (pfn_t
);
1333 size_t ksyms_size
= dumphdr
.dump_ksyms_size
;
1334 size_t ksyms_csize
= dumphdr
.dump_ksyms_csize
;
1336 char *ksyms_base
= Zalloc(ksyms_size
);
1337 char *ksyms_cbase
= Zalloc(ksyms_csize
);
1340 int corefd
= Open(corefile
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0644);
1341 int namefd
= Open(namelist
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0644);
1343 (void) printf("Constructing namelist %s/%s\n", savedir
, namelist
);
1346 * Determine the optimum write size for the core file
1348 Fstat(corefd
, &st
, corefile
);
1351 (void) printf("%s: %ld block size\n", corefile
,
1352 (long)st
.st_blksize
);
1353 coreblksize
= st
.st_blksize
;
1354 if (coreblksize
< MINCOREBLKSIZE
|| !ISP2(coreblksize
))
1355 coreblksize
= MINCOREBLKSIZE
;
1357 hist
= Zalloc((sizeof (uint64_t) * BTOP(coreblksize
)) + 1);
1360 * This dump file is now uncompressed
1362 corehdr
.dump_flags
&= ~DF_COMPRESSED
;
1365 * Read in the compressed symbol table, copy it to corefile,
1366 * decompress it, and write the result to namelist.
1368 corehdr
.dump_ksyms
= pagesize
;
1369 Pread(dumpfd
, ksyms_cbase
, ksyms_csize
, dumphdr
.dump_ksyms
);
1370 Pwrite(corefd
, ksyms_cbase
, ksyms_csize
, corehdr
.dump_ksyms
);
1372 ksyms_dsize
= decompress(ksyms_cbase
, ksyms_base
, ksyms_csize
,
1374 if (ksyms_dsize
!= ksyms_size
)
1375 logprint(SC_SL_WARN
,
1376 "bad data in symbol table, %lu of %lu bytes saved",
1377 ksyms_dsize
, ksyms_size
);
1379 Pwrite(namefd
, ksyms_base
, ksyms_size
, 0);
1380 (void) close(namefd
);
1384 (void) printf("Constructing corefile %s/%s\n", savedir
, corefile
);
1387 * Read in and write out the pfn table.
1389 pfn_table
= Zalloc(pfn_table_size
);
1390 corehdr
.dump_pfn
= corehdr
.dump_ksyms
+ roundup(ksyms_size
, pagesize
);
1391 Pread(dumpfd
, pfn_table
, pfn_table_size
, dumphdr
.dump_pfn
);
1392 Pwrite(corefd
, pfn_table
, pfn_table_size
, corehdr
.dump_pfn
);
1395 * Convert the raw translation data into a hashed dump map.
1397 corehdr
.dump_map
= corehdr
.dump_pfn
+ roundup(pfn_table_size
, pagesize
);
1398 build_dump_map(corefd
, pfn_table
);
1402 * Decompress the pages
1404 decompress_pages(corefd
);
1405 (void) printf(": %ld of %ld pages saved\n", (pgcnt_t
)saved
,
1406 dumphdr
.dump_npages
);
1409 (void) printf("%ld (%ld%%) zero pages were not written\n",
1410 (pgcnt_t
)zpages
, (pgcnt_t
)zpages
* 100 /
1411 dumphdr
.dump_npages
);
1413 if (saved
!= dumphdr
.dump_npages
)
1414 logprint(SC_SL_WARN
, "bad data after page %ld", saved
);
1417 * Write out the modified dump headers.
1419 Pwrite(corefd
, &corehdr
, sizeof (corehdr
), 0);
1421 Pwrite(dumpfd
, &dumphdr
, sizeof (dumphdr
), endoff
);
1423 (void) close(corefd
);
1427 * When the system panics, the kernel saves all undelivered messages (messages
1428 * that never made it out to syslogd(1M)) in the dump. At a mimimum, the
1429 * panic message itself will always fall into this category. Upon reboot,
1430 * the syslog startup script runs savecore -m to recover these messages.
1432 * To do this, we read the unsent messages from the dump and send them to
1433 * /dev/conslog on priority band 1. This has the effect of prepending them
1434 * to any already-accumulated messages in the console backlog, thus preserving
1435 * temporal ordering across the reboot.
1437 * Note: since savecore -m is used *only* for this purpose, it does *not*
1438 * attempt to save the crash dump. The dump will be saved later, after
1439 * syslogd(1M) starts, by the savecore startup script.
1444 offset_t dumpoff
= -(DUMP_OFFSET
+ DUMP_LOGSIZE
);
1448 struct strbuf ctl
, dat
;
1451 logfd
= Open("/dev/conslog", O_WRONLY
, 0644);
1452 dumpfd
= Open(dumpfile
, O_RDWR
| O_DSYNC
, 0644);
1453 dumpoff
= llseek(dumpfd
, dumpoff
, SEEK_END
) & -DUMP_OFFSET
;
1455 ctl
.buf
= (void *)&lc
;
1456 ctl
.len
= sizeof (log_ctl_t
);
1458 dat
.buf
= Zalloc(DUMP_LOGSIZE
);
1463 Pread(dumpfd
, &ld
, sizeof (log_dump_t
), dumpoff
);
1464 dumpoff
+= sizeof (log_dump_t
);
1465 dat
.len
= ld
.ld_msgsize
;
1467 if (ld
.ld_magic
== 0)
1470 if (ld
.ld_magic
!= LOG_MAGIC
)
1471 logprint(SC_SL_ERR
| SC_IF_VERBOSE
| SC_EXIT_ERR
,
1472 "bad magic %x", ld
.ld_magic
);
1474 if (dat
.len
>= DUMP_LOGSIZE
)
1475 logprint(SC_SL_ERR
| SC_IF_VERBOSE
| SC_EXIT_ERR
,
1476 "bad size %d", ld
.ld_msgsize
);
1478 Pread(dumpfd
, ctl
.buf
, ctl
.len
, dumpoff
);
1481 if (ld
.ld_csum
!= checksum32(ctl
.buf
, ctl
.len
))
1482 logprint(SC_SL_ERR
| SC_IF_VERBOSE
| SC_EXIT_OK
,
1483 "bad log_ctl checksum");
1485 lc
.flags
|= SL_LOGONLY
;
1487 Pread(dumpfd
, dat
.buf
, dat
.len
, dumpoff
);
1490 if (ld
.ld_msum
!= checksum32(dat
.buf
, dat
.len
))
1491 logprint(SC_SL_ERR
| SC_IF_VERBOSE
| SC_EXIT_OK
,
1492 "bad message checksum");
1494 if (putpmsg(logfd
, &ctl
, &dat
, 1, MSG_BAND
) == -1)
1495 logprint(SC_SL_ERR
| SC_EXIT_ERR
, "putpmsg: %s",
1498 ld
.ld_magic
= 0; /* clear magic so we never save twice */
1499 Pwrite(dumpfd
, &ld
, sizeof (log_dump_t
), ldoff
);
1505 getbounds(const char *f
)
1508 const char *p
= strrchr(f
, '/');
1510 if (p
== NULL
|| strncmp(p
, "vmdump", 6) != 0)
1511 p
= strstr(f
, "vmdump");
1513 if (p
!= NULL
&& *p
== '/')
1516 (void) sscanf(p
? p
: f
, "vmdump.%ld", &b
);
1522 stack_retrieve(char *stack
)
1525 offset_t dumpoff
= -(DUMP_OFFSET
+ DUMP_LOGSIZE
+
1527 dumpoff
-= DUMP_SUMMARYSIZE
;
1529 dumpfd
= Open(dumpfile
, O_RDWR
| O_DSYNC
, 0644);
1530 dumpoff
= llseek(dumpfd
, dumpoff
, SEEK_END
) & -DUMP_OFFSET
;
1532 Pread(dumpfd
, &sd
, sizeof (summary_dump_t
), dumpoff
);
1533 dumpoff
+= sizeof (summary_dump_t
);
1535 if (sd
.sd_magic
== 0) {
1540 if (sd
.sd_magic
!= SUMMARY_MAGIC
) {
1542 logprint(SC_SL_NONE
| SC_IF_VERBOSE
,
1543 "bad summary magic %x", sd
.sd_magic
);
1546 Pread(dumpfd
, stack
, STACK_BUF_SIZE
, dumpoff
);
1547 if (sd
.sd_ssum
!= checksum32(stack
, STACK_BUF_SIZE
))
1548 logprint(SC_SL_NONE
| SC_IF_VERBOSE
, "bad stack checksum");
1552 raise_event(enum sc_event_type evidx
, char *warn_string
)
1554 uint32_t pl
= sc_event
[evidx
].sce_payload
;
1555 char panic_stack
[STACK_BUF_SIZE
];
1556 nvlist_t
*attr
= NULL
;
1557 char uuidbuf
[36 + 1];
1560 if (nvlist_alloc(&attr
, NV_UNIQUE_NAME
, 0) != 0)
1561 goto publish
; /* try to send payload-free event */
1563 if (pl
& SC_PAYLOAD_SAVEDIR
&& savedir
!= NULL
)
1564 err
|= nvlist_add_string(attr
, "dumpdir", savedir
);
1566 if (pl
& SC_PAYLOAD_INSTANCE
&& bounds
!= -1)
1567 err
|= nvlist_add_int64(attr
, "instance", bounds
);
1569 if (pl
& SC_PAYLOAD_ISCOMPRESSED
) {
1570 err
|= nvlist_add_boolean_value(attr
, "compressed",
1571 csave
? B_TRUE
: B_FALSE
);
1574 if (pl
& SC_PAYLOAD_DUMPADM_EN
) {
1575 char *disabled
= defread("DUMPADM_ENABLE=no");
1577 err
|= nvlist_add_boolean_value(attr
, "savecore-enabled",
1578 disabled
? B_FALSE
: B_TRUE
);
1581 if (pl
& SC_PAYLOAD_IMAGEUUID
) {
1582 (void) strncpy(uuidbuf
, corehdr
.dump_uuid
, 36);
1584 err
|= nvlist_add_string(attr
, "os-instance-uuid", uuidbuf
);
1587 if (pl
& SC_PAYLOAD_CRASHTIME
) {
1588 err
|= nvlist_add_int64(attr
, "crashtime",
1589 (int64_t)corehdr
.dump_crashtime
);
1592 if (pl
& SC_PAYLOAD_PANICSTR
&& corehdr
.dump_panicstring
[0] != '\0') {
1593 err
|= nvlist_add_string(attr
, "panicstr",
1594 corehdr
.dump_panicstring
);
1597 if (pl
& SC_PAYLOAD_PANICSTACK
) {
1598 stack_retrieve(panic_stack
);
1600 if (panic_stack
[0] != '\0') {
1602 * The summary page may not be present if the dump
1603 * was previously recorded compressed.
1605 (void) nvlist_add_string(attr
, "panicstack",
1610 /* add warning string if this is an ireport for dump failure */
1611 if (pl
& SC_PAYLOAD_FAILREASON
&& warn_string
!= NULL
)
1612 (void) nvlist_add_string(attr
, "failure-reason", warn_string
);
1614 if (pl
& SC_PAYLOAD_DUMPCOMPLETE
)
1615 err
|= nvlist_add_boolean_value(attr
, "dump-incomplete",
1616 dump_incomplete
? B_TRUE
: B_FALSE
);
1618 if (pl
& SC_PAYLOAD_FM_PANIC
) {
1619 err
|= nvlist_add_boolean_value(attr
, "fm-panic",
1620 fm_panic
? B_TRUE
: B_FALSE
);
1623 if (pl
& SC_PAYLOAD_JUSTCHECKING
) {
1624 err
|= nvlist_add_boolean_value(attr
, "will-attempt-savecore",
1625 cflag
? B_FALSE
: B_TRUE
);
1629 logprint(SC_SL_WARN
, "Errors while constructing '%s' "
1630 "event payload; will try to publish anyway.");
1632 if (fmev_rspublish_nvl(FMEV_RULESET_ON_SUNOS
,
1633 "panic", sc_event
[evidx
].sce_subclass
, FMEV_HIPRI
,
1634 attr
) != FMEV_SUCCESS
) {
1635 logprint(SC_SL_ERR
, "failed to publish '%s' event: %s",
1636 sc_event
[evidx
].sce_subclass
, fmev_strerror(fmev_errno
));
1644 main(int argc
, char *argv
[])
1649 long filebounds
= -1;
1650 char namelist
[30], corefile
[30], boundstr
[30];
1653 startts
= gethrtime();
1655 (void) getrlimit(RLIMIT_NOFILE
, &rl
);
1656 rl
.rlim_cur
= rl
.rlim_max
;
1657 (void) setrlimit(RLIMIT_NOFILE
, &rl
);
1659 openlog(progname
, LOG_ODELAY
, LOG_AUTH
);
1661 (void) defopen("/etc/dumpadm.conf");
1662 savedir
= defread("DUMPADM_SAVDIR=");
1663 if (savedir
!= NULL
)
1664 savedir
= strdup(savedir
);
1666 while ((c
= getopt(argc
, argv
, "Lvcdmf:")) != EOF
) {
1678 disregard_valid_flag
++;
1685 filebounds
= getbounds(dumpfile
);
1693 * If doing something other than extracting an existing dump (i.e.
1694 * dumpfile has been provided as an option), the user must be root.
1696 if (geteuid() != 0 && dumpfile
== NULL
) {
1697 (void) fprintf(stderr
, "%s: %s %s\n", progname
,
1698 gettext("you must be root to use"), progname
);
1702 interactive
= isatty(STDOUT_FILENO
);
1704 if (cflag
&& livedump
)
1707 if (dumpfile
== NULL
|| livedump
)
1708 dumpfd
= Open("/dev/dump", O_RDONLY
, 0444);
1710 if (dumpfile
== NULL
) {
1711 dumpfile
= Zalloc(MAXPATHLEN
);
1712 if (ioctl(dumpfd
, DIOCGETDEV
, dumpfile
) == -1)
1713 logprint(SC_SL_NONE
| SC_IF_ISATTY
| SC_EXIT_ERR
,
1714 "no dump device configured");
1718 return (message_save());
1720 if (optind
== argc
- 1)
1721 savedir
= argv
[optind
];
1723 if (savedir
== NULL
|| optind
< argc
- 1)
1726 if (livedump
&& ioctl(dumpfd
, DIOCDUMP
, NULL
) == -1)
1727 logprint(SC_SL_NONE
| SC_EXIT_ERR
,
1728 "dedicated dump device required");
1730 (void) close(dumpfd
);
1733 Stat(dumpfile
, &st
);
1735 filemode
= S_ISREG(st
.st_mode
);
1737 if (!filemode
&& defread("DUMPADM_CSAVE=off") == NULL
)
1743 * We want this message to go to the log file, but not the console.
1744 * There's no good way to do that with the existing syslog facility.
1745 * We could extend it to handle this, but there doesn't seem to be
1746 * a general need for it, so we isolate the complexity here instead.
1748 if (dumphdr
.dump_panicstring
[0] != '\0') {
1749 int logfd
= Open("/dev/conslog", O_WRONLY
, 0644);
1751 struct strbuf ctl
, dat
;
1752 char msg
[DUMP_PANICSIZE
+ 100];
1753 char fmt
[] = "reboot after panic: %s";
1756 STRLOG_MAKE_MSGID(fmt
, msgid
);
1758 /* LINTED: E_SEC_SPRINTF_UNBOUNDED_COPY */
1759 (void) sprintf(msg
, "%s: [ID %u FACILITY_AND_PRIORITY] ",
1761 /* LINTED: E_SEC_PRINTF_VAR_FMT */
1762 (void) sprintf(msg
+ strlen(msg
), fmt
,
1763 dumphdr
.dump_panicstring
);
1765 lc
.pri
= LOG_AUTH
| LOG_ERR
;
1766 lc
.flags
= SL_CONSOLE
| SL_LOGONLY
;
1769 ctl
.buf
= (void *)&lc
;
1770 ctl
.len
= sizeof (log_ctl_t
);
1772 dat
.buf
= (void *)msg
;
1773 dat
.len
= strlen(msg
) + 1;
1775 (void) putmsg(logfd
, &ctl
, &dat
, 0);
1776 (void) close(logfd
);
1779 if ((dumphdr
.dump_flags
& DF_COMPLETE
) == 0) {
1780 logprint(SC_SL_WARN
, "incomplete dump on dump device");
1781 dump_incomplete
= B_TRUE
;
1784 if (dumphdr
.dump_fm_panic
)
1788 * We have a valid dump on a dump device and know as much about
1789 * it as we're going to at this stage. Raise an event for
1790 * logging and so that FMA can open a case for this panic.
1791 * Avoid this step for FMA-initiated panics - FMA will replay
1792 * ereports off the dump device independently of savecore and
1793 * will make a diagnosis, so we don't want to open two cases
1794 * for the same event. Also avoid raising an event for a
1795 * livedump, or when we inflating a compressed dump.
1797 if (!fm_panic
&& !livedump
&& !filemode
)
1798 raise_event(SC_EVENT_DUMP_PENDING
, NULL
);
1800 logprint(SC_SL_WARN
, "System dump time: %s",
1801 ctime(&dumphdr
.dump_crashtime
));
1804 * Option -c is designed for use from svc-dumpadm where we know
1805 * that dumpadm -n is in effect but run savecore -c just to
1806 * get the above dump_pending_on_device event raised. If it is run
1807 * interactively then just print further panic details.
1810 char *disabled
= defread("DUMPADM_ENABLE=no");
1811 int lvl
= interactive
? SC_SL_WARN
: SC_SL_ERR
;
1812 int ec
= fm_panic
? SC_EXIT_FM
: SC_EXIT_PEND
;
1815 "Panic crashdump pending on dump device%s "
1816 "run savecore(1M) manually to extract. "
1818 disabled
? " but dumpadm -n in effect;" : ";",
1820 fm_panic
? "(fault-management initiated)" : "");
1824 if (chdir(savedir
) == -1)
1825 logprint(SC_SL_ERR
| SC_EXIT_ERR
, "chdir(\"%s\"): %s",
1826 savedir
, strerror(errno
));
1831 bounds
= read_number_from_file("bounds", 0);
1833 bounds
= filebounds
;
1836 size_t metrics_size
= datahdr
.dump_metrics
;
1838 (void) sprintf(corefile
, "vmdump.%ld", bounds
);
1840 datahdr
.dump_metrics
= 0;
1843 "Saving compressed system crash dump in %s/%s",
1846 copy_crashfile(corefile
);
1849 * Raise a fault management event that indicates the system
1850 * has panicked. We know a reasonable amount about the
1851 * condition at this time, but the dump is still compressed.
1853 if (!livedump
&& !fm_panic
)
1854 raise_event(SC_EVENT_DUMP_AVAILABLE
, NULL
);
1856 if (metrics_size
> 0) {
1857 int sec
= (gethrtime() - startts
) / 1000 / 1000 / 1000;
1858 FILE *mfile
= fopen(METRICSFILE
, "a");
1859 char *metrics
= Zalloc(metrics_size
+ 1);
1861 Pread(dumpfd
, metrics
, metrics_size
, endoff
+
1862 sizeof (dumphdr
) + sizeof (datahdr
));
1867 if (mfile
== NULL
) {
1868 logprint(SC_SL_WARN
,
1869 "Can't create %s:\n%s",
1870 METRICSFILE
, metrics
);
1872 (void) fprintf(mfile
, "[[[[,,,");
1873 for (i
= 0; i
< argc
; i
++)
1874 (void) fprintf(mfile
, "%s ", argv
[i
]);
1875 (void) fprintf(mfile
, "\n");
1876 (void) fprintf(mfile
, ",,,%s %s %s %s %s\n",
1877 dumphdr
.dump_utsname
.sysname
,
1878 dumphdr
.dump_utsname
.nodename
,
1879 dumphdr
.dump_utsname
.release
,
1880 dumphdr
.dump_utsname
.version
,
1881 dumphdr
.dump_utsname
.machine
);
1882 (void) fprintf(mfile
, ",,,%s dump time %s\n",
1883 dumphdr
.dump_flags
& DF_LIVE
? "Live" :
1884 "Crash", ctime(&dumphdr
.dump_crashtime
));
1885 (void) fprintf(mfile
, ",,,%s/%s\n", savedir
,
1887 (void) fprintf(mfile
, "Metrics:\n%s\n",
1889 (void) fprintf(mfile
, "Copy pages,%ld\n",
1890 dumphdr
. dump_npages
);
1891 (void) fprintf(mfile
, "Copy time,%d\n", sec
);
1892 (void) fprintf(mfile
, "Copy pages/sec,%ld\n",
1893 dumphdr
.dump_npages
/ sec
);
1894 (void) fprintf(mfile
, "]]]]\n");
1895 (void) fclose(mfile
);
1901 "Decompress the crash dump with "
1902 "\n'savecore -vf %s/%s'",
1906 (void) sprintf(namelist
, "unix.%ld", bounds
);
1907 (void) sprintf(corefile
, "vmcore.%ld", bounds
);
1909 if (interactive
&& filebounds
>= 0 && access(corefile
, F_OK
)
1911 logprint(SC_SL_NONE
| SC_EXIT_ERR
,
1912 "%s already exists: remove with "
1913 "'rm -f %s/{unix,vmcore}.%ld'",
1914 corefile
, savedir
, bounds
);
1917 "saving system crash dump in %s/{unix,vmcore}.%ld",
1920 build_corefile(namelist
, corefile
);
1922 if (!livedump
&& !filemode
&& !fm_panic
)
1923 raise_event(SC_EVENT_DUMP_AVAILABLE
, NULL
);
1925 if (access(METRICSFILE
, F_OK
) == 0) {
1926 int sec
= (gethrtime() - startts
) / 1000 / 1000 / 1000;
1927 FILE *mfile
= fopen(METRICSFILE
, "a");
1932 (void) fprintf(mfile
, "[[[[,,,");
1933 for (i
= 0; i
< argc
; i
++)
1934 (void) fprintf(mfile
, "%s ", argv
[i
]);
1935 (void) fprintf(mfile
, "\n");
1936 (void) fprintf(mfile
, ",,,%s/%s\n", savedir
, corefile
);
1937 (void) fprintf(mfile
, ",,,%s %s %s %s %s\n",
1938 dumphdr
.dump_utsname
.sysname
,
1939 dumphdr
.dump_utsname
.nodename
,
1940 dumphdr
.dump_utsname
.release
,
1941 dumphdr
.dump_utsname
.version
,
1942 dumphdr
.dump_utsname
.machine
);
1943 (void) fprintf(mfile
, "Uncompress pages,%"PRIu64
"\n",
1945 (void) fprintf(mfile
, "Uncompress time,%d\n", sec
);
1946 (void) fprintf(mfile
, "Uncompress pages/sec,%"
1947 PRIu64
"\n", saved
/ sec
);
1948 (void) fprintf(mfile
, "]]]]\n");
1949 (void) fclose(mfile
);
1953 if (filebounds
< 0) {
1954 (void) sprintf(boundstr
, "%ld\n", bounds
+ 1);
1955 bfd
= Open("bounds", O_WRONLY
| O_CREAT
| O_TRUNC
, 0644);
1956 Pwrite(bfd
, boundstr
, strlen(boundstr
), 0);
1961 int sec
= (gethrtime() - startts
) / 1000 / 1000 / 1000;
1963 (void) printf("%d:%02d dump %s is done\n",
1965 csave
? "copy" : "decompress");
1968 if (verbose
> 1 && hist
!= NULL
) {
1971 for (i
= 1, nw
= 0; i
<= BTOP(coreblksize
); ++i
)
1973 (void) printf("pages count %%\n");
1974 for (i
= 0; i
<= BTOP(coreblksize
); ++i
) {
1977 (void) printf("%3d %5u %6.2f\n",
1978 i
, hist
[i
], 100.0 * hist
[i
] * i
/ nw
);
1982 (void) close(dumpfd
);