dumpsubr.c revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/compress.h>
#include <sys/systeminfo.h>
#include <vm/seg_kmem.h>
char *dumppath; /* pathname of dump device */
int dump_timeleft; /* portion of dump_timeout remaining */
int dump_ioerr; /* dump i/o error */
#ifdef DEBUG
#else
int dumpfaildebug = 0;
#endif
static char *dump_cmap; /* VA for dump compression mapping */
static char *dump_cbuf; /* compression buffer */
static char *dump_uebuf; /* memory error detection buffer */
/*
* The dump i/o buffer must be at least one page, at most xfer_size bytes, and
* should scale with physmem in between. The transfer size passed in will
* either represent a global default (maxphys) or the best size for the device.
* Once the physical memory size exceeds dumpbuf_thresh (1GB by default), we
* increase the percentage of physical memory that dumpbuf can consume by a
* factor of dumpbuf_mult (8 by default) to improve large memory performance.
* The size of the dumpbuf i/o buffer is limited by dumpbuf_limit (8MB by
* default) because the dump performance saturates beyond a certain size.
*/
static size_t
{
} else
return (iosize);
}
static void
dumpbuf_resize(void)
{
char *old_buf = dumpbuf_start;
char *new_buf;
return; /* no need to reallocate buffer */
}
static void
dumphdr_init(void)
{
}
npages = num_phys_pages();
if (dump_bitmapsize != npages) {
dump_bitmap = map;
}
}
/*
* Establish a new dump device.
*/
int
{
int error = 0;
dumphdr_init();
return (0);
/*
* Determine whether this is a plausible dump device. We want either:
* (1) a real device that's not mounted and has a cb_dump routine, or
* (2) a swapfile on some filesystem that has a vop_dump routine.
*/
return (error);
} else {
}
}
if (error || justchecking) {
return (error);
}
dumpfini(); /* unconfigure the old dump device */
dump_iosize = 0;
/*
* If the dump device is a block device, attempt to open up the
* corresponding character device and determine its maximum transfer
* size. We use this information to potentially resize dumpbuf to a
* larger and more optimal size for performing i/o to the dump device.
*/
vtoc.v_sectorsz != 0)
else
}
}
}
return (0);
}
void
dumpfini(void)
{
dumpvp_size = 0;
}
static pfn_t
{
}
return (PFN_INVALID);
}
static pgcnt_t
{
}
return ((pgcnt_t)-1);
}
static offset_t
dumpvp_flush(void)
{
int err;
dump_ioerr = ENOSPC;
} else if (size != 0) {
if (panicstr)
else
kcred, 0);
if (err && dump_ioerr == 0)
dump_ioerr = err;
}
dumpvp_off += size;
return (dumpvp_off);
}
void
{
while (size != 0) {
if (len == 0) {
(void) dumpvp_flush();
} else {
dumpbuf_cur += len;
}
}
}
/*ARGSUSED*/
static void
{
}
/*
* Mark 'pfn' in the bitmap and dump its translation table entry.
*/
void
{
dumphdr->dump_npages++;
}
dumphdr->dump_nvtop++;
}
}
/*
* Mark 'pfn' in the bitmap
*/
void
{
dumphdr->dump_npages++;
}
}
}
/*
* Dump the <as, va, pfn> information for a given address space.
* SEGOP_DUMP() will call dump_addpage() for each page in the segment.
*/
static void
{
break;
continue;
}
}
static int
{
if (p == NULL)
return (-1);
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
sprunlock(p);
return (0);
}
void
dump_ereports(void)
{
return;
if (panicstr)
errorq_dump();
(void) dumpvp_flush();
if (!panicstr) {
}
}
void
dump_messages(void)
{
return;
do {
continue;
}
(void) dumpvp_flush();
if (!panicstr) {
}
}
static void
{
volatile int w = 0;
volatile int ueoff = -1;
if (ueoff == -1) {
ueoff = w * sizeof (long);
+ ueoff;
}
#ifdef _LP64
wdst[w++] = 0xbadecc00badecc;
#else
wdst[w++] = 0xbadecc;
#endif
}
while (w < ncopies) {
w++;
}
no_trap();
}
/*
* Dump the system.
*/
void
dumpsys(void)
{
int npages = 0;
int percent_done = 0;
u_offset_t total_csize = 0;
int compress_ratio;
proc_t *p;
char *content;
uprintf("skipping system dump - no dump device configured\n");
return;
}
/*
* Calculate the starting block for dump. If we're dumping on a
* swap device, start 1/5 of the way in; otherwise, start at the
* beginning. And never use the first page -- it may be a disk label.
*/
else
dumphdr->dump_npages = 0;
dumphdr->dump_nvtop = 0;
if (panicstr) {
}
if (dump_conflags & DUMP_ALL)
content = "all";
else if (dump_conflags & DUMP_CURPROC)
content = "kernel + curproc";
else
content = "kernel";
/*
* Leave room for the message and ereport save areas and terminal dump
* header.
*/
/*
* Write out the symbol table. It's no longer compressed,
* so its 'size' and 'csize' are equal.
*/
/*
* Write out the translation map.
*/
/*
* call into hat, which may have unmapped pages that also need to
* be in the dump
*/
hat_dump();
if (dump_conflags & DUMP_ALL) {
}
} else if (dump_conflags & DUMP_CURPROC) {
/*
* Determine which pid is to be dumped. If we're panicking, we
* dump the process associated with panic_thread (if any). If
* this is a live dump, we dump the process associated with
* curthread.
*/
npids = 0;
if (panicstr) {
if (panic_thread != NULL &&
}
} else {
}
else
} else {
}
/*
* Write out the pfn table.
*/
continue;
}
/*
* Write out all the pages.
*/
continue;
/*
* Map in page frame 'pfn', scan it for UE's while copying
* the data to dump_uebuf, unmap it, compress dump_uebuf into
* dump_cbuf, and write out dump_cbuf. The UE check ensures
* that we don't lose the whole dump because of a latent UE.
*/
if (dump_ioerr) {
break;
}
total_csize += csize;
if (!panicstr)
}
}
(void) dumpvp_flush();
/*
* Write out the initial and terminal dump headers.
*/
(void) dumpvp_flush();
(void) dumpvp_flush();
uprintf("\r%3d%% done: %d pages dumped, compression ratio %d.%02d, ",
if (dump_ioerr == 0) {
uprintf("dump succeeded\n");
} else {
if (panicstr && dumpfaildebug)
debug_enter("dump failed");
}
/*
* Write out all undelivered messages. This has to be the *last*
* thing we do because the dump process itself emits messages.
*/
if (panicstr) {
}
dump_timeleft = 0;
dump_ioerr = 0;
}
/*
* This function is called whenever the memory size, as represented
* by the phys_install list, changes.
*/
void
{
dumphdr_init();
}