kern/171360: [patch][dtrace] the fasttrap fork handler recurses on
the child proc mutex
Mark Johnston
markjdb at gmail.com
Thu Sep 6 01:30:03 UTC 2012
>Number: 171360
>Category: kern
>Synopsis: [patch][dtrace] the fasttrap fork handler recurses on the child proc mutex
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Thu Sep 06 01:30:02 UTC 2012
>Closed-Date:
>Last-Modified:
>Originator: Mark Johnston
>Release: CURRENT
>Organization:
>Environment:
FreeBSD oddish 10.0-CURRENT FreeBSD 10.0-CURRENT #7 r240137=b105ea9-dirty: Wed Sep 5 14:02:01 EDT 2012 mark at oddish:/usr/obj/usr/home/mark/src/freebsd/sys/GENERIC amd64
>Description:
The fasttrap fork handler calls fasttrap_tracepoint_remove() with the child proc mutex held (acquired in do_fork()), which then calls fasttrap_isa.c:proc_ops(), which acquires the proc mutex again (in PHOLD()). With INVARIANTS enabled, this causes a panic.
>How-To-Repeat:
An easy way to reproduce this is by running
dtrace -n 'pid$target::main:entry {}' -c /bin/sh
and then running ls at the sh prompt. If INVARIANTS is enabled, you'll get a panic that looks like this:
panic: _mtx_lock_sleep: recursed on non-recursive mutex process lock @ /usr/home/mark/src/freebsd/sys/modules/dtrace/fasttrap/../../../cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c:77
(kgdb) bt
#0 doadump (textdump=1) at /usr/home/mark/src/freebsd/sys/kern/kern_shutdown.c:266
#1 0xffffffff8063f262 in kern_reboot (howto=260) at /usr/home/mark/src/freebsd/sys/kern/kern_shutdown.c:449
#2 0xffffffff8063ec8a in panic (fmt=0x0) at /usr/home/mark/src/freebsd/sys/kern/kern_shutdown.c:637
#3 0xffffffff8062ccff in _mtx_lock_sleep (m=Variable "m" is not available.
) at /usr/home/mark/src/freebsd/sys/kern/kern_mutex.c:363
#4 0xffffffff8062ce11 in _mtx_lock_flags (m=0xfffffe0008dec598, opts=0, file=0xffffffff816908f8 "/usr/home/mark/src/freebsd/sys/modules/dtrace/fasttrap/../../../cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c", line=77)
at /usr/home/mark/src/freebsd/sys/kern/kern_mutex.c:212
#5 0xffffffff8168df91 in proc_ops (op=Variable "op" is not available.
) at /usr/home/mark/src/freebsd/sys/modules/dtrace/fasttrap/../../../cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c:77
#6 0xffffffff8168e1c8 in fasttrap_tracepoint_remove (p=0xfffffe0008dec4a0, tp=0xfffffe0008b9f680) at /usr/home/mark/src/freebsd/sys/modules/dtrace/fasttrap/../../../cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c:693
#7 0xffffffff8168cf17 in fasttrap_fork (p=Variable "p" is not available.
) at /usr/home/mark/src/freebsd/sys/modules/dtrace/fasttrap/../../../cddl/contrib/opensolaris/uts/common/dtrace/fasttrap.c:515
#8 0xffffffff8061072a in fork1 (td=0xfffffe000b176900, flags=20, pages=Variable "pages" is not available.
) at /usr/home/mark/src/freebsd/sys/kern/kern_fork.c:693
#9 0xffffffff80610f12 in sys_fork (td=0xfffffe000b176900, uap=Variable "uap" is not available.
) at /usr/home/mark/src/freebsd/sys/kern/kern_fork.c:110
>Fix:
It doesn't seem to me that either the child or parent proc mutexes need to be held in the fasttrap fork handler, so I've attached a patch which just releases them at the beginning of the handler. This is what the exec() and exit() handlers also do.
The patch fixes the problem for me so that I can go on playing around with userland dtrace without disabling INVARIANTS, but I'm more than happy to test other fixes.
Patch attached with submission follows:
diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/fasttrap.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/fasttrap.c
index 4599a32..bc2f5e7 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/fasttrap.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/fasttrap.c
@@ -450,31 +450,31 @@ fasttrap_fork(proc_t *p, proc_t *cp)
#if defined(sun)
ASSERT(curproc == p);
ASSERT(p->p_proc_flag & P_PR_LOCK);
-#else
- PROC_LOCK_ASSERT(p, MA_OWNED);
-#endif
-#if defined(sun)
ASSERT(p->p_dtrace_count > 0);
#else
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ PROC_LOCK_ASSERT(cp, MA_OWNED);
+
+ PROC_UNLOCK(p);
+ PROC_UNLOCK(cp);
if (p->p_dtrace_helpers) {
/*
* dtrace_helpers_duplicate() allocates memory.
*/
- _PHOLD(cp);
- PROC_UNLOCK(p);
- PROC_UNLOCK(cp);
+ PHOLD(cp);
dtrace_helpers_duplicate(p, cp);
- PROC_LOCK(cp);
- PROC_LOCK(p);
- _PRELE(cp);
+ PRELE(cp);
}
/*
* This check is purposely here instead of in kern_fork.c because,
* for legal resons, we cannot include the dtrace_cddl.h header
* inside kern_fork.c and insert if-clause there.
*/
- if (p->p_dtrace_count == 0)
+ if (p->p_dtrace_count == 0) {
+ PROC_LOCK(cp);
+ PROC_LOCK(p);
return;
+ }
#endif
ASSERT(cp->p_dtrace_count == 0);
@@ -497,7 +497,7 @@ fasttrap_fork(proc_t *p, proc_t *cp)
sprlock_proc(cp);
mtx_unlock_spin(&cp->p_slock);
#else
- _PHOLD(cp);
+ PHOLD(cp);
#endif
/*
@@ -532,6 +532,8 @@ fasttrap_fork(proc_t *p, proc_t *cp)
mutex_enter(&cp->p_lock);
sprunlock(cp);
#else
+ PROC_LOCK(cp);
+ PROC_LOCK(p);
_PRELE(cp);
#endif
}
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list