From owner-svn-src-all@FreeBSD.ORG Fri Nov 11 02:15:44 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 AD6F61065676; Fri, 11 Nov 2011 02:15:44 +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 9CDAC8FC16; Fri, 11 Nov 2011 02:15:44 +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 pAB2FiAX066359; Fri, 11 Nov 2011 02:15:44 GMT (envelope-from rstone@svn.freebsd.org) Received: (from rstone@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id pAB2FilL066357; Fri, 11 Nov 2011 02:15:44 GMT (envelope-from rstone@svn.freebsd.org) Message-Id: <201111110215.pAB2FilL066357@svn.freebsd.org> From: Ryan Stone Date: Fri, 11 Nov 2011 02:15:44 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org X-SVN-Group: stable-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r227440 - stable/8/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: Fri, 11 Nov 2011 02:15:44 -0000 Author: rstone Date: Fri Nov 11 02:15:44 2011 New Revision: 227440 URL: http://svn.freebsd.org/changeset/base/227440 Log: MFC 224156: 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. Modified: stable/8/sys/kern/kern_linker.c Directory Properties: stable/8/sys/ (props changed) stable/8/sys/amd64/include/xen/ (props changed) stable/8/sys/cddl/contrib/opensolaris/ (props changed) stable/8/sys/contrib/dev/acpica/ (props changed) stable/8/sys/contrib/pf/ (props changed) Modified: stable/8/sys/kern/kern_linker.c ============================================================================== --- stable/8/sys/kern/kern_linker.c Fri Nov 11 02:13:35 2011 (r227439) +++ stable/8/sys/kern/kern_linker.c Fri Nov 11 02:15:44 2011 (r227440) @@ -68,6 +68,9 @@ int kld_debug = 0; #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) \ @@ -1014,18 +1017,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); } @@ -1097,10 +1106,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); } @@ -1919,7 +1932,7 @@ linker_hwpmc_list_objects(void) int i, nmappings; nmappings = 0; - KLD_LOCK(); + KLD_LOCK_READ(); TAILQ_FOREACH(lf, &linker_files, link) nmappings++; @@ -1934,7 +1947,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?"));