Changeset View
Changeset View
Standalone View
Standalone View
head/sys/kern/kern_shutdown.c
Show All 35 Lines | |||||
* @(#)kern_shutdown.c 8.3 (Berkeley) 1/21/94 | * @(#)kern_shutdown.c 8.3 (Berkeley) 1/21/94 | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include "opt_ddb.h" | #include "opt_ddb.h" | ||||
#include "opt_ekcd.h" | #include "opt_ekcd.h" | ||||
#include "opt_gzio.h" | |||||
#include "opt_kdb.h" | #include "opt_kdb.h" | ||||
#include "opt_panic.h" | #include "opt_panic.h" | ||||
#include "opt_sched.h" | #include "opt_sched.h" | ||||
#include "opt_watchdog.h" | #include "opt_watchdog.h" | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/bio.h> | #include <sys/bio.h> | ||||
#include <sys/buf.h> | #include <sys/buf.h> | ||||
#include <sys/conf.h> | #include <sys/conf.h> | ||||
#include <sys/compressor.h> | |||||
#include <sys/cons.h> | #include <sys/cons.h> | ||||
#include <sys/eventhandler.h> | #include <sys/eventhandler.h> | ||||
#include <sys/filedesc.h> | #include <sys/filedesc.h> | ||||
#include <sys/gzio.h> | |||||
#include <sys/jail.h> | #include <sys/jail.h> | ||||
#include <sys/kdb.h> | #include <sys/kdb.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/kerneldump.h> | #include <sys/kerneldump.h> | ||||
#include <sys/kthread.h> | #include <sys/kthread.h> | ||||
#include <sys/ktr.h> | #include <sys/ktr.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/mount.h> | #include <sys/mount.h> | ||||
▲ Show 20 Lines • Show All 102 Lines • ▼ Show 20 Lines | struct kerneldumpcrypto { | ||||
uint8_t kdc_iv[KERNELDUMP_IV_MAX_SIZE]; | uint8_t kdc_iv[KERNELDUMP_IV_MAX_SIZE]; | ||||
keyInstance kdc_ki; | keyInstance kdc_ki; | ||||
cipherInstance kdc_ci; | cipherInstance kdc_ci; | ||||
uint32_t kdc_dumpkeysize; | uint32_t kdc_dumpkeysize; | ||||
struct kerneldumpkey kdc_dumpkey[]; | struct kerneldumpkey kdc_dumpkey[]; | ||||
}; | }; | ||||
#endif | #endif | ||||
#ifdef GZIO | struct kerneldumpcomp { | ||||
struct kerneldumpgz { | struct compressor *kdc_stream; | ||||
struct gzio_stream *kdgz_stream; | uint8_t *kdc_buf; | ||||
uint8_t *kdgz_buf; | size_t kdc_resid; | ||||
size_t kdgz_resid; | |||||
}; | }; | ||||
static struct kerneldumpgz *kerneldumpgz_create(struct dumperinfo *di, | static struct kerneldumpcomp *kerneldumpcomp_create(struct dumperinfo *di, | ||||
uint8_t compression); | uint8_t compression); | ||||
static void kerneldumpgz_destroy(struct dumperinfo *di); | static void kerneldumpcomp_destroy(struct dumperinfo *di); | ||||
static int kerneldumpgz_write_cb(void *cb, size_t len, off_t off, void *arg); | static int kerneldumpcomp_write_cb(void *base, size_t len, off_t off, void *arg); | ||||
static int kerneldump_gzlevel = 6; | static int kerneldump_gzlevel = 6; | ||||
SYSCTL_INT(_kern, OID_AUTO, kerneldump_gzlevel, CTLFLAG_RWTUN, | SYSCTL_INT(_kern, OID_AUTO, kerneldump_gzlevel, CTLFLAG_RWTUN, | ||||
&kerneldump_gzlevel, 0, | &kerneldump_gzlevel, 0, | ||||
"Kernel crash dump gzip compression level"); | "Kernel crash dump compression level"); | ||||
#endif /* GZIO */ | |||||
/* | /* | ||||
* Variable panicstr contains argument to first call to panic; used as flag | * Variable panicstr contains argument to first call to panic; used as flag | ||||
* to indicate that the kernel has already called panic. | * to indicate that the kernel has already called panic. | ||||
*/ | */ | ||||
const char *panicstr; | const char *panicstr; | ||||
int dumping; /* system is dumping */ | int dumping; /* system is dumping */ | ||||
▲ Show 20 Lines • Show All 779 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
if (kdc == NULL) | if (kdc == NULL) | ||||
return (0); | return (0); | ||||
return (kdc->kdc_dumpkeysize); | return (kdc->kdc_dumpkeysize); | ||||
} | } | ||||
#endif /* EKCD */ | #endif /* EKCD */ | ||||
#ifdef GZIO | static struct kerneldumpcomp * | ||||
static struct kerneldumpgz * | kerneldumpcomp_create(struct dumperinfo *di, uint8_t compression) | ||||
kerneldumpgz_create(struct dumperinfo *di, uint8_t compression) | |||||
{ | { | ||||
struct kerneldumpgz *kdgz; | struct kerneldumpcomp *kdcomp; | ||||
if (compression != KERNELDUMP_COMP_GZIP) | if (compression != KERNELDUMP_COMP_GZIP) | ||||
return (NULL); | return (NULL); | ||||
kdgz = malloc(sizeof(*kdgz), M_DUMPER, M_WAITOK | M_ZERO); | kdcomp = malloc(sizeof(*kdcomp), M_DUMPER, M_WAITOK | M_ZERO); | ||||
kdgz->kdgz_stream = gzio_init(kerneldumpgz_write_cb, GZIO_DEFLATE, | kdcomp->kdc_stream = compressor_init(kerneldumpcomp_write_cb, | ||||
di->maxiosize, kerneldump_gzlevel, di); | COMPRESS_GZIP, di->maxiosize, kerneldump_gzlevel, di); | ||||
if (kdgz->kdgz_stream == NULL) { | if (kdcomp->kdc_stream == NULL) { | ||||
free(kdgz, M_DUMPER); | free(kdcomp, M_DUMPER); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
kdgz->kdgz_buf = malloc(di->maxiosize, M_DUMPER, M_WAITOK | M_NODUMP); | kdcomp->kdc_buf = malloc(di->maxiosize, M_DUMPER, M_WAITOK | M_NODUMP); | ||||
return (kdgz); | return (kdcomp); | ||||
} | } | ||||
static void | static void | ||||
kerneldumpgz_destroy(struct dumperinfo *di) | kerneldumpcomp_destroy(struct dumperinfo *di) | ||||
{ | { | ||||
struct kerneldumpgz *kdgz; | struct kerneldumpcomp *kdcomp; | ||||
kdgz = di->kdgz; | kdcomp = di->kdcomp; | ||||
if (kdgz == NULL) | if (kdcomp == NULL) | ||||
return; | return; | ||||
gzio_fini(kdgz->kdgz_stream); | compressor_fini(kdcomp->kdc_stream); | ||||
explicit_bzero(kdgz->kdgz_buf, di->maxiosize); | explicit_bzero(kdcomp->kdc_buf, di->maxiosize); | ||||
free(kdgz->kdgz_buf, M_DUMPER); | free(kdcomp->kdc_buf, M_DUMPER); | ||||
free(kdgz, M_DUMPER); | free(kdcomp, M_DUMPER); | ||||
} | } | ||||
#endif /* GZIO */ | |||||
/* Registration of dumpers */ | /* Registration of dumpers */ | ||||
int | int | ||||
set_dumper(struct dumperinfo *di, const char *devname, struct thread *td, | set_dumper(struct dumperinfo *di, const char *devname, struct thread *td, | ||||
uint8_t compression, uint8_t encryption, const uint8_t *key, | uint8_t compression, uint8_t encryption, const uint8_t *key, | ||||
uint32_t encryptedkeysize, const uint8_t *encryptedkey) | uint32_t encryptedkeysize, const uint8_t *encryptedkey) | ||||
{ | { | ||||
size_t wantcopy; | size_t wantcopy; | ||||
int error; | int error; | ||||
error = priv_check(td, PRIV_SETDUMPER); | error = priv_check(td, PRIV_SETDUMPER); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
if (di == NULL) { | if (di == NULL) { | ||||
error = 0; | error = 0; | ||||
goto cleanup; | goto cleanup; | ||||
} | } | ||||
if (dumper.dumper != NULL) | if (dumper.dumper != NULL) | ||||
return (EBUSY); | return (EBUSY); | ||||
dumper = *di; | dumper = *di; | ||||
dumper.blockbuf = NULL; | dumper.blockbuf = NULL; | ||||
dumper.kdc = NULL; | dumper.kdcrypto = NULL; | ||||
dumper.kdgz = NULL; | dumper.kdcomp = NULL; | ||||
if (encryption != KERNELDUMP_ENC_NONE) { | if (encryption != KERNELDUMP_ENC_NONE) { | ||||
#ifdef EKCD | #ifdef EKCD | ||||
dumper.kdc = kerneldumpcrypto_create(di->blocksize, encryption, | dumper.kdcrypto = kerneldumpcrypto_create(di->blocksize, | ||||
key, encryptedkeysize, encryptedkey); | encryption, key, encryptedkeysize, encryptedkey); | ||||
if (dumper.kdc == NULL) { | if (dumper.kdcrypto == NULL) { | ||||
error = EINVAL; | error = EINVAL; | ||||
goto cleanup; | goto cleanup; | ||||
} | } | ||||
#else | #else | ||||
error = EOPNOTSUPP; | error = EOPNOTSUPP; | ||||
goto cleanup; | goto cleanup; | ||||
#endif | #endif | ||||
} | } | ||||
wantcopy = strlcpy(dumpdevname, devname, sizeof(dumpdevname)); | wantcopy = strlcpy(dumpdevname, devname, sizeof(dumpdevname)); | ||||
if (wantcopy >= sizeof(dumpdevname)) { | if (wantcopy >= sizeof(dumpdevname)) { | ||||
printf("set_dumper: device name truncated from '%s' -> '%s'\n", | printf("set_dumper: device name truncated from '%s' -> '%s'\n", | ||||
devname, dumpdevname); | devname, dumpdevname); | ||||
} | } | ||||
if (compression != KERNELDUMP_COMP_NONE) { | if (compression != KERNELDUMP_COMP_NONE) { | ||||
#ifdef GZIO | |||||
/* | /* | ||||
* We currently can't support simultaneous encryption and | * We currently can't support simultaneous encryption and | ||||
* compression. | * compression. | ||||
*/ | */ | ||||
if (encryption != KERNELDUMP_ENC_NONE) { | if (encryption != KERNELDUMP_ENC_NONE) { | ||||
error = EOPNOTSUPP; | error = EOPNOTSUPP; | ||||
goto cleanup; | goto cleanup; | ||||
} | } | ||||
dumper.kdgz = kerneldumpgz_create(&dumper, compression); | dumper.kdcomp = kerneldumpcomp_create(&dumper, compression); | ||||
if (dumper.kdgz == NULL) { | if (dumper.kdcomp == NULL) { | ||||
error = EINVAL; | error = EINVAL; | ||||
goto cleanup; | goto cleanup; | ||||
} | } | ||||
#else | |||||
error = EOPNOTSUPP; | |||||
goto cleanup; | |||||
#endif | |||||
} | } | ||||
dumper.blockbuf = malloc(di->blocksize, M_DUMPER, M_WAITOK | M_ZERO); | dumper.blockbuf = malloc(di->blocksize, M_DUMPER, M_WAITOK | M_ZERO); | ||||
return (0); | return (0); | ||||
cleanup: | cleanup: | ||||
#ifdef EKCD | #ifdef EKCD | ||||
if (dumper.kdc != NULL) { | if (dumper.kdcrypto != NULL) { | ||||
explicit_bzero(dumper.kdc, sizeof(*dumper.kdc) + | explicit_bzero(dumper.kdcrypto, sizeof(*dumper.kdcrypto) + | ||||
dumper.kdc->kdc_dumpkeysize); | dumper.kdcrypto->kdc_dumpkeysize); | ||||
free(dumper.kdc, M_EKCD); | free(dumper.kdcrypto, M_EKCD); | ||||
} | } | ||||
#endif | #endif | ||||
#ifdef GZIO | kerneldumpcomp_destroy(&dumper); | ||||
kerneldumpgz_destroy(&dumper); | |||||
#endif | |||||
if (dumper.blockbuf != NULL) { | if (dumper.blockbuf != NULL) { | ||||
explicit_bzero(dumper.blockbuf, dumper.blocksize); | explicit_bzero(dumper.blockbuf, dumper.blocksize); | ||||
free(dumper.blockbuf, M_DUMPER); | free(dumper.blockbuf, M_DUMPER); | ||||
} | } | ||||
explicit_bzero(&dumper, sizeof(dumper)); | explicit_bzero(&dumper, sizeof(dumper)); | ||||
dumpdevname[0] = '\0'; | dumpdevname[0] = '\0'; | ||||
return (error); | return (error); | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | |||||
dump_encrypted_write(struct dumperinfo *di, void *virtual, | dump_encrypted_write(struct dumperinfo *di, void *virtual, | ||||
vm_offset_t physical, off_t offset, size_t length) | vm_offset_t physical, off_t offset, size_t length) | ||||
{ | { | ||||
static uint8_t buf[KERNELDUMP_BUFFER_SIZE]; | static uint8_t buf[KERNELDUMP_BUFFER_SIZE]; | ||||
struct kerneldumpcrypto *kdc; | struct kerneldumpcrypto *kdc; | ||||
int error; | int error; | ||||
size_t nbytes; | size_t nbytes; | ||||
kdc = di->kdc; | kdc = di->kdcrypto; | ||||
while (length > 0) { | while (length > 0) { | ||||
nbytes = MIN(length, sizeof(buf)); | nbytes = MIN(length, sizeof(buf)); | ||||
bcopy(virtual, buf, nbytes); | bcopy(virtual, buf, nbytes); | ||||
if (dump_encrypt(kdc, buf, nbytes) != 0) | if (dump_encrypt(kdc, buf, nbytes) != 0) | ||||
return (EIO); | return (EIO); | ||||
Show All 9 Lines | dump_encrypted_write(struct dumperinfo *di, void *virtual, | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
dump_write_key(struct dumperinfo *di, off_t offset) | dump_write_key(struct dumperinfo *di, off_t offset) | ||||
{ | { | ||||
struct kerneldumpcrypto *kdc; | struct kerneldumpcrypto *kdc; | ||||
kdc = di->kdc; | kdc = di->kdcrypto; | ||||
if (kdc == NULL) | if (kdc == NULL) | ||||
return (0); | return (0); | ||||
return (dump_write(di, kdc->kdc_dumpkey, 0, offset, | return (dump_write(di, kdc->kdc_dumpkey, 0, offset, | ||||
kdc->kdc_dumpkeysize)); | kdc->kdc_dumpkeysize)); | ||||
} | } | ||||
#endif /* EKCD */ | #endif /* EKCD */ | ||||
#ifdef GZIO | |||||
static int | static int | ||||
kerneldumpgz_write_cb(void *base, size_t length, off_t offset, void *arg) | kerneldumpcomp_write_cb(void *base, size_t length, off_t offset, void *arg) | ||||
{ | { | ||||
struct dumperinfo *di; | struct dumperinfo *di; | ||||
size_t resid, rlength; | size_t resid, rlength; | ||||
int error; | int error; | ||||
di = arg; | di = arg; | ||||
if (length % di->blocksize != 0) { | if (length % di->blocksize != 0) { | ||||
/* | /* | ||||
* This must be the final write after flushing the compression | * This must be the final write after flushing the compression | ||||
* stream. Write as many full blocks as possible and stash the | * stream. Write as many full blocks as possible and stash the | ||||
* residual data in the dumper's block buffer. It will be | * residual data in the dumper's block buffer. It will be | ||||
* padded and written in dump_finish(). | * padded and written in dump_finish(). | ||||
*/ | */ | ||||
rlength = rounddown(length, di->blocksize); | rlength = rounddown(length, di->blocksize); | ||||
if (rlength != 0) { | if (rlength != 0) { | ||||
error = _dump_append(di, base, 0, rlength); | error = _dump_append(di, base, 0, rlength); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
} | } | ||||
resid = length - rlength; | resid = length - rlength; | ||||
memmove(di->blockbuf, (uint8_t *)base + rlength, resid); | memmove(di->blockbuf, (uint8_t *)base + rlength, resid); | ||||
di->kdgz->kdgz_resid = resid; | di->kdcomp->kdc_resid = resid; | ||||
return (EAGAIN); | return (EAGAIN); | ||||
} | } | ||||
return (_dump_append(di, base, 0, length)); | return (_dump_append(di, base, 0, length)); | ||||
} | } | ||||
#endif /* GZIO */ | |||||
/* | /* | ||||
* Write a kerneldumpheader at the specified offset. The header structure is 512 | * Write a kerneldumpheader at the specified offset. The header structure is 512 | ||||
* bytes in size, but we must pad to the device sector size. | * bytes in size, but we must pad to the device sector size. | ||||
*/ | */ | ||||
static int | static int | ||||
dump_write_header(struct dumperinfo *di, struct kerneldumpheader *kdh, | dump_write_header(struct dumperinfo *di, struct kerneldumpheader *kdh, | ||||
off_t offset) | off_t offset) | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
int | int | ||||
dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh) | dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh) | ||||
{ | { | ||||
uint64_t dumpextent; | uint64_t dumpextent; | ||||
uint32_t keysize; | uint32_t keysize; | ||||
#ifdef EKCD | #ifdef EKCD | ||||
int error = kerneldumpcrypto_init(di->kdc); | int error = kerneldumpcrypto_init(di->kdcrypto); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
keysize = kerneldumpcrypto_dumpkeysize(di->kdc); | keysize = kerneldumpcrypto_dumpkeysize(di->kdcrypto); | ||||
#else | #else | ||||
keysize = 0; | keysize = 0; | ||||
#endif | #endif | ||||
dumpextent = dtoh64(kdh->dumpextent); | dumpextent = dtoh64(kdh->dumpextent); | ||||
if (di->mediasize < SIZEOF_METADATA + dumpextent + 2 * di->blocksize + | if (di->mediasize < SIZEOF_METADATA + dumpextent + 2 * di->blocksize + | ||||
keysize) { | keysize) { | ||||
#ifdef GZIO | if (di->kdcomp != NULL) { | ||||
if (di->kdgz != NULL) { | |||||
/* | /* | ||||
* We don't yet know how much space the compressed dump | * We don't yet know how much space the compressed dump | ||||
* will occupy, so try to use the whole swap partition | * will occupy, so try to use the whole swap partition | ||||
* (minus the first 64KB) in the hope that the | * (minus the first 64KB) in the hope that the | ||||
* compressed dump will fit. If that doesn't turn out to | * compressed dump will fit. If that doesn't turn out to | ||||
* be enouch, the bounds checking in dump_write() | * be enouch, the bounds checking in dump_write() | ||||
* will catch us and cause the dump to fail. | * will catch us and cause the dump to fail. | ||||
*/ | */ | ||||
dumpextent = di->mediasize - SIZEOF_METADATA - | dumpextent = di->mediasize - SIZEOF_METADATA - | ||||
2 * di->blocksize - keysize; | 2 * di->blocksize - keysize; | ||||
kdh->dumpextent = htod64(dumpextent); | kdh->dumpextent = htod64(dumpextent); | ||||
} else | } else | ||||
#endif | |||||
return (E2BIG); | return (E2BIG); | ||||
} | } | ||||
/* The offset at which to begin writing the dump. */ | /* The offset at which to begin writing the dump. */ | ||||
di->dumpoff = di->mediaoffset + di->mediasize - di->blocksize - | di->dumpoff = di->mediaoffset + di->mediasize - di->blocksize - | ||||
dumpextent; | dumpextent; | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
_dump_append(struct dumperinfo *di, void *virtual, vm_offset_t physical, | _dump_append(struct dumperinfo *di, void *virtual, vm_offset_t physical, | ||||
size_t length) | size_t length) | ||||
{ | { | ||||
int error; | int error; | ||||
#ifdef EKCD | #ifdef EKCD | ||||
if (di->kdc != NULL) | if (di->kdcrypto != NULL) | ||||
error = dump_encrypted_write(di, virtual, physical, di->dumpoff, | error = dump_encrypted_write(di, virtual, physical, di->dumpoff, | ||||
length); | length); | ||||
else | else | ||||
#endif | #endif | ||||
error = dump_write(di, virtual, physical, di->dumpoff, length); | error = dump_write(di, virtual, physical, di->dumpoff, length); | ||||
if (error == 0) | if (error == 0) | ||||
di->dumpoff += length; | di->dumpoff += length; | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Write to the dump device starting at dumpoff. When compression is enabled, | * Write to the dump device starting at dumpoff. When compression is enabled, | ||||
* writes to the device will be performed using a callback that gets invoked | * writes to the device will be performed using a callback that gets invoked | ||||
* when the compression stream's output buffer is full. | * when the compression stream's output buffer is full. | ||||
*/ | */ | ||||
int | int | ||||
dump_append(struct dumperinfo *di, void *virtual, vm_offset_t physical, | dump_append(struct dumperinfo *di, void *virtual, vm_offset_t physical, | ||||
size_t length) | size_t length) | ||||
{ | { | ||||
#ifdef GZIO | |||||
void *buf; | void *buf; | ||||
if (di->kdgz != NULL) { | if (di->kdcomp != NULL) { | ||||
/* Bounce through a buffer to avoid gzip CRC errors. */ | /* Bounce through a buffer to avoid CRC errors. */ | ||||
if (length > di->maxiosize) | if (length > di->maxiosize) | ||||
return (EINVAL); | return (EINVAL); | ||||
buf = di->kdgz->kdgz_buf; | buf = di->kdcomp->kdc_buf; | ||||
memmove(buf, virtual, length); | memmove(buf, virtual, length); | ||||
return (gzio_write(di->kdgz->kdgz_stream, buf, length)); | return (compressor_write(di->kdcomp->kdc_stream, buf, length)); | ||||
} | } | ||||
#endif | |||||
return (_dump_append(di, virtual, physical, length)); | return (_dump_append(di, virtual, physical, length)); | ||||
} | } | ||||
/* | /* | ||||
* Write to the dump device at the specified offset. | * Write to the dump device at the specified offset. | ||||
*/ | */ | ||||
int | int | ||||
dump_write(struct dumperinfo *di, void *virtual, vm_offset_t physical, | dump_write(struct dumperinfo *di, void *virtual, vm_offset_t physical, | ||||
Show All 18 Lines | |||||
{ | { | ||||
uint64_t extent; | uint64_t extent; | ||||
uint32_t keysize; | uint32_t keysize; | ||||
int error; | int error; | ||||
extent = dtoh64(kdh->dumpextent); | extent = dtoh64(kdh->dumpextent); | ||||
#ifdef EKCD | #ifdef EKCD | ||||
keysize = kerneldumpcrypto_dumpkeysize(di->kdc); | keysize = kerneldumpcrypto_dumpkeysize(di->kdcrypto); | ||||
#else | #else | ||||
keysize = 0; | keysize = 0; | ||||
#endif | #endif | ||||
#ifdef GZIO | if (di->kdcomp != NULL) { | ||||
if (di->kdgz != NULL) { | error = compressor_flush(di->kdcomp->kdc_stream); | ||||
error = gzio_flush(di->kdgz->kdgz_stream); | |||||
if (error == EAGAIN) { | if (error == EAGAIN) { | ||||
/* We have residual data in di->blockbuf. */ | /* We have residual data in di->blockbuf. */ | ||||
error = dump_write(di, di->blockbuf, 0, di->dumpoff, | error = dump_write(di, di->blockbuf, 0, di->dumpoff, | ||||
di->blocksize); | di->blocksize); | ||||
di->dumpoff += di->kdgz->kdgz_resid; | di->dumpoff += di->kdcomp->kdc_resid; | ||||
di->kdgz->kdgz_resid = 0; | di->kdcomp->kdc_resid = 0; | ||||
} | } | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
/* | /* | ||||
* We now know the size of the compressed dump, so update the | * We now know the size of the compressed dump, so update the | ||||
* header accordingly and recompute parity. | * header accordingly and recompute parity. | ||||
*/ | */ | ||||
kdh->dumplength = htod64(di->dumpoff - | kdh->dumplength = htod64(di->dumpoff - | ||||
(di->mediaoffset + di->mediasize - di->blocksize - extent)); | (di->mediaoffset + di->mediasize - di->blocksize - extent)); | ||||
kdh->parity = 0; | kdh->parity = 0; | ||||
kdh->parity = kerneldump_parity(kdh); | kdh->parity = kerneldump_parity(kdh); | ||||
gzio_reset(di->kdgz->kdgz_stream); | compressor_reset(di->kdcomp->kdc_stream); | ||||
} | } | ||||
#endif | |||||
/* | /* | ||||
* Write kerneldump headers at the beginning and end of the dump extent. | * Write kerneldump headers at the beginning and end of the dump extent. | ||||
* Write the key after the leading header. | * Write the key after the leading header. | ||||
*/ | */ | ||||
error = dump_write_header(di, kdh, | error = dump_write_header(di, kdh, | ||||
di->mediaoffset + di->mediasize - 2 * di->blocksize - extent - | di->mediaoffset + di->mediasize - 2 * di->blocksize - extent - | ||||
keysize); | keysize); | ||||
Show All 26 Lines | dump_init_header(const struct dumperinfo *di, struct kerneldumpheader *kdh, | ||||
strlcpy(kdh->magic, magic, sizeof(kdh->magic)); | strlcpy(kdh->magic, magic, sizeof(kdh->magic)); | ||||
strlcpy(kdh->architecture, MACHINE_ARCH, sizeof(kdh->architecture)); | strlcpy(kdh->architecture, MACHINE_ARCH, sizeof(kdh->architecture)); | ||||
kdh->version = htod32(KERNELDUMPVERSION); | kdh->version = htod32(KERNELDUMPVERSION); | ||||
kdh->architectureversion = htod32(archver); | kdh->architectureversion = htod32(archver); | ||||
kdh->dumplength = htod64(dumplen); | kdh->dumplength = htod64(dumplen); | ||||
kdh->dumpextent = kdh->dumplength; | kdh->dumpextent = kdh->dumplength; | ||||
kdh->dumptime = htod64(time_second); | kdh->dumptime = htod64(time_second); | ||||
#ifdef EKCD | #ifdef EKCD | ||||
kdh->dumpkeysize = htod32(kerneldumpcrypto_dumpkeysize(di->kdc)); | kdh->dumpkeysize = htod32(kerneldumpcrypto_dumpkeysize(di->kdcrypto)); | ||||
#else | #else | ||||
kdh->dumpkeysize = 0; | kdh->dumpkeysize = 0; | ||||
#endif | #endif | ||||
kdh->blocksize = htod32(di->blocksize); | kdh->blocksize = htod32(di->blocksize); | ||||
strlcpy(kdh->hostname, prison0.pr_hostname, sizeof(kdh->hostname)); | strlcpy(kdh->hostname, prison0.pr_hostname, sizeof(kdh->hostname)); | ||||
dstsize = sizeof(kdh->versionstring); | dstsize = sizeof(kdh->versionstring); | ||||
if (strlcpy(kdh->versionstring, version, dstsize) >= dstsize) | if (strlcpy(kdh->versionstring, version, dstsize) >= dstsize) | ||||
kdh->versionstring[dstsize - 2] = '\n'; | kdh->versionstring[dstsize - 2] = '\n'; | ||||
if (panicstr != NULL) | if (panicstr != NULL) | ||||
strlcpy(kdh->panicstring, panicstr, sizeof(kdh->panicstring)); | strlcpy(kdh->panicstring, panicstr, sizeof(kdh->panicstring)); | ||||
#ifdef GZIO | if (di->kdcomp != NULL) | ||||
if (di->kdgz != NULL) | |||||
kdh->compression = KERNELDUMP_COMP_GZIP; | kdh->compression = KERNELDUMP_COMP_GZIP; | ||||
#endif | |||||
kdh->parity = kerneldump_parity(kdh); | kdh->parity = kerneldump_parity(kdh); | ||||
} | } | ||||
#ifdef DDB | #ifdef DDB | ||||
DB_SHOW_COMMAND(panic, db_show_panic) | DB_SHOW_COMMAND(panic, db_show_panic) | ||||
{ | { | ||||
if (panicstr == NULL) | if (panicstr == NULL) | ||||
db_printf("panicstr not set\n"); | db_printf("panicstr not set\n"); | ||||
else | else | ||||
db_printf("panic: %s\n", panicstr); | db_printf("panic: %s\n", panicstr); | ||||
} | } | ||||
#endif | #endif |