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