Page MenuHomeFreeBSD

D34347.id103121.diff
No OneTemporary

D34347.id103121.diff

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, &sectorsize);
@@ -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

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)

Event Timeline