Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 15 Apr 2016 17:45:12 +0000 (UTC)
From:      "Conrad E. Meyer" <cem@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r298076 - in head: sbin/savecore sys/amd64/amd64 sys/kern sys/sys
Message-ID:  <201604151745.u3FHjCqW021550@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: cem
Date: Fri Apr 15 17:45:12 2016
New Revision: 298076
URL: https://svnweb.freebsd.org/changeset/base/298076

Log:
  Add 4Kn kernel dump support
  
  (And 4Kn minidump support, but only for amd64.)
  
  Make sure all I/O to the dump device is of the native sector size.  To
  that end, we keep a native sector sized buffer associated with dump
  devices (di->blockbuf) and use it to pad smaller objects as needed (e.g.
  kerneldumpheader).
  
  Add dump_write_pad() as a convenience API to dump smaller objects with
  zero padding.  (Rather than pull in NPM leftpad, we wrote our own.)
  
  Savecore(1) has been updated to deal with these dumps.  The format for
  512-byte sector dumps should remain backwards compatible.
  
  Minidumps for other architectures are left as an exercise for the
  reader.
  
  PR:		194279
  Submitted by:	ambrisko@
  Reviewed by:	cem (earlier version), rpokala
  Tested by:	rpokala (4Kn/512 except 512 fulldump), cem (512 fulldump)
  Relnotes:	yes
  Sponsored by:	EMC / Isilon Storage Division
  Differential Revision:	https://reviews.freebsd.org/D5848

Modified:
  head/sbin/savecore/savecore.c
  head/sys/amd64/amd64/minidump_machdep.c
  head/sys/kern/kern_dump.c
  head/sys/kern/kern_shutdown.c
  head/sys/sys/conf.h

