From owner-svn-src-stable@FreeBSD.ORG Tue Nov 30 22:25:45 2010 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 0D8ED1065675; Tue, 30 Nov 2010 22:25:45 +0000 (UTC) (envelope-from gibbs@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id EF03C8FC13; Tue, 30 Nov 2010 22:25:44 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id oAUMPinF040160; Tue, 30 Nov 2010 22:25:44 GMT (envelope-from gibbs@svn.freebsd.org) Received: (from gibbs@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id oAUMPiRc040158; Tue, 30 Nov 2010 22:25:44 GMT (envelope-from gibbs@svn.freebsd.org) Message-Id: <201011302225.oAUMPiRc040158@svn.freebsd.org> From: "Justin T. Gibbs" Date: Tue, 30 Nov 2010 22:25: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: r216087 - stable/8/sys/kern X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 30 Nov 2010 22:25:45 -0000 Author: gibbs Date: Tue Nov 30 22:25:44 2010 New Revision: 216087 URL: http://svn.freebsd.org/changeset/base/216087 Log: Merge revision 211236 form current: Allow interrupt driven config hooks to be registered from config hook callbacks. Interrupt driven configuration hooks serve two purposes: they are a mechanism for registering for a callback that is invoked once interrupt services are available, and they hold off root device selection so long as any configuration hooks are still active. Before this change, it was not possible to safely register additional hooks from the context of a configuration hook callback. The need for this feature arises when interrupts are required to discover new devices (e.g. access to the XenStore to find para-virtualized devices) which in turn also require the ability to hold off root device selection until some lengthy, interrupt driven, configuration task has completed (e.g. Xen front/back device driver negotiation). More specifically, the mutex protecting the list of active configuration hooks is never held during a callback, and static information is used to ensure proper ordering and only a single callback to each hook even when faced with registration or removal of a hook during an active run. Sponsored by: Spectra Logic Corporation Approved by: re (kib) Modified: stable/8/sys/kern/subr_autoconf.c Directory Properties: stable/8/sys/ (props changed) Modified: stable/8/sys/kern/subr_autoconf.c ============================================================================== --- stable/8/sys/kern/subr_autoconf.c Tue Nov 30 21:26:21 2010 (r216086) +++ stable/8/sys/kern/subr_autoconf.c Tue Nov 30 22:25:44 2010 (r216087) @@ -55,11 +55,12 @@ __FBSDID("$FreeBSD$"); */ static TAILQ_HEAD(, intr_config_hook) intr_config_hook_list = TAILQ_HEAD_INITIALIZER(intr_config_hook_list); +static struct intr_config_hook *next_to_notify; static struct mtx intr_config_hook_lock; MTX_SYSINIT(intr_config_hook, &intr_config_hook_lock, "intr config", MTX_DEF); /* ARGSUSED */ -static void run_interrupt_driven_config_hooks(void *dummy); +static void run_interrupt_driven_config_hooks(void); /* * If we wait too long for an interrupt-driven config hook to return, print @@ -91,19 +92,46 @@ run_interrupt_driven_config_hooks_warnin } static void -run_interrupt_driven_config_hooks(void *dummy) +run_interrupt_driven_config_hooks() { - struct intr_config_hook *hook_entry, *next_entry; - int warned; + static int running; + struct intr_config_hook *hook_entry; mtx_lock(&intr_config_hook_lock); - TAILQ_FOREACH_SAFE(hook_entry, &intr_config_hook_list, ich_links, - next_entry) { + + /* + * If hook processing is already active, any newly + * registered hooks will eventually be notified. + * Let the currently running session issue these + * notifications. + */ + if (running != 0) { + mtx_unlock(&intr_config_hook_lock); + return; + } + running = 1; + + while (next_to_notify != NULL) { + hook_entry = next_to_notify; + next_to_notify = TAILQ_NEXT(hook_entry, ich_links); mtx_unlock(&intr_config_hook_lock); (*hook_entry->ich_func)(hook_entry->ich_arg); mtx_lock(&intr_config_hook_lock); } + running = 0; + mtx_unlock(&intr_config_hook_lock); +} + +static void +boot_run_interrupt_driven_config_hooks(void *dummy) +{ + int warned; + + run_interrupt_driven_config_hooks(); + + /* Block boot processing until all hooks are disestablished. */ + mtx_lock(&intr_config_hook_lock); warned = 0; while (!TAILQ_EMPTY(&intr_config_hook_list)) { if (msleep(&intr_config_hook_list, &intr_config_hook_lock, @@ -117,8 +145,9 @@ run_interrupt_driven_config_hooks(void * } mtx_unlock(&intr_config_hook_lock); } + SYSINIT(intr_config_hooks, SI_SUB_INT_CONFIG_HOOKS, SI_ORDER_FIRST, - run_interrupt_driven_config_hooks, NULL); + boot_run_interrupt_driven_config_hooks, NULL); /* * Register a hook that will be called after "cold" @@ -141,10 +170,16 @@ config_intrhook_establish(struct intr_co return (1); } TAILQ_INSERT_TAIL(&intr_config_hook_list, hook, ich_links); + if (next_to_notify == NULL) + next_to_notify = hook; mtx_unlock(&intr_config_hook_lock); if (cold == 0) + /* + * XXX Call from a task since not all drivers expect + * to be re-entered at the time a hook is established. + */ /* XXX Sufficient for modules loaded after initial config??? */ - run_interrupt_driven_config_hooks(NULL); + run_interrupt_driven_config_hooks(); return (0); } @@ -161,6 +196,8 @@ config_intrhook_disestablish(struct intr panic("config_intrhook_disestablish: disestablishing an " "unestablished hook"); + if (next_to_notify == hook) + next_to_notify = TAILQ_NEXT(hook, ich_links); TAILQ_REMOVE(&intr_config_hook_list, hook, ich_links); /* Wakeup anyone watching the list */