Implement a simple psref leak detector

It detects leaks by counting up the number of held psref by an LWP and checking
its zeroness at the end of syscalls and softint handlers.  For the counter, a
unused field of struct lwp is reused.

The detector runs only if DIAGNOSTIC is turned on.
This commit is contained in:
ozaki-r 2019-04-19 01:52:55 +00:00
parent ad35be2d80
commit 3843688c40
6 changed files with 30 additions and 11 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_lwp.c,v 1.196 2019/03/01 09:02:03 hannken Exp $ */
/* $NetBSD: kern_lwp.c,v 1.197 2019/04/19 01:52:55 ozaki-r Exp $ */
/*-
* Copyright (c) 2001, 2006, 2007, 2008, 2009 The NetBSD Foundation, Inc.
@ -211,7 +211,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.196 2019/03/01 09:02:03 hannken Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.197 2019/04/19 01:52:55 ozaki-r Exp $");
#include "opt_ddb.h"
#include "opt_lockdebug.h"
@ -836,6 +836,7 @@ lwp_create(lwp_t *l1, proc_t *p2, vaddr_t uaddr, int flags,
l2->l_flag = 0;
l2->l_pflag = LP_MPSAFE;
TAILQ_INIT(&l2->l_ld_locks);
l2->l_psrefs = 0;
/*
* For vfork, borrow parent's lwpctl context if it exists.

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_softint.c,v 1.45 2017/12/28 03:39:48 msaitoh Exp $ */
/* $NetBSD: kern_softint.c,v 1.46 2019/04/19 01:52:55 ozaki-r Exp $ */
/*-
* Copyright (c) 2007, 2008 The NetBSD Foundation, Inc.
@ -170,7 +170,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_softint.c,v 1.45 2017/12/28 03:39:48 msaitoh Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_softint.c,v 1.46 2019/04/19 01:52:55 ozaki-r Exp $");
#include <sys/param.h>
#include <sys/proc.h>
@ -595,6 +595,9 @@ softint_execute(softint_t *si, lwp_t *l, int s)
KASSERTMSG(curcpu()->ci_mtx_count == 0,
"%s: ci_mtx_count (%d) != 0, sh_func %p\n",
__func__, curcpu()->ci_mtx_count, sh->sh_func);
/* Diagnostic: check that psrefs have not leaked. */
KASSERTMSG(l->l_psrefs == 0, "%s: l_psrefs=%d, sh_func=%p\n",
__func__, l->l_psrefs, sh->sh_func);
(void)splhigh();
KASSERT((sh->sh_flags & SOFTINT_ACTIVE) != 0);

View File

@ -1,4 +1,4 @@
/* $NetBSD: subr_psref.c,v 1.11 2018/02/01 03:17:00 ozaki-r Exp $ */
/* $NetBSD: subr_psref.c,v 1.12 2019/04/19 01:52:55 ozaki-r Exp $ */
/*-
* Copyright (c) 2016 The NetBSD Foundation, Inc.
@ -64,7 +64,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: subr_psref.c,v 1.11 2018/02/01 03:17:00 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: subr_psref.c,v 1.12 2019/04/19 01:52:55 ozaki-r Exp $");
#include <sys/types.h>
#include <sys/condvar.h>
@ -278,6 +278,10 @@ psref_acquire(struct psref *psref, const struct psref_target *target,
/* Release the CPU list and restore interrupts. */
percpu_putref(class->prc_percpu);
splx(s);
#ifdef DIAGNOSTIC
curlwp->l_psrefs++;
#endif
}
/*
@ -332,6 +336,11 @@ psref_release(struct psref *psref, const struct psref_target *target,
percpu_putref(class->prc_percpu);
splx(s);
#ifdef DIAGNOSTIC
KASSERT(curlwp->l_psrefs > 0);
curlwp->l_psrefs--;
#endif
/* If someone is waiting for users to drain, notify 'em. */
if (__predict_false(target->prt_draining))
cv_broadcast(&class->prc_cv);
@ -388,6 +397,10 @@ psref_copy(struct psref *pto, const struct psref *pfrom,
/* Release the CPU list and restore interrupts. */
percpu_putref(class->prc_percpu);
splx(s);
#ifdef DIAGNOSTIC
curlwp->l_psrefs++;
#endif
}
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: sysproxy.c,v 1.5 2019/04/18 08:31:44 ozaki-r Exp $ */
/* $NetBSD: sysproxy.c,v 1.6 2019/04/19 01:52:55 ozaki-r Exp $ */
/*
* Copyright (c) 2010, 2011 Antti Kantee. All Rights Reserved.
@ -26,7 +26,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: sysproxy.c,v 1.5 2019/04/18 08:31:44 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: sysproxy.c,v 1.6 2019/04/19 01:52:55 ozaki-r Exp $");
#include <sys/param.h>
#include <sys/filedesc.h>
@ -77,6 +77,7 @@ hyp_syscall(int num, void *arg, long *retval)
/* Sanity checks (from mi_userret) */
LOCKDEBUG_BARRIER(NULL, 0);
KASSERT(l->l_nopreempt == 0);
KASSERT(l->l_psrefs == 0);
return rv;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: lwp.h,v 1.181 2019/03/01 09:02:03 hannken Exp $ */
/* $NetBSD: lwp.h,v 1.182 2019/04/19 01:52:55 ozaki-r Exp $ */
/*
* Copyright (c) 2001, 2006, 2007, 2008, 2009, 2010
@ -184,7 +184,7 @@ struct lwp {
u_int l_cv_signalled; /* c: restarted by cv_signal() */
u_short l_shlocks; /* !: lockdebug: shared locks held */
u_short l_exlocks; /* !: lockdebug: excl. locks held */
u_short l_unused; /* !: unused */
u_short l_psrefs; /* !: count of psref held */
u_short l_blcnt; /* !: count of kernel_lock held */
int l_nopreempt; /* !: don't preempt me! */
u_int l_dopreempt; /* s: kernel preemption pending */

View File

@ -1,4 +1,4 @@
/* $NetBSD: userret.h,v 1.26 2013/04/07 07:54:53 kiyohara Exp $ */
/* $NetBSD: userret.h,v 1.27 2019/04/19 01:52:55 ozaki-r Exp $ */
/*-
* Copyright (c) 1998, 2000, 2003, 2006, 2008 The NetBSD Foundation, Inc.
@ -114,6 +114,7 @@ mi_userret(struct lwp *l)
LOCKDEBUG_BARRIER(NULL, 0);
KASSERT(l->l_nopreempt == 0);
KASSERT(l->l_psrefs == 0);
}
#endif /* !_SYS_USERRET_H_ */