Modified: head/sbin/savecore/savecore.c
==============================================================================
--- head/sbin/savecore/savecore.c	Fri Apr 15 17:30:33 2016	(r298075)
+++ head/sbin/savecore/savecore.c	Fri Apr 15 17:45:12 2016	(r298076)
@@ -436,7 +436,7 @@ DoFile(const char *savedir, const char *
 {
 	xo_handle_t *xostdout, *xoinfo;
 	static char infoname[PATH_MAX], corename[PATH_MAX], linkname[PATH_MAX];
-	static char *buf = NULL;
+	static char *buf = NULL, *temp = NULL;
 	struct kerneldumpheader kdhf, kdhl;
 	off_t mediasize, dumpsize, firsthd, lasthd;
 	FILE *info, *fp;
@@ -490,14 +490,29 @@ DoFile(const char *savedir, const char *
 		printf("sectorsize = %u\n", sectorsize);
 	}
 
+	if (sectorsize < sizeof(kdhl)) {
+		syslog(LOG_ERR,
+		    "Sector size is less the kernel dump header %zu",
+		    sizeof(kdhl));
+		goto closefd;
+	}
+
 	lasthd = mediasize - sectorsize;
+	if (temp == NULL) {
+		temp = malloc(sectorsize);
+		if (temp == NULL) {
+			syslog(LOG_ERR, "%m");
+			return;
+		}
+	}
 	if (lseek(fd, lasthd, SEEK_SET) != lasthd ||
-	    read(fd, &kdhl, sizeof(kdhl)) != sizeof(kdhl)) {
+	    read(fd, temp, sectorsize) != sectorsize) {
 		syslog(LOG_ERR,
 		    "error reading last dump header at offset %lld in %s: %m",
 		    (long long)lasthd, device);
 		goto closefd;
 	}
+	memcpy(&kdhl, temp, sizeof(kdhl));
 	istextdump = 0;
 	if (strncmp(kdhl.magic, TEXTDUMPMAGIC, sizeof kdhl) == 0) {
 		if (verbose)
@@ -567,15 +582,16 @@ DoFile(const char *savedir, const char *
 			goto closefd;
 	}
 	dumpsize = dtoh64(kdhl.dumplength);
-	firsthd = lasthd - dumpsize - sizeof kdhf;
+	firsthd = lasthd - dumpsize - sectorsize;
 	if (lseek(fd, firsthd, SEEK_SET) != firsthd ||
-	    read(fd, &kdhf, sizeof(kdhf)) != sizeof(kdhf)) {
+	    read(fd, temp, sectorsize) != sectorsize) {
 		syslog(LOG_ERR,
 		    "error reading first dump header at offset %lld in %s: %m",
 		    (long long)firsthd, device);
 		nerr++;
 		goto closefd;
 	}
+	memcpy(&kdhf, temp, sizeof(kdhf));
 
 	if (verbose >= 2) {
 		printf("First dump headers:\n");
@@ -586,7 +602,7 @@ DoFile(const char *savedir, const char *
 		printf("\n");
 	}
 
-	if (memcmp(&kdhl, &kdhf, sizeof kdhl)) {
+	if (memcmp(&kdhl, &kdhf, sizeof(kdhl))) {
 		syslog(LOG_ERR,
 		    "first and last dump headers disagree on %s", device);
 		nerr++;
@@ -603,7 +619,7 @@ DoFile(const char *savedir, const char *
 		exit(0);
 	}
 
-	if (kdhl.panicstring[0])
+	if (kdhl.panicstring[0] != '\0')
 		syslog(LOG_ALERT, "reboot after panic: %*s",
 		    (int)sizeof(kdhl.panicstring), kdhl.panicstring);
 	else
@@ -724,9 +740,10 @@ nuke:
 	if (!keep) {
 		if (verbose)
 			printf("clearing dump header\n");
-		memcpy(kdhl.magic, KERNELDUMPMAGIC_CLEARED, sizeof kdhl.magic);
+		memcpy(kdhl.magic, KERNELDUMPMAGIC_CLEARED, sizeof(kdhl.magic));
+		memcpy(temp, &kdhl, sizeof(kdhl));
 		if (lseek(fd, lasthd, SEEK_SET) != lasthd ||
-		    write(fd, &kdhl, sizeof(kdhl)) != sizeof(kdhl))
+		    write(fd, temp, sectorsize) != sectorsize)
 			syslog(LOG_ERR,
 			    "error while clearing the dump header: %m");
 	}

Modified: head/sys/amd64/amd64/minidump_machdep.c
==============================================================================
--- head/sys/amd64/amd64/minidump_machdep.c	Fri Apr 15 17:30:33 2016	(r298075)
+++ head/sys/amd64/amd64/minidump_machdep.c	Fri Apr 15 17:45:12 2016	(r298076)
@@ -56,9 +56,6 @@ CTASSERT(sizeof(struct kerneldumpheader)
  */
 #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;
 
@@ -222,6 +219,7 @@ minidumpsys(struct dumperinfo *di)
 	int error;
 	uint64_t bits;
 	uint64_t *pml4, *pdp, *pd, *pt, pa;
+	size_t size;
 	int i, ii, j, k, n, bit;
 	int retry_count;
 	struct minidumphdr mdhdr;
@@ -319,12 +317,12 @@ minidumpsys(struct dumperinfo *di)
 	dumpsize += PAGE_SIZE;
 
 	/* Determine dump offset on device. */
-	if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2) {
+	if (di->mediasize < SIZEOF_METADATA + dumpsize + di->blocksize * 2) {
 		error = E2BIG;
 		goto fail;
 	}
 	dumplo = di->mediaoffset + di->mediasize - dumpsize;
-	dumplo -= sizeof(kdh) * 2;
+	dumplo -= di->blocksize * 2;
 	progress = dumpsize;
 
 	/* Initialize mdhdr */
@@ -344,10 +342,10 @@ minidumpsys(struct dumperinfo *di)
 	    ptoa((uintmax_t)physmem) / 1048576);
 
 	/* Dump leader */
-	error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh));
+	error = dump_write_pad(di, &kdh, 0, dumplo, sizeof(kdh), &size);
 	if (error)
 		goto fail;
-	dumplo += sizeof(kdh);
+	dumplo += size;
 
 	/* Dump my header */
 	bzero(&fakepd, sizeof(fakepd));
@@ -432,10 +430,10 @@ minidumpsys(struct dumperinfo *di)
 		goto fail;
 
 	/* Dump trailer */
-	error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh));
+	error = dump_write_pad(di, &kdh, 0, dumplo, sizeof(kdh), &size);
 	if (error)
 		goto fail;
-	dumplo += sizeof(kdh);
+	dumplo += size;
 
 	/* Signal completion, signoff and exit stage left. */
 	dump_write(di, NULL, 0, 0, 0);

Modified: head/sys/kern/kern_dump.c
==============================================================================
--- head/sys/kern/kern_dump.c	Fri Apr 15 17:30:33 2016	(r298075)
+++ head/sys/kern/kern_dump.c	Fri Apr 15 17:45:12 2016	(r298076)
@@ -55,13 +55,11 @@ CTASSERT(sizeof(struct kerneldumpheader)
  */
 #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))
+#define	MD_ALIGN(x)	roundup2((off_t)(x), PAGE_SIZE)
 
 off_t dumplo;
 
 /* Handle buffered writes. */
-static char buffer[DEV_BSIZE];
 static size_t fragsz;
 
 struct dump_pa dump_map[DUMPSYS_MD_PA_NPAIRS];
@@ -125,19 +123,19 @@ dumpsys_buf_write(struct dumperinfo *di,
 	int error;
 
 	while (sz) {
-		len = DEV_BSIZE - fragsz;
+		len = di->blocksize - fragsz;
 		if (len > sz)
 			len = sz;
-		bcopy(ptr, buffer + fragsz, len);
+		memcpy((char *)di->blockbuf + fragsz, ptr, len);
 		fragsz += len;
 		ptr += len;
 		sz -= len;
-		if (fragsz == DEV_BSIZE) {
-			error = dump_write(di, buffer, 0, dumplo,
-			    DEV_BSIZE);
+		if (fragsz == di->blocksize) {
+			error = dump_write(di, di->blockbuf, 0, dumplo,
+			    di->blocksize);
 			if (error)
 				return (error);
-			dumplo += DEV_BSIZE;
+			dumplo += di->blocksize;
 			fragsz = 0;
 		}
 	}
@@ -152,8 +150,8 @@ dumpsys_buf_flush(struct dumperinfo *di)
 	if (fragsz == 0)
 		return (0);
 
-	error = dump_write(di, buffer, 0, dumplo, DEV_BSIZE);
-	dumplo += DEV_BSIZE;
+	error = dump_write(di, di->blockbuf, 0, dumplo, di->blocksize);
+	dumplo += di->blocksize;
 	fragsz = 0;
 	return (error);
 }
@@ -286,7 +284,7 @@ dumpsys_generic(struct dumperinfo *di)
 	Elf_Ehdr ehdr;
 	uint64_t dumpsize;
 	off_t hdrgap;
-	size_t hdrsz;
+	size_t hdrsz, size;
 	int error;
 
 #ifndef __powerpc__
@@ -324,15 +322,15 @@ dumpsys_generic(struct dumperinfo *di)
 	hdrsz = ehdr.e_phoff + ehdr.e_phnum * ehdr.e_phentsize;
 	fileofs = MD_ALIGN(hdrsz);
 	dumpsize += fileofs;
-	hdrgap = fileofs - DEV_ALIGN(hdrsz);
+	hdrgap = fileofs - roundup2((off_t)hdrsz, di->blocksize);
 
 	/* Determine dump offset on device. */
-	if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2) {
+	if (di->mediasize < SIZEOF_METADATA + dumpsize + di->blocksize * 2) {
 		error = ENOSPC;
 		goto fail;
 	}
 	dumplo = di->mediaoffset + di->mediasize - dumpsize;
-	dumplo -= sizeof(kdh) * 2;
+	dumplo -= di->blocksize * 2;
 
 	mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_ARCH_VERSION, dumpsize,
 	    di->blocksize);
@@ -341,10 +339,10 @@ dumpsys_generic(struct dumperinfo *di)
 	    ehdr.e_phnum - DUMPSYS_NUM_AUX_HDRS);
 
 	/* Dump leader */
-	error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh));
+	error = dump_write_pad(di, &kdh, 0, dumplo, sizeof(kdh), &size);
 	if (error)
 		goto fail;
