From owner-svn-src-head@freebsd.org Wed Apr 27 02:25:22 2016 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 9B31CB1D10B; Wed, 27 Apr 2016 02:25:22 +0000 (UTC) (envelope-from jamie@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 77CF51D7C; Wed, 27 Apr 2016 02:25:22 +0000 (UTC) (envelope-from jamie@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u3R2PLI5045460; Wed, 27 Apr 2016 02:25:21 GMT (envelope-from jamie@FreeBSD.org) Received: (from jamie@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u3R2PLG9045458; Wed, 27 Apr 2016 02:25:21 GMT (envelope-from jamie@FreeBSD.org) Message-Id: <201604270225.u3R2PLG9045458@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: jamie set sender to jamie@FreeBSD.org using -f From: Jamie Gritton Date: Wed, 27 Apr 2016 02:25:21 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r298683 - in head/sys: kern sys X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 27 Apr 2016 02:25:22 -0000 Author: jamie Date: Wed Apr 27 02:25:21 2016 New Revision: 298683 URL: https://svnweb.freebsd.org/changeset/base/298683 Log: Delay revmoing the last jail reference in prison_proc_free, and instead put it off into the pr_task. This is similar to prison_free, and in fact uses the same task even though they do something slightly different. This resolves a LOR between the process lock and allprison_lock, which came about in r298565. PR: 48471 Modified: head/sys/kern/kern_jail.c head/sys/sys/jail.h Modified: head/sys/kern/kern_jail.c ============================================================================== --- head/sys/kern/kern_jail.c Wed Apr 27 02:13:57 2016 (r298682) +++ head/sys/kern/kern_jail.c Wed Apr 27 02:25:21 2016 (r298683) @@ -1328,6 +1328,7 @@ kern_jail_set(struct thread *td, struct LIST_INIT(&pr->pr_children); mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF | MTX_DUPOK); + TASK_INIT(&pr->pr_task, 0, prison_complete, pr); #ifdef VIMAGE /* Allocate a new vnet if specified. */ @@ -2575,16 +2576,13 @@ prison_allow(struct ucred *cred, unsigne void prison_free_locked(struct prison *pr) { + int ref; mtx_assert(&pr->pr_mtx, MA_OWNED); - pr->pr_ref--; - if (pr->pr_ref == 0) { - mtx_unlock(&pr->pr_mtx); - TASK_INIT(&pr->pr_task, 0, prison_complete, pr); - taskqueue_enqueue(taskqueue_thread, &pr->pr_task); - return; - } + ref = --pr->pr_ref; mtx_unlock(&pr->pr_mtx); + if (ref == 0) + taskqueue_enqueue(taskqueue_thread, &pr->pr_task); } void @@ -2595,11 +2593,17 @@ prison_free(struct prison *pr) prison_free_locked(pr); } +/* + * Complete a call to either prison_free or prison_proc_free. + */ static void prison_complete(void *context, int pending) { + struct prison *pr = context; - prison_deref((struct prison *)context, 0); + mtx_lock(&pr->pr_mtx); + prison_deref(pr, pr->pr_uref + ? PD_DEREF | PD_DEUREF | PD_LOCKED : PD_LOCKED); } /* @@ -2618,6 +2622,9 @@ prison_deref(struct prison *pr, int flag mtx_lock(&pr->pr_mtx); for (;;) { if (flags & PD_DEUREF) { + KASSERT(pr->pr_uref > 0, + ("prison_deref PD_DEUREF on a dead prison (jid=%d)", + pr->pr_id)); pr->pr_uref--; lasturef = pr->pr_uref == 0; if (lasturef) @@ -2625,8 +2632,12 @@ prison_deref(struct prison *pr, int flag KASSERT(prison0.pr_uref != 0, ("prison0 pr_uref=0")); } else lasturef = 0; - if (flags & PD_DEREF) + if (flags & PD_DEREF) { + KASSERT(pr->pr_ref > 0, + ("prison_deref PD_DEREF on a dead prison (jid=%d)", + pr->pr_id)); pr->pr_ref--; + } ref = pr->pr_ref; mtx_unlock(&pr->pr_mtx); @@ -2740,7 +2751,20 @@ prison_proc_free(struct prison *pr) mtx_lock(&pr->pr_mtx); KASSERT(pr->pr_uref > 0, ("Trying to kill a process in a dead prison (jid=%d)", pr->pr_id)); - prison_deref(pr, PD_DEUREF | PD_LOCKED); + if (pr->pr_uref > 1) + pr->pr_uref--; + else { + /* + * Don't remove the last user reference in this context, which + * is expected to be a process that is not only locked, but + * also half dead. + */ + pr->pr_ref++; + mtx_unlock(&pr->pr_mtx); + taskqueue_enqueue(taskqueue_thread, &pr->pr_task); + return; + } + mtx_unlock(&pr->pr_mtx); } Modified: head/sys/sys/jail.h ============================================================================== --- head/sys/sys/jail.h Wed Apr 27 02:13:57 2016 (r298682) +++ head/sys/sys/jail.h Wed Apr 27 02:25:21 2016 (r298683) @@ -149,7 +149,6 @@ struct prison_racct; * (p) locked by pr_mtx * (c) set only during creation before the structure is shared, no mutex * required to read - * (d) set only during destruction of jail, no mutex needed */ struct prison { TAILQ_ENTRY(prison) pr_list; /* (a) all prisons */ @@ -161,7 +160,7 @@ struct prison { LIST_ENTRY(prison) pr_sibling; /* (a) next in parent's list */ struct prison *pr_parent; /* (c) containing jail */ struct mtx pr_mtx; - struct task pr_task; /* (d) destroy task */ + struct task pr_task; /* (c) destroy task */ struct osd pr_osd; /* (p) additional data */ struct cpuset *pr_cpuset; /* (p) cpuset */ struct vnet *pr_vnet; /* (c) network stack */