38 #include "opt_rootdevname.h"
40 #include <sys/cdefs.h>
43 #include <sys/param.h>
46 #include <sys/fcntl.h>
48 #include <sys/kernel.h>
49 #include <sys/malloc.h>
50 #include <sys/mdioctl.h>
51 #include <sys/mount.h>
52 #include <sys/mutex.h>
53 #include <sys/namei.h>
56 #include <sys/filedesc.h>
57 #include <sys/reboot.h>
60 #include <sys/syscallsubr.h>
61 #include <sys/sysproto.h>
63 #include <sys/sysctl.h>
64 #include <sys/sysent.h>
65 #include <sys/systm.h>
66 #include <sys/vnode.h>
68 #include <geom/geom.h>
109 LIST_HEAD_INITIALIZER(root_holds);
125 TUNABLE_INT(
"vfs.mountroot.timeout", &root_mount_timeout);
135 h =
malloc(
sizeof *h, M_DEVBUF, M_ZERO | M_WAITOK);
138 LIST_INSERT_HEAD(&root_holds, h, list);
150 LIST_REMOVE(h, list);
161 return (root_mount_complete);
172 KASSERT(curthread->td_proc->p_pid != 0,
173 (
"root_mount_wait: cannot be called from the swapper thread"));
175 while (!root_mount_complete) {
188 panic(
"Cannot find root vnode");
192 p = curthread->td_proc;
193 FILEDESC_XLOCK(p->p_fd);
195 if (p->p_fd->fd_cdir != NULL)
196 vrele(p->p_fd->fd_cdir);
200 if (p->p_fd->fd_rdir != NULL)
201 vrele(p->p_fd->fd_rdir);
205 FILEDESC_XUNLOCK(p->p_fd);
211 struct vfsoptlist *opts;
219 KASSERT(vfsp != NULL, (
"Could not find devfs by name"));
225 error = VFS_MOUNT(mp);
226 KASSERT(error == 0, (
"VFS_MOUNT(devfs) failed %d", error));
230 opts =
malloc(
sizeof(
struct vfsoptlist), M_MOUNT, M_WAITOK);
235 TAILQ_INSERT_HEAD(&
mountlist, mp, mnt_list);
243 printf(
"kern_symlink /dev -> / returns %d\n", error);
252 struct mount *mporoot, *mpnroot;
253 struct vnode *vp, *vporoot, *vpdevfs;
257 mpnroot = TAILQ_NEXT(mpdevfs, mnt_list);
262 TAILQ_REMOVE(&
mountlist, mpdevfs, mnt_list);
263 if (mporoot != mpdevfs) {
264 TAILQ_REMOVE(&
mountlist, mpnroot, mnt_list);
265 TAILQ_INSERT_HEAD(&
mountlist, mpnroot, mnt_list);
267 TAILQ_INSERT_TAIL(&
mountlist, mpdevfs, mnt_list);
271 if (mporoot != mpdevfs)
274 VFS_ROOT(mporoot, LK_EXCLUSIVE, &vporoot);
277 vporoot->v_iflag &= ~VI_MOUNT;
279 vporoot->v_mountedhere = NULL;
280 mporoot->mnt_flag &= ~MNT_ROOTFS;
281 mporoot->mnt_vnodecovered = NULL;
285 mpnroot->mnt_vnodecovered = NULL;
289 if (mporoot != mpdevfs) {
292 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE,
296 NDFREE(&nd, NDF_ONLY_PNBUF);
298 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE,
304 error = (vp->v_type == VDIR) ? 0 : ENOTDIR;
309 mporoot->mnt_vnodecovered = vp;
310 vp->v_mountedhere = mporoot;
311 strlcpy(mporoot->mnt_stat.f_mntonname,
317 NDFREE(&nd, NDF_ONLY_PNBUF);
320 printf(
"mountroot: unable to remount previous root "
321 "under /.mount or /mnt (error %d).\n", error);
325 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE,
"/dev", td);
329 error = (vp->v_type == VDIR) ? 0 : ENOTDIR;
333 vpdevfs = mpdevfs->mnt_vnodecovered;
334 if (vpdevfs != NULL) {
336 vpdevfs->v_mountedhere = NULL;
339 mpdevfs->mnt_vnodecovered = vp;
340 vp->v_mountedhere = mpdevfs;
346 printf(
"mountroot: unable to remount devfs under /dev "
347 "(error %d).\n", error);
348 NDFREE(&nd, NDF_ONLY_PNBUF);
350 if (mporoot == mpdevfs) {
355 printf(
"mountroot: unable to unlink /dev/dev "
356 "(error %d)\n", error);
367 #define CC_WHITESPACE -1
368 #define CC_NONWHITESPACE -2
406 match = (c ==
' ' || c ==
'\t' || c ==
'\n') ? 1 : 0;
411 match = (c !=
' ' && c !=
'\t') ? 1 : 0;
414 match = (c == mc) ? 1 : 0;
438 *tok =
malloc(len + 1, M_TEMP, M_WAITOK | M_ZERO);
450 printf(
" %s=%s\n", var, val);
462 printf(
"\nLoader variables:\n");
466 printf(
"\nManual root filesystem specification:\n");
467 printf(
" <fstype>:<device> [options]\n");
468 printf(
" Mount <device> using filesystem <fstype>\n");
469 printf(
" and with the specified (optional) option list.\n");
471 printf(
" eg. ufs:/dev/da0s1a\n");
473 printf(
" cd9660:/dev/acd0 ro\n");
474 printf(
" (which is equivalent to: ");
475 printf(
"mount -t cd9660 -o ro /dev/acd0 /)\n");
477 printf(
" ? List valid disk boot devices\n");
478 printf(
" . Yield 1 second (for background tasks)\n");
479 printf(
" <empty line> Abort manual input\n");
484 cngets(name,
sizeof(name), GETS_ECHO);
487 if (name[0] ==
'?' && name[1] ==
'\0') {
488 printf(
"\nList of GEOM managed disk devices:\n ");
492 if (name[0] ==
'.' && name[1] ==
'\0') {
499 printf(
"Invalid file system specification.\n");
500 }
while (error != 0);
510 struct md_ioctl *mdio;
521 mdio =
malloc(
sizeof(*mdio) + len + 1, M_TEMP, M_WAITOK | M_ZERO);
522 path = (
void *)(mdio + 1);
523 bcopy(tok, path, len);
527 error =
kern_stat(td, path, UIO_SYSSPACE, &sb);
532 error =
kern_open(td,
"/dev/" MDCTL_NAME, UIO_SYSSPACE, O_RDWR, 0);
536 fd = td->td_retval[0];
537 mdio->md_version = MDIOVERSION;
538 mdio->md_type = MD_VNODE;
540 if (root_mount_mddev != -1) {
543 error =
kern_ioctl(td, fd, MDIOCDETACH, (
void *)mdio);
546 root_mount_mddev = -1;
549 mdio->md_file = (
void *)(mdio + 1);
550 mdio->md_options = MD_AUTOUNIT | MD_READONLY;
551 mdio->md_mediasize = sb.st_size;
554 error =
kern_ioctl(td, fd, MDIOCATTACH, (
void *)mdio);
559 if (mdio->md_unit > 9) {
560 printf(
"rootmount: too many md units\n");
561 mdio->md_file = NULL;
562 mdio->md_options = 0;
563 mdio->md_mediasize = 0;
565 error =
kern_ioctl(td, fd, MDIOCDETACH, (
void *)mdio);
572 root_mount_mddev = mdio->md_unit;
573 printf(MD_NAME
"%u attached to %s\n", root_mount_mddev, mdio->md_file);
592 if (!strcmp(action,
"continue"))
593 root_mount_onfail = A_CONTINUE;
594 else if (!strcmp(action,
"panic"))
595 root_mount_onfail = A_PANIC;
596 else if (!strcmp(action,
"reboot"))
597 root_mount_onfail = A_REBOOT;
598 else if (!strcmp(action,
"retry"))
599 root_mount_onfail = A_RETRY;
601 printf(
"rootmount: %s: unknown action\n", action);
605 free(action, M_TEMP);
620 secs = strtol(tok, &endtok, 0);
621 error = (secs < 0 || *endtok !=
'\0') ? EINVAL : 0;
623 root_mount_timeout = secs;
638 if (strcmp(dir,
".ask") == 0)
640 else if (strcmp(dir,
".md") == 0)
642 else if (strcmp(dir,
".onfail") == 0)
644 else if (strcmp(dir,
".timeout") == 0)
647 printf(
"mountroot: invalid directive `%s'\n", dir);
662 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, dev, curthread);
666 NDFREE(&nd, NDF_ONLY_PNBUF);
667 return (error != 0) ? 0 : 1;
676 char *dev, *fs, *opts, *tok;
692 if (root_mount_mddev != -1) {
694 tok = strstr(dev,
"md#");
701 opts = (error == 0) ? tok : NULL;
703 printf(
"Trying to mount root from %s:%s [%s]...\n", fs, dev,
704 (opts != NULL) ? opts :
"");
709 strlcpy(errmsg,
"unknown file system",
ERRMSGL);
714 if (strcmp(fs,
"zfs") != 0 && dev[0] !=
'\0' &&
716 printf(
"mountroot: waiting for device %s ...\n", dev);
718 timeout = root_mount_timeout *
hz;
720 pause(
"rmdev", delay);
740 printf(
"Mounting from %s:%s failed with error %d",
742 if (errmsg[0] !=
'\0')
747 free(errmsg, M_TEMP);
751 return ((error < 0) ? EDOOFUS : error);
762 root_mount_mddev = -1;
766 mp = TAILQ_NEXT(mpdevfs, mnt_list);
767 error = (mp == NULL) ? 0 : EDOOFUS;
768 root_mount_onfail = A_CONTINUE;
792 printf(
"mountroot: advancing to next directive...\n");
795 mp = TAILQ_NEXT(mpdevfs, mnt_list);
803 switch (root_mount_onfail) {
807 panic(
"mountroot: unable to (re-)mount root.");
822 char *s, *tok, *mnt, *opt;
826 sbuf_printf(sb,
".timeout %d\n", root_mount_timeout);
837 sbuf_printf(sb,
".timeout %d\n", root_mount_timeout);
839 s =
getenv(
"vfs.root.mountfrom");
841 opt =
getenv(
"vfs.root.mountfrom.options");
846 (opt != NULL) ? opt :
"");
869 static char buf[128];
873 int error, flags, len, vfslocked;
875 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE,
878 error =
vn_open(&nd, &flags, 0, NULL);
882 vfslocked = NDHASGIANT(&nd);
883 NDFREE(&nd, NDF_ONLY_PNBUF);
885 len =
sizeof(
buf) - 1;
887 error =
vn_rdwr(UIO_READ, nd.ni_vp, buf, len, ofs,
888 UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred,
894 buf[len - resid] = 0;
899 VOP_UNLOCK(nd.ni_vp, 0);
900 vn_close(nd.ni_vp, FREAD, td->td_ucred, td);
901 VFS_UNLOCK_GIANT(vfslocked);
909 struct timeval lastfail;
918 if (LIST_EMPTY(&root_holds)) {
923 printf(
"Root mount waiting for:");
924 LIST_FOREACH(h, &root_holds, list)
946 sb = sbuf_new_auto();
975 if (mp->mnt_time > timebase)
976 timebase = mp->mnt_time;
977 mp = TAILQ_NEXT(mp, mnt_list);
989 atomic_store_rel_int(&root_mount_complete, 1);
990 wakeup(&root_mount_complete);
993 EVENTHANDLER_INVOKE(mountroot);
1000 char *
name, *name_arg;
1001 char *val, *val_arg;
1004 if (options == NULL || options[0] ==
'\0')
1007 p = opts = strdup(options, M_MOUNT);
1012 while((name = strsep(&p,
",")) != NULL) {
1013 if (name[0] ==
'\0')
1016 val = strchr(name,
'=');
1021 if( strcmp(name,
"rw") == 0 ||
1022 strcmp(name,
"noro") == 0) {
1030 name_arg = strdup(name, M_MOUNT);
1033 val_arg = strdup(val, M_MOUNT);
1036 (val_arg != NULL ? -1 : 0));
1038 free(opts, M_MOUNT);
static int parse_skipto(char **conf, int mc)
static int vfs_mountroot_shuffle(struct thread *td, struct mount *mpdevfs)
struct callout_handle timeout(timeout_t *ftn, void *arg, int to_ticks)
int vinvalbuf(struct vnode *vp, int flags, int slpflag, int slptimeo)
int kern_close(struct thread *td, int fd)
void inittodr(time_t base)
void NDFREE(struct nameidata *ndp, const u_int flags)
static __inline void parse_poke(char **conf, int c)
int ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps)
void kern_reboot(int howto)
static int root_mount_timeout
void cngets(char *cp, size_t size, int visible)
static void vfs_mountroot_conf0(struct sbuf *sb)
void * malloc(unsigned long size, struct malloc_type *mtp, int flags)
void cache_purge(struct vnode *vp)
static int parse_dir_onfail(char **conf)
static int root_mount_mddev
static int vfs_mountroot_parse(struct sbuf *sb, struct mount *mpdevfs)
void panic(const char *fmt,...)
static int root_mount_complete
static int parse_dir_ask(char **conf)
static int vfs_mountroot_devfs(struct thread *td, struct mount **mpp)
void root_mount_rel(struct root_hold_token *h)
static LIST_HEAD(root_hold_token)
int kern_stat(struct thread *td, char *path, enum uio_seg pathseg, struct stat *sbp)
struct vfsconfhead vfsconf
static int parse_dir_timeout(char **conf)
static int parse_mount_dev_present(const char *dev)
static void vfs_mountroot_wait(void)
void vref(struct vnode *vp)
static void set_rootvnode(void)
struct vfsconf * vfs_byname(const char *name)
static int parse_dir_md(char **conf)
void vput(struct vnode *vp)
struct mount * vfs_mount_alloc(struct vnode *vp, struct vfsconf *vfsp, const char *fspath, struct ucred *cred)
void sbuf_clear(struct sbuf *s)
struct mtx root_holds_mtx
int kern_unlink(struct thread *td, char *path, enum uio_seg pathseg)
void cache_purgevfs(struct mount *mp)
void vfs_unbusy(struct mount *mp)
int kern_open(struct thread *td, char *path, enum uio_seg pathseg, int flags, int mode)
static struct mntarg * parse_mountroot_options(struct mntarg *, const char *)
int namei(struct nameidata *ndp)
int sbuf_printf(struct sbuf *s, const char *fmt,...)
struct mntarg * mount_arg(struct mntarg *ma, const char *name, const void *val, int len)
int kern_ioctl(struct thread *td, int fd, u_long com, caddr_t data)
static void parse_dir_ask_printenv(const char *var)
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)
static int vfs_mountroot_readconf(struct thread *td, struct sbuf *sb)
char * getenv(const char *name)
MTX_SYSINIT(root_holds,&root_holds_mtx,"root_holds", MTX_DEF)
static int parse_directive(char **conf)
int kernel_mount(struct mntarg *ma, uint64_t flags)
int pause(const char *wmesg, int timo)
void free(void *addr, struct malloc_type *mtp)
int vn_close(struct vnode *vp, int flags, struct ucred *file_cred, struct thread *td)
int printf(const char *fmt,...)
void sbuf_delete(struct sbuf *s)
TUNABLE_INT("vfs.mountroot.timeout",&root_mount_timeout)
void vrele(struct vnode *vp)
int kern_symlink(struct thread *td, char *path, char *link, enum uio_seg segflg)
char * sbuf_data(struct sbuf *s)
void root_mount_wait(void)
int sbuf_finish(struct sbuf *s)
static int parse_mount(char **)
static int parse_token(char **conf, char **tok)
static enum action root_mount_onfail
int vn_open(struct nameidata *ndp, int *flagp, int cmode, struct file *fp)
static __inline void parse_advance(char **conf)
static __inline int parse_peek(char **conf)
struct root_hold_token * root_mount_hold(const char *identifier)