diff --git a/share/man/man5/mount.conf.5 b/share/man/man5/mount.conf.5 --- a/share/man/man5/mount.conf.5 +++ b/share/man/man5/mount.conf.5 @@ -143,6 +143,20 @@ If .Ic .timeout is not specified, the default timeout is 3 seconds. +.It Ic .hold_timeout Ar N +Before trying to mount a root file system, +if the root hold is active, wait at most +.Ar N +seconds for the root hold to drop. +A value of -1 waits forever, which was the +.Fx 11 +though +.Fx 14 +behavior for zfs, nfs and p9fs. +A value of 0 does not wait at all. +If +.Ic .hold_timeout +is not specified, the default timeout is 10 seconds. .El .Sh EXAMPLES The following example @@ -224,6 +238,22 @@ .Xr devfs 4 . If this directory does not exist, the system may hang during the bootup process. +.Pp +When root is a ZFS, NFS, and P9FS filesystem, or if +.Va vfs.mountroot.root_mount_awlays_wait +is none-zero, +.Fn vfs_mountroot +will wait up to +the +.Va .hold_timeout +set in the config file or the +.Va vfs.mountroot.hold_timeout +tunable seconds for the root holds to be dropped. +During execution of startup scripts in +.Pa /etc/rc.d , +the system will wait up to +.Va root_hold_delay +seconds for the root holds to be released. .Sh SEE ALSO .Xr nmount 2 , .Xr md 4 , diff --git a/sys/kern/vfs_mountroot.c b/sys/kern/vfs_mountroot.c --- a/sys/kern/vfs_mountroot.c +++ b/sys/kern/vfs_mountroot.c @@ -132,6 +132,10 @@ static int root_mount_timeout = 3; TUNABLE_INT("vfs.mountroot.timeout", &root_mount_timeout); +/* Wait 10s for the root holds to drop, set to 0 to ignore root hold, -1 for loop forever */ +static int root_hold_timeout = 10; +TUNABLE_INT("vfs.mountroot.hold_timeout", &root_hold_timeout); + static int root_mount_always_wait = 0; SYSCTL_INT(_vfs, OID_AUTO, root_mount_always_wait, CTLFLAG_RDTUN, &root_mount_always_wait, 0, @@ -686,6 +690,25 @@ return (error); } +static int +parse_dir_hold_timeout(char **conf) +{ + char *tok, *endtok; + long secs; + int error; + + error = parse_token(conf, &tok); + if (error) + return (error); + + secs = strtol(tok, &endtok, 0); + error = (secs < 0 || *endtok != '\0') ? EINVAL : 0; + if (!error) + root_hold_timeout = secs; + free(tok, M_TEMP); + return (error); +} + static int parse_directive(char **conf) { @@ -704,6 +727,8 @@ error = parse_dir_onfail(conf); else if (strcmp(dir, ".timeout") == 0) error = parse_dir_timeout(conf); + else if (strcmp(dir, ".hold_timeout") == 0) + error = parse_dir_hold_timeout(conf); else { printf("mountroot: invalid directive `%s'\n", dir); /* Ignore the rest of the line. */ @@ -978,14 +1003,17 @@ struct thread *td; struct timeval lastfail; int curfail; + sbintime_t start, now; TSENTER(); curfail = 0; lastfail.tv_sec = 0; + now = start = sbinuptime(); eventratecheck(&lastfail, &curfail, 1); td = curthread; - while (1) { + while (root_hold_timeout < 0 || + now - start < (SBT_1S * root_hold_timeout)) { g_waitidle(td); mtx_lock(&root_holds_mtx); if (TAILQ_EMPTY(&root_holds)) { @@ -1002,6 +1030,7 @@ msleep(&root_holds, &root_holds_mtx, PZERO | PDROP, "roothold", hz); TSUNWAIT("root mount"); + now = sbinuptime(); } g_waitidle(td);