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