diff --git a/sys/amd64/amd64/minidump_machdep.c b/sys/amd64/amd64/minidump_machdep.c index c5414a18ab67..d1990ba9cf69 100644 --- a/sys/amd64/amd64/minidump_machdep.c +++ b/sys/amd64/amd64/minidump_machdep.c @@ -56,7 +56,6 @@ uint64_t *vm_page_dump; int vm_page_dump_size; static struct kerneldumpheader kdh; -static off_t dumplo; /* Handle chunked writes. */ static size_t fragsz; @@ -93,8 +92,7 @@ blk_flush(struct dumperinfo *di) if (fragsz == 0) return (0); - error = dump_write(di, dump_va, 0, dumplo, fragsz); - dumplo += fragsz; + error = dump_append(di, dump_va, 0, fragsz); fragsz = 0; return (error); } @@ -177,10 +175,9 @@ blk_write(struct dumperinfo *di, char *ptr, vm_paddr_t pa, size_t sz) wdog_kern_pat(WD_LASTVAL); if (ptr) { - error = dump_write(di, ptr, 0, dumplo, len); + error = dump_append(di, ptr, 0, len); if (error) return (error); - dumplo += len; ptr += len; sz -= len; } else { @@ -333,7 +330,7 @@ minidumpsys(struct dumperinfo *di) printf("Dumping %llu out of %ju MB:", (long long)dumpsize >> 20, ptoa((uintmax_t)physmem) / 1048576); - error = dump_start(di, &kdh, &dumplo); + error = dump_start(di, &kdh); if (error != 0) goto fail; @@ -419,7 +416,7 @@ minidumpsys(struct dumperinfo *di) if (error) goto fail; - error = dump_finish(di, &kdh, dumplo); + error = dump_finish(di, &kdh); if (error != 0) goto fail; diff --git a/sys/arm/arm/minidump_machdep.c b/sys/arm/arm/minidump_machdep.c index 9fff9fda1d34..c6a0de4483d4 100644 --- a/sys/arm/arm/minidump_machdep.c +++ b/sys/arm/arm/minidump_machdep.c @@ -58,8 +58,6 @@ int vm_page_dump_size; static struct kerneldumpheader kdh; -static off_t dumplo; - /* Handle chunked writes. */ static size_t fragsz; static void *dump_va; @@ -89,8 +87,7 @@ blk_flush(struct dumperinfo *di) if (fragsz == 0) return (0); - error = dump_write(di, dump_va, 0, dumplo, fragsz); - dumplo += fragsz; + error = dump_append(di, dump_va, 0, fragsz); fragsz = 0; return (error); } @@ -141,10 +138,9 @@ blk_write(struct dumperinfo *di, char *ptr, vm_paddr_t pa, size_t sz) wdog_kern_pat(WD_LASTVAL); #endif if (ptr) { - error = dump_write(di, ptr, 0, dumplo, len); + error = dump_append(di, ptr, 0, len); if (error) return (error); - dumplo += len; ptr += len; sz -= len; } else { @@ -251,7 +247,7 @@ minidumpsys(struct dumperinfo *di) printf("Physical memory: %u MB\n", ptoa((uintmax_t)physmem) / 1048576); printf("Dumping %llu MB:", (long long)dumpsize >> 20); - error = dump_start(di, &kdh, &dumplo); + error = dump_start(di, &kdh); if (error != 0) goto fail; @@ -329,7 +325,7 @@ minidumpsys(struct dumperinfo *di) if (error) goto fail; - error = dump_finish(di, &kdh, dumplo); + error = dump_finish(di, &kdh); if (error != 0) goto fail; diff --git a/sys/arm64/arm64/minidump_machdep.c b/sys/arm64/arm64/minidump_machdep.c index 50139b1b54b9..34295be87a08 100644 --- a/sys/arm64/arm64/minidump_machdep.c +++ b/sys/arm64/arm64/minidump_machdep.c @@ -62,7 +62,6 @@ uint64_t *vm_page_dump; int vm_page_dump_size; static struct kerneldumpheader kdh; -static off_t dumplo; /* Handle chunked writes. */ static size_t fragsz; @@ -96,8 +95,7 @@ blk_flush(struct dumperinfo *di) if (fragsz == 0) return (0); - error = dump_write(di, dump_va, 0, dumplo, fragsz); - dumplo += fragsz; + error = dump_append(di, dump_va, 0, fragsz); fragsz = 0; return (error); } @@ -183,10 +181,9 @@ blk_write(struct dumperinfo *di, char *ptr, vm_paddr_t pa, size_t sz) wdog_kern_pat(WD_LASTVAL); if (ptr) { - error = dump_write(di, ptr, 0, dumplo, len); + error = dump_append(di, ptr, 0, len); if (error) return (error); - dumplo += len; ptr += len; sz -= len; } else { @@ -295,7 +292,7 @@ minidumpsys(struct dumperinfo *di) printf("Dumping %llu out of %ju MB:", (long long)dumpsize >> 20, ptoa((uintmax_t)physmem) / 1048576); - error = dump_start(di, &kdh, &dumplo); + error = dump_start(di, &kdh); if (error != 0) goto fail; @@ -395,7 +392,7 @@ minidumpsys(struct dumperinfo *di) if (error) goto fail; - error = dump_finish(di, &kdh, dumplo); + error = dump_finish(di, &kdh); if (error != 0) goto fail; diff --git a/sys/i386/i386/minidump_machdep.c b/sys/i386/i386/minidump_machdep.c index d28a64f52fc3..689982af81d6 100644 --- a/sys/i386/i386/minidump_machdep.c +++ b/sys/i386/i386/minidump_machdep.c @@ -54,7 +54,6 @@ uint32_t *vm_page_dump; int vm_page_dump_size; static struct kerneldumpheader kdh; -static off_t dumplo; /* Handle chunked writes. */ static size_t fragsz; @@ -86,8 +85,7 @@ blk_flush(struct dumperinfo *di) if (fragsz == 0) return (0); - error = dump_write(di, dump_va, 0, dumplo, fragsz); - dumplo += fragsz; + error = dump_append(di, dump_va, 0, fragsz); fragsz = 0; return (error); } @@ -135,10 +133,9 @@ blk_write(struct dumperinfo *di, char *ptr, vm_paddr_t pa, size_t sz) wdog_kern_pat(WD_LASTVAL); if (ptr) { - error = dump_write(di, ptr, 0, dumplo, len); + error = dump_append(di, ptr, 0, len); if (error) return (error); - dumplo += len; ptr += len; sz -= len; } else { @@ -258,7 +255,7 @@ minidumpsys(struct dumperinfo *di) printf("Physical memory: %ju MB\n", ptoa((uintmax_t)physmem) / 1048576); printf("Dumping %llu MB:", (long long)dumpsize >> 20); - error = dump_start(di, &kdh, &dumplo); + error = dump_start(di, &kdh); if (error != 0) goto fail; @@ -334,7 +331,7 @@ minidumpsys(struct dumperinfo *di) if (error) goto fail; - error = dump_finish(di, &kdh, dumplo); + error = dump_finish(di, &kdh); if (error != 0) goto fail; diff --git a/sys/kern/kern_dump.c b/sys/kern/kern_dump.c index a8e32a75a98b..d2914966957a 100644 --- a/sys/kern/kern_dump.c +++ b/sys/kern/kern_dump.c @@ -51,8 +51,6 @@ CTASSERT(sizeof(struct kerneldumpheader) == 512); #define MD_ALIGN(x) roundup2((off_t)(x), PAGE_SIZE) -off_t dumplo; - /* Handle buffered writes. */ static size_t fragsz; @@ -122,11 +120,9 @@ dumpsys_buf_seek(struct dumperinfo *di, size_t sz) while (sz > 0) { nbytes = MIN(sz, sizeof(buf)); - error = dump_write(di, buf, 0, dumplo, nbytes); + error = dump_append(di, buf, 0, nbytes); if (error) return (error); - dumplo += nbytes; - sz -= nbytes; } @@ -148,11 +144,9 @@ dumpsys_buf_write(struct dumperinfo *di, char *ptr, size_t sz) ptr += len; sz -= len; if (fragsz == di->blocksize) { - error = dump_write(di, di->blockbuf, 0, dumplo, - di->blocksize); + error = dump_append(di, di->blockbuf, 0, di->blocksize); if (error) return (error); - dumplo += di->blocksize; fragsz = 0; } } @@ -167,8 +161,7 @@ dumpsys_buf_flush(struct dumperinfo *di) if (fragsz == 0) return (0); - error = dump_write(di, di->blockbuf, 0, dumplo, di->blocksize); - dumplo += di->blocksize; + error = dump_append(di, di->blockbuf, 0, di->blocksize); fragsz = 0; return (error); } @@ -216,11 +209,10 @@ dumpsys_cb_dumpdata(struct dump_pa *mdp, int seqnr, void *arg) wdog_kern_pat(WD_LASTVAL); #endif - error = dump_write(di, va, 0, dumplo, sz); + error = dump_append(di, va, 0, sz); dumpsys_unmap_chunk(pa, chunk, va); if (error) break; - dumplo += sz; pgs -= chunk; pa += sz; @@ -347,7 +339,7 @@ dumpsys_generic(struct dumperinfo *di) printf("Dumping %ju MB (%d chunks)\n", (uintmax_t)dumpsize >> 20, ehdr.e_phnum - DUMPSYS_NUM_AUX_HDRS); - error = dump_start(di, &kdh, &dumplo); + error = dump_start(di, &kdh); if (error != 0) goto fail; @@ -369,19 +361,18 @@ dumpsys_generic(struct dumperinfo *di) * All headers are written using blocked I/O, so we know the * current offset is (still) block aligned. Skip the alignement * in the file to have the segment contents aligned at page - * boundary. We cannot use MD_ALIGN on dumplo, because we don't - * care and may very well be unaligned within the dump device. + * boundary. */ error = dumpsys_buf_seek(di, (size_t)hdrgap); if (error) goto fail; - /* Dump memory chunks (updates dumplo) */ + /* Dump memory chunks. */ error = dumpsys_foreach_chunk(dumpsys_cb_dumpdata, di); if (error < 0) goto fail; - error = dump_finish(di, &kdh, dumplo); + error = dump_finish(di, &kdh); if (error != 0) goto fail; diff --git a/sys/kern/kern_shutdown.c b/sys/kern/kern_shutdown.c index 168da47170af..36c275809add 100644 --- a/sys/kern/kern_shutdown.c +++ b/sys/kern/kern_shutdown.c @@ -157,7 +157,6 @@ struct kerneldumpcrypto { uint8_t kdc_iv[KERNELDUMP_IV_MAX_SIZE]; keyInstance kdc_ki; cipherInstance kdc_ci; - off_t kdc_nextoffset; uint32_t kdc_dumpkeysize; struct kerneldumpkey kdc_dumpkey[]; }; @@ -931,8 +930,6 @@ kerneldumpcrypto_init(struct kerneldumpcrypto *kdc) goto out; } - kdc->kdc_nextoffset = 0; - kdk = kdc->kdc_dumpkey; memcpy(kdk->kdk_iv, kdc->kdc_iv, sizeof(kdk->kdk_iv)); out: @@ -1024,24 +1021,20 @@ dump_check_bounds(struct dumperinfo *di, off_t offset, size_t length) (uintmax_t)length, (intmax_t)di->mediasize); return (ENOSPC); } + if (length % di->blocksize != 0) { + printf("Attempt to write partial block of length %ju.\n", + (uintmax_t)length); + return (EINVAL); + } + if (offset % di->blocksize != 0) { + printf("Attempt to write at unaligned offset %jd.\n", + (intmax_t)offset); + return (EINVAL); + } return (0); } -/* Call dumper with bounds checking. */ -static int -dump_raw_write(struct dumperinfo *di, void *virtual, vm_offset_t physical, - off_t offset, size_t length) -{ - int error; - - error = dump_check_bounds(di, offset, length); - if (error != 0) - return (error); - - return (di->dumper(di->priv, virtual, physical, offset, length)); -} - #ifdef EKCD static int dump_encrypt(struct kerneldumpcrypto *kdc, uint8_t *buf, size_t size) @@ -1067,40 +1060,16 @@ dump_encrypt(struct kerneldumpcrypto *kdc, uint8_t *buf, size_t size) /* Encrypt data and call dumper. */ static int -dump_encrypted_write(struct dumperinfo *di, void *virtual, vm_offset_t physical, - off_t offset, size_t length) +dump_encrypted_write(struct dumperinfo *di, void *virtual, + vm_offset_t physical, off_t offset, size_t length) { static uint8_t buf[KERNELDUMP_BUFFER_SIZE]; struct kerneldumpcrypto *kdc; int error; size_t nbytes; - off_t nextoffset; kdc = di->kdc; - error = dump_check_bounds(di, offset, length); - if (error != 0) - return (error); - - /* Signal completion. */ - if (virtual == NULL && physical == 0 && offset == 0 && length == 0) { - return (di->dumper(di->priv, virtual, physical, offset, - length)); - } - - /* Data have to be aligned to block size. */ - if ((length % di->blocksize) != 0) - return (EINVAL); - - /* - * Data have to be written continuously becase we're encrypting using - * CBC mode which has this assumption. - */ - if (kdc->kdc_nextoffset != 0 && kdc->kdc_nextoffset != offset) - return (EINVAL); - - nextoffset = offset + (off_t)length; - while (length > 0) { nbytes = MIN(length, sizeof(buf)); bcopy(virtual, buf, nbytes); @@ -1108,7 +1077,7 @@ dump_encrypted_write(struct dumperinfo *di, void *virtual, vm_offset_t physical, if (dump_encrypt(kdc, buf, nbytes) != 0) return (EIO); - error = di->dumper(di->priv, buf, physical, offset, nbytes); + error = dump_write(di, buf, physical, offset, nbytes); if (error != 0) return (error); @@ -1117,8 +1086,6 @@ dump_encrypted_write(struct dumperinfo *di, void *virtual, vm_offset_t physical, length -= nbytes; } - kdc->kdc_nextoffset = nextoffset; - return (0); } @@ -1131,26 +1098,11 @@ dump_write_key(struct dumperinfo *di, vm_offset_t physical, off_t offset) if (kdc == NULL) return (0); - return (dump_raw_write(di, kdc->kdc_dumpkey, physical, offset, + return (dump_write(di, kdc->kdc_dumpkey, physical, offset, kdc->kdc_dumpkeysize)); } #endif /* EKCD */ -int -dump_write(struct dumperinfo *di, void *virtual, vm_offset_t physical, - off_t offset, size_t length) -{ - -#ifdef EKCD - if (di->kdc != NULL) { - return (dump_encrypted_write(di, virtual, physical, offset, - length)); - } -#endif - - return (dump_raw_write(di, virtual, physical, offset, length)); -} - static int dump_write_header(struct dumperinfo *di, struct kerneldumpheader *kdh, vm_offset_t physical, off_t offset) @@ -1170,7 +1122,7 @@ dump_write_header(struct dumperinfo *di, struct kerneldumpheader *kdh, memcpy(buf, kdh, hdrsz); } - return (dump_raw_write(di, buf, physical, offset, di->blocksize)); + return (dump_write(di, buf, physical, offset, di->blocksize)); } /* @@ -1185,7 +1137,7 @@ dump_write_header(struct dumperinfo *di, struct kerneldumpheader *kdh, * key. */ int -dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh, off_t *dumplop) +dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh) { uint64_t dumpsize; uint32_t keysize; @@ -1204,33 +1156,65 @@ dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh, off_t *dumplop) if (di->mediasize < SIZEOF_METADATA + dumpsize) return (E2BIG); - *dumplop = di->mediaoffset + di->mediasize - dumpsize; + di->dumpoff = di->mediaoffset + di->mediasize - dumpsize; - error = dump_write_header(di, kdh, 0, *dumplop); + error = dump_write_header(di, kdh, 0, di->dumpoff); if (error != 0) return (error); - *dumplop += di->blocksize; + di->dumpoff += di->blocksize; #ifdef EKCD - error = dump_write_key(di, 0, *dumplop); + error = dump_write_key(di, 0, di->dumpoff); if (error != 0) return (error); - *dumplop += keysize; + di->dumpoff += keysize; #endif return (0); } +/* Write to the dump device at the current dump offset. */ +int +dump_append(struct dumperinfo *di, void *virtual, vm_offset_t physical, + size_t length) +{ + int error; + +#ifdef EKCD + if (di->kdc != NULL) + error = dump_encrypted_write(di, virtual, physical, di->dumpoff, + length); + else +#endif + error = dump_write(di, virtual, physical, di->dumpoff, length); + if (error == 0) + di->dumpoff += length; + return (error); +} + +/* Perform a raw write to the dump device at the specified offset. */ +int +dump_write(struct dumperinfo *di, void *virtual, vm_offset_t physical, + off_t offset, size_t length) +{ + int error; + + error = dump_check_bounds(di, offset, length); + if (error != 0) + return (error); + return (di->dumper(di->priv, virtual, physical, offset, length)); +} + /* * Write the trailing kernel dump header and signal to the lower layers that the * dump has completed. */ int -dump_finish(struct dumperinfo *di, struct kerneldumpheader *kdh, off_t dumplo) +dump_finish(struct dumperinfo *di, struct kerneldumpheader *kdh) { int error; - error = dump_write_header(di, kdh, 0, dumplo); + error = dump_write_header(di, kdh, 0, di->dumpoff); if (error != 0) return (error); diff --git a/sys/mips/mips/minidump_machdep.c b/sys/mips/mips/minidump_machdep.c index c38e60412a99..9b55ddbb3c5f 100644 --- a/sys/mips/mips/minidump_machdep.c +++ b/sys/mips/mips/minidump_machdep.c @@ -56,7 +56,6 @@ uint32_t *vm_page_dump; int vm_page_dump_size; static struct kerneldumpheader kdh; -static off_t dumplo; /* Handle chunked writes. */ static uint64_t counter, progress, dumpsize; @@ -166,10 +165,9 @@ write_buffer(struct dumperinfo *di, char *ptr, size_t sz) wdog_kern_pat(WD_LASTVAL); if (ptr) { - error = dump_write(di, ptr, 0, dumplo, len); + error = dump_append(di, ptr, 0, len); if (error) return (error); - dumplo += len; ptr += len; sz -= len; } else { @@ -267,7 +265,7 @@ minidumpsys(struct dumperinfo *di) printf("Dumping %llu out of %ju MB:", (long long)dumpsize >> 20, ptoa((uintmax_t)physmem) / 1048576); - error = dump_start(di, &kdh, &dumplo); + error = dump_start(di, &kdh); if (error != 0) goto fail; @@ -335,7 +333,7 @@ minidumpsys(struct dumperinfo *di) } } - error = dump_finish(di, &kdh, dumplo); + error = dump_finish(di, &kdh); if (error != 0) goto fail; diff --git a/sys/sparc64/sparc64/dump_machdep.c b/sys/sparc64/sparc64/dump_machdep.c index 769c8d1a2cf6..5b61c5d237c8 100644 --- a/sys/sparc64/sparc64/dump_machdep.c +++ b/sys/sparc64/sparc64/dump_machdep.c @@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$"); static off_t fileofs; -extern off_t dumplo; extern struct dump_pa dump_map[DUMPSYS_MD_PA_NPAIRS]; int do_minidump = 0; @@ -99,7 +98,7 @@ dumpsys(struct dumperinfo *di) printf("Dumping %lu MB (%d chunks)\n", (u_long)(size >> 20), nreg); - error = dump_start(di, &kdh, &dumplo); + error = dump_start(di, &kdh); if (error != 0) goto fail; @@ -128,7 +127,7 @@ dumpsys(struct dumperinfo *di) if (error < 0) goto fail; - error = dump_finish(di, &kdh, dumplo); + error = dump_finish(di, &kdh); if (error != 0) goto fail; diff --git a/sys/sys/conf.h b/sys/sys/conf.h index 1b4e576db25c..4c33ec34a9b6 100644 --- a/sys/sys/conf.h +++ b/sys/sys/conf.h @@ -336,21 +336,23 @@ struct dumperinfo { off_t mediaoffset; /* Initial offset in bytes. */ off_t mediasize; /* Space available in bytes. */ void *blockbuf; /* Buffer for padding shorter dump blocks */ + off_t dumpoff; /* Offset of ongoing kernel dump. */ struct kerneldumpcrypto *kdc; /* Kernel dump crypto. */ }; +extern int dumping; /* system is dumping */ + +int doadump(boolean_t); int set_dumper(struct dumperinfo *di, const char *devname, struct thread *td, uint8_t encrypt, const uint8_t *key, uint32_t encryptedkeysize, const uint8_t *encryptedkey); + +int dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh); +int dump_append(struct dumperinfo *, void *, vm_offset_t, size_t); +int dump_write(struct dumperinfo *, void *, vm_offset_t, off_t, size_t); +int dump_finish(struct dumperinfo *di, struct kerneldumpheader *kdh); void dump_init_header(const struct dumperinfo *di, struct kerneldumpheader *kdh, char *magic, uint32_t archver, uint64_t dumplen); -int dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh, - off_t *dumplop); -int dump_finish(struct dumperinfo *di, struct kerneldumpheader *kdh, - off_t dumplo); -int dump_write(struct dumperinfo *, void *, vm_offset_t, off_t, size_t); -int doadump(boolean_t); -extern int dumping; /* system is dumping */ #endif /* _KERNEL */