40#include "opt_rootdevname.h"
48#include <sys/eventhandler.h>
51#include <sys/kernel.h>
52#include <sys/malloc.h>
53#include <sys/mdioctl.h>
59#include <sys/filedesc.h>
60#include <sys/reboot.h>
63#include <sys/syscallsubr.h>
64#include <sys/sysproto.h>
66#include <sys/sysctl.h>
67#include <sys/sysent.h>
115 TAILQ_HEAD_INITIALIZER(root_holds);
142 "Wait for root mount holds even if the root device already exists");
145 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
147 "List of root mount hold tokens");
153 struct root_hold_token *h;
156 sbuf_new(&sb, NULL, 256, SBUF_AUTOEXTEND | SBUF_INCLUDENUL);
159 TAILQ_FOREACH(h, &root_holds, list) {
160 if (h != TAILQ_FIRST(&root_holds))
173struct root_hold_token *
176 struct root_hold_token *h;
178 h =
malloc(
sizeof *h, M_DEVBUF, M_ZERO | M_WAITOK);
182 TSHOLD(
"root mount");
183 TAILQ_INSERT_TAIL(&root_holds, h, list);
192 struct root_hold_token *t;
199 TAILQ_FOREACH(t, &root_holds, list) {
201 panic(
"Duplicate mount hold by '%s' on %p",
206 TSHOLD(
"root mount");
207 TAILQ_INSERT_TAIL(&root_holds, h, list);
215 if (h == NULL || h->flags ==
RH_FREE)
219 TAILQ_REMOVE(&root_holds, h, list);
220 TSRELEASE(
"root mount");
242 panic(
"set_rootvnode: Cannot find root vnode");
252 struct vfsoptlist *opts;
269 KASSERT(vfsp != NULL, (
"Could not find devfs by name"));
275 error = VFS_MOUNT(mp);
276 KASSERT(error == 0, (
"VFS_MOUNT(devfs) failed %d", error));
280 error = VFS_STATFS(mp, &mp->mnt_stat);
281 KASSERT(error == 0, (
"VFS_STATFS(devfs) failed %d", error));
285 opts =
malloc(
sizeof(
struct vfsoptlist), M_MOUNT, M_WAITOK);
290 TAILQ_INSERT_HEAD(&
mountlist, mp, mnt_list);
302 printf(
"kern_symlink /dev -> / returns %d\n", error);
311 struct mount *mporoot, *mpnroot;
312 struct vnode *vp, *vporoot, *vpdevfs;
316 mpnroot = TAILQ_NEXT(mpdevfs, mnt_list);
321 TAILQ_REMOVE(&
mountlist, mpdevfs, mnt_list);
322 if (mporoot != mpdevfs) {
323 TAILQ_REMOVE(&
mountlist, mpnroot, mnt_list);
324 TAILQ_INSERT_HEAD(&
mountlist, mpnroot, mnt_list);
326 TAILQ_INSERT_TAIL(&
mountlist, mpdevfs, mnt_list);
330 if (mporoot != mpdevfs)
333 if (VFS_ROOT(mporoot, LK_EXCLUSIVE, &vporoot))
334 panic(
"vfs_mountroot_shuffle: Cannot find root vnode");
337 vporoot->v_iflag &= ~VI_MOUNT;
339 vporoot->v_mountedhere = NULL;
341 mporoot->mnt_flag &= ~MNT_ROOTFS;
342 mporoot->mnt_vnodecovered = NULL;
346 mpnroot->mnt_vnodecovered = NULL;
350 if (mporoot != mpdevfs) {
353 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspath);
356 NDFREE(&nd, NDF_ONLY_PNBUF);
358 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE,
364 error = (vp->v_type == VDIR) ? 0 : ENOTDIR;
370 mporoot->mnt_vnodecovered = vp;
372 vp->v_mountedhere = mporoot;
373 strlcpy(mporoot->mnt_stat.f_mntonname,
380 NDFREE(&nd, NDF_ONLY_PNBUF);
383 printf(
"mountroot: unable to remount previous root "
384 "under /.mount or /mnt (error %d)\n", error);
388 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE,
"/dev");
392 error = (vp->v_type == VDIR) ? 0 : ENOTDIR;
396 vpdevfs = mpdevfs->mnt_vnodecovered;
397 if (vpdevfs != NULL) {
401 vpdevfs->v_mountedhere = NULL;
406 mpdevfs->mnt_vnodecovered = vp;
408 vp->v_mountedhere = mpdevfs;
415 printf(
"mountroot: unable to remount devfs under /dev "
416 "(error %d)\n", error);
417 NDFREE(&nd, NDF_ONLY_PNBUF);
419 if (mporoot == mpdevfs) {
425 printf(
"mountroot: unable to unlink /dev/dev "
426 "(error %d)\n", error);
435#define CC_WHITESPACE -1
436#define CC_NONWHITESPACE -2
474 match = (c ==
' ' || c ==
'\t' || c ==
'\n') ? 1 : 0;
479 match = (c !=
' ' && c !=
'\t') ? 1 : 0;
482 match = (c == mc) ? 1 : 0;
506 *tok =
malloc(len + 1, M_TEMP, M_WAITOK | M_ZERO);
518 printf(
" %s=%s\n", var, val);
532 printf(
"\nLoader variables:\n");
536 printf(
"\nManual root filesystem specification:\n");
537 printf(
" <fstype>:<device> [options]\n");
538 printf(
" Mount <device> using filesystem <fstype>\n");
539 printf(
" and with the specified (optional) option list.\n");
541 printf(
" eg. ufs:/dev/da0s1a\n");
542 printf(
" zfs:zroot/ROOT/default\n");
543 printf(
" cd9660:/dev/cd0 ro\n");
544 printf(
" (which is equivalent to: ");
545 printf(
"mount -t cd9660 -o ro /dev/cd0 /)\n");
547 printf(
" ? List valid disk boot devices\n");
548 printf(
" . Yield 1 second (for background tasks)\n");
549 printf(
" <empty line> Abort manual input\n");
557 if (
name[0] ==
'?' &&
name[1] ==
'\0') {
558 printf(
"\nList of GEOM managed disk devices:\n ");
562 if (
name[0] ==
'.' &&
name[1] ==
'\0') {
569 printf(
"Invalid file system specification.\n");
570 }
while (error != 0);
580 struct md_ioctl *mdio;
592 mdio =
malloc(
sizeof(*mdio) + len + 1, M_TEMP, M_WAITOK | M_ZERO);
593 path = (
void *)(mdio + 1);
594 bcopy(tok,
path, len);
603 error =
kern_openat(td, AT_FDCWD,
"/dev/" MDCTL_NAME, UIO_SYSSPACE,
608 fd = td->td_retval[0];
609 mdio->md_version = MDIOVERSION;
610 mdio->md_type = MD_VNODE;
619 mdio->md_file = (
void *)(mdio + 1);
620 mdio->md_options = MD_AUTOUNIT | MD_READONLY;
621 mdio->md_mediasize = sb.st_size;
627 if (mdio->md_unit > 9) {
628 printf(
"rootmount: too many md units\n");
629 mdio->md_file = NULL;
630 mdio->md_options = 0;
631 mdio->md_mediasize = 0;
658 if (!strcmp(action,
"continue"))
660 else if (!strcmp(action,
"panic"))
662 else if (!strcmp(action,
"reboot"))
664 else if (!strcmp(action,
"retry"))
667 printf(
"rootmount: %s: unknown action\n", action);
671 free(action, M_TEMP);
686 secs = strtol(tok, &endtok, 0);
687 error = (secs < 0 || *endtok !=
'\0') ? EINVAL : 0;
704 if (strcmp(dir,
".ask") == 0)
706 else if (strcmp(dir,
".md") == 0)
708 else if (strcmp(dir,
".onfail") == 0)
710 else if (strcmp(dir,
".timeout") == 0)
713 printf(
"mountroot: invalid directive `%s'\n", dir);
728 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, dev);
732 NDFREE(&nd, NDF_ONLY_PNBUF);
733 return (error != 0) ? 0 : 1;
742 char *dev, *fs, *opts, *tok;
743 int delay,
error, timeout;
760 tok = strstr(dev,
"md#");
767 opts = (
error == 0) ? tok : NULL;
769 printf(
"Trying to mount root from %s:%s [%s]...\n", fs, dev,
770 (opts != NULL) ? opts :
"");
775 strlcpy(errmsg,
"unknown file system",
ERRMSGL);
797 if (
error == 0 || timeout <= 0)
802 printf(
"Mounting from %s:%s failed with error %d; "
803 "retrying for %d more second%s\n", fs, dev,
error,
804 timeout /
hz, (timeout /
hz > 1) ?
"s" :
"");
806 pause(
"rmretry", delay);
811 printf(
"Mounting from %s:%s failed with error %d",
813 if (errmsg[0] !=
'\0')
818 free(errmsg, M_TEMP);
837 mp = TAILQ_NEXT(mpdevfs, mnt_list);
838 error = (mp == NULL) ? 0 : EDOOFUS;
858 printf(
"mountroot: invalid file system "
868 printf(
"mountroot: advancing to next directive...\n");
871 mp = TAILQ_NEXT(mpdevfs, mnt_list);
883 panic(
"mountroot: unable to (re-)mount root.");
898 char *s, *tok, *mnt, *opt;
922 (opt != NULL) ? opt :
"");
945 static char buf[128];
949 int error,
flags, len;
951 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE,
"/.mount.conf");
957 NDFREE(&nd, NDF_ONLY_PNBUF);
959 len =
sizeof(
buf) - 1;
961 error =
vn_rdwr(UIO_READ, nd.ni_vp,
buf, len, ofs,
962 UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred,
968 buf[len - resid] = 0;
973 VOP_UNLOCK(nd.ni_vp);
974 vn_close(nd.ni_vp, FREAD, td->td_ucred, td);
981 struct root_hold_token *h;
982 struct timeval lastfail;
993 if (TAILQ_EMPTY(&root_holds)) {
998 printf(
"Root mount waiting for:");
999 TAILQ_FOREACH(h, &root_holds, list)
1003 TSWAIT(
"root mount");
1006 TSUNWAIT(
"root mount");
1023 if (strcmp(fs,
"zfs") == 0 || strstr(fs,
"nfs") != NULL ||
1045 printf(
"mountroot: waiting for device %s...\n", dev);
1049 pause(
"rmdev", delay);
1068 mtx_assert(&
Giant, MA_NOTOWNED);
1074 sb = sbuf_new_auto();
1100 while (mp != NULL) {
1101 if (mp->mnt_time > timebase)
1102 timebase = mp->mnt_time;
1103 mp = TAILQ_NEXT(mp, mnt_list);
1119 EVENTHANDLER_INVOKE(mountroot);
1128 char *
name, *name_arg;
1129 char *val, *val_arg;
1132 if (options == NULL || options[0] ==
'\0')
1135 p = opts = strdup(options, M_MOUNT);
1140 while((
name = strsep(&p,
",")) != NULL) {
1141 if (
name[0] ==
'\0')
1144 val = strchr(
name,
'=');
1149 if (strcmp(
name,
"rw") == 0 || strcmp(
name,
"noro") == 0) {
1157 name_arg = strdup(
name, M_MOUNT);
1160 val_arg = strdup(val, M_MOUNT);
1163 (val_arg != NULL ? -1 : 0));
1165 free(opts, M_MOUNT);
void cngets(char *cp, size_t size, int visible)
int kern_close(struct thread *td, int fd)
void pwd_set_rootvnode(void)
char * kern_getenv(const char *name)
void *() malloc(size_t size, struct malloc_type *mtp, int flags)
void free(void *addr, struct malloc_type *mtp)
struct mtx __exclusive_cache_line Giant
void kern_reboot(int howto)
void panic(const char *fmt,...)
void wakeup(const void *ident)
int ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps)
int printf(const char *fmt,...)
void inittodr(time_t base)
int sbuf_finish(struct sbuf *s)
int sbuf_putc(struct sbuf *s, int c)
void sbuf_delete(struct sbuf *s)
int sbuf_printf(struct sbuf *s, const char *fmt,...)
ssize_t sbuf_len(struct sbuf *s)
char * sbuf_data(struct sbuf *s)
void sbuf_clear(struct sbuf *s)
struct sbuf * sbuf_new(struct sbuf *s, char *buf, int length, int flags)
int kern_ioctl(struct thread *td, int fd, u_long com, caddr_t data)
void cache_purgevfs(struct mount *mp)
void cache_purge(struct vnode *vp)
struct vfsconfhead vfsconf
struct vfsconf * vfs_byname(const char *name)
void() NDFREE(struct nameidata *ndp, const u_int flags)
int namei(struct nameidata *ndp)
struct mtx_padalign __exclusive_cache_line mountlist_mtx
struct mount * vfs_mount_alloc(struct vnode *vp, struct vfsconf *vfsp, const char *fspath, struct ucred *cred)
int kernel_mount(struct mntarg *ma, uint64_t flags)
void vfs_op_exit(struct mount *mp)
struct mntarg * mount_arg(struct mntarg *ma, const char *name, const void *val, int len)
SYSCTL_INT(_vfs, OID_AUTO, root_mount_always_wait, CTLFLAG_RDTUN, &root_mount_always_wait, 0, "Wait for root mount holds even if the root device already exists")
static int parse_token(char **conf, char **tok)
static int vfs_mountroot_readconf(struct thread *td, struct sbuf *sb)
static int parse_skipto(char **conf, int mc)
static __inline void parse_advance(char **conf)
static int parse_dir_onfail(char **conf)
static int parse_dir_timeout(char **conf)
static int sysctl_vfs_root_mount_hold(SYSCTL_HANDLER_ARGS)
void root_mount_hold_token(const char *identifier, struct root_hold_token *h)
static int parse_directive(char **conf)
static __inline void parse_poke(char **conf, int c)
void root_mount_rel(struct root_hold_token *h)
static __inline int parse_peek(char **conf)
static int parse_mount_dev_present(const char *dev)
TUNABLE_INT("vfs.mountroot.timeout", &root_mount_timeout)
static void parse_dir_ask_printenv(const char *var)
static void set_rootvnode(void)
static void vfs_mountroot_conf0(struct sbuf *sb)
static void vfs_mountroot_shuffle(struct thread *td, struct mount *mpdevfs)
static int parse_mount(char **)
static int parse_dir_ask(char **conf)
static int vfs_mountroot_wait_if_neccessary(const char *fs, const char *dev)
static int root_mount_always_wait
MTX_SYSINIT(root_holds, &root_holds_mtx, "root_holds", MTX_DEF)
struct mtx root_holds_mtx
static int root_mount_mddev
static struct mntarg * parse_mountroot_options(struct mntarg *, const char *)
static int root_mount_complete
static int parse_dir_md(char **conf)
SYSCTL_PROC(_vfs, OID_AUTO, root_mount_hold, CTLTYPE_STRING|CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, 0, sysctl_vfs_root_mount_hold, "A", "List of root mount hold tokens")
struct root_hold_token * root_mount_hold(const char *identifier)
static int root_mount_timeout
static int vfs_mountroot_parse(struct sbuf *sb, struct mount *mpdevfs)
static TAILQ_HEAD(root_hold_token)
static enum action root_mount_onfail
static int vfs_mountroot_devfs(struct thread *td, struct mount **mpp)
static void vfs_mountroot_wait(void)
void vref(struct vnode *vp)
void vn_irflag_unset_locked(struct vnode *vp, short tounset)
void vfs_unbusy(struct mount *mp)
void vn_irflag_set_locked(struct vnode *vp, short toset)
void vrele(struct vnode *vp)
void vput(struct vnode *vp)
int vfs_busy(struct mount *mp, int flags)
int vinvalbuf(struct vnode *vp, int flags, int slpflag, int slptimeo)
int kern_openat(struct thread *td, int fd, const char *path, enum uio_seg pathseg, int flags, int mode)
int kern_funlinkat(struct thread *td, int dfd, const char *path, int fd, enum uio_seg pathseg, int flag, ino_t oldinum)
int kern_statat(struct thread *td, int flag, int fd, const char *path, enum uio_seg pathseg, struct stat *sbp, void(*hook)(struct vnode *vp, struct stat *sbp))
int kern_symlinkat(struct thread *td, const char *path1, int fd, const char *path2, enum uio_seg segflg)
int vn_rdwr(enum uio_rw rw, struct vnode *vp, void *base, int len, off_t offset, enum uio_seg segflg, int ioflg, struct ucred *active_cred, struct ucred *file_cred, ssize_t *aresid, struct thread *td)
int vn_open(struct nameidata *ndp, int *flagp, int cmode, struct file *fp)
int vn_close(struct vnode *vp, int flags, struct ucred *file_cred, struct thread *td)