From owner-svn-src-all@FreeBSD.ORG Sun Jul 17 21:53:43 2011 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 26364106566B; Sun, 17 Jul 2011 21:53:43 +0000 (UTC) (envelope-from rstone@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 0B2548FC08; Sun, 17 Jul 2011 21:53:43 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id p6HLrg4g091980; Sun, 17 Jul 2011 21:53:42 GMT (envelope-from rstone@svn.freebsd.org) Received: (from rstone@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id p6HLrgOM091978; Sun, 17 Jul 2011 21:53:42 GMT (envelope-from rstone@svn.freebsd.org) Message-Id: <201107172153.p6HLrgOM091978@svn.freebsd.org> From: Ryan Stone Date: Sun, 17 Jul 2011 21:53:42 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r224156 - head/sys/kern X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 17 Jul 2011 21:53:43 -0000 Author: rstone Date: Sun Jul 17 21:53:42 2011 New Revision: 224156 URL: http://svn.freebsd.org/changeset/base/224156 Log: Fix a LOR between hwpmc and the kernel linker. When a system-wide sampling mode PMC is allocated, hwpmc calls linker_hwpmc_list_objects() while already holding an exclusive lock on pmc-sx lock. list_objects() tries to acquire an exclusive lock on the kld_sx lock. When a KLD module is loaded or unloaded successfully, kern_kld(un)load calls into the pmc hook while already holding an exclusive lock on the kld_sx lock. Calling the pmc hook requires acquiring a shared lock on the pmc-sx lock. Fix this by only acquiring a shared lock on the kld_sx lock in linker_hwpmc_list_objects(), and also downgrading to a shared lock on the kld_sx lock in kern_kld(un)load before calling into the pmc hook. In kern_kldload this required moving some modifications of the linker_file_t to happen before calling into the pmc hook. This fixes the deadlock by ensuring that the hwpmc -> list_objects() case is always able to proceed. Without this patch, I was able to deadlock a multicore system within minutes by constantly loading and unloading an KLD module while I simultaneously started a sampling mode PMC in a loop. MFC after: 1 month Modified: head/sys/kern/kern_linker.c Modified: head/sys/kern/kern_linker.c ============================================================================== --- head/sys/kern/kern_linker.c Sun Jul 17 21:52:55 2011 (r224155) +++ head/sys/kern/kern_linker.c Sun Jul 17 21:53:42 2011 (r224156) @@ -70,6 +70,9 @@ SYSCTL_INT(_debug, OID_AUTO, kld_debug, #define KLD_LOCK() sx_xlock(&kld_sx) #define KLD_UNLOCK() sx_xunlock(&kld_sx) +#define KLD_DOWNGRADE() sx_downgrade(&kld_sx) +#define KLD_LOCK_READ() sx_slock(&kld_sx) +#define KLD_UNLOCK_READ() sx_sunlock(&kld_sx) #define KLD_LOCKED() sx_xlocked(&kld_sx) #define KLD_LOCK_ASSERT() do { \ if (!cold) \ @@ -1019,18 +1022,24 @@ kern_kldload(struct thread *td, const ch KLD_LOCK(); error = linker_load_module(kldname, modname, NULL, NULL, &lf); - if (error) - goto unlock; + if (error) { + KLD_UNLOCK(); + goto done; + } + lf->userrefs++; + if (fileid != NULL) + *fileid = lf->id; #ifdef HWPMC_HOOKS + KLD_DOWNGRADE(); pkm.pm_file = lf->filename; pkm.pm_address = (uintptr_t) lf->address; PMC_CALL_HOOK(td, PMC_FN_KLD_LOAD, (void *) &pkm); -#endif - lf->userrefs++; - if (fileid != NULL) - *fileid = lf->id; -unlock: + KLD_UNLOCK_READ(); +#else KLD_UNLOCK(); +#endif + +done: CURVNET_RESTORE(); return (error); } @@ -1102,10 +1111,14 @@ kern_kldunload(struct thread *td, int fi error = ENOENT; #ifdef HWPMC_HOOKS - if (error == 0) + if (error == 0) { + KLD_DOWNGRADE(); PMC_CALL_HOOK(td, PMC_FN_KLD_UNLOAD, (void *) &pkm); + KLD_UNLOCK_READ(); + } else +#else + KLD_UNLOCK(); #endif - KLD_UNLOCK(); CURVNET_RESTORE(); return (error); } @@ -1932,7 +1945,7 @@ linker_hwpmc_list_objects(void) int i, nmappings; nmappings = 0; - KLD_LOCK(); + KLD_LOCK_READ(); TAILQ_FOREACH(lf, &linker_files, link) nmappings++; @@ -1947,7 +1960,7 @@ linker_hwpmc_list_objects(void) kobase[i].pm_address = (uintptr_t)lf->address; i++; } - KLD_UNLOCK(); + KLD_UNLOCK_READ(); KASSERT(i > 0, ("linker_hpwmc_list_objects: no kernel objects?"));