Print this page
[mq]: core-v2
@@ -19,10 +19,11 @@
* CDDL HEADER END
*/
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, Josef 'Jeff' Sipek <jeffpc@31bits.net>. All rights reserved.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
@@ -69,34 +70,11 @@
#include <vm/seg.h>
#include <vm/seg_kmem.h>
#include <sys/clock_impl.h>
#include <sys/hold_page.h>
-#include <bzip2/bzlib.h>
-
/*
- * Crash dump time is dominated by disk write time. To reduce this,
- * the stronger compression method bzip2 is applied to reduce the dump
- * size and hence reduce I/O time. However, bzip2 is much more
- * computationally expensive than the existing lzjb algorithm, so to
- * avoid increasing compression time, CPUs that are otherwise idle
- * during panic are employed to parallelize the compression task.
- * Many helper CPUs are needed to prevent bzip2 from being a
- * bottleneck, and on systems with too few CPUs, the lzjb algorithm is
- * parallelized instead. Lastly, I/O and compression are performed by
- * different CPUs, and are hence overlapped in time, unlike the older
- * serial code.
- *
- * Another important consideration is the speed of the dump
- * device. Faster disks need less CPUs in order to benefit from
- * parallel lzjb versus parallel bzip2. Therefore, the CPU count
- * threshold for switching from parallel lzjb to paralled bzip2 is
- * elevated for faster disks. The dump device speed is adduced from
- * the setting for dumpbuf.iosize, see dump_update_clevel.
- */
-
-/*
* exported vars
*/
kmutex_t dump_lock; /* lock for dump configuration */
dumphdr_t *dumphdr; /* dump header */
int dump_conflags = DUMP_KERNEL; /* dump configuration flags */
@@ -104,69 +82,25 @@
u_offset_t dumpvp_size; /* size of dump device, in bytes */
char *dumppath; /* pathname of dump device */
int dump_timeout = 120; /* timeout for dumping pages */
int dump_timeleft; /* portion of dump_timeout remaining */
int dump_ioerr; /* dump i/o error */
-int dump_check_used; /* enable check for used pages */
char *dump_stack_scratch; /* scratch area for saving stack summary */
/*
- * Tunables for dump compression and parallelism. These can be set via
- * /etc/system.
+ * Tunables for dump. These can be set via /etc/system.
*
- * dump_ncpu_low number of helpers for parallel lzjb
- * This is also the minimum configuration.
- *
- * dump_bzip2_level bzip2 compression level: 1-9
- * Higher numbers give greater compression, but take more memory
- * and time. Memory used per helper is ~(dump_bzip2_level * 1MB).
- *
- * dump_plat_mincpu the cross-over limit for using bzip2 (per platform):
- * if dump_plat_mincpu == 0, then always do single threaded dump
- * if ncpu >= dump_plat_mincpu then try to use bzip2
- *
* dump_metrics_on if set, metrics are collected in the kernel, passed
* to savecore via the dump file, and recorded by savecore in
* METRICS.txt.
*/
-uint_t dump_ncpu_low = 4; /* minimum config for parallel lzjb */
-uint_t dump_bzip2_level = 1; /* bzip2 level (1-9) */
-/* Use dump_plat_mincpu_default unless this variable is set by /etc/system */
-#define MINCPU_NOT_SET ((uint_t)-1)
-uint_t dump_plat_mincpu = MINCPU_NOT_SET;
-
/* tunables for pre-reserved heap */
uint_t dump_kmem_permap = 1024;
uint_t dump_kmem_pages = 8;
-/* Define multiple buffers per helper to avoid stalling */
-#define NCBUF_PER_HELPER 2
-#define NCMAP_PER_HELPER 4
-
-/* minimum number of helpers configured */
-#define MINHELPERS (dump_ncpu_low)
-#define MINCBUFS (MINHELPERS * NCBUF_PER_HELPER)
-
/*
- * Define constant parameters.
- *
- * CBUF_SIZE size of an output buffer
- *
- * CBUF_MAPSIZE size of virtual range for mapping pages
- *
- * CBUF_MAPNP size of virtual range in pages
- *
- */
-#define DUMP_1KB ((size_t)1 << 10)
-#define DUMP_1MB ((size_t)1 << 20)
-#define CBUF_SIZE ((size_t)1 << 17)
-#define CBUF_MAPSHIFT (22)
-#define CBUF_MAPSIZE ((size_t)1 << CBUF_MAPSHIFT)
-#define CBUF_MAPNP ((size_t)1 << (CBUF_MAPSHIFT - PAGESHIFT))
-
-/*
* Compression metrics are accumulated nano-second subtotals. The
* results are normalized by the number of pages dumped. A report is
* generated when dumpsys() completes and is saved in the dump image
* after the trailing dump header.
*
@@ -210,210 +144,50 @@
#define HRBEGIN(v, m, s)
#define HREND(v, m)
#define HRNORM(v, m, n)
#endif /* COLLECT_METRICS */
-/*
- * Buffers for copying and compressing memory pages.
- *
- * cbuf_t buffer controllers: used for both input and output.
- *
- * The buffer state indicates how it is being used:
- *
- * CBUF_FREEMAP: CBUF_MAPSIZE virtual address range is available for
- * mapping input pages.
- *
- * CBUF_INREADY: input pages are mapped and ready for compression by a
- * helper.
- *
- * CBUF_USEDMAP: mapping has been consumed by a helper. Needs unmap.
- *
- * CBUF_FREEBUF: CBUF_SIZE output buffer, which is available.
- *
- * CBUF_WRITE: CBUF_SIZE block of compressed pages from a helper,
- * ready to write out.
- *
- * CBUF_ERRMSG: CBUF_SIZE block of error messages from a helper
- * (reports UE errors.)
- */
-
-typedef enum cbufstate {
- CBUF_FREEMAP,
- CBUF_INREADY,
- CBUF_USEDMAP,
- CBUF_FREEBUF,
- CBUF_WRITE,
- CBUF_ERRMSG
-} cbufstate_t;
-
-typedef struct cbuf cbuf_t;
-
-struct cbuf {
- cbuf_t *next; /* next in list */
- cbufstate_t state; /* processing state */
- size_t used; /* amount used */
- size_t size; /* mem size */
- char *buf; /* kmem or vmem */
- pgcnt_t pagenum; /* index to pfn map */
- pgcnt_t bitnum; /* first set bitnum */
- pfn_t pfn; /* first pfn in mapped range */
- int off; /* byte offset to first pfn */
-};
-
static char dump_osimage_uuid[36 + 1];
#define isdigit(ch) ((ch) >= '0' && (ch) <= '9')
#define isxdigit(ch) (isdigit(ch) || ((ch) >= 'a' && (ch) <= 'f') || \
((ch) >= 'A' && (ch) <= 'F'))
/*
- * cqueue_t queues: a uni-directional channel for communication
- * from the master to helper tasks or vice-versa using put and
- * get primitives. Both mappings and data buffers are passed via
- * queues. Producers close a queue when done. The number of
- * active producers is reference counted so the consumer can
- * detect end of data. Concurrent access is mediated by atomic
- * operations for panic dump, or mutex/cv for live dump.
- *
- * There a four queues, used as follows:
- *
- * Queue Dataflow NewState
- * --------------------------------------------------
- * mainq master -> master FREEMAP
- * master has initialized or unmapped an input buffer
- * --------------------------------------------------
- * helperq master -> helper INREADY
- * master has mapped input for use by helper
- * --------------------------------------------------
- * mainq master <- helper USEDMAP
- * helper is done with input
- * --------------------------------------------------
- * freebufq master -> helper FREEBUF
- * master has initialized or written an output buffer
- * --------------------------------------------------
- * mainq master <- helper WRITE
- * block of compressed pages from a helper
- * --------------------------------------------------
- * mainq master <- helper ERRMSG
- * error messages from a helper (memory error case)
- * --------------------------------------------------
- * writerq master <- master WRITE
- * non-blocking queue of blocks to write
- * --------------------------------------------------
- */
-typedef struct cqueue {
- cbuf_t *volatile first; /* first in list */
- cbuf_t *last; /* last in list */
- hrtime_t ts; /* timestamp */
- hrtime_t empty; /* total time empty */
- kmutex_t mutex; /* live state lock */
- kcondvar_t cv; /* live wait var */
- lock_t spinlock; /* panic mode spin lock */
- volatile uint_t open; /* producer ref count */
-} cqueue_t;
-
-/*
- * Convenience macros for using the cqueue functions
- * Note that the caller must have defined "dumpsync_t *ds"
- */
-#define CQ_IS_EMPTY(q) \
- (ds->q.first == NULL)
-
-#define CQ_OPEN(q) \
- atomic_inc_uint(&ds->q.open)
-
-#define CQ_CLOSE(q) \
- dumpsys_close_cq(&ds->q, ds->live)
-
-#define CQ_PUT(q, cp, st) \
- dumpsys_put_cq(&ds->q, cp, st, ds->live)
-
-#define CQ_GET(q) \
- dumpsys_get_cq(&ds->q, ds->live)
-
-/*
* Dynamic state when dumpsys() is running.
*/
typedef struct dumpsync {
pgcnt_t npages; /* subtotal of pages dumped */
pgcnt_t pages_mapped; /* subtotal of pages mapped */
pgcnt_t pages_used; /* subtotal of pages used per map */
size_t nwrite; /* subtotal of bytes written */
- uint_t live; /* running live dump */
- uint_t neednl; /* will need to print a newline */
uint_t percent; /* dump progress */
uint_t percent_done; /* dump progress reported */
- cqueue_t freebufq; /* free kmem bufs for writing */
- cqueue_t mainq; /* input for main task */
- cqueue_t helperq; /* input for helpers */
- cqueue_t writerq; /* input for writer */
hrtime_t start; /* start time */
hrtime_t elapsed; /* elapsed time when completed */
hrtime_t iotime; /* time spent writing nwrite bytes */
hrtime_t iowait; /* time spent waiting for output */
hrtime_t iowaitts; /* iowait timestamp */
perpage_t perpage; /* metrics */
perpage_t perpagets;
- int dumpcpu; /* master cpu */
} dumpsync_t;
static dumpsync_t dumpsync; /* synchronization vars */
/*
- * helper_t helpers: contains the context for a stream. CPUs run in
- * parallel at dump time; each CPU creates a single stream of
- * compression data. Stream data is divided into CBUF_SIZE blocks.
- * The blocks are written in order within a stream. But, blocks from
- * multiple streams can be interleaved. Each stream is identified by a
- * unique tag.
+ * configuration vars for dumpsys
*/
-typedef struct helper {
- int helper; /* bound helper id */
- int tag; /* compression stream tag */
+typedef struct dumpcfg {
perpage_t perpage; /* per page metrics */
perpage_t perpagets; /* per page metrics (timestamps) */
- taskqid_t taskqid; /* live dump task ptr */
- int in, out; /* buffer offsets */
- cbuf_t *cpin, *cpout, *cperr; /* cbuf objects in process */
- dumpsync_t *ds; /* pointer to sync vars */
- size_t used; /* counts input consumed */
char *page; /* buffer for page copy */
char *lzbuf; /* lzjb output */
- bz_stream bzstream; /* bzip2 state */
-} helper_t;
-#define MAINHELPER (-1) /* helper is also the main task */
-#define FREEHELPER (-2) /* unbound helper */
-#define DONEHELPER (-3) /* helper finished */
-
-/*
- * configuration vars for dumpsys
- */
-typedef struct dumpcfg {
- int threshold; /* ncpu threshold for bzip2 */
- int nhelper; /* number of helpers */
- int nhelper_used; /* actual number of helpers used */
- int ncmap; /* number VA pages for compression */
- int ncbuf; /* number of bufs for compression */
- int ncbuf_used; /* number of bufs in use */
- uint_t clevel; /* dump compression level */
- helper_t *helper; /* array of helpers */
- cbuf_t *cmap; /* array of input (map) buffers */
- cbuf_t *cbuf; /* array of output buffers */
- ulong_t *helpermap; /* set of dumpsys helper CPU ids */
+ char *cmap; /* array of input (map) buffers */
ulong_t *bitmap; /* bitmap for marking pages to dump */
- ulong_t *rbitmap; /* bitmap for used CBUF_MAPSIZE ranges */
pgcnt_t bitmapsize; /* size of bitmap */
- pgcnt_t rbitmapsize; /* size of bitmap for ranges */
- pgcnt_t found4m; /* number ranges allocated by dump */
- pgcnt_t foundsm; /* number small pages allocated by dump */
pid_t *pids; /* list of process IDs at dump time */
- size_t maxsize; /* memory size needed at dump time */
- size_t maxvmsize; /* size of reserved VM */
- char *maxvm; /* reserved VM for spare pages */
- lock_t helper_lock; /* protect helper state */
- char helpers_wanted; /* flag to enable parallelism */
} dumpcfg_t;
static dumpcfg_t dumpcfg; /* config vars */
/*
@@ -431,11 +205,11 @@
char *end; /* dump buffer end */
size_t size; /* size of dumpbuf in bytes */
size_t iosize; /* best transfer size for device */
} dumpbuf_t;
-dumpbuf_t dumpbuf; /* I/O buffer */
+static dumpbuf_t dumpbuf; /* I/O buffer */
/*
* The dump I/O buffer must be at least one page, at most xfer_size
* bytes, and should scale with physmem in between. The transfer size
* passed in will either represent a global default (maxphys) or the
@@ -443,11 +217,11 @@
* limited by dumpbuf_limit (8MB by default) because the dump
* performance saturates beyond a certain size. The default is to
* select 1/4096 of the memory.
*/
static int dumpbuf_fraction = 12; /* memory size scale factor */
-static size_t dumpbuf_limit = 8 * DUMP_1MB; /* max I/O buf size */
+static size_t dumpbuf_limit = 8 << 20; /* max I/O buf size */
static size_t
dumpbuf_iosize(size_t xfer_size)
{
size_t iosize = ptob(physmem >> dumpbuf_fraction);
@@ -485,11 +259,10 @@
kmem_free(old_buf, old_size);
}
/*
* dump_update_clevel is called when dumpadm configures the dump device.
- * Calculate number of helpers and buffers.
* Allocate the minimum configuration for now.
*
* When the dump file is configured we reserve a minimum amount of
* memory for use at crash time. But we reserve VA for all the memory
* we really want in order to do the fastest dump possible. The VA is
@@ -497,195 +270,51 @@
* there is insufficient spare memory, however, we fall back to the
* minimum.
*
* Live dump (savecore -L) always uses the minimum config.
*
- * clevel 0 is single threaded lzjb
- * clevel 1 is parallel lzjb
- * clevel 2 is parallel bzip2
+ * For single-threaded dumps, the panic CPU does lzjb compression.
*
- * The ncpu threshold is selected with dump_plat_mincpu.
- * On OPL, set_platform_defaults() overrides the sun4u setting.
- * The actual values are defined via DUMP_PLAT_*_MINCPU macros.
- *
- * Architecture Threshold Algorithm
- * sun4u < 51 parallel lzjb
- * sun4u >= 51 parallel bzip2(*)
- * sun4u OPL < 8 parallel lzjb
- * sun4u OPL >= 8 parallel bzip2(*)
- * sun4v < 128 parallel lzjb
- * sun4v >= 128 parallel bzip2(*)
- * x86 < 11 parallel lzjb
- * x86 >= 11 parallel bzip2(*)
- * 32-bit N/A single-threaded lzjb
- *
- * (*) bzip2 is only chosen if there is sufficient available
- * memory for buffers at dump time. See dumpsys_get_maxmem().
- *
- * Faster dump devices have larger I/O buffers. The threshold value is
- * increased according to the size of the dump I/O buffer, because
- * parallel lzjb performs better with faster disks. For buffers >= 1MB
- * the threshold is 3X; for buffers >= 256K threshold is 2X.
- *
- * For parallel dumps, the number of helpers is ncpu-1. The CPU
- * running panic runs the main task. For single-threaded dumps, the
- * panic CPU does lzjb compression (it is tagged as MAINHELPER.)
- *
- * Need multiple buffers per helper so that they do not block waiting
- * for the main task.
- * parallel single-threaded
- * Number of output buffers: nhelper*2 1
- * Number of mapping buffers: nhelper*4 1
- *
*/
static void
dump_update_clevel()
{
- int tag;
- size_t bz2size;
- helper_t *hp, *hpend;
- cbuf_t *cp, *cpend;
dumpcfg_t *old = &dumpcfg;
dumpcfg_t newcfg = *old;
dumpcfg_t *new = &newcfg;
ASSERT(MUTEX_HELD(&dump_lock));
/*
* Free the previously allocated bufs and VM.
*/
- if (old->helper != NULL) {
+ if (old->lzbuf)
+ kmem_free(old->lzbuf, PAGESIZE);
+ if (old->page)
+ kmem_free(old->page, PAGESIZE);
- /* helpers */
- hpend = &old->helper[old->nhelper];
- for (hp = old->helper; hp != hpend; hp++) {
- if (hp->lzbuf != NULL)
- kmem_free(hp->lzbuf, PAGESIZE);
- if (hp->page != NULL)
- kmem_free(hp->page, PAGESIZE);
- }
- kmem_free(old->helper, old->nhelper * sizeof (helper_t));
-
+ if (old->cmap)
/* VM space for mapping pages */
- cpend = &old->cmap[old->ncmap];
- for (cp = old->cmap; cp != cpend; cp++)
- vmem_xfree(heap_arena, cp->buf, CBUF_MAPSIZE);
- kmem_free(old->cmap, old->ncmap * sizeof (cbuf_t));
+ vmem_xfree(heap_arena, old->cmap, PAGESIZE);
- /* output bufs */
- cpend = &old->cbuf[old->ncbuf];
- for (cp = old->cbuf; cp != cpend; cp++)
- if (cp->buf != NULL)
- kmem_free(cp->buf, cp->size);
- kmem_free(old->cbuf, old->ncbuf * sizeof (cbuf_t));
-
- /* reserved VM for dumpsys_get_maxmem */
- if (old->maxvmsize > 0)
- vmem_xfree(heap_arena, old->maxvm, old->maxvmsize);
- }
-
/*
- * Allocate memory and VM.
- * One CPU runs dumpsys, the rest are helpers.
+ * Allocate new data structures and buffers, and also figure the max
+ * desired size.
*/
- new->nhelper = ncpus - 1;
- if (new->nhelper < 1)
- new->nhelper = 1;
+ new->lzbuf = kmem_alloc(PAGESIZE, KM_SLEEP);
+ new->page = kmem_alloc(PAGESIZE, KM_SLEEP);
- if (new->nhelper > DUMP_MAX_NHELPER)
- new->nhelper = DUMP_MAX_NHELPER;
-
- /* use platform default, unless /etc/system overrides */
- if (dump_plat_mincpu == MINCPU_NOT_SET)
- dump_plat_mincpu = dump_plat_mincpu_default;
-
- /* increase threshold for faster disks */
- new->threshold = dump_plat_mincpu;
- if (dumpbuf.iosize >= DUMP_1MB)
- new->threshold *= 3;
- else if (dumpbuf.iosize >= (256 * DUMP_1KB))
- new->threshold *= 2;
-
- /* figure compression level based upon the computed threshold. */
- if (dump_plat_mincpu == 0 || new->nhelper < 2) {
- new->clevel = 0;
- new->nhelper = 1;
- } else if ((new->nhelper + 1) >= new->threshold) {
- new->clevel = DUMP_CLEVEL_BZIP2;
- } else {
- new->clevel = DUMP_CLEVEL_LZJB;
- }
-
- if (new->clevel == 0) {
- new->ncbuf = 1;
- new->ncmap = 1;
- } else {
- new->ncbuf = NCBUF_PER_HELPER * new->nhelper;
- new->ncmap = NCMAP_PER_HELPER * new->nhelper;
- }
-
- /*
- * Allocate new data structures and buffers for MINHELPERS,
- * and also figure the max desired size.
- */
- bz2size = BZ2_bzCompressInitSize(dump_bzip2_level);
- new->maxsize = 0;
- new->maxvmsize = 0;
- new->maxvm = NULL;
- tag = 1;
- new->helper = kmem_zalloc(new->nhelper * sizeof (helper_t), KM_SLEEP);
- hpend = &new->helper[new->nhelper];
- for (hp = new->helper; hp != hpend; hp++) {
- hp->tag = tag++;
- if (hp < &new->helper[MINHELPERS]) {
- hp->lzbuf = kmem_alloc(PAGESIZE, KM_SLEEP);
- hp->page = kmem_alloc(PAGESIZE, KM_SLEEP);
- } else if (new->clevel < DUMP_CLEVEL_BZIP2) {
- new->maxsize += 2 * PAGESIZE;
- } else {
- new->maxsize += PAGESIZE;
- }
- if (new->clevel >= DUMP_CLEVEL_BZIP2)
- new->maxsize += bz2size;
- }
-
- new->cbuf = kmem_zalloc(new->ncbuf * sizeof (cbuf_t), KM_SLEEP);
- cpend = &new->cbuf[new->ncbuf];
- for (cp = new->cbuf; cp != cpend; cp++) {
- cp->state = CBUF_FREEBUF;
- cp->size = CBUF_SIZE;
- if (cp < &new->cbuf[MINCBUFS])
- cp->buf = kmem_alloc(cp->size, KM_SLEEP);
- else
- new->maxsize += cp->size;
- }
-
- new->cmap = kmem_zalloc(new->ncmap * sizeof (cbuf_t), KM_SLEEP);
- cpend = &new->cmap[new->ncmap];
- for (cp = new->cmap; cp != cpend; cp++) {
- cp->state = CBUF_FREEMAP;
- cp->size = CBUF_MAPSIZE;
- cp->buf = vmem_xalloc(heap_arena, CBUF_MAPSIZE, CBUF_MAPSIZE,
+ new->cmap = vmem_xalloc(heap_arena, PAGESIZE, PAGESIZE,
0, 0, NULL, NULL, VM_SLEEP);
- }
- /* reserve VA to be backed with spare pages at crash time */
- if (new->maxsize > 0) {
- new->maxsize = P2ROUNDUP(new->maxsize, PAGESIZE);
- new->maxvmsize = P2ROUNDUP(new->maxsize, CBUF_MAPSIZE);
- new->maxvm = vmem_xalloc(heap_arena, new->maxvmsize,
- CBUF_MAPSIZE, 0, 0, NULL, NULL, VM_SLEEP);
- }
-
/*
* Reserve memory for kmem allocation calls made during crash
* dump. The hat layer allocates memory for each mapping
* created, and the I/O path allocates buffers and data structs.
* Add a few pages for safety.
*/
- kmem_dump_init((new->ncmap * dump_kmem_permap) +
- (dump_kmem_pages * PAGESIZE));
+ kmem_dump_init(dump_kmem_permap + (dump_kmem_pages * PAGESIZE));
/* set new config pointers */
*old = *new;
}
@@ -751,343 +380,14 @@
bitnum += mp->ml_size >> PAGESHIFT;
}
return ((pgcnt_t)-1);
}
-/*
- * Set/test bitmap for a CBUF_MAPSIZE range which includes pfn. The
- * mapping of pfn to range index is imperfect because pfn and bitnum
- * do not have the same phase. To make sure a CBUF_MAPSIZE range is
- * covered, call this for both ends:
- * dump_set_used(base)
- * dump_set_used(base+CBUF_MAPNP-1)
- *
- * This is used during a panic dump to mark pages allocated by
- * dumpsys_get_maxmem(). The macro IS_DUMP_PAGE(pp) is used by
- * page_get_mnode_freelist() to make sure pages used by dump are never
- * allocated.
- */
-#define CBUF_MAPP2R(pfn) ((pfn) >> (CBUF_MAPSHIFT - PAGESHIFT))
-
static void
-dump_set_used(pfn_t pfn)
-{
-
- pgcnt_t bitnum, rbitnum;
-
- bitnum = dump_pfn_to_bitnum(pfn);
- ASSERT(bitnum != (pgcnt_t)-1);
-
- rbitnum = CBUF_MAPP2R(bitnum);
- ASSERT(rbitnum < dumpcfg.rbitmapsize);
-
- BT_SET(dumpcfg.rbitmap, rbitnum);
-}
-
-int
-dump_test_used(pfn_t pfn)
-{
- pgcnt_t bitnum, rbitnum;
-
- bitnum = dump_pfn_to_bitnum(pfn);
- ASSERT(bitnum != (pgcnt_t)-1);
-
- rbitnum = CBUF_MAPP2R(bitnum);
- ASSERT(rbitnum < dumpcfg.rbitmapsize);
-
- return (BT_TEST(dumpcfg.rbitmap, rbitnum));
-}
-
-/*
- * dumpbzalloc and dumpbzfree are callbacks from the bzip2 library.
- * dumpsys_get_maxmem() uses them for BZ2_bzCompressInit().
- */
-static void *
-dumpbzalloc(void *opaque, int items, int size)
-{
- size_t *sz;
- char *ret;
-
- ASSERT(opaque != NULL);
- sz = opaque;
- ret = dumpcfg.maxvm + *sz;
- *sz += items * size;
- *sz = P2ROUNDUP(*sz, BZ2_BZALLOC_ALIGN);
- ASSERT(*sz <= dumpcfg.maxvmsize);
- return (ret);
-}
-
-/*ARGSUSED*/
-static void
-dumpbzfree(void *opaque, void *addr)
-{
-}
-
-/*
- * Perform additional checks on the page to see if we can really use
- * it. The kernel (kas) pages are always set in the bitmap. However,
- * boot memory pages (prom_ppages or P_BOOTPAGES) are not in the
- * bitmap. So we check for them.
- */
-static inline int
-dump_pfn_check(pfn_t pfn)
-{
- page_t *pp = page_numtopp_nolock(pfn);
- if (pp == NULL || pp->p_pagenum != pfn ||
-#if defined(__sparc)
- pp->p_vnode == &promvp ||
-#else
- PP_ISBOOTPAGES(pp) ||
-#endif
- pp->p_toxic != 0)
- return (0);
- return (1);
-}
-
-/*
- * Check a range to see if all contained pages are available and
- * return non-zero if the range can be used.
- */
-static inline int
-dump_range_check(pgcnt_t start, pgcnt_t end, pfn_t pfn)
-{
- for (; start < end; start++, pfn++) {
- if (BT_TEST(dumpcfg.bitmap, start))
- return (0);
- if (!dump_pfn_check(pfn))
- return (0);
- }
- return (1);
-}
-
-/*
- * dumpsys_get_maxmem() is called during panic. Find unused ranges
- * and use them for buffers. If we find enough memory switch to
- * parallel bzip2, otherwise use parallel lzjb.
- *
- * It searches the dump bitmap in 2 passes. The first time it looks
- * for CBUF_MAPSIZE ranges. On the second pass it uses small pages.
- */
-static void
-dumpsys_get_maxmem()
-{
- dumpcfg_t *cfg = &dumpcfg;
- cbuf_t *endcp = &cfg->cbuf[cfg->ncbuf];
- helper_t *endhp = &cfg->helper[cfg->nhelper];
- pgcnt_t bitnum, end;
- size_t sz, endsz, bz2size;
- pfn_t pfn, off;
- cbuf_t *cp;
- helper_t *hp, *ohp;
- dumpmlw_t mlw;
- int k;
-
- /*
- * Setting dump_plat_mincpu to 0 at any time forces a serial
- * dump.
- */
- if (dump_plat_mincpu == 0) {
- cfg->clevel = 0;
- return;
- }
-
- /*
- * There may be no point in looking for spare memory. If
- * dumping all memory, then none is spare. If doing a serial
- * dump, then already have buffers.
- */
- if (cfg->maxsize == 0 || cfg->clevel < DUMP_CLEVEL_LZJB ||
- (dump_conflags & DUMP_ALL) != 0) {
- if (cfg->clevel > DUMP_CLEVEL_LZJB)
- cfg->clevel = DUMP_CLEVEL_LZJB;
- return;
- }
-
- sz = 0;
- cfg->found4m = 0;
- cfg->foundsm = 0;
-
- /* bitmap of ranges used to estimate which pfns are being used */
- bzero(dumpcfg.rbitmap, BT_SIZEOFMAP(dumpcfg.rbitmapsize));
-
- /* find ranges that are not being dumped to use for buffers */
- dump_init_memlist_walker(&mlw);
- for (bitnum = 0; bitnum < dumpcfg.bitmapsize; bitnum = end) {
- dump_timeleft = dump_timeout;
- end = bitnum + CBUF_MAPNP;
- pfn = dump_bitnum_to_pfn(bitnum, &mlw);
- ASSERT(pfn != PFN_INVALID);
-
- /* skip partial range at end of mem segment */
- if (mlw.mpleft < CBUF_MAPNP) {
- end = bitnum + mlw.mpleft;
- continue;
- }
-
- /* skip non aligned pages */
- off = P2PHASE(pfn, CBUF_MAPNP);
- if (off != 0) {
- end -= off;
- continue;
- }
-
- if (!dump_range_check(bitnum, end, pfn))
- continue;
-
- ASSERT((sz + CBUF_MAPSIZE) <= cfg->maxvmsize);
- hat_devload(kas.a_hat, cfg->maxvm + sz, CBUF_MAPSIZE, pfn,
- PROT_READ | PROT_WRITE, HAT_LOAD_NOCONSIST);
- sz += CBUF_MAPSIZE;
- cfg->found4m++;
-
- /* set the bitmap for both ends to be sure to cover the range */
- dump_set_used(pfn);
- dump_set_used(pfn + CBUF_MAPNP - 1);
-
- if (sz >= cfg->maxsize)
- goto foundmax;
- }
-
- /* Add small pages if we can't find enough large pages. */
- dump_init_memlist_walker(&mlw);
- for (bitnum = 0; bitnum < dumpcfg.bitmapsize; bitnum = end) {
- dump_timeleft = dump_timeout;
- end = bitnum + CBUF_MAPNP;
- pfn = dump_bitnum_to_pfn(bitnum, &mlw);
- ASSERT(pfn != PFN_INVALID);
-
- /* Find any non-aligned pages at start and end of segment. */
- off = P2PHASE(pfn, CBUF_MAPNP);
- if (mlw.mpleft < CBUF_MAPNP) {
- end = bitnum + mlw.mpleft;
- } else if (off != 0) {
- end -= off;
- } else if (cfg->found4m && dump_test_used(pfn)) {
- continue;
- }
-
- for (; bitnum < end; bitnum++, pfn++) {
- dump_timeleft = dump_timeout;
- if (BT_TEST(dumpcfg.bitmap, bitnum))
- continue;
- if (!dump_pfn_check(pfn))
- continue;
- ASSERT((sz + PAGESIZE) <= cfg->maxvmsize);
- hat_devload(kas.a_hat, cfg->maxvm + sz, PAGESIZE, pfn,
- PROT_READ | PROT_WRITE, HAT_LOAD_NOCONSIST);
- sz += PAGESIZE;
- cfg->foundsm++;
- dump_set_used(pfn);
- if (sz >= cfg->maxsize)
- goto foundmax;
- }
- }
-
- /* Fall back to lzjb if we did not get enough memory for bzip2. */
- endsz = (cfg->maxsize * cfg->threshold) / cfg->nhelper;
- if (sz < endsz) {
- cfg->clevel = DUMP_CLEVEL_LZJB;
- }
-
- /* Allocate memory for as many helpers as we can. */
-foundmax:
-
- /* Byte offsets into memory found and mapped above */
- endsz = sz;
- sz = 0;
-
- /* Set the size for bzip2 state. Only bzip2 needs it. */
- bz2size = BZ2_bzCompressInitSize(dump_bzip2_level);
-
- /* Skip the preallocate output buffers. */
- cp = &cfg->cbuf[MINCBUFS];
-
- /* Use this to move memory up from the preallocated helpers. */
- ohp = cfg->helper;
-
- /* Loop over all helpers and allocate memory. */
- for (hp = cfg->helper; hp < endhp; hp++) {
-
- /* Skip preallocated helpers by checking hp->page. */
- if (hp->page == NULL) {
- if (cfg->clevel <= DUMP_CLEVEL_LZJB) {
- /* lzjb needs 2 1-page buffers */
- if ((sz + (2 * PAGESIZE)) > endsz)
- break;
- hp->page = cfg->maxvm + sz;
- sz += PAGESIZE;
- hp->lzbuf = cfg->maxvm + sz;
- sz += PAGESIZE;
-
- } else if (ohp->lzbuf != NULL) {
- /* re-use the preallocted lzjb page for bzip2 */
- hp->page = ohp->lzbuf;
- ohp->lzbuf = NULL;
- ++ohp;
-
- } else {
- /* bzip2 needs a 1-page buffer */
- if ((sz + PAGESIZE) > endsz)
- break;
- hp->page = cfg->maxvm + sz;
- sz += PAGESIZE;
- }
- }
-
- /*
- * Add output buffers per helper. The number of
- * buffers per helper is determined by the ratio of
- * ncbuf to nhelper.
- */
- for (k = 0; cp < endcp && (sz + CBUF_SIZE) <= endsz &&
- k < NCBUF_PER_HELPER; k++) {
- cp->state = CBUF_FREEBUF;
- cp->size = CBUF_SIZE;
- cp->buf = cfg->maxvm + sz;
- sz += CBUF_SIZE;
- ++cp;
- }
-
- /*
- * bzip2 needs compression state. Use the dumpbzalloc
- * and dumpbzfree callbacks to allocate the memory.
- * bzip2 does allocation only at init time.
- */
- if (cfg->clevel >= DUMP_CLEVEL_BZIP2) {
- if ((sz + bz2size) > endsz) {
- hp->page = NULL;
- break;
- } else {
- hp->bzstream.opaque = &sz;
- hp->bzstream.bzalloc = dumpbzalloc;
- hp->bzstream.bzfree = dumpbzfree;
- (void) BZ2_bzCompressInit(&hp->bzstream,
- dump_bzip2_level, 0, 0);
- hp->bzstream.opaque = NULL;
- }
- }
- }
-
- /* Finish allocating output buffers */
- for (; cp < endcp && (sz + CBUF_SIZE) <= endsz; cp++) {
- cp->state = CBUF_FREEBUF;
- cp->size = CBUF_SIZE;
- cp->buf = cfg->maxvm + sz;
- sz += CBUF_SIZE;
- }
-
- /* Enable IS_DUMP_PAGE macro, which checks for pages we took. */
- if (cfg->found4m || cfg->foundsm)
- dump_check_used = 1;
-
- ASSERT(sz <= endsz);
-}
-
-static void
dumphdr_init(void)
{
- pgcnt_t npages = 0;
+ pgcnt_t npages;
ASSERT(MUTEX_HELD(&dump_lock));
if (dumphdr == NULL) {
dumphdr = kmem_zalloc(sizeof (dumphdr_t), KM_SLEEP);
@@ -1100,34 +400,25 @@
(void) strcpy(dumphdr->dump_platform, platform);
dumpbuf.size = dumpbuf_iosize(maxphys);
dumpbuf.start = kmem_alloc(dumpbuf.size, KM_SLEEP);
dumpbuf.end = dumpbuf.start + dumpbuf.size;
dumpcfg.pids = kmem_alloc(v.v_proc * sizeof (pid_t), KM_SLEEP);
- dumpcfg.helpermap = kmem_zalloc(BT_SIZEOFMAP(NCPU), KM_SLEEP);
- LOCK_INIT_HELD(&dumpcfg.helper_lock);
dump_stack_scratch = kmem_alloc(STACK_BUF_SIZE, KM_SLEEP);
(void) strncpy(dumphdr->dump_uuid, dump_get_uuid(),
sizeof (dumphdr->dump_uuid));
}
npages = num_phys_pages();
if (dumpcfg.bitmapsize != npages) {
- size_t rlen = CBUF_MAPP2R(P2ROUNDUP(npages, CBUF_MAPNP));
void *map = kmem_alloc(BT_SIZEOFMAP(npages), KM_SLEEP);
- void *rmap = kmem_alloc(BT_SIZEOFMAP(rlen), KM_SLEEP);
if (dumpcfg.bitmap != NULL)
kmem_free(dumpcfg.bitmap, BT_SIZEOFMAP(dumpcfg.
bitmapsize));
- if (dumpcfg.rbitmap != NULL)
- kmem_free(dumpcfg.rbitmap, BT_SIZEOFMAP(dumpcfg.
- rbitmapsize));
dumpcfg.bitmap = map;
dumpcfg.bitmapsize = npages;
- dumpcfg.rbitmap = rmap;
- dumpcfg.rbitmapsize = rlen;
}
}
/*
* Establish a new dump device.
@@ -1553,17 +844,10 @@
B_INVAL | B_FORCE, kcred, NULL);
}
}
/*
- * The following functions are called on multiple CPUs during dump.
- * They must not use most kernel services, because all cross-calls are
- * disabled during panic. Therefore, blocking locks and cache flushes
- * will not work.
- */
-
-/*
* Copy pages, trapping ECC errors. Also, for robustness, trap data
* access in case something goes wrong in the hat layer and the
* mapping is broken.
*/
static int
@@ -1598,924 +882,18 @@
}
no_trap();
return (ueoff);
}
-static void
-dumpsys_close_cq(cqueue_t *cq, int live)
-{
- if (live) {
- mutex_enter(&cq->mutex);
- atomic_dec_uint(&cq->open);
- cv_signal(&cq->cv);
- mutex_exit(&cq->mutex);
- } else {
- atomic_dec_uint(&cq->open);
- }
-}
-
-static inline void
-dumpsys_spinlock(lock_t *lp)
-{
- uint_t backoff = 0;
- int loop_count = 0;
-
- while (LOCK_HELD(lp) || !lock_spin_try(lp)) {
- if (++loop_count >= ncpus) {
- backoff = mutex_lock_backoff(0);
- loop_count = 0;
- } else {
- backoff = mutex_lock_backoff(backoff);
- }
- mutex_lock_delay(backoff);
- }
-}
-
-static inline void
-dumpsys_spinunlock(lock_t *lp)
-{
- lock_clear(lp);
-}
-
-static inline void
-dumpsys_lock(cqueue_t *cq, int live)
-{
- if (live)
- mutex_enter(&cq->mutex);
- else
- dumpsys_spinlock(&cq->spinlock);
-}
-
-static inline void
-dumpsys_unlock(cqueue_t *cq, int live, int signal)
-{
- if (live) {
- if (signal)
- cv_signal(&cq->cv);
- mutex_exit(&cq->mutex);
- } else {
- dumpsys_spinunlock(&cq->spinlock);
- }
-}
-
-static void
-dumpsys_wait_cq(cqueue_t *cq, int live)
-{
- if (live) {
- cv_wait(&cq->cv, &cq->mutex);
- } else {
- dumpsys_spinunlock(&cq->spinlock);
- while (cq->open)
- if (cq->first)
- break;
- dumpsys_spinlock(&cq->spinlock);
- }
-}
-
-static void
-dumpsys_put_cq(cqueue_t *cq, cbuf_t *cp, int newstate, int live)
-{
- if (cp == NULL)
- return;
-
- dumpsys_lock(cq, live);
-
- if (cq->ts != 0) {
- cq->empty += gethrtime() - cq->ts;
- cq->ts = 0;
- }
-
- cp->state = newstate;
- cp->next = NULL;
- if (cq->last == NULL)
- cq->first = cp;
- else
- cq->last->next = cp;
- cq->last = cp;
-
- dumpsys_unlock(cq, live, 1);
-}
-
-static cbuf_t *
-dumpsys_get_cq(cqueue_t *cq, int live)
-{
- cbuf_t *cp;
- hrtime_t now = gethrtime();
-
- dumpsys_lock(cq, live);
-
- /* CONSTCOND */
- while (1) {
- cp = (cbuf_t *)cq->first;
- if (cp == NULL) {
- if (cq->open == 0)
- break;
- dumpsys_wait_cq(cq, live);
- continue;
- }
- cq->first = cp->next;
- if (cq->first == NULL) {
- cq->last = NULL;
- cq->ts = now;
- }
- break;
- }
-
- dumpsys_unlock(cq, live, cq->first != NULL || cq->open == 0);
- return (cp);
-}
-
-/*
- * Send an error message to the console. If the main task is running
- * just write the message via uprintf. If a helper is running the
- * message has to be put on a queue for the main task. Setting fmt to
- * NULL means flush the error message buffer. If fmt is not NULL, just
- * add the text to the existing buffer.
- */
-static void
-dumpsys_errmsg(helper_t *hp, const char *fmt, ...)
-{
- dumpsync_t *ds = hp->ds;
- cbuf_t *cp = hp->cperr;
- va_list adx;
-
- if (hp->helper == MAINHELPER) {
- if (fmt != NULL) {
- if (ds->neednl) {
- uprintf("\n");
- ds->neednl = 0;
- }
- va_start(adx, fmt);
- vuprintf(fmt, adx);
- va_end(adx);
- }
- } else if (fmt == NULL) {
- if (cp != NULL) {
- CQ_PUT(mainq, cp, CBUF_ERRMSG);
- hp->cperr = NULL;
- }
- } else {
- if (hp->cperr == NULL) {
- cp = CQ_GET(freebufq);
- hp->cperr = cp;
- cp->used = 0;
- }
- va_start(adx, fmt);
- cp->used += vsnprintf(cp->buf + cp->used, cp->size - cp->used,
- fmt, adx);
- va_end(adx);
- if ((cp->used + LOG_MSGSIZE) > cp->size) {
- CQ_PUT(mainq, cp, CBUF_ERRMSG);
- hp->cperr = NULL;
- }
- }
-}
-
-/*
- * Write an output buffer to the dump file. If the main task is
- * running just write the data. If a helper is running the output is
- * placed on a queue for the main task.
- */
-static void
-dumpsys_swrite(helper_t *hp, cbuf_t *cp, size_t used)
-{
- dumpsync_t *ds = hp->ds;
-
- if (hp->helper == MAINHELPER) {
- HRSTART(ds->perpage, write);
- dumpvp_write(cp->buf, used);
- HRSTOP(ds->perpage, write);
- CQ_PUT(freebufq, cp, CBUF_FREEBUF);
- } else {
- cp->used = used;
- CQ_PUT(mainq, cp, CBUF_WRITE);
- }
-}
-
-/*
- * Copy one page within the mapped range. The offset starts at 0 and
- * is relative to the first pfn. cp->buf + cp->off is the address of
- * the first pfn. If dump_pagecopy returns a UE offset, create an
- * error message. Returns the offset to the next pfn in the range
- * selected by the bitmap.
- */
-static int
-dumpsys_copy_page(helper_t *hp, int offset)
-{
- cbuf_t *cp = hp->cpin;
- int ueoff;
-
- ASSERT(cp->off + offset + PAGESIZE <= cp->size);
- ASSERT(BT_TEST(dumpcfg.bitmap, cp->bitnum));
-
- ueoff = dump_pagecopy(cp->buf + cp->off + offset, hp->page);
-
- /* ueoff is the offset in the page to a UE error */
- if (ueoff != -1) {
- uint64_t pa = ptob(cp->pfn) + offset + ueoff;
-
- dumpsys_errmsg(hp, "cpu %d: memory error at PA 0x%08x.%08x\n",
- CPU->cpu_id, (uint32_t)(pa >> 32), (uint32_t)pa);
- }
-
- /*
- * Advance bitnum and offset to the next input page for the
- * next call to this function.
- */
- offset += PAGESIZE;
- cp->bitnum++;
- while (cp->off + offset < cp->size) {
- if (BT_TEST(dumpcfg.bitmap, cp->bitnum))
- break;
- offset += PAGESIZE;
- cp->bitnum++;
- }
-
- return (offset);
-}
-
-/*
- * Read the helper queue, and copy one mapped page. Return 0 when
- * done. Return 1 when a page has been copied into hp->page.
- */
-static int
-dumpsys_sread(helper_t *hp)
-{
- dumpsync_t *ds = hp->ds;
-
- /* CONSTCOND */
- while (1) {
-
- /* Find the next input buffer. */
- if (hp->cpin == NULL) {
- HRSTART(hp->perpage, inwait);
-
- /* CONSTCOND */
- while (1) {
- hp->cpin = CQ_GET(helperq);
- dump_timeleft = dump_timeout;
-
- /*
- * NULL return means the helper queue
- * is closed and empty.
- */
- if (hp->cpin == NULL)
- break;
-
- /* Have input, check for dump I/O error. */
- if (!dump_ioerr)
- break;
-
- /*
- * If an I/O error occurs, stay in the
- * loop in order to empty the helper
- * queue. Return the buffers to the
- * main task to unmap and free it.
- */
- hp->cpin->used = 0;
- CQ_PUT(mainq, hp->cpin, CBUF_USEDMAP);
- }
- HRSTOP(hp->perpage, inwait);
-
- /* Stop here when the helper queue is closed. */
- if (hp->cpin == NULL)
- break;
-
- /* Set the offset=0 to get the first pfn. */
- hp->in = 0;
-
- /* Set the total processed to 0 */
- hp->used = 0;
- }
-
- /* Process the next page. */
- if (hp->used < hp->cpin->used) {
-
- /*
- * Get the next page from the input buffer and
- * return a copy.
- */
- ASSERT(hp->in != -1);
- HRSTART(hp->perpage, copy);
- hp->in = dumpsys_copy_page(hp, hp->in);
- hp->used += PAGESIZE;
- HRSTOP(hp->perpage, copy);
- break;
-
- } else {
-
- /*
- * Done with the input. Flush the VM and
- * return the buffer to the main task.
- */
- if (panicstr && hp->helper != MAINHELPER)
- hat_flush_range(kas.a_hat,
- hp->cpin->buf, hp->cpin->size);
- dumpsys_errmsg(hp, NULL);
- CQ_PUT(mainq, hp->cpin, CBUF_USEDMAP);
- hp->cpin = NULL;
- }
- }
-
- return (hp->cpin != NULL);
-}
-
-/*
- * Compress size bytes starting at buf with bzip2
- * mode:
- * BZ_RUN add one more compressed page
- * BZ_FINISH no more input, flush the state
- */
-static void
-dumpsys_bzrun(helper_t *hp, void *buf, size_t size, int mode)
-{
- dumpsync_t *ds = hp->ds;
- const int CSIZE = sizeof (dumpcsize_t);
- bz_stream *ps = &hp->bzstream;
- int rc = 0;
- uint32_t csize;
- dumpcsize_t cs;
-
- /* Set input pointers to new input page */
- if (size > 0) {
- ps->avail_in = size;
- ps->next_in = buf;
- }
-
- /* CONSTCOND */
- while (1) {
-
- /* Quit when all input has been consumed */
- if (ps->avail_in == 0 && mode == BZ_RUN)
- break;
-
- /* Get a new output buffer */
- if (hp->cpout == NULL) {
- HRSTART(hp->perpage, outwait);
- hp->cpout = CQ_GET(freebufq);
- HRSTOP(hp->perpage, outwait);
- ps->avail_out = hp->cpout->size - CSIZE;
- ps->next_out = hp->cpout->buf + CSIZE;
- }
-
- /* Compress input, or finalize */
- HRSTART(hp->perpage, compress);
- rc = BZ2_bzCompress(ps, mode);
- HRSTOP(hp->perpage, compress);
-
- /* Check for error */
- if (mode == BZ_RUN && rc != BZ_RUN_OK) {
- dumpsys_errmsg(hp, "%d: BZ_RUN error %s at page %lx\n",
- hp->helper, BZ2_bzErrorString(rc),
- hp->cpin->pagenum);
- break;
- }
-
- /* Write the buffer if it is full, or we are flushing */
- if (ps->avail_out == 0 || mode == BZ_FINISH) {
- csize = hp->cpout->size - CSIZE - ps->avail_out;
- cs = DUMP_SET_TAG(csize, hp->tag);
- if (csize > 0) {
- (void) memcpy(hp->cpout->buf, &cs, CSIZE);
- dumpsys_swrite(hp, hp->cpout, csize + CSIZE);
- hp->cpout = NULL;
- }
- }
-
- /* Check for final complete */
- if (mode == BZ_FINISH) {
- if (rc == BZ_STREAM_END)
- break;
- if (rc != BZ_FINISH_OK) {
- dumpsys_errmsg(hp, "%d: BZ_FINISH error %s\n",
- hp->helper, BZ2_bzErrorString(rc));
- break;
- }
- }
- }
-
- /* Cleanup state and buffers */
- if (mode == BZ_FINISH) {
-
- /* Reset state so that it is re-usable. */
- (void) BZ2_bzCompressReset(&hp->bzstream);
-
- /* Give any unused outout buffer to the main task */
- if (hp->cpout != NULL) {
- hp->cpout->used = 0;
- CQ_PUT(mainq, hp->cpout, CBUF_ERRMSG);
- hp->cpout = NULL;
- }
- }
-}
-
-static void
-dumpsys_bz2compress(helper_t *hp)
-{
- dumpsync_t *ds = hp->ds;
- dumpstreamhdr_t sh;
-
- (void) strcpy(sh.stream_magic, DUMP_STREAM_MAGIC);
- sh.stream_pagenum = (pgcnt_t)-1;
- sh.stream_npages = 0;
- hp->cpin = NULL;
- hp->cpout = NULL;
- hp->cperr = NULL;
- hp->in = 0;
- hp->out = 0;
- hp->bzstream.avail_in = 0;
-
- /* Bump reference to mainq while we are running */
- CQ_OPEN(mainq);
-
- /* Get one page at a time */
- while (dumpsys_sread(hp)) {
- if (sh.stream_pagenum != hp->cpin->pagenum) {
- sh.stream_pagenum = hp->cpin->pagenum;
- sh.stream_npages = btop(hp->cpin->used);
- dumpsys_bzrun(hp, &sh, sizeof (sh), BZ_RUN);
- }
- dumpsys_bzrun(hp, hp->page, PAGESIZE, 0);
- }
-
- /* Done with input, flush any partial buffer */
- if (sh.stream_pagenum != (pgcnt_t)-1) {
- dumpsys_bzrun(hp, NULL, 0, BZ_FINISH);
- dumpsys_errmsg(hp, NULL);
- }
-
- ASSERT(hp->cpin == NULL && hp->cpout == NULL && hp->cperr == NULL);
-
- /* Decrement main queue count, we are done */
- CQ_CLOSE(mainq);
-}
-
-/*
- * Compress with lzjb
- * write stream block if full or size==0
- * if csize==0 write stream header, else write <csize, data>
- * size==0 is a call to flush a buffer
- * hp->cpout is the buffer we are flushing or filling
- * hp->out is the next index to fill data
- * osize is either csize+data, or the size of a stream header
- */
-static void
-dumpsys_lzjbrun(helper_t *hp, size_t csize, void *buf, size_t size)
-{
- dumpsync_t *ds = hp->ds;
- const int CSIZE = sizeof (dumpcsize_t);
- dumpcsize_t cs;
- size_t osize = csize > 0 ? CSIZE + size : size;
-
- /* If flush, and there is no buffer, just return */
- if (size == 0 && hp->cpout == NULL)
- return;
-
- /* If flush, or cpout is full, write it out */
- if (size == 0 ||
- hp->cpout != NULL && hp->out + osize > hp->cpout->size) {
-
- /* Set tag+size word at the front of the stream block. */
- cs = DUMP_SET_TAG(hp->out - CSIZE, hp->tag);
- (void) memcpy(hp->cpout->buf, &cs, CSIZE);
-
- /* Write block to dump file. */
- dumpsys_swrite(hp, hp->cpout, hp->out);
-
- /* Clear pointer to indicate we need a new buffer */
- hp->cpout = NULL;
-
- /* flushing, we are done */
- if (size == 0)
- return;
- }
-
- /* Get an output buffer if we dont have one. */
- if (hp->cpout == NULL) {
- HRSTART(hp->perpage, outwait);
- hp->cpout = CQ_GET(freebufq);
- HRSTOP(hp->perpage, outwait);
- hp->out = CSIZE;
- }
-
- /* Store csize word. This is the size of compressed data. */
- if (csize > 0) {
- cs = DUMP_SET_TAG(csize, 0);
- (void) memcpy(hp->cpout->buf + hp->out, &cs, CSIZE);
- hp->out += CSIZE;
- }
-
- /* Store the data. */
- (void) memcpy(hp->cpout->buf + hp->out, buf, size);
- hp->out += size;
-}
-
-static void
-dumpsys_lzjbcompress(helper_t *hp)
-{
- dumpsync_t *ds = hp->ds;
- size_t csize;
- dumpstreamhdr_t sh;
-
- (void) strcpy(sh.stream_magic, DUMP_STREAM_MAGIC);
- sh.stream_pagenum = (pfn_t)-1;
- sh.stream_npages = 0;
- hp->cpin = NULL;
- hp->cpout = NULL;
- hp->cperr = NULL;
- hp->in = 0;
- hp->out = 0;
-
- /* Bump reference to mainq while we are running */
- CQ_OPEN(mainq);
-
- /* Get one page at a time */
- while (dumpsys_sread(hp)) {
-
- /* Create a stream header for each new input map */
- if (sh.stream_pagenum != hp->cpin->pagenum) {
- sh.stream_pagenum = hp->cpin->pagenum;
- sh.stream_npages = btop(hp->cpin->used);
- dumpsys_lzjbrun(hp, 0, &sh, sizeof (sh));
- }
-
- /* Compress one page */
- HRSTART(hp->perpage, compress);
- csize = compress(hp->page, hp->lzbuf, PAGESIZE);
- HRSTOP(hp->perpage, compress);
-
- /* Add csize+data to output block */
- ASSERT(csize > 0 && csize <= PAGESIZE);
- dumpsys_lzjbrun(hp, csize, hp->lzbuf, csize);
- }
-
- /* Done with input, flush any partial buffer */
- if (sh.stream_pagenum != (pfn_t)-1) {
- dumpsys_lzjbrun(hp, 0, NULL, 0);
- dumpsys_errmsg(hp, NULL);
- }
-
- ASSERT(hp->cpin == NULL && hp->cpout == NULL && hp->cperr == NULL);
-
- /* Decrement main queue count, we are done */
- CQ_CLOSE(mainq);
-}
-
-/*
- * Dump helper called from panic_idle() to compress pages. CPUs in
- * this path must not call most kernel services.
- *
- * During panic, all but one of the CPUs is idle. These CPUs are used
- * as helpers working in parallel to copy and compress memory
- * pages. During a panic, however, these processors cannot call any
- * kernel services. This is because mutexes become no-ops during
- * panic, and, cross-call interrupts are inhibited. Therefore, during
- * panic dump the helper CPUs communicate with the panic CPU using
- * memory variables. All memory mapping and I/O is performed by the
- * panic CPU.
- *
- * At dump configuration time, helper_lock is set and helpers_wanted
- * is 0. dumpsys() decides whether to set helpers_wanted before
- * clearing helper_lock.
- *
- * At panic time, idle CPUs spin-wait on helper_lock, then alternately
- * take the lock and become a helper, or return.
- */
-void
-dumpsys_helper()
-{
- dumpsys_spinlock(&dumpcfg.helper_lock);
- if (dumpcfg.helpers_wanted) {
- helper_t *hp, *hpend = &dumpcfg.helper[dumpcfg.nhelper];
-
- for (hp = dumpcfg.helper; hp != hpend; hp++) {
- if (hp->helper == FREEHELPER) {
- hp->helper = CPU->cpu_id;
- BT_SET(dumpcfg.helpermap, CPU->cpu_seqid);
-
- dumpsys_spinunlock(&dumpcfg.helper_lock);
-
- if (dumpcfg.clevel < DUMP_CLEVEL_BZIP2)
- dumpsys_lzjbcompress(hp);
- else
- dumpsys_bz2compress(hp);
-
- hp->helper = DONEHELPER;
- return;
- }
- }
-
- /* No more helpers are needed. */
- dumpcfg.helpers_wanted = 0;
-
- }
- dumpsys_spinunlock(&dumpcfg.helper_lock);
-}
-
-/*
- * No-wait helper callable in spin loops.
- *
- * Do not wait for helper_lock. Just check helpers_wanted. The caller
- * may decide to continue. This is the "c)ontinue, s)ync, r)eset? s"
- * case.
- */
-void
-dumpsys_helper_nw()
-{
- if (dumpcfg.helpers_wanted)
- dumpsys_helper();
-}
-
-/*
- * Dump helper for live dumps.
- * These run as a system task.
- */
-static void
-dumpsys_live_helper(void *arg)
-{
- helper_t *hp = arg;
-
- BT_ATOMIC_SET(dumpcfg.helpermap, CPU->cpu_seqid);
- if (dumpcfg.clevel < DUMP_CLEVEL_BZIP2)
- dumpsys_lzjbcompress(hp);
- else
- dumpsys_bz2compress(hp);
-}
-
-/*
- * Compress one page with lzjb (single threaded case)
- */
-static void
-dumpsys_lzjb_page(helper_t *hp, cbuf_t *cp)
-{
- dumpsync_t *ds = hp->ds;
- uint32_t csize;
-
- hp->helper = MAINHELPER;
- hp->in = 0;
- hp->used = 0;
- hp->cpin = cp;
- while (hp->used < cp->used) {
- HRSTART(hp->perpage, copy);
- hp->in = dumpsys_copy_page(hp, hp->in);
- hp->used += PAGESIZE;
- HRSTOP(hp->perpage, copy);
-
- HRSTART(hp->perpage, compress);
- csize = compress(hp->page, hp->lzbuf, PAGESIZE);
- HRSTOP(hp->perpage, compress);
-
- HRSTART(hp->perpage, write);
- dumpvp_write(&csize, sizeof (csize));
- dumpvp_write(hp->lzbuf, csize);
- HRSTOP(hp->perpage, write);
- }
- CQ_PUT(mainq, hp->cpin, CBUF_USEDMAP);
- hp->cpin = NULL;
-}
-
-/*
- * Main task to dump pages. This is called on the dump CPU.
- */
-static void
-dumpsys_main_task(void *arg)
-{
- dumpsync_t *ds = arg;
- pgcnt_t pagenum = 0, bitnum = 0, hibitnum;
- dumpmlw_t mlw;
- cbuf_t *cp;
- pgcnt_t baseoff, pfnoff;
- pfn_t base, pfn;
- int sec, i, dumpserial;
-
- /*
- * Fall back to serial mode if there are no helpers.
- * dump_plat_mincpu can be set to 0 at any time.
- * dumpcfg.helpermap must contain at least one member.
- */
- dumpserial = 1;
-
- if (dump_plat_mincpu != 0 && dumpcfg.clevel != 0) {
- for (i = 0; i < BT_BITOUL(NCPU); ++i) {
- if (dumpcfg.helpermap[i] != 0) {
- dumpserial = 0;
- break;
- }
- }
- }
-
- if (dumpserial) {
- dumpcfg.clevel = 0;
- if (dumpcfg.helper[0].lzbuf == NULL)
- dumpcfg.helper[0].lzbuf = dumpcfg.helper[1].page;
- }
-
- dump_init_memlist_walker(&mlw);
-
- /* CONSTCOND */
- while (1) {
-
- if (ds->percent > ds->percent_done) {
- ds->percent_done = ds->percent;
- sec = (gethrtime() - ds->start) / 1000 / 1000 / 1000;
- uprintf("^\r%2d:%02d %3d%% done",
- sec / 60, sec % 60, ds->percent);
- ds->neednl = 1;
- }
-
- while (CQ_IS_EMPTY(mainq) && !CQ_IS_EMPTY(writerq)) {
-
- /* the writerq never blocks */
- cp = CQ_GET(writerq);
- if (cp == NULL)
- break;
-
- dump_timeleft = dump_timeout;
-
- HRSTART(ds->perpage, write);
- dumpvp_write(cp->buf, cp->used);
- HRSTOP(ds->perpage, write);
-
- CQ_PUT(freebufq, cp, CBUF_FREEBUF);
- }
-
- /*
- * Wait here for some buffers to process. Returns NULL
- * when all helpers have terminated and all buffers
- * have been processed.
- */
- cp = CQ_GET(mainq);
-
- if (cp == NULL) {
-
- /* Drain the write queue. */
- if (!CQ_IS_EMPTY(writerq))
- continue;
-
- /* Main task exits here. */
- break;
- }
-
- dump_timeleft = dump_timeout;
-
- switch (cp->state) {
-
- case CBUF_FREEMAP:
-
- /*
- * Note that we drop CBUF_FREEMAP buffers on
- * the floor (they will not be on any cqueue)
- * when we no longer need them.
- */
- if (bitnum >= dumpcfg.bitmapsize)
- break;
-
- if (dump_ioerr) {
- bitnum = dumpcfg.bitmapsize;
- CQ_CLOSE(helperq);
- break;
- }
-
- HRSTART(ds->perpage, bitmap);
- for (; bitnum < dumpcfg.bitmapsize; bitnum++)
- if (BT_TEST(dumpcfg.bitmap, bitnum))
- break;
- HRSTOP(ds->perpage, bitmap);
- dump_timeleft = dump_timeout;
-
- if (bitnum >= dumpcfg.bitmapsize) {
- CQ_CLOSE(helperq);
- break;
- }
-
- /*
- * Try to map CBUF_MAPSIZE ranges. Can't
- * assume that memory segment size is a
- * multiple of CBUF_MAPSIZE. Can't assume that
- * the segment starts on a CBUF_MAPSIZE
- * boundary.
- */
- pfn = dump_bitnum_to_pfn(bitnum, &mlw);
- ASSERT(pfn != PFN_INVALID);
- ASSERT(bitnum + mlw.mpleft <= dumpcfg.bitmapsize);
-
- base = P2ALIGN(pfn, CBUF_MAPNP);
- if (base < mlw.mpaddr) {
- base = mlw.mpaddr;
- baseoff = P2PHASE(base, CBUF_MAPNP);
- } else {
- baseoff = 0;
- }
-
- pfnoff = pfn - base;
- if (pfnoff + mlw.mpleft < CBUF_MAPNP) {
- hibitnum = bitnum + mlw.mpleft;
- cp->size = ptob(pfnoff + mlw.mpleft);
- } else {
- hibitnum = bitnum - pfnoff + CBUF_MAPNP -
- baseoff;
- cp->size = CBUF_MAPSIZE - ptob(baseoff);
- }
-
- cp->pfn = pfn;
- cp->bitnum = bitnum++;
- cp->pagenum = pagenum++;
- cp->off = ptob(pfnoff);
-
- for (; bitnum < hibitnum; bitnum++)
- if (BT_TEST(dumpcfg.bitmap, bitnum))
- pagenum++;
-
- dump_timeleft = dump_timeout;
- cp->used = ptob(pagenum - cp->pagenum);
-
- HRSTART(ds->perpage, map);
- hat_devload(kas.a_hat, cp->buf, cp->size, base,
- PROT_READ, HAT_LOAD_NOCONSIST);
- HRSTOP(ds->perpage, map);
-
- ds->pages_mapped += btop(cp->size);
- ds->pages_used += pagenum - cp->pagenum;
-
- CQ_OPEN(mainq);
-
- /*
- * If there are no helpers the main task does
- * non-streams lzjb compress.
- */
- if (dumpserial) {
- dumpsys_lzjb_page(dumpcfg.helper, cp);
- break;
- }
-
- /* pass mapped pages to a helper */
- CQ_PUT(helperq, cp, CBUF_INREADY);
-
- /* the last page was done */
- if (bitnum >= dumpcfg.bitmapsize)
- CQ_CLOSE(helperq);
-
- break;
-
- case CBUF_USEDMAP:
-
- ds->npages += btop(cp->used);
-
- HRSTART(ds->perpage, unmap);
- hat_unload(kas.a_hat, cp->buf, cp->size, HAT_UNLOAD);
- HRSTOP(ds->perpage, unmap);
-
- if (bitnum < dumpcfg.bitmapsize)
- CQ_PUT(mainq, cp, CBUF_FREEMAP);
- CQ_CLOSE(mainq);
-
- ASSERT(ds->npages <= dumphdr->dump_npages);
- ds->percent = ds->npages * 100LL / dumphdr->dump_npages;
- break;
-
- case CBUF_WRITE:
-
- CQ_PUT(writerq, cp, CBUF_WRITE);
- break;
-
- case CBUF_ERRMSG:
-
- if (cp->used > 0) {
- cp->buf[cp->size - 2] = '\n';
- cp->buf[cp->size - 1] = '\0';
- if (ds->neednl) {
- uprintf("\n%s", cp->buf);
- ds->neednl = 0;
- } else {
- uprintf("%s", cp->buf);
- }
- /* wait for console output */
- drv_usecwait(200000);
- dump_timeleft = dump_timeout;
- }
- CQ_PUT(freebufq, cp, CBUF_FREEBUF);
- break;
-
- default:
- uprintf("dump: unexpected buffer state %d, "
- "buffer will be lost\n", cp->state);
- break;
-
- } /* end switch */
-
- } /* end while(1) */
-}
-
#ifdef COLLECT_METRICS
size_t
dumpsys_metrics(dumpsync_t *ds, char *buf, size_t size)
{
dumpcfg_t *cfg = &dumpcfg;
int myid = CPU->cpu_seqid;
int i, compress_ratio;
int sec, iorate;
- helper_t *hp, *hpend = &cfg->helper[cfg->nhelper];
char *e = buf + size;
char *p = buf;
sec = ds->elapsed / (1000 * 1000 * 1000ULL);
if (sec < 1)
@@ -2532,36 +910,13 @@
P("Master cpu_seqid,%d\n", CPU->cpu_seqid);
P("Master cpu_id,%d\n", CPU->cpu_id);
P("dump_flags,0x%x\n", dumphdr->dump_flags);
P("dump_ioerr,%d\n", dump_ioerr);
- P("Helpers:\n");
- for (i = 0; i < ncpus; i++) {
- if ((i & 15) == 0)
- P(",,%03d,", i);
- if (i == myid)
- P(" M");
- else if (BT_TEST(cfg->helpermap, i))
- P("%4d", cpu_seq[i]->cpu_id);
- else
- P(" *");
- if ((i & 15) == 15)
- P("\n");
- }
-
- P("ncbuf_used,%d\n", cfg->ncbuf_used);
- P("ncmap,%d\n", cfg->ncmap);
-
- P("Found %ldM ranges,%ld\n", (CBUF_MAPSIZE / DUMP_1MB), cfg->found4m);
- P("Found small pages,%ld\n", cfg->foundsm);
-
- P("Compression level,%d\n", cfg->clevel);
- P("Compression type,%s %s\n", cfg->clevel == 0 ? "serial" : "parallel",
- cfg->clevel >= DUMP_CLEVEL_BZIP2 ? "bzip2" : "lzjb");
+ P("Compression type,serial lzjb\n");
P("Compression ratio,%d.%02d\n", compress_ratio / 100, compress_ratio %
100);
- P("nhelper_used,%d\n", cfg->nhelper_used);
P("Dump I/O rate MBS,%d.%02d\n", iorate / 100, iorate % 100);
P("..total bytes,%lld\n", (u_longlong_t)ds->nwrite);
P("..total nsec,%lld\n", (u_longlong_t)ds->iotime);
P("dumpbuf.iosize,%ld\n", dumpbuf.iosize);
@@ -2575,26 +930,17 @@
P("per-cent map utilization,%d\n", (int)((100 * ds->pages_used)
/ ds->pages_mapped));
P("\nPer-page metrics:\n");
if (ds->npages > 0) {
- for (hp = cfg->helper; hp != hpend; hp++) {
-#define PERPAGE(x) ds->perpage.x += hp->perpage.x;
+#define PERPAGE(x) ds->perpage.x += cfg->perpage.x;
PERPAGES;
#undef PERPAGE
- }
#define PERPAGE(x) \
P("%s nsec/page,%d\n", #x, (int)(ds->perpage.x / ds->npages));
PERPAGES;
#undef PERPAGE
- P("freebufq.empty,%d\n", (int)(ds->freebufq.empty /
- ds->npages));
- P("helperq.empty,%d\n", (int)(ds->helperq.empty /
- ds->npages));
- P("writerq.empty,%d\n", (int)(ds->writerq.empty /
- ds->npages));
- P("mainq.empty,%d\n", (int)(ds->mainq.empty / ds->npages));
P("I/O wait nsec/page,%llu\n", (u_longlong_t)(ds->iowait /
ds->npages));
}
#undef P
@@ -2609,39 +955,29 @@
*/
void
dumpsys(void)
{
dumpsync_t *ds = &dumpsync;
- taskq_t *livetaskq = NULL;
pfn_t pfn;
pgcnt_t bitnum;
proc_t *p;
- helper_t *hp, *hpend = &dumpcfg.helper[dumpcfg.nhelper];
- cbuf_t *cp;
pid_t npids, pidx;
char *content;
char *buf;
size_t size;
- int save_dump_clevel;
dumpmlw_t mlw;
dumpcsize_t datatag;
dumpdatahdr_t datahdr;
if (dumpvp == NULL || dumphdr == NULL) {
uprintf("skipping system dump - no dump device configured\n");
- if (panicstr) {
- dumpcfg.helpers_wanted = 0;
- dumpsys_spinunlock(&dumpcfg.helper_lock);
- }
return;
}
dumpbuf.cur = dumpbuf.start;
/* clear the sync variables */
- ASSERT(dumpcfg.nhelper > 0);
bzero(ds, sizeof (*ds));
- ds->dumpcpu = CPU->cpu_id;
/*
* Calculate the starting block for dump. If we're dumping on a
* swap device, start 1/5 of the way in; otherwise, start at the
* beginning. And never use the first page -- it may be a disk label.
@@ -2810,98 +1146,82 @@
dump_plat_pfn();
/*
* Write out all the pages.
* Map pages, copy them handling UEs, compress, and write them out.
- * Cooperate with any helpers running on CPUs in panic_idle().
*/
dumphdr->dump_data = dumpvp_flush();
- bzero(dumpcfg.helpermap, BT_SIZEOFMAP(NCPU));
- ds->live = dumpcfg.clevel > 0 &&
- (dumphdr->dump_flags & DF_LIVE) != 0;
+ ASSERT(dumpcfg.page);
+ bzero(&dumpcfg.perpage, sizeof (dumpcfg.perpage));
- save_dump_clevel = dumpcfg.clevel;
+ ds->start = gethrtime();
+ ds->iowaitts = ds->start;
+
if (panicstr)
- dumpsys_get_maxmem();
- else if (dumpcfg.clevel >= DUMP_CLEVEL_BZIP2)
- dumpcfg.clevel = DUMP_CLEVEL_LZJB;
+ kmem_dump_begin();
- dumpcfg.nhelper_used = 0;
- for (hp = dumpcfg.helper; hp != hpend; hp++) {
- if (hp->page == NULL) {
- hp->helper = DONEHELPER;
+ dump_init_memlist_walker(&mlw);
+ for (bitnum = 0; bitnum < dumpcfg.bitmapsize; bitnum++) {
+ size_t csize;
+
+ dump_timeleft = dump_timeout;
+ HRSTART(ds->perpage, bitmap);
+ if (!BT_TEST(dumpcfg.bitmap, bitnum)) {
+ HRSTOP(ds->perpage, bitmap);
continue;
}
- ++dumpcfg.nhelper_used;
- hp->helper = FREEHELPER;
- hp->taskqid = NULL;
- hp->ds = ds;
- bzero(&hp->perpage, sizeof (hp->perpage));
- if (dumpcfg.clevel >= DUMP_CLEVEL_BZIP2)
- (void) BZ2_bzCompressReset(&hp->bzstream);
- }
+ HRSTOP(ds->perpage, bitmap);
- CQ_OPEN(freebufq);
- CQ_OPEN(helperq);
+ pfn = dump_bitnum_to_pfn(bitnum, &mlw);
+ ASSERT(pfn != PFN_INVALID);
- dumpcfg.ncbuf_used = 0;
- for (cp = dumpcfg.cbuf; cp != &dumpcfg.cbuf[dumpcfg.ncbuf]; cp++) {
- if (cp->buf != NULL) {
- CQ_PUT(freebufq, cp, CBUF_FREEBUF);
- ++dumpcfg.ncbuf_used;
- }
- }
+ HRSTART(ds->perpage, map);
+ hat_devload(kas.a_hat, dumpcfg.cmap, PAGESIZE, pfn, PROT_READ,
+ HAT_LOAD_NOCONSIST);
+ HRSTOP(ds->perpage, map);
- for (cp = dumpcfg.cmap; cp != &dumpcfg.cmap[dumpcfg.ncmap]; cp++)
- CQ_PUT(mainq, cp, CBUF_FREEMAP);
+ dump_pagecopy(dumpcfg.cmap, dumpcfg.page);
- ds->start = gethrtime();
- ds->iowaitts = ds->start;
+ HRSTART(ds->perpage, unmap);
+ hat_unload(kas.a_hat, dumpcfg.cmap, PAGESIZE, HAT_UNLOAD);
+ HRSTOP(ds->perpage, unmap);
- /* start helpers */
- if (ds->live) {
- int n = dumpcfg.nhelper_used;
- int pri = MINCLSYSPRI - 25;
+ HRSTART(dumpcfg.perpage, compress);
+ csize = compress(dumpcfg.page, dumpcfg.lzbuf, PAGESIZE);
+ HRSTOP(dumpcfg.perpage, compress);
- livetaskq = taskq_create("LiveDump", n, pri, n, n,
- TASKQ_PREPOPULATE);
- for (hp = dumpcfg.helper; hp != hpend; hp++) {
- if (hp->page == NULL)
- continue;
- hp->helper = hp - dumpcfg.helper;
- hp->taskqid = taskq_dispatch(livetaskq,
- dumpsys_live_helper, (void *)hp, TQ_NOSLEEP);
+ HRSTART(dumpcfg.perpage, write);
+ dumpvp_write(&csize, sizeof (csize));
+ dumpvp_write(dumpcfg.lzbuf, csize);
+ HRSTOP(dumpcfg.perpage, write);
+
+ if (dump_ioerr) {
+ dumphdr->dump_flags &= ~DF_COMPLETE;
+ dumphdr->dump_npages = ds->npages;
+ break;
}
+ if (++ds->npages * 100LL / dumphdr->dump_npages > ds->percent_done) {
+ int sec;
- } else {
- if (panicstr)
- kmem_dump_begin();
- dumpcfg.helpers_wanted = dumpcfg.clevel > 0;
- dumpsys_spinunlock(&dumpcfg.helper_lock);
+ sec = (gethrtime() - ds->start) / 1000 / 1000 / 1000;
+ uprintf("^\r%2d:%02d %3d%% done", sec / 60, sec % 60,
+ ++ds->percent_done);
+ if (!panicstr)
+ delay(1); /* let the output be sent */
}
+ }
- /* run main task */
- dumpsys_main_task(ds);
-
ds->elapsed = gethrtime() - ds->start;
if (ds->elapsed < 1)
ds->elapsed = 1;
- if (livetaskq != NULL)
- taskq_destroy(livetaskq);
-
- if (ds->neednl) {
- uprintf("\n");
- ds->neednl = 0;
- }
-
/* record actual pages dumped */
dumphdr->dump_npages = ds->npages;
/* platform-specific data */
- dumphdr->dump_npages += dump_plat_data(dumpcfg.cbuf[0].buf);
+ dumphdr->dump_npages += dump_plat_data(dumpcfg.page);
/* note any errors by clearing DF_COMPLETE */
if (dump_ioerr || ds->npages < dumphdr->dump_npages)
dumphdr->dump_flags &= ~DF_COMPLETE;
@@ -2910,12 +1230,12 @@
dumpvp_write(&datatag, sizeof (datatag));
bzero(&datahdr, sizeof (datahdr));
/* buffer for metrics */
- buf = dumpcfg.cbuf[0].buf;
- size = MIN(dumpcfg.cbuf[0].size, DUMP_OFFSET - sizeof (dumphdr_t) -
+ buf = dumpcfg.page;
+ size = MIN(PAGESIZE, DUMP_OFFSET - sizeof (dumphdr_t) -
sizeof (dumpdatahdr_t));
/* finish the kmem intercepts, collect kmem verbose info */
if (panicstr) {
datahdr.dump_metrics = kmem_dump_finish(buf, size);
@@ -2928,14 +1248,14 @@
dumphdr->dump_fm_panic = is_fm_panic();
/* compression info in data header */
datahdr.dump_datahdr_magic = DUMP_DATAHDR_MAGIC;
datahdr.dump_datahdr_version = DUMP_DATAHDR_VERSION;
- datahdr.dump_maxcsize = CBUF_SIZE;
- datahdr.dump_maxrange = CBUF_MAPSIZE / PAGESIZE;
- datahdr.dump_nstreams = dumpcfg.nhelper_used;
- datahdr.dump_clevel = dumpcfg.clevel;
+ datahdr.dump_maxcsize = PAGESIZE;
+ datahdr.dump_maxrange = 1;
+ datahdr.dump_nstreams = 1;
+ datahdr.dump_clevel = 0;
#ifdef COLLECT_METRICS
if (dump_metrics_on)
datahdr.dump_metrics += dumpsys_metrics(ds, buf, size);
#endif
datahdr.dump_data_csize = dumpvp_flush() - dumphdr->dump_data;
@@ -2949,11 +1269,11 @@
dumpbuf.vp_limit = dumpvp_size;
dumpbuf.vp_off = dumpbuf.vp_limit - DUMP_OFFSET;
dumpvp_write(dumphdr, sizeof (dumphdr_t));
dumpvp_write(&datahdr, sizeof (dumpdatahdr_t));
- dumpvp_write(dumpcfg.cbuf[0].buf, datahdr.dump_metrics);
+ dumpvp_write(dumpcfg.page, datahdr.dump_metrics);
(void) dumpvp_flush();
uprintf("\r%3d%% done: %llu pages dumped, ",
ds->percent_done, (u_longlong_t)ds->npages);
@@ -2982,12 +1302,10 @@
dump_timeleft = 0;
dump_ioerr = 0;
/* restore settings after live dump completes */
if (!panicstr) {
- dumpcfg.clevel = save_dump_clevel;
-
/* release any VCHR open of the dump device */
if (dumpbuf.cdev_vp != NULL) {
(void) VOP_CLOSE(dumpbuf.cdev_vp, FREAD | FWRITE, 1, 0,
kcred, NULL);
VN_RELE(dumpbuf.cdev_vp);