svn commit: r347192 - in head: sbin/dumpon sys/dev/null sys/geom sys/geom/raid sys/kern sys/netinet/netdump sys/sys
Conrad Meyer
cem at FreeBSD.org
Mon May 6 18:24:10 UTC 2019
Author: cem
Date: Mon May 6 18:24:07 2019
New Revision: 347192
URL: https://svnweb.freebsd.org/changeset/base/347192
Log:
List-ify kernel dump device configuration
Allow users to specify multiple dump configurations in a prioritized list.
This enables fallback to secondary device(s) if primary dump fails. E.g.,
one might configure a preference for netdump, but fallback to disk dump as a
second choice if netdump is unavailable.
This change does not list-ify netdump configuration, which is tracked
separately from ordinary disk dumps internally; only one netdump
configuration can be made at a time, for now. It also does not implement
IPv6 netdump.
savecore(8) is already capable of scanning and iterating multiple devices
from /etc/fstab or passed on the command line.
This change doesn't update the rc or loader variables 'dumpdev' in any way;
it can still be set to configure a single dump device, and rc.d/savecore
still uses it as a single device. Only dumpon(8) is updated to be able to
configure the more complicated configurations for now.
As part of revving the ABI, unify netdump and disk dump configuration ioctl
/ structure, and leave room for ipv6 netdump as a future possibility.
Backwards-compatibility ioctls are added to smooth ABI transition,
especially for developers who may not keep kernel and userspace perfectly
synced.
Reviewed by: markj, scottl (earlier version)
Relnotes: maybe
Sponsored by: Dell EMC Isilon
Differential Revision: https://reviews.freebsd.org/D19996
Modified:
head/sbin/dumpon/dumpon.8
head/sbin/dumpon/dumpon.c
head/sys/dev/null/null.c
head/sys/geom/geom_dev.c
head/sys/geom/raid/g_raid.h
head/sys/kern/kern_shutdown.c
head/sys/netinet/netdump/netdump.h
head/sys/netinet/netdump/netdump_client.c
head/sys/sys/conf.h
head/sys/sys/disk.h
head/sys/sys/param.h
Modified: head/sbin/dumpon/dumpon.8
==============================================================================
--- head/sbin/dumpon/dumpon.8 Mon May 6 16:54:35 2019 (r347191)
+++ head/sbin/dumpon/dumpon.8 Mon May 6 18:24:07 2019 (r347192)
@@ -28,7 +28,7 @@
.\" From: @(#)swapon.8 8.1 (Berkeley) 6/5/93
.\" $FreeBSD$
.\"
-.Dd November 17, 2018
+.Dd May 6, 2019
.Dt DUMPON 8
.Os
.Sh NAME
@@ -36,12 +36,16 @@
.Nd "specify a device for crash dumps"
.Sh SYNOPSIS
.Nm
+.Op Fl i Ar index
+.Op Fl r
.Op Fl v
.Op Fl k Ar pubkey
.Op Fl Z
.Op Fl z
.Ar device
.Nm
+.Op Fl i Ar index
+.Op Fl r
.Op Fl v
.Op Fl k Ar pubkey
.Op Fl Z
@@ -72,8 +76,38 @@ and
.Va dumpon_flags .
For more information on this usage, see
.Xr rc.conf 5 .
+.Pp
+Starting in
+.Fx 13.0 ,
+.Nm
+can configure a series of fallback dump devices.
+For example, an administrator may prefer
+.Xr netdump 4
+by default, but if the
+.Xr netdump 4
+service cannot be reached or some other failure occurs, they might choose a
+local disk dump as a second choice option.
.Ss General options
.Bl -tag -width _k_pubkey
+.It Fl i Ar index
+Insert the specified dump configuration into the prioritized fallback dump
+device list at the specified index, starting at zero.
+.Pp
+If
+.Fl i
+is not specified, the configured dump device is appended to the prioritized
+list.
+.It Fl r
+Remove the specified dump device configuration or configurations from the
+fallback dump device list rather than inserting or appending it.
+In contrast,
+.Do
+.Nm
+off
+.Dc
+removes all configured devices.
+Conflicts with
+.Fl i .
.It Fl k Ar pubkey
Configure encrypted kernel dumps.
.Pp
@@ -96,7 +130,7 @@ The
.Va pubkey
file should be a PEM-formatted RSA key of at least 1024 bits.
.It Fl l
-List the currently configured dump device, or /dev/null if no device is
+List the currently configured dump device(s), or /dev/null if no devices are
configured.
.It Fl v
Enable verbose mode.
Modified: head/sbin/dumpon/dumpon.c
==============================================================================
--- head/sbin/dumpon/dumpon.c Mon May 6 16:54:35 2019 (r347191)
+++ head/sbin/dumpon/dumpon.c Mon May 6 18:24:07 2019 (r347192)
@@ -86,8 +86,8 @@ static void _Noreturn
usage(void)
{
fprintf(stderr,
- "usage: dumpon [-v] [-k <pubkey>] [-Zz] <device>\n"
- " dumpon [-v] [-k <pubkey>] [-Zz]\n"
+ "usage: dumpon [-i index] [-r] [-v] [-k <pubkey>] [-Zz] <device>\n"
+ " dumpon [-i index] [-r] [-v] [-k <pubkey>] [-Zz]\n"
" [-g <gateway>] -s <server> -c <client> <iface>\n"
" dumpon [-v] off\n"
" dumpon [-v] -l\n");
@@ -290,8 +290,10 @@ genkey(const char *pubkeyfile, struct diocskerneldump_
static void
listdumpdev(void)
{
+ static char ip[200];
+
char dumpdev[PATH_MAX];
- struct netdump_conf ndconf;
+ struct diocskerneldump_arg ndconf;
size_t len;
const char *sysctlname = "kern.shutdown.dumpdevname";
int fd;
@@ -308,10 +310,18 @@ listdumpdev(void)
if (strlen(dumpdev) == 0)
(void)strlcpy(dumpdev, _PATH_DEVNULL, sizeof(dumpdev));
- if (verbose)
- printf("kernel dumps on ");
- printf("%s\n", dumpdev);
+ if (verbose) {
+ char *ctx, *dd;
+ unsigned idx;
+ printf("kernel dumps on priority: device\n");
+ idx = 0;
+ ctx = dumpdev;
+ while ((dd = strsep(&ctx, ",")) != NULL)
+ printf("%u: %s\n", idx++, dd);
+ } else
+ printf("%s\n", dumpdev);
+
/* If netdump is enabled, print the configuration parameters. */
if (verbose) {
fd = open(_PATH_NETDUMP, O_RDONLY);
@@ -320,16 +330,22 @@ listdumpdev(void)
err(EX_OSERR, "opening %s", _PATH_NETDUMP);
return;
}
- if (ioctl(fd, NETDUMPGCONF, &ndconf) != 0) {
+ if (ioctl(fd, DIOCGKERNELDUMP, &ndconf) != 0) {
if (errno != ENXIO)
- err(EX_OSERR, "ioctl(NETDUMPGCONF)");
+ err(EX_OSERR, "ioctl(DIOCGKERNELDUMP)");
(void)close(fd);
return;
}
- printf("server address: %s\n", inet_ntoa(ndconf.ndc_server));
- printf("client address: %s\n", inet_ntoa(ndconf.ndc_client));
- printf("gateway address: %s\n", inet_ntoa(ndconf.ndc_gateway));
+ printf("server address: %s\n",
+ inet_ntop(ndconf.kda_af, &ndconf.kda_server, ip,
+ sizeof(ip)));
+ printf("client address: %s\n",
+ inet_ntop(ndconf.kda_af, &ndconf.kda_client, ip,
+ sizeof(ip)));
+ printf("gateway address: %s\n",
+ inet_ntop(ndconf.kda_af, &ndconf.kda_gateway, ip,
+ sizeof(ip)));
(void)close(fd);
}
}
@@ -359,19 +375,20 @@ int
main(int argc, char *argv[])
{
char dumpdev[PATH_MAX];
- struct diocskerneldump_arg _kda, *kdap;
- struct netdump_conf ndconf;
+ struct diocskerneldump_arg ndconf, *kdap;
struct addrinfo hints, *res;
const char *dev, *pubkeyfile, *server, *client, *gateway;
int ch, error, fd;
- bool enable, gzip, list, netdump, zstd;
+ bool gzip, list, netdump, zstd, insert, rflag;
+ uint8_t ins_idx;
- gzip = list = netdump = zstd = false;
+ gzip = list = netdump = zstd = insert = rflag = false;
kdap = NULL;
pubkeyfile = NULL;
server = client = gateway = NULL;
+ ins_idx = KDA_APPEND;
- while ((ch = getopt(argc, argv, "c:g:k:ls:vZz")) != -1)
+ while ((ch = getopt(argc, argv, "c:g:i:k:lrs:vZz")) != -1)
switch ((char)ch) {
case 'c':
client = optarg;
@@ -379,12 +396,28 @@ main(int argc, char *argv[])
case 'g':
gateway = optarg;
break;
+ case 'i':
+ {
+ int i;
+
+ i = atoi(optarg);
+ if (i < 0 || i >= KDA_APPEND - 1)
+ errx(EX_USAGE,
+ "-i index must be between zero and %d.",
+ (int)KDA_APPEND - 2);
+ insert = true;
+ ins_idx = i;
+ }
+ break;
case 'k':
pubkeyfile = optarg;
break;
case 'l':
list = true;
break;
+ case 'r':
+ rflag = true;
+ break;
case 's':
server = optarg;
break;
@@ -404,6 +437,9 @@ main(int argc, char *argv[])
if (gzip && zstd)
errx(EX_USAGE, "The -z and -Z options are mutually exclusive.");
+ if (insert && rflag)
+ errx(EX_USAGE, "The -i and -r options are mutually exclusive.");
+
argc -= optind;
argv += optind;
@@ -422,31 +458,30 @@ main(int argc, char *argv[])
#endif
if (server != NULL && client != NULL) {
- enable = true;
dev = _PATH_NETDUMP;
netdump = true;
- kdap = &ndconf.ndc_kda;
} else if (server == NULL && client == NULL && argc > 0) {
- enable = strcmp(argv[0], "off") != 0;
- dev = enable ? argv[0] : _PATH_DEVNULL;
+ if (strcmp(argv[0], "off") == 0) {
+ rflag = true;
+ dev = _PATH_DEVNULL;
+ } else
+ dev = argv[0];
netdump = false;
- kdap = &_kda;
} else
usage();
fd = opendumpdev(dev, dumpdev);
- if (!netdump && !gzip)
+ if (!netdump && !gzip && !rflag)
check_size(fd, dumpdev);
+ kdap = &ndconf;
bzero(kdap, sizeof(*kdap));
- kdap->kda_enable = 0;
- if (ioctl(fd, DIOCSKERNELDUMP, kdap) != 0)
- err(EX_OSERR, "ioctl(DIOCSKERNELDUMP)");
- if (!enable)
- exit(EX_OK);
- explicit_bzero(kdap, sizeof(*kdap));
- kdap->kda_enable = 1;
+ if (rflag)
+ kdap->kda_index = KDA_REMOVE;
+ else
+ kdap->kda_index = ins_idx;
+
kdap->kda_compression = KERNELDUMP_COMP_NONE;
if (zstd)
kdap->kda_compression = KERNELDUMP_COMP_ZSTD;
@@ -467,12 +502,12 @@ main(int argc, char *argv[])
((struct sockaddr_in *)(void *)res->ai_addr)->sin_addr);
freeaddrinfo(res);
- if (strlcpy(ndconf.ndc_iface, argv[0],
- sizeof(ndconf.ndc_iface)) >= sizeof(ndconf.ndc_iface))
+ if (strlcpy(ndconf.kda_iface, argv[0],
+ sizeof(ndconf.kda_iface)) >= sizeof(ndconf.kda_iface))
errx(EX_USAGE, "invalid interface name '%s'", argv[0]);
- if (inet_aton(server, &ndconf.ndc_server) == 0)
+ if (inet_aton(server, &ndconf.kda_server.in4) == 0)
errx(EX_USAGE, "invalid server address '%s'", server);
- if (inet_aton(client, &ndconf.ndc_client) == 0)
+ if (inet_aton(client, &ndconf.kda_client.in4) == 0)
errx(EX_USAGE, "invalid client address '%s'", client);
if (gateway == NULL) {
@@ -485,39 +520,41 @@ main(int argc, char *argv[])
gateway = server;
}
}
- if (inet_aton(gateway, &ndconf.ndc_gateway) == 0)
+ if (inet_aton(gateway, &ndconf.kda_gateway.in4) == 0)
errx(EX_USAGE, "invalid gateway address '%s'", gateway);
+ ndconf.kda_af = AF_INET;
+ }
#ifdef HAVE_CRYPTO
- if (pubkeyfile != NULL)
- genkey(pubkeyfile, kdap);
+ if (pubkeyfile != NULL)
+ genkey(pubkeyfile, kdap);
#endif
- error = ioctl(fd, NETDUMPSCONF, &ndconf);
- if (error != 0)
- error = errno;
- explicit_bzero(kdap->kda_encryptedkey,
- kdap->kda_encryptedkeysize);
- free(kdap->kda_encryptedkey);
- explicit_bzero(kdap, sizeof(*kdap));
- if (error != 0)
- errc(EX_OSERR, error, "ioctl(NETDUMPSCONF)");
- } else {
-#ifdef HAVE_CRYPTO
- if (pubkeyfile != NULL)
- genkey(pubkeyfile, kdap);
-#endif
- error = ioctl(fd, DIOCSKERNELDUMP, kdap);
- if (error != 0)
- error = errno;
- explicit_bzero(kdap->kda_encryptedkey,
- kdap->kda_encryptedkeysize);
- free(kdap->kda_encryptedkey);
- explicit_bzero(kdap, sizeof(*kdap));
- if (error != 0)
- errc(EX_OSERR, error, "ioctl(DIOCSKERNELDUMP)");
+ error = ioctl(fd, DIOCSKERNELDUMP, kdap);
+ if (error != 0)
+ error = errno;
+ explicit_bzero(kdap->kda_encryptedkey, kdap->kda_encryptedkeysize);
+ free(kdap->kda_encryptedkey);
+ explicit_bzero(kdap, sizeof(*kdap));
+ if (error != 0) {
+ if (netdump) {
+ /*
+ * Be slightly less user-hostile for some common
+ * errors, especially as users don't have any great
+ * discoverability into which NICs support netdump.
+ */
+ if (error == ENXIO)
+ errx(EX_OSERR, "Unable to configure netdump "
+ "because the interface's link is down.");
+ else if (error == ENODEV)
+ errx(EX_OSERR, "Unable to configure netdump "
+ "because the interface driver does not yet "
+ "support netdump.");
+ }
+ errc(EX_OSERR, error, "ioctl(DIOCSKERNELDUMP)");
}
+
if (verbose)
- printf("kernel dumps on %s\n", dumpdev);
+ listdumpdev();
exit(EX_OK);
}
Modified: head/sys/dev/null/null.c
==============================================================================
--- head/sys/dev/null/null.c Mon May 6 16:54:35 2019 (r347191)
+++ head/sys/dev/null/null.c Mon May 6 18:24:07 2019 (r347192)
@@ -106,15 +106,26 @@ static int
null_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data __unused,
int flags __unused, struct thread *td)
{
+ struct diocskerneldump_arg kda;
int error;
error = 0;
switch (cmd) {
#ifdef COMPAT_FREEBSD11
case DIOCSKERNELDUMP_FREEBSD11:
+ gone_in(13, "FreeBSD 11.x ABI compat");
+ /* FALLTHROUGH */
#endif
+#ifdef COMPAT_FREEBSD12
+ case DIOCSKERNELDUMP_FREEBSD12:
+ if (cmd == DIOCSKERNELDUMP_FREEBSD12)
+ gone_in(14, "FreeBSD 12.x ABI compat");
+ /* FALLTHROUGH */
+#endif
case DIOCSKERNELDUMP:
- error = clear_dumper(td);
+ bzero(&kda, sizeof(kda));
+ kda.kda_index = KDA_REMOVE_ALL;
+ error = dumper_remove(NULL, &kda);
break;
case FIONBIO:
break;
Modified: head/sys/geom/geom_dev.c
==============================================================================
--- head/sys/geom/geom_dev.c Mon May 6 16:54:35 2019 (r347191)
+++ head/sys/geom/geom_dev.c Mon May 6 18:24:07 2019 (r347192)
@@ -135,15 +135,14 @@ g_dev_fini(struct g_class *mp)
}
static int
-g_dev_setdumpdev(struct cdev *dev, struct diocskerneldump_arg *kda,
- struct thread *td)
+g_dev_setdumpdev(struct cdev *dev, struct diocskerneldump_arg *kda)
{
struct g_kerneldump kd;
struct g_consumer *cp;
int error, len;
- if (dev == NULL || kda == NULL)
- return (clear_dumper(td));
+ MPASS(dev != NULL && kda != NULL);
+ MPASS(kda->kda_index != KDA_REMOVE);
cp = dev->si_drv2;
len = sizeof(kd);
@@ -154,9 +153,7 @@ g_dev_setdumpdev(struct cdev *dev, struct diocskerneld
if (error != 0)
return (error);
- error = set_dumper(&kd.di, devtoname(dev), td, kda->kda_compression,
- kda->kda_encryption, kda->kda_key, kda->kda_encryptedkeysize,
- kda->kda_encryptedkey);
+ error = dumper_insert(&kd.di, devtoname(dev), kda);
if (error == 0)
dev->si_flags |= SI_DUMPDEV;
@@ -173,7 +170,7 @@ init_dumpdev(struct cdev *dev)
size_t len;
bzero(&kda, sizeof(kda));
- kda.kda_enable = 1;
+ kda.kda_index = KDA_APPEND;
if (dumpdev == NULL)
return (0);
@@ -190,7 +187,7 @@ init_dumpdev(struct cdev *dev)
if (error != 0)
return (error);
- error = g_dev_setdumpdev(dev, &kda, curthread);
+ error = g_dev_setdumpdev(dev, &kda);
if (error == 0) {
freeenv(dumpdev);
dumpdev = NULL;
@@ -509,6 +506,9 @@ g_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data
struct g_provider *pp;
off_t offset, length, chunk, odd;
int i, error;
+#ifdef COMPAT_FREEBSD12
+ struct diocskerneldump_arg kda_copy;
+#endif
cp = dev->si_drv2;
pp = cp->provider;
@@ -547,31 +547,55 @@ g_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data
{
struct diocskerneldump_arg kda;
+ gone_in(13, "FreeBSD 11.x ABI compat");
+
bzero(&kda, sizeof(kda));
kda.kda_encryption = KERNELDUMP_ENC_NONE;
- kda.kda_enable = (uint8_t)*(u_int *)data;
- if (kda.kda_enable == 0)
- error = g_dev_setdumpdev(NULL, NULL, td);
+ kda.kda_index = (*(u_int *)data ? 0 : KDA_REMOVE_ALL);
+ if (kda.kda_index == KDA_REMOVE_ALL)
+ error = dumper_remove(devtoname(dev), &kda);
else
- error = g_dev_setdumpdev(dev, &kda, td);
+ error = g_dev_setdumpdev(dev, &kda);
break;
}
#endif
+#ifdef COMPAT_FREEBSD12
+ case DIOCSKERNELDUMP_FREEBSD12:
+ {
+ struct diocskerneldump_arg_freebsd12 *kda12;
+
+ gone_in(14, "FreeBSD 12.x ABI compat");
+
+ kda12 = (void *)data;
+ memcpy(&kda_copy, kda12, sizeof(kda_copy));
+ kda_copy.kda_index = (kda12->kda12_enable ?
+ 0 : KDA_REMOVE_ALL);
+
+ explicit_bzero(kda12, sizeof(*kda12));
+ /* Kludge to pass kda_copy to kda in fallthrough. */
+ data = (void *)&kda_copy;
+ }
+ /* FALLTHROUGH */
+#endif
case DIOCSKERNELDUMP:
{
struct diocskerneldump_arg *kda;
uint8_t *encryptedkey;
kda = (struct diocskerneldump_arg *)data;
- if (kda->kda_enable == 0) {
- error = g_dev_setdumpdev(NULL, NULL, td);
+ if (kda->kda_index == KDA_REMOVE_ALL ||
+ kda->kda_index == KDA_REMOVE_DEV ||
+ kda->kda_index == KDA_REMOVE) {
+ error = dumper_remove(devtoname(dev), kda);
+ explicit_bzero(kda, sizeof(*kda));
break;
}
if (kda->kda_encryption != KERNELDUMP_ENC_NONE) {
- if (kda->kda_encryptedkeysize <= 0 ||
+ if (kda->kda_encryptedkeysize == 0 ||
kda->kda_encryptedkeysize >
KERNELDUMP_ENCKEY_MAX_SIZE) {
+ explicit_bzero(kda, sizeof(*kda));
return (EINVAL);
}
encryptedkey = malloc(kda->kda_encryptedkeysize, M_TEMP,
@@ -583,7 +607,7 @@ g_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data
}
if (error == 0) {
kda->kda_encryptedkey = encryptedkey;
- error = g_dev_setdumpdev(dev, kda, td);
+ error = g_dev_setdumpdev(dev, kda);
}
if (encryptedkey != NULL) {
explicit_bzero(encryptedkey, kda->kda_encryptedkeysize);
@@ -859,8 +883,13 @@ g_dev_orphan(struct g_consumer *cp)
g_trace(G_T_TOPOLOGY, "g_dev_orphan(%p(%s))", cp, cp->geom->name);
/* Reset any dump-area set on this device */
- if (dev->si_flags & SI_DUMPDEV)
- (void)clear_dumper(curthread);
+ if (dev->si_flags & SI_DUMPDEV) {
+ struct diocskerneldump_arg kda;
+
+ bzero(&kda, sizeof(kda));
+ kda.kda_index = KDA_REMOVE_DEV;
+ (void)dumper_remove(devtoname(dev), &kda);
+ }
/* Destroy the struct cdev *so we get no more requests */
delist_dev(dev);
Modified: head/sys/geom/raid/g_raid.h
==============================================================================
--- head/sys/geom/raid/g_raid.h Mon May 6 16:54:35 2019 (r347191)
+++ head/sys/geom/raid/g_raid.h Mon May 6 18:24:07 2019 (r347192)
@@ -155,7 +155,6 @@ struct g_raid_disk {
struct g_raid_softc *d_softc; /* Back-pointer to softc. */
struct g_consumer *d_consumer; /* GEOM disk consumer. */
void *d_md_data; /* Disk's metadata storage. */
- struct g_kerneldump d_kd; /* Kernel dumping method/args. */
int d_candelete; /* BIO_DELETE supported. */
uint64_t d_flags; /* Additional flags. */
u_int d_state; /* Disk state. */
@@ -164,6 +163,7 @@ struct g_raid_disk {
int d_read_errs; /* Count of the read errors */
TAILQ_HEAD(, g_raid_subdisk) d_subdisks; /* List of subdisks. */
TAILQ_ENTRY(g_raid_disk) d_next; /* Next disk in the node. */
+ struct g_kerneldump d_kd; /* Kernel dumping method/args. */
};
#define G_RAID_SUBDISK_S_NONE 0x00 /* Absent. */
Modified: head/sys/kern/kern_shutdown.c
==============================================================================
--- head/sys/kern/kern_shutdown.c Mon May 6 16:54:35 2019 (r347191)
+++ head/sys/kern/kern_shutdown.c Mon May 6 18:24:07 2019 (r347192)
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include "opt_ekcd.h"
#include "opt_kdb.h"
#include "opt_panic.h"
+#include "opt_printf.h"
#include "opt_sched.h"
#include "opt_watchdog.h"
@@ -53,6 +54,7 @@ __FBSDID("$FreeBSD$");
#include <sys/conf.h>
#include <sys/compressor.h>
#include <sys/cons.h>
+#include <sys/disk.h>
#include <sys/eventhandler.h>
#include <sys/filedesc.h>
#include <sys/jail.h>
@@ -69,6 +71,7 @@ __FBSDID("$FreeBSD$");
#include <sys/reboot.h>
#include <sys/resourcevar.h>
#include <sys/rwlock.h>
+#include <sys/sbuf.h>
#include <sys/sched.h>
#include <sys/smp.h>
#include <sys/sysctl.h>
@@ -209,8 +212,17 @@ const char *panicstr;
int dumping; /* system is dumping */
int rebooting; /* system is rebooting */
-static struct dumperinfo dumper; /* our selected dumper */
+/*
+ * Used to serialize between sysctl kern.shutdown.dumpdevname and list
+ * modifications via ioctl.
+ */
+static struct mtx dumpconf_list_lk;
+MTX_SYSINIT(dumper_configs, &dumpconf_list_lk, "dumper config list", MTX_DEF);
+/* Our selected dumper(s). */
+static TAILQ_HEAD(dumpconflist, dumperinfo) dumper_configs =
+ TAILQ_HEAD_INITIALIZER(dumper_configs);
+
/* Context information for dump-debuggers. */
static struct pcb dumppcb; /* Registers. */
lwpid_t dumptid; /* Thread ID. */
@@ -364,7 +376,7 @@ doadump(boolean_t textdump)
error = 0;
if (dumping)
return (EBUSY);
- if (dumper.dumper == NULL)
+ if (TAILQ_EMPTY(&dumper_configs))
return (ENXIO);
savectx(&dumppcb);
@@ -375,12 +387,19 @@ doadump(boolean_t textdump)
#ifdef DDB
if (textdump && textdump_pending) {
coredump = FALSE;
- textdump_dumpsys(&dumper);
+ textdump_dumpsys(TAILQ_FIRST(&dumper_configs));
}
#endif
- if (coredump)
- error = dumpsys(&dumper);
+ if (coredump) {
+ struct dumperinfo *di;
+ TAILQ_FOREACH(di, &dumper_configs, di_next) {
+ error = dumpsys(di);
+ if (error == 0)
+ break;
+ }
+ }
+
dumping--;
return (error);
}
@@ -952,10 +971,36 @@ kthread_shutdown(void *arg, int howto)
printf("done\n");
}
-static char dumpdevname[sizeof(((struct cdev*)NULL)->si_name)];
-SYSCTL_STRING(_kern_shutdown, OID_AUTO, dumpdevname, CTLFLAG_RD,
- dumpdevname, 0, "Device for kernel dumps");
+static int
+dumpdevname_sysctl_handler(SYSCTL_HANDLER_ARGS)
+{
+ char buf[256];
+ struct dumperinfo *di;
+ struct sbuf sb;
+ int error;
+ error = sysctl_wire_old_buffer(req, 0);
+ if (error != 0)
+ return (error);
+
+ sbuf_new_for_sysctl(&sb, buf, sizeof(buf), req);
+
+ mtx_lock(&dumpconf_list_lk);
+ TAILQ_FOREACH(di, &dumper_configs, di_next) {
+ if (di != TAILQ_FIRST(&dumper_configs))
+ sbuf_putc(&sb, ',');
+ sbuf_cat(&sb, di->di_devname);
+ }
+ mtx_unlock(&dumpconf_list_lk);
+
+ error = sbuf_finish(&sb);
+ sbuf_delete(&sb);
+ return (error);
+}
+SYSCTL_PROC(_kern_shutdown, OID_AUTO, dumpdevname, CTLTYPE_STRING | CTLFLAG_RD,
+ &dumper_configs, 0, dumpdevname_sysctl_handler, "A",
+ "Device(s) for kernel dumps");
+
static int _dump_append(struct dumperinfo *di, void *virtual,
vm_offset_t physical, size_t length);
@@ -1092,31 +1137,67 @@ kerneldumpcomp_destroy(struct dumperinfo *di)
free(kdcomp, M_DUMPER);
}
+/*
+ * Must not be present on global list.
+ */
+static void
+free_single_dumper(struct dumperinfo *di)
+{
+
+ if (di == NULL)
+ return;
+
+ if (di->blockbuf != NULL) {
+ explicit_bzero(di->blockbuf, di->blocksize);
+ free(di->blockbuf, M_DUMPER);
+ }
+
+ kerneldumpcomp_destroy(di);
+
+#ifdef EKCD
+ if (di->kdcrypto != NULL) {
+ explicit_bzero(di->kdcrypto, sizeof(*di->kdcrypto) +
+ di->kdcrypto->kdc_dumpkeysize);
+ free(di->kdcrypto, M_EKCD);
+ }
+#endif
+
+ explicit_bzero(di, sizeof(*di));
+ free(di, M_DUMPER);
+}
+
/* Registration of dumpers */
int
-set_dumper(struct dumperinfo *di, const char *devname, struct thread *td,
- uint8_t compression, uint8_t encryption, const uint8_t *key,
- uint32_t encryptedkeysize, const uint8_t *encryptedkey)
+dumper_insert(const struct dumperinfo *di_template, const char *devname,
+ const struct diocskerneldump_arg *kda)
{
- size_t wantcopy;
+ struct dumperinfo *newdi, *listdi;
+ bool inserted;
+ uint8_t index;
int error;
- error = priv_check(td, PRIV_SETDUMPER);
+ index = kda->kda_index;
+ MPASS(index != KDA_REMOVE && index != KDA_REMOVE_DEV &&
+ index != KDA_REMOVE_ALL);
+
+ error = priv_check(curthread, PRIV_SETDUMPER);
if (error != 0)
return (error);
- if (dumper.dumper != NULL)
- return (EBUSY);
- dumper = *di;
- dumper.blockbuf = NULL;
- dumper.kdcrypto = NULL;
- dumper.kdcomp = NULL;
+ newdi = malloc(sizeof(*newdi) + strlen(devname) + 1, M_DUMPER, M_WAITOK
+ | M_ZERO);
+ memcpy(newdi, di_template, sizeof(*newdi));
+ newdi->blockbuf = NULL;
+ newdi->kdcrypto = NULL;
+ newdi->kdcomp = NULL;
+ strcpy(newdi->di_devname, devname);
- if (encryption != KERNELDUMP_ENC_NONE) {
+ if (kda->kda_encryption != KERNELDUMP_ENC_NONE) {
#ifdef EKCD
- dumper.kdcrypto = kerneldumpcrypto_create(di->blocksize,
- encryption, key, encryptedkeysize, encryptedkey);
- if (dumper.kdcrypto == NULL) {
+ newdi->kdcrypto = kerneldumpcrypto_create(di_template->blocksize,
+ kda->kda_encryption, kda->kda_key,
+ kda->kda_encryptedkeysize, kda->kda_encryptedkey);
+ if (newdi->kdcrypto == NULL) {
error = EINVAL;
goto cleanup;
}
@@ -1125,66 +1206,117 @@ set_dumper(struct dumperinfo *di, const char *devname,
goto cleanup;
#endif
}
-
- wantcopy = strlcpy(dumpdevname, devname, sizeof(dumpdevname));
- if (wantcopy >= sizeof(dumpdevname)) {
- printf("set_dumper: device name truncated from '%s' -> '%s'\n",
- devname, dumpdevname);
- }
-
- if (compression != KERNELDUMP_COMP_NONE) {
+ if (kda->kda_compression != KERNELDUMP_COMP_NONE) {
/*
* We currently can't support simultaneous encryption and
- * compression.
+ * compression because our only encryption mode is an unpadded
+ * block cipher, go figure. This is low hanging fruit to fix.
*/
- if (encryption != KERNELDUMP_ENC_NONE) {
+ if (kda->kda_encryption != KERNELDUMP_ENC_NONE) {
error = EOPNOTSUPP;
goto cleanup;
}
- dumper.kdcomp = kerneldumpcomp_create(&dumper, compression);
- if (dumper.kdcomp == NULL) {
+ newdi->kdcomp = kerneldumpcomp_create(newdi,
+ kda->kda_compression);
+ if (newdi->kdcomp == NULL) {
error = EINVAL;
goto cleanup;
}
}
- dumper.blockbuf = malloc(di->blocksize, M_DUMPER, M_WAITOK | M_ZERO);
+ newdi->blockbuf = malloc(newdi->blocksize, M_DUMPER, M_WAITOK | M_ZERO);
+
+ /* Add the new configuration to the queue */
+ mtx_lock(&dumpconf_list_lk);
+ inserted = false;
+ TAILQ_FOREACH(listdi, &dumper_configs, di_next) {
+ if (index == 0) {
+ TAILQ_INSERT_BEFORE(listdi, newdi, di_next);
+ inserted = true;
+ break;
+ }
+ index--;
+ }
+ if (!inserted)
+ TAILQ_INSERT_TAIL(&dumper_configs, newdi, di_next);
+ mtx_unlock(&dumpconf_list_lk);
+
return (0);
cleanup:
- (void)clear_dumper(td);
+ free_single_dumper(newdi);
return (error);
}
-int
-clear_dumper(struct thread *td)
+static bool
+dumper_config_match(const struct dumperinfo *di, const char *devname,
+ const struct diocskerneldump_arg *kda)
{
- int error;
+ if (kda->kda_index == KDA_REMOVE_ALL)
+ return (true);
- error = priv_check(td, PRIV_SETDUMPER);
- if (error != 0)
- return (error);
+ if (strcmp(di->di_devname, devname) != 0)
+ return (false);
-#ifdef NETDUMP
- netdump_mbuf_drain();
-#endif
+ /*
+ * Allow wildcard removal of configs matching a device on g_dev_orphan.
+ */
+ if (kda->kda_index == KDA_REMOVE_DEV)
+ return (true);
+ if (di->kdcomp != NULL) {
+ if (di->kdcomp->kdc_format != kda->kda_compression)
+ return (false);
+ } else if (kda->kda_compression != KERNELDUMP_COMP_NONE)
+ return (false);
#ifdef EKCD
- if (dumper.kdcrypto != NULL) {
- explicit_bzero(dumper.kdcrypto, sizeof(*dumper.kdcrypto) +
- dumper.kdcrypto->kdc_dumpkeysize);
- free(dumper.kdcrypto, M_EKCD);
- }
+ if (di->kdcrypto != NULL) {
+ if (di->kdcrypto->kdc_encryption != kda->kda_encryption)
+ return (false);
+ /*
+ * Do we care to verify keys match to delete? It seems weird
+ * to expect multiple fallback dump configurations on the same
+ * device that only differ in crypto key.
+ */
+ } else
#endif
+ if (kda->kda_encryption != KERNELDUMP_ENC_NONE)
+ return (false);
- kerneldumpcomp_destroy(&dumper);
+ return (true);
+}
- if (dumper.blockbuf != NULL) {
- explicit_bzero(dumper.blockbuf, dumper.blocksize);
- free(dumper.blockbuf, M_DUMPER);
+int
+dumper_remove(const char *devname, const struct diocskerneldump_arg *kda)
+{
+ struct dumperinfo *di, *sdi;
+ bool found;
+ int error;
+
+ error = priv_check(curthread, PRIV_SETDUMPER);
+ if (error != 0)
+ return (error);
+
+ /*
+ * Try to find a matching configuration, and kill it.
+ *
+ * NULL 'kda' indicates remove any configuration matching 'devname',
+ * which may remove multiple configurations in atypical configurations.
+ */
+ found = false;
+ mtx_lock(&dumpconf_list_lk);
+ TAILQ_FOREACH_SAFE(di, &dumper_configs, di_next, sdi) {
+ if (dumper_config_match(di, devname, kda)) {
+ found = true;
+ TAILQ_REMOVE(&dumper_configs, di, di_next);
+ free_single_dumper(di);
+ }
}
- explicit_bzero(&dumper, sizeof(dumper));
- dumpdevname[0] = '\0';
+ mtx_unlock(&dumpconf_list_lk);
+
+ /* Only produce ENOENT if a more targeted match didn't match. */
+ if (!found && kda->kda_index == KDA_REMOVE)
+ return (ENOENT);
return (0);
}
Modified: head/sys/netinet/netdump/netdump.h
==============================================================================
--- head/sys/netinet/netdump/netdump.h Mon May 6 16:54:35 2019 (r347191)
+++ head/sys/netinet/netdump/netdump.h Mon May 6 18:24:07 2019 (r347192)
@@ -60,18 +60,18 @@ struct netdump_ack {
uint32_t na_seqno; /* Match acks with msgs. */
} __packed;
-struct netdump_conf {
- struct diocskerneldump_arg ndc_kda;
- char ndc_iface[IFNAMSIZ];
- struct in_addr ndc_server;
- struct in_addr ndc_client;
- struct in_addr ndc_gateway;
+struct netdump_conf_freebsd12 {
+ struct diocskerneldump_arg_freebsd12 ndc12_kda;
+ char ndc12_iface[IFNAMSIZ];
+ struct in_addr ndc12_server;
+ struct in_addr ndc12_client;
+ struct in_addr ndc12_gateway;
};
-#define _PATH_NETDUMP "/dev/netdump"
+#define NETDUMPGCONF_FREEBSD12 _IOR('n', 1, struct netdump_conf_freebsd12)
+#define NETDUMPSCONF_FREEBSD12 _IOW('n', 2, struct netdump_conf_freebsd12)
-#define NETDUMPGCONF _IOR('n', 1, struct netdump_conf)
-#define NETDUMPSCONF _IOW('n', 2, struct netdump_conf)
+#define _PATH_NETDUMP "/dev/netdump"
#ifdef _KERNEL
#ifdef NETDUMP
Modified: head/sys/netinet/netdump/netdump_client.c
==============================================================================
--- head/sys/netinet/netdump/netdump_client.c Mon May 6 16:54:35 2019 (r347191)
+++ head/sys/netinet/netdump/netdump_client.c Mon May 6 18:24:07 2019 (r347192)
@@ -89,7 +89,8 @@ __FBSDID("$FreeBSD$");
static int netdump_arp_gw(void);
static void netdump_cleanup(void);
-static int netdump_configure(struct netdump_conf *, struct thread *);
+static int netdump_configure(struct diocskerneldump_arg *,
+ struct thread *);
static int netdump_dumper(void *priv __unused, void *virtual,
vm_offset_t physical __unused, off_t offset, size_t length);
static int netdump_ether_output(struct mbuf *m, struct ifnet *ifp,
@@ -118,10 +119,10 @@ static uint64_t rcvd_acks;
CTASSERT(sizeof(rcvd_acks) * NBBY == NETDUMP_MAX_IN_FLIGHT);
/* Configuration parameters. */
-static struct netdump_conf nd_conf;
-#define nd_server nd_conf.ndc_server
-#define nd_client nd_conf.ndc_client
-#define nd_gateway nd_conf.ndc_gateway
+static struct diocskerneldump_arg nd_conf;
+#define nd_server nd_conf.kda_server.in4
+#define nd_client nd_conf.kda_client.in4
+#define nd_gateway nd_conf.kda_gateway.in4
/* General dynamic settings. */
static struct ether_addr nd_gw_mac;
@@ -1059,7 +1060,7 @@ static struct cdevsw netdump_cdevsw = {
static struct cdev *netdump_cdev;
static int
-netdump_configure(struct netdump_conf *conf, struct thread *td)
+netdump_configure(struct diocskerneldump_arg *conf, struct thread *td)
{
struct epoch_tracker et;
struct ifnet *ifp;
@@ -1071,7 +1072,7 @@ netdump_configure(struct netdump_conf *conf, struct th
}
NET_EPOCH_ENTER(et);
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
- if (strcmp(ifp->if_xname, conf->ndc_iface) == 0)
+ if (strcmp(ifp->if_xname, conf->kda_iface) == 0)
break;
}
/* XXX ref */
@@ -1083,7 +1084,7 @@ netdump_configure(struct netdump_conf *conf, struct th
if ((if_getflags(ifp) & IFF_UP) == 0)
return (ENXIO);
if (!netdump_supported_nic(ifp) || ifp->if_type != IFT_ETHER)
- return (EINVAL);
+ return (ENODEV);
nd_ifp = ifp;
netdump_reinit(ifp);
@@ -1135,19 +1136,24 @@ static int
netdump_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr,
int flags __unused, struct thread *td)
{
- struct diocskerneldump_arg *kda;
+ struct diocskerneldump_arg kda_copy, *conf;
struct dumperinfo dumper;
- struct netdump_conf *conf;
uint8_t *encryptedkey;
int error;
#ifdef COMPAT_FREEBSD11
u_int u;
#endif
+#ifdef COMPAT_FREEBSD12
+ struct diocskerneldump_arg_freebsd12 *kda12;
+ struct netdump_conf_freebsd12 *conf12;
+#endif
+ conf = NULL;
error = 0;
switch (cmd) {
#ifdef COMPAT_FREEBSD11
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-head
mailing list