Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F132425863
D34347.id103121.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D34347.id103121.diff
View Options
Index: sbin/savecore/savecore.c
===================================================================
--- sbin/savecore/savecore.c
+++ sbin/savecore/savecore.c
@@ -68,6 +68,7 @@
#include <sys/param.h>
#include <sys/disk.h>
#include <sys/kerneldump.h>
+#include <sys/memrange.h>
#include <sys/mount.h>
#include <sys/stat.h>
@@ -105,7 +106,7 @@
static cap_channel_t *capsyslog;
static fileargs_t *capfa;
-static bool checkfor, compress, uncompress, clear, force, keep; /* flags */
+static bool checkfor, compress, uncompress, clear, force, keep, livecore; /* flags */
static int verbose;
static int nfound, nsaved, nerr; /* statistics */
static int maxdumps;
@@ -220,6 +221,7 @@
break;
}
xo_emit_h(xo, "{P: }{Lwc:Dump Status}{:dump_status/%s}\n", stat_str);
+ xo_emit_h(xo, "{P: }{Lwc:Livedump}{:livedump/%s}\n", livecore ? "yes" : "no");
xo_flush_h(xo);
}
@@ -354,6 +356,12 @@
(void)unlinkat(savedirfd, path, 0);
(void)snprintf(path, sizeof(path), "textdump.tar.%d.gz", bounds);
(void)unlinkat(savedirfd, path, 0);
+ (void)snprintf(path, sizeof(path), "livecore.%d", bounds);
+ (void)unlinkat(savedirfd, path, 0);
+ (void)snprintf(path, sizeof(path), "livecore.%d.gz", bounds);
+ (void)unlinkat(savedirfd, path, 0);
+ (void)snprintf(path, sizeof(path), "livecore.%d.zst", bounds);
+ (void)unlinkat(savedirfd, path, 0);
}
static void
@@ -369,6 +377,11 @@
(void)unlinkat(savedirfd, "vmcore_encrypted.last.gz", 0);
(void)unlinkat(savedirfd, "textdump.tar.last", 0);
(void)unlinkat(savedirfd, "textdump.tar.last.gz", 0);
+ (void)unlinkat(savedirfd, "livecore.last", 0);
+ (void)unlinkat(savedirfd, "livecore.last.gz", 0);
+ (void)unlinkat(savedirfd, "livecore.last.zst", 0);
+ (void)unlinkat(savedirfd, "livecore_encrypted.last", 0);
+ (void)unlinkat(savedirfd, "livecore_encrypted.last.gz", 0);
}
/*
@@ -692,6 +705,64 @@
return (0);
}
+static int
+DoLivedumpFile(int fd, off_t dumpsize, char *buf, const char *filename, FILE *fp)
+{
+ off_t offset;
+ int nr, nw, wl;
+ int error;
+ bool needmove;
+
+ /*
+ * The livedump output file will initially have the following layout:
+ * +---------------------+---------------+--------------------+
+ * | dump key (optional) | dump contents | kernel dump header |
+ * +---------------------+---------------+--------------------+
+ * ^
+ * fd position
+ *
+ * We have already read they key and header, so this routine will
+ * shrink it down to just the dump contents. This means shifting the
+ * contents to overwrite the key if it is present, and truncating the
+ * final result to dumpsize.
+ *
+ * NB: fd and fp reference the same file.
+ */
+ offset = 0;
+ needmove = ftell(fp) != 0; /* TODO: Handle -1 */
+ while (needmove && offset < dumpsize) {
+ wl = MIN(dumpsize - offset, BUFFERSIZE);
+ nr = read(fd, buf, wl);
+ if (nr != wl) {
+ if (nr == 0)
+ logmsg(LOG_WARNING,
+ "WARNING: EOF on dump device");
+ else
+ logmsg(LOG_ERR, "read error: %m");
+ nerr++;
+ return (-1);
+ }
+ nw = pwrite(fd, buf, wl, offset);
+ if (nw != wl) {
+ logmsg(LOG_ERR,
+ "write error on %s file: %m", filename);
+ logmsg(LOG_WARNING,
+ "WARNING: dump may be incomplete");
+ nerr++;
+ return (-1);
+ }
+ offset += wl;
+ if (verbose) {
+ printf("%llu\r", (unsigned long long)offset);
+ fflush(stdout);
+ }
+ }
+
+ /* Remove the vestigial kernel dump header. */
+ error = ftruncate(fd, dumpsize);
+ return (error);
+}
+
static void
DoFile(const char *savedir, int savedirfd, const char *device)
{
@@ -741,6 +812,38 @@
return;
}
+ if (livecore) {
+ /* Invoke the live dump, saved to a temporary file. */
+ fdcore = openat(savedirfd, "livedump.tmp",
+ O_RDWR | O_CREAT | O_TRUNC);
+ if (fdcore < 0) {
+ logmsg(LOG_ERR, "error opening temp file: %m");
+ exit(1);
+ }
+ printf("opened temp file, fd=%d\n", fdcore);
+ if (ioctl(fddev, MEM_INVOKE_DUMP, &fdcore) == -1) {
+ logmsg(LOG_ERR,
+ "failed to invoke live-dump on system: %m");
+ exit(1);
+ }
+
+ /* Seek to the end of the file, minus the size of the header. */
+ lasthd = lseek(fdcore, -sizeof(kdhl), SEEK_END);
+ if (lasthd == -1) {
+ printf("lseek failed!\n");
+ exit(1);
+ }
+
+ if (read(fdcore, &kdhl, sizeof(kdhl)) != sizeof(kdhl)) {
+ printf("failed to read enough!\n");
+ logmsg(LOG_ERR, "Failed to read kernel dump header");
+ goto closefd;
+ }
+ /* Reset cursor */
+ (void)lseek(fdcore, 0, SEEK_SET);
+ goto validate;
+ }
+
error = ioctl(fddev, DIOCGMEDIASIZE, &mediasize);
if (!error)
error = ioctl(fddev, DIOCGSECTORSIZE, §orsize);
@@ -776,6 +879,8 @@
goto closefd;
}
memcpy(&kdhl, temp, sizeof(kdhl));
+
+validate:
iscompressed = istextdump = false;
if (compare_magic(&kdhl, TEXTDUMPMAGIC)) {
if (verbose)
@@ -862,27 +967,37 @@
dumpextent = dtoh64(kdhl.dumpextent);
dumplength = dtoh64(kdhl.dumplength);
dumpkeysize = dtoh32(kdhl.dumpkeysize);
- firsthd = lasthd - dumpextent - sectorsize - dumpkeysize;
- if (lseek(fddev, firsthd, SEEK_SET) != firsthd ||
- read(fddev, temp, sectorsize) != (ssize_t)sectorsize) {
- logmsg(LOG_ERR,
- "error reading first dump header at offset %lld in %s: %m",
- (long long)firsthd, device);
- nerr++;
- goto closefd;
+
+ /* Get the first dump header. */
+ if (!livecore) {
+ firsthd = lasthd - dumpextent - sectorsize - dumpkeysize;
+ if (lseek(fddev, firsthd, SEEK_SET) != firsthd ||
+ read(fddev, temp, sectorsize) != (ssize_t)sectorsize) {
+ logmsg(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));
}
- memcpy(&kdhf, temp, sizeof(kdhf));
if (verbose >= 2) {
- printf("First dump headers:\n");
- printheader(xostdout, &kdhf, device, bounds, -1);
+ if (!livecore) {
+ printf("First dump headers:\n");
+ printheader(xostdout, &kdhf, device, bounds, -1);
+ }
printf("\nLast dump headers:\n");
printheader(xostdout, &kdhl, device, bounds, -1);
printf("\n");
}
- if (memcmp(&kdhl, &kdhf, sizeof(kdhl))) {
+ /*
+ * Check that the two dump headers are consistent with one another.
+ * Livedumps contain only one header.
+ */
+ if (!livecore && memcmp(&kdhl, &kdhf, sizeof(kdhl))) {
logmsg(LOG_ERR,
"first and last dump headers disagree on %s", device);
nerr++;
@@ -908,7 +1023,8 @@
if (verbose)
printf("Checking for available free space\n");
- if (!check_space(savedir, savedirfd, dumplength, bounds)) {
+ /* Live cores are already written to the filesystem. */
+ if (!livecore && !check_space(savedir, savedirfd, dumplength, bounds)) {
nerr++;
goto closefd;
}
@@ -933,16 +1049,28 @@
if (compress)
snprintf(corename, sizeof(corename), "%s.%d.gz",
istextdump ? "textdump.tar" :
- (isencrypted ? "vmcore_encrypted" : "vmcore"), bounds);
+ (livecore ? (isencrypted ? "livecore_encrypted" : "livecore") :
+ (isencrypted ? "vmcore_encrypted" : "vmcore")), bounds);
else if (iscompressed && !isencrypted && !uncompress)
- snprintf(corename, sizeof(corename), "vmcore.%d.%s", bounds,
+ snprintf(corename, sizeof(corename), "%s.%d.%s",
+ livecore ? "livecore" : "vmcore", bounds,
(kdhl.compression == KERNELDUMP_COMP_GZIP) ? "gz" : "zst");
else
snprintf(corename, sizeof(corename), "%s.%d",
istextdump ? "textdump.tar" :
- (isencrypted ? "vmcore_encrypted" : "vmcore"), bounds);
- fdcore = openat(savedirfd, corename, O_WRONLY | O_CREAT | O_TRUNC,
- 0600);
+ (livecore ? (isencrypted ? "livecore_encrypted" : "livecore") :
+ (isencrypted ? "vmcore_encrypted" : "vmcore")), bounds);
+ if (livecore) {
+ if (verbose)
+ printf("renaming livedump.tmp to %s\n", corename);
+ if (renameat(savedirfd, "livedump.tmp", savedirfd, corename) != 0) {
+ logmsg(LOG_ERR, "renameat failed: %m");
+ exit(1);
+ }
+ } else {
+ fdcore = openat(savedirfd, corename, O_WRONLY | O_CREAT | O_TRUNC,
+ 0600);
+ }
if (fdcore < 0) {
logmsg(LOG_ERR, "open(%s): %m", corename);
fclose(info);
@@ -961,7 +1089,7 @@
nerr++;
goto closefd;
}
- fdcore = -1;
+ //fdcore = -1;
xostyle = xo_get_style(NULL);
xoinfo = xo_create_to_file(info, xostyle, 0);
@@ -990,7 +1118,9 @@
goto closeall;
}
- if (read(fddev, dumpkey, dumpkeysize) != (ssize_t)dumpkeysize) {
+ /* For live dumps we are reading from the file, not the device. */
+ if (read(livecore ? fdcore : fddev, dumpkey, dumpkeysize) !=
+ (ssize_t)dumpkeysize) {
logmsg(LOG_ERR, "Unable to read kernel dump key: %m.");
nerr++;
goto closeall;
@@ -1013,6 +1143,9 @@
if (DoTextdumpFile(fddev, dumplength, lasthd, buf, device,
corename, core) < 0)
goto closeall;
+ } else if (livecore) {
+ if (DoLivedumpFile(fdcore, dumplength, buf, corename, core) < 0)
+ goto closeall;
} else {
if (DoRegularFile(fddev, dumplength, sectorsize,
!(compress || iscompressed || isencrypted),
@@ -1045,12 +1178,16 @@
if ((iscompressed && !uncompress) || compress) {
snprintf(linkname, sizeof(linkname), "%s.last.%s",
istextdump ? "textdump.tar" :
- (isencrypted ? "vmcore_encrypted" : "vmcore"),
+ (livecore ?
+ (isencrypted ? "livecore" : "livecore_encrypted") :
+ (isencrypted ? "vmcore_encrypted" : "vmcore")),
(kdhl.compression == KERNELDUMP_COMP_ZSTD) ? "zst" : "gz");
} else {
snprintf(linkname, sizeof(linkname), "%s.last",
istextdump ? "textdump.tar" :
- (isencrypted ? "vmcore_encrypted" : "vmcore"));
+ (livecore ?
+ (isencrypted ? "livecore" : "livecore_encrypted") :
+ (isencrypted ? "vmcore_encrypted" : "vmcore")));
}
if (symlinkat(corename, savedirfd, linkname) == -1) {
logmsg(LOG_WARNING, "unable to create symlink %s/%s: %m",
@@ -1063,7 +1200,7 @@
printf("dump saved\n");
nuke:
- if (!keep) {
+ if (!keep && !livecore) {
if (verbose)
printf("clearing dump header\n");
memcpy(kdhl.magic, KERNELDUMPMAGIC_CLEARED, sizeof(kdhl.magic));
@@ -1214,6 +1351,7 @@
xo_error("%s\n%s\n%s\n",
"usage: savecore -c [-v] [device ...]",
" savecore -C [-v] [device ...]",
+ " savecore -L [-fuv] [-m maxdumps] [directory]",
" savecore [-fkvz] [-m maxdumps] [directory [device ...]]");
exit(1);
}
@@ -1226,7 +1364,7 @@
char **devs;
int i, ch, error, savedirfd;
- checkfor = compress = clear = force = keep = false;
+ checkfor = compress = clear = force = keep = livecore = false;
verbose = 0;
nfound = nsaved = nerr = 0;
savedir = ".";
@@ -1238,7 +1376,7 @@
if (argc < 0)
exit(1);
- while ((ch = getopt(argc, argv, "Ccfkm:uvz")) != -1)
+ while ((ch = getopt(argc, argv, "CcfkLm:uvz")) != -1)
switch(ch) {
case 'C':
checkfor = true;
@@ -1252,6 +1390,9 @@
case 'k':
keep = true;
break;
+ case 'L':
+ livecore = true;
+ break;
case 'm':
maxdumps = atoi(optarg);
if (maxdumps <= 0) {
@@ -1280,6 +1421,8 @@
usage();
if (compress && uncompress)
usage();
+ if (livecore && (checkfor || clear || compress || keep))
+ usage();
argc -= optind;
argv += optind;
if (argc >= 1 && !checkfor && !clear) {
@@ -1292,7 +1435,15 @@
argc--;
argv++;
}
- if (argc == 0)
+ if (livecore) {
+ if (argc > 0)
+ usage();
+
+ /* Always need /dev/mem to invoke the dump */
+ devs = malloc(sizeof(char *));
+ devs[0] = strdup("/dev/mem");
+ argc++;
+ } else if (argc == 0)
devs = enum_dumpdevs(&argc);
else
devs = devify(argc, argv);
@@ -1305,6 +1456,10 @@
(void)cap_rights_init(&rights, CAP_CREATE, CAP_FCNTL, CAP_FSTATAT,
CAP_FSTATFS, CAP_PREAD, CAP_SYMLINKAT, CAP_FTRUNCATE, CAP_UNLINKAT,
CAP_WRITE);
+ if (livecore)
+ /* Rename rights are needed. */
+ cap_rights_set(&rights, CAP_RENAMEAT_SOURCE,
+ CAP_RENAMEAT_TARGET);
if (caph_rights_limit(savedirfd, &rights) < 0) {
logmsg(LOG_ERR, "cap_rights_limit(): %m");
exit(1);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Oct 17, 8:17 PM (18 h, 41 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
23845139
Default Alt Text
D34347.id103121.diff (11 KB)
Attached To
Mode
D34347: savecore: add an option to save a live minidump
Attached
Detach File
Event Timeline
Log In to Comment