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:
Marko Zec 2010-02-04 07:55:42 +00:00
parent 7a377edc31
commit 0a705ab66f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=203483
2 changed files with 74 additions and 3 deletions

View File

@ -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 */

View File

@ -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)