Print this page
NEX-18463 Parallel dump produces corrupted dump file
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-17845 Remove support for BZIP2 from dump
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-17857 Parallel dump threshold (dump_ncpu_low) is not applied
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-17501 Enable parallel crash dump
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-17762 After a live dump (savecore -L) a subsequent panic will be saved in wrong directory
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Alexander Eremin <alexander.eremin@nexenta.com>
NEX-17182 Parallel dump hangs (fix typo)
Reviewed by: Jean McCormack <jean.mccormack@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-17182 Parallel dump hangs
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-9338 improve the layout of the crash directory (use sys/uuid.h)
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-9338 improve the layout of the crash directory
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Steve Peng <steve.peng@nexenta.com>
NEX-5164 backport illumos 6514 AS_* lock macros simplification
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
6514 AS_* lock macros simplification
Reviewed by: Piotr Jasiukajtis <estibi@me.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Albert Lee <trisk@omniti.com>
Approved by: Dan McDonald <danmcd@omniti.com>
*** 20,29 ****
--- 20,30 ----
*/
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2016 Joyent, Inc.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
*** 69,100 ****
#include <vm/pvn.h>
#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
*/
--- 70,88 ----
#include <vm/pvn.h>
#include <vm/seg.h>
#include <vm/seg_kmem.h>
#include <sys/clock_impl.h>
#include <sys/hold_page.h>
+ #include <sys/cpu.h>
! #include <sys/uuid.h>
/*
! * Parallel Dump:
! * CPUs that are otherwise idle during panic are employed to parallelize
! * the compression task. I/O and compression are performed by different
! * CPUs, and are hence overlapped in time, unlike the older serial code.
*/
/*
* exported vars
*/
*** 109,153 ****
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.
*
! * 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.
*
--- 97,129 ----
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.
*
! * dump_ncpu_low:
! * This is the minimum configuration for parallel lzjb.
! * A special value of 0 means that parallel dump will not be used.
*
! * 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 */
/* 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 (MAX(dump_ncpu_low, 1))
#define MINCBUFS (MINHELPERS * NCBUF_PER_HELPER)
/*
* Define constant parameters.
*
*** 258,268 ****
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'))
--- 234,244 ----
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[UUID_PRINTABLE_STRING_LENGTH];
#define isdigit(ch) ((ch) >= '0' && (ch) <= '9')
#define isxdigit(ch) (isdigit(ch) || ((ch) >= 'a' && (ch) <= 'f') || \
((ch) >= 'A' && (ch) <= 'F'))
*** 378,388 ****
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 */
--- 354,363 ----
*** 389,399 ****
/*
* 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 */
--- 364,373 ----
*** 436,445 ****
--- 410,427 ----
} dumpbuf_t;
dumpbuf_t dumpbuf; /* I/O buffer */
/*
+ * DUMP_HELPER_MAX_WAIT
+ * For parallel dump, defines maximum time main task thread will wait
+ * for at least one helper to register in dumpcfg.helpermap, before
+ * assuming there are no helpers and falling back to serial mode.
+ */
+ #define DUMP_HELPER_MAX_WAIT 1000 /* millisec */
+
+ /*
* The dump I/O buffer must be at least one page, at most xfer_size
* bytes, and should scale with physmem in between. The transfer size
* passed in will either represent a global default (maxphys) or the
* best size for the device. The size of the dumpbuf I/O buffer is
* limited by dumpbuf_limit (8MB by default) because the dump
*** 487,496 ****
--- 469,481 ----
kmem_free(old_buf, old_size);
}
/*
* dump_update_clevel is called when dumpadm configures the dump device.
+ * Determine the compression level / type
+ * - DUMP_CLEVEL_SERIAL is single threaded lzjb
+ * - DUMP_CLEVEL_LZJB is parallel lzjb
* 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
*** 499,535 ****
* 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
- *
- * 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
--- 484,493 ----
*** 541,551 ****
*/
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;
--- 499,508 ----
*** 594,637 ****
new->nhelper = 1;
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);
--- 551,576 ----
new->nhelper = 1;
if (new->nhelper > DUMP_MAX_NHELPER)
new->nhelper = DUMP_MAX_NHELPER;
! /* If dump_ncpu_low is 0 or greater than ncpus, do serial dump */
! if (dump_ncpu_low == 0 || dump_ncpu_low > ncpus || new->nhelper < 2) {
! new->clevel = DUMP_CLEVEL_SERIAL;
new->nhelper = 1;
new->ncbuf = 1;
new->ncmap = 1;
} else {
+ new->clevel = DUMP_CLEVEL_LZJB;
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.
*/
new->maxsize = 0;
new->maxvmsize = 0;
new->maxvm = NULL;
tag = 1;
new->helper = kmem_zalloc(new->nhelper * sizeof (helper_t), KM_SLEEP);
*** 639,655 ****
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++) {
--- 578,590 ----
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 {
! new->maxsize += 2 * PAGESIZE;
}
}
new->cbuf = kmem_zalloc(new->ncbuf * sizeof (cbuf_t), KM_SLEEP);
cpend = &new->cbuf[new->ncbuf];
for (cp = new->cbuf; cp != cpend; cp++) {
*** 798,832 ****
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.
*/
--- 733,742 ----
*** 861,873 ****
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()
--- 771,781 ----
return (1);
}
/*
* dumpsys_get_maxmem() is called during panic. Find unused ranges
! * and use them for buffers.
* 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()
*** 874,908 ****
{
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;
--- 782,813 ----
{
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;
pfn_t pfn, off;
cbuf_t *cp;
! helper_t *hp;
dumpmlw_t mlw;
int k;
/*
! * Setting dump_ncpu_low to 0 forces a single threaded dump.
*/
! if (dump_ncpu_low == 0) {
! cfg->clevel = DUMP_CLEVEL_SERIAL;
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_SERIAL ||
(dump_conflags & DUMP_ALL) != 0) {
return;
}
sz = 0;
cfg->found4m = 0;
*** 982,1041 ****
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.
--- 887,919 ----
*** 1046,1075 ****
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;
--- 924,934 ----
*** 1908,1919 ****
/*
* 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;
}
}
--- 1767,1777 ----
/*
* Done with the input. Flush the VM and
* return the buffer to the main task.
*/
if (panicstr && hp->helper != MAINHELPER)
! hat_flush();
dumpsys_errmsg(hp, NULL);
CQ_PUT(mainq, hp->cpin, CBUF_USEDMAP);
hp->cpin = NULL;
}
}
*** 1920,2059 ****
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
--- 1778,1787 ----
*** 2191,2208 ****
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;
}
}
--- 1919,1930 ----
*** 2235,2248 ****
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)
*/
--- 1957,1967 ----
*** 2285,2317 ****
pgcnt_t pagenum = 0, bitnum = 0, hibitnum;
dumpmlw_t mlw;
cbuf_t *cp;
pgcnt_t baseoff, pfnoff;
pfn_t base, pfn;
! int 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);
for (;;) {
int sec = (gethrtime() - ds->start) / NANOSEC;
--- 2004,2052 ----
pgcnt_t pagenum = 0, bitnum = 0, hibitnum;
dumpmlw_t mlw;
cbuf_t *cp;
pgcnt_t baseoff, pfnoff;
pfn_t base, pfn;
! int i;
/*
* Fall back to serial mode if there are no helpers.
! * dump_ncpu_low can be set to 0 at any time.
* dumpcfg.helpermap must contain at least one member.
+ *
+ * It is possible that the helpers haven't registered
+ * in helpermap yet; wait up to DUMP_HELPER_MAX_WAIT.
*/
! if (dump_ncpu_low != 0 && dumpcfg.clevel != DUMP_CLEVEL_SERIAL) {
! boolean_t dumpserial = B_TRUE;
! hrtime_t hrtmax = MSEC2NSEC(DUMP_HELPER_MAX_WAIT);
! hrtime_t hrtstart = gethrtime();
! for (;;) {
for (i = 0; i < BT_BITOUL(NCPU); ++i) {
if (dumpcfg.helpermap[i] != 0) {
! dumpserial = B_FALSE;
break;
}
}
+
+ if ((!dumpserial) ||
+ ((gethrtime() - hrtstart) >= hrtmax)) {
+ break;
}
+ ht_pause();
+ }
+
if (dumpserial) {
! dumpcfg.clevel = DUMP_CLEVEL_SERIAL;
! if (dumpcfg.helper[0].lzbuf == NULL) {
! dumpcfg.helper[0].lzbuf =
! dumpcfg.helper[1].page;
}
+ }
+ }
dump_init_memlist_walker(&mlw);
for (;;) {
int sec = (gethrtime() - ds->start) / NANOSEC;
*** 2449,2465 ****
/*
* 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);
--- 2184,2199 ----
/*
* If there are no helpers the main task does
* non-streams lzjb compress.
*/
! if (dumpcfg.clevel == DUMP_CLEVEL_SERIAL) {
dumpsys_lzjb_page(dumpcfg.helper, cp);
! } else {
/* pass mapped pages to a helper */
CQ_PUT(helperq, cp, CBUF_INREADY);
+ }
/* the last page was done */
if (bitnum >= dumpcfg.bitmapsize)
CQ_CLOSE(helperq);
*** 2561,2572 ****
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 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);
--- 2295,2306 ----
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 lzjb\n",
! cfg->clevel == DUMP_CLEVEL_SERIAL ? "serial" : "parallel");
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);
*** 2670,2680 ****
dumphdr->dump_flags &= ~DF_LIVE;
(void) VOP_DUMPCTL(dumpvp, DUMP_FREE, NULL, NULL);
(void) VOP_DUMPCTL(dumpvp, DUMP_ALLOC, NULL, NULL);
(void) vsnprintf(dumphdr->dump_panicstring, DUMP_PANICSIZE,
panicstr, panicargs);
!
}
if (dump_conflags & DUMP_ALL)
content = "all";
else if (dump_conflags & DUMP_CURPROC)
--- 2404,2415 ----
dumphdr->dump_flags &= ~DF_LIVE;
(void) VOP_DUMPCTL(dumpvp, DUMP_FREE, NULL, NULL);
(void) VOP_DUMPCTL(dumpvp, DUMP_ALLOC, NULL, NULL);
(void) vsnprintf(dumphdr->dump_panicstring, DUMP_PANICSIZE,
panicstr, panicargs);
! (void) strncpy(dumphdr->dump_uuid, dump_get_uuid(),
! sizeof (dumphdr->dump_uuid));
}
if (dump_conflags & DUMP_ALL)
content = "all";
else if (dump_conflags & DUMP_CURPROC)
*** 2715,2729 ****
* Store a hires timestamp so we can look it up during debugging.
*/
lbolt_debug_entry();
/*
! * Leave room for the message and ereport save areas and terminal dump
! * header.
*/
dumpbuf.vp_limit = dumpvp_size - DUMP_LOGSIZE - DUMP_OFFSET -
! DUMP_ERPTSIZE;
/*
* Write out the symbol table. It's no longer compressed,
* so its 'size' and 'csize' are equal.
*/
--- 2450,2464 ----
* Store a hires timestamp so we can look it up during debugging.
*/
lbolt_debug_entry();
/*
! * Leave room for the summary, message and ereport save areas
! * and terminal dump header.
*/
dumpbuf.vp_limit = dumpvp_size - DUMP_LOGSIZE - DUMP_OFFSET -
! DUMP_ERPTSIZE - DUMP_SUMMARYSIZE;
/*
* Write out the symbol table. It's no longer compressed,
* so its 'size' and 'csize' are equal.
*/
*** 2823,2840 ****
* 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;
save_dump_clevel = dumpcfg.clevel;
if (panicstr)
dumpsys_get_maxmem();
- else if (dumpcfg.clevel >= DUMP_CLEVEL_BZIP2)
- dumpcfg.clevel = DUMP_CLEVEL_LZJB;
dumpcfg.nhelper_used = 0;
for (hp = dumpcfg.helper; hp != hpend; hp++) {
if (hp->page == NULL) {
hp->helper = DONEHELPER;
--- 2558,2573 ----
* 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 > DUMP_CLEVEL_SERIAL &&
(dumphdr->dump_flags & DF_LIVE) != 0;
save_dump_clevel = dumpcfg.clevel;
if (panicstr)
dumpsys_get_maxmem();
dumpcfg.nhelper_used = 0;
for (hp = dumpcfg.helper; hp != hpend; hp++) {
if (hp->page == NULL) {
hp->helper = DONEHELPER;
*** 2843,2854 ****
++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);
}
CQ_OPEN(freebufq);
CQ_OPEN(helperq);
--- 2576,2585 ----
*** 2882,2892 ****
}
} else {
if (panicstr)
kmem_dump_begin();
! dumpcfg.helpers_wanted = dumpcfg.clevel > 0;
dumpsys_spinunlock(&dumpcfg.helper_lock);
}
/* run main task */
dumpsys_main_task(ds);
--- 2613,2623 ----
}
} else {
if (panicstr)
kmem_dump_begin();
! dumpcfg.helpers_wanted = dumpcfg.clevel > DUMP_CLEVEL_SERIAL;
dumpsys_spinunlock(&dumpcfg.helper_lock);
}
/* run main task */
dumpsys_main_task(ds);
*** 3043,3063 ****
dumpvp_size = vattr.va_size & -DUMP_OFFSET;
mutex_exit(&dump_lock);
return (0);
}
! int
! dump_set_uuid(const char *uuidstr)
{
const char *ptr;
int i;
! if (uuidstr == NULL || strnlen(uuidstr, 36 + 1) != 36)
return (EINVAL);
/* uuid_parse is not common code so check manually */
! for (i = 0, ptr = uuidstr; i < 36; i++, ptr++) {
switch (i) {
case 8:
case 13:
case 18:
case 23:
--- 2774,2796 ----
dumpvp_size = vattr.va_size & -DUMP_OFFSET;
mutex_exit(&dump_lock);
return (0);
}
! static int
! dump_validate_uuid(const char *uuidstr)
{
const char *ptr;
int i;
! if (uuidstr == NULL || strlen(uuidstr) !=
! UUID_PRINTABLE_STRING_LENGTH - 1)
return (EINVAL);
/* uuid_parse is not common code so check manually */
! for (i = 0, ptr = uuidstr; i < UUID_PRINTABLE_STRING_LENGTH - 1;
! i++, ptr++) {
switch (i) {
case 8:
case 13:
case 18:
case 23:
*** 3070,3083 ****
return (EINVAL);
break;
}
}
if (dump_osimage_uuid[0] != '\0')
return (EALREADY);
! (void) strncpy(dump_osimage_uuid, uuidstr, 36 + 1);
cmn_err(CE_CONT, "?This Solaris instance has UUID %s\n",
dump_osimage_uuid);
return (0);
--- 2803,2840 ----
return (EINVAL);
break;
}
}
+ return (0);
+ }
+
+ int
+ dump_update_uuid(const char *uuidstr)
+ {
+
+ if (dump_validate_uuid(uuidstr) != 0 || dumphdr == NULL)
+ return (EINVAL);
+
+ bzero(dumphdr->dump_uuid, sizeof (dumphdr->dump_uuid));
+ (void) strncpy(dumphdr->dump_uuid, uuidstr,
+ sizeof (dumphdr->dump_uuid));
+
+ return (0);
+ }
+
+ int
+ dump_set_uuid(const char *uuidstr)
+ {
+ if (dump_validate_uuid(uuidstr) != 0)
+ return (EINVAL);
+
if (dump_osimage_uuid[0] != '\0')
return (EALREADY);
! (void) strncpy(dump_osimage_uuid, uuidstr,
! UUID_PRINTABLE_STRING_LENGTH);
cmn_err(CE_CONT, "?This Solaris instance has UUID %s\n",
dump_osimage_uuid);
return (0);