Index: sys/conf/files =================================================================== --- sys/conf/files +++ sys/conf/files @@ -3241,6 +3241,7 @@ kern/subr_hints.c standard kern/subr_kdb.c standard kern/subr_kobj.c standard +kern/subr_kwarn.c optional witness kern/subr_lock.c standard kern/subr_log.c standard kern/subr_mbpool.c optional libmbpool Index: sys/kern/subr_kwarn.c =================================================================== --- /dev/null +++ sys/kern/subr_kwarn.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2016, EMC / Isilon Storage Division + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_ddb.h" +#include "opt_stack.h" + +#include +#include +#include +#include +#include +#include + +#ifdef DDB +#include +#endif + +#include + +static int kwarn_do_panic; +#ifdef KDB +static int kwarn_do_kdb; +#endif +static int kwarn_do_log = 1; +static int kwarn_log_pps_limit = 4; +static unsigned kwarn_log_mute_at; +static unsigned kwarn_log_panic_at; +static unsigned kwarn_warnings; + +static SYSCTL_NODE(_debug, OID_AUTO, kwarn, CTLFLAG_RW, NULL, "kwarn options"); + +SYSCTL_INT(_debug_kwarn, OID_AUTO, do_panic, CTLFLAG_RWTUN, + &kwarn_do_panic, 0, "If non-zero, KWARN will cause panic"); +#ifdef KDB +SYSCTL_INT(_debug_kwarn, OID_AUTO, do_kdb, CTLFLAG_RWTUN, &kwarn_do_kdb, + 0, "If non-zero, KWARN will enter the debugger"); +#endif +SYSCTL_INT(_debug_kwarn, OID_AUTO, do_log, CTLFLAG_RWTUN, &kwarn_do_log, + 0, "If non-zero, KWARN will produce log messages"); +SYSCTL_INT(_debug_kwarn, OID_AUTO, log_pps_limit, CTLFLAG_RWTUN, + &kwarn_log_pps_limit, 0, + "If positive, limit to this many KWARNS per second; if zero, never log; " + "if -1, always log"); +SYSCTL_UINT(_debug_kwarn, OID_AUTO, log_mute_at, CTLFLAG_RWTUN, + &kwarn_log_mute_at, 0, + "If non-zero, limit to this many KWARNS"); +SYSCTL_UINT(_debug_kwarn, OID_AUTO, log_panic_at, CTLFLAG_RWTUN, + &kwarn_log_panic_at, 0, + "If non-zero, KWARN will panic after this many warnings"); +SYSCTL_UINT(_debug_kwarn, OID_AUTO, warnings, CTLFLAG_RWTUN, + &kwarn_warnings, 0, "Number of KWARNS triggered"); + +static int kwarn_test_sysctl(SYSCTL_HANDLER_ARGS); +SYSCTL_PROC(_debug_kwarn, OID_AUTO, test, + CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE, NULL, 0, kwarn_test_sysctl, "I", + "trigger a test KWARN"); + +static int +kwarn_test_sysctl(SYSCTL_HANDLER_ARGS) +{ + int error, arg; + + arg = 0; + error = SYSCTL_OUT(req, &arg, sizeof(arg)); + if (error != 0 || req->newptr == NULL) + return (error); + error = SYSCTL_IN(req, &arg, sizeof(arg)); + if (error != 0) + return (error); + + KWARN(false, ("%s: TEST arg=%d", __func__, arg)); + return (0); +} + +void +kwarn(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vkwarn(fmt, ap); + va_end(ap); +} + +void +vkwarn(const char *fmt, va_list ap) +{ + static struct timeval ppstv; + static int pps; + + char sbuf[128], *buf; + va_list ap2; + int len; + + if (kwarn_do_panic || + (kwarn_log_panic_at != 0 && kwarn_warnings >= kwarn_log_panic_at)) { + vpanic(fmt, ap); + /* NORETURN */ + } + + buf = sbuf; + va_copy(ap2, ap); + len = vsnprintf(sbuf, sizeof(sbuf), fmt, ap); + + if (len >= (int)sizeof(sbuf)) { + /* + * Don't use M_WAITOK, for ithread callers. + * + * Most callers will probably safely fit in 128 chars. + * + * However, in the case that we can't get memory without + * blocking, prefer to truncate. + */ + buf = malloc((size_t)len + 1, M_TEMP, M_NOWAIT); + if (buf == NULL) + buf = sbuf; + else + (void)vsnprintf(buf, (size_t)len + 1, fmt, ap2); + } + + if (kwarn_do_log && + (kwarn_log_mute_at == 0 || kwarn_warnings < kwarn_log_mute_at)) { + if (ppsratecheck(&ppstv, &pps, kwarn_log_pps_limit)) { + printf("KWARN: %s\n", buf); + kdb_backtrace(); + } + } + +#ifdef KDB + if (kwarn_do_kdb) + kdb_enter(KDB_WHY_KWARN, buf); +#endif + + atomic_add_int(&kwarn_warnings, 1); + + if (buf != sbuf) + free(buf, M_TEMP); +} Index: sys/sys/kdb.h =================================================================== --- sys/sys/kdb.h +++ sys/sys/kdb.h @@ -97,7 +97,7 @@ extern const char * volatile kdb_why; #define KDB_WHY_UNSET NULL /* No reason set. */ #define KDB_WHY_PANIC "panic" /* panic() was called. */ -#define KDB_WHY_KASSERT "kassert" /* kassert failed. */ +#define KDB_WHY_KWARN "kwarn" /* kwarn tripped. */ #define KDB_WHY_SYSCTL "sysctl" /* Sysctl entered debugger. */ #define KDB_WHY_BOOTFLAGS "bootflags" /* Boot flags were set. */ #define KDB_WHY_WITNESS "witness" /* Witness entered debugger. */ Index: sys/sys/kwarn.h =================================================================== --- /dev/null +++ sys/sys/kwarn.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016, EMC / Isilon Storage Division + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _SYS_KWARN_H_ +#define _SYS_KWARN_H_ + +#include + +#define KWARN(exp, msg) do { \ + if (__predict_false(!(exp))) \ + kwarn msg; \ +} while (0) +void kwarn(const char *, ...) __printflike(1, 2); +void vkwarn(const char *, __va_list); + +#endif /* !_SYS_KWARN_H_ */