Index: sys/amd64/amd64/minidump_machdep.c =================================================================== --- sys/amd64/amd64/minidump_machdep.c +++ sys/amd64/amd64/minidump_machdep.c @@ -49,22 +49,10 @@ #include #include -CTASSERT(sizeof(struct kerneldumpheader) == 512); - -/* - * Don't touch the first SIZEOF_METADATA bytes on the dump device. This - * is to protect us from metadata and to protect metadata from us. - */ -#define SIZEOF_METADATA (64*1024) - -#define MD_ALIGN(x) (((off_t)(x) + PAGE_MASK) & ~PAGE_MASK) -#define DEV_ALIGN(x) (((off_t)(x) + (DEV_BSIZE-1)) & ~(DEV_BSIZE-1)) - 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; @@ -98,8 +86,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); } @@ -182,10 +169,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 { @@ -319,13 +305,6 @@ } dumpsize += PAGE_SIZE; - /* Determine dump offset on device. */ - if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2) { - error = E2BIG; - goto fail; - } - dumplo = di->mediaoffset + di->mediasize - dumpsize; - dumplo -= sizeof(kdh) * 2; progress = dumpsize; /* Initialize mdhdr */ @@ -344,11 +323,9 @@ printf("Dumping %llu out of %ju MB:", (long long)dumpsize >> 20, ptoa((uintmax_t)physmem) / 1048576); - /* Dump leader */ - error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); + error = dump_start(di, &kdh); if (error) goto fail; - dumplo += sizeof(kdh); /* Dump my header */ bzero(&fakepd, sizeof(fakepd)); @@ -432,14 +409,10 @@ if (error) goto fail; - /* Dump trailer */ - error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); + /* Signal completion, signoff and exit stage left. */ + error = dump_finish(di, &kdh); if (error) goto fail; - dumplo += sizeof(kdh); - - /* Signal completion, signoff and exit stage left. */ - dump_write(di, NULL, 0, 0, 0); printf("\nDump complete\n"); return (0); Index: sys/arm/arm/minidump_machdep.c =================================================================== --- sys/arm/arm/minidump_machdep.c +++ sys/arm/arm/minidump_machdep.c @@ -50,14 +50,6 @@ #include #include -CTASSERT(sizeof(struct kerneldumpheader) == 512); - -/* - * Don't touch the first SIZEOF_METADATA bytes on the dump device. This - * is to protect us from metadata and to protect metadata from us. - */ -#define SIZEOF_METADATA (64*1024) - uint32_t *vm_page_dump; int vm_page_dump_size; @@ -65,8 +57,6 @@ static struct kerneldumpheader kdh; -static off_t dumplo; - /* Handle chunked writes. */ static size_t fragsz, offset; static void *dump_va; @@ -96,8 +86,7 @@ if (fragsz == 0) return (0); - error = dump_write(di, (char*)dump_va + offset, 0, dumplo, fragsz - offset); - dumplo += (fragsz - offset); + error = dump_append(di, (char*)dump_va + offset, 0, fragsz - offset); fragsz = 0; offset = 0; return (error); @@ -149,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 { @@ -294,14 +282,6 @@ dumpsize += PAGE_SIZE; - /* Determine dump offset on device. */ - if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2) { - error = ENOSPC; - goto fail; - } - - dumplo = di->mediaoffset + di->mediasize - dumpsize; - dumplo -= sizeof(kdh) * 2; progress = dumpsize; /* Initialize mdhdr */ @@ -319,11 +299,9 @@ printf("Physical memory: %u MB\n", ptoa((uintmax_t)physmem) / 1048576); printf("Dumping %llu MB:", (long long)dumpsize >> 20); - /* Dump leader */ - error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); + error = dump_start(di, &kdh); if (error) goto fail; - dumplo += sizeof(kdh); /* Dump my header */ bzero(&fakept, sizeof(fakept)); @@ -454,14 +432,10 @@ prev_pa = 0; } - /* Dump trailer */ - error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); - if (error) - goto fail; - dumplo += sizeof(kdh); - /* Signal completion, signoff and exit stage left. */ - dump_write(di, NULL, 0, 0, 0); + error = dump_finish(di, &kdh); + if (error != 0) + goto fail; printf("\nDump complete\n"); return (0); Index: sys/ddb/db_textdump.c =================================================================== --- sys/ddb/db_textdump.c +++ sys/ddb/db_textdump.c @@ -245,7 +245,7 @@ return (EIO); if (offset < SIZEOF_METADATA) return (ENOSPC); - textdump_error = dump_write(di, buffer, 0, offset + di->mediaoffset, + textdump_error = dump_write_raw(di, buffer, 0, offset + di->mediaoffset, TEXTDUMP_BLOCKSIZE); if (textdump_error) printf("textdump_writeblock: offset %jd, error %d\n", (intmax_t)offset, @@ -491,7 +491,7 @@ * Terminate the dump, report any errors, and clear the pending flag. */ if (textdump_error == 0) - (void)dump_write(di, NULL, 0, 0, 0); + (void)dump_write_raw(di, NULL, 0, 0, 0); if (textdump_error == ENOSPC) printf("Textdump: Insufficient space on dump partition\n"); else if (textdump_error != 0) Index: sys/geom/raid/g_raid.c =================================================================== --- sys/geom/raid/g_raid.c +++ sys/geom/raid/g_raid.c @@ -1425,7 +1425,7 @@ return (ENXIO); if (sd->sd_disk->d_kd.di.dumper == NULL) return (EOPNOTSUPP); - return (dump_write(&sd->sd_disk->d_kd.di, + return (dump_write_raw(&sd->sd_disk->d_kd.di, virtual, physical, sd->sd_disk->d_kd.di.mediaoffset + sd->sd_offset + offset, length)); Index: sys/i386/i386/minidump_machdep.c =================================================================== --- sys/i386/i386/minidump_machdep.c +++ sys/i386/i386/minidump_machdep.c @@ -45,17 +45,6 @@ #include #include -CTASSERT(sizeof(struct kerneldumpheader) == 512); - -/* - * Don't touch the first SIZEOF_METADATA bytes on the dump device. This - * is to protect us from metadata and to protect metadata from us. - */ -#define SIZEOF_METADATA (64*1024) - -#define MD_ALIGN(x) (((off_t)(x) + PAGE_MASK) & ~PAGE_MASK) -#define DEV_ALIGN(x) (((off_t)(x) + (DEV_BSIZE-1)) & ~(DEV_BSIZE-1)) - uint32_t *vm_page_dump; int vm_page_dump_size; @@ -92,8 +81,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 +129,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 { @@ -244,13 +231,6 @@ } dumpsize += PAGE_SIZE; - /* Determine dump offset on device. */ - if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2) { - error = ENOSPC; - goto fail; - } - dumplo = di->mediaoffset + di->mediasize - dumpsize; - dumplo -= sizeof(kdh) * 2; progress = dumpsize; /* Initialize mdhdr */ @@ -271,10 +251,9 @@ printf("Dumping %llu MB:", (long long)dumpsize >> 20); /* Dump leader */ - error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); + error = dump_start(di, &kdh); if (error) goto fail; - dumplo += sizeof(kdh); /* Dump my header */ bzero(&fakept, sizeof(fakept)); @@ -348,14 +327,10 @@ if (error) goto fail; - /* Dump trailer */ - error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); + /* Signal completion, signoff and exit stage left. */ + error = dump_finish(di, &kdh); if (error) goto fail; - dumplo += sizeof(kdh); - - /* Signal completion, signoff and exit stage left. */ - dump_write(di, NULL, 0, 0, 0); printf("\nDump complete\n"); return (0); Index: sys/kern/kern_dump.c =================================================================== --- sys/kern/kern_dump.c +++ sys/kern/kern_dump.c @@ -43,10 +43,13 @@ #ifdef SW_WATCHDOG #include #endif + #include + #include #include #include + #include #include #include @@ -64,7 +67,6 @@ #define DEV_ALIGN(x) (((off_t)(x) + (DEV_BSIZE-1)) & ~(DEV_BSIZE-1)) struct dump_pa dump_map[DUMPSYS_MD_PA_NPAIRS]; -off_t dumplo; /* Our selected dumper. */ static struct dumperinfo dumper; @@ -73,11 +75,12 @@ static struct pcb dumppcb; /* Registers. */ lwpid_t dumptid; /* Thread ID. */ -/* Handle buffered writes. */ +/* Dump state. */ +static off_t dumpoff; static char buffer[DEV_BSIZE]; static size_t fragsz; -char dumpdevname[sizeof(((struct cdev *)NULL)->si_name)]; +static char dumpdevname[sizeof(((struct cdev *)NULL)->si_name)]; SYSCTL_DECL(_kern_shutdown); SYSCTL_STRING(_kern_shutdown, OID_AUTO, dumpdevname, CTLFLAG_RD, dumpdevname, 0, "Device for kernel dumps"); @@ -112,9 +115,71 @@ return (error); } +/* Perform any needed initialization in preparation for a kernel dump. */ +int +dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh) +{ + uint64_t length; + + length = dtoh64(kdh->dumplength); + if (di->mediasize < SIZEOF_METADATA + length + sizeof(*kdh) * 2) + return (E2BIG); + + dumpoff = di->mediaoffset + di->mediasize - length - sizeof(*kdh); + return (0); +} + +/* Complete a kernel dump. */ +int +dump_finish(struct dumperinfo *di, struct kerneldumpheader *kdh) +{ + uint64_t length; + int error; + + dumpoff = 0; + + length = dtoh64(kdh->dumplength); + + /* Write dump headers at the beginning and end of the dump extent. */ + error = dump_write_raw(di, kdh, 0, + di->mediaoffset + di->mediasize - sizeof(*kdh), sizeof(*kdh)); + if (error != 0) + return (error); + error = dump_write_raw(di, kdh, 0, + di->mediaoffset + di->mediasize - length - 2 * sizeof(*kdh), + sizeof(*kdh)); + if (error != 0) + return (error); + + /* Tell the dump media driver that we're done. */ + return (dump_write_raw(di, NULL, 0, 0, 0)); +} + +/* Write starting at the current kernel dump offset. */ +int +dump_append(struct dumperinfo *di, void *virtual, vm_offset_t physical, + size_t length) +{ + int error; + + error = dump_write_raw(di, virtual, physical, dumpoff, length); + if (error == 0) + dumpoff += length; + return (error); +} + +/* Seek forward by the specified number of bytes. */ +int +dump_skip(struct dumperinfo *di, size_t gap) +{ + + dumpoff += gap; + return (0); +} + /* Call dumper with bounds checking. */ int -dump_write(struct dumperinfo *di, void *virtual, vm_offset_t physical, +dump_write_raw(struct dumperinfo *di, void *virtual, vm_offset_t physical, off_t offset, size_t length) { @@ -238,11 +303,9 @@ ptr += len; sz -= len; if (fragsz == DEV_BSIZE) { - error = dump_write(di, buffer, 0, dumplo, - DEV_BSIZE); + error = dump_append(di, buffer, 0, DEV_BSIZE); if (error) return (error); - dumplo += DEV_BSIZE; fragsz = 0; } } @@ -257,8 +320,7 @@ if (fragsz == 0) return (0); - error = dump_write(di, buffer, 0, dumplo, DEV_BSIZE); - dumplo += DEV_BSIZE; + error = dump_append(di, buffer, 0, DEV_BSIZE); fragsz = 0; return (error); } @@ -306,11 +368,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; @@ -430,25 +491,15 @@ dumpsize += fileofs; hdrgap = fileofs - DEV_ALIGN(hdrsz); - /* Determine dump offset on device. */ - if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2) { - error = ENOSPC; - goto fail; - } - dumplo = di->mediaoffset + di->mediasize - dumpsize; - dumplo -= sizeof(kdh) * 2; - mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_ARCH_VERSION, dumpsize, di->blocksize); printf("Dumping %ju MB (%d chunks)\n", (uintmax_t)dumpsize >> 20, ehdr.e_phnum - DUMPSYS_NUM_AUX_HDRS); - /* Dump leader */ - error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); + error = dump_start(di, &kdh); if (error) goto fail; - dumplo += sizeof(kdh); /* Dump ELF header */ error = dumpsys_buf_write(di, (char*)&ehdr, sizeof(ehdr)); @@ -468,23 +519,23 @@ * 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. We cannot use MD_ALIGN on the current offset, because + * we don't care and may very well be unaligned within the dump + * device. */ - dumplo += hdrgap; + error = dump_skip(di, hdrgap); + if (error != 0) + goto fail; - /* Dump memory chunks (updates dumplo) */ + /* Dump memory chunks. */ error = dumpsys_foreach_chunk(dumpsys_cb_dumpdata, di); if (error < 0) goto fail; - /* Dump trailer */ - error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); - if (error) - goto fail; - /* Signal completion, signoff and exit stage left. */ - dump_write(di, NULL, 0, 0, 0); + error = dump_finish(di, &kdh); + if (error != 0) + goto fail; printf("\nDump complete\n"); return (0); Index: sys/mips/mips/minidump_machdep.c =================================================================== --- sys/mips/mips/minidump_machdep.c +++ sys/mips/mips/minidump_machdep.c @@ -47,20 +47,10 @@ #include #include -CTASSERT(sizeof(struct kerneldumpheader) == 512); - -/* - * Don't touch the first SIZEOF_METADATA bytes on the dump device. This - * is to protect us from metadata and to protect metadata from us. - */ -#define SIZEOF_METADATA (64*1024) - uint32_t *vm_page_dump; int vm_page_dump_size; static struct kerneldumpheader kdh; -static off_t dumplo; -static off_t origdumplo; /* Handle chunked writes. */ static uint64_t counter, progress; @@ -132,10 +122,9 @@ } 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 { @@ -219,14 +208,6 @@ dumpsize += PAGE_SIZE; - /* Determine dump offset on device. */ - if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2) { - error = ENOSPC; - goto fail; - } - - origdumplo = dumplo = di->mediaoffset + di->mediasize - dumpsize; - dumplo -= sizeof(kdh) * 2; progress = dumpsize; /* Initialize mdhdr */ @@ -245,11 +226,9 @@ (uintmax_t)ptoa((uintmax_t)physmem) / 1048576); printf("Dumping %llu MB:", (long long)dumpsize >> 20); - /* Dump leader */ - error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); + error = dump_start(di, &kdh); if (error) goto fail; - dumplo += sizeof(kdh); /* Dump my header */ bzero(tmpbuffer, sizeof(tmpbuffer)); @@ -316,14 +295,10 @@ } } - /* Dump trailer */ - error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); + /* Signal completion, signoff and exit stage left. */ + error = dump_finish(di, &kdh); if (error) goto fail; - dumplo += sizeof(kdh); - - /* Signal completion, signoff and exit stage left. */ - dump_write(di, NULL, 0, 0, 0); printf("\nDump complete\n"); return (0); 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; @@ -113,19 +112,14 @@ goto fail; } - /* Determine dump offset on device. */ - dumplo = di->mediaoffset + di->mediasize - totsize; - mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_SPARC64_VERSION, size, di->blocksize); printf("Dumping %lu MB (%d chunks)\n", (u_long)(size >> 20), nreg); - /* Dump leader */ - error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); + error = dump_start(di, &kdh); if (error) goto fail; - dumplo += sizeof(kdh); /* Dump the private header. */ hdr.dh_hdr_size = hdrsize; @@ -152,13 +146,10 @@ if (error < 0) goto fail; - /* Dump trailer */ - error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); - if (error) - goto fail; - /* Signal completion, signoff and exit stage left. */ - dump_write(di, NULL, 0, 0, 0); + error = dump_finish(di, &kdh); + if (error != 0) + goto fail; printf("\nDump complete\n"); return (0); Index: sys/sys/kerneldump.h =================================================================== --- sys/sys/kerneldump.h +++ sys/sys/kerneldump.h @@ -105,9 +105,6 @@ vm_paddr_t pa_size; }; -void mkdumpheader(struct kerneldumpheader *kdh, char *magic, uint32_t archver, - uint64_t dumplen, uint32_t blksz); - int dumpsys_generic(struct dumperinfo *); void dumpsys_map_chunk(vm_paddr_t, size_t, void **); @@ -123,9 +120,16 @@ void dumpsys_gen_unmap_chunk(vm_paddr_t, size_t, void *); int dumpsys_gen_write_aux_headers(struct dumperinfo *); -int set_dumper(struct dumperinfo *, const char *, struct thread *); -int dump_write(struct dumperinfo *, void *, vm_offset_t, off_t, size_t); +int dump_start(struct dumperinfo *, struct kerneldumpheader *); +int dump_finish(struct dumperinfo *, struct kerneldumpheader *); +int dump_append(struct dumperinfo *, void *, vm_offset_t, size_t); +int dump_skip(struct dumperinfo *, size_t); +int dump_write_raw(struct dumperinfo *, void *, vm_offset_t, off_t, size_t); + int doadump(boolean_t); +int set_dumper(struct dumperinfo *, const char *, struct thread *); +void mkdumpheader(struct kerneldumpheader *, char *, uint32_t, uint64_t, + uint32_t); extern int do_minidump;