diff options
Diffstat (limited to 'sys/kern/kern_shutdown.c')
-rw-r--r-- | sys/kern/kern_shutdown.c | 32 |
1 files changed, 31 insertions, 1 deletions
diff --git a/sys/kern/kern_shutdown.c b/sys/kern/kern_shutdown.c index 87e7d63..7588d4c 100644 --- a/sys/kern/kern_shutdown.c +++ b/sys/kern/kern_shutdown.c @@ -88,6 +88,8 @@ __FBSDID("$FreeBSD$"); #include <sys/signalvar.h> +static MALLOC_DEFINE(M_DUMPER, "dumper", "dumper block buffer"); + #ifndef PANIC_REBOOT_WAIT_TIME #define PANIC_REBOOT_WAIT_TIME 15 /* default to 15 seconds */ #endif @@ -848,7 +850,9 @@ set_dumper(struct dumperinfo *di, const char *devname, struct thread *td) return (error); if (di == NULL) { - bzero(&dumper, sizeof dumper); + if (dumper.blockbuf != NULL) + free(dumper.blockbuf, M_DUMPER); + bzero(&dumper, sizeof(dumper)); dumpdevname[0] = '\0'; return (0); } @@ -860,6 +864,7 @@ set_dumper(struct dumperinfo *di, const char *devname, struct thread *td) printf("set_dumper: device name truncated from '%s' -> '%s'\n", devname, dumpdevname); } + dumper.blockbuf = malloc(di->blocksize, M_DUMPER, M_WAITOK | M_ZERO); return (0); } @@ -880,6 +885,31 @@ dump_write(struct dumperinfo *di, void *virtual, vm_offset_t physical, return (di->dumper(di->priv, virtual, physical, offset, length)); } +/* Call dumper with bounds checking. */ +int +dump_write_pad(struct dumperinfo *di, void *virtual, vm_offset_t physical, + off_t offset, size_t length, size_t *size) +{ + char *temp; + int ret; + + if (length > di->blocksize) + return (ENOMEM); + + *size = di->blocksize; + if (length == di->blocksize) + temp = virtual; + else { + temp = di->blockbuf; + memset(temp + length, 0, di->blocksize - length); + memcpy(temp, virtual, length); + } + ret = dump_write(di, temp, physical, offset, *size); + + return (ret); +} + + void mkdumpheader(struct kerneldumpheader *kdh, char *magic, uint32_t archver, uint64_t dumplen, uint32_t blksz) |