10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
53446Smrj * Common Development and Distribution License (the "License").
63446Smrj * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
217563SPrasad.Singamsetty@Sun.COM
220Sstevel@tonic-gate /*
2312042SDave.Plauger@Sun.COM * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include <sys/types.h>
270Sstevel@tonic-gate #include <sys/param.h>
280Sstevel@tonic-gate #include <sys/systm.h>
290Sstevel@tonic-gate #include <sys/vm.h>
300Sstevel@tonic-gate #include <sys/proc.h>
310Sstevel@tonic-gate #include <sys/file.h>
320Sstevel@tonic-gate #include <sys/conf.h>
330Sstevel@tonic-gate #include <sys/kmem.h>
340Sstevel@tonic-gate #include <sys/mem.h>
350Sstevel@tonic-gate #include <sys/mman.h>
360Sstevel@tonic-gate #include <sys/vnode.h>
370Sstevel@tonic-gate #include <sys/errno.h>
380Sstevel@tonic-gate #include <sys/memlist.h>
390Sstevel@tonic-gate #include <sys/dumphdr.h>
400Sstevel@tonic-gate #include <sys/dumpadm.h>
410Sstevel@tonic-gate #include <sys/ksyms.h>
420Sstevel@tonic-gate #include <sys/compress.h>
430Sstevel@tonic-gate #include <sys/stream.h>
440Sstevel@tonic-gate #include <sys/strsun.h>
450Sstevel@tonic-gate #include <sys/cmn_err.h>
460Sstevel@tonic-gate #include <sys/bitmap.h>
470Sstevel@tonic-gate #include <sys/modctl.h>
480Sstevel@tonic-gate #include <sys/utsname.h>
490Sstevel@tonic-gate #include <sys/systeminfo.h>
500Sstevel@tonic-gate #include <sys/vmem.h>
510Sstevel@tonic-gate #include <sys/log.h>
520Sstevel@tonic-gate #include <sys/var.h>
530Sstevel@tonic-gate #include <sys/debug.h>
540Sstevel@tonic-gate #include <sys/sunddi.h>
550Sstevel@tonic-gate #include <fs/fs_subr.h>
560Sstevel@tonic-gate #include <sys/fs/snode.h>
570Sstevel@tonic-gate #include <sys/ontrap.h>
580Sstevel@tonic-gate #include <sys/panic.h>
590Sstevel@tonic-gate #include <sys/dkio.h>
600Sstevel@tonic-gate #include <sys/vtoc.h>
610Sstevel@tonic-gate #include <sys/errorq.h>
620Sstevel@tonic-gate #include <sys/fm/util.h>
636423Sgw25295 #include <sys/fs/zfs.h>
640Sstevel@tonic-gate
650Sstevel@tonic-gate #include <vm/hat.h>
660Sstevel@tonic-gate #include <vm/as.h>
670Sstevel@tonic-gate #include <vm/page.h>
6810843SDave.Plauger@Sun.COM #include <vm/pvn.h>
690Sstevel@tonic-gate #include <vm/seg.h>
700Sstevel@tonic-gate #include <vm/seg_kmem.h>
7111066Srafael.vanoni@sun.com #include <sys/clock_impl.h>
7211480SStuart.Maybee@Sun.COM #include <sys/hold_page.h>
730Sstevel@tonic-gate
7410843SDave.Plauger@Sun.COM #include <bzip2/bzlib.h>
7510843SDave.Plauger@Sun.COM
7610843SDave.Plauger@Sun.COM /*
7710843SDave.Plauger@Sun.COM * Crash dump time is dominated by disk write time. To reduce this,
7810843SDave.Plauger@Sun.COM * the stronger compression method bzip2 is applied to reduce the dump
7910843SDave.Plauger@Sun.COM * size and hence reduce I/O time. However, bzip2 is much more
8010843SDave.Plauger@Sun.COM * computationally expensive than the existing lzjb algorithm, so to
8110843SDave.Plauger@Sun.COM * avoid increasing compression time, CPUs that are otherwise idle
8210843SDave.Plauger@Sun.COM * during panic are employed to parallelize the compression task.
8310843SDave.Plauger@Sun.COM * Many helper CPUs are needed to prevent bzip2 from being a
8410843SDave.Plauger@Sun.COM * bottleneck, and on systems with too few CPUs, the lzjb algorithm is
8510843SDave.Plauger@Sun.COM * parallelized instead. Lastly, I/O and compression are performed by
8610843SDave.Plauger@Sun.COM * different CPUs, and are hence overlapped in time, unlike the older
8710843SDave.Plauger@Sun.COM * serial code.
8810843SDave.Plauger@Sun.COM *
8910843SDave.Plauger@Sun.COM * Another important consideration is the speed of the dump
9010843SDave.Plauger@Sun.COM * device. Faster disks need less CPUs in order to benefit from
9110843SDave.Plauger@Sun.COM * parallel lzjb versus parallel bzip2. Therefore, the CPU count
9210843SDave.Plauger@Sun.COM * threshold for switching from parallel lzjb to paralled bzip2 is
9310843SDave.Plauger@Sun.COM * elevated for faster disks. The dump device speed is adduced from
9410843SDave.Plauger@Sun.COM * the setting for dumpbuf.iosize, see dump_update_clevel.
9510843SDave.Plauger@Sun.COM */
9610843SDave.Plauger@Sun.COM
9710843SDave.Plauger@Sun.COM /*
9810843SDave.Plauger@Sun.COM * exported vars
9910843SDave.Plauger@Sun.COM */
10010843SDave.Plauger@Sun.COM kmutex_t dump_lock; /* lock for dump configuration */
10110843SDave.Plauger@Sun.COM dumphdr_t *dumphdr; /* dump header */
1020Sstevel@tonic-gate int dump_conflags = DUMP_KERNEL; /* dump configuration flags */
10310843SDave.Plauger@Sun.COM vnode_t *dumpvp; /* dump device vnode pointer */
10410843SDave.Plauger@Sun.COM u_offset_t dumpvp_size; /* size of dump device, in bytes */
10510843SDave.Plauger@Sun.COM char *dumppath; /* pathname of dump device */
10610843SDave.Plauger@Sun.COM int dump_timeout = 120; /* timeout for dumping pages */
10710843SDave.Plauger@Sun.COM int dump_timeleft; /* portion of dump_timeout remaining */
10810843SDave.Plauger@Sun.COM int dump_ioerr; /* dump i/o error */
10910843SDave.Plauger@Sun.COM int dump_check_used; /* enable check for used pages */
11012967Sgavin.maltby@oracle.com char *dump_stack_scratch; /* scratch area for saving stack summary */
11110843SDave.Plauger@Sun.COM
11210843SDave.Plauger@Sun.COM /*
11310843SDave.Plauger@Sun.COM * Tunables for dump compression and parallelism. These can be set via
11410843SDave.Plauger@Sun.COM * /etc/system.
11510843SDave.Plauger@Sun.COM *
11610843SDave.Plauger@Sun.COM * dump_ncpu_low number of helpers for parallel lzjb
11710843SDave.Plauger@Sun.COM * This is also the minimum configuration.
11810843SDave.Plauger@Sun.COM *
11910843SDave.Plauger@Sun.COM * dump_bzip2_level bzip2 compression level: 1-9
12010843SDave.Plauger@Sun.COM * Higher numbers give greater compression, but take more memory
12110843SDave.Plauger@Sun.COM * and time. Memory used per helper is ~(dump_bzip2_level * 1MB).
12210843SDave.Plauger@Sun.COM *
12310843SDave.Plauger@Sun.COM * dump_plat_mincpu the cross-over limit for using bzip2 (per platform):
12410843SDave.Plauger@Sun.COM * if dump_plat_mincpu == 0, then always do single threaded dump
12510843SDave.Plauger@Sun.COM * if ncpu >= dump_plat_mincpu then try to use bzip2
12610843SDave.Plauger@Sun.COM *
12710843SDave.Plauger@Sun.COM * dump_metrics_on if set, metrics are collected in the kernel, passed
12810843SDave.Plauger@Sun.COM * to savecore via the dump file, and recorded by savecore in
12910843SDave.Plauger@Sun.COM * METRICS.txt.
13010843SDave.Plauger@Sun.COM */
13110843SDave.Plauger@Sun.COM uint_t dump_ncpu_low = 4; /* minimum config for parallel lzjb */
13210843SDave.Plauger@Sun.COM uint_t dump_bzip2_level = 1; /* bzip2 level (1-9) */
13310843SDave.Plauger@Sun.COM
13412931SDave.Plauger@Sun.COM /* Use dump_plat_mincpu_default unless this variable is set by /etc/system */
13512931SDave.Plauger@Sun.COM #define MINCPU_NOT_SET ((uint_t)-1)
13612931SDave.Plauger@Sun.COM uint_t dump_plat_mincpu = MINCPU_NOT_SET;
13712931SDave.Plauger@Sun.COM
13811178SDave.Plauger@Sun.COM /* tunables for pre-reserved heap */
13911178SDave.Plauger@Sun.COM uint_t dump_kmem_permap = 1024;
14011178SDave.Plauger@Sun.COM uint_t dump_kmem_pages = 8;
14111178SDave.Plauger@Sun.COM
14210843SDave.Plauger@Sun.COM /* Define multiple buffers per helper to avoid stalling */
14310843SDave.Plauger@Sun.COM #define NCBUF_PER_HELPER 2
14410843SDave.Plauger@Sun.COM #define NCMAP_PER_HELPER 4
14510843SDave.Plauger@Sun.COM
14610843SDave.Plauger@Sun.COM /* minimum number of helpers configured */
14710843SDave.Plauger@Sun.COM #define MINHELPERS (dump_ncpu_low)
14810843SDave.Plauger@Sun.COM #define MINCBUFS (MINHELPERS * NCBUF_PER_HELPER)
14910843SDave.Plauger@Sun.COM
15010843SDave.Plauger@Sun.COM /*
15110843SDave.Plauger@Sun.COM * Define constant parameters.
15210843SDave.Plauger@Sun.COM *
15310843SDave.Plauger@Sun.COM * CBUF_SIZE size of an output buffer
15410843SDave.Plauger@Sun.COM *
15510843SDave.Plauger@Sun.COM * CBUF_MAPSIZE size of virtual range for mapping pages
15610843SDave.Plauger@Sun.COM *
15710843SDave.Plauger@Sun.COM * CBUF_MAPNP size of virtual range in pages
15810843SDave.Plauger@Sun.COM *
15910843SDave.Plauger@Sun.COM */
16010843SDave.Plauger@Sun.COM #define DUMP_1KB ((size_t)1 << 10)
16110843SDave.Plauger@Sun.COM #define DUMP_1MB ((size_t)1 << 20)
16210843SDave.Plauger@Sun.COM #define CBUF_SIZE ((size_t)1 << 17)
16310843SDave.Plauger@Sun.COM #define CBUF_MAPSHIFT (22)
16410843SDave.Plauger@Sun.COM #define CBUF_MAPSIZE ((size_t)1 << CBUF_MAPSHIFT)
16510843SDave.Plauger@Sun.COM #define CBUF_MAPNP ((size_t)1 << (CBUF_MAPSHIFT - PAGESHIFT))
16610843SDave.Plauger@Sun.COM
16710843SDave.Plauger@Sun.COM /*
16810843SDave.Plauger@Sun.COM * Compression metrics are accumulated nano-second subtotals. The
16910843SDave.Plauger@Sun.COM * results are normalized by the number of pages dumped. A report is
17010843SDave.Plauger@Sun.COM * generated when dumpsys() completes and is saved in the dump image
17110843SDave.Plauger@Sun.COM * after the trailing dump header.
17210843SDave.Plauger@Sun.COM *
17310843SDave.Plauger@Sun.COM * Metrics are always collected. Set the variable dump_metrics_on to
17410843SDave.Plauger@Sun.COM * cause metrics to be saved in the crash file, where savecore will
17510843SDave.Plauger@Sun.COM * save it in the file METRICS.txt.
17610843SDave.Plauger@Sun.COM */
17710843SDave.Plauger@Sun.COM #define PERPAGES \
17810843SDave.Plauger@Sun.COM PERPAGE(bitmap) PERPAGE(map) PERPAGE(unmap) \
17910843SDave.Plauger@Sun.COM PERPAGE(copy) PERPAGE(compress) \
18010843SDave.Plauger@Sun.COM PERPAGE(write) \
18110843SDave.Plauger@Sun.COM PERPAGE(inwait) PERPAGE(outwait)
18210843SDave.Plauger@Sun.COM
18310843SDave.Plauger@Sun.COM typedef struct perpage {
18410843SDave.Plauger@Sun.COM #define PERPAGE(x) hrtime_t x;
18510843SDave.Plauger@Sun.COM PERPAGES
18610843SDave.Plauger@Sun.COM #undef PERPAGE
18710843SDave.Plauger@Sun.COM } perpage_t;
18810843SDave.Plauger@Sun.COM
18910843SDave.Plauger@Sun.COM /*
19010843SDave.Plauger@Sun.COM * This macro controls the code generation for collecting dump
19110843SDave.Plauger@Sun.COM * performance information. By default, the code is generated, but
19210843SDave.Plauger@Sun.COM * automatic saving of the information is disabled. If dump_metrics_on
19310843SDave.Plauger@Sun.COM * is set to 1, the timing information is passed to savecore via the
19410843SDave.Plauger@Sun.COM * crash file, where it is appended to the file dump-dir/METRICS.txt.
19510843SDave.Plauger@Sun.COM */
19610843SDave.Plauger@Sun.COM #define COLLECT_METRICS
19710843SDave.Plauger@Sun.COM
19810843SDave.Plauger@Sun.COM #ifdef COLLECT_METRICS
19910843SDave.Plauger@Sun.COM uint_t dump_metrics_on = 0; /* set to 1 to enable recording metrics */
20010843SDave.Plauger@Sun.COM
20110843SDave.Plauger@Sun.COM #define HRSTART(v, m) v##ts.m = gethrtime()
20210843SDave.Plauger@Sun.COM #define HRSTOP(v, m) v.m += gethrtime() - v##ts.m
20310843SDave.Plauger@Sun.COM #define HRBEGIN(v, m, s) v##ts.m = gethrtime(); v.size += s
20410843SDave.Plauger@Sun.COM #define HREND(v, m) v.m += gethrtime() - v##ts.m
20510843SDave.Plauger@Sun.COM #define HRNORM(v, m, n) v.m /= (n)
20610843SDave.Plauger@Sun.COM
2070Sstevel@tonic-gate #else
20810843SDave.Plauger@Sun.COM #define HRSTART(v, m)
20910843SDave.Plauger@Sun.COM #define HRSTOP(v, m)
21010843SDave.Plauger@Sun.COM #define HRBEGIN(v, m, s)
21110843SDave.Plauger@Sun.COM #define HREND(v, m)
21210843SDave.Plauger@Sun.COM #define HRNORM(v, m, n)
21310843SDave.Plauger@Sun.COM #endif /* COLLECT_METRICS */
21410843SDave.Plauger@Sun.COM
21510843SDave.Plauger@Sun.COM /*
21610843SDave.Plauger@Sun.COM * Buffers for copying and compressing memory pages.
21710843SDave.Plauger@Sun.COM *
21810843SDave.Plauger@Sun.COM * cbuf_t buffer controllers: used for both input and output.
21910843SDave.Plauger@Sun.COM *
22010843SDave.Plauger@Sun.COM * The buffer state indicates how it is being used:
22110843SDave.Plauger@Sun.COM *
22210843SDave.Plauger@Sun.COM * CBUF_FREEMAP: CBUF_MAPSIZE virtual address range is available for
22310843SDave.Plauger@Sun.COM * mapping input pages.
22410843SDave.Plauger@Sun.COM *
22510843SDave.Plauger@Sun.COM * CBUF_INREADY: input pages are mapped and ready for compression by a
22610843SDave.Plauger@Sun.COM * helper.
22710843SDave.Plauger@Sun.COM *
22810843SDave.Plauger@Sun.COM * CBUF_USEDMAP: mapping has been consumed by a helper. Needs unmap.
22910843SDave.Plauger@Sun.COM *
23010843SDave.Plauger@Sun.COM * CBUF_FREEBUF: CBUF_SIZE output buffer, which is available.
23110843SDave.Plauger@Sun.COM *
23210843SDave.Plauger@Sun.COM * CBUF_WRITE: CBUF_SIZE block of compressed pages from a helper,
23310843SDave.Plauger@Sun.COM * ready to write out.
23410843SDave.Plauger@Sun.COM *
23510843SDave.Plauger@Sun.COM * CBUF_ERRMSG: CBUF_SIZE block of error messages from a helper
23610843SDave.Plauger@Sun.COM * (reports UE errors.)
23710843SDave.Plauger@Sun.COM */
23810843SDave.Plauger@Sun.COM
23910843SDave.Plauger@Sun.COM typedef enum cbufstate {
24010843SDave.Plauger@Sun.COM CBUF_FREEMAP,
24110843SDave.Plauger@Sun.COM CBUF_INREADY,
24210843SDave.Plauger@Sun.COM CBUF_USEDMAP,
24310843SDave.Plauger@Sun.COM CBUF_FREEBUF,
24410843SDave.Plauger@Sun.COM CBUF_WRITE,
24510843SDave.Plauger@Sun.COM CBUF_ERRMSG
24610843SDave.Plauger@Sun.COM } cbufstate_t;
24710843SDave.Plauger@Sun.COM
24810843SDave.Plauger@Sun.COM typedef struct cbuf cbuf_t;
24910843SDave.Plauger@Sun.COM
25010843SDave.Plauger@Sun.COM struct cbuf {
25110843SDave.Plauger@Sun.COM cbuf_t *next; /* next in list */
25210843SDave.Plauger@Sun.COM cbufstate_t state; /* processing state */
25310843SDave.Plauger@Sun.COM size_t used; /* amount used */
25410843SDave.Plauger@Sun.COM size_t size; /* mem size */
25510843SDave.Plauger@Sun.COM char *buf; /* kmem or vmem */
25610843SDave.Plauger@Sun.COM pgcnt_t pagenum; /* index to pfn map */
25710843SDave.Plauger@Sun.COM pgcnt_t bitnum; /* first set bitnum */
25810843SDave.Plauger@Sun.COM pfn_t pfn; /* first pfn in mapped range */
25910843SDave.Plauger@Sun.COM int off; /* byte offset to first pfn */
26010843SDave.Plauger@Sun.COM };
2610Sstevel@tonic-gate
26212967Sgavin.maltby@oracle.com static char dump_osimage_uuid[36 + 1];
26312967Sgavin.maltby@oracle.com
26412967Sgavin.maltby@oracle.com #define isdigit(ch) ((ch) >= '0' && (ch) <= '9')
26512967Sgavin.maltby@oracle.com #define isxdigit(ch) (isdigit(ch) || ((ch) >= 'a' && (ch) <= 'f') || \
26612967Sgavin.maltby@oracle.com ((ch) >= 'A' && (ch) <= 'F'))
26712967Sgavin.maltby@oracle.com
2680Sstevel@tonic-gate /*
26910843SDave.Plauger@Sun.COM * cqueue_t queues: a uni-directional channel for communication
27010843SDave.Plauger@Sun.COM * from the master to helper tasks or vice-versa using put and
27110843SDave.Plauger@Sun.COM * get primitives. Both mappings and data buffers are passed via
27210843SDave.Plauger@Sun.COM * queues. Producers close a queue when done. The number of
27310843SDave.Plauger@Sun.COM * active producers is reference counted so the consumer can
27410843SDave.Plauger@Sun.COM * detect end of data. Concurrent access is mediated by atomic
27510843SDave.Plauger@Sun.COM * operations for panic dump, or mutex/cv for live dump.
27610843SDave.Plauger@Sun.COM *
27710843SDave.Plauger@Sun.COM * There a four queues, used as follows:
27810843SDave.Plauger@Sun.COM *
27910843SDave.Plauger@Sun.COM * Queue Dataflow NewState
28010843SDave.Plauger@Sun.COM * --------------------------------------------------
28110843SDave.Plauger@Sun.COM * mainq master -> master FREEMAP
28210843SDave.Plauger@Sun.COM * master has initialized or unmapped an input buffer
28310843SDave.Plauger@Sun.COM * --------------------------------------------------
28410843SDave.Plauger@Sun.COM * helperq master -> helper INREADY
28510843SDave.Plauger@Sun.COM * master has mapped input for use by helper
28610843SDave.Plauger@Sun.COM * --------------------------------------------------
28710843SDave.Plauger@Sun.COM * mainq master <- helper USEDMAP
28810843SDave.Plauger@Sun.COM * helper is done with input
28910843SDave.Plauger@Sun.COM * --------------------------------------------------
29010843SDave.Plauger@Sun.COM * freebufq master -> helper FREEBUF
29110843SDave.Plauger@Sun.COM * master has initialized or written an output buffer
29210843SDave.Plauger@Sun.COM * --------------------------------------------------
29310843SDave.Plauger@Sun.COM * mainq master <- helper WRITE
29410843SDave.Plauger@Sun.COM * block of compressed pages from a helper
29510843SDave.Plauger@Sun.COM * --------------------------------------------------
29610843SDave.Plauger@Sun.COM * mainq master <- helper ERRMSG
29710843SDave.Plauger@Sun.COM * error messages from a helper (memory error case)
29810843SDave.Plauger@Sun.COM * --------------------------------------------------
29910843SDave.Plauger@Sun.COM * writerq master <- master WRITE
30010843SDave.Plauger@Sun.COM * non-blocking queue of blocks to write
30110843SDave.Plauger@Sun.COM * --------------------------------------------------
30210843SDave.Plauger@Sun.COM */
30310843SDave.Plauger@Sun.COM typedef struct cqueue {
30410843SDave.Plauger@Sun.COM cbuf_t *volatile first; /* first in list */
30510843SDave.Plauger@Sun.COM cbuf_t *last; /* last in list */
30610843SDave.Plauger@Sun.COM hrtime_t ts; /* timestamp */
30710843SDave.Plauger@Sun.COM hrtime_t empty; /* total time empty */
30810843SDave.Plauger@Sun.COM kmutex_t mutex; /* live state lock */
30910843SDave.Plauger@Sun.COM kcondvar_t cv; /* live wait var */
31010843SDave.Plauger@Sun.COM lock_t spinlock; /* panic mode spin lock */
31110843SDave.Plauger@Sun.COM volatile uint_t open; /* producer ref count */
31210843SDave.Plauger@Sun.COM } cqueue_t;
31310843SDave.Plauger@Sun.COM
31410843SDave.Plauger@Sun.COM /*
31510843SDave.Plauger@Sun.COM * Convenience macros for using the cqueue functions
31610843SDave.Plauger@Sun.COM * Note that the caller must have defined "dumpsync_t *ds"
31710843SDave.Plauger@Sun.COM */
31810843SDave.Plauger@Sun.COM #define CQ_IS_EMPTY(q) \
31910843SDave.Plauger@Sun.COM (ds->q.first == NULL)
32010843SDave.Plauger@Sun.COM
32110843SDave.Plauger@Sun.COM #define CQ_OPEN(q) \
32210843SDave.Plauger@Sun.COM atomic_inc_uint(&ds->q.open)
32310843SDave.Plauger@Sun.COM
32410843SDave.Plauger@Sun.COM #define CQ_CLOSE(q) \
32510843SDave.Plauger@Sun.COM dumpsys_close_cq(&ds->q, ds->live)
32610843SDave.Plauger@Sun.COM
32710843SDave.Plauger@Sun.COM #define CQ_PUT(q, cp, st) \
32810843SDave.Plauger@Sun.COM dumpsys_put_cq(&ds->q, cp, st, ds->live)
32910843SDave.Plauger@Sun.COM
33010843SDave.Plauger@Sun.COM #define CQ_GET(q) \
33110843SDave.Plauger@Sun.COM dumpsys_get_cq(&ds->q, ds->live)
33210843SDave.Plauger@Sun.COM
33310843SDave.Plauger@Sun.COM /*
33410843SDave.Plauger@Sun.COM * Dynamic state when dumpsys() is running.
3350Sstevel@tonic-gate */
33610843SDave.Plauger@Sun.COM typedef struct dumpsync {
33710843SDave.Plauger@Sun.COM pgcnt_t npages; /* subtotal of pages dumped */
33810843SDave.Plauger@Sun.COM pgcnt_t pages_mapped; /* subtotal of pages mapped */
33910843SDave.Plauger@Sun.COM pgcnt_t pages_used; /* subtotal of pages used per map */
34010843SDave.Plauger@Sun.COM size_t nwrite; /* subtotal of bytes written */
34110843SDave.Plauger@Sun.COM uint_t live; /* running live dump */
34210843SDave.Plauger@Sun.COM uint_t neednl; /* will need to print a newline */
34310843SDave.Plauger@Sun.COM uint_t percent; /* dump progress */
34410843SDave.Plauger@Sun.COM uint_t percent_done; /* dump progress reported */
34510843SDave.Plauger@Sun.COM cqueue_t freebufq; /* free kmem bufs for writing */
34610843SDave.Plauger@Sun.COM cqueue_t mainq; /* input for main task */
34710843SDave.Plauger@Sun.COM cqueue_t helperq; /* input for helpers */
34810843SDave.Plauger@Sun.COM cqueue_t writerq; /* input for writer */
34910843SDave.Plauger@Sun.COM hrtime_t start; /* start time */
35010843SDave.Plauger@Sun.COM hrtime_t elapsed; /* elapsed time when completed */
35110843SDave.Plauger@Sun.COM hrtime_t iotime; /* time spent writing nwrite bytes */
35210843SDave.Plauger@Sun.COM hrtime_t iowait; /* time spent waiting for output */
35310843SDave.Plauger@Sun.COM hrtime_t iowaitts; /* iowait timestamp */
35410843SDave.Plauger@Sun.COM perpage_t perpage; /* metrics */
35510843SDave.Plauger@Sun.COM perpage_t perpagets;
35610843SDave.Plauger@Sun.COM int dumpcpu; /* master cpu */
35710843SDave.Plauger@Sun.COM } dumpsync_t;
35810843SDave.Plauger@Sun.COM
35910843SDave.Plauger@Sun.COM static dumpsync_t dumpsync; /* synchronization vars */
36010843SDave.Plauger@Sun.COM
36110843SDave.Plauger@Sun.COM /*
36210843SDave.Plauger@Sun.COM * helper_t helpers: contains the context for a stream. CPUs run in
36310843SDave.Plauger@Sun.COM * parallel at dump time; each CPU creates a single stream of
36410843SDave.Plauger@Sun.COM * compression data. Stream data is divided into CBUF_SIZE blocks.
36510843SDave.Plauger@Sun.COM * The blocks are written in order within a stream. But, blocks from
36610843SDave.Plauger@Sun.COM * multiple streams can be interleaved. Each stream is identified by a
36710843SDave.Plauger@Sun.COM * unique tag.
36810843SDave.Plauger@Sun.COM */
36910843SDave.Plauger@Sun.COM typedef struct helper {
37010843SDave.Plauger@Sun.COM int helper; /* bound helper id */
37110843SDave.Plauger@Sun.COM int tag; /* compression stream tag */
37210843SDave.Plauger@Sun.COM perpage_t perpage; /* per page metrics */
37310843SDave.Plauger@Sun.COM perpage_t perpagets; /* per page metrics (timestamps) */
37410843SDave.Plauger@Sun.COM taskqid_t taskqid; /* live dump task ptr */
37510843SDave.Plauger@Sun.COM int in, out; /* buffer offsets */
37610843SDave.Plauger@Sun.COM cbuf_t *cpin, *cpout, *cperr; /* cbuf objects in process */
37710843SDave.Plauger@Sun.COM dumpsync_t *ds; /* pointer to sync vars */
37810843SDave.Plauger@Sun.COM size_t used; /* counts input consumed */
37910843SDave.Plauger@Sun.COM char *page; /* buffer for page copy */
38010843SDave.Plauger@Sun.COM char *lzbuf; /* lzjb output */
38110843SDave.Plauger@Sun.COM bz_stream bzstream; /* bzip2 state */
38210843SDave.Plauger@Sun.COM } helper_t;
38310843SDave.Plauger@Sun.COM
38410843SDave.Plauger@Sun.COM #define MAINHELPER (-1) /* helper is also the main task */
38510843SDave.Plauger@Sun.COM #define FREEHELPER (-2) /* unbound helper */
38610843SDave.Plauger@Sun.COM #define DONEHELPER (-3) /* helper finished */
38710843SDave.Plauger@Sun.COM
38810843SDave.Plauger@Sun.COM /*
38910843SDave.Plauger@Sun.COM * configuration vars for dumpsys
39010843SDave.Plauger@Sun.COM */
39110843SDave.Plauger@Sun.COM typedef struct dumpcfg {
39210843SDave.Plauger@Sun.COM int threshold; /* ncpu threshold for bzip2 */
39310843SDave.Plauger@Sun.COM int nhelper; /* number of helpers */
39410843SDave.Plauger@Sun.COM int nhelper_used; /* actual number of helpers used */
39510843SDave.Plauger@Sun.COM int ncmap; /* number VA pages for compression */
39610843SDave.Plauger@Sun.COM int ncbuf; /* number of bufs for compression */
39710843SDave.Plauger@Sun.COM int ncbuf_used; /* number of bufs in use */
39810843SDave.Plauger@Sun.COM uint_t clevel; /* dump compression level */
39910843SDave.Plauger@Sun.COM helper_t *helper; /* array of helpers */
40010843SDave.Plauger@Sun.COM cbuf_t *cmap; /* array of input (map) buffers */
40110843SDave.Plauger@Sun.COM cbuf_t *cbuf; /* array of output buffers */
40210843SDave.Plauger@Sun.COM ulong_t *helpermap; /* set of dumpsys helper CPU ids */
40310843SDave.Plauger@Sun.COM ulong_t *bitmap; /* bitmap for marking pages to dump */
40410843SDave.Plauger@Sun.COM ulong_t *rbitmap; /* bitmap for used CBUF_MAPSIZE ranges */
40510843SDave.Plauger@Sun.COM pgcnt_t bitmapsize; /* size of bitmap */
40610843SDave.Plauger@Sun.COM pgcnt_t rbitmapsize; /* size of bitmap for ranges */
40710843SDave.Plauger@Sun.COM pgcnt_t found4m; /* number ranges allocated by dump */
40810843SDave.Plauger@Sun.COM pgcnt_t foundsm; /* number small pages allocated by dump */
40910843SDave.Plauger@Sun.COM pid_t *pids; /* list of process IDs at dump time */
41010843SDave.Plauger@Sun.COM size_t maxsize; /* memory size needed at dump time */
41110843SDave.Plauger@Sun.COM size_t maxvmsize; /* size of reserved VM */
41210843SDave.Plauger@Sun.COM char *maxvm; /* reserved VM for spare pages */
41310843SDave.Plauger@Sun.COM lock_t helper_lock; /* protect helper state */
41410843SDave.Plauger@Sun.COM char helpers_wanted; /* flag to enable parallelism */
41510843SDave.Plauger@Sun.COM } dumpcfg_t;
41610843SDave.Plauger@Sun.COM
41710843SDave.Plauger@Sun.COM static dumpcfg_t dumpcfg; /* config vars */
41810843SDave.Plauger@Sun.COM
41910843SDave.Plauger@Sun.COM /*
42010843SDave.Plauger@Sun.COM * The dump I/O buffer.
42110843SDave.Plauger@Sun.COM *
42210843SDave.Plauger@Sun.COM * There is one I/O buffer used by dumpvp_write and dumvp_flush. It is
42310843SDave.Plauger@Sun.COM * sized according to the optimum device transfer speed.
42410843SDave.Plauger@Sun.COM */
42510843SDave.Plauger@Sun.COM typedef struct dumpbuf {
42610843SDave.Plauger@Sun.COM vnode_t *cdev_vp; /* VCHR open of the dump device */
42710843SDave.Plauger@Sun.COM len_t vp_limit; /* maximum write offset */
42810843SDave.Plauger@Sun.COM offset_t vp_off; /* current dump device offset */
42910843SDave.Plauger@Sun.COM char *cur; /* dump write pointer */
43010843SDave.Plauger@Sun.COM char *start; /* dump buffer address */
43110843SDave.Plauger@Sun.COM char *end; /* dump buffer end */
43210843SDave.Plauger@Sun.COM size_t size; /* size of dumpbuf in bytes */
43310843SDave.Plauger@Sun.COM size_t iosize; /* best transfer size for device */
43410843SDave.Plauger@Sun.COM } dumpbuf_t;
43510843SDave.Plauger@Sun.COM
43610843SDave.Plauger@Sun.COM dumpbuf_t dumpbuf; /* I/O buffer */
43710843SDave.Plauger@Sun.COM
43810843SDave.Plauger@Sun.COM /*
43910843SDave.Plauger@Sun.COM * The dump I/O buffer must be at least one page, at most xfer_size
44010843SDave.Plauger@Sun.COM * bytes, and should scale with physmem in between. The transfer size
44110843SDave.Plauger@Sun.COM * passed in will either represent a global default (maxphys) or the
44210843SDave.Plauger@Sun.COM * best size for the device. The size of the dumpbuf I/O buffer is
44310843SDave.Plauger@Sun.COM * limited by dumpbuf_limit (8MB by default) because the dump
44410843SDave.Plauger@Sun.COM * performance saturates beyond a certain size. The default is to
44510843SDave.Plauger@Sun.COM * select 1/4096 of the memory.
44610843SDave.Plauger@Sun.COM */
44710843SDave.Plauger@Sun.COM static int dumpbuf_fraction = 12; /* memory size scale factor */
44810843SDave.Plauger@Sun.COM static size_t dumpbuf_limit = 8 * DUMP_1MB; /* max I/O buf size */
44910843SDave.Plauger@Sun.COM
4500Sstevel@tonic-gate static size_t
dumpbuf_iosize(size_t xfer_size)4510Sstevel@tonic-gate dumpbuf_iosize(size_t xfer_size)
4520Sstevel@tonic-gate {
45310843SDave.Plauger@Sun.COM size_t iosize = ptob(physmem >> dumpbuf_fraction);
45410843SDave.Plauger@Sun.COM
45510843SDave.Plauger@Sun.COM if (iosize < PAGESIZE)
45610843SDave.Plauger@Sun.COM iosize = PAGESIZE;
45710843SDave.Plauger@Sun.COM else if (iosize > xfer_size)
45810843SDave.Plauger@Sun.COM iosize = xfer_size;
45910843SDave.Plauger@Sun.COM if (iosize > dumpbuf_limit)
46010843SDave.Plauger@Sun.COM iosize = dumpbuf_limit;
46110843SDave.Plauger@Sun.COM return (iosize & PAGEMASK);
4620Sstevel@tonic-gate }
4630Sstevel@tonic-gate
46410843SDave.Plauger@Sun.COM /*
46510843SDave.Plauger@Sun.COM * resize the I/O buffer
46610843SDave.Plauger@Sun.COM */
4670Sstevel@tonic-gate static void
dumpbuf_resize(void)4680Sstevel@tonic-gate dumpbuf_resize(void)
4690Sstevel@tonic-gate {
47010843SDave.Plauger@Sun.COM char *old_buf = dumpbuf.start;
47110843SDave.Plauger@Sun.COM size_t old_size = dumpbuf.size;
4720Sstevel@tonic-gate char *new_buf;
4730Sstevel@tonic-gate size_t new_size;
4740Sstevel@tonic-gate
4750Sstevel@tonic-gate ASSERT(MUTEX_HELD(&dump_lock));
4760Sstevel@tonic-gate
47710843SDave.Plauger@Sun.COM new_size = dumpbuf_iosize(MAX(dumpbuf.iosize, maxphys));
47810843SDave.Plauger@Sun.COM if (new_size <= old_size)
4790Sstevel@tonic-gate return; /* no need to reallocate buffer */
4800Sstevel@tonic-gate
4810Sstevel@tonic-gate new_buf = kmem_alloc(new_size, KM_SLEEP);
48210843SDave.Plauger@Sun.COM dumpbuf.size = new_size;
48310843SDave.Plauger@Sun.COM dumpbuf.start = new_buf;
48410843SDave.Plauger@Sun.COM dumpbuf.end = new_buf + new_size;
4850Sstevel@tonic-gate kmem_free(old_buf, old_size);
4860Sstevel@tonic-gate }
4870Sstevel@tonic-gate
48810843SDave.Plauger@Sun.COM /*
48910843SDave.Plauger@Sun.COM * dump_update_clevel is called when dumpadm configures the dump device.
49010843SDave.Plauger@Sun.COM * Calculate number of helpers and buffers.
49110843SDave.Plauger@Sun.COM * Allocate the minimum configuration for now.
49210843SDave.Plauger@Sun.COM *
49310843SDave.Plauger@Sun.COM * When the dump file is configured we reserve a minimum amount of
49410843SDave.Plauger@Sun.COM * memory for use at crash time. But we reserve VA for all the memory
49510843SDave.Plauger@Sun.COM * we really want in order to do the fastest dump possible. The VA is
49610843SDave.Plauger@Sun.COM * backed by pages not being dumped, according to the bitmap. If
49710843SDave.Plauger@Sun.COM * there is insufficient spare memory, however, we fall back to the
49810843SDave.Plauger@Sun.COM * minimum.
49910843SDave.Plauger@Sun.COM *
50010843SDave.Plauger@Sun.COM * Live dump (savecore -L) always uses the minimum config.
50110843SDave.Plauger@Sun.COM *
50210843SDave.Plauger@Sun.COM * clevel 0 is single threaded lzjb
50310843SDave.Plauger@Sun.COM * clevel 1 is parallel lzjb
50410843SDave.Plauger@Sun.COM * clevel 2 is parallel bzip2
50510843SDave.Plauger@Sun.COM *
50610843SDave.Plauger@Sun.COM * The ncpu threshold is selected with dump_plat_mincpu.
50710843SDave.Plauger@Sun.COM * On OPL, set_platform_defaults() overrides the sun4u setting.
50810843SDave.Plauger@Sun.COM * The actual values are defined via DUMP_PLAT_*_MINCPU macros.
50910843SDave.Plauger@Sun.COM *
51010843SDave.Plauger@Sun.COM * Architecture Threshold Algorithm
51110843SDave.Plauger@Sun.COM * sun4u < 51 parallel lzjb
51210843SDave.Plauger@Sun.COM * sun4u >= 51 parallel bzip2(*)
51310843SDave.Plauger@Sun.COM * sun4u OPL < 8 parallel lzjb
51410843SDave.Plauger@Sun.COM * sun4u OPL >= 8 parallel bzip2(*)
51510843SDave.Plauger@Sun.COM * sun4v < 128 parallel lzjb
51610843SDave.Plauger@Sun.COM * sun4v >= 128 parallel bzip2(*)
51710843SDave.Plauger@Sun.COM * x86 < 11 parallel lzjb
51810843SDave.Plauger@Sun.COM * x86 >= 11 parallel bzip2(*)
51910843SDave.Plauger@Sun.COM * 32-bit N/A single-threaded lzjb
52010843SDave.Plauger@Sun.COM *
52110843SDave.Plauger@Sun.COM * (*) bzip2 is only chosen if there is sufficient available
52210843SDave.Plauger@Sun.COM * memory for buffers at dump time. See dumpsys_get_maxmem().
52310843SDave.Plauger@Sun.COM *
52410843SDave.Plauger@Sun.COM * Faster dump devices have larger I/O buffers. The threshold value is
52510843SDave.Plauger@Sun.COM * increased according to the size of the dump I/O buffer, because
52610843SDave.Plauger@Sun.COM * parallel lzjb performs better with faster disks. For buffers >= 1MB
52710843SDave.Plauger@Sun.COM * the threshold is 3X; for buffers >= 256K threshold is 2X.
52810843SDave.Plauger@Sun.COM *
52910843SDave.Plauger@Sun.COM * For parallel dumps, the number of helpers is ncpu-1. The CPU
53010843SDave.Plauger@Sun.COM * running panic runs the main task. For single-threaded dumps, the
53110843SDave.Plauger@Sun.COM * panic CPU does lzjb compression (it is tagged as MAINHELPER.)
53210843SDave.Plauger@Sun.COM *
53310843SDave.Plauger@Sun.COM * Need multiple buffers per helper so that they do not block waiting
53410843SDave.Plauger@Sun.COM * for the main task.
53510843SDave.Plauger@Sun.COM * parallel single-threaded
53610843SDave.Plauger@Sun.COM * Number of output buffers: nhelper*2 1
53710843SDave.Plauger@Sun.COM * Number of mapping buffers: nhelper*4 1
53810843SDave.Plauger@Sun.COM *
53910843SDave.Plauger@Sun.COM */
54010843SDave.Plauger@Sun.COM static void
dump_update_clevel()54110843SDave.Plauger@Sun.COM dump_update_clevel()
54210843SDave.Plauger@Sun.COM {
54310843SDave.Plauger@Sun.COM int tag;
54410843SDave.Plauger@Sun.COM size_t bz2size;
54510843SDave.Plauger@Sun.COM helper_t *hp, *hpend;
54610843SDave.Plauger@Sun.COM cbuf_t *cp, *cpend;
54710843SDave.Plauger@Sun.COM dumpcfg_t *old = &dumpcfg;
54810843SDave.Plauger@Sun.COM dumpcfg_t newcfg = *old;
54910843SDave.Plauger@Sun.COM dumpcfg_t *new = &newcfg;
55010843SDave.Plauger@Sun.COM
55110843SDave.Plauger@Sun.COM ASSERT(MUTEX_HELD(&dump_lock));
55210843SDave.Plauger@Sun.COM
55310843SDave.Plauger@Sun.COM /*
55410843SDave.Plauger@Sun.COM * Free the previously allocated bufs and VM.
55510843SDave.Plauger@Sun.COM */
55610843SDave.Plauger@Sun.COM if (old->helper != NULL) {
55710843SDave.Plauger@Sun.COM
55810843SDave.Plauger@Sun.COM /* helpers */
55910843SDave.Plauger@Sun.COM hpend = &old->helper[old->nhelper];
56010843SDave.Plauger@Sun.COM for (hp = old->helper; hp != hpend; hp++) {
56110843SDave.Plauger@Sun.COM if (hp->lzbuf != NULL)
56210843SDave.Plauger@Sun.COM kmem_free(hp->lzbuf, PAGESIZE);
56310843SDave.Plauger@Sun.COM if (hp->page != NULL)
56410843SDave.Plauger@Sun.COM kmem_free(hp->page, PAGESIZE);
56510843SDave.Plauger@Sun.COM }
56610843SDave.Plauger@Sun.COM kmem_free(old->helper, old->nhelper * sizeof (helper_t));
56710843SDave.Plauger@Sun.COM
56810843SDave.Plauger@Sun.COM /* VM space for mapping pages */
56910843SDave.Plauger@Sun.COM cpend = &old->cmap[old->ncmap];
57010843SDave.Plauger@Sun.COM for (cp = old->cmap; cp != cpend; cp++)
57110843SDave.Plauger@Sun.COM vmem_xfree(heap_arena, cp->buf, CBUF_MAPSIZE);
57210843SDave.Plauger@Sun.COM kmem_free(old->cmap, old->ncmap * sizeof (cbuf_t));
57310843SDave.Plauger@Sun.COM
57410843SDave.Plauger@Sun.COM /* output bufs */
57510843SDave.Plauger@Sun.COM cpend = &old->cbuf[old->ncbuf];
57610843SDave.Plauger@Sun.COM for (cp = old->cbuf; cp != cpend; cp++)
57710843SDave.Plauger@Sun.COM if (cp->buf != NULL)
57810843SDave.Plauger@Sun.COM kmem_free(cp->buf, cp->size);
57910843SDave.Plauger@Sun.COM kmem_free(old->cbuf, old->ncbuf * sizeof (cbuf_t));
58010843SDave.Plauger@Sun.COM
58110843SDave.Plauger@Sun.COM /* reserved VM for dumpsys_get_maxmem */
58210843SDave.Plauger@Sun.COM if (old->maxvmsize > 0)
58310843SDave.Plauger@Sun.COM vmem_xfree(heap_arena, old->maxvm, old->maxvmsize);
58410843SDave.Plauger@Sun.COM }
58510843SDave.Plauger@Sun.COM
58610843SDave.Plauger@Sun.COM /*
58710843SDave.Plauger@Sun.COM * Allocate memory and VM.
58810843SDave.Plauger@Sun.COM * One CPU runs dumpsys, the rest are helpers.
58910843SDave.Plauger@Sun.COM */
59010843SDave.Plauger@Sun.COM new->nhelper = ncpus - 1;
59110843SDave.Plauger@Sun.COM if (new->nhelper < 1)
59210843SDave.Plauger@Sun.COM new->nhelper = 1;
59310843SDave.Plauger@Sun.COM
59410843SDave.Plauger@Sun.COM if (new->nhelper > DUMP_MAX_NHELPER)
59510843SDave.Plauger@Sun.COM new->nhelper = DUMP_MAX_NHELPER;
59610843SDave.Plauger@Sun.COM
59712931SDave.Plauger@Sun.COM /* use platform default, unless /etc/system overrides */
59812931SDave.Plauger@Sun.COM if (dump_plat_mincpu == MINCPU_NOT_SET)
59912931SDave.Plauger@Sun.COM dump_plat_mincpu = dump_plat_mincpu_default;
60012931SDave.Plauger@Sun.COM
60110843SDave.Plauger@Sun.COM /* increase threshold for faster disks */
60210843SDave.Plauger@Sun.COM new->threshold = dump_plat_mincpu;
60310843SDave.Plauger@Sun.COM if (dumpbuf.iosize >= DUMP_1MB)
60410843SDave.Plauger@Sun.COM new->threshold *= 3;
60510843SDave.Plauger@Sun.COM else if (dumpbuf.iosize >= (256 * DUMP_1KB))
60610843SDave.Plauger@Sun.COM new->threshold *= 2;
60710843SDave.Plauger@Sun.COM
60810843SDave.Plauger@Sun.COM /* figure compression level based upon the computed threshold. */
60910843SDave.Plauger@Sun.COM if (dump_plat_mincpu == 0 || new->nhelper < 2) {
61010843SDave.Plauger@Sun.COM new->clevel = 0;
61110843SDave.Plauger@Sun.COM new->nhelper = 1;
61210843SDave.Plauger@Sun.COM } else if ((new->nhelper + 1) >= new->threshold) {
61310843SDave.Plauger@Sun.COM new->clevel = DUMP_CLEVEL_BZIP2;
61410843SDave.Plauger@Sun.COM } else {
61510843SDave.Plauger@Sun.COM new->clevel = DUMP_CLEVEL_LZJB;
61610843SDave.Plauger@Sun.COM }
61710843SDave.Plauger@Sun.COM
61810843SDave.Plauger@Sun.COM if (new->clevel == 0) {
61910843SDave.Plauger@Sun.COM new->ncbuf = 1;
62010843SDave.Plauger@Sun.COM new->ncmap = 1;
62110843SDave.Plauger@Sun.COM } else {
62210843SDave.Plauger@Sun.COM new->ncbuf = NCBUF_PER_HELPER * new->nhelper;
62310843SDave.Plauger@Sun.COM new->ncmap = NCMAP_PER_HELPER * new->nhelper;
62410843SDave.Plauger@Sun.COM }
62510843SDave.Plauger@Sun.COM
62610843SDave.Plauger@Sun.COM /*
62710843SDave.Plauger@Sun.COM * Allocate new data structures and buffers for MINHELPERS,
62810843SDave.Plauger@Sun.COM * and also figure the max desired size.
62910843SDave.Plauger@Sun.COM */
63010843SDave.Plauger@Sun.COM bz2size = BZ2_bzCompressInitSize(dump_bzip2_level);
63110843SDave.Plauger@Sun.COM new->maxsize = 0;
63210843SDave.Plauger@Sun.COM new->maxvmsize = 0;
63310843SDave.Plauger@Sun.COM new->maxvm = NULL;
63410843SDave.Plauger@Sun.COM tag = 1;
63510843SDave.Plauger@Sun.COM new->helper = kmem_zalloc(new->nhelper * sizeof (helper_t), KM_SLEEP);
63610843SDave.Plauger@Sun.COM hpend = &new->helper[new->nhelper];
63710843SDave.Plauger@Sun.COM for (hp = new->helper; hp != hpend; hp++) {
63810843SDave.Plauger@Sun.COM hp->tag = tag++;
63910843SDave.Plauger@Sun.COM if (hp < &new->helper[MINHELPERS]) {
64010843SDave.Plauger@Sun.COM hp->lzbuf = kmem_alloc(PAGESIZE, KM_SLEEP);
64110843SDave.Plauger@Sun.COM hp->page = kmem_alloc(PAGESIZE, KM_SLEEP);
64210843SDave.Plauger@Sun.COM } else if (new->clevel < DUMP_CLEVEL_BZIP2) {
64310843SDave.Plauger@Sun.COM new->maxsize += 2 * PAGESIZE;
64410843SDave.Plauger@Sun.COM } else {
64510843SDave.Plauger@Sun.COM new->maxsize += PAGESIZE;
64610843SDave.Plauger@Sun.COM }
64710843SDave.Plauger@Sun.COM if (new->clevel >= DUMP_CLEVEL_BZIP2)
64810843SDave.Plauger@Sun.COM new->maxsize += bz2size;
64910843SDave.Plauger@Sun.COM }
65010843SDave.Plauger@Sun.COM
65110843SDave.Plauger@Sun.COM new->cbuf = kmem_zalloc(new->ncbuf * sizeof (cbuf_t), KM_SLEEP);
65210843SDave.Plauger@Sun.COM cpend = &new->cbuf[new->ncbuf];
65310843SDave.Plauger@Sun.COM for (cp = new->cbuf; cp != cpend; cp++) {
65410843SDave.Plauger@Sun.COM cp->state = CBUF_FREEBUF;
65510843SDave.Plauger@Sun.COM cp->size = CBUF_SIZE;
65610843SDave.Plauger@Sun.COM if (cp < &new->cbuf[MINCBUFS])
65710843SDave.Plauger@Sun.COM cp->buf = kmem_alloc(cp->size, KM_SLEEP);
65810843SDave.Plauger@Sun.COM else
65910843SDave.Plauger@Sun.COM new->maxsize += cp->size;
66010843SDave.Plauger@Sun.COM }
66110843SDave.Plauger@Sun.COM
66210843SDave.Plauger@Sun.COM new->cmap = kmem_zalloc(new->ncmap * sizeof (cbuf_t), KM_SLEEP);
66310843SDave.Plauger@Sun.COM cpend = &new->cmap[new->ncmap];
66410843SDave.Plauger@Sun.COM for (cp = new->cmap; cp != cpend; cp++) {
66510843SDave.Plauger@Sun.COM cp->state = CBUF_FREEMAP;
66610843SDave.Plauger@Sun.COM cp->size = CBUF_MAPSIZE;
66710843SDave.Plauger@Sun.COM cp->buf = vmem_xalloc(heap_arena, CBUF_MAPSIZE, CBUF_MAPSIZE,
66810843SDave.Plauger@Sun.COM 0, 0, NULL, NULL, VM_SLEEP);
66910843SDave.Plauger@Sun.COM }
67010843SDave.Plauger@Sun.COM
67110843SDave.Plauger@Sun.COM /* reserve VA to be backed with spare pages at crash time */
67210843SDave.Plauger@Sun.COM if (new->maxsize > 0) {
67310843SDave.Plauger@Sun.COM new->maxsize = P2ROUNDUP(new->maxsize, PAGESIZE);
67410843SDave.Plauger@Sun.COM new->maxvmsize = P2ROUNDUP(new->maxsize, CBUF_MAPSIZE);
67510843SDave.Plauger@Sun.COM new->maxvm = vmem_xalloc(heap_arena, new->maxvmsize,
67610843SDave.Plauger@Sun.COM CBUF_MAPSIZE, 0, 0, NULL, NULL, VM_SLEEP);
67710843SDave.Plauger@Sun.COM }
67810843SDave.Plauger@Sun.COM
67911178SDave.Plauger@Sun.COM /*
68011178SDave.Plauger@Sun.COM * Reserve memory for kmem allocation calls made during crash
68111178SDave.Plauger@Sun.COM * dump. The hat layer allocates memory for each mapping
68211178SDave.Plauger@Sun.COM * created, and the I/O path allocates buffers and data structs.
68311178SDave.Plauger@Sun.COM * Add a few pages for safety.
68411178SDave.Plauger@Sun.COM */
68511178SDave.Plauger@Sun.COM kmem_dump_init((new->ncmap * dump_kmem_permap) +
68611178SDave.Plauger@Sun.COM (dump_kmem_pages * PAGESIZE));
68711178SDave.Plauger@Sun.COM
68810843SDave.Plauger@Sun.COM /* set new config pointers */
68910843SDave.Plauger@Sun.COM *old = *new;
69010843SDave.Plauger@Sun.COM }
69110843SDave.Plauger@Sun.COM
69210843SDave.Plauger@Sun.COM /*
69310843SDave.Plauger@Sun.COM * Define a struct memlist walker to optimize bitnum to pfn
69410843SDave.Plauger@Sun.COM * lookup. The walker maintains the state of the list traversal.
69510843SDave.Plauger@Sun.COM */
69610843SDave.Plauger@Sun.COM typedef struct dumpmlw {
69710843SDave.Plauger@Sun.COM struct memlist *mp; /* current memlist */
69810843SDave.Plauger@Sun.COM pgcnt_t basenum; /* bitnum base offset */
69910843SDave.Plauger@Sun.COM pgcnt_t mppages; /* current memlist size */
70010843SDave.Plauger@Sun.COM pgcnt_t mpleft; /* size to end of current memlist */
70110843SDave.Plauger@Sun.COM pfn_t mpaddr; /* first pfn in memlist */
70210843SDave.Plauger@Sun.COM } dumpmlw_t;
70310843SDave.Plauger@Sun.COM
70410843SDave.Plauger@Sun.COM /* initialize the walker */
70510843SDave.Plauger@Sun.COM static inline void
dump_init_memlist_walker(dumpmlw_t * pw)70610843SDave.Plauger@Sun.COM dump_init_memlist_walker(dumpmlw_t *pw)
70710843SDave.Plauger@Sun.COM {
70810843SDave.Plauger@Sun.COM pw->mp = phys_install;
70910843SDave.Plauger@Sun.COM pw->basenum = 0;
71011474SJonathan.Adams@Sun.COM pw->mppages = pw->mp->ml_size >> PAGESHIFT;
71110843SDave.Plauger@Sun.COM pw->mpleft = pw->mppages;
71211474SJonathan.Adams@Sun.COM pw->mpaddr = pw->mp->ml_address >> PAGESHIFT;
71310843SDave.Plauger@Sun.COM }
71410843SDave.Plauger@Sun.COM
71510843SDave.Plauger@Sun.COM /*
71610843SDave.Plauger@Sun.COM * Lookup pfn given bitnum. The memlist can be quite long on some
71710843SDave.Plauger@Sun.COM * systems (e.g.: one per board). To optimize sequential lookups, the
71810843SDave.Plauger@Sun.COM * caller initializes and presents a memlist walker.
71910843SDave.Plauger@Sun.COM */
72010843SDave.Plauger@Sun.COM static pfn_t
dump_bitnum_to_pfn(pgcnt_t bitnum,dumpmlw_t * pw)72110843SDave.Plauger@Sun.COM dump_bitnum_to_pfn(pgcnt_t bitnum, dumpmlw_t *pw)
72210843SDave.Plauger@Sun.COM {
72310843SDave.Plauger@Sun.COM bitnum -= pw->basenum;
72410843SDave.Plauger@Sun.COM while (pw->mp != NULL) {
72510843SDave.Plauger@Sun.COM if (bitnum < pw->mppages) {
72610843SDave.Plauger@Sun.COM pw->mpleft = pw->mppages - bitnum;
72710843SDave.Plauger@Sun.COM return (pw->mpaddr + bitnum);
72810843SDave.Plauger@Sun.COM }
72910843SDave.Plauger@Sun.COM bitnum -= pw->mppages;
73010843SDave.Plauger@Sun.COM pw->basenum += pw->mppages;
73111474SJonathan.Adams@Sun.COM pw->mp = pw->mp->ml_next;
73210843SDave.Plauger@Sun.COM if (pw->mp != NULL) {
73311474SJonathan.Adams@Sun.COM pw->mppages = pw->mp->ml_size >> PAGESHIFT;
73410843SDave.Plauger@Sun.COM pw->mpleft = pw->mppages;
73511474SJonathan.Adams@Sun.COM pw->mpaddr = pw->mp->ml_address >> PAGESHIFT;
73610843SDave.Plauger@Sun.COM }
73710843SDave.Plauger@Sun.COM }
73810843SDave.Plauger@Sun.COM return (PFN_INVALID);
73910843SDave.Plauger@Sun.COM }
74010843SDave.Plauger@Sun.COM
74110843SDave.Plauger@Sun.COM static pgcnt_t
dump_pfn_to_bitnum(pfn_t pfn)74210843SDave.Plauger@Sun.COM dump_pfn_to_bitnum(pfn_t pfn)
74310843SDave.Plauger@Sun.COM {
74410843SDave.Plauger@Sun.COM struct memlist *mp;
74510843SDave.Plauger@Sun.COM pgcnt_t bitnum = 0;
74610843SDave.Plauger@Sun.COM
74711474SJonathan.Adams@Sun.COM for (mp = phys_install; mp != NULL; mp = mp->ml_next) {
74811474SJonathan.Adams@Sun.COM if (pfn >= (mp->ml_address >> PAGESHIFT) &&
74911474SJonathan.Adams@Sun.COM pfn < ((mp->ml_address + mp->ml_size) >> PAGESHIFT))
75011474SJonathan.Adams@Sun.COM return (bitnum + pfn - (mp->ml_address >> PAGESHIFT));
75111474SJonathan.Adams@Sun.COM bitnum += mp->ml_size >> PAGESHIFT;
75210843SDave.Plauger@Sun.COM }
75310843SDave.Plauger@Sun.COM return ((pgcnt_t)-1);
75410843SDave.Plauger@Sun.COM }
75510843SDave.Plauger@Sun.COM
75610843SDave.Plauger@Sun.COM /*
75710843SDave.Plauger@Sun.COM * Set/test bitmap for a CBUF_MAPSIZE range which includes pfn. The
75810843SDave.Plauger@Sun.COM * mapping of pfn to range index is imperfect because pfn and bitnum
75910843SDave.Plauger@Sun.COM * do not have the same phase. To make sure a CBUF_MAPSIZE range is
76010843SDave.Plauger@Sun.COM * covered, call this for both ends:
76110843SDave.Plauger@Sun.COM * dump_set_used(base)
76210843SDave.Plauger@Sun.COM * dump_set_used(base+CBUF_MAPNP-1)
76310843SDave.Plauger@Sun.COM *
76410843SDave.Plauger@Sun.COM * This is used during a panic dump to mark pages allocated by
76510843SDave.Plauger@Sun.COM * dumpsys_get_maxmem(). The macro IS_DUMP_PAGE(pp) is used by
76610843SDave.Plauger@Sun.COM * page_get_mnode_freelist() to make sure pages used by dump are never
76710843SDave.Plauger@Sun.COM * allocated.
76810843SDave.Plauger@Sun.COM */
76910843SDave.Plauger@Sun.COM #define CBUF_MAPP2R(pfn) ((pfn) >> (CBUF_MAPSHIFT - PAGESHIFT))
77010843SDave.Plauger@Sun.COM
77110843SDave.Plauger@Sun.COM static void
dump_set_used(pfn_t pfn)77210843SDave.Plauger@Sun.COM dump_set_used(pfn_t pfn)
77310843SDave.Plauger@Sun.COM {
77410843SDave.Plauger@Sun.COM
77510843SDave.Plauger@Sun.COM pgcnt_t bitnum, rbitnum;
77610843SDave.Plauger@Sun.COM
77710843SDave.Plauger@Sun.COM bitnum = dump_pfn_to_bitnum(pfn);
77810843SDave.Plauger@Sun.COM ASSERT(bitnum != (pgcnt_t)-1);
77910843SDave.Plauger@Sun.COM
78010843SDave.Plauger@Sun.COM rbitnum = CBUF_MAPP2R(bitnum);
78110843SDave.Plauger@Sun.COM ASSERT(rbitnum < dumpcfg.rbitmapsize);
78210843SDave.Plauger@Sun.COM
78310843SDave.Plauger@Sun.COM BT_SET(dumpcfg.rbitmap, rbitnum);
78410843SDave.Plauger@Sun.COM }
78510843SDave.Plauger@Sun.COM
78610843SDave.Plauger@Sun.COM int
dump_test_used(pfn_t pfn)78710843SDave.Plauger@Sun.COM dump_test_used(pfn_t pfn)
78810843SDave.Plauger@Sun.COM {
78910843SDave.Plauger@Sun.COM pgcnt_t bitnum, rbitnum;
79010843SDave.Plauger@Sun.COM
79110843SDave.Plauger@Sun.COM bitnum = dump_pfn_to_bitnum(pfn);
79210843SDave.Plauger@Sun.COM ASSERT(bitnum != (pgcnt_t)-1);
79310843SDave.Plauger@Sun.COM
79410843SDave.Plauger@Sun.COM rbitnum = CBUF_MAPP2R(bitnum);
79510843SDave.Plauger@Sun.COM ASSERT(rbitnum < dumpcfg.rbitmapsize);
79610843SDave.Plauger@Sun.COM
79710843SDave.Plauger@Sun.COM return (BT_TEST(dumpcfg.rbitmap, rbitnum));
79810843SDave.Plauger@Sun.COM }
79910843SDave.Plauger@Sun.COM
80010843SDave.Plauger@Sun.COM /*
80110843SDave.Plauger@Sun.COM * dumpbzalloc and dumpbzfree are callbacks from the bzip2 library.
80210843SDave.Plauger@Sun.COM * dumpsys_get_maxmem() uses them for BZ2_bzCompressInit().
80310843SDave.Plauger@Sun.COM */
80410843SDave.Plauger@Sun.COM static void *
dumpbzalloc(void * opaque,int items,int size)80510843SDave.Plauger@Sun.COM dumpbzalloc(void *opaque, int items, int size)
80610843SDave.Plauger@Sun.COM {
80710843SDave.Plauger@Sun.COM size_t *sz;
80810843SDave.Plauger@Sun.COM char *ret;
80910843SDave.Plauger@Sun.COM
81010843SDave.Plauger@Sun.COM ASSERT(opaque != NULL);
81110843SDave.Plauger@Sun.COM sz = opaque;
81210843SDave.Plauger@Sun.COM ret = dumpcfg.maxvm + *sz;
81310843SDave.Plauger@Sun.COM *sz += items * size;
81410843SDave.Plauger@Sun.COM *sz = P2ROUNDUP(*sz, BZ2_BZALLOC_ALIGN);
81510843SDave.Plauger@Sun.COM ASSERT(*sz <= dumpcfg.maxvmsize);
81610843SDave.Plauger@Sun.COM return (ret);
81710843SDave.Plauger@Sun.COM }
81810843SDave.Plauger@Sun.COM
81910843SDave.Plauger@Sun.COM /*ARGSUSED*/
82010843SDave.Plauger@Sun.COM static void
dumpbzfree(void * opaque,void * addr)82110843SDave.Plauger@Sun.COM dumpbzfree(void *opaque, void *addr)
82210843SDave.Plauger@Sun.COM {
82310843SDave.Plauger@Sun.COM }
82410843SDave.Plauger@Sun.COM
82510843SDave.Plauger@Sun.COM /*
82610843SDave.Plauger@Sun.COM * Perform additional checks on the page to see if we can really use
82710843SDave.Plauger@Sun.COM * it. The kernel (kas) pages are always set in the bitmap. However,
82810843SDave.Plauger@Sun.COM * boot memory pages (prom_ppages or P_BOOTPAGES) are not in the
82910843SDave.Plauger@Sun.COM * bitmap. So we check for them.
83010843SDave.Plauger@Sun.COM */
83110843SDave.Plauger@Sun.COM static inline int
dump_pfn_check(pfn_t pfn)83210843SDave.Plauger@Sun.COM dump_pfn_check(pfn_t pfn)
83310843SDave.Plauger@Sun.COM {
83410843SDave.Plauger@Sun.COM page_t *pp = page_numtopp_nolock(pfn);
83510843SDave.Plauger@Sun.COM if (pp == NULL || pp->p_pagenum != pfn ||
83610843SDave.Plauger@Sun.COM #if defined(__sparc)
83711185SSean.McEnroe@Sun.COM pp->p_vnode == &promvp ||
83810843SDave.Plauger@Sun.COM #else
83910843SDave.Plauger@Sun.COM PP_ISBOOTPAGES(pp) ||
84010843SDave.Plauger@Sun.COM #endif
84110843SDave.Plauger@Sun.COM pp->p_toxic != 0)
84210843SDave.Plauger@Sun.COM return (0);
84310843SDave.Plauger@Sun.COM return (1);
84410843SDave.Plauger@Sun.COM }
84510843SDave.Plauger@Sun.COM
84610843SDave.Plauger@Sun.COM /*
84710843SDave.Plauger@Sun.COM * Check a range to see if all contained pages are available and
84810843SDave.Plauger@Sun.COM * return non-zero if the range can be used.
84910843SDave.Plauger@Sun.COM */
85010843SDave.Plauger@Sun.COM static inline int
dump_range_check(pgcnt_t start,pgcnt_t end,pfn_t pfn)85110843SDave.Plauger@Sun.COM dump_range_check(pgcnt_t start, pgcnt_t end, pfn_t pfn)
85210843SDave.Plauger@Sun.COM {
85310843SDave.Plauger@Sun.COM for (; start < end; start++, pfn++) {
85410843SDave.Plauger@Sun.COM if (BT_TEST(dumpcfg.bitmap, start))
85510843SDave.Plauger@Sun.COM return (0);
85610843SDave.Plauger@Sun.COM if (!dump_pfn_check(pfn))
85710843SDave.Plauger@Sun.COM return (0);
85810843SDave.Plauger@Sun.COM }
85910843SDave.Plauger@Sun.COM return (1);
86010843SDave.Plauger@Sun.COM }
86110843SDave.Plauger@Sun.COM
86210843SDave.Plauger@Sun.COM /*
86310843SDave.Plauger@Sun.COM * dumpsys_get_maxmem() is called during panic. Find unused ranges
86410843SDave.Plauger@Sun.COM * and use them for buffers. If we find enough memory switch to
86510843SDave.Plauger@Sun.COM * parallel bzip2, otherwise use parallel lzjb.
86610843SDave.Plauger@Sun.COM *
86710843SDave.Plauger@Sun.COM * It searches the dump bitmap in 2 passes. The first time it looks
86810843SDave.Plauger@Sun.COM * for CBUF_MAPSIZE ranges. On the second pass it uses small pages.
86910843SDave.Plauger@Sun.COM */
87010843SDave.Plauger@Sun.COM static void
dumpsys_get_maxmem()87110843SDave.Plauger@Sun.COM dumpsys_get_maxmem()
87210843SDave.Plauger@Sun.COM {
87310843SDave.Plauger@Sun.COM dumpcfg_t *cfg = &dumpcfg;
87410843SDave.Plauger@Sun.COM cbuf_t *endcp = &cfg->cbuf[cfg->ncbuf];
87510843SDave.Plauger@Sun.COM helper_t *endhp = &cfg->helper[cfg->nhelper];
87610843SDave.Plauger@Sun.COM pgcnt_t bitnum, end;
87710843SDave.Plauger@Sun.COM size_t sz, endsz, bz2size;
87810843SDave.Plauger@Sun.COM pfn_t pfn, off;
87910843SDave.Plauger@Sun.COM cbuf_t *cp;
88010843SDave.Plauger@Sun.COM helper_t *hp, *ohp;
88110843SDave.Plauger@Sun.COM dumpmlw_t mlw;
88210843SDave.Plauger@Sun.COM int k;
88310843SDave.Plauger@Sun.COM
88412931SDave.Plauger@Sun.COM /*
885*13145SDave.Plauger@Sun.COM * Setting dump_plat_mincpu to 0 at any time forces a serial
886*13145SDave.Plauger@Sun.COM * dump.
88712931SDave.Plauger@Sun.COM */
888*13145SDave.Plauger@Sun.COM if (dump_plat_mincpu == 0) {
88912931SDave.Plauger@Sun.COM cfg->clevel = 0;
89012931SDave.Plauger@Sun.COM return;
89112931SDave.Plauger@Sun.COM }
89212931SDave.Plauger@Sun.COM
89312931SDave.Plauger@Sun.COM /*
89412931SDave.Plauger@Sun.COM * There may be no point in looking for spare memory. If
89512931SDave.Plauger@Sun.COM * dumping all memory, then none is spare. If doing a serial
89612931SDave.Plauger@Sun.COM * dump, then already have buffers.
89712931SDave.Plauger@Sun.COM */
89810843SDave.Plauger@Sun.COM if (cfg->maxsize == 0 || cfg->clevel < DUMP_CLEVEL_LZJB ||
89912042SDave.Plauger@Sun.COM (dump_conflags & DUMP_ALL) != 0) {
90012042SDave.Plauger@Sun.COM if (cfg->clevel > DUMP_CLEVEL_LZJB)
90112042SDave.Plauger@Sun.COM cfg->clevel = DUMP_CLEVEL_LZJB;
90210843SDave.Plauger@Sun.COM return;
90312042SDave.Plauger@Sun.COM }
90410843SDave.Plauger@Sun.COM
90510843SDave.Plauger@Sun.COM sz = 0;
90610843SDave.Plauger@Sun.COM cfg->found4m = 0;
90710843SDave.Plauger@Sun.COM cfg->foundsm = 0;
90810843SDave.Plauger@Sun.COM
90910843SDave.Plauger@Sun.COM /* bitmap of ranges used to estimate which pfns are being used */
91010843SDave.Plauger@Sun.COM bzero(dumpcfg.rbitmap, BT_SIZEOFMAP(dumpcfg.rbitmapsize));
91110843SDave.Plauger@Sun.COM
91210843SDave.Plauger@Sun.COM /* find ranges that are not being dumped to use for buffers */
91310843SDave.Plauger@Sun.COM dump_init_memlist_walker(&mlw);
91410843SDave.Plauger@Sun.COM for (bitnum = 0; bitnum < dumpcfg.bitmapsize; bitnum = end) {
91510843SDave.Plauger@Sun.COM dump_timeleft = dump_timeout;
91610843SDave.Plauger@Sun.COM end = bitnum + CBUF_MAPNP;
91710843SDave.Plauger@Sun.COM pfn = dump_bitnum_to_pfn(bitnum, &mlw);
91810843SDave.Plauger@Sun.COM ASSERT(pfn != PFN_INVALID);
91910843SDave.Plauger@Sun.COM
92010843SDave.Plauger@Sun.COM /* skip partial range at end of mem segment */
92110843SDave.Plauger@Sun.COM if (mlw.mpleft < CBUF_MAPNP) {
92210843SDave.Plauger@Sun.COM end = bitnum + mlw.mpleft;
92310843SDave.Plauger@Sun.COM continue;
92410843SDave.Plauger@Sun.COM }
92510843SDave.Plauger@Sun.COM
92610843SDave.Plauger@Sun.COM /* skip non aligned pages */
92710843SDave.Plauger@Sun.COM off = P2PHASE(pfn, CBUF_MAPNP);
92810843SDave.Plauger@Sun.COM if (off != 0) {
92910843SDave.Plauger@Sun.COM end -= off;
93010843SDave.Plauger@Sun.COM continue;
93110843SDave.Plauger@Sun.COM }
93210843SDave.Plauger@Sun.COM
93310843SDave.Plauger@Sun.COM if (!dump_range_check(bitnum, end, pfn))
93410843SDave.Plauger@Sun.COM continue;
93510843SDave.Plauger@Sun.COM
93610843SDave.Plauger@Sun.COM ASSERT((sz + CBUF_MAPSIZE) <= cfg->maxvmsize);
93710843SDave.Plauger@Sun.COM hat_devload(kas.a_hat, cfg->maxvm + sz, CBUF_MAPSIZE, pfn,
93810843SDave.Plauger@Sun.COM PROT_READ | PROT_WRITE, HAT_LOAD_NOCONSIST);
93910843SDave.Plauger@Sun.COM sz += CBUF_MAPSIZE;
94010843SDave.Plauger@Sun.COM cfg->found4m++;
94110843SDave.Plauger@Sun.COM
94210843SDave.Plauger@Sun.COM /* set the bitmap for both ends to be sure to cover the range */
94310843SDave.Plauger@Sun.COM dump_set_used(pfn);
94410843SDave.Plauger@Sun.COM dump_set_used(pfn + CBUF_MAPNP - 1);
94510843SDave.Plauger@Sun.COM
94610843SDave.Plauger@Sun.COM if (sz >= cfg->maxsize)
94710843SDave.Plauger@Sun.COM goto foundmax;
94810843SDave.Plauger@Sun.COM }
94910843SDave.Plauger@Sun.COM
95010843SDave.Plauger@Sun.COM /* Add small pages if we can't find enough large pages. */
95110843SDave.Plauger@Sun.COM dump_init_memlist_walker(&mlw);
95210843SDave.Plauger@Sun.COM for (bitnum = 0; bitnum < dumpcfg.bitmapsize; bitnum = end) {
95310843SDave.Plauger@Sun.COM dump_timeleft = dump_timeout;
95410843SDave.Plauger@Sun.COM end = bitnum + CBUF_MAPNP;
95510843SDave.Plauger@Sun.COM pfn = dump_bitnum_to_pfn(bitnum, &mlw);
95610843SDave.Plauger@Sun.COM ASSERT(pfn != PFN_INVALID);
95710843SDave.Plauger@Sun.COM
95810843SDave.Plauger@Sun.COM /* Find any non-aligned pages at start and end of segment. */
95910843SDave.Plauger@Sun.COM off = P2PHASE(pfn, CBUF_MAPNP);
96010843SDave.Plauger@Sun.COM if (mlw.mpleft < CBUF_MAPNP) {
96110843SDave.Plauger@Sun.COM end = bitnum + mlw.mpleft;
96210843SDave.Plauger@Sun.COM } else if (off != 0) {
96310843SDave.Plauger@Sun.COM end -= off;
96410843SDave.Plauger@Sun.COM } else if (cfg->found4m && dump_test_used(pfn)) {
96510843SDave.Plauger@Sun.COM continue;
96610843SDave.Plauger@Sun.COM }
96710843SDave.Plauger@Sun.COM
96810843SDave.Plauger@Sun.COM for (; bitnum < end; bitnum++, pfn++) {
96910843SDave.Plauger@Sun.COM dump_timeleft = dump_timeout;
97010843SDave.Plauger@Sun.COM if (BT_TEST(dumpcfg.bitmap, bitnum))
97110843SDave.Plauger@Sun.COM continue;
97210843SDave.Plauger@Sun.COM if (!dump_pfn_check(pfn))
97310843SDave.Plauger@Sun.COM continue;
97410843SDave.Plauger@Sun.COM ASSERT((sz + PAGESIZE) <= cfg->maxvmsize);
97510843SDave.Plauger@Sun.COM hat_devload(kas.a_hat, cfg->maxvm + sz, PAGESIZE, pfn,
97610843SDave.Plauger@Sun.COM PROT_READ | PROT_WRITE, HAT_LOAD_NOCONSIST);
97710843SDave.Plauger@Sun.COM sz += PAGESIZE;
97810843SDave.Plauger@Sun.COM cfg->foundsm++;
97910843SDave.Plauger@Sun.COM dump_set_used(pfn);
98010843SDave.Plauger@Sun.COM if (sz >= cfg->maxsize)
98110843SDave.Plauger@Sun.COM goto foundmax;
98210843SDave.Plauger@Sun.COM }
98310843SDave.Plauger@Sun.COM }
98410843SDave.Plauger@Sun.COM
98510843SDave.Plauger@Sun.COM /* Fall back to lzjb if we did not get enough memory for bzip2. */
98610843SDave.Plauger@Sun.COM endsz = (cfg->maxsize * cfg->threshold) / cfg->nhelper;
98710843SDave.Plauger@Sun.COM if (sz < endsz) {
98810843SDave.Plauger@Sun.COM cfg->clevel = DUMP_CLEVEL_LZJB;
98910843SDave.Plauger@Sun.COM }
99010843SDave.Plauger@Sun.COM
99110843SDave.Plauger@Sun.COM /* Allocate memory for as many helpers as we can. */
99210843SDave.Plauger@Sun.COM foundmax:
99310843SDave.Plauger@Sun.COM
99410843SDave.Plauger@Sun.COM /* Byte offsets into memory found and mapped above */
99510843SDave.Plauger@Sun.COM endsz = sz;
99610843SDave.Plauger@Sun.COM sz = 0;
99710843SDave.Plauger@Sun.COM
99810843SDave.Plauger@Sun.COM /* Set the size for bzip2 state. Only bzip2 needs it. */
99910843SDave.Plauger@Sun.COM bz2size = BZ2_bzCompressInitSize(dump_bzip2_level);
100010843SDave.Plauger@Sun.COM
100110843SDave.Plauger@Sun.COM /* Skip the preallocate output buffers. */
100210843SDave.Plauger@Sun.COM cp = &cfg->cbuf[MINCBUFS];
100310843SDave.Plauger@Sun.COM
100410843SDave.Plauger@Sun.COM /* Use this to move memory up from the preallocated helpers. */
100510843SDave.Plauger@Sun.COM ohp = cfg->helper;
100610843SDave.Plauger@Sun.COM
100710843SDave.Plauger@Sun.COM /* Loop over all helpers and allocate memory. */
100810843SDave.Plauger@Sun.COM for (hp = cfg->helper; hp < endhp; hp++) {
100910843SDave.Plauger@Sun.COM
101010843SDave.Plauger@Sun.COM /* Skip preallocated helpers by checking hp->page. */
101110843SDave.Plauger@Sun.COM if (hp->page == NULL) {
101210843SDave.Plauger@Sun.COM if (cfg->clevel <= DUMP_CLEVEL_LZJB) {
101310843SDave.Plauger@Sun.COM /* lzjb needs 2 1-page buffers */
101410843SDave.Plauger@Sun.COM if ((sz + (2 * PAGESIZE)) > endsz)
101510843SDave.Plauger@Sun.COM break;
101610843SDave.Plauger@Sun.COM hp->page = cfg->maxvm + sz;
101710843SDave.Plauger@Sun.COM sz += PAGESIZE;
101810843SDave.Plauger@Sun.COM hp->lzbuf = cfg->maxvm + sz;
101910843SDave.Plauger@Sun.COM sz += PAGESIZE;
102010843SDave.Plauger@Sun.COM
102110843SDave.Plauger@Sun.COM } else if (ohp->lzbuf != NULL) {
102210843SDave.Plauger@Sun.COM /* re-use the preallocted lzjb page for bzip2 */
102310843SDave.Plauger@Sun.COM hp->page = ohp->lzbuf;
102410843SDave.Plauger@Sun.COM ohp->lzbuf = NULL;
102510843SDave.Plauger@Sun.COM ++ohp;
102610843SDave.Plauger@Sun.COM
102710843SDave.Plauger@Sun.COM } else {
102810843SDave.Plauger@Sun.COM /* bzip2 needs a 1-page buffer */
102910843SDave.Plauger@Sun.COM if ((sz + PAGESIZE) > endsz)
103010843SDave.Plauger@Sun.COM break;
103110843SDave.Plauger@Sun.COM hp->page = cfg->maxvm + sz;
103210843SDave.Plauger@Sun.COM sz += PAGESIZE;
103310843SDave.Plauger@Sun.COM }
103410843SDave.Plauger@Sun.COM }
103510843SDave.Plauger@Sun.COM
103610843SDave.Plauger@Sun.COM /*
103710843SDave.Plauger@Sun.COM * Add output buffers per helper. The number of
103810843SDave.Plauger@Sun.COM * buffers per helper is determined by the ratio of
103910843SDave.Plauger@Sun.COM * ncbuf to nhelper.
104010843SDave.Plauger@Sun.COM */
104110843SDave.Plauger@Sun.COM for (k = 0; cp < endcp && (sz + CBUF_SIZE) <= endsz &&
104210843SDave.Plauger@Sun.COM k < NCBUF_PER_HELPER; k++) {
104310843SDave.Plauger@Sun.COM cp->state = CBUF_FREEBUF;
104410843SDave.Plauger@Sun.COM cp->size = CBUF_SIZE;
104510843SDave.Plauger@Sun.COM cp->buf = cfg->maxvm + sz;
104610843SDave.Plauger@Sun.COM sz += CBUF_SIZE;
104710843SDave.Plauger@Sun.COM ++cp;
104810843SDave.Plauger@Sun.COM }
104910843SDave.Plauger@Sun.COM
105010843SDave.Plauger@Sun.COM /*
105110843SDave.Plauger@Sun.COM * bzip2 needs compression state. Use the dumpbzalloc
105210843SDave.Plauger@Sun.COM * and dumpbzfree callbacks to allocate the memory.
105310843SDave.Plauger@Sun.COM * bzip2 does allocation only at init time.
105410843SDave.Plauger@Sun.COM */
105510843SDave.Plauger@Sun.COM if (cfg->clevel >= DUMP_CLEVEL_BZIP2) {
105610843SDave.Plauger@Sun.COM if ((sz + bz2size) > endsz) {
105710843SDave.Plauger@Sun.COM hp->page = NULL;
105810843SDave.Plauger@Sun.COM break;
105910843SDave.Plauger@Sun.COM } else {
106010843SDave.Plauger@Sun.COM hp->bzstream.opaque = &sz;
106110843SDave.Plauger@Sun.COM hp->bzstream.bzalloc = dumpbzalloc;
106210843SDave.Plauger@Sun.COM hp->bzstream.bzfree = dumpbzfree;
106310843SDave.Plauger@Sun.COM (void) BZ2_bzCompressInit(&hp->bzstream,
106410843SDave.Plauger@Sun.COM dump_bzip2_level, 0, 0);
106510843SDave.Plauger@Sun.COM hp->bzstream.opaque = NULL;
106610843SDave.Plauger@Sun.COM }
106710843SDave.Plauger@Sun.COM }
106810843SDave.Plauger@Sun.COM }
106910843SDave.Plauger@Sun.COM
107010843SDave.Plauger@Sun.COM /* Finish allocating output buffers */
107110843SDave.Plauger@Sun.COM for (; cp < endcp && (sz + CBUF_SIZE) <= endsz; cp++) {
107210843SDave.Plauger@Sun.COM cp->state = CBUF_FREEBUF;
107310843SDave.Plauger@Sun.COM cp->size = CBUF_SIZE;
107410843SDave.Plauger@Sun.COM cp->buf = cfg->maxvm + sz;
107510843SDave.Plauger@Sun.COM sz += CBUF_SIZE;
107610843SDave.Plauger@Sun.COM }
107710843SDave.Plauger@Sun.COM
107810843SDave.Plauger@Sun.COM /* Enable IS_DUMP_PAGE macro, which checks for pages we took. */
107910843SDave.Plauger@Sun.COM if (cfg->found4m || cfg->foundsm)
108010843SDave.Plauger@Sun.COM dump_check_used = 1;
108110843SDave.Plauger@Sun.COM
108210843SDave.Plauger@Sun.COM ASSERT(sz <= endsz);
108310843SDave.Plauger@Sun.COM }
108410843SDave.Plauger@Sun.COM
10850Sstevel@tonic-gate static void
dumphdr_init(void)10860Sstevel@tonic-gate dumphdr_init(void)
10870Sstevel@tonic-gate {
10880Sstevel@tonic-gate pgcnt_t npages = 0;
10890Sstevel@tonic-gate
10900Sstevel@tonic-gate ASSERT(MUTEX_HELD(&dump_lock));
10910Sstevel@tonic-gate
10920Sstevel@tonic-gate if (dumphdr == NULL) {
10930Sstevel@tonic-gate dumphdr = kmem_zalloc(sizeof (dumphdr_t), KM_SLEEP);
10940Sstevel@tonic-gate dumphdr->dump_magic = DUMP_MAGIC;
10950Sstevel@tonic-gate dumphdr->dump_version = DUMP_VERSION;
10960Sstevel@tonic-gate dumphdr->dump_wordsize = DUMP_WORDSIZE;
10970Sstevel@tonic-gate dumphdr->dump_pageshift = PAGESHIFT;
10980Sstevel@tonic-gate dumphdr->dump_pagesize = PAGESIZE;
10990Sstevel@tonic-gate dumphdr->dump_utsname = utsname;
11000Sstevel@tonic-gate (void) strcpy(dumphdr->dump_platform, platform);
110110843SDave.Plauger@Sun.COM dumpbuf.size = dumpbuf_iosize(maxphys);
110210843SDave.Plauger@Sun.COM dumpbuf.start = kmem_alloc(dumpbuf.size, KM_SLEEP);
110310843SDave.Plauger@Sun.COM dumpbuf.end = dumpbuf.start + dumpbuf.size;
110410843SDave.Plauger@Sun.COM dumpcfg.pids = kmem_alloc(v.v_proc * sizeof (pid_t), KM_SLEEP);
110510843SDave.Plauger@Sun.COM dumpcfg.helpermap = kmem_zalloc(BT_SIZEOFMAP(NCPU), KM_SLEEP);
110610843SDave.Plauger@Sun.COM LOCK_INIT_HELD(&dumpcfg.helper_lock);
110712967Sgavin.maltby@oracle.com dump_stack_scratch = kmem_alloc(STACK_BUF_SIZE, KM_SLEEP);
110812967Sgavin.maltby@oracle.com (void) strncpy(dumphdr->dump_uuid, dump_get_uuid(),
110912967Sgavin.maltby@oracle.com sizeof (dumphdr->dump_uuid));
11100Sstevel@tonic-gate }
11110Sstevel@tonic-gate
11125084Sjohnlev npages = num_phys_pages();
11130Sstevel@tonic-gate
111410843SDave.Plauger@Sun.COM if (dumpcfg.bitmapsize != npages) {
111510843SDave.Plauger@Sun.COM size_t rlen = CBUF_MAPP2R(P2ROUNDUP(npages, CBUF_MAPNP));
11160Sstevel@tonic-gate void *map = kmem_alloc(BT_SIZEOFMAP(npages), KM_SLEEP);
111710843SDave.Plauger@Sun.COM void *rmap = kmem_alloc(BT_SIZEOFMAP(rlen), KM_SLEEP);
111810843SDave.Plauger@Sun.COM
111910843SDave.Plauger@Sun.COM if (dumpcfg.bitmap != NULL)
112010843SDave.Plauger@Sun.COM kmem_free(dumpcfg.bitmap, BT_SIZEOFMAP(dumpcfg.
112110843SDave.Plauger@Sun.COM bitmapsize));
112210843SDave.Plauger@Sun.COM if (dumpcfg.rbitmap != NULL)
112310843SDave.Plauger@Sun.COM kmem_free(dumpcfg.rbitmap, BT_SIZEOFMAP(dumpcfg.
112410843SDave.Plauger@Sun.COM rbitmapsize));
112510843SDave.Plauger@Sun.COM dumpcfg.bitmap = map;
112610843SDave.Plauger@Sun.COM dumpcfg.bitmapsize = npages;
112710843SDave.Plauger@Sun.COM dumpcfg.rbitmap = rmap;
112810843SDave.Plauger@Sun.COM dumpcfg.rbitmapsize = rlen;
11290Sstevel@tonic-gate }
11300Sstevel@tonic-gate }
11310Sstevel@tonic-gate
11320Sstevel@tonic-gate /*
11330Sstevel@tonic-gate * Establish a new dump device.
11340Sstevel@tonic-gate */
11350Sstevel@tonic-gate int
dumpinit(vnode_t * vp,char * name,int justchecking)11360Sstevel@tonic-gate dumpinit(vnode_t *vp, char *name, int justchecking)
11370Sstevel@tonic-gate {
11380Sstevel@tonic-gate vnode_t *cvp;
11390Sstevel@tonic-gate vattr_t vattr;
11400Sstevel@tonic-gate vnode_t *cdev_vp;
11410Sstevel@tonic-gate int error = 0;
11420Sstevel@tonic-gate
11430Sstevel@tonic-gate ASSERT(MUTEX_HELD(&dump_lock));
11440Sstevel@tonic-gate
11450Sstevel@tonic-gate dumphdr_init();
11460Sstevel@tonic-gate
11470Sstevel@tonic-gate cvp = common_specvp(vp);
11480Sstevel@tonic-gate if (cvp == dumpvp)
11490Sstevel@tonic-gate return (0);
11500Sstevel@tonic-gate
11510Sstevel@tonic-gate /*
11520Sstevel@tonic-gate * Determine whether this is a plausible dump device. We want either:
11530Sstevel@tonic-gate * (1) a real device that's not mounted and has a cb_dump routine, or
11540Sstevel@tonic-gate * (2) a swapfile on some filesystem that has a vop_dump routine.
11550Sstevel@tonic-gate */
11565331Samw if ((error = VOP_OPEN(&cvp, FREAD | FWRITE, kcred, NULL)) != 0)
11570Sstevel@tonic-gate return (error);
11580Sstevel@tonic-gate
11590Sstevel@tonic-gate vattr.va_mask = AT_SIZE | AT_TYPE | AT_RDEV;
11605331Samw if ((error = VOP_GETATTR(cvp, &vattr, 0, kcred, NULL)) == 0) {
11610Sstevel@tonic-gate if (vattr.va_type == VBLK || vattr.va_type == VCHR) {
11620Sstevel@tonic-gate if (devopsp[getmajor(vattr.va_rdev)]->
11630Sstevel@tonic-gate devo_cb_ops->cb_dump == nodev)
11640Sstevel@tonic-gate error = ENOTSUP;
11650Sstevel@tonic-gate else if (vfs_devismounted(vattr.va_rdev))
11660Sstevel@tonic-gate error = EBUSY;
116710588SEric.Taylor@Sun.COM if (strcmp(ddi_driver_name(VTOS(cvp)->s_dip),
116810588SEric.Taylor@Sun.COM ZFS_DRIVER) == 0 &&
116910588SEric.Taylor@Sun.COM IS_SWAPVP(common_specvp(cvp)))
117010588SEric.Taylor@Sun.COM error = EBUSY;
11710Sstevel@tonic-gate } else {
11720Sstevel@tonic-gate if (vn_matchopval(cvp, VOPNAME_DUMP, fs_nosys) ||
11730Sstevel@tonic-gate !IS_SWAPVP(cvp))
11740Sstevel@tonic-gate error = ENOTSUP;
11750Sstevel@tonic-gate }
11760Sstevel@tonic-gate }
11770Sstevel@tonic-gate
11780Sstevel@tonic-gate if (error == 0 && vattr.va_size < 2 * DUMP_LOGSIZE + DUMP_ERPTSIZE)
11790Sstevel@tonic-gate error = ENOSPC;
11800Sstevel@tonic-gate
11810Sstevel@tonic-gate if (error || justchecking) {
11825331Samw (void) VOP_CLOSE(cvp, FREAD | FWRITE, 1, (offset_t)0,
11835331Samw kcred, NULL);
11840Sstevel@tonic-gate return (error);
11850Sstevel@tonic-gate }
11860Sstevel@tonic-gate
11870Sstevel@tonic-gate VN_HOLD(cvp);
11880Sstevel@tonic-gate
11890Sstevel@tonic-gate if (dumpvp != NULL)
11900Sstevel@tonic-gate dumpfini(); /* unconfigure the old dump device */
11910Sstevel@tonic-gate
11920Sstevel@tonic-gate dumpvp = cvp;
11930Sstevel@tonic-gate dumpvp_size = vattr.va_size & -DUMP_OFFSET;
11940Sstevel@tonic-gate dumppath = kmem_alloc(strlen(name) + 1, KM_SLEEP);
11950Sstevel@tonic-gate (void) strcpy(dumppath, name);
119610843SDave.Plauger@Sun.COM dumpbuf.iosize = 0;
11970Sstevel@tonic-gate
11980Sstevel@tonic-gate /*
11990Sstevel@tonic-gate * If the dump device is a block device, attempt to open up the
12000Sstevel@tonic-gate * corresponding character device and determine its maximum transfer
12010Sstevel@tonic-gate * size. We use this information to potentially resize dumpbuf to a
12020Sstevel@tonic-gate * larger and more optimal size for performing i/o to the dump device.
12030Sstevel@tonic-gate */
12040Sstevel@tonic-gate if (cvp->v_type == VBLK &&
12050Sstevel@tonic-gate (cdev_vp = makespecvp(VTOS(cvp)->s_dev, VCHR)) != NULL) {
12065331Samw if (VOP_OPEN(&cdev_vp, FREAD | FWRITE, kcred, NULL) == 0) {
12070Sstevel@tonic-gate size_t blk_size;
12080Sstevel@tonic-gate struct dk_cinfo dki;
12099889SLarry.Liu@Sun.COM struct dk_minfo minf;
12100Sstevel@tonic-gate
12119889SLarry.Liu@Sun.COM if (VOP_IOCTL(cdev_vp, DKIOCGMEDIAINFO,
12129889SLarry.Liu@Sun.COM (intptr_t)&minf, FKIOCTL, kcred, NULL, NULL)
12139889SLarry.Liu@Sun.COM == 0 && minf.dki_lbsize != 0)
12149889SLarry.Liu@Sun.COM blk_size = minf.dki_lbsize;
12150Sstevel@tonic-gate else
12160Sstevel@tonic-gate blk_size = DEV_BSIZE;
12170Sstevel@tonic-gate
12180Sstevel@tonic-gate if (VOP_IOCTL(cdev_vp, DKIOCINFO, (intptr_t)&dki,
12195331Samw FKIOCTL, kcred, NULL, NULL) == 0) {
122010843SDave.Plauger@Sun.COM dumpbuf.iosize = dki.dki_maxtransfer * blk_size;
12210Sstevel@tonic-gate dumpbuf_resize();
12220Sstevel@tonic-gate }
12236423Sgw25295 /*
122410588SEric.Taylor@Sun.COM * If we are working with a zvol then dumpify it
122510588SEric.Taylor@Sun.COM * if it's not being used as swap.
12266423Sgw25295 */
12276423Sgw25295 if (strcmp(dki.dki_dname, ZVOL_DRIVER) == 0) {
122810588SEric.Taylor@Sun.COM if (IS_SWAPVP(common_specvp(cvp)))
122910588SEric.Taylor@Sun.COM error = EBUSY;
123010588SEric.Taylor@Sun.COM else if ((error = VOP_IOCTL(cdev_vp,
12316423Sgw25295 DKIOCDUMPINIT, NULL, FKIOCTL, kcred,
123210588SEric.Taylor@Sun.COM NULL, NULL)) != 0)
12336423Sgw25295 dumpfini();
12346423Sgw25295 }
12350Sstevel@tonic-gate
12365331Samw (void) VOP_CLOSE(cdev_vp, FREAD | FWRITE, 1, 0,
12375331Samw kcred, NULL);
12380Sstevel@tonic-gate }
12390Sstevel@tonic-gate
12400Sstevel@tonic-gate VN_RELE(cdev_vp);
12410Sstevel@tonic-gate }
12420Sstevel@tonic-gate
12430Sstevel@tonic-gate cmn_err(CE_CONT, "?dump on %s size %llu MB\n", name, dumpvp_size >> 20);
12440Sstevel@tonic-gate
124510843SDave.Plauger@Sun.COM dump_update_clevel();
124610843SDave.Plauger@Sun.COM
12476423Sgw25295 return (error);
12480Sstevel@tonic-gate }
12490Sstevel@tonic-gate
12500Sstevel@tonic-gate void
dumpfini(void)12510Sstevel@tonic-gate dumpfini(void)
12520Sstevel@tonic-gate {
12536423Sgw25295 vattr_t vattr;
12546423Sgw25295 boolean_t is_zfs = B_FALSE;
12556423Sgw25295 vnode_t *cdev_vp;
12560Sstevel@tonic-gate ASSERT(MUTEX_HELD(&dump_lock));
12570Sstevel@tonic-gate
12580Sstevel@tonic-gate kmem_free(dumppath, strlen(dumppath) + 1);
12590Sstevel@tonic-gate
12606423Sgw25295 /*
12616423Sgw25295 * Determine if we are using zvols for our dump device
12626423Sgw25295 */
12636423Sgw25295 vattr.va_mask = AT_RDEV;
12646423Sgw25295 if (VOP_GETATTR(dumpvp, &vattr, 0, kcred, NULL) == 0) {
12656423Sgw25295 is_zfs = (getmajor(vattr.va_rdev) ==
12666423Sgw25295 ddi_name_to_major(ZFS_DRIVER)) ? B_TRUE : B_FALSE;
12676423Sgw25295 }
12686423Sgw25295
12696423Sgw25295 /*
12706423Sgw25295 * If we have a zvol dump device then we call into zfs so
12716423Sgw25295 * that it may have a chance to cleanup.
12726423Sgw25295 */
12736423Sgw25295 if (is_zfs &&
12746423Sgw25295 (cdev_vp = makespecvp(VTOS(dumpvp)->s_dev, VCHR)) != NULL) {
12756423Sgw25295 if (VOP_OPEN(&cdev_vp, FREAD | FWRITE, kcred, NULL) == 0) {
12766423Sgw25295 (void) VOP_IOCTL(cdev_vp, DKIOCDUMPFINI, NULL, FKIOCTL,
12776423Sgw25295 kcred, NULL, NULL);
12786423Sgw25295 (void) VOP_CLOSE(cdev_vp, FREAD | FWRITE, 1, 0,
12796423Sgw25295 kcred, NULL);
12806423Sgw25295 }
12816423Sgw25295 VN_RELE(cdev_vp);
12826423Sgw25295 }
12836423Sgw25295
12845331Samw (void) VOP_CLOSE(dumpvp, FREAD | FWRITE, 1, (offset_t)0, kcred, NULL);
12850Sstevel@tonic-gate
12860Sstevel@tonic-gate VN_RELE(dumpvp);
12870Sstevel@tonic-gate
12880Sstevel@tonic-gate dumpvp = NULL;
12890Sstevel@tonic-gate dumpvp_size = 0;
12900Sstevel@tonic-gate dumppath = NULL;
12910Sstevel@tonic-gate }
12920Sstevel@tonic-gate
12930Sstevel@tonic-gate static offset_t
dumpvp_flush(void)12940Sstevel@tonic-gate dumpvp_flush(void)
12950Sstevel@tonic-gate {
129610843SDave.Plauger@Sun.COM size_t size = P2ROUNDUP(dumpbuf.cur - dumpbuf.start, PAGESIZE);
129710843SDave.Plauger@Sun.COM hrtime_t iotime;
12980Sstevel@tonic-gate int err;
12990Sstevel@tonic-gate
130010843SDave.Plauger@Sun.COM if (dumpbuf.vp_off + size > dumpbuf.vp_limit) {
13010Sstevel@tonic-gate dump_ioerr = ENOSPC;
130210843SDave.Plauger@Sun.COM dumpbuf.vp_off = dumpbuf.vp_limit;
13030Sstevel@tonic-gate } else if (size != 0) {
130410843SDave.Plauger@Sun.COM iotime = gethrtime();
130510843SDave.Plauger@Sun.COM dumpsync.iowait += iotime - dumpsync.iowaitts;
13060Sstevel@tonic-gate if (panicstr)
130710843SDave.Plauger@Sun.COM err = VOP_DUMP(dumpvp, dumpbuf.start,
130810843SDave.Plauger@Sun.COM lbtodb(dumpbuf.vp_off), btod(size), NULL);
13090Sstevel@tonic-gate else
131010843SDave.Plauger@Sun.COM err = vn_rdwr(UIO_WRITE, dumpbuf.cdev_vp != NULL ?
131110843SDave.Plauger@Sun.COM dumpbuf.cdev_vp : dumpvp, dumpbuf.start, size,
131210843SDave.Plauger@Sun.COM dumpbuf.vp_off, UIO_SYSSPACE, 0, dumpbuf.vp_limit,
13130Sstevel@tonic-gate kcred, 0);
13140Sstevel@tonic-gate if (err && dump_ioerr == 0)
13150Sstevel@tonic-gate dump_ioerr = err;
131610843SDave.Plauger@Sun.COM dumpsync.iowaitts = gethrtime();
131710843SDave.Plauger@Sun.COM dumpsync.iotime += dumpsync.iowaitts - iotime;
131810843SDave.Plauger@Sun.COM dumpsync.nwrite += size;
131910843SDave.Plauger@Sun.COM dumpbuf.vp_off += size;
13200Sstevel@tonic-gate }
132110843SDave.Plauger@Sun.COM dumpbuf.cur = dumpbuf.start;
13220Sstevel@tonic-gate dump_timeleft = dump_timeout;
132310843SDave.Plauger@Sun.COM return (dumpbuf.vp_off);
13240Sstevel@tonic-gate }
13250Sstevel@tonic-gate
132610843SDave.Plauger@Sun.COM /* maximize write speed by keeping seek offset aligned with size */
13270Sstevel@tonic-gate void
dumpvp_write(const void * va,size_t size)13280Sstevel@tonic-gate dumpvp_write(const void *va, size_t size)
13290Sstevel@tonic-gate {
133010843SDave.Plauger@Sun.COM size_t len, off, sz;
133110843SDave.Plauger@Sun.COM
13320Sstevel@tonic-gate while (size != 0) {
133310843SDave.Plauger@Sun.COM len = MIN(size, dumpbuf.end - dumpbuf.cur);
13340Sstevel@tonic-gate if (len == 0) {
133510843SDave.Plauger@Sun.COM off = P2PHASE(dumpbuf.vp_off, dumpbuf.size);
133610843SDave.Plauger@Sun.COM if (off == 0 || !ISP2(dumpbuf.size)) {
133710843SDave.Plauger@Sun.COM (void) dumpvp_flush();
133810843SDave.Plauger@Sun.COM } else {
133910843SDave.Plauger@Sun.COM sz = dumpbuf.size - off;
134010843SDave.Plauger@Sun.COM dumpbuf.cur = dumpbuf.start + sz;
134110843SDave.Plauger@Sun.COM (void) dumpvp_flush();
134210843SDave.Plauger@Sun.COM ovbcopy(dumpbuf.start + sz, dumpbuf.start, off);
134310843SDave.Plauger@Sun.COM dumpbuf.cur += off;
134410843SDave.Plauger@Sun.COM }
13450Sstevel@tonic-gate } else {
134610843SDave.Plauger@Sun.COM bcopy(va, dumpbuf.cur, len);
13470Sstevel@tonic-gate va = (char *)va + len;
134810843SDave.Plauger@Sun.COM dumpbuf.cur += len;
13490Sstevel@tonic-gate size -= len;
13500Sstevel@tonic-gate }
13510Sstevel@tonic-gate }
13520Sstevel@tonic-gate }
13530Sstevel@tonic-gate
13540Sstevel@tonic-gate /*ARGSUSED*/
13550Sstevel@tonic-gate static void
dumpvp_ksyms_write(const void * src,void * dst,size_t size)13560Sstevel@tonic-gate dumpvp_ksyms_write(const void *src, void *dst, size_t size)
13570Sstevel@tonic-gate {
13580Sstevel@tonic-gate dumpvp_write(src, size);
13590Sstevel@tonic-gate }
13600Sstevel@tonic-gate
13610Sstevel@tonic-gate /*
13620Sstevel@tonic-gate * Mark 'pfn' in the bitmap and dump its translation table entry.
13630Sstevel@tonic-gate */
13640Sstevel@tonic-gate void
dump_addpage(struct as * as,void * va,pfn_t pfn)13650Sstevel@tonic-gate dump_addpage(struct as *as, void *va, pfn_t pfn)
13660Sstevel@tonic-gate {
13670Sstevel@tonic-gate mem_vtop_t mem_vtop;
13680Sstevel@tonic-gate pgcnt_t bitnum;
13690Sstevel@tonic-gate
13700Sstevel@tonic-gate if ((bitnum = dump_pfn_to_bitnum(pfn)) != (pgcnt_t)-1) {
137110843SDave.Plauger@Sun.COM if (!BT_TEST(dumpcfg.bitmap, bitnum)) {
13720Sstevel@tonic-gate dumphdr->dump_npages++;
137310843SDave.Plauger@Sun.COM BT_SET(dumpcfg.bitmap, bitnum);
13740Sstevel@tonic-gate }
13750Sstevel@tonic-gate dumphdr->dump_nvtop++;
13760Sstevel@tonic-gate mem_vtop.m_as = as;
13770Sstevel@tonic-gate mem_vtop.m_va = va;
13780Sstevel@tonic-gate mem_vtop.m_pfn = pfn;
13790Sstevel@tonic-gate dumpvp_write(&mem_vtop, sizeof (mem_vtop_t));
13800Sstevel@tonic-gate }
13810Sstevel@tonic-gate dump_timeleft = dump_timeout;
13820Sstevel@tonic-gate }
13830Sstevel@tonic-gate
13840Sstevel@tonic-gate /*
13850Sstevel@tonic-gate * Mark 'pfn' in the bitmap
13860Sstevel@tonic-gate */
13870Sstevel@tonic-gate void
dump_page(pfn_t pfn)13880Sstevel@tonic-gate dump_page(pfn_t pfn)
13890Sstevel@tonic-gate {
13900Sstevel@tonic-gate pgcnt_t bitnum;
13910Sstevel@tonic-gate
13920Sstevel@tonic-gate if ((bitnum = dump_pfn_to_bitnum(pfn)) != (pgcnt_t)-1) {
139310843SDave.Plauger@Sun.COM if (!BT_TEST(dumpcfg.bitmap, bitnum)) {
13940Sstevel@tonic-gate dumphdr->dump_npages++;
139510843SDave.Plauger@Sun.COM BT_SET(dumpcfg.bitmap, bitnum);
13960Sstevel@tonic-gate }
13970Sstevel@tonic-gate }
13980Sstevel@tonic-gate dump_timeleft = dump_timeout;
13990Sstevel@tonic-gate }
14000Sstevel@tonic-gate
14010Sstevel@tonic-gate /*
14020Sstevel@tonic-gate * Dump the <as, va, pfn> information for a given address space.
14030Sstevel@tonic-gate * SEGOP_DUMP() will call dump_addpage() for each page in the segment.
14040Sstevel@tonic-gate */
14050Sstevel@tonic-gate static void
dump_as(struct as * as)14060Sstevel@tonic-gate dump_as(struct as *as)
14070Sstevel@tonic-gate {
14080Sstevel@tonic-gate struct seg *seg;
14090Sstevel@tonic-gate
14100Sstevel@tonic-gate AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
14110Sstevel@tonic-gate for (seg = AS_SEGFIRST(as); seg; seg = AS_SEGNEXT(as, seg)) {
14120Sstevel@tonic-gate if (seg->s_as != as)
14130Sstevel@tonic-gate break;
14140Sstevel@tonic-gate if (seg->s_ops == NULL)
14150Sstevel@tonic-gate continue;
14160Sstevel@tonic-gate SEGOP_DUMP(seg);
14170Sstevel@tonic-gate }
14180Sstevel@tonic-gate AS_LOCK_EXIT(as, &as->a_lock);
14190Sstevel@tonic-gate
14200Sstevel@tonic-gate if (seg != NULL)
14210Sstevel@tonic-gate cmn_err(CE_WARN, "invalid segment %p in address space %p",
14220Sstevel@tonic-gate (void *)seg, (void *)as);
14230Sstevel@tonic-gate }
14240Sstevel@tonic-gate
14250Sstevel@tonic-gate static int
dump_process(pid_t pid)14260Sstevel@tonic-gate dump_process(pid_t pid)
14270Sstevel@tonic-gate {
14280Sstevel@tonic-gate proc_t *p = sprlock(pid);
14290Sstevel@tonic-gate
14300Sstevel@tonic-gate if (p == NULL)
14310Sstevel@tonic-gate return (-1);
14320Sstevel@tonic-gate if (p->p_as != &kas) {
14330Sstevel@tonic-gate mutex_exit(&p->p_lock);
14340Sstevel@tonic-gate dump_as(p->p_as);
14350Sstevel@tonic-gate mutex_enter(&p->p_lock);
14360Sstevel@tonic-gate }
14370Sstevel@tonic-gate
14380Sstevel@tonic-gate sprunlock(p);
14390Sstevel@tonic-gate
14400Sstevel@tonic-gate return (0);
14410Sstevel@tonic-gate }
14420Sstevel@tonic-gate
144312967Sgavin.maltby@oracle.com /*
144412967Sgavin.maltby@oracle.com * The following functions (dump_summary(), dump_ereports(), and
144512967Sgavin.maltby@oracle.com * dump_messages()), write data to an uncompressed area within the
144612967Sgavin.maltby@oracle.com * crashdump. The layout of these is
144712967Sgavin.maltby@oracle.com *
144812967Sgavin.maltby@oracle.com * +------------------------------------------------------------+
144912967Sgavin.maltby@oracle.com * | compressed pages | summary | ereports | messages |
145012967Sgavin.maltby@oracle.com * +------------------------------------------------------------+
145112967Sgavin.maltby@oracle.com *
145212967Sgavin.maltby@oracle.com * With the advent of saving a compressed crash dump by default, we
145312967Sgavin.maltby@oracle.com * need to save a little more data to describe the failure mode in
145412967Sgavin.maltby@oracle.com * an uncompressed buffer available before savecore uncompresses
145512967Sgavin.maltby@oracle.com * the dump. Initially this is a copy of the stack trace. Additional
145612967Sgavin.maltby@oracle.com * summary information should be added here.
145712967Sgavin.maltby@oracle.com */
145812967Sgavin.maltby@oracle.com
145912967Sgavin.maltby@oracle.com void
dump_summary(void)146012967Sgavin.maltby@oracle.com dump_summary(void)
146112967Sgavin.maltby@oracle.com {
146212967Sgavin.maltby@oracle.com u_offset_t dumpvp_start;
146312967Sgavin.maltby@oracle.com summary_dump_t sd;
146412967Sgavin.maltby@oracle.com
146512967Sgavin.maltby@oracle.com if (dumpvp == NULL || dumphdr == NULL)
146612967Sgavin.maltby@oracle.com return;
146712967Sgavin.maltby@oracle.com
146812967Sgavin.maltby@oracle.com dumpbuf.cur = dumpbuf.start;
146912967Sgavin.maltby@oracle.com
147012967Sgavin.maltby@oracle.com dumpbuf.vp_limit = dumpvp_size - (DUMP_OFFSET + DUMP_LOGSIZE +
147112967Sgavin.maltby@oracle.com DUMP_ERPTSIZE);
147212967Sgavin.maltby@oracle.com dumpvp_start = dumpbuf.vp_limit - DUMP_SUMMARYSIZE;
147312967Sgavin.maltby@oracle.com dumpbuf.vp_off = dumpvp_start;
147412967Sgavin.maltby@oracle.com
147512967Sgavin.maltby@oracle.com sd.sd_magic = SUMMARY_MAGIC;
147612967Sgavin.maltby@oracle.com sd.sd_ssum = checksum32(dump_stack_scratch, STACK_BUF_SIZE);
147712967Sgavin.maltby@oracle.com dumpvp_write(&sd, sizeof (sd));
147812967Sgavin.maltby@oracle.com dumpvp_write(dump_stack_scratch, STACK_BUF_SIZE);
147912967Sgavin.maltby@oracle.com
148012967Sgavin.maltby@oracle.com sd.sd_magic = 0; /* indicate end of summary */
148112967Sgavin.maltby@oracle.com dumpvp_write(&sd, sizeof (sd));
148212967Sgavin.maltby@oracle.com (void) dumpvp_flush();
148312967Sgavin.maltby@oracle.com }
148412967Sgavin.maltby@oracle.com
14850Sstevel@tonic-gate void
dump_ereports(void)14860Sstevel@tonic-gate dump_ereports(void)
14870Sstevel@tonic-gate {
14880Sstevel@tonic-gate u_offset_t dumpvp_start;
14890Sstevel@tonic-gate erpt_dump_t ed;
14900Sstevel@tonic-gate
14910Sstevel@tonic-gate if (dumpvp == NULL || dumphdr == NULL)
14920Sstevel@tonic-gate return;
14930Sstevel@tonic-gate
149410843SDave.Plauger@Sun.COM dumpbuf.cur = dumpbuf.start;
149510843SDave.Plauger@Sun.COM dumpbuf.vp_limit = dumpvp_size - (DUMP_OFFSET + DUMP_LOGSIZE);
149610843SDave.Plauger@Sun.COM dumpvp_start = dumpbuf.vp_limit - DUMP_ERPTSIZE;
149710843SDave.Plauger@Sun.COM dumpbuf.vp_off = dumpvp_start;
14980Sstevel@tonic-gate
14990Sstevel@tonic-gate fm_ereport_dump();
15000Sstevel@tonic-gate if (panicstr)
15010Sstevel@tonic-gate errorq_dump();
15020Sstevel@tonic-gate
15030Sstevel@tonic-gate bzero(&ed, sizeof (ed)); /* indicate end of ereports */
15040Sstevel@tonic-gate dumpvp_write(&ed, sizeof (ed));
15050Sstevel@tonic-gate (void) dumpvp_flush();
15060Sstevel@tonic-gate
15070Sstevel@tonic-gate if (!panicstr) {
15080Sstevel@tonic-gate (void) VOP_PUTPAGE(dumpvp, dumpvp_start,
150910843SDave.Plauger@Sun.COM (size_t)(dumpbuf.vp_off - dumpvp_start),
15105331Samw B_INVAL | B_FORCE, kcred, NULL);
15110Sstevel@tonic-gate }
15120Sstevel@tonic-gate }
15130Sstevel@tonic-gate
15140Sstevel@tonic-gate void
dump_messages(void)15150Sstevel@tonic-gate dump_messages(void)
15160Sstevel@tonic-gate {
15170Sstevel@tonic-gate log_dump_t ld;
15180Sstevel@tonic-gate mblk_t *mctl, *mdata;
15190Sstevel@tonic-gate queue_t *q, *qlast;
15200Sstevel@tonic-gate u_offset_t dumpvp_start;
15210Sstevel@tonic-gate
15220Sstevel@tonic-gate if (dumpvp == NULL || dumphdr == NULL || log_consq == NULL)
15230Sstevel@tonic-gate return;
15240Sstevel@tonic-gate
152510843SDave.Plauger@Sun.COM dumpbuf.cur = dumpbuf.start;
152610843SDave.Plauger@Sun.COM dumpbuf.vp_limit = dumpvp_size - DUMP_OFFSET;
152710843SDave.Plauger@Sun.COM dumpvp_start = dumpbuf.vp_limit - DUMP_LOGSIZE;
152810843SDave.Plauger@Sun.COM dumpbuf.vp_off = dumpvp_start;
15290Sstevel@tonic-gate
15300Sstevel@tonic-gate qlast = NULL;
15310Sstevel@tonic-gate do {
15320Sstevel@tonic-gate for (q = log_consq; q->q_next != qlast; q = q->q_next)
15330Sstevel@tonic-gate continue;
15340Sstevel@tonic-gate for (mctl = q->q_first; mctl != NULL; mctl = mctl->b_next) {
15350Sstevel@tonic-gate dump_timeleft = dump_timeout;
15360Sstevel@tonic-gate mdata = mctl->b_cont;
15370Sstevel@tonic-gate ld.ld_magic = LOG_MAGIC;
15380Sstevel@tonic-gate ld.ld_msgsize = MBLKL(mctl->b_cont);
15390Sstevel@tonic-gate ld.ld_csum = checksum32(mctl->b_rptr, MBLKL(mctl));
15400Sstevel@tonic-gate ld.ld_msum = checksum32(mdata->b_rptr, MBLKL(mdata));
15410Sstevel@tonic-gate dumpvp_write(&ld, sizeof (ld));
15420Sstevel@tonic-gate dumpvp_write(mctl->b_rptr, MBLKL(mctl));
15430Sstevel@tonic-gate dumpvp_write(mdata->b_rptr, MBLKL(mdata));
15440Sstevel@tonic-gate }
15450Sstevel@tonic-gate } while ((qlast = q) != log_consq);
15460Sstevel@tonic-gate
15470Sstevel@tonic-gate ld.ld_magic = 0; /* indicate end of messages */
15480Sstevel@tonic-gate dumpvp_write(&ld, sizeof (ld));
15490Sstevel@tonic-gate (void) dumpvp_flush();
15500Sstevel@tonic-gate if (!panicstr) {
15510Sstevel@tonic-gate (void) VOP_PUTPAGE(dumpvp, dumpvp_start,
155210843SDave.Plauger@Sun.COM (size_t)(dumpbuf.vp_off - dumpvp_start),
15535331Samw B_INVAL | B_FORCE, kcred, NULL);
15540Sstevel@tonic-gate }
15550Sstevel@tonic-gate }
15560Sstevel@tonic-gate
155710843SDave.Plauger@Sun.COM /*
155810843SDave.Plauger@Sun.COM * The following functions are called on multiple CPUs during dump.
155910843SDave.Plauger@Sun.COM * They must not use most kernel services, because all cross-calls are
156010843SDave.Plauger@Sun.COM * disabled during panic. Therefore, blocking locks and cache flushes
156110843SDave.Plauger@Sun.COM * will not work.
156210843SDave.Plauger@Sun.COM */
156310843SDave.Plauger@Sun.COM
156411178SDave.Plauger@Sun.COM /*
156511178SDave.Plauger@Sun.COM * Copy pages, trapping ECC errors. Also, for robustness, trap data
156611178SDave.Plauger@Sun.COM * access in case something goes wrong in the hat layer and the
156711178SDave.Plauger@Sun.COM * mapping is broken.
156811178SDave.Plauger@Sun.COM */
156910843SDave.Plauger@Sun.COM static int
dump_pagecopy(void * src,void * dst)15700Sstevel@tonic-gate dump_pagecopy(void *src, void *dst)
15710Sstevel@tonic-gate {
15720Sstevel@tonic-gate long *wsrc = (long *)src;
15730Sstevel@tonic-gate long *wdst = (long *)dst;
15740Sstevel@tonic-gate const ulong_t ncopies = PAGESIZE / sizeof (long);
15750Sstevel@tonic-gate volatile int w = 0;
15760Sstevel@tonic-gate volatile int ueoff = -1;
15770Sstevel@tonic-gate on_trap_data_t otd;
15780Sstevel@tonic-gate
157911178SDave.Plauger@Sun.COM if (on_trap(&otd, OT_DATA_EC | OT_DATA_ACCESS)) {
158010843SDave.Plauger@Sun.COM if (ueoff == -1)
15810Sstevel@tonic-gate ueoff = w * sizeof (long);
158211178SDave.Plauger@Sun.COM /* report "bad ECC" or "bad address" */
15830Sstevel@tonic-gate #ifdef _LP64
158411178SDave.Plauger@Sun.COM if (otd.ot_trap & OT_DATA_EC)
158511178SDave.Plauger@Sun.COM wdst[w++] = 0x00badecc00badecc;
158611178SDave.Plauger@Sun.COM else
158711178SDave.Plauger@Sun.COM wdst[w++] = 0x00badadd00badadd;
15880Sstevel@tonic-gate #else
158911178SDave.Plauger@Sun.COM if (otd.ot_trap & OT_DATA_EC)
159011178SDave.Plauger@Sun.COM wdst[w++] = 0x00badecc;
159111178SDave.Plauger@Sun.COM else
159211178SDave.Plauger@Sun.COM wdst[w++] = 0x00badadd;
15930Sstevel@tonic-gate #endif
15940Sstevel@tonic-gate }
15950Sstevel@tonic-gate while (w < ncopies) {
15960Sstevel@tonic-gate wdst[w] = wsrc[w];
15970Sstevel@tonic-gate w++;
15980Sstevel@tonic-gate }
15990Sstevel@tonic-gate no_trap();
160010843SDave.Plauger@Sun.COM return (ueoff);
16010Sstevel@tonic-gate }
16020Sstevel@tonic-gate
160310843SDave.Plauger@Sun.COM static void
dumpsys_close_cq(cqueue_t * cq,int live)160410843SDave.Plauger@Sun.COM dumpsys_close_cq(cqueue_t *cq, int live)
160510843SDave.Plauger@Sun.COM {
160610843SDave.Plauger@Sun.COM if (live) {
160710843SDave.Plauger@Sun.COM mutex_enter(&cq->mutex);
160810843SDave.Plauger@Sun.COM atomic_dec_uint(&cq->open);
160910843SDave.Plauger@Sun.COM cv_signal(&cq->cv);
161010843SDave.Plauger@Sun.COM mutex_exit(&cq->mutex);
161110843SDave.Plauger@Sun.COM } else {
161210843SDave.Plauger@Sun.COM atomic_dec_uint(&cq->open);
161310843SDave.Plauger@Sun.COM }
161410843SDave.Plauger@Sun.COM }
161510843SDave.Plauger@Sun.COM
161610843SDave.Plauger@Sun.COM static inline void
dumpsys_spinlock(lock_t * lp)161710843SDave.Plauger@Sun.COM dumpsys_spinlock(lock_t *lp)
161810843SDave.Plauger@Sun.COM {
161910843SDave.Plauger@Sun.COM uint_t backoff = 0;
162010843SDave.Plauger@Sun.COM int loop_count = 0;
162110843SDave.Plauger@Sun.COM
162210843SDave.Plauger@Sun.COM while (LOCK_HELD(lp) || !lock_spin_try(lp)) {
162310843SDave.Plauger@Sun.COM if (++loop_count >= ncpus) {
162410843SDave.Plauger@Sun.COM backoff = mutex_lock_backoff(0);
162510843SDave.Plauger@Sun.COM loop_count = 0;
162610843SDave.Plauger@Sun.COM } else {
162710843SDave.Plauger@Sun.COM backoff = mutex_lock_backoff(backoff);
162810843SDave.Plauger@Sun.COM }
162910843SDave.Plauger@Sun.COM mutex_lock_delay(backoff);
163010843SDave.Plauger@Sun.COM }
163110843SDave.Plauger@Sun.COM }
163210843SDave.Plauger@Sun.COM
163310843SDave.Plauger@Sun.COM static inline void
dumpsys_spinunlock(lock_t * lp)163410843SDave.Plauger@Sun.COM dumpsys_spinunlock(lock_t *lp)
163510843SDave.Plauger@Sun.COM {
163610843SDave.Plauger@Sun.COM lock_clear(lp);
163710843SDave.Plauger@Sun.COM }
163810843SDave.Plauger@Sun.COM
163910843SDave.Plauger@Sun.COM static inline void
dumpsys_lock(cqueue_t * cq,int live)164010843SDave.Plauger@Sun.COM dumpsys_lock(cqueue_t *cq, int live)
164110843SDave.Plauger@Sun.COM {
164210843SDave.Plauger@Sun.COM if (live)
164310843SDave.Plauger@Sun.COM mutex_enter(&cq->mutex);
164410843SDave.Plauger@Sun.COM else
164510843SDave.Plauger@Sun.COM dumpsys_spinlock(&cq->spinlock);
164610843SDave.Plauger@Sun.COM }
164710843SDave.Plauger@Sun.COM
164810843SDave.Plauger@Sun.COM static inline void
dumpsys_unlock(cqueue_t * cq,int live,int signal)164910843SDave.Plauger@Sun.COM dumpsys_unlock(cqueue_t *cq, int live, int signal)
165010843SDave.Plauger@Sun.COM {
165110843SDave.Plauger@Sun.COM if (live) {
165210843SDave.Plauger@Sun.COM if (signal)
165310843SDave.Plauger@Sun.COM cv_signal(&cq->cv);
165410843SDave.Plauger@Sun.COM mutex_exit(&cq->mutex);
165510843SDave.Plauger@Sun.COM } else {
165610843SDave.Plauger@Sun.COM dumpsys_spinunlock(&cq->spinlock);
165710843SDave.Plauger@Sun.COM }
165810843SDave.Plauger@Sun.COM }
165910843SDave.Plauger@Sun.COM
166010843SDave.Plauger@Sun.COM static void
dumpsys_wait_cq(cqueue_t * cq,int live)166110843SDave.Plauger@Sun.COM dumpsys_wait_cq(cqueue_t *cq, int live)
166210843SDave.Plauger@Sun.COM {
166310843SDave.Plauger@Sun.COM if (live) {
166410843SDave.Plauger@Sun.COM cv_wait(&cq->cv, &cq->mutex);
166510843SDave.Plauger@Sun.COM } else {
166610843SDave.Plauger@Sun.COM dumpsys_spinunlock(&cq->spinlock);
166710843SDave.Plauger@Sun.COM while (cq->open)
166810843SDave.Plauger@Sun.COM if (cq->first)
166910843SDave.Plauger@Sun.COM break;
167010843SDave.Plauger@Sun.COM dumpsys_spinlock(&cq->spinlock);
167110843SDave.Plauger@Sun.COM }
167210843SDave.Plauger@Sun.COM }
167310843SDave.Plauger@Sun.COM
167410843SDave.Plauger@Sun.COM static void
dumpsys_put_cq(cqueue_t * cq,cbuf_t * cp,int newstate,int live)167510843SDave.Plauger@Sun.COM dumpsys_put_cq(cqueue_t *cq, cbuf_t *cp, int newstate, int live)
167610843SDave.Plauger@Sun.COM {
167710843SDave.Plauger@Sun.COM if (cp == NULL)
167810843SDave.Plauger@Sun.COM return;
167910843SDave.Plauger@Sun.COM
168010843SDave.Plauger@Sun.COM dumpsys_lock(cq, live);
168110843SDave.Plauger@Sun.COM
168210843SDave.Plauger@Sun.COM if (cq->ts != 0) {
168310843SDave.Plauger@Sun.COM cq->empty += gethrtime() - cq->ts;
168410843SDave.Plauger@Sun.COM cq->ts = 0;
168510843SDave.Plauger@Sun.COM }
168610843SDave.Plauger@Sun.COM
168710843SDave.Plauger@Sun.COM cp->state = newstate;
168810843SDave.Plauger@Sun.COM cp->next = NULL;
168910843SDave.Plauger@Sun.COM if (cq->last == NULL)
169010843SDave.Plauger@Sun.COM cq->first = cp;
169110843SDave.Plauger@Sun.COM else
169210843SDave.Plauger@Sun.COM cq->last->next = cp;
169310843SDave.Plauger@Sun.COM cq->last = cp;
169410843SDave.Plauger@Sun.COM
169510843SDave.Plauger@Sun.COM dumpsys_unlock(cq, live, 1);
169610843SDave.Plauger@Sun.COM }
169710843SDave.Plauger@Sun.COM
169810843SDave.Plauger@Sun.COM static cbuf_t *
dumpsys_get_cq(cqueue_t * cq,int live)169910843SDave.Plauger@Sun.COM dumpsys_get_cq(cqueue_t *cq, int live)
170010843SDave.Plauger@Sun.COM {
170110843SDave.Plauger@Sun.COM cbuf_t *cp;
170210843SDave.Plauger@Sun.COM hrtime_t now = gethrtime();
170310843SDave.Plauger@Sun.COM
170410843SDave.Plauger@Sun.COM dumpsys_lock(cq, live);
170510843SDave.Plauger@Sun.COM
170610843SDave.Plauger@Sun.COM /* CONSTCOND */
170710843SDave.Plauger@Sun.COM while (1) {
170810843SDave.Plauger@Sun.COM cp = (cbuf_t *)cq->first;
170910843SDave.Plauger@Sun.COM if (cp == NULL) {
171010843SDave.Plauger@Sun.COM if (cq->open == 0)
171110843SDave.Plauger@Sun.COM break;
171210843SDave.Plauger@Sun.COM dumpsys_wait_cq(cq, live);
171310843SDave.Plauger@Sun.COM continue;
171410843SDave.Plauger@Sun.COM }
171510843SDave.Plauger@Sun.COM cq->first = cp->next;
171610843SDave.Plauger@Sun.COM if (cq->first == NULL) {
171710843SDave.Plauger@Sun.COM cq->last = NULL;
171810843SDave.Plauger@Sun.COM cq->ts = now;
171910843SDave.Plauger@Sun.COM }
172010843SDave.Plauger@Sun.COM break;
172110843SDave.Plauger@Sun.COM }
172210843SDave.Plauger@Sun.COM
172310843SDave.Plauger@Sun.COM dumpsys_unlock(cq, live, cq->first != NULL || cq->open == 0);
172410843SDave.Plauger@Sun.COM return (cp);
172510843SDave.Plauger@Sun.COM }
172610843SDave.Plauger@Sun.COM
172710843SDave.Plauger@Sun.COM /*
172810843SDave.Plauger@Sun.COM * Send an error message to the console. If the main task is running
172910843SDave.Plauger@Sun.COM * just write the message via uprintf. If a helper is running the
173010843SDave.Plauger@Sun.COM * message has to be put on a queue for the main task. Setting fmt to
173110843SDave.Plauger@Sun.COM * NULL means flush the error message buffer. If fmt is not NULL, just
173210843SDave.Plauger@Sun.COM * add the text to the existing buffer.
173310843SDave.Plauger@Sun.COM */
173410843SDave.Plauger@Sun.COM static void
dumpsys_errmsg(helper_t * hp,const char * fmt,...)173510843SDave.Plauger@Sun.COM dumpsys_errmsg(helper_t *hp, const char *fmt, ...)
173610843SDave.Plauger@Sun.COM {
173710843SDave.Plauger@Sun.COM dumpsync_t *ds = hp->ds;
173810843SDave.Plauger@Sun.COM cbuf_t *cp = hp->cperr;
173910843SDave.Plauger@Sun.COM va_list adx;
174010843SDave.Plauger@Sun.COM
174110843SDave.Plauger@Sun.COM if (hp->helper == MAINHELPER) {
174210843SDave.Plauger@Sun.COM if (fmt != NULL) {
174310843SDave.Plauger@Sun.COM if (ds->neednl) {
174410843SDave.Plauger@Sun.COM uprintf("\n");
174510843SDave.Plauger@Sun.COM ds->neednl = 0;
174610843SDave.Plauger@Sun.COM }
174710843SDave.Plauger@Sun.COM va_start(adx, fmt);
174810843SDave.Plauger@Sun.COM vuprintf(fmt, adx);
174910843SDave.Plauger@Sun.COM va_end(adx);
175010843SDave.Plauger@Sun.COM }
175110843SDave.Plauger@Sun.COM } else if (fmt == NULL) {
175210843SDave.Plauger@Sun.COM if (cp != NULL) {
175310843SDave.Plauger@Sun.COM CQ_PUT(mainq, cp, CBUF_ERRMSG);
175410843SDave.Plauger@Sun.COM hp->cperr = NULL;
175510843SDave.Plauger@Sun.COM }
175610843SDave.Plauger@Sun.COM } else {
175710843SDave.Plauger@Sun.COM if (hp->cperr == NULL) {
175810843SDave.Plauger@Sun.COM cp = CQ_GET(freebufq);
175910843SDave.Plauger@Sun.COM hp->cperr = cp;
176010843SDave.Plauger@Sun.COM cp->used = 0;
176110843SDave.Plauger@Sun.COM }
176210843SDave.Plauger@Sun.COM va_start(adx, fmt);
176310843SDave.Plauger@Sun.COM cp->used += vsnprintf(cp->buf + cp->used, cp->size - cp->used,
176410843SDave.Plauger@Sun.COM fmt, adx);
176510843SDave.Plauger@Sun.COM va_end(adx);
176610843SDave.Plauger@Sun.COM if ((cp->used + LOG_MSGSIZE) > cp->size) {
176710843SDave.Plauger@Sun.COM CQ_PUT(mainq, cp, CBUF_ERRMSG);
176810843SDave.Plauger@Sun.COM hp->cperr = NULL;
176910843SDave.Plauger@Sun.COM }
177010843SDave.Plauger@Sun.COM }
177110843SDave.Plauger@Sun.COM }
177210843SDave.Plauger@Sun.COM
177310843SDave.Plauger@Sun.COM /*
177410843SDave.Plauger@Sun.COM * Write an output buffer to the dump file. If the main task is
177510843SDave.Plauger@Sun.COM * running just write the data. If a helper is running the output is
177610843SDave.Plauger@Sun.COM * placed on a queue for the main task.
177710843SDave.Plauger@Sun.COM */
177810843SDave.Plauger@Sun.COM static void
dumpsys_swrite(helper_t * hp,cbuf_t * cp,size_t used)177910843SDave.Plauger@Sun.COM dumpsys_swrite(helper_t *hp, cbuf_t *cp, size_t used)
178010843SDave.Plauger@Sun.COM {
178110843SDave.Plauger@Sun.COM dumpsync_t *ds = hp->ds;
178210843SDave.Plauger@Sun.COM
178310843SDave.Plauger@Sun.COM if (hp->helper == MAINHELPER) {
178410843SDave.Plauger@Sun.COM HRSTART(ds->perpage, write);
178510843SDave.Plauger@Sun.COM dumpvp_write(cp->buf, used);
178610843SDave.Plauger@Sun.COM HRSTOP(ds->perpage, write);
178710843SDave.Plauger@Sun.COM CQ_PUT(freebufq, cp, CBUF_FREEBUF);
178810843SDave.Plauger@Sun.COM } else {
178910843SDave.Plauger@Sun.COM cp->used = used;
179010843SDave.Plauger@Sun.COM CQ_PUT(mainq, cp, CBUF_WRITE);
179110843SDave.Plauger@Sun.COM }
179210843SDave.Plauger@Sun.COM }
179310843SDave.Plauger@Sun.COM
179410843SDave.Plauger@Sun.COM /*
179510843SDave.Plauger@Sun.COM * Copy one page within the mapped range. The offset starts at 0 and
179610843SDave.Plauger@Sun.COM * is relative to the first pfn. cp->buf + cp->off is the address of
179710843SDave.Plauger@Sun.COM * the first pfn. If dump_pagecopy returns a UE offset, create an
179810843SDave.Plauger@Sun.COM * error message. Returns the offset to the next pfn in the range
179910843SDave.Plauger@Sun.COM * selected by the bitmap.
180010843SDave.Plauger@Sun.COM */
180110843SDave.Plauger@Sun.COM static int
dumpsys_copy_page(helper_t * hp,int offset)180210843SDave.Plauger@Sun.COM dumpsys_copy_page(helper_t *hp, int offset)
180310843SDave.Plauger@Sun.COM {
180410843SDave.Plauger@Sun.COM cbuf_t *cp = hp->cpin;
180510843SDave.Plauger@Sun.COM int ueoff;
180610843SDave.Plauger@Sun.COM
180710843SDave.Plauger@Sun.COM ASSERT(cp->off + offset + PAGESIZE <= cp->size);
180810843SDave.Plauger@Sun.COM ASSERT(BT_TEST(dumpcfg.bitmap, cp->bitnum));
180910843SDave.Plauger@Sun.COM
181010843SDave.Plauger@Sun.COM ueoff = dump_pagecopy(cp->buf + cp->off + offset, hp->page);
181110843SDave.Plauger@Sun.COM
181210843SDave.Plauger@Sun.COM /* ueoff is the offset in the page to a UE error */
181310843SDave.Plauger@Sun.COM if (ueoff != -1) {
181410843SDave.Plauger@Sun.COM uint64_t pa = ptob(cp->pfn) + offset + ueoff;
181510843SDave.Plauger@Sun.COM
181611178SDave.Plauger@Sun.COM dumpsys_errmsg(hp, "cpu %d: memory error at PA 0x%08x.%08x\n",
181711178SDave.Plauger@Sun.COM CPU->cpu_id, (uint32_t)(pa >> 32), (uint32_t)pa);
181810843SDave.Plauger@Sun.COM }
181910843SDave.Plauger@Sun.COM
182010843SDave.Plauger@Sun.COM /*
182110843SDave.Plauger@Sun.COM * Advance bitnum and offset to the next input page for the
182210843SDave.Plauger@Sun.COM * next call to this function.
182310843SDave.Plauger@Sun.COM */
182410843SDave.Plauger@Sun.COM offset += PAGESIZE;
182510843SDave.Plauger@Sun.COM cp->bitnum++;
182610843SDave.Plauger@Sun.COM while (cp->off + offset < cp->size) {
182710843SDave.Plauger@Sun.COM if (BT_TEST(dumpcfg.bitmap, cp->bitnum))
182810843SDave.Plauger@Sun.COM break;
182910843SDave.Plauger@Sun.COM offset += PAGESIZE;
183010843SDave.Plauger@Sun.COM cp->bitnum++;
183110843SDave.Plauger@Sun.COM }
183210843SDave.Plauger@Sun.COM
183310843SDave.Plauger@Sun.COM return (offset);
183410843SDave.Plauger@Sun.COM }
183510843SDave.Plauger@Sun.COM
183610843SDave.Plauger@Sun.COM /*
183710843SDave.Plauger@Sun.COM * Read the helper queue, and copy one mapped page. Return 0 when
183810843SDave.Plauger@Sun.COM * done. Return 1 when a page has been copied into hp->page.
183910843SDave.Plauger@Sun.COM */
184010843SDave.Plauger@Sun.COM static int
dumpsys_sread(helper_t * hp)184110843SDave.Plauger@Sun.COM dumpsys_sread(helper_t *hp)
184210843SDave.Plauger@Sun.COM {
184310843SDave.Plauger@Sun.COM dumpsync_t *ds = hp->ds;
184410843SDave.Plauger@Sun.COM
184510843SDave.Plauger@Sun.COM /* CONSTCOND */
184610843SDave.Plauger@Sun.COM while (1) {
184710843SDave.Plauger@Sun.COM
184810843SDave.Plauger@Sun.COM /* Find the next input buffer. */
184910843SDave.Plauger@Sun.COM if (hp->cpin == NULL) {
185010843SDave.Plauger@Sun.COM HRSTART(hp->perpage, inwait);
185110843SDave.Plauger@Sun.COM
185210843SDave.Plauger@Sun.COM /* CONSTCOND */
185310843SDave.Plauger@Sun.COM while (1) {
185410843SDave.Plauger@Sun.COM hp->cpin = CQ_GET(helperq);
185510843SDave.Plauger@Sun.COM dump_timeleft = dump_timeout;
185610843SDave.Plauger@Sun.COM
185710843SDave.Plauger@Sun.COM /*
185810843SDave.Plauger@Sun.COM * NULL return means the helper queue
185910843SDave.Plauger@Sun.COM * is closed and empty.
186010843SDave.Plauger@Sun.COM */
186110843SDave.Plauger@Sun.COM if (hp->cpin == NULL)
186210843SDave.Plauger@Sun.COM break;
186310843SDave.Plauger@Sun.COM
186410843SDave.Plauger@Sun.COM /* Have input, check for dump I/O error. */
186510843SDave.Plauger@Sun.COM if (!dump_ioerr)
186610843SDave.Plauger@Sun.COM break;
186710843SDave.Plauger@Sun.COM
186810843SDave.Plauger@Sun.COM /*
186910843SDave.Plauger@Sun.COM * If an I/O error occurs, stay in the
187010843SDave.Plauger@Sun.COM * loop in order to empty the helper
187110843SDave.Plauger@Sun.COM * queue. Return the buffers to the
187210843SDave.Plauger@Sun.COM * main task to unmap and free it.
187310843SDave.Plauger@Sun.COM */
187410843SDave.Plauger@Sun.COM hp->cpin->used = 0;
187510843SDave.Plauger@Sun.COM CQ_PUT(mainq, hp->cpin, CBUF_USEDMAP);
187610843SDave.Plauger@Sun.COM }
187710843SDave.Plauger@Sun.COM HRSTOP(hp->perpage, inwait);
187810843SDave.Plauger@Sun.COM
187910843SDave.Plauger@Sun.COM /* Stop here when the helper queue is closed. */
188010843SDave.Plauger@Sun.COM if (hp->cpin == NULL)
188110843SDave.Plauger@Sun.COM break;
188210843SDave.Plauger@Sun.COM
188310843SDave.Plauger@Sun.COM /* Set the offset=0 to get the first pfn. */
188410843SDave.Plauger@Sun.COM hp->in = 0;
188510843SDave.Plauger@Sun.COM
188610843SDave.Plauger@Sun.COM /* Set the total processed to 0 */
188710843SDave.Plauger@Sun.COM hp->used = 0;
188810843SDave.Plauger@Sun.COM }
188910843SDave.Plauger@Sun.COM
189010843SDave.Plauger@Sun.COM /* Process the next page. */
189110843SDave.Plauger@Sun.COM if (hp->used < hp->cpin->used) {
189210843SDave.Plauger@Sun.COM
189310843SDave.Plauger@Sun.COM /*
189410843SDave.Plauger@Sun.COM * Get the next page from the input buffer and
189510843SDave.Plauger@Sun.COM * return a copy.
189610843SDave.Plauger@Sun.COM */
189710843SDave.Plauger@Sun.COM ASSERT(hp->in != -1);
189810843SDave.Plauger@Sun.COM HRSTART(hp->perpage, copy);
189910843SDave.Plauger@Sun.COM hp->in = dumpsys_copy_page(hp, hp->in);
190010843SDave.Plauger@Sun.COM hp->used += PAGESIZE;
190110843SDave.Plauger@Sun.COM HRSTOP(hp->perpage, copy);
190210843SDave.Plauger@Sun.COM break;
190310843SDave.Plauger@Sun.COM
190410843SDave.Plauger@Sun.COM } else {
190510843SDave.Plauger@Sun.COM
190610843SDave.Plauger@Sun.COM /*
190710843SDave.Plauger@Sun.COM * Done with the input. Flush the VM and
190810843SDave.Plauger@Sun.COM * return the buffer to the main task.
190910843SDave.Plauger@Sun.COM */
191010843SDave.Plauger@Sun.COM if (panicstr && hp->helper != MAINHELPER)
191110843SDave.Plauger@Sun.COM hat_flush_range(kas.a_hat,
191210843SDave.Plauger@Sun.COM hp->cpin->buf, hp->cpin->size);
191310843SDave.Plauger@Sun.COM dumpsys_errmsg(hp, NULL);
191410843SDave.Plauger@Sun.COM CQ_PUT(mainq, hp->cpin, CBUF_USEDMAP);
191510843SDave.Plauger@Sun.COM hp->cpin = NULL;
191610843SDave.Plauger@Sun.COM }
191710843SDave.Plauger@Sun.COM }
191810843SDave.Plauger@Sun.COM
191910843SDave.Plauger@Sun.COM return (hp->cpin != NULL);
192010843SDave.Plauger@Sun.COM }
192110843SDave.Plauger@Sun.COM
192210843SDave.Plauger@Sun.COM /*
192310843SDave.Plauger@Sun.COM * Compress size bytes starting at buf with bzip2
192410843SDave.Plauger@Sun.COM * mode:
192510843SDave.Plauger@Sun.COM * BZ_RUN add one more compressed page
192610843SDave.Plauger@Sun.COM * BZ_FINISH no more input, flush the state
192710843SDave.Plauger@Sun.COM */
192810843SDave.Plauger@Sun.COM static void
dumpsys_bzrun(helper_t * hp,void * buf,size_t size,int mode)192910843SDave.Plauger@Sun.COM dumpsys_bzrun(helper_t *hp, void *buf, size_t size, int mode)
193010843SDave.Plauger@Sun.COM {
193110843SDave.Plauger@Sun.COM dumpsync_t *ds = hp->ds;
193210843SDave.Plauger@Sun.COM const int CSIZE = sizeof (dumpcsize_t);
193310843SDave.Plauger@Sun.COM bz_stream *ps = &hp->bzstream;
193410843SDave.Plauger@Sun.COM int rc = 0;
193510843SDave.Plauger@Sun.COM uint32_t csize;
193610843SDave.Plauger@Sun.COM dumpcsize_t cs;
193710843SDave.Plauger@Sun.COM
193810843SDave.Plauger@Sun.COM /* Set input pointers to new input page */
193910843SDave.Plauger@Sun.COM if (size > 0) {
194010843SDave.Plauger@Sun.COM ps->avail_in = size;
194110843SDave.Plauger@Sun.COM ps->next_in = buf;
194210843SDave.Plauger@Sun.COM }
194310843SDave.Plauger@Sun.COM
194410843SDave.Plauger@Sun.COM /* CONSTCOND */
194510843SDave.Plauger@Sun.COM while (1) {
194610843SDave.Plauger@Sun.COM
194710843SDave.Plauger@Sun.COM /* Quit when all input has been consumed */
194810843SDave.Plauger@Sun.COM if (ps->avail_in == 0 && mode == BZ_RUN)
194910843SDave.Plauger@Sun.COM break;
195010843SDave.Plauger@Sun.COM
195110843SDave.Plauger@Sun.COM /* Get a new output buffer */
195210843SDave.Plauger@Sun.COM if (hp->cpout == NULL) {
195310843SDave.Plauger@Sun.COM HRSTART(hp->perpage, outwait);
195410843SDave.Plauger@Sun.COM hp->cpout = CQ_GET(freebufq);
195510843SDave.Plauger@Sun.COM HRSTOP(hp->perpage, outwait);
195610843SDave.Plauger@Sun.COM ps->avail_out = hp->cpout->size - CSIZE;
195710843SDave.Plauger@Sun.COM ps->next_out = hp->cpout->buf + CSIZE;
195810843SDave.Plauger@Sun.COM }
195910843SDave.Plauger@Sun.COM
196010843SDave.Plauger@Sun.COM /* Compress input, or finalize */
196110843SDave.Plauger@Sun.COM HRSTART(hp->perpage, compress);
196210843SDave.Plauger@Sun.COM rc = BZ2_bzCompress(ps, mode);
196310843SDave.Plauger@Sun.COM HRSTOP(hp->perpage, compress);
196410843SDave.Plauger@Sun.COM
196510843SDave.Plauger@Sun.COM /* Check for error */
196610843SDave.Plauger@Sun.COM if (mode == BZ_RUN && rc != BZ_RUN_OK) {
196710843SDave.Plauger@Sun.COM dumpsys_errmsg(hp, "%d: BZ_RUN error %s at page %lx\n",
196810843SDave.Plauger@Sun.COM hp->helper, BZ2_bzErrorString(rc),
196910843SDave.Plauger@Sun.COM hp->cpin->pagenum);
197010843SDave.Plauger@Sun.COM break;
197110843SDave.Plauger@Sun.COM }
197210843SDave.Plauger@Sun.COM
197310843SDave.Plauger@Sun.COM /* Write the buffer if it is full, or we are flushing */
197410843SDave.Plauger@Sun.COM if (ps->avail_out == 0 || mode == BZ_FINISH) {
197510843SDave.Plauger@Sun.COM csize = hp->cpout->size - CSIZE - ps->avail_out;
197610843SDave.Plauger@Sun.COM cs = DUMP_SET_TAG(csize, hp->tag);
197710843SDave.Plauger@Sun.COM if (csize > 0) {
197810843SDave.Plauger@Sun.COM (void) memcpy(hp->cpout->buf, &cs, CSIZE);
197910843SDave.Plauger@Sun.COM dumpsys_swrite(hp, hp->cpout, csize + CSIZE);
198010843SDave.Plauger@Sun.COM hp->cpout = NULL;
198110843SDave.Plauger@Sun.COM }
198210843SDave.Plauger@Sun.COM }
198310843SDave.Plauger@Sun.COM
198410843SDave.Plauger@Sun.COM /* Check for final complete */
198510843SDave.Plauger@Sun.COM if (mode == BZ_FINISH) {
198610843SDave.Plauger@Sun.COM if (rc == BZ_STREAM_END)
198710843SDave.Plauger@Sun.COM break;
198810843SDave.Plauger@Sun.COM if (rc != BZ_FINISH_OK) {
198910843SDave.Plauger@Sun.COM dumpsys_errmsg(hp, "%d: BZ_FINISH error %s\n",
199010843SDave.Plauger@Sun.COM hp->helper, BZ2_bzErrorString(rc));
199110843SDave.Plauger@Sun.COM break;
199210843SDave.Plauger@Sun.COM }
199310843SDave.Plauger@Sun.COM }
199410843SDave.Plauger@Sun.COM }
199510843SDave.Plauger@Sun.COM
199610843SDave.Plauger@Sun.COM /* Cleanup state and buffers */
199710843SDave.Plauger@Sun.COM if (mode == BZ_FINISH) {
199810843SDave.Plauger@Sun.COM
199910843SDave.Plauger@Sun.COM /* Reset state so that it is re-usable. */
200010843SDave.Plauger@Sun.COM (void) BZ2_bzCompressReset(&hp->bzstream);
200110843SDave.Plauger@Sun.COM
200210843SDave.Plauger@Sun.COM /* Give any unused outout buffer to the main task */
200310843SDave.Plauger@Sun.COM if (hp->cpout != NULL) {
200410843SDave.Plauger@Sun.COM hp->cpout->used = 0;
200510843SDave.Plauger@Sun.COM CQ_PUT(mainq, hp->cpout, CBUF_ERRMSG);
200610843SDave.Plauger@Sun.COM hp->cpout = NULL;
200710843SDave.Plauger@Sun.COM }
200810843SDave.Plauger@Sun.COM }
200910843SDave.Plauger@Sun.COM }
201010843SDave.Plauger@Sun.COM
201110843SDave.Plauger@Sun.COM static void
dumpsys_bz2compress(helper_t * hp)201210843SDave.Plauger@Sun.COM dumpsys_bz2compress(helper_t *hp)
201310843SDave.Plauger@Sun.COM {
201410843SDave.Plauger@Sun.COM dumpsync_t *ds = hp->ds;
201510843SDave.Plauger@Sun.COM dumpstreamhdr_t sh;
201610843SDave.Plauger@Sun.COM
201710843SDave.Plauger@Sun.COM (void) strcpy(sh.stream_magic, DUMP_STREAM_MAGIC);
201810843SDave.Plauger@Sun.COM sh.stream_pagenum = (pgcnt_t)-1;
201910843SDave.Plauger@Sun.COM sh.stream_npages = 0;
202010843SDave.Plauger@Sun.COM hp->cpin = NULL;
202110843SDave.Plauger@Sun.COM hp->cpout = NULL;
202210843SDave.Plauger@Sun.COM hp->cperr = NULL;
202310843SDave.Plauger@Sun.COM hp->in = 0;
202410843SDave.Plauger@Sun.COM hp->out = 0;
202510843SDave.Plauger@Sun.COM hp->bzstream.avail_in = 0;
202610843SDave.Plauger@Sun.COM
202710843SDave.Plauger@Sun.COM /* Bump reference to mainq while we are running */
202810843SDave.Plauger@Sun.COM CQ_OPEN(mainq);
202910843SDave.Plauger@Sun.COM
203010843SDave.Plauger@Sun.COM /* Get one page at a time */
203110843SDave.Plauger@Sun.COM while (dumpsys_sread(hp)) {
203210843SDave.Plauger@Sun.COM if (sh.stream_pagenum != hp->cpin->pagenum) {
203310843SDave.Plauger@Sun.COM sh.stream_pagenum = hp->cpin->pagenum;
203410843SDave.Plauger@Sun.COM sh.stream_npages = btop(hp->cpin->used);
203510843SDave.Plauger@Sun.COM dumpsys_bzrun(hp, &sh, sizeof (sh), BZ_RUN);
203610843SDave.Plauger@Sun.COM }
203710843SDave.Plauger@Sun.COM dumpsys_bzrun(hp, hp->page, PAGESIZE, 0);
203810843SDave.Plauger@Sun.COM }
203910843SDave.Plauger@Sun.COM
204010843SDave.Plauger@Sun.COM /* Done with input, flush any partial buffer */
204110843SDave.Plauger@Sun.COM if (sh.stream_pagenum != (pgcnt_t)-1) {
204210843SDave.Plauger@Sun.COM dumpsys_bzrun(hp, NULL, 0, BZ_FINISH);
204310843SDave.Plauger@Sun.COM dumpsys_errmsg(hp, NULL);
204410843SDave.Plauger@Sun.COM }
204510843SDave.Plauger@Sun.COM
204610843SDave.Plauger@Sun.COM ASSERT(hp->cpin == NULL && hp->cpout == NULL && hp->cperr == NULL);
204710843SDave.Plauger@Sun.COM
204810843SDave.Plauger@Sun.COM /* Decrement main queue count, we are done */
204910843SDave.Plauger@Sun.COM CQ_CLOSE(mainq);
205010843SDave.Plauger@Sun.COM }
205110843SDave.Plauger@Sun.COM
205210843SDave.Plauger@Sun.COM /*
205310843SDave.Plauger@Sun.COM * Compress with lzjb
205410843SDave.Plauger@Sun.COM * write stream block if full or size==0
205510843SDave.Plauger@Sun.COM * if csize==0 write stream header, else write <csize, data>
205610843SDave.Plauger@Sun.COM * size==0 is a call to flush a buffer
205710843SDave.Plauger@Sun.COM * hp->cpout is the buffer we are flushing or filling
205810843SDave.Plauger@Sun.COM * hp->out is the next index to fill data
205910843SDave.Plauger@Sun.COM * osize is either csize+data, or the size of a stream header
206010843SDave.Plauger@Sun.COM */
206110843SDave.Plauger@Sun.COM static void
dumpsys_lzjbrun(helper_t * hp,size_t csize,void * buf,size_t size)206210843SDave.Plauger@Sun.COM dumpsys_lzjbrun(helper_t *hp, size_t csize, void *buf, size_t size)
206310843SDave.Plauger@Sun.COM {
206410843SDave.Plauger@Sun.COM dumpsync_t *ds = hp->ds;
206510843SDave.Plauger@Sun.COM const int CSIZE = sizeof (dumpcsize_t);
206610843SDave.Plauger@Sun.COM dumpcsize_t cs;
206710843SDave.Plauger@Sun.COM size_t osize = csize > 0 ? CSIZE + size : size;
206810843SDave.Plauger@Sun.COM
206910843SDave.Plauger@Sun.COM /* If flush, and there is no buffer, just return */
207010843SDave.Plauger@Sun.COM if (size == 0 && hp->cpout == NULL)
207110843SDave.Plauger@Sun.COM return;
207210843SDave.Plauger@Sun.COM
207310843SDave.Plauger@Sun.COM /* If flush, or cpout is full, write it out */
207410843SDave.Plauger@Sun.COM if (size == 0 ||
207510843SDave.Plauger@Sun.COM hp->cpout != NULL && hp->out + osize > hp->cpout->size) {
207610843SDave.Plauger@Sun.COM
207710843SDave.Plauger@Sun.COM /* Set tag+size word at the front of the stream block. */
207810843SDave.Plauger@Sun.COM cs = DUMP_SET_TAG(hp->out - CSIZE, hp->tag);
207910843SDave.Plauger@Sun.COM (void) memcpy(hp->cpout->buf, &cs, CSIZE);
208010843SDave.Plauger@Sun.COM
208110843SDave.Plauger@Sun.COM /* Write block to dump file. */
208210843SDave.Plauger@Sun.COM dumpsys_swrite(hp, hp->cpout, hp->out);
208310843SDave.Plauger@Sun.COM
208410843SDave.Plauger@Sun.COM /* Clear pointer to indicate we need a new buffer */
208510843SDave.Plauger@Sun.COM hp->cpout = NULL;
208610843SDave.Plauger@Sun.COM
208710843SDave.Plauger@Sun.COM /* flushing, we are done */
208810843SDave.Plauger@Sun.COM if (size == 0)
208910843SDave.Plauger@Sun.COM return;
209010843SDave.Plauger@Sun.COM }
209110843SDave.Plauger@Sun.COM
209210843SDave.Plauger@Sun.COM /* Get an output buffer if we dont have one. */
209310843SDave.Plauger@Sun.COM if (hp->cpout == NULL) {
209410843SDave.Plauger@Sun.COM HRSTART(hp->perpage, outwait);
209510843SDave.Plauger@Sun.COM hp->cpout = CQ_GET(freebufq);
209610843SDave.Plauger@Sun.COM HRSTOP(hp->perpage, outwait);
209710843SDave.Plauger@Sun.COM hp->out = CSIZE;
209810843SDave.Plauger@Sun.COM }
209910843SDave.Plauger@Sun.COM
210010843SDave.Plauger@Sun.COM /* Store csize word. This is the size of compressed data. */
210110843SDave.Plauger@Sun.COM if (csize > 0) {
210210843SDave.Plauger@Sun.COM cs = DUMP_SET_TAG(csize, 0);
210310843SDave.Plauger@Sun.COM (void) memcpy(hp->cpout->buf + hp->out, &cs, CSIZE);
210410843SDave.Plauger@Sun.COM hp->out += CSIZE;
210510843SDave.Plauger@Sun.COM }
210610843SDave.Plauger@Sun.COM
210710843SDave.Plauger@Sun.COM /* Store the data. */
210810843SDave.Plauger@Sun.COM (void) memcpy(hp->cpout->buf + hp->out, buf, size);
210910843SDave.Plauger@Sun.COM hp->out += size;
211010843SDave.Plauger@Sun.COM }
211110843SDave.Plauger@Sun.COM
211210843SDave.Plauger@Sun.COM static void
dumpsys_lzjbcompress(helper_t * hp)211310843SDave.Plauger@Sun.COM dumpsys_lzjbcompress(helper_t *hp)
211410843SDave.Plauger@Sun.COM {
211510843SDave.Plauger@Sun.COM dumpsync_t *ds = hp->ds;
211610843SDave.Plauger@Sun.COM size_t csize;
211710843SDave.Plauger@Sun.COM dumpstreamhdr_t sh;
211810843SDave.Plauger@Sun.COM
211910843SDave.Plauger@Sun.COM (void) strcpy(sh.stream_magic, DUMP_STREAM_MAGIC);
212010843SDave.Plauger@Sun.COM sh.stream_pagenum = (pfn_t)-1;
212110843SDave.Plauger@Sun.COM sh.stream_npages = 0;
212210843SDave.Plauger@Sun.COM hp->cpin = NULL;
212310843SDave.Plauger@Sun.COM hp->cpout = NULL;
212410843SDave.Plauger@Sun.COM hp->cperr = NULL;
212510843SDave.Plauger@Sun.COM hp->in = 0;
212610843SDave.Plauger@Sun.COM hp->out = 0;
212710843SDave.Plauger@Sun.COM
212810843SDave.Plauger@Sun.COM /* Bump reference to mainq while we are running */
212910843SDave.Plauger@Sun.COM CQ_OPEN(mainq);
213010843SDave.Plauger@Sun.COM
213110843SDave.Plauger@Sun.COM /* Get one page at a time */
213210843SDave.Plauger@Sun.COM while (dumpsys_sread(hp)) {
213310843SDave.Plauger@Sun.COM
213410843SDave.Plauger@Sun.COM /* Create a stream header for each new input map */
213510843SDave.Plauger@Sun.COM if (sh.stream_pagenum != hp->cpin->pagenum) {
213610843SDave.Plauger@Sun.COM sh.stream_pagenum = hp->cpin->pagenum;
213710843SDave.Plauger@Sun.COM sh.stream_npages = btop(hp->cpin->used);
213810843SDave.Plauger@Sun.COM dumpsys_lzjbrun(hp, 0, &sh, sizeof (sh));
213910843SDave.Plauger@Sun.COM }
214010843SDave.Plauger@Sun.COM
214110843SDave.Plauger@Sun.COM /* Compress one page */
214210843SDave.Plauger@Sun.COM HRSTART(hp->perpage, compress);
214310843SDave.Plauger@Sun.COM csize = compress(hp->page, hp->lzbuf, PAGESIZE);
214410843SDave.Plauger@Sun.COM HRSTOP(hp->perpage, compress);
214510843SDave.Plauger@Sun.COM
214610843SDave.Plauger@Sun.COM /* Add csize+data to output block */
214710843SDave.Plauger@Sun.COM ASSERT(csize > 0 && csize <= PAGESIZE);
214810843SDave.Plauger@Sun.COM dumpsys_lzjbrun(hp, csize, hp->lzbuf, csize);
214910843SDave.Plauger@Sun.COM }
215010843SDave.Plauger@Sun.COM
215110843SDave.Plauger@Sun.COM /* Done with input, flush any partial buffer */
215210843SDave.Plauger@Sun.COM if (sh.stream_pagenum != (pfn_t)-1) {
215310843SDave.Plauger@Sun.COM dumpsys_lzjbrun(hp, 0, NULL, 0);
215410843SDave.Plauger@Sun.COM dumpsys_errmsg(hp, NULL);
215510843SDave.Plauger@Sun.COM }
215610843SDave.Plauger@Sun.COM
215710843SDave.Plauger@Sun.COM ASSERT(hp->cpin == NULL && hp->cpout == NULL && hp->cperr == NULL);
215810843SDave.Plauger@Sun.COM
215910843SDave.Plauger@Sun.COM /* Decrement main queue count, we are done */
216010843SDave.Plauger@Sun.COM CQ_CLOSE(mainq);
216110843SDave.Plauger@Sun.COM }
216210843SDave.Plauger@Sun.COM
216310843SDave.Plauger@Sun.COM /*
216410843SDave.Plauger@Sun.COM * Dump helper called from panic_idle() to compress pages. CPUs in
216510843SDave.Plauger@Sun.COM * this path must not call most kernel services.
216610843SDave.Plauger@Sun.COM *
216710843SDave.Plauger@Sun.COM * During panic, all but one of the CPUs is idle. These CPUs are used
216810843SDave.Plauger@Sun.COM * as helpers working in parallel to copy and compress memory
216910843SDave.Plauger@Sun.COM * pages. During a panic, however, these processors cannot call any
217010843SDave.Plauger@Sun.COM * kernel services. This is because mutexes become no-ops during
217110843SDave.Plauger@Sun.COM * panic, and, cross-call interrupts are inhibited. Therefore, during
217210843SDave.Plauger@Sun.COM * panic dump the helper CPUs communicate with the panic CPU using
217310843SDave.Plauger@Sun.COM * memory variables. All memory mapping and I/O is performed by the
217410843SDave.Plauger@Sun.COM * panic CPU.
217512640SDave.Plauger@Sun.COM *
217612640SDave.Plauger@Sun.COM * At dump configuration time, helper_lock is set and helpers_wanted
217712640SDave.Plauger@Sun.COM * is 0. dumpsys() decides whether to set helpers_wanted before
217812640SDave.Plauger@Sun.COM * clearing helper_lock.
217912640SDave.Plauger@Sun.COM *
218012640SDave.Plauger@Sun.COM * At panic time, idle CPUs spin-wait on helper_lock, then alternately
218112640SDave.Plauger@Sun.COM * take the lock and become a helper, or return.
218210843SDave.Plauger@Sun.COM */
218310843SDave.Plauger@Sun.COM void
dumpsys_helper()218410843SDave.Plauger@Sun.COM dumpsys_helper()
218510843SDave.Plauger@Sun.COM {
218610843SDave.Plauger@Sun.COM dumpsys_spinlock(&dumpcfg.helper_lock);
218710843SDave.Plauger@Sun.COM if (dumpcfg.helpers_wanted) {
218810843SDave.Plauger@Sun.COM helper_t *hp, *hpend = &dumpcfg.helper[dumpcfg.nhelper];
218910843SDave.Plauger@Sun.COM
219010843SDave.Plauger@Sun.COM for (hp = dumpcfg.helper; hp != hpend; hp++) {
219110843SDave.Plauger@Sun.COM if (hp->helper == FREEHELPER) {
219210843SDave.Plauger@Sun.COM hp->helper = CPU->cpu_id;
219310843SDave.Plauger@Sun.COM BT_SET(dumpcfg.helpermap, CPU->cpu_seqid);
219410843SDave.Plauger@Sun.COM
219510843SDave.Plauger@Sun.COM dumpsys_spinunlock(&dumpcfg.helper_lock);
219610843SDave.Plauger@Sun.COM
219710843SDave.Plauger@Sun.COM if (dumpcfg.clevel < DUMP_CLEVEL_BZIP2)
219810843SDave.Plauger@Sun.COM dumpsys_lzjbcompress(hp);
219910843SDave.Plauger@Sun.COM else
220010843SDave.Plauger@Sun.COM dumpsys_bz2compress(hp);
220110843SDave.Plauger@Sun.COM
220210843SDave.Plauger@Sun.COM hp->helper = DONEHELPER;
220310843SDave.Plauger@Sun.COM return;
220410843SDave.Plauger@Sun.COM }
220510843SDave.Plauger@Sun.COM }
220612640SDave.Plauger@Sun.COM
220712640SDave.Plauger@Sun.COM /* No more helpers are needed. */
220812640SDave.Plauger@Sun.COM dumpcfg.helpers_wanted = 0;
220912640SDave.Plauger@Sun.COM
221010843SDave.Plauger@Sun.COM }
221110843SDave.Plauger@Sun.COM dumpsys_spinunlock(&dumpcfg.helper_lock);
221210843SDave.Plauger@Sun.COM }
221310843SDave.Plauger@Sun.COM
221410843SDave.Plauger@Sun.COM /*
221512640SDave.Plauger@Sun.COM * No-wait helper callable in spin loops.
221612640SDave.Plauger@Sun.COM *
221712640SDave.Plauger@Sun.COM * Do not wait for helper_lock. Just check helpers_wanted. The caller
221812640SDave.Plauger@Sun.COM * may decide to continue. This is the "c)ontinue, s)ync, r)eset? s"
221912640SDave.Plauger@Sun.COM * case.
222012640SDave.Plauger@Sun.COM */
222112640SDave.Plauger@Sun.COM void
dumpsys_helper_nw()222212640SDave.Plauger@Sun.COM dumpsys_helper_nw()
222312640SDave.Plauger@Sun.COM {
222412640SDave.Plauger@Sun.COM if (dumpcfg.helpers_wanted)
222512640SDave.Plauger@Sun.COM dumpsys_helper();
222612640SDave.Plauger@Sun.COM }
222712640SDave.Plauger@Sun.COM
222812640SDave.Plauger@Sun.COM /*
222910843SDave.Plauger@Sun.COM * Dump helper for live dumps.
223010843SDave.Plauger@Sun.COM * These run as a system task.
223110843SDave.Plauger@Sun.COM */
223210843SDave.Plauger@Sun.COM static void
dumpsys_live_helper(void * arg)223310843SDave.Plauger@Sun.COM dumpsys_live_helper(void *arg)
223410843SDave.Plauger@Sun.COM {
223510843SDave.Plauger@Sun.COM helper_t *hp = arg;
223610843SDave.Plauger@Sun.COM
223710843SDave.Plauger@Sun.COM BT_ATOMIC_SET(dumpcfg.helpermap, CPU->cpu_seqid);
223810843SDave.Plauger@Sun.COM if (dumpcfg.clevel < DUMP_CLEVEL_BZIP2)
223910843SDave.Plauger@Sun.COM dumpsys_lzjbcompress(hp);
224010843SDave.Plauger@Sun.COM else
224110843SDave.Plauger@Sun.COM dumpsys_bz2compress(hp);
224210843SDave.Plauger@Sun.COM }
224310843SDave.Plauger@Sun.COM
224410843SDave.Plauger@Sun.COM /*
224510843SDave.Plauger@Sun.COM * Compress one page with lzjb (single threaded case)
224610843SDave.Plauger@Sun.COM */
224710843SDave.Plauger@Sun.COM static void
dumpsys_lzjb_page(helper_t * hp,cbuf_t * cp)224810843SDave.Plauger@Sun.COM dumpsys_lzjb_page(helper_t *hp, cbuf_t *cp)
224910843SDave.Plauger@Sun.COM {
225010843SDave.Plauger@Sun.COM dumpsync_t *ds = hp->ds;
225110843SDave.Plauger@Sun.COM uint32_t csize;
225210843SDave.Plauger@Sun.COM
225310843SDave.Plauger@Sun.COM hp->helper = MAINHELPER;
225410843SDave.Plauger@Sun.COM hp->in = 0;
225510843SDave.Plauger@Sun.COM hp->used = 0;
225610843SDave.Plauger@Sun.COM hp->cpin = cp;
225710843SDave.Plauger@Sun.COM while (hp->used < cp->used) {
225810843SDave.Plauger@Sun.COM HRSTART(hp->perpage, copy);
225910843SDave.Plauger@Sun.COM hp->in = dumpsys_copy_page(hp, hp->in);
226010843SDave.Plauger@Sun.COM hp->used += PAGESIZE;
226110843SDave.Plauger@Sun.COM HRSTOP(hp->perpage, copy);
226210843SDave.Plauger@Sun.COM
226310843SDave.Plauger@Sun.COM HRSTART(hp->perpage, compress);
226410843SDave.Plauger@Sun.COM csize = compress(hp->page, hp->lzbuf, PAGESIZE);
226510843SDave.Plauger@Sun.COM HRSTOP(hp->perpage, compress);
226610843SDave.Plauger@Sun.COM
226710843SDave.Plauger@Sun.COM HRSTART(hp->perpage, write);
226810843SDave.Plauger@Sun.COM dumpvp_write(&csize, sizeof (csize));
226910843SDave.Plauger@Sun.COM dumpvp_write(hp->lzbuf, csize);
227010843SDave.Plauger@Sun.COM HRSTOP(hp->perpage, write);
227110843SDave.Plauger@Sun.COM }
227210843SDave.Plauger@Sun.COM CQ_PUT(mainq, hp->cpin, CBUF_USEDMAP);
227310843SDave.Plauger@Sun.COM hp->cpin = NULL;
227410843SDave.Plauger@Sun.COM }
227510843SDave.Plauger@Sun.COM
227610843SDave.Plauger@Sun.COM /*
227710843SDave.Plauger@Sun.COM * Main task to dump pages. This is called on the dump CPU.
227810843SDave.Plauger@Sun.COM */
227910843SDave.Plauger@Sun.COM static void
dumpsys_main_task(void * arg)228010843SDave.Plauger@Sun.COM dumpsys_main_task(void *arg)
228110843SDave.Plauger@Sun.COM {
228210843SDave.Plauger@Sun.COM dumpsync_t *ds = arg;
228310843SDave.Plauger@Sun.COM pgcnt_t pagenum = 0, bitnum = 0, hibitnum;
228410843SDave.Plauger@Sun.COM dumpmlw_t mlw;
228510843SDave.Plauger@Sun.COM cbuf_t *cp;
228610843SDave.Plauger@Sun.COM pgcnt_t baseoff, pfnoff;
228710843SDave.Plauger@Sun.COM pfn_t base, pfn;
2288*13145SDave.Plauger@Sun.COM int sec, i, dumpserial;
2289*13145SDave.Plauger@Sun.COM
2290*13145SDave.Plauger@Sun.COM /*
2291*13145SDave.Plauger@Sun.COM * Fall back to serial mode if there are no helpers.
2292*13145SDave.Plauger@Sun.COM * dump_plat_mincpu can be set to 0 at any time.
2293*13145SDave.Plauger@Sun.COM * dumpcfg.helpermap must contain at least one member.
2294*13145SDave.Plauger@Sun.COM */
2295*13145SDave.Plauger@Sun.COM dumpserial = 1;
2296*13145SDave.Plauger@Sun.COM
2297*13145SDave.Plauger@Sun.COM if (dump_plat_mincpu != 0 && dumpcfg.clevel != 0) {
2298*13145SDave.Plauger@Sun.COM for (i = 0; i < BT_BITOUL(NCPU); ++i) {
2299*13145SDave.Plauger@Sun.COM if (dumpcfg.helpermap[i] != 0) {
2300*13145SDave.Plauger@Sun.COM dumpserial = 0;
2301*13145SDave.Plauger@Sun.COM break;
2302*13145SDave.Plauger@Sun.COM }
2303*13145SDave.Plauger@Sun.COM }
2304*13145SDave.Plauger@Sun.COM }
2305*13145SDave.Plauger@Sun.COM
2306*13145SDave.Plauger@Sun.COM if (dumpserial) {
2307*13145SDave.Plauger@Sun.COM dumpcfg.clevel = 0;
2308*13145SDave.Plauger@Sun.COM if (dumpcfg.helper[0].lzbuf == NULL)
2309*13145SDave.Plauger@Sun.COM dumpcfg.helper[0].lzbuf = dumpcfg.helper[1].page;
2310*13145SDave.Plauger@Sun.COM }
231110843SDave.Plauger@Sun.COM
231210843SDave.Plauger@Sun.COM dump_init_memlist_walker(&mlw);
231310843SDave.Plauger@Sun.COM
231410843SDave.Plauger@Sun.COM /* CONSTCOND */
231510843SDave.Plauger@Sun.COM while (1) {
231610843SDave.Plauger@Sun.COM
231710843SDave.Plauger@Sun.COM if (ds->percent > ds->percent_done) {
231810843SDave.Plauger@Sun.COM ds->percent_done = ds->percent;
231910843SDave.Plauger@Sun.COM sec = (gethrtime() - ds->start) / 1000 / 1000 / 1000;
232010843SDave.Plauger@Sun.COM uprintf("^\r%2d:%02d %3d%% done",
232110843SDave.Plauger@Sun.COM sec / 60, sec % 60, ds->percent);
232210843SDave.Plauger@Sun.COM ds->neednl = 1;
232310843SDave.Plauger@Sun.COM }
232410843SDave.Plauger@Sun.COM
232510843SDave.Plauger@Sun.COM while (CQ_IS_EMPTY(mainq) && !CQ_IS_EMPTY(writerq)) {
232610843SDave.Plauger@Sun.COM
232710843SDave.Plauger@Sun.COM /* the writerq never blocks */
232810843SDave.Plauger@Sun.COM cp = CQ_GET(writerq);
232910843SDave.Plauger@Sun.COM if (cp == NULL)
233010843SDave.Plauger@Sun.COM break;
233110843SDave.Plauger@Sun.COM
233210843SDave.Plauger@Sun.COM dump_timeleft = dump_timeout;
233310843SDave.Plauger@Sun.COM
233410843SDave.Plauger@Sun.COM HRSTART(ds->perpage, write);
233510843SDave.Plauger@Sun.COM dumpvp_write(cp->buf, cp->used);
233610843SDave.Plauger@Sun.COM HRSTOP(ds->perpage, write);
233710843SDave.Plauger@Sun.COM
233810843SDave.Plauger@Sun.COM CQ_PUT(freebufq, cp, CBUF_FREEBUF);
233910843SDave.Plauger@Sun.COM }
234010843SDave.Plauger@Sun.COM
234110843SDave.Plauger@Sun.COM /*
234210843SDave.Plauger@Sun.COM * Wait here for some buffers to process. Returns NULL
234310843SDave.Plauger@Sun.COM * when all helpers have terminated and all buffers
234410843SDave.Plauger@Sun.COM * have been processed.
234510843SDave.Plauger@Sun.COM */
234610843SDave.Plauger@Sun.COM cp = CQ_GET(mainq);
234710843SDave.Plauger@Sun.COM
234810843SDave.Plauger@Sun.COM if (cp == NULL) {
234910843SDave.Plauger@Sun.COM
235010843SDave.Plauger@Sun.COM /* Drain the write queue. */
235110843SDave.Plauger@Sun.COM if (!CQ_IS_EMPTY(writerq))
235210843SDave.Plauger@Sun.COM continue;
235310843SDave.Plauger@Sun.COM
235410843SDave.Plauger@Sun.COM /* Main task exits here. */
235510843SDave.Plauger@Sun.COM break;
235610843SDave.Plauger@Sun.COM }
235710843SDave.Plauger@Sun.COM
235810843SDave.Plauger@Sun.COM dump_timeleft = dump_timeout;
235910843SDave.Plauger@Sun.COM
236010843SDave.Plauger@Sun.COM switch (cp->state) {
236110843SDave.Plauger@Sun.COM
236210843SDave.Plauger@Sun.COM case CBUF_FREEMAP:
236310843SDave.Plauger@Sun.COM
236410843SDave.Plauger@Sun.COM /*
236510843SDave.Plauger@Sun.COM * Note that we drop CBUF_FREEMAP buffers on
236610843SDave.Plauger@Sun.COM * the floor (they will not be on any cqueue)
236710843SDave.Plauger@Sun.COM * when we no longer need them.
236810843SDave.Plauger@Sun.COM */
236910843SDave.Plauger@Sun.COM if (bitnum >= dumpcfg.bitmapsize)
237010843SDave.Plauger@Sun.COM break;
237110843SDave.Plauger@Sun.COM
237210843SDave.Plauger@Sun.COM if (dump_ioerr) {
237310843SDave.Plauger@Sun.COM bitnum = dumpcfg.bitmapsize;
237410843SDave.Plauger@Sun.COM CQ_CLOSE(helperq);
237510843SDave.Plauger@Sun.COM break;
237610843SDave.Plauger@Sun.COM }
237710843SDave.Plauger@Sun.COM
237810843SDave.Plauger@Sun.COM HRSTART(ds->perpage, bitmap);
237910843SDave.Plauger@Sun.COM for (; bitnum < dumpcfg.bitmapsize; bitnum++)
238010843SDave.Plauger@Sun.COM if (BT_TEST(dumpcfg.bitmap, bitnum))
238110843SDave.Plauger@Sun.COM break;
238210843SDave.Plauger@Sun.COM HRSTOP(ds->perpage, bitmap);
238310843SDave.Plauger@Sun.COM dump_timeleft = dump_timeout;
238410843SDave.Plauger@Sun.COM
238510843SDave.Plauger@Sun.COM if (bitnum >= dumpcfg.bitmapsize) {
238610843SDave.Plauger@Sun.COM CQ_CLOSE(helperq);
238710843SDave.Plauger@Sun.COM break;
238810843SDave.Plauger@Sun.COM }
238910843SDave.Plauger@Sun.COM
239010843SDave.Plauger@Sun.COM /*
239110843SDave.Plauger@Sun.COM * Try to map CBUF_MAPSIZE ranges. Can't
239210843SDave.Plauger@Sun.COM * assume that memory segment size is a
239310843SDave.Plauger@Sun.COM * multiple of CBUF_MAPSIZE. Can't assume that
239410843SDave.Plauger@Sun.COM * the segment starts on a CBUF_MAPSIZE
239510843SDave.Plauger@Sun.COM * boundary.
239610843SDave.Plauger@Sun.COM */
239710843SDave.Plauger@Sun.COM pfn = dump_bitnum_to_pfn(bitnum, &mlw);
239810843SDave.Plauger@Sun.COM ASSERT(pfn != PFN_INVALID);
239910843SDave.Plauger@Sun.COM ASSERT(bitnum + mlw.mpleft <= dumpcfg.bitmapsize);
240010843SDave.Plauger@Sun.COM
240110843SDave.Plauger@Sun.COM base = P2ALIGN(pfn, CBUF_MAPNP);
240210843SDave.Plauger@Sun.COM if (base < mlw.mpaddr) {
240310843SDave.Plauger@Sun.COM base = mlw.mpaddr;
240410843SDave.Plauger@Sun.COM baseoff = P2PHASE(base, CBUF_MAPNP);
240510843SDave.Plauger@Sun.COM } else {
240610843SDave.Plauger@Sun.COM baseoff = 0;
240710843SDave.Plauger@Sun.COM }
240810843SDave.Plauger@Sun.COM
240910843SDave.Plauger@Sun.COM pfnoff = pfn - base;
241010843SDave.Plauger@Sun.COM if (pfnoff + mlw.mpleft < CBUF_MAPNP) {
241110843SDave.Plauger@Sun.COM hibitnum = bitnum + mlw.mpleft;
241210843SDave.Plauger@Sun.COM cp->size = ptob(pfnoff + mlw.mpleft);
241310843SDave.Plauger@Sun.COM } else {
241410843SDave.Plauger@Sun.COM hibitnum = bitnum - pfnoff + CBUF_MAPNP -
241510843SDave.Plauger@Sun.COM baseoff;
241610843SDave.Plauger@Sun.COM cp->size = CBUF_MAPSIZE - ptob(baseoff);
241710843SDave.Plauger@Sun.COM }
241810843SDave.Plauger@Sun.COM
241910843SDave.Plauger@Sun.COM cp->pfn = pfn;
242010843SDave.Plauger@Sun.COM cp->bitnum = bitnum++;
242110843SDave.Plauger@Sun.COM cp->pagenum = pagenum++;
242210843SDave.Plauger@Sun.COM cp->off = ptob(pfnoff);
242310843SDave.Plauger@Sun.COM
242410843SDave.Plauger@Sun.COM for (; bitnum < hibitnum; bitnum++)
242510843SDave.Plauger@Sun.COM if (BT_TEST(dumpcfg.bitmap, bitnum))
242610843SDave.Plauger@Sun.COM pagenum++;
242710843SDave.Plauger@Sun.COM
242810843SDave.Plauger@Sun.COM dump_timeleft = dump_timeout;
242910843SDave.Plauger@Sun.COM cp->used = ptob(pagenum - cp->pagenum);
243010843SDave.Plauger@Sun.COM
243110843SDave.Plauger@Sun.COM HRSTART(ds->perpage, map);
243210843SDave.Plauger@Sun.COM hat_devload(kas.a_hat, cp->buf, cp->size, base,
243310843SDave.Plauger@Sun.COM PROT_READ, HAT_LOAD_NOCONSIST);
243410843SDave.Plauger@Sun.COM HRSTOP(ds->perpage, map);
243510843SDave.Plauger@Sun.COM
243610843SDave.Plauger@Sun.COM ds->pages_mapped += btop(cp->size);
243710843SDave.Plauger@Sun.COM ds->pages_used += pagenum - cp->pagenum;
243810843SDave.Plauger@Sun.COM
243910843SDave.Plauger@Sun.COM CQ_OPEN(mainq);
244010843SDave.Plauger@Sun.COM
244110843SDave.Plauger@Sun.COM /*
244210843SDave.Plauger@Sun.COM * If there are no helpers the main task does
244310843SDave.Plauger@Sun.COM * non-streams lzjb compress.
244410843SDave.Plauger@Sun.COM */
2445*13145SDave.Plauger@Sun.COM if (dumpserial) {
244610843SDave.Plauger@Sun.COM dumpsys_lzjb_page(dumpcfg.helper, cp);
244710843SDave.Plauger@Sun.COM break;
244810843SDave.Plauger@Sun.COM }
244910843SDave.Plauger@Sun.COM
245010843SDave.Plauger@Sun.COM /* pass mapped pages to a helper */
245110843SDave.Plauger@Sun.COM CQ_PUT(helperq, cp, CBUF_INREADY);
245210843SDave.Plauger@Sun.COM
245310843SDave.Plauger@Sun.COM /* the last page was done */
245410843SDave.Plauger@Sun.COM if (bitnum >= dumpcfg.bitmapsize)
245510843SDave.Plauger@Sun.COM CQ_CLOSE(helperq);
245610843SDave.Plauger@Sun.COM
245710843SDave.Plauger@Sun.COM break;
245810843SDave.Plauger@Sun.COM
245910843SDave.Plauger@Sun.COM case CBUF_USEDMAP:
246010843SDave.Plauger@Sun.COM
246110843SDave.Plauger@Sun.COM ds->npages += btop(cp->used);
246210843SDave.Plauger@Sun.COM
246310843SDave.Plauger@Sun.COM HRSTART(ds->perpage, unmap);
246410843SDave.Plauger@Sun.COM hat_unload(kas.a_hat, cp->buf, cp->size, HAT_UNLOAD);
246510843SDave.Plauger@Sun.COM HRSTOP(ds->perpage, unmap);
246610843SDave.Plauger@Sun.COM
246710843SDave.Plauger@Sun.COM if (bitnum < dumpcfg.bitmapsize)
246810843SDave.Plauger@Sun.COM CQ_PUT(mainq, cp, CBUF_FREEMAP);
246910843SDave.Plauger@Sun.COM CQ_CLOSE(mainq);
247010843SDave.Plauger@Sun.COM
247110843SDave.Plauger@Sun.COM ASSERT(ds->npages <= dumphdr->dump_npages);
247210843SDave.Plauger@Sun.COM ds->percent = ds->npages * 100LL / dumphdr->dump_npages;
247310843SDave.Plauger@Sun.COM break;
247410843SDave.Plauger@Sun.COM
247510843SDave.Plauger@Sun.COM case CBUF_WRITE:
247610843SDave.Plauger@Sun.COM
247710843SDave.Plauger@Sun.COM CQ_PUT(writerq, cp, CBUF_WRITE);
247810843SDave.Plauger@Sun.COM break;
247910843SDave.Plauger@Sun.COM
248010843SDave.Plauger@Sun.COM case CBUF_ERRMSG:
248110843SDave.Plauger@Sun.COM
248210843SDave.Plauger@Sun.COM if (cp->used > 0) {
248310843SDave.Plauger@Sun.COM cp->buf[cp->size - 2] = '\n';
248410843SDave.Plauger@Sun.COM cp->buf[cp->size - 1] = '\0';
248510843SDave.Plauger@Sun.COM if (ds->neednl) {
248610843SDave.Plauger@Sun.COM uprintf("\n%s", cp->buf);
248710843SDave.Plauger@Sun.COM ds->neednl = 0;
248810843SDave.Plauger@Sun.COM } else {
248910843SDave.Plauger@Sun.COM uprintf("%s", cp->buf);
249010843SDave.Plauger@Sun.COM }
249111178SDave.Plauger@Sun.COM /* wait for console output */
249211178SDave.Plauger@Sun.COM drv_usecwait(200000);
249311178SDave.Plauger@Sun.COM dump_timeleft = dump_timeout;
249410843SDave.Plauger@Sun.COM }
249510843SDave.Plauger@Sun.COM CQ_PUT(freebufq, cp, CBUF_FREEBUF);
249610843SDave.Plauger@Sun.COM break;
249710843SDave.Plauger@Sun.COM
249810843SDave.Plauger@Sun.COM default:
249910843SDave.Plauger@Sun.COM uprintf("dump: unexpected buffer state %d, "
250010843SDave.Plauger@Sun.COM "buffer will be lost\n", cp->state);
250110843SDave.Plauger@Sun.COM break;
250210843SDave.Plauger@Sun.COM
250310843SDave.Plauger@Sun.COM } /* end switch */
250410843SDave.Plauger@Sun.COM
250510843SDave.Plauger@Sun.COM } /* end while(1) */
250610843SDave.Plauger@Sun.COM }
250710843SDave.Plauger@Sun.COM
250810843SDave.Plauger@Sun.COM #ifdef COLLECT_METRICS
250910843SDave.Plauger@Sun.COM size_t
dumpsys_metrics(dumpsync_t * ds,char * buf,size_t size)251010843SDave.Plauger@Sun.COM dumpsys_metrics(dumpsync_t *ds, char *buf, size_t size)
251110843SDave.Plauger@Sun.COM {
251210843SDave.Plauger@Sun.COM dumpcfg_t *cfg = &dumpcfg;
251310843SDave.Plauger@Sun.COM int myid = CPU->cpu_seqid;
251410843SDave.Plauger@Sun.COM int i, compress_ratio;
251510843SDave.Plauger@Sun.COM int sec, iorate;
251610843SDave.Plauger@Sun.COM helper_t *hp, *hpend = &cfg->helper[cfg->nhelper];
251710843SDave.Plauger@Sun.COM char *e = buf + size;
251810843SDave.Plauger@Sun.COM char *p = buf;
251910843SDave.Plauger@Sun.COM
252010843SDave.Plauger@Sun.COM sec = ds->elapsed / (1000 * 1000 * 1000ULL);
252110843SDave.Plauger@Sun.COM if (sec < 1)
252210843SDave.Plauger@Sun.COM sec = 1;
252310843SDave.Plauger@Sun.COM
252410843SDave.Plauger@Sun.COM if (ds->iotime < 1)
252510843SDave.Plauger@Sun.COM ds->iotime = 1;
252610843SDave.Plauger@Sun.COM iorate = (ds->nwrite * 100000ULL) / ds->iotime;
252710843SDave.Plauger@Sun.COM
252810843SDave.Plauger@Sun.COM compress_ratio = 100LL * ds->npages / btopr(ds->nwrite + 1);
252910843SDave.Plauger@Sun.COM
253010843SDave.Plauger@Sun.COM #define P(...) (p += p < e ? snprintf(p, e - p, __VA_ARGS__) : 0)
253110843SDave.Plauger@Sun.COM
253210843SDave.Plauger@Sun.COM P("Master cpu_seqid,%d\n", CPU->cpu_seqid);
253310843SDave.Plauger@Sun.COM P("Master cpu_id,%d\n", CPU->cpu_id);
253410843SDave.Plauger@Sun.COM P("dump_flags,0x%x\n", dumphdr->dump_flags);
253510843SDave.Plauger@Sun.COM P("dump_ioerr,%d\n", dump_ioerr);
253610843SDave.Plauger@Sun.COM
253710843SDave.Plauger@Sun.COM P("Helpers:\n");
253810843SDave.Plauger@Sun.COM for (i = 0; i < ncpus; i++) {
253910843SDave.Plauger@Sun.COM if ((i & 15) == 0)
254010843SDave.Plauger@Sun.COM P(",,%03d,", i);
254110843SDave.Plauger@Sun.COM if (i == myid)
254210843SDave.Plauger@Sun.COM P(" M");
254310843SDave.Plauger@Sun.COM else if (BT_TEST(cfg->helpermap, i))
254410843SDave.Plauger@Sun.COM P("%4d", cpu_seq[i]->cpu_id);
254510843SDave.Plauger@Sun.COM else
254610843SDave.Plauger@Sun.COM P(" *");
254710843SDave.Plauger@Sun.COM if ((i & 15) == 15)
254810843SDave.Plauger@Sun.COM P("\n");
254910843SDave.Plauger@Sun.COM }
255010843SDave.Plauger@Sun.COM
255110843SDave.Plauger@Sun.COM P("ncbuf_used,%d\n", cfg->ncbuf_used);
255210843SDave.Plauger@Sun.COM P("ncmap,%d\n", cfg->ncmap);
255310843SDave.Plauger@Sun.COM
255410843SDave.Plauger@Sun.COM P("Found %ldM ranges,%ld\n", (CBUF_MAPSIZE / DUMP_1MB), cfg->found4m);
255510843SDave.Plauger@Sun.COM P("Found small pages,%ld\n", cfg->foundsm);
255610843SDave.Plauger@Sun.COM
255710843SDave.Plauger@Sun.COM P("Compression level,%d\n", cfg->clevel);
255810843SDave.Plauger@Sun.COM P("Compression type,%s %s\n", cfg->clevel == 0 ? "serial" : "parallel",
255910843SDave.Plauger@Sun.COM cfg->clevel >= DUMP_CLEVEL_BZIP2 ? "bzip2" : "lzjb");
256010843SDave.Plauger@Sun.COM P("Compression ratio,%d.%02d\n", compress_ratio / 100, compress_ratio %
256110843SDave.Plauger@Sun.COM 100);
256210843SDave.Plauger@Sun.COM P("nhelper_used,%d\n", cfg->nhelper_used);
256310843SDave.Plauger@Sun.COM
256410843SDave.Plauger@Sun.COM P("Dump I/O rate MBS,%d.%02d\n", iorate / 100, iorate % 100);
256510843SDave.Plauger@Sun.COM P("..total bytes,%lld\n", (u_longlong_t)ds->nwrite);
256610843SDave.Plauger@Sun.COM P("..total nsec,%lld\n", (u_longlong_t)ds->iotime);
256710843SDave.Plauger@Sun.COM P("dumpbuf.iosize,%ld\n", dumpbuf.iosize);
256810843SDave.Plauger@Sun.COM P("dumpbuf.size,%ld\n", dumpbuf.size);
256910843SDave.Plauger@Sun.COM
257010843SDave.Plauger@Sun.COM P("Dump pages/sec,%llu\n", (u_longlong_t)ds->npages / sec);
257110843SDave.Plauger@Sun.COM P("Dump pages,%llu\n", (u_longlong_t)ds->npages);
257210843SDave.Plauger@Sun.COM P("Dump time,%d\n", sec);
257310843SDave.Plauger@Sun.COM
257410843SDave.Plauger@Sun.COM if (ds->pages_mapped > 0)
257510843SDave.Plauger@Sun.COM P("per-cent map utilization,%d\n", (int)((100 * ds->pages_used)
257610843SDave.Plauger@Sun.COM / ds->pages_mapped));
257710843SDave.Plauger@Sun.COM
257810843SDave.Plauger@Sun.COM P("\nPer-page metrics:\n");
257910843SDave.Plauger@Sun.COM if (ds->npages > 0) {
258010843SDave.Plauger@Sun.COM for (hp = cfg->helper; hp != hpend; hp++) {
258110843SDave.Plauger@Sun.COM #define PERPAGE(x) ds->perpage.x += hp->perpage.x;
258210843SDave.Plauger@Sun.COM PERPAGES;
258310843SDave.Plauger@Sun.COM #undef PERPAGE
258410843SDave.Plauger@Sun.COM }
258510843SDave.Plauger@Sun.COM #define PERPAGE(x) \
258610843SDave.Plauger@Sun.COM P("%s nsec/page,%d\n", #x, (int)(ds->perpage.x / ds->npages));
258710843SDave.Plauger@Sun.COM PERPAGES;
258810843SDave.Plauger@Sun.COM #undef PERPAGE
258910843SDave.Plauger@Sun.COM P("freebufq.empty,%d\n", (int)(ds->freebufq.empty /
259010843SDave.Plauger@Sun.COM ds->npages));
259110843SDave.Plauger@Sun.COM P("helperq.empty,%d\n", (int)(ds->helperq.empty /
259210843SDave.Plauger@Sun.COM ds->npages));
259310843SDave.Plauger@Sun.COM P("writerq.empty,%d\n", (int)(ds->writerq.empty /
259410843SDave.Plauger@Sun.COM ds->npages));
259510843SDave.Plauger@Sun.COM P("mainq.empty,%d\n", (int)(ds->mainq.empty / ds->npages));
259610843SDave.Plauger@Sun.COM
259710843SDave.Plauger@Sun.COM P("I/O wait nsec/page,%llu\n", (u_longlong_t)(ds->iowait /
259810843SDave.Plauger@Sun.COM ds->npages));
259910843SDave.Plauger@Sun.COM }
260010843SDave.Plauger@Sun.COM #undef P
260110843SDave.Plauger@Sun.COM if (p < e)
260210843SDave.Plauger@Sun.COM bzero(p, e - p);
260310843SDave.Plauger@Sun.COM return (p - buf);
260410843SDave.Plauger@Sun.COM }
260510843SDave.Plauger@Sun.COM #endif /* COLLECT_METRICS */
260610843SDave.Plauger@Sun.COM
26070Sstevel@tonic-gate /*
26080Sstevel@tonic-gate * Dump the system.
26090Sstevel@tonic-gate */
26100Sstevel@tonic-gate void
dumpsys(void)26110Sstevel@tonic-gate dumpsys(void)
26120Sstevel@tonic-gate {
261310843SDave.Plauger@Sun.COM dumpsync_t *ds = &dumpsync;
261410843SDave.Plauger@Sun.COM taskq_t *livetaskq = NULL;
26150Sstevel@tonic-gate pfn_t pfn;
26160Sstevel@tonic-gate pgcnt_t bitnum;
26170Sstevel@tonic-gate proc_t *p;
261810843SDave.Plauger@Sun.COM helper_t *hp, *hpend = &dumpcfg.helper[dumpcfg.nhelper];
261910843SDave.Plauger@Sun.COM cbuf_t *cp;
26200Sstevel@tonic-gate pid_t npids, pidx;
26210Sstevel@tonic-gate char *content;
262211178SDave.Plauger@Sun.COM char *buf;
262311178SDave.Plauger@Sun.COM size_t size;
262410843SDave.Plauger@Sun.COM int save_dump_clevel;
262510843SDave.Plauger@Sun.COM dumpmlw_t mlw;
262610843SDave.Plauger@Sun.COM dumpcsize_t datatag;
262710843SDave.Plauger@Sun.COM dumpdatahdr_t datahdr;
26280Sstevel@tonic-gate
26290Sstevel@tonic-gate if (dumpvp == NULL || dumphdr == NULL) {
26300Sstevel@tonic-gate uprintf("skipping system dump - no dump device configured\n");
263110843SDave.Plauger@Sun.COM if (panicstr) {
263210843SDave.Plauger@Sun.COM dumpcfg.helpers_wanted = 0;
263310843SDave.Plauger@Sun.COM dumpsys_spinunlock(&dumpcfg.helper_lock);
263410843SDave.Plauger@Sun.COM }
26350Sstevel@tonic-gate return;
26360Sstevel@tonic-gate }
263710843SDave.Plauger@Sun.COM dumpbuf.cur = dumpbuf.start;
263810843SDave.Plauger@Sun.COM
263910843SDave.Plauger@Sun.COM /* clear the sync variables */
264010843SDave.Plauger@Sun.COM ASSERT(dumpcfg.nhelper > 0);
264110843SDave.Plauger@Sun.COM bzero(ds, sizeof (*ds));
264210843SDave.Plauger@Sun.COM ds->dumpcpu = CPU->cpu_id;
26430Sstevel@tonic-gate
26440Sstevel@tonic-gate /*
26450Sstevel@tonic-gate * Calculate the starting block for dump. If we're dumping on a
26460Sstevel@tonic-gate * swap device, start 1/5 of the way in; otherwise, start at the
26470Sstevel@tonic-gate * beginning. And never use the first page -- it may be a disk label.
26480Sstevel@tonic-gate */
26490Sstevel@tonic-gate if (dumpvp->v_flag & VISSWAP)
26500Sstevel@tonic-gate dumphdr->dump_start = P2ROUNDUP(dumpvp_size / 5, DUMP_OFFSET);
26510Sstevel@tonic-gate else
26520Sstevel@tonic-gate dumphdr->dump_start = DUMP_OFFSET;
26530Sstevel@tonic-gate
265410843SDave.Plauger@Sun.COM dumphdr->dump_flags = DF_VALID | DF_COMPLETE | DF_LIVE | DF_COMPRESSED;
26550Sstevel@tonic-gate dumphdr->dump_crashtime = gethrestime_sec();
26560Sstevel@tonic-gate dumphdr->dump_npages = 0;
26570Sstevel@tonic-gate dumphdr->dump_nvtop = 0;
265810843SDave.Plauger@Sun.COM bzero(dumpcfg.bitmap, BT_SIZEOFMAP(dumpcfg.bitmapsize));
26590Sstevel@tonic-gate dump_timeleft = dump_timeout;
26600Sstevel@tonic-gate
26610Sstevel@tonic-gate if (panicstr) {
26620Sstevel@tonic-gate dumphdr->dump_flags &= ~DF_LIVE;
26635331Samw (void) VOP_DUMPCTL(dumpvp, DUMP_FREE, NULL, NULL);
26645331Samw (void) VOP_DUMPCTL(dumpvp, DUMP_ALLOC, NULL, NULL);
26650Sstevel@tonic-gate (void) vsnprintf(dumphdr->dump_panicstring, DUMP_PANICSIZE,
26660Sstevel@tonic-gate panicstr, panicargs);
266710843SDave.Plauger@Sun.COM
26680Sstevel@tonic-gate }
26690Sstevel@tonic-gate
26700Sstevel@tonic-gate if (dump_conflags & DUMP_ALL)
26710Sstevel@tonic-gate content = "all";
26720Sstevel@tonic-gate else if (dump_conflags & DUMP_CURPROC)
26730Sstevel@tonic-gate content = "kernel + curproc";
26740Sstevel@tonic-gate else
26750Sstevel@tonic-gate content = "kernel";
26760Sstevel@tonic-gate uprintf("dumping to %s, offset %lld, content: %s\n", dumppath,
26770Sstevel@tonic-gate dumphdr->dump_start, content);
26780Sstevel@tonic-gate
267910843SDave.Plauger@Sun.COM /* Make sure nodename is current */
268010843SDave.Plauger@Sun.COM bcopy(utsname.nodename, dumphdr->dump_utsname.nodename, SYS_NMLN);
268110843SDave.Plauger@Sun.COM
268210843SDave.Plauger@Sun.COM /*
268310843SDave.Plauger@Sun.COM * If this is a live dump, try to open a VCHR vnode for better
268410843SDave.Plauger@Sun.COM * performance. We must take care to flush the buffer cache
268510843SDave.Plauger@Sun.COM * first.
268610843SDave.Plauger@Sun.COM */
268710843SDave.Plauger@Sun.COM if (!panicstr) {
268810843SDave.Plauger@Sun.COM vnode_t *cdev_vp, *cmn_cdev_vp;
268910843SDave.Plauger@Sun.COM
269010843SDave.Plauger@Sun.COM ASSERT(dumpbuf.cdev_vp == NULL);
269110843SDave.Plauger@Sun.COM cdev_vp = makespecvp(VTOS(dumpvp)->s_dev, VCHR);
269210843SDave.Plauger@Sun.COM if (cdev_vp != NULL) {
269310843SDave.Plauger@Sun.COM cmn_cdev_vp = common_specvp(cdev_vp);
269410843SDave.Plauger@Sun.COM if (VOP_OPEN(&cmn_cdev_vp, FREAD | FWRITE, kcred, NULL)
269510843SDave.Plauger@Sun.COM == 0) {
269610843SDave.Plauger@Sun.COM if (vn_has_cached_data(dumpvp))
269710843SDave.Plauger@Sun.COM (void) pvn_vplist_dirty(dumpvp, 0, NULL,
269810843SDave.Plauger@Sun.COM B_INVAL | B_TRUNC, kcred);
269910843SDave.Plauger@Sun.COM dumpbuf.cdev_vp = cmn_cdev_vp;
270010843SDave.Plauger@Sun.COM } else {
270110843SDave.Plauger@Sun.COM VN_RELE(cdev_vp);
270210843SDave.Plauger@Sun.COM }
270310843SDave.Plauger@Sun.COM }
270410843SDave.Plauger@Sun.COM }
270510843SDave.Plauger@Sun.COM
27060Sstevel@tonic-gate /*
270711066Srafael.vanoni@sun.com * Store a hires timestamp so we can look it up during debugging.
270811066Srafael.vanoni@sun.com */
270911066Srafael.vanoni@sun.com lbolt_debug_entry();
271011066Srafael.vanoni@sun.com
271111066Srafael.vanoni@sun.com /*
27120Sstevel@tonic-gate * Leave room for the message and ereport save areas and terminal dump
27130Sstevel@tonic-gate * header.
27140Sstevel@tonic-gate */
271510843SDave.Plauger@Sun.COM dumpbuf.vp_limit = dumpvp_size - DUMP_LOGSIZE - DUMP_OFFSET -
271610843SDave.Plauger@Sun.COM DUMP_ERPTSIZE;
27170Sstevel@tonic-gate
27180Sstevel@tonic-gate /*
27190Sstevel@tonic-gate * Write out the symbol table. It's no longer compressed,
27200Sstevel@tonic-gate * so its 'size' and 'csize' are equal.
27210Sstevel@tonic-gate */
272210843SDave.Plauger@Sun.COM dumpbuf.vp_off = dumphdr->dump_ksyms = dumphdr->dump_start + PAGESIZE;
27230Sstevel@tonic-gate dumphdr->dump_ksyms_size = dumphdr->dump_ksyms_csize =
27240Sstevel@tonic-gate ksyms_snapshot(dumpvp_ksyms_write, NULL, LONG_MAX);
27250Sstevel@tonic-gate
27260Sstevel@tonic-gate /*
27270Sstevel@tonic-gate * Write out the translation map.
27280Sstevel@tonic-gate */
27290Sstevel@tonic-gate dumphdr->dump_map = dumpvp_flush();
27300Sstevel@tonic-gate dump_as(&kas);
27313446Smrj dumphdr->dump_nvtop += dump_plat_addr();
27320Sstevel@tonic-gate
27330Sstevel@tonic-gate /*
27340Sstevel@tonic-gate * call into hat, which may have unmapped pages that also need to
27350Sstevel@tonic-gate * be in the dump
27360Sstevel@tonic-gate */
27370Sstevel@tonic-gate hat_dump();
27380Sstevel@tonic-gate
27390Sstevel@tonic-gate if (dump_conflags & DUMP_ALL) {
27400Sstevel@tonic-gate mutex_enter(&pidlock);
27410Sstevel@tonic-gate
27420Sstevel@tonic-gate for (npids = 0, p = practive; p != NULL; p = p->p_next)
274310843SDave.Plauger@Sun.COM dumpcfg.pids[npids++] = p->p_pid;
27440Sstevel@tonic-gate
27450Sstevel@tonic-gate mutex_exit(&pidlock);
27460Sstevel@tonic-gate
27470Sstevel@tonic-gate for (pidx = 0; pidx < npids; pidx++)
274810843SDave.Plauger@Sun.COM (void) dump_process(dumpcfg.pids[pidx]);
274910843SDave.Plauger@Sun.COM
275012042SDave.Plauger@Sun.COM dump_init_memlist_walker(&mlw);
275110843SDave.Plauger@Sun.COM for (bitnum = 0; bitnum < dumpcfg.bitmapsize; bitnum++) {
27520Sstevel@tonic-gate dump_timeleft = dump_timeout;
275311480SStuart.Maybee@Sun.COM pfn = dump_bitnum_to_pfn(bitnum, &mlw);
275411480SStuart.Maybee@Sun.COM /*
275511480SStuart.Maybee@Sun.COM * Some hypervisors do not have all pages available to
275611480SStuart.Maybee@Sun.COM * be accessed by the guest OS. Check for page
275711480SStuart.Maybee@Sun.COM * accessibility.
275811480SStuart.Maybee@Sun.COM */
275911480SStuart.Maybee@Sun.COM if (plat_hold_page(pfn, PLAT_HOLD_NO_LOCK, NULL) !=
276011480SStuart.Maybee@Sun.COM PLAT_HOLD_OK)
276111480SStuart.Maybee@Sun.COM continue;
276210843SDave.Plauger@Sun.COM BT_SET(dumpcfg.bitmap, bitnum);
27630Sstevel@tonic-gate }
276410843SDave.Plauger@Sun.COM dumphdr->dump_npages = dumpcfg.bitmapsize;
27650Sstevel@tonic-gate dumphdr->dump_flags |= DF_ALL;
27660Sstevel@tonic-gate
27670Sstevel@tonic-gate } else if (dump_conflags & DUMP_CURPROC) {
27680Sstevel@tonic-gate /*
27690Sstevel@tonic-gate * Determine which pid is to be dumped. If we're panicking, we
27700Sstevel@tonic-gate * dump the process associated with panic_thread (if any). If
27710Sstevel@tonic-gate * this is a live dump, we dump the process associated with
27720Sstevel@tonic-gate * curthread.
27730Sstevel@tonic-gate */
27740Sstevel@tonic-gate npids = 0;
27750Sstevel@tonic-gate if (panicstr) {
27760Sstevel@tonic-gate if (panic_thread != NULL &&
27770Sstevel@tonic-gate panic_thread->t_procp != NULL &&
27780Sstevel@tonic-gate panic_thread->t_procp != &p0) {
277910843SDave.Plauger@Sun.COM dumpcfg.pids[npids++] =
27800Sstevel@tonic-gate panic_thread->t_procp->p_pid;
27810Sstevel@tonic-gate }
27820Sstevel@tonic-gate } else {
278310843SDave.Plauger@Sun.COM dumpcfg.pids[npids++] = curthread->t_procp->p_pid;
27840Sstevel@tonic-gate }
27850Sstevel@tonic-gate
278610843SDave.Plauger@Sun.COM if (npids && dump_process(dumpcfg.pids[0]) == 0)
27870Sstevel@tonic-gate dumphdr->dump_flags |= DF_CURPROC;
27880Sstevel@tonic-gate else
27890Sstevel@tonic-gate dumphdr->dump_flags |= DF_KERNEL;
27900Sstevel@tonic-gate
27910Sstevel@tonic-gate } else {
27920Sstevel@tonic-gate dumphdr->dump_flags |= DF_KERNEL;
27930Sstevel@tonic-gate }
27940Sstevel@tonic-gate
27950Sstevel@tonic-gate dumphdr->dump_hashmask = (1 << highbit(dumphdr->dump_nvtop - 1)) - 1;
27960Sstevel@tonic-gate
27970Sstevel@tonic-gate /*
27980Sstevel@tonic-gate * Write out the pfn table.
27990Sstevel@tonic-gate */
28000Sstevel@tonic-gate dumphdr->dump_pfn = dumpvp_flush();
280110843SDave.Plauger@Sun.COM dump_init_memlist_walker(&mlw);
280210843SDave.Plauger@Sun.COM for (bitnum = 0; bitnum < dumpcfg.bitmapsize; bitnum++) {
28030Sstevel@tonic-gate dump_timeleft = dump_timeout;
280410843SDave.Plauger@Sun.COM if (!BT_TEST(dumpcfg.bitmap, bitnum))
28050Sstevel@tonic-gate continue;
280610843SDave.Plauger@Sun.COM pfn = dump_bitnum_to_pfn(bitnum, &mlw);
28070Sstevel@tonic-gate ASSERT(pfn != PFN_INVALID);
28080Sstevel@tonic-gate dumpvp_write(&pfn, sizeof (pfn_t));
28090Sstevel@tonic-gate }
28103446Smrj dump_plat_pfn();
28110Sstevel@tonic-gate
28120Sstevel@tonic-gate /*
28130Sstevel@tonic-gate * Write out all the pages.
281410843SDave.Plauger@Sun.COM * Map pages, copy them handling UEs, compress, and write them out.
281510843SDave.Plauger@Sun.COM * Cooperate with any helpers running on CPUs in panic_idle().
28160Sstevel@tonic-gate */
28170Sstevel@tonic-gate dumphdr->dump_data = dumpvp_flush();
281810843SDave.Plauger@Sun.COM
281910843SDave.Plauger@Sun.COM bzero(dumpcfg.helpermap, BT_SIZEOFMAP(NCPU));
282010843SDave.Plauger@Sun.COM ds->live = dumpcfg.clevel > 0 &&
282110843SDave.Plauger@Sun.COM (dumphdr->dump_flags & DF_LIVE) != 0;
282210843SDave.Plauger@Sun.COM
282310843SDave.Plauger@Sun.COM save_dump_clevel = dumpcfg.clevel;
282410843SDave.Plauger@Sun.COM if (panicstr)
282510843SDave.Plauger@Sun.COM dumpsys_get_maxmem();
282610843SDave.Plauger@Sun.COM else if (dumpcfg.clevel >= DUMP_CLEVEL_BZIP2)
282710843SDave.Plauger@Sun.COM dumpcfg.clevel = DUMP_CLEVEL_LZJB;
282810843SDave.Plauger@Sun.COM
282910843SDave.Plauger@Sun.COM dumpcfg.nhelper_used = 0;
283010843SDave.Plauger@Sun.COM for (hp = dumpcfg.helper; hp != hpend; hp++) {
283110843SDave.Plauger@Sun.COM if (hp->page == NULL) {
283210843SDave.Plauger@Sun.COM hp->helper = DONEHELPER;
28330Sstevel@tonic-gate continue;
28340Sstevel@tonic-gate }
283510843SDave.Plauger@Sun.COM ++dumpcfg.nhelper_used;
283610843SDave.Plauger@Sun.COM hp->helper = FREEHELPER;
283710843SDave.Plauger@Sun.COM hp->taskqid = NULL;
283810843SDave.Plauger@Sun.COM hp->ds = ds;
283910843SDave.Plauger@Sun.COM bzero(&hp->perpage, sizeof (hp->perpage));
284010843SDave.Plauger@Sun.COM if (dumpcfg.clevel >= DUMP_CLEVEL_BZIP2)
284110843SDave.Plauger@Sun.COM (void) BZ2_bzCompressReset(&hp->bzstream);
284210843SDave.Plauger@Sun.COM }
284310843SDave.Plauger@Sun.COM
284410843SDave.Plauger@Sun.COM CQ_OPEN(freebufq);
284510843SDave.Plauger@Sun.COM CQ_OPEN(helperq);
284610843SDave.Plauger@Sun.COM
284710843SDave.Plauger@Sun.COM dumpcfg.ncbuf_used = 0;
284810843SDave.Plauger@Sun.COM for (cp = dumpcfg.cbuf; cp != &dumpcfg.cbuf[dumpcfg.ncbuf]; cp++) {
284910843SDave.Plauger@Sun.COM if (cp->buf != NULL) {
285010843SDave.Plauger@Sun.COM CQ_PUT(freebufq, cp, CBUF_FREEBUF);
285110843SDave.Plauger@Sun.COM ++dumpcfg.ncbuf_used;
28520Sstevel@tonic-gate }
28530Sstevel@tonic-gate }
285410843SDave.Plauger@Sun.COM
285510843SDave.Plauger@Sun.COM for (cp = dumpcfg.cmap; cp != &dumpcfg.cmap[dumpcfg.ncmap]; cp++)
285610843SDave.Plauger@Sun.COM CQ_PUT(mainq, cp, CBUF_FREEMAP);
285710843SDave.Plauger@Sun.COM
285810843SDave.Plauger@Sun.COM ds->start = gethrtime();
285910843SDave.Plauger@Sun.COM ds->iowaitts = ds->start;
286010843SDave.Plauger@Sun.COM
286110843SDave.Plauger@Sun.COM /* start helpers */
286210843SDave.Plauger@Sun.COM if (ds->live) {
286310843SDave.Plauger@Sun.COM int n = dumpcfg.nhelper_used;
286410843SDave.Plauger@Sun.COM int pri = MINCLSYSPRI - 25;
286510843SDave.Plauger@Sun.COM
286610843SDave.Plauger@Sun.COM livetaskq = taskq_create("LiveDump", n, pri, n, n,
286710843SDave.Plauger@Sun.COM TASKQ_PREPOPULATE);
286810843SDave.Plauger@Sun.COM for (hp = dumpcfg.helper; hp != hpend; hp++) {
286910843SDave.Plauger@Sun.COM if (hp->page == NULL)
287010843SDave.Plauger@Sun.COM continue;
287110843SDave.Plauger@Sun.COM hp->helper = hp - dumpcfg.helper;
287210843SDave.Plauger@Sun.COM hp->taskqid = taskq_dispatch(livetaskq,
287310843SDave.Plauger@Sun.COM dumpsys_live_helper, (void *)hp, TQ_NOSLEEP);
287410843SDave.Plauger@Sun.COM }
287510843SDave.Plauger@Sun.COM
287610843SDave.Plauger@Sun.COM } else {
287711178SDave.Plauger@Sun.COM if (panicstr)
287811178SDave.Plauger@Sun.COM kmem_dump_begin();
287910843SDave.Plauger@Sun.COM dumpcfg.helpers_wanted = dumpcfg.clevel > 0;
288010843SDave.Plauger@Sun.COM dumpsys_spinunlock(&dumpcfg.helper_lock);
288110843SDave.Plauger@Sun.COM }
288210843SDave.Plauger@Sun.COM
288310843SDave.Plauger@Sun.COM /* run main task */
288410843SDave.Plauger@Sun.COM dumpsys_main_task(ds);
288510843SDave.Plauger@Sun.COM
288610843SDave.Plauger@Sun.COM ds->elapsed = gethrtime() - ds->start;
288710843SDave.Plauger@Sun.COM if (ds->elapsed < 1)
288810843SDave.Plauger@Sun.COM ds->elapsed = 1;
288910843SDave.Plauger@Sun.COM
289010843SDave.Plauger@Sun.COM if (livetaskq != NULL)
289110843SDave.Plauger@Sun.COM taskq_destroy(livetaskq);
289210843SDave.Plauger@Sun.COM
289310843SDave.Plauger@Sun.COM if (ds->neednl) {
289410843SDave.Plauger@Sun.COM uprintf("\n");
289510843SDave.Plauger@Sun.COM ds->neednl = 0;
289610843SDave.Plauger@Sun.COM }
289710843SDave.Plauger@Sun.COM
289810843SDave.Plauger@Sun.COM /* record actual pages dumped */
289910843SDave.Plauger@Sun.COM dumphdr->dump_npages = ds->npages;
290010843SDave.Plauger@Sun.COM
290110843SDave.Plauger@Sun.COM /* platform-specific data */
290210843SDave.Plauger@Sun.COM dumphdr->dump_npages += dump_plat_data(dumpcfg.cbuf[0].buf);
290310843SDave.Plauger@Sun.COM
290410843SDave.Plauger@Sun.COM /* note any errors by clearing DF_COMPLETE */
290510843SDave.Plauger@Sun.COM if (dump_ioerr || ds->npages < dumphdr->dump_npages)
290610843SDave.Plauger@Sun.COM dumphdr->dump_flags &= ~DF_COMPLETE;
290710843SDave.Plauger@Sun.COM
290810843SDave.Plauger@Sun.COM /* end of stream blocks */
290910843SDave.Plauger@Sun.COM datatag = 0;
291010843SDave.Plauger@Sun.COM dumpvp_write(&datatag, sizeof (datatag));
291110843SDave.Plauger@Sun.COM
291211178SDave.Plauger@Sun.COM bzero(&datahdr, sizeof (datahdr));
291311178SDave.Plauger@Sun.COM
291411178SDave.Plauger@Sun.COM /* buffer for metrics */
291511178SDave.Plauger@Sun.COM buf = dumpcfg.cbuf[0].buf;
291611178SDave.Plauger@Sun.COM size = MIN(dumpcfg.cbuf[0].size, DUMP_OFFSET - sizeof (dumphdr_t) -
291711178SDave.Plauger@Sun.COM sizeof (dumpdatahdr_t));
291811178SDave.Plauger@Sun.COM
291911178SDave.Plauger@Sun.COM /* finish the kmem intercepts, collect kmem verbose info */
292011178SDave.Plauger@Sun.COM if (panicstr) {
292111178SDave.Plauger@Sun.COM datahdr.dump_metrics = kmem_dump_finish(buf, size);
292211178SDave.Plauger@Sun.COM buf += datahdr.dump_metrics;
292311178SDave.Plauger@Sun.COM size -= datahdr.dump_metrics;
292411178SDave.Plauger@Sun.COM }
292511178SDave.Plauger@Sun.COM
292612967Sgavin.maltby@oracle.com /* record in the header whether this is a fault-management panic */
292712967Sgavin.maltby@oracle.com if (panicstr)
292812967Sgavin.maltby@oracle.com dumphdr->dump_fm_panic = is_fm_panic();
292912967Sgavin.maltby@oracle.com
293010843SDave.Plauger@Sun.COM /* compression info in data header */
293110843SDave.Plauger@Sun.COM datahdr.dump_datahdr_magic = DUMP_DATAHDR_MAGIC;
293210843SDave.Plauger@Sun.COM datahdr.dump_datahdr_version = DUMP_DATAHDR_VERSION;
293310843SDave.Plauger@Sun.COM datahdr.dump_maxcsize = CBUF_SIZE;
293410843SDave.Plauger@Sun.COM datahdr.dump_maxrange = CBUF_MAPSIZE / PAGESIZE;
293510843SDave.Plauger@Sun.COM datahdr.dump_nstreams = dumpcfg.nhelper_used;
293610843SDave.Plauger@Sun.COM datahdr.dump_clevel = dumpcfg.clevel;
293710843SDave.Plauger@Sun.COM #ifdef COLLECT_METRICS
293810843SDave.Plauger@Sun.COM if (dump_metrics_on)
293911178SDave.Plauger@Sun.COM datahdr.dump_metrics += dumpsys_metrics(ds, buf, size);
294010843SDave.Plauger@Sun.COM #endif
294110843SDave.Plauger@Sun.COM datahdr.dump_data_csize = dumpvp_flush() - dumphdr->dump_data;
29420Sstevel@tonic-gate
29430Sstevel@tonic-gate /*
29440Sstevel@tonic-gate * Write out the initial and terminal dump headers.
29450Sstevel@tonic-gate */
294610843SDave.Plauger@Sun.COM dumpbuf.vp_off = dumphdr->dump_start;
29470Sstevel@tonic-gate dumpvp_write(dumphdr, sizeof (dumphdr_t));
29480Sstevel@tonic-gate (void) dumpvp_flush();
29490Sstevel@tonic-gate
295010843SDave.Plauger@Sun.COM dumpbuf.vp_limit = dumpvp_size;
295110843SDave.Plauger@Sun.COM dumpbuf.vp_off = dumpbuf.vp_limit - DUMP_OFFSET;
29520Sstevel@tonic-gate dumpvp_write(dumphdr, sizeof (dumphdr_t));
295310843SDave.Plauger@Sun.COM dumpvp_write(&datahdr, sizeof (dumpdatahdr_t));
295410843SDave.Plauger@Sun.COM dumpvp_write(dumpcfg.cbuf[0].buf, datahdr.dump_metrics);
295510843SDave.Plauger@Sun.COM
29560Sstevel@tonic-gate (void) dumpvp_flush();
29570Sstevel@tonic-gate
295810843SDave.Plauger@Sun.COM uprintf("\r%3d%% done: %llu pages dumped, ",
295910843SDave.Plauger@Sun.COM ds->percent_done, (u_longlong_t)ds->npages);
29600Sstevel@tonic-gate
29610Sstevel@tonic-gate if (dump_ioerr == 0) {
29620Sstevel@tonic-gate uprintf("dump succeeded\n");
29630Sstevel@tonic-gate } else {
29640Sstevel@tonic-gate uprintf("dump failed: error %d\n", dump_ioerr);
296510843SDave.Plauger@Sun.COM #ifdef DEBUG
296610843SDave.Plauger@Sun.COM if (panicstr)
29670Sstevel@tonic-gate debug_enter("dump failed");
296810843SDave.Plauger@Sun.COM #endif
29690Sstevel@tonic-gate }
29700Sstevel@tonic-gate
29710Sstevel@tonic-gate /*
29720Sstevel@tonic-gate * Write out all undelivered messages. This has to be the *last*
29730Sstevel@tonic-gate * thing we do because the dump process itself emits messages.
29740Sstevel@tonic-gate */
29750Sstevel@tonic-gate if (panicstr) {
297612967Sgavin.maltby@oracle.com dump_summary();
29770Sstevel@tonic-gate dump_ereports();
29780Sstevel@tonic-gate dump_messages();
29790Sstevel@tonic-gate }
29800Sstevel@tonic-gate
29810Sstevel@tonic-gate delay(2 * hz); /* let people see the 'done' message */
29820Sstevel@tonic-gate dump_timeleft = 0;
29830Sstevel@tonic-gate dump_ioerr = 0;
298410843SDave.Plauger@Sun.COM
298510843SDave.Plauger@Sun.COM /* restore settings after live dump completes */
298610843SDave.Plauger@Sun.COM if (!panicstr) {
298710843SDave.Plauger@Sun.COM dumpcfg.clevel = save_dump_clevel;
298810843SDave.Plauger@Sun.COM
298910843SDave.Plauger@Sun.COM /* release any VCHR open of the dump device */
299010843SDave.Plauger@Sun.COM if (dumpbuf.cdev_vp != NULL) {
299110843SDave.Plauger@Sun.COM (void) VOP_CLOSE(dumpbuf.cdev_vp, FREAD | FWRITE, 1, 0,
299210843SDave.Plauger@Sun.COM kcred, NULL);
299310843SDave.Plauger@Sun.COM VN_RELE(dumpbuf.cdev_vp);
299410843SDave.Plauger@Sun.COM dumpbuf.cdev_vp = NULL;
299510843SDave.Plauger@Sun.COM }
299610843SDave.Plauger@Sun.COM }
29970Sstevel@tonic-gate }
29980Sstevel@tonic-gate
29990Sstevel@tonic-gate /*
30000Sstevel@tonic-gate * This function is called whenever the memory size, as represented
30010Sstevel@tonic-gate * by the phys_install list, changes.
30020Sstevel@tonic-gate */
30030Sstevel@tonic-gate void
dump_resize()30040Sstevel@tonic-gate dump_resize()
30050Sstevel@tonic-gate {
30060Sstevel@tonic-gate mutex_enter(&dump_lock);
30070Sstevel@tonic-gate dumphdr_init();
30080Sstevel@tonic-gate dumpbuf_resize();
300910843SDave.Plauger@Sun.COM dump_update_clevel();
30100Sstevel@tonic-gate mutex_exit(&dump_lock);
30110Sstevel@tonic-gate }
30126423Sgw25295
30136423Sgw25295 /*
30146423Sgw25295 * This function allows for dynamic resizing of a dump area. It assumes that
30156423Sgw25295 * the underlying device has update its appropriate size(9P).
30166423Sgw25295 */
30176423Sgw25295 int
dumpvp_resize()30186423Sgw25295 dumpvp_resize()
30196423Sgw25295 {
30206423Sgw25295 int error;
30216423Sgw25295 vattr_t vattr;
30226423Sgw25295
30236423Sgw25295 mutex_enter(&dump_lock);
30246423Sgw25295 vattr.va_mask = AT_SIZE;
30256423Sgw25295 if ((error = VOP_GETATTR(dumpvp, &vattr, 0, kcred, NULL)) != 0) {
30266423Sgw25295 mutex_exit(&dump_lock);
30276423Sgw25295 return (error);
30286423Sgw25295 }
30296423Sgw25295
30306423Sgw25295 if (error == 0 && vattr.va_size < 2 * DUMP_LOGSIZE + DUMP_ERPTSIZE) {
30316423Sgw25295 mutex_exit(&dump_lock);
30326423Sgw25295 return (ENOSPC);
30336423Sgw25295 }
30346423Sgw25295
30356423Sgw25295 dumpvp_size = vattr.va_size & -DUMP_OFFSET;
30366423Sgw25295 mutex_exit(&dump_lock);
30376423Sgw25295 return (0);
30386423Sgw25295 }
303912967Sgavin.maltby@oracle.com
304012967Sgavin.maltby@oracle.com int
dump_set_uuid(const char * uuidstr)304112967Sgavin.maltby@oracle.com dump_set_uuid(const char *uuidstr)
304212967Sgavin.maltby@oracle.com {
304312967Sgavin.maltby@oracle.com const char *ptr;
304412967Sgavin.maltby@oracle.com int i;
304512967Sgavin.maltby@oracle.com
304612967Sgavin.maltby@oracle.com if (uuidstr == NULL || strnlen(uuidstr, 36 + 1) != 36)
304712967Sgavin.maltby@oracle.com return (EINVAL);
304812967Sgavin.maltby@oracle.com
304912967Sgavin.maltby@oracle.com /* uuid_parse is not common code so check manually */
305012967Sgavin.maltby@oracle.com for (i = 0, ptr = uuidstr; i < 36; i++, ptr++) {
305112967Sgavin.maltby@oracle.com switch (i) {
305212967Sgavin.maltby@oracle.com case 8:
305312967Sgavin.maltby@oracle.com case 13:
305412967Sgavin.maltby@oracle.com case 18:
305512967Sgavin.maltby@oracle.com case 23:
305612967Sgavin.maltby@oracle.com if (*ptr != '-')
305712967Sgavin.maltby@oracle.com return (EINVAL);
305812967Sgavin.maltby@oracle.com break;
305912967Sgavin.maltby@oracle.com
306012967Sgavin.maltby@oracle.com default:
306112967Sgavin.maltby@oracle.com if (!isxdigit(*ptr))
306212967Sgavin.maltby@oracle.com return (EINVAL);
306312967Sgavin.maltby@oracle.com break;
306412967Sgavin.maltby@oracle.com }
306512967Sgavin.maltby@oracle.com }
306612967Sgavin.maltby@oracle.com
306712967Sgavin.maltby@oracle.com if (dump_osimage_uuid[0] != '\0')
306812967Sgavin.maltby@oracle.com return (EALREADY);
306912967Sgavin.maltby@oracle.com
307012967Sgavin.maltby@oracle.com (void) strncpy(dump_osimage_uuid, uuidstr, 36 + 1);
307112967Sgavin.maltby@oracle.com
307212967Sgavin.maltby@oracle.com cmn_err(CE_CONT, "?This Solaris instance has UUID %s",
307312967Sgavin.maltby@oracle.com dump_osimage_uuid);
307412967Sgavin.maltby@oracle.com
307512967Sgavin.maltby@oracle.com return (0);
307612967Sgavin.maltby@oracle.com }
307712967Sgavin.maltby@oracle.com
307812967Sgavin.maltby@oracle.com const char *
dump_get_uuid(void)307912967Sgavin.maltby@oracle.com dump_get_uuid(void)
308012967Sgavin.maltby@oracle.com {
308112967Sgavin.maltby@oracle.com return (dump_osimage_uuid[0] != '\0' ? dump_osimage_uuid : "");
308212967Sgavin.maltby@oracle.com }
3083