-	dumplo += sizeof(kdh);
+	dumplo += size;
 
 	/* Dump ELF header */
 	error = dumpsys_buf_write(di, (char*)&ehdr, sizeof(ehdr));
@@ -375,7 +373,7 @@ dumpsys_generic(struct dumperinfo *di)
 		goto fail;
 
 	/* Dump trailer */
-	error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh));
+	error = dump_write_pad(di, &kdh, 0, dumplo, sizeof(kdh), &size);
 	if (error)
 		goto fail;
 

Modified: head/sys/kern/kern_shutdown.c
==============================================================================
--- head/sys/kern/kern_shutdown.c	Fri Apr 15 17:30:33 2016	(r298075)
+++ head/sys/kern/kern_shutdown.c	Fri Apr 15 17:45:12 2016	(r298076)
@@ -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 
 		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 
 		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 *
 	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)

Modified: head/sys/sys/conf.h
==============================================================================
--- head/sys/sys/conf.h	Fri Apr 15 17:30:33 2016	(r298075)
+++ head/sys/sys/conf.h	Fri Apr 15 17:45:12 2016	(r298076)
@@ -328,15 +328,18 @@ EVENTHANDLER_DECLARE(dev_clone, dev_clon
 
 struct dumperinfo {
 	dumper_t *dumper;	/* Dumping function. */
-	void    *priv;		/* Private parts. */
-	u_int   blocksize;	/* Size of block in bytes. */
+	void	*priv;		/* Private parts. */
+	u_int	blocksize;	/* Size of block in bytes. */
 	u_int	maxiosize;	/* Max size allowed for an individual I/O */
-	off_t   mediaoffset;	/* Initial offset in bytes. */
-	off_t   mediasize;	/* Space available in bytes. */
+	off_t	mediaoffset;	/* Initial offset in bytes. */
+	off_t	mediasize;	/* Space available in bytes. */
+	void	*blockbuf;	/* Buffer for padding shorter dump blocks */
 };
 
 int set_dumper(struct dumperinfo *, const char *_devname, struct thread *td);
 int dump_write(struct dumperinfo *, void *, vm_offset_t, off_t, size_t);
+int dump_write_pad(struct dumperinfo *, void *, vm_offset_t, off_t, size_t,
+    size_t *);
 int doadump(boolean_t);
 extern int dumping;		/* system is dumping */
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201604151745.u3FHjCqW021550>