Module Name: src Committed By: pooka Date: Mon Feb 21 20:23:29 UTC 2011
Modified Files: src/sys/kern: kern_exec.c kern_exit.c kern_lwp.c src/sys/sys: lwp.h Log Message: Borrow the lwpctl data area from the parent for the vfork() child. Otherwise the child will incorrectly see it is not running on any CPU. Among other things, this fixes crashes from having LD_PRELOAD=libpthread.so set in the env. reviewed by tech-kern To generate a diff of this commit: cvs rdiff -u -r1.307 -r1.308 src/sys/kern/kern_exec.c cvs rdiff -u -r1.231 -r1.232 src/sys/kern/kern_exit.c cvs rdiff -u -r1.155 -r1.156 src/sys/kern/kern_lwp.c cvs rdiff -u -r1.148 -r1.149 src/sys/sys/lwp.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/kern_exec.c diff -u src/sys/kern/kern_exec.c:1.307 src/sys/kern/kern_exec.c:1.308 --- src/sys/kern/kern_exec.c:1.307 Tue Feb 15 16:49:54 2011 +++ src/sys/kern/kern_exec.c Mon Feb 21 20:23:29 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: kern_exec.c,v 1.307 2011/02/15 16:49:54 pooka Exp $ */ +/* $NetBSD: kern_exec.c,v 1.308 2011/02/21 20:23:29 pooka Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -59,7 +59,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.307 2011/02/15 16:49:54 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.308 2011/02/21 20:23:29 pooka Exp $"); #include "opt_ktrace.h" #include "opt_modular.h" @@ -978,6 +978,7 @@ */ if ((p->p_lflag & PL_PPWAIT) != 0) { mutex_enter(proc_lock); + l->l_lwpctl = NULL; /* was on loan from blocked parent */ p->p_lflag &= ~PL_PPWAIT; cv_broadcast(&p->p_pptr->p_waitcv); mutex_exit(proc_lock); Index: src/sys/kern/kern_exit.c diff -u src/sys/kern/kern_exit.c:1.231 src/sys/kern/kern_exit.c:1.232 --- src/sys/kern/kern_exit.c:1.231 Sat Dec 18 01:36:19 2010 +++ src/sys/kern/kern_exit.c Mon Feb 21 20:23:28 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: kern_exit.c,v 1.231 2010/12/18 01:36:19 rmind Exp $ */ +/* $NetBSD: kern_exit.c,v 1.232 2011/02/21 20:23:28 pooka Exp $ */ /*- * Copyright (c) 1998, 1999, 2006, 2007, 2008 The NetBSD Foundation, Inc. @@ -67,7 +67,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_exit.c,v 1.231 2010/12/18 01:36:19 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_exit.c,v 1.232 2011/02/21 20:23:28 pooka Exp $"); #include "opt_ktrace.h" #include "opt_perfctrs.h" @@ -341,6 +341,7 @@ */ mutex_enter(proc_lock); if (p->p_lflag & PL_PPWAIT) { + l->l_lwpctl = NULL; /* was on loan from blocked parent */ p->p_lflag &= ~PL_PPWAIT; cv_broadcast(&p->p_pptr->p_waitcv); } Index: src/sys/kern/kern_lwp.c diff -u src/sys/kern/kern_lwp.c:1.155 src/sys/kern/kern_lwp.c:1.156 --- src/sys/kern/kern_lwp.c:1.155 Thu Feb 17 18:50:02 2011 +++ src/sys/kern/kern_lwp.c Mon Feb 21 20:23:28 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: kern_lwp.c,v 1.155 2011/02/17 18:50:02 matt Exp $ */ +/* $NetBSD: kern_lwp.c,v 1.156 2011/02/21 20:23:28 pooka 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.155 2011/02/17 18:50:02 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.156 2011/02/21 20:23:28 pooka Exp $"); #include "opt_ddb.h" #include "opt_lockdebug.h" @@ -697,6 +697,15 @@ TAILQ_INIT(&l2->l_ld_locks); /* + * For vfork, borrow parent's lwpctl context if it exists. + * This also causes us to return via lwp_userret. + */ + if (flags & LWP_VFORK && l1->l_lwpctl) { + l2->l_lwpctl = l1->l_lwpctl; + l2->l_flag |= LW_LWPCTL; + } + + /* * If not the first LWP in the process, grab a reference to the * descriptor table. */ @@ -1377,6 +1386,16 @@ KASSERT(0); /* NOTREACHED */ } + + /* update lwpctl processor (for vfork child_return) */ + if (l->l_flag & LW_LWPCTL) { + lwp_lock(l); + KASSERT(kpreempt_disabled()); + l->l_lwpctl->lc_curcpu = (int)cpu_index(l->l_cpu); + l->l_lwpctl->lc_pctr++; + l->l_flag &= ~LW_LWPCTL; + lwp_unlock(l); + } } #ifdef KERN_SA @@ -1530,6 +1549,10 @@ l = curlwp; p = l->l_proc; + /* don't allow a vforked process to create lwp ctls */ + if (p->p_lflag & PL_PPWAIT) + return EBUSY; + if (l->l_lcpage != NULL) { lcp = l->l_lcpage; *uaddr = lcp->lcp_uaddr + (vaddr_t)l->l_lwpctl - lcp->lcp_kaddr; @@ -1654,11 +1677,18 @@ void lwp_ctl_free(lwp_t *l) { + struct proc *p = l->l_proc; lcproc_t *lp; lcpage_t *lcp; u_int map, offset; - lp = l->l_proc->p_lwpctl; + /* don't free a lwp context we borrowed for vfork */ + if (p->p_lflag & PL_PPWAIT) { + l->l_lwpctl = NULL; + return; + } + + lp = p->p_lwpctl; KASSERT(lp != NULL); lcp = l->l_lcpage; Index: src/sys/sys/lwp.h diff -u src/sys/sys/lwp.h:1.148 src/sys/sys/lwp.h:1.149 --- src/sys/sys/lwp.h:1.148 Sat Feb 19 20:19:54 2011 +++ src/sys/sys/lwp.h Mon Feb 21 20:23:28 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: lwp.h,v 1.148 2011/02/19 20:19:54 matt Exp $ */ +/* $NetBSD: lwp.h,v 1.149 2011/02/21 20:23:28 pooka Exp $ */ /*- * Copyright (c) 2001, 2006, 2007, 2008, 2009, 2010 @@ -215,6 +215,7 @@ /* These flags are kept in l_flag. */ #define LW_IDLE 0x00000001 /* Idle lwp. */ +#define LW_LWPCTL 0x00000002 /* Adjust lwpctl in userret */ #define LW_SINTR 0x00000080 /* Sleep is interruptible. */ #define LW_SA_SWITCHING 0x00000100 /* SA LWP in context switch */ #define LW_SYSTEM 0x00000200 /* Kernel thread */ @@ -259,7 +260,7 @@ * user. */ #define LW_USERRET (LW_WEXIT|LW_PENDSIG|LW_WREBOOT|LW_WSUSPEND|LW_WCORE|\ - LW_SA_BLOCKING|LW_SA_UPCALL) + LW_SA_BLOCKING|LW_SA_UPCALL|LW_LWPCTL) /* * Status values.