Instrument "boot holds" for the benefit of the TSLOG framework. These

are places where the "main thread" of the booting kernel (either the
thread which later becomes swapper or the thread which later becomes
init) has to stop and wait for action to take place in another thread
before continuing.

There are currently three such holds:
1. The intr_config_hooks SYSINIT waits for hooks registered via the
config_intrhook_establish function; this allows (typically) devices
which need interrupts enabled to complete their initialization to do
so before root is mounted.

2. The g_waitidle function waits for the GEOM event queue to be empty;
this ensures that all of the disks which have been attached have been
tasted before we attempt to mount root.

3. The vfs_mountroot_wait function (in addition to calling g_waitidle)
waits for holds registered via root_mount_hold; among other things, this
is used by the USB subsystem to ensure that we don't fail to mount root
if it's located on a USB disk which takes a while to probe.
This commit is contained in:
Colin Percival 2017-12-31 09:23:52 +00:00
parent 82614df42c
commit 8b8a7c43a9
3 changed files with 13 additions and 0 deletions

View File

@ -87,9 +87,11 @@ g_waitidle(void)
g_topology_assert_not();
mtx_lock(&g_eventlock);
TSWAIT("GEOM events");
while (!TAILQ_EMPTY(&g_events))
msleep(&g_pending_events, &g_eventlock, PPAUSE,
"g_waitidle", hz/5);
TSUNWAIT("GEOM events");
mtx_unlock(&g_eventlock);
curthread->td_pflags &= ~TDP_GEOM;
}
@ -266,6 +268,7 @@ one_event(void)
ep->func(ep->arg, 0);
g_topology_assert();
mtx_lock(&g_eventlock);
TSRELEASE("GEOM events");
TAILQ_REMOVE(&g_events, ep, events);
ep->flag &= ~EV_INPROGRESS;
if (ep->flag & EV_WAKEUP) {
@ -324,6 +327,7 @@ g_cancel_event(void *ref)
break;
if (ep->ref[n] != ref)
continue;
TSRELEASE("GEOM events");
TAILQ_REMOVE(&g_events, ep, events);
ep->func(ep->arg, EV_CANCEL);
mtx_assert(&g_eventlock, MA_OWNED);
@ -367,6 +371,7 @@ g_post_event_x(g_event_t *func, void *arg, int flag, int wuflag, struct g_event
ep->func = func;
ep->arg = arg;
mtx_lock(&g_eventlock);
TSHOLD("GEOM events");
TAILQ_INSERT_TAIL(&g_events, ep, events);
mtx_unlock(&g_eventlock);
wakeup(&g_wait_event);

View File

@ -155,6 +155,7 @@ boot_run_interrupt_driven_config_hooks(void *dummy)
run_interrupt_driven_config_hooks();
/* Block boot processing until all hooks are disestablished. */
TSWAIT("config hooks");
mtx_lock(&intr_config_hook_lock);
warned = 0;
while (!TAILQ_EMPTY(&intr_config_hook_list)) {
@ -168,6 +169,7 @@ boot_run_interrupt_driven_config_hooks(void *dummy)
}
}
mtx_unlock(&intr_config_hook_lock);
TSUNWAIT("config hooks");
}
SYSINIT(intr_config_hooks, SI_SUB_INT_CONFIG_HOOKS, SI_ORDER_FIRST,
@ -183,6 +185,7 @@ config_intrhook_establish(struct intr_config_hook *hook)
{
struct intr_config_hook *hook_entry;
TSHOLD("config hooks");
mtx_lock(&intr_config_hook_lock);
TAILQ_FOREACH(hook_entry, &intr_config_hook_list, ich_links)
if (hook_entry == hook)
@ -239,6 +242,7 @@ config_intrhook_disestablish(struct intr_config_hook *hook)
if (next_to_notify == hook)
next_to_notify = TAILQ_NEXT(hook, ich_links);
TAILQ_REMOVE(&intr_config_hook_list, hook, ich_links);
TSRELEASE("config hooks");
/* Wakeup anyone watching the list */
wakeup(&intr_config_hook_list);

View File

@ -176,6 +176,7 @@ root_mount_hold(const char *identifier)
h = malloc(sizeof *h, M_DEVBUF, M_ZERO | M_WAITOK);
h->who = identifier;
mtx_lock(&root_holds_mtx);
TSHOLD("root mount");
LIST_INSERT_HEAD(&root_holds, h, list);
mtx_unlock(&root_holds_mtx);
return (h);
@ -190,6 +191,7 @@ root_mount_rel(struct root_hold_token *h)
mtx_lock(&root_holds_mtx);
LIST_REMOVE(h, list);
TSRELEASE("root mount");
wakeup(&root_holds);
mtx_unlock(&root_holds_mtx);
free(h, M_DEVBUF);
@ -956,8 +958,10 @@ vfs_mountroot_wait(void)
printf(" %s", h->who);
printf("\n");
}
TSWAIT("root mount");
msleep(&root_holds, &root_holds_mtx, PZERO | PDROP, "roothold",
hz);
TSUNWAIT("root mount");
}
TSEXIT();