xref: /illumos-gate/usr/src/uts/common/os/dumpsubr.c (revision ae115bc77f6fcde83175c75b4206dc2e50747966)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/types.h>
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/vm.h>
32 #include <sys/proc.h>
33 #include <sys/file.h>
34 #include <sys/conf.h>
35 #include <sys/kmem.h>
36 #include <sys/mem.h>
37 #include <sys/mman.h>
38 #include <sys/vnode.h>
39 #include <sys/errno.h>
40 #include <sys/memlist.h>
41 #include <sys/dumphdr.h>
42 #include <sys/dumpadm.h>
43 #include <sys/ksyms.h>
44 #include <sys/compress.h>
45 #include <sys/stream.h>
46 #include <sys/strsun.h>
47 #include <sys/cmn_err.h>
48 #include <sys/bitmap.h>
49 #include <sys/modctl.h>
50 #include <sys/utsname.h>
51 #include <sys/systeminfo.h>
52 #include <sys/vmem.h>
53 #include <sys/log.h>
54 #include <sys/var.h>
55 #include <sys/debug.h>
56 #include <sys/sunddi.h>
57 #include <fs/fs_subr.h>
58 #include <sys/fs/snode.h>
59 #include <sys/ontrap.h>
60 #include <sys/panic.h>
61 #include <sys/dkio.h>
62 #include <sys/vtoc.h>
63 #include <sys/errorq.h>
64 #include <sys/fm/util.h>
65 
66 #include <vm/hat.h>
67 #include <vm/as.h>
68 #include <vm/page.h>
69 #include <vm/seg.h>
70 #include <vm/seg_kmem.h>
71 
72 kmutex_t	dump_lock;	/* lock for dump configuration */
73 dumphdr_t	*dumphdr;	/* dump header */
74 int		dump_conflags = DUMP_KERNEL; /* dump configuration flags */
75 vnode_t		*dumpvp;	/* dump device vnode pointer */
76 u_offset_t	dumpvp_size;	/* size of dump device, in bytes */
77 static u_offset_t dumpvp_limit;	/* maximum write offset */
78 char		*dumppath;	/* pathname of dump device */
79 int		dump_timeout = 120; /* timeout for dumping page during panic */
80 int		dump_timeleft;	/* portion of dump_timeout remaining */
81 
82 #ifdef DEBUG
83 int		dumpfaildebug = 1;	/* enter debugger if dump fails */
84 #else
85 int		dumpfaildebug = 0;
86 #endif
87 
88 static ulong_t	*dump_bitmap;	/* bitmap for marking pages to dump */
89 static pgcnt_t	dump_bitmapsize; /* size of bitmap */
90 static pid_t	*dump_pids;	/* list of process IDs at dump time */
91 static int	dump_ioerr;	/* dump i/o error */
92 static offset_t	dumpvp_off;	/* current dump device offset */
93 static char	*dump_cmap;	/* VA for dump compression mapping */
94 static char	*dumpbuf_cur, *dumpbuf_start, *dumpbuf_end;
95 static char	*dump_cbuf;	/* compression buffer */
96 static char	*dump_uebuf;	/* memory error detection buffer */
97 static size_t	dumpbuf_size;	/* size of dumpbuf in bytes */
98 static size_t	dumpbuf_limit = 1UL << 23;	/* 8MB */
99 static size_t	dump_iosize;	/* device's best transfer size, if any */
100 static uint64_t	dumpbuf_thresh = 1ULL << 30;	/* 1GB */
101 static ulong_t	dumpbuf_mult = 8;
102 
103 /*
104  * The dump i/o buffer must be at least one page, at most xfer_size bytes, and
105  * should scale with physmem in between.  The transfer size passed in will
106  * either represent a global default (maxphys) or the best size for the device.
107  * Once the physical memory size exceeds dumpbuf_thresh (1GB by default), we
108  * increase the percentage of physical memory that dumpbuf can consume by a
109  * factor of dumpbuf_mult (8 by default) to improve large memory performance.
110  * The size of the dumpbuf i/o buffer is limited by dumpbuf_limit (8MB by
111  * default) because the dump performance saturates beyond a certain size.
112  */
113 static size_t
114 dumpbuf_iosize(size_t xfer_size)
115 {
116 	pgcnt_t scale = physmem;
117 	size_t iosize;
118 
119 	if (scale >= dumpbuf_thresh / PAGESIZE) {
120 		scale *= dumpbuf_mult; /* increase scaling factor */
121 		iosize = MIN(xfer_size, scale) & PAGEMASK;
122 		if (dumpbuf_limit && iosize > dumpbuf_limit)
123 			iosize = MAX(PAGESIZE, dumpbuf_limit & PAGEMASK);
124 	} else
125 		iosize = MAX(PAGESIZE, MIN(xfer_size, scale) & PAGEMASK);
126 
127 	return (iosize);
128 }
129 
130 static void
131 dumpbuf_resize(void)
132 {
133 	char *old_buf = dumpbuf_start;
134 	size_t old_size = dumpbuf_size;
135 	char *new_buf;
136 	size_t new_size;
137 
138 	ASSERT(MUTEX_HELD(&dump_lock));
139 
140 	if ((new_size = dumpbuf_iosize(MAX(dump_iosize, maxphys))) <= old_size)
141 		return; /* no need to reallocate buffer */
142 
143 	new_buf = kmem_alloc(new_size, KM_SLEEP);
144 	dumpbuf_size = new_size;
145 	dumpbuf_start = new_buf;
146 	dumpbuf_end = new_buf + new_size;
147 	kmem_free(old_buf, old_size);
148 }
149 
150 static void
151 dumphdr_init(void)
152 {
153 	pgcnt_t npages = 0;
154 	struct memlist *mp;
155 
156 	ASSERT(MUTEX_HELD(&dump_lock));
157 
158 	if (dumphdr == NULL) {
159 		dumphdr = kmem_zalloc(sizeof (dumphdr_t), KM_SLEEP);
160 		dumphdr->dump_magic = DUMP_MAGIC;
161 		dumphdr->dump_version = DUMP_VERSION;
162 		dumphdr->dump_wordsize = DUMP_WORDSIZE;
163 		dumphdr->dump_pageshift = PAGESHIFT;
164 		dumphdr->dump_pagesize = PAGESIZE;
165 		dumphdr->dump_utsname = utsname;
166 		(void) strcpy(dumphdr->dump_platform, platform);
167 		dump_cmap = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP);
168 		dumpbuf_size = dumpbuf_iosize(maxphys);
169 		dumpbuf_start = kmem_alloc(dumpbuf_size, KM_SLEEP);
170 		dumpbuf_end = dumpbuf_start + dumpbuf_size;
171 		dump_cbuf = kmem_alloc(PAGESIZE, KM_SLEEP); /* compress buf */
172 		dump_uebuf = kmem_alloc(PAGESIZE, KM_SLEEP); /* UE buf */
173 		dump_pids = kmem_alloc(v.v_proc * sizeof (pid_t), KM_SLEEP);
174 	}
175 
176 	for (mp = phys_install; mp != NULL; mp = mp->next)
177 		npages += mp->size >> PAGESHIFT;
178 
179 	if (dump_bitmapsize != npages) {
180 		void *map = kmem_alloc(BT_SIZEOFMAP(npages), KM_SLEEP);
181 		kmem_free(dump_bitmap, BT_SIZEOFMAP(dump_bitmapsize));
182 		dump_bitmap = map;
183 		dump_bitmapsize = npages;
184 	}
185 }
186 
187 /*
188  * Establish a new dump device.
189  */
190 int
191 dumpinit(vnode_t *vp, char *name, int justchecking)
192 {
193 	vnode_t *cvp;
194 	vattr_t vattr;
195 	vnode_t *cdev_vp;
196 	int error = 0;
197 
198 	ASSERT(MUTEX_HELD(&dump_lock));
199 
200 	dumphdr_init();
201 
202 	cvp = common_specvp(vp);
203 	if (cvp == dumpvp)
204 		return (0);
205 
206 	/*
207 	 * Determine whether this is a plausible dump device.  We want either:
208 	 * (1) a real device that's not mounted and has a cb_dump routine, or
209 	 * (2) a swapfile on some filesystem that has a vop_dump routine.
210 	 */
211 	if ((error = VOP_OPEN(&cvp, FREAD | FWRITE, kcred)) != 0)
212 		return (error);
213 
214 	vattr.va_mask = AT_SIZE | AT_TYPE | AT_RDEV;
215 	if ((error = VOP_GETATTR(cvp, &vattr, 0, kcred)) == 0) {
216 		if (vattr.va_type == VBLK || vattr.va_type == VCHR) {
217 			if (devopsp[getmajor(vattr.va_rdev)]->
218 			    devo_cb_ops->cb_dump == nodev)
219 				error = ENOTSUP;
220 			else if (vfs_devismounted(vattr.va_rdev))
221 				error = EBUSY;
222 		} else {
223 			if (vn_matchopval(cvp, VOPNAME_DUMP, fs_nosys) ||
224 			    !IS_SWAPVP(cvp))
225 				error = ENOTSUP;
226 		}
227 	}
228 
229 	if (error == 0 && vattr.va_size < 2 * DUMP_LOGSIZE + DUMP_ERPTSIZE)
230 		error = ENOSPC;
231 
232 	if (error || justchecking) {
233 		(void) VOP_CLOSE(cvp, FREAD | FWRITE, 1, (offset_t)0, kcred);
234 		return (error);
235 	}
236 
237 	VN_HOLD(cvp);
238 
239 	if (dumpvp != NULL)
240 		dumpfini();	/* unconfigure the old dump device */
241 
242 	dumpvp = cvp;
243 	dumpvp_size = vattr.va_size & -DUMP_OFFSET;
244 	dumppath = kmem_alloc(strlen(name) + 1, KM_SLEEP);
245 	(void) strcpy(dumppath, name);
246 	dump_iosize = 0;
247 
248 	/*
249 	 * If the dump device is a block device, attempt to open up the
250 	 * corresponding character device and determine its maximum transfer
251 	 * size.  We use this information to potentially resize dumpbuf to a
252 	 * larger and more optimal size for performing i/o to the dump device.
253 	 */
254 	if (cvp->v_type == VBLK &&
255 	    (cdev_vp = makespecvp(VTOS(cvp)->s_dev, VCHR)) != NULL) {
256 		if (VOP_OPEN(&cdev_vp, FREAD | FWRITE, kcred) == 0) {
257 			size_t blk_size;
258 			struct dk_cinfo dki;
259 			struct vtoc vtoc;
260 
261 			if (VOP_IOCTL(cdev_vp, DKIOCGVTOC, (intptr_t)&vtoc,
262 			    FKIOCTL, kcred, NULL) == 0 && vtoc.v_sectorsz != 0)
263 				blk_size = vtoc.v_sectorsz;
264 			else
265 				blk_size = DEV_BSIZE;
266 
267 			if (VOP_IOCTL(cdev_vp, DKIOCINFO, (intptr_t)&dki,
268 			    FKIOCTL, kcred, NULL) == 0) {
269 				dump_iosize = dki.dki_maxtransfer * blk_size;
270 				dumpbuf_resize();
271 			}
272 
273 			(void) VOP_CLOSE(cdev_vp, FREAD | FWRITE, 1, 0, kcred);
274 		}
275 
276 		VN_RELE(cdev_vp);
277 	}
278 
279 	cmn_err(CE_CONT, "?dump on %s size %llu MB\n", name, dumpvp_size >> 20);
280 
281 	return (0);
282 }
283 
284 void
285 dumpfini(void)
286 {
287 	ASSERT(MUTEX_HELD(&dump_lock));
288 
289 	kmem_free(dumppath, strlen(dumppath) + 1);
290 
291 	(void) VOP_CLOSE(dumpvp, FREAD | FWRITE, 1, (offset_t)0, kcred);
292 
293 	VN_RELE(dumpvp);
294 
295 	dumpvp = NULL;
296 	dumpvp_size = 0;
297 	dumppath = NULL;
298 }
299 
300 static pfn_t
301 dump_bitnum_to_pfn(pgcnt_t bitnum)
302 {
303 	struct memlist *mp;
304 
305 	for (mp = phys_install; mp != NULL; mp = mp->next) {
306 		if (bitnum < (mp->size >> PAGESHIFT))
307 			return ((mp->address >> PAGESHIFT) + bitnum);
308 		bitnum -= mp->size >> PAGESHIFT;
309 	}
310 	return (PFN_INVALID);
311 }
312 
313 static pgcnt_t
314 dump_pfn_to_bitnum(pfn_t pfn)
315 {
316 	struct memlist *mp;
317 	pgcnt_t bitnum = 0;
318 
319 	for (mp = phys_install; mp != NULL; mp = mp->next) {
320 		if (pfn >= (mp->address >> PAGESHIFT) &&
321 		    pfn < ((mp->address + mp->size) >> PAGESHIFT))
322 			return (bitnum + pfn - (mp->address >> PAGESHIFT));
323 		bitnum += mp->size >> PAGESHIFT;
324 	}
325 	return ((pgcnt_t)-1);
326 }
327 
328 static offset_t
329 dumpvp_flush(void)
330 {
331 	size_t size = P2ROUNDUP(dumpbuf_cur - dumpbuf_start, PAGESIZE);
332 	int err;
333 
334 	if (dumpvp_off + size > dumpvp_limit) {
335 		dump_ioerr = ENOSPC;
336 	} else if (size != 0) {
337 		if (panicstr)
338 			err = VOP_DUMP(dumpvp, dumpbuf_start,
339 			    lbtodb(dumpvp_off), btod(size));
340 		else
341 			err = vn_rdwr(UIO_WRITE, dumpvp, dumpbuf_start, size,
342 			    dumpvp_off, UIO_SYSSPACE, 0, dumpvp_limit,
343 			    kcred, 0);
344 		if (err && dump_ioerr == 0)
345 			dump_ioerr = err;
346 	}
347 	dumpvp_off += size;
348 	dumpbuf_cur = dumpbuf_start;
349 	dump_timeleft = dump_timeout;
350 	return (dumpvp_off);
351 }
352 
353 void
354 dumpvp_write(const void *va, size_t size)
355 {
356 	while (size != 0) {
357 		size_t len = MIN(size, dumpbuf_end - dumpbuf_cur);
358 		if (len == 0) {
359 			(void) dumpvp_flush();
360 		} else {
361 			bcopy(va, dumpbuf_cur, len);
362 			va = (char *)va + len;
363 			dumpbuf_cur += len;
364 			size -= len;
365 		}
366 	}
367 }
368 
369 /*ARGSUSED*/
370 static void
371 dumpvp_ksyms_write(const void *src, void *dst, size_t size)
372 {
373 	dumpvp_write(src, size);
374 }
375 
376 /*
377  * Mark 'pfn' in the bitmap and dump its translation table entry.
378  */
379 void
380 dump_addpage(struct as *as, void *va, pfn_t pfn)
381 {
382 	mem_vtop_t mem_vtop;
383 	pgcnt_t bitnum;
384 
385 	if ((bitnum = dump_pfn_to_bitnum(pfn)) != (pgcnt_t)-1) {
386 		if (!BT_TEST(dump_bitmap, bitnum)) {
387 			dumphdr->dump_npages++;
388 			BT_SET(dump_bitmap, bitnum);
389 		}
390 		dumphdr->dump_nvtop++;
391 		mem_vtop.m_as = as;
392 		mem_vtop.m_va = va;
393 		mem_vtop.m_pfn = pfn;
394 		dumpvp_write(&mem_vtop, sizeof (mem_vtop_t));
395 	}
396 	dump_timeleft = dump_timeout;
397 }
398 
399 /*
400  * Mark 'pfn' in the bitmap
401  */
402 void
403 dump_page(pfn_t pfn)
404 {
405 	pgcnt_t bitnum;
406 
407 	if ((bitnum = dump_pfn_to_bitnum(pfn)) != (pgcnt_t)-1) {
408 		if (!BT_TEST(dump_bitmap, bitnum)) {
409 			dumphdr->dump_npages++;
410 			BT_SET(dump_bitmap, bitnum);
411 		}
412 	}
413 	dump_timeleft = dump_timeout;
414 }
415 
416 /*
417  * Dump the <as, va, pfn> information for a given address space.
418  * SEGOP_DUMP() will call dump_addpage() for each page in the segment.
419  */
420 static void
421 dump_as(struct as *as)
422 {
423 	struct seg *seg;
424 
425 	AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
426 	for (seg = AS_SEGFIRST(as); seg; seg = AS_SEGNEXT(as, seg)) {
427 		if (seg->s_as != as)
428 			break;
429 		if (seg->s_ops == NULL)
430 			continue;
431 		SEGOP_DUMP(seg);
432 	}
433 	AS_LOCK_EXIT(as, &as->a_lock);
434 
435 	if (seg != NULL)
436 		cmn_err(CE_WARN, "invalid segment %p in address space %p",
437 		    (void *)seg, (void *)as);
438 }
439 
440 static int
441 dump_process(pid_t pid)
442 {
443 	proc_t *p = sprlock(pid);
444 
445 	if (p == NULL)
446 		return (-1);
447 	if (p->p_as != &kas) {
448 		mutex_exit(&p->p_lock);
449 		dump_as(p->p_as);
450 		mutex_enter(&p->p_lock);
451 	}
452 
453 	sprunlock(p);
454 
455 	return (0);
456 }
457 
458 void
459 dump_ereports(void)
460 {
461 	u_offset_t dumpvp_start;
462 	erpt_dump_t ed;
463 
464 	if (dumpvp == NULL || dumphdr == NULL)
465 		return;
466 
467 	dumpbuf_cur = dumpbuf_start;
468 	dumpvp_limit = dumpvp_size - (DUMP_OFFSET + DUMP_LOGSIZE);
469 	dumpvp_start = dumpvp_limit - DUMP_ERPTSIZE;
470 	dumpvp_off = dumpvp_start;
471 
472 	fm_ereport_dump();
473 	if (panicstr)
474 		errorq_dump();
475 
476 	bzero(&ed, sizeof (ed)); /* indicate end of ereports */
477 	dumpvp_write(&ed, sizeof (ed));
478 	(void) dumpvp_flush();
479 
480 	if (!panicstr) {
481 		(void) VOP_PUTPAGE(dumpvp, dumpvp_start,
482 		    (size_t)(dumpvp_off - dumpvp_start),
483 		    B_INVAL | B_FORCE, kcred);
484 	}
485 }
486 
487 void
488 dump_messages(void)
489 {
490 	log_dump_t ld;
491 	mblk_t *mctl, *mdata;
492 	queue_t *q, *qlast;
493 	u_offset_t dumpvp_start;
494 
495 	if (dumpvp == NULL || dumphdr == NULL || log_consq == NULL)
496 		return;
497 
498 	dumpbuf_cur = dumpbuf_start;
499 	dumpvp_limit = dumpvp_size - DUMP_OFFSET;
500 	dumpvp_start = dumpvp_limit - DUMP_LOGSIZE;
501 	dumpvp_off = dumpvp_start;
502 
503 	qlast = NULL;
504 	do {
505 		for (q = log_consq; q->q_next != qlast; q = q->q_next)
506 			continue;
507 		for (mctl = q->q_first; mctl != NULL; mctl = mctl->b_next) {
508 			dump_timeleft = dump_timeout;
509 			mdata = mctl->b_cont;
510 			ld.ld_magic = LOG_MAGIC;
511 			ld.ld_msgsize = MBLKL(mctl->b_cont);
512 			ld.ld_csum = checksum32(mctl->b_rptr, MBLKL(mctl));
513 			ld.ld_msum = checksum32(mdata->b_rptr, MBLKL(mdata));
514 			dumpvp_write(&ld, sizeof (ld));
515 			dumpvp_write(mctl->b_rptr, MBLKL(mctl));
516 			dumpvp_write(mdata->b_rptr, MBLKL(mdata));
517 		}
518 	} while ((qlast = q) != log_consq);
519 
520 	ld.ld_magic = 0;		/* indicate end of messages */
521 	dumpvp_write(&ld, sizeof (ld));
522 	(void) dumpvp_flush();
523 	if (!panicstr) {
524 		(void) VOP_PUTPAGE(dumpvp, dumpvp_start,
525 		    (size_t)(dumpvp_off - dumpvp_start),
526 		    B_INVAL | B_FORCE, kcred);
527 	}
528 }
529 
530 static void
531 dump_pagecopy(void *src, void *dst)
532 {
533 	long *wsrc = (long *)src;
534 	long *wdst = (long *)dst;
535 	const ulong_t ncopies = PAGESIZE / sizeof (long);
536 	volatile int w = 0;
537 	volatile int ueoff = -1;
538 	on_trap_data_t otd;
539 
540 	if (on_trap(&otd, OT_DATA_EC)) {
541 		if (ueoff == -1) {
542 			uint64_t pa;
543 
544 			ueoff = w * sizeof (long);
545 			pa = ptob((uint64_t)hat_getpfnum(kas.a_hat, src))
546 			    + ueoff;
547 			cmn_err(CE_WARN, "memory error at PA 0x%08x.%08x",
548 			    (uint32_t)(pa >> 32), (uint32_t)pa);
549 		}
550 #ifdef _LP64
551 		wdst[w++] = 0xbadecc00badecc;
552 #else
553 		wdst[w++] = 0xbadecc;
554 #endif
555 	}
556 	while (w < ncopies) {
557 		wdst[w] = wsrc[w];
558 		w++;
559 	}
560 	no_trap();
561 }
562 
563 /*
564  * Dump the system.
565  */
566 void
567 dumpsys(void)
568 {
569 	pfn_t pfn;
570 	pgcnt_t bitnum;
571 	int npages = 0;
572 	int percent_done = 0;
573 	uint32_t csize;
574 	u_offset_t total_csize = 0;
575 	int compress_ratio;
576 	proc_t *p;
577 	pid_t npids, pidx;
578 	char *content;
579 
580 	if (dumpvp == NULL || dumphdr == NULL) {
581 		uprintf("skipping system dump - no dump device configured\n");
582 		return;
583 	}
584 	dumpbuf_cur = dumpbuf_start;
585 
586 	/*
587 	 * Calculate the starting block for dump.  If we're dumping on a
588 	 * swap device, start 1/5 of the way in; otherwise, start at the
589 	 * beginning.  And never use the first page -- it may be a disk label.
590 	 */
591 	if (dumpvp->v_flag & VISSWAP)
592 		dumphdr->dump_start = P2ROUNDUP(dumpvp_size / 5, DUMP_OFFSET);
593 	else
594 		dumphdr->dump_start = DUMP_OFFSET;
595 
596 	dumphdr->dump_flags = DF_VALID | DF_COMPLETE | DF_LIVE;
597 	dumphdr->dump_crashtime = gethrestime_sec();
598 	dumphdr->dump_npages = 0;
599 	dumphdr->dump_nvtop = 0;
600 	bzero(dump_bitmap, BT_SIZEOFMAP(dump_bitmapsize));
601 	dump_timeleft = dump_timeout;
602 
603 	if (panicstr) {
604 		dumphdr->dump_flags &= ~DF_LIVE;
605 		(void) VOP_DUMPCTL(dumpvp, DUMP_FREE, NULL);
606 		(void) VOP_DUMPCTL(dumpvp, DUMP_ALLOC, NULL);
607 		(void) vsnprintf(dumphdr->dump_panicstring, DUMP_PANICSIZE,
608 		    panicstr, panicargs);
609 	}
610 
611 	if (dump_conflags & DUMP_ALL)
612 		content = "all";
613 	else if (dump_conflags & DUMP_CURPROC)
614 		content = "kernel + curproc";
615 	else
616 		content = "kernel";
617 	uprintf("dumping to %s, offset %lld, content: %s\n", dumppath,
618 	    dumphdr->dump_start, content);
619 
620 	/*
621 	 * Leave room for the message and ereport save areas and terminal dump
622 	 * header.
623 	 */
624 	dumpvp_limit = dumpvp_size - DUMP_LOGSIZE - DUMP_OFFSET - DUMP_ERPTSIZE;
625 
626 	/*
627 	 * Write out the symbol table.  It's no longer compressed,
628 	 * so its 'size' and 'csize' are equal.
629 	 */
630 	dumpvp_off = dumphdr->dump_ksyms = dumphdr->dump_start + PAGESIZE;
631 	dumphdr->dump_ksyms_size = dumphdr->dump_ksyms_csize =
632 	    ksyms_snapshot(dumpvp_ksyms_write, NULL, LONG_MAX);
633 
634 	/*
635 	 * Write out the translation map.
636 	 */
637 	dumphdr->dump_map = dumpvp_flush();
638 	dump_as(&kas);
639 	dumphdr->dump_nvtop += dump_plat_addr();
640 
641 	/*
642 	 * call into hat, which may have unmapped pages that also need to
643 	 * be in the dump
644 	 */
645 	hat_dump();
646 
647 	if (dump_conflags & DUMP_ALL) {
648 		mutex_enter(&pidlock);
649 
650 		for (npids = 0, p = practive; p != NULL; p = p->p_next)
651 			dump_pids[npids++] = p->p_pid;
652 
653 		mutex_exit(&pidlock);
654 
655 		for (pidx = 0; pidx < npids; pidx++)
656 			(void) dump_process(dump_pids[pidx]);
657 
658 		for (bitnum = 0; bitnum < dump_bitmapsize; bitnum++) {
659 			dump_timeleft = dump_timeout;
660 			BT_SET(dump_bitmap, bitnum);
661 		}
662 		dumphdr->dump_npages = dump_bitmapsize;
663 		dumphdr->dump_flags |= DF_ALL;
664 
665 	} else if (dump_conflags & DUMP_CURPROC) {
666 		/*
667 		 * Determine which pid is to be dumped.  If we're panicking, we
668 		 * dump the process associated with panic_thread (if any).  If
669 		 * this is a live dump, we dump the process associated with
670 		 * curthread.
671 		 */
672 		npids = 0;
673 		if (panicstr) {
674 			if (panic_thread != NULL &&
675 			    panic_thread->t_procp != NULL &&
676 			    panic_thread->t_procp != &p0) {
677 				dump_pids[npids++] =
678 				    panic_thread->t_procp->p_pid;
679 			}
680 		} else {
681 			dump_pids[npids++] = curthread->t_procp->p_pid;
682 		}
683 
684 		if (npids && dump_process(dump_pids[0]) == 0)
685 			dumphdr->dump_flags |= DF_CURPROC;
686 		else
687 			dumphdr->dump_flags |= DF_KERNEL;
688 
689 	} else {
690 		dumphdr->dump_flags |= DF_KERNEL;
691 	}
692 
693 	dumphdr->dump_hashmask = (1 << highbit(dumphdr->dump_nvtop - 1)) - 1;
694 
695 	/*
696 	 * Write out the pfn table.
697 	 */
698 	dumphdr->dump_pfn = dumpvp_flush();
699 	for (bitnum = 0; bitnum < dump_bitmapsize; bitnum++) {
700 		dump_timeleft = dump_timeout;
701 		if (!BT_TEST(dump_bitmap, bitnum))
702 			continue;
703 		pfn = dump_bitnum_to_pfn(bitnum);
704 		ASSERT(pfn != PFN_INVALID);
705 		dumpvp_write(&pfn, sizeof (pfn_t));
706 	}
707 	dump_plat_pfn();
708 
709 	/*
710 	 * Write out all the pages.
711 	 */
712 	dumphdr->dump_data = dumpvp_flush();
713 	for (bitnum = 0; bitnum < dump_bitmapsize; bitnum++) {
714 		dump_timeleft = dump_timeout;
715 		if (!BT_TEST(dump_bitmap, bitnum))
716 			continue;
717 		pfn = dump_bitnum_to_pfn(bitnum);
718 		ASSERT(pfn != PFN_INVALID);
719 
720 		/*
721 		 * Map in page frame 'pfn', scan it for UE's while copying
722 		 * the data to dump_uebuf, unmap it, compress dump_uebuf into
723 		 * dump_cbuf, and write out dump_cbuf.  The UE check ensures
724 		 * that we don't lose the whole dump because of a latent UE.
725 		 */
726 		hat_devload(kas.a_hat, dump_cmap, PAGESIZE, pfn, PROT_READ,
727 		    HAT_LOAD_NOCONSIST);
728 		dump_pagecopy(dump_cmap, dump_uebuf);
729 		hat_unload(kas.a_hat, dump_cmap, PAGESIZE, HAT_UNLOAD);
730 		csize = (uint32_t)compress(dump_uebuf, dump_cbuf, PAGESIZE);
731 		dumpvp_write(&csize, sizeof (uint32_t));
732 		dumpvp_write(dump_cbuf, csize);
733 		if (dump_ioerr) {
734 			dumphdr->dump_flags &= ~DF_COMPLETE;
735 			dumphdr->dump_npages = npages;
736 			break;
737 		}
738 		total_csize += csize;
739 		if (++npages * 100LL / dumphdr->dump_npages > percent_done) {
740 			uprintf("^\r%3d%% done", ++percent_done);
741 			if (!panicstr)
742 				delay(1);	/* let the output be sent */
743 		}
744 	}
745 	dumphdr->dump_npages += dump_plat_data(dump_cbuf);
746 
747 	(void) dumpvp_flush();
748 
749 	/*
750 	 * Write out the initial and terminal dump headers.
751 	 */
752 	dumpvp_off = dumphdr->dump_start;
753 	dumpvp_write(dumphdr, sizeof (dumphdr_t));
754 	(void) dumpvp_flush();
755 
756 	dumpvp_limit = dumpvp_size;
757 	dumpvp_off = dumpvp_limit - DUMP_OFFSET;
758 	dumpvp_write(dumphdr, sizeof (dumphdr_t));
759 	(void) dumpvp_flush();
760 
761 	compress_ratio = (int)(100LL * npages / (btopr(total_csize + 1)));
762 
763 	uprintf("\r%3d%% done: %d pages dumped, compression ratio %d.%02d, ",
764 	    percent_done, npages, compress_ratio / 100, compress_ratio % 100);
765 
766 	if (dump_ioerr == 0) {
767 		uprintf("dump succeeded\n");
768 	} else {
769 		uprintf("dump failed: error %d\n", dump_ioerr);
770 		if (panicstr && dumpfaildebug)
771 			debug_enter("dump failed");
772 	}
773 
774 	/*
775 	 * Write out all undelivered messages.  This has to be the *last*
776 	 * thing we do because the dump process itself emits messages.
777 	 */
778 	if (panicstr) {
779 		dump_ereports();
780 		dump_messages();
781 	}
782 
783 	delay(2 * hz);	/* let people see the 'done' message */
784 	dump_timeleft = 0;
785 	dump_ioerr = 0;
786 }
787 
788 /*
789  * This function is called whenever the memory size, as represented
790  * by the phys_install list, changes.
791  */
792 void
793 dump_resize()
794 {
795 	mutex_enter(&dump_lock);
796 	dumphdr_init();
797 	dumpbuf_resize();
798 	mutex_exit(&dump_lock);
799 }
800