summaryrefslogtreecommitdiffstats
path: root/sys/net/vnet.c
diff options
context:
space:
mode:
authorzec <zec@FreeBSD.org>2010-02-04 07:55:42 +0000
committerzec <zec@FreeBSD.org>2010-02-04 07:55:42 +0000
commit393450ca7b6226ab2ec1b9837777e0651d534a4e (patch)
tree7764b989a82fe6fe95e035ec04067054114e99ad /sys/net/vnet.c
parent6db2453429c4a733846d86797a80dc47edc2aba9 (diff)
downloadFreeBSD-src-393450ca7b6226ab2ec1b9837777e0651d534a4e.zip
FreeBSD-src-393450ca7b6226ab2ec1b9837777e0651d534a4e.tar.gz
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
Diffstat (limited to 'sys/net/vnet.c')
-rw-r--r--sys/net/vnet.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/sys/net/vnet.c b/sys/net/vnet.c
index 298ffb2..26635db 100644
--- a/sys/net/vnet.c
+++ b/sys/net/vnet.c
@@ -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 */
OpenPOWER on IntegriCloud