Instead of spamming the console on each curvnet recursion event, print
out each such call graph only once, along with a stack backtrace. This should make kernels built with VNET_DEBUG reasonably usable again in busy / production environments. Introduce a new DDB command "show vnetrcrs" which dumps the whole log of distinctive curvnet recursion events. This might be useful when recursion reports get burried / lost too deep in the message buffer. In the later case stack backtraces are not available. Reviewed by: bz MFC after: 3 days
This commit is contained in:
parent
7a377edc31
commit
0a705ab66f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=203483
@ -37,8 +37,10 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_ddb.h"
|
||||
#include "opt_kdb.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kdb.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/jail.h>
|
||||
#include <sys/systm.h>
|
||||
@ -616,6 +618,65 @@ vnet_sysuninit(void)
|
||||
VNET_SYSINIT_RUNLOCK();
|
||||
}
|
||||
|
||||
#ifdef VNET_DEBUG
|
||||
struct vnet_recursion {
|
||||
SLIST_ENTRY(vnet_recursion) vnr_le;
|
||||
const char *prev_fn;
|
||||
const char *where_fn;
|
||||
int where_line;
|
||||
struct vnet *old_vnet;
|
||||
struct vnet *new_vnet;
|
||||
};
|
||||
|
||||
static SLIST_HEAD(, vnet_recursion) vnet_recursions =
|
||||
SLIST_HEAD_INITIALIZER(vnet_recursions);
|
||||
|
||||
static void
|
||||
vnet_print_recursion(struct vnet_recursion *vnr, int brief)
|
||||
{
|
||||
|
||||
if (!brief)
|
||||
printf("CURVNET_SET() recursion in ");
|
||||
printf("%s() line %d, prev in %s()", vnr->where_fn, vnr->where_line,
|
||||
vnr->prev_fn);
|
||||
if (brief)
|
||||
printf(", ");
|
||||
else
|
||||
printf("\n ");
|
||||
printf("%p -> %p\n", vnr->old_vnet, vnr->new_vnet);
|
||||
}
|
||||
|
||||
void
|
||||
vnet_log_recursion(struct vnet *old_vnet, const char *old_fn, int line)
|
||||
{
|
||||
struct vnet_recursion *vnr;
|
||||
|
||||
/* Skip already logged recursion events. */
|
||||
SLIST_FOREACH(vnr, &vnet_recursions, vnr_le)
|
||||
if (vnr->prev_fn == old_fn &&
|
||||
vnr->where_fn == curthread->td_vnet_lpush &&
|
||||
vnr->where_line == line &&
|
||||
(vnr->old_vnet == vnr->new_vnet) == (curvnet == old_vnet))
|
||||
return;
|
||||
|
||||
vnr = malloc(sizeof(*vnr), M_VNET, M_NOWAIT | M_ZERO);
|
||||
if (vnr == NULL)
|
||||
panic("%s: malloc failed", __func__);
|
||||
vnr->prev_fn = old_fn;
|
||||
vnr->where_fn = curthread->td_vnet_lpush;
|
||||
vnr->where_line = line;
|
||||
vnr->old_vnet = old_vnet;
|
||||
vnr->new_vnet = curvnet;
|
||||
|
||||
SLIST_INSERT_HEAD(&vnet_recursions, vnr, vnr_le);
|
||||
|
||||
vnet_print_recursion(vnr, 0);
|
||||
#ifdef KDB
|
||||
kdb_backtrace();
|
||||
#endif
|
||||
}
|
||||
#endif /* VNET_DEBUG */
|
||||
|
||||
#ifdef DDB
|
||||
DB_SHOW_COMMAND(vnets, db_show_vnets)
|
||||
{
|
||||
@ -637,4 +698,14 @@ DB_SHOW_COMMAND(vnets, db_show_vnets)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VNET_DEBUG
|
||||
DB_SHOW_COMMAND(vnetrcrs, db_show_vnetrcrs)
|
||||
{
|
||||
struct vnet_recursion *vnr;
|
||||
|
||||
SLIST_FOREACH(vnr, &vnet_recursions, vnr_le)
|
||||
vnet_print_recursion(vnr, 1);
|
||||
}
|
||||
#endif
|
||||
#endif /* DDB */
|
||||
|
@ -108,6 +108,8 @@ void vnet_destroy(struct vnet *vnet);
|
||||
* assertions.
|
||||
*/
|
||||
#ifdef VNET_DEBUG
|
||||
void vnet_log_recursion(struct vnet *, const char *, int);
|
||||
|
||||
#define VNET_ASSERT(condition) \
|
||||
if (!(condition)) { \
|
||||
printf("VNET_ASSERT @ %s:%d %s():\n", \
|
||||
@ -125,9 +127,7 @@ void vnet_destroy(struct vnet *vnet);
|
||||
#define CURVNET_SET_VERBOSE(arg) \
|
||||
CURVNET_SET_QUIET(arg) \
|
||||
if (saved_vnet) \
|
||||
printf("CURVNET_SET(%p) in %s() on cpu %d, prev %p in %s()\n", \
|
||||
curvnet, curthread->td_vnet_lpush, curcpu, \
|
||||
saved_vnet, saved_vnet_lpush);
|
||||
vnet_log_recursion(saved_vnet, saved_vnet_lpush, __LINE__);
|
||||
|
||||
#define CURVNET_SET(arg) CURVNET_SET_VERBOSE(arg)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user