Index: sys/amd64/amd64/minidump_machdep.c =================================================================== --- sys/amd64/amd64/minidump_machdep.c +++ sys/amd64/amd64/minidump_machdep.c @@ -56,7 +56,6 @@ int vm_page_dump_size; static struct kerneldumpheader kdh; -static off_t dumplo; /* Handle chunked writes. */ static size_t fragsz; @@ -93,8 +92,7 @@ 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 @@ 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 @@ 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 @@ if (error) goto fail; - error = dump_finish(di, &kdh, dumplo); + error = dump_finish(di, &kdh); if (error != 0) goto fail; Index: sys/arm/arm/minidump_machdep.c =================================================================== --- sys/arm/arm/minidump_machdep.c +++ sys/arm/arm/minidump_machdep.c @@ -58,8 +58,6 @@ static struct kerneldumpheader kdh; -static off_t dumplo; - /* Handle chunked writes. */ static size_t fragsz; static void *dump_va; @@ -89,8 +87,7 @@ 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 @@ 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 @@ 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 @@ if (error) goto fail; - error = dump_finish(di, &kdh, dumplo); + error = dump_finish(di, &kdh); if (error != 0) goto fail; Index: sys/arm64/arm64/minidump_machdep.c =================================================================== --- sys/arm64/arm64/minidump_machdep.c +++ sys/arm64/arm64/minidump_machdep.c @@ -62,7 +62,6 @@ int vm_page_dump_size; static struct kerneldumpheader kdh; -static off_t dumplo; /* Handle chunked writes. */ static size_t fragsz; @@ -96,8 +95,7 @@ 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 @@ 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 @@ 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 @@ if (error) goto fail; - error = dump_finish(di, &kdh, dumplo); + error = dump_finish(di, &kdh); if (error != 0) goto fail; Index: sys/i386/i386/minidump_machdep.c =================================================================== --- sys/i386/i386/minidump_machdep.c +++ sys/i386/i386/minidump_machdep.c @@ -54,7 +54,6 @@ int vm_page_dump_size; static struct kerneldumpheader kdh; -static off_t dumplo; /* Handle chunked writes. */ static size_t fragsz; @@ -86,8 +85,7 @@ 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 @@ 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 @@ 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 @@ if (error) goto fail; - error = dump_finish(di, &kdh, dumplo); + error = dump_finish(di, &kdh); if (error != 0) goto fail; Index: sys/kern/kern_dump.c =================================================================== --- sys/kern/kern_dump.c +++ sys/kern/kern_dump.c @@ -51,8 +51,6 @@ #define MD_ALIGN(x) roundup2((off_t)(x), PAGE_SIZE) -off_t dumplo; - /* Handle buffered writes. */ static size_t fragsz; @@ -122,11 +120,9 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ * 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; Index: sys/kern/kern_shutdown.c =================================================================== --- sys/kern/kern_shutdown.c +++ sys/kern/kern_shutdown.c @@ -157,7 +157,6 @@ 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 @@ 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 @@ (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 @@ /* 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_append(struct dumperinfo *di, void *virtual, + vm_offset_t physical, 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,17 +1077,14 @@ if (dump_encrypt(kdc, buf, nbytes) != 0) return (EIO); - error = di->dumper(di->priv, buf, physical, offset, nbytes); + error = dump_append(di, buf, physical, nbytes); if (error != 0) return (error); - offset += nbytes; virtual = (void *)((uint8_t *)virtual + nbytes); length -= nbytes; } - kdc->kdc_nextoffset = nextoffset; - return (0); } @@ -1131,26 +1097,11 @@ 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 +1121,7 @@ memcpy(buf, kdh, hdrsz); } - return (dump_raw_write(di, buf, physical, offset, di->blocksize)); + return (dump_write(di, buf, physical, offset, di->blocksize)); } /* @@ -1179,10 +1130,9 @@ * key. */ int -dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh, off_t *dumplop) +dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh) { uint64_t dumpsize; - off_t dumplo; uint32_t keysize; int error; @@ -1199,35 +1149,62 @@ if (di->mediasize < KERNELDUMP_METADATA_SIZE + dumpsize) return (E2BIG); - dumplo = di->mediaoffset + di->mediasize - dumpsize; + di->dumpoff = di->mediaoffset + di->mediasize - dumpsize; - error = dump_write_header(di, kdh, 0, dumplo); + error = dump_write_header(di, kdh, 0, di->dumpoff); if (error != 0) return (error); - dumplo += 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); - dumplo += keysize; + di->dumpoff += keysize; #endif - *dumplop = dumplo; - return (0); } +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_append(di, virtual, physical, length); + else +#endif + error = dump_write(di, virtual, physical, di->dumpoff, length); + if (error == 0) + di->dumpoff += length; + return (error); +} + +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); Index: sys/mips/mips/minidump_machdep.c =================================================================== --- sys/mips/mips/minidump_machdep.c +++ sys/mips/mips/minidump_machdep.c @@ -56,7 +56,6 @@ 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 @@ 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 @@ 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 @@ } } - error = dump_finish(di, &kdh, dumplo); + error = dump_finish(di, &kdh); if (error != 0) goto fail; Index: sys/sparc64/sparc64/dump_machdep.c =================================================================== --- sys/sparc64/sparc64/dump_machdep.c +++ sys/sparc64/sparc64/dump_machdep.c @@ -49,7 +49,6 @@ 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 @@ 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 @@ if (error < 0) goto fail; - error = dump_finish(di, &kdh, dumplo); + error = dump_finish(di, &kdh); if (error != 0) goto fail; Index: sys/sys/conf.h =================================================================== --- sys/sys/conf.h +++ sys/sys/conf.h @@ -336,21 +336,23 @@ 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 */