KASSERT: Make runtime optionality optional

Add an option, KASSERT_PANIC_OPTIONAL, that allows runtime KASSERT()
behavior changes.  When this option is not enabled, code that allows
KASSERTs to become optional is not enabled, and all violated assertions
cause termination.

The runtime KASSERT behavior was added in r243980.

One important distinction here is that panic has __dead2
("attribute((noreturn))"), while kassert_panic does not.  Static analyzers
like Coverity understand __dead2.  Without it, KASSERTs go misunderstood,
resulting in many false positives that result from violation of program
invariants.

Reviewed by:	jhb, jtl, np, vangyzen
Relnotes:	yes
Sponsored by:	Dell EMC Isilon
Differential Revision:	https://reviews.freebsd.org/D16835
This commit is contained in:
Conrad Meyer 2018-08-22 22:19:42 +00:00
parent 1e88cc8b59
commit 4ca8c1efe4
4 changed files with 41 additions and 13 deletions

View File

@ -553,6 +553,14 @@ options INVARIANTS
#
options INVARIANT_SUPPORT
#
# The KASSERT_PANIC_OPTIONAL option allows kasserts to fire without
# necessarily inducing a panic. Panic is the default behavior, but
# runtime options can configure it either entirely off, or off with a
# limit.
#
options KASSERT_PANIC_OPTIONAL
#
# The DIAGNOSTIC option is used to enable extra debugging information
# from some parts of the kernel. As this makes everything more noisy,

View File

@ -605,6 +605,7 @@ DFLTPHYS opt_global.h
DIAGNOSTIC opt_global.h
INVARIANT_SUPPORT opt_global.h
INVARIANTS opt_global.h
KASSERT_PANIC_OPTIONAL opt_global.h
MAXCPU opt_global.h
MAXMEMDOM opt_global.h
MAXPHYS opt_global.h

View File

@ -652,40 +652,47 @@ static int kassert_warnings = 0;
SYSCTL_NODE(_debug, OID_AUTO, kassert, CTLFLAG_RW, NULL, "kassert options");
SYSCTL_INT(_debug_kassert, OID_AUTO, warn_only, CTLFLAG_RWTUN,
#ifdef KASSERT_PANIC_OPTIONAL
#define KASSERT_RWTUN CTLFLAG_RWTUN
#else
#define KASSERT_RWTUN CTLFLAG_RDTUN
#endif
SYSCTL_INT(_debug_kassert, OID_AUTO, warn_only, KASSERT_RWTUN,
&kassert_warn_only, 0,
"KASSERT triggers a panic (1) or just a warning (0)");
"KASSERT triggers a panic (0) or just a warning (1)");
#ifdef KDB
SYSCTL_INT(_debug_kassert, OID_AUTO, do_kdb, CTLFLAG_RWTUN,
SYSCTL_INT(_debug_kassert, OID_AUTO, do_kdb, KASSERT_RWTUN,
&kassert_do_kdb, 0, "KASSERT will enter the debugger");
#endif
#ifdef KTR
SYSCTL_UINT(_debug_kassert, OID_AUTO, do_ktr, CTLFLAG_RWTUN,
SYSCTL_UINT(_debug_kassert, OID_AUTO, do_ktr, KASSERT_RWTUN,
&kassert_do_ktr, 0,
"KASSERT does a KTR, set this to the KTRMASK you want");
#endif
SYSCTL_INT(_debug_kassert, OID_AUTO, do_log, CTLFLAG_RWTUN,
SYSCTL_INT(_debug_kassert, OID_AUTO, do_log, KASSERT_RWTUN,
&kassert_do_log, 0,
"If warn_only is enabled, log (1) or do not log (0) assertion violations");
SYSCTL_INT(_debug_kassert, OID_AUTO, warnings, CTLFLAG_RWTUN,
SYSCTL_INT(_debug_kassert, OID_AUTO, warnings, KASSERT_RWTUN,
&kassert_warnings, 0, "number of KASSERTs that have been triggered");
SYSCTL_INT(_debug_kassert, OID_AUTO, log_panic_at, CTLFLAG_RWTUN,
SYSCTL_INT(_debug_kassert, OID_AUTO, log_panic_at, KASSERT_RWTUN,
&kassert_log_panic_at, 0, "max number of KASSERTS before we will panic");
SYSCTL_INT(_debug_kassert, OID_AUTO, log_pps_limit, CTLFLAG_RWTUN,
SYSCTL_INT(_debug_kassert, OID_AUTO, log_pps_limit, KASSERT_RWTUN,
&kassert_log_pps_limit, 0, "limit number of log messages per second");
SYSCTL_INT(_debug_kassert, OID_AUTO, log_mute_at, CTLFLAG_RWTUN,
SYSCTL_INT(_debug_kassert, OID_AUTO, log_mute_at, KASSERT_RWTUN,
&kassert_log_mute_at, 0, "max number of KASSERTS to log");
SYSCTL_INT(_debug_kassert, OID_AUTO, suppress_in_panic, CTLFLAG_RWTUN,
SYSCTL_INT(_debug_kassert, OID_AUTO, suppress_in_panic, KASSERT_RWTUN,
&kassert_suppress_in_panic, 0,
"KASSERTs will be suppressed while handling a panic");
#undef KASSERT_RWTUN
static int kassert_sysctl_kassert(SYSCTL_HANDLER_ARGS);
@ -709,6 +716,7 @@ kassert_sysctl_kassert(SYSCTL_HANDLER_ARGS)
return (0);
}
#ifdef KASSERT_PANIC_OPTIONAL
/*
* Called by KASSERT, this decides if we will panic
* or if we will log via printf and/or ktr.
@ -774,6 +782,7 @@ kassert_panic(const char *fmt, ...)
#endif
atomic_add_int(&kassert_warnings, 1);
}
#endif /* KASSERT_PANIC_OPTIONAL */
#endif
/*

View File

@ -80,8 +80,21 @@ extern int vm_guest; /* Running as virtual machine guest? */
enum VM_GUEST { VM_GUEST_NO = 0, VM_GUEST_VM, VM_GUEST_XEN, VM_GUEST_HV,
VM_GUEST_VMWARE, VM_GUEST_KVM, VM_GUEST_BHYVE, VM_LAST };
/*
* These functions need to be declared before the KASSERT macro is invoked in
* !KASSERT_PANIC_OPTIONAL builds, so their declarations are sort of out of
* place compared to other function definitions in this header. On the other
* hand, this header is a bit disorganized anyway.
*/
void panic(const char *, ...) __dead2 __printflike(1, 2);
void vpanic(const char *, __va_list) __dead2 __printflike(1, 0);
#if defined(WITNESS) || defined(INVARIANT_SUPPORT)
#ifdef KASSERT_PANIC_OPTIONAL
void kassert_panic(const char *fmt, ...) __printflike(1, 2);
#else
#define kassert_panic panic
#endif
#endif
#ifdef INVARIANTS /* The option is always available */
@ -213,9 +226,6 @@ void *phashinit_flags(int count, struct malloc_type *type, u_long *nentries,
int flags);
void g_waitidle(void);
void panic(const char *, ...) __dead2 __printflike(1, 2);
void vpanic(const char *, __va_list) __dead2 __printflike(1, 0);
void cpu_boot(int);
void cpu_flush_dcache(void *, size_t);
void cpu_rootconf(void);