/* * Mount (mountfrom) as the root filesystem. */ static int vfs_mountroot_try(const char *mountfrom) { struct mount *mp; char *vfsname, *devname; int error; char patt[32]; const char *cp, *ep; char *mf; vfsname = NULL; devname = NULL; mp = NULL; error = EINVAL; if (mountfrom == NULL) return(error); /* don't complain */ crit_enter(); kprintf("Mounting root from %s\n", mountfrom); crit_exit(); cp = mountfrom; /* parse vfs name and devname */ vfsname = kmalloc(MFSNAMELEN, M_MOUNT, M_WAITOK); devname = kmalloc(MNAMELEN, M_MOUNT, M_WAITOK); mf = kmalloc(MFSNAMELEN+MNAMELEN, M_MOUNT, M_WAITOK); for(;;) { for (ep = cp; (*ep != 0) && (*ep != ';'); ep++); bzero(vfsname, MFSNAMELEN); bzero(devname, MNAMELEN); bzero(mf, MFSNAMELEN+MNAMELEN); strncpy(mf, cp, MFSNAMELEN+MNAMELEN); vfsname[0] = devname[0] = 0; ksprintf(patt, "%%%d[a-z0-9]:%%%ds", MFSNAMELEN, MNAMELEN); if (ksscanf(mf, patt, vfsname, devname) < 1) goto end; /* allocate a root mount */ error = vfs_rootmountalloc(vfsname, devname[0] != 0 ? devname : ROOTNAME, &mp); if (error != 0) { kprintf("Can't allocate root mount for filesystem '%s': %d\n", vfsname, error); goto end; } mp->mnt_flag |= MNT_ROOTFS; /* do our best to set rootdev */ if ((strcmp(vfsname, "hammer") != 0) && (devname[0] != 0) && setrootbyname(devname)) kprintf("setrootbyname failed\n"); /* If the root device is a type "memory disk", mount RW */ if (rootdev != NULL && dev_is_good(rootdev) && (dev_dflags(rootdev) & D_MEMDISK)) { mp->mnt_flag &= ~MNT_RDONLY; } error = VFS_MOUNT(mp, NULL, NULL, proc0.p_ucred); if (!error) break; end: if(*ep == 0) break; cp = ep + 1; } if (vfsname != NULL) kfree(vfsname, M_MOUNT); if (devname != NULL) kfree(devname, M_MOUNT); if (mf != NULL) kfree(mf, M_MOUNT); if (error == 0) { /* register with list of mounted filesystems */ mountlist_insert(mp, MNTINS_FIRST); /* sanity check system clock against root fs timestamp */ inittodr(mp->mnt_time); vfs_unbusy(mp); if (mp->mnt_syncer == NULL) { error = vfs_allocate_syncvnode(mp); if (error) kprintf("Warning: no syncer vp for root!\n"); error = 0; } } else { if (mp != NULL) { vfs_unbusy(mp); kfree(mp, M_MOUNT); } kprintf("Root mount failed: %d\n", error); } return(error); }
int free_all_nnpfs_nodes(struct nnpfs *nnpfsp, int flags, int unmountp) { int error = 0; struct mount *mp = NNPFS_TO_VFS(nnpfsp); if (mp == NULL) { NNPFSDEB(XDEBNODE, ("free_all_nnpfs_nodes already freed\n")); return 0; } NNPFSDEB(XDEBNODE, ("free_all_nnpfs_nodes starting\n")); nnpfs_dnlc_purge_mp(mp); if (nnpfsp->root) { NNPFSDEB(XDEBNODE, ("free_all_nnpfs_nodes now removing root\n")); vgone(XNODE_TO_VNODE(nnpfsp->root)); nnpfsp->root = NULL; } NNPFSDEB(XDEBNODE, ("free_all_nnpfs_nodes root removed\n")); NNPFSDEB(XDEBNODE, ("free_all_nnpfs_nodes now killing all remaining nodes\n")); /* * If we have a syncer vnode, release it (to emulate dounmount) * and the create it again when if we are going to need it. */ #ifdef HAVE_STRUCT_MOUNT_MNT_SYNCER if (!unmountp) { if (mp->mnt_syncer != NULL) { #ifdef HAVE_KERNEL_VFS_DEALLOCATE_SYNCVNODE vfs_deallocate_syncvnode(mp); #else /* * FreeBSD and OpenBSD uses different semantics, * FreeBSD does vrele, and OpenBSD does vgone. */ #if defined(__OpenBSD__) vgone(mp->mnt_syncer); #elif defined(__FreeBSD__) vrele(mp->mnt_syncer); #else #error what os do you use ? #endif mp->mnt_syncer = NULL; #endif } } #endif error = nnpfs_vflush(mp, flags); #ifdef HAVE_STRUCT_MOUNT_MNT_SYNCER if (!unmountp) { NNPFSDEB(XDEBNODE, ("free_all_nnpfs_nodes not flushing syncer vnode\n")); if (mp->mnt_syncer == NULL) if (vfs_allocate_syncvnode(mp)) panic("failed to allocate syncer node when nnpfs daemon died"); } #endif if (error) { NNPFSDEB(XDEBNODE, ("xfree_all_nnpfs_nodes: vflush() error == %d\n", error)); return error; } NNPFSDEB(XDEBNODE, ("free_all_nnpfs_nodes done\n")); return error; }
int vfs_mountroot_devfs(void) { struct vnode *vp; struct nchandle nch; struct nlookupdata nd; struct mount *mp; struct vfsconf *vfsp; int error; struct ucred *cred = proc0.p_ucred; const char *devfs_path, *init_chroot; char *dev_malloced = NULL; if ((init_chroot = kgetenv("init_chroot")) != NULL) { size_t l; l = strlen(init_chroot) + sizeof("/dev"); dev_malloced = kmalloc(l, M_MOUNT, M_WAITOK); ksnprintf(dev_malloced, l, "%s/dev", init_chroot); devfs_path = dev_malloced; } else { devfs_path = "/dev"; } /* * Lookup the requested path and extract the nch and vnode. */ error = nlookup_init_raw(&nd, devfs_path, UIO_SYSSPACE, NLC_FOLLOW, cred, &rootnch); if (error == 0) { devfs_debug(DEVFS_DEBUG_DEBUG, "vfs_mountroot_devfs: nlookup_init is ok...\n"); if ((error = nlookup(&nd)) == 0) { devfs_debug(DEVFS_DEBUG_DEBUG, "vfs_mountroot_devfs: nlookup is ok...\n"); if (nd.nl_nch.ncp->nc_vp == NULL) { devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: nlookup: simply not found\n"); error = ENOENT; } } } if (dev_malloced != NULL) kfree(dev_malloced, M_MOUNT), dev_malloced = NULL; devfs_path = NULL; if (error) { nlookup_done(&nd); devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: nlookup failed, error: %d\n", error); return (error); } /* * Extract the locked+refd ncp and cleanup the nd structure */ nch = nd.nl_nch; cache_zero(&nd.nl_nch); nlookup_done(&nd); /* * now we have the locked ref'd nch and unreferenced vnode. */ vp = nch.ncp->nc_vp; if ((error = vget(vp, LK_EXCLUSIVE)) != 0) { cache_put(&nch); devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: vget failed\n"); return (error); } cache_unlock(&nch); if ((error = vinvalbuf(vp, V_SAVE, 0, 0)) != 0) { cache_drop(&nch); vput(vp); devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: vinvalbuf failed\n"); return (error); } if (vp->v_type != VDIR) { cache_drop(&nch); vput(vp); devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: vp is not VDIR\n"); return (ENOTDIR); } vfsp = vfsconf_find_by_name("devfs"); vsetflags(vp, VMOUNT); /* * Allocate and initialize the filesystem. */ mp = kmalloc(sizeof(struct mount), M_MOUNT, M_ZERO|M_WAITOK); mount_init(mp); vfs_busy(mp, LK_NOWAIT); mp->mnt_op = vfsp->vfc_vfsops; mp->mnt_vfc = vfsp; vfsp->vfc_refcount++; mp->mnt_stat.f_type = vfsp->vfc_typenum; mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); mp->mnt_stat.f_owner = cred->cr_uid; vn_unlock(vp); /* * Mount the filesystem. */ error = VFS_MOUNT(mp, "/dev", NULL, cred); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); /* * Put the new filesystem on the mount list after root. The mount * point gets its own mnt_ncmountpt (unless the VFS already set one * up) which represents the root of the mount. The lookup code * detects the mount point going forward and checks the root of * the mount going backwards. * * It is not necessary to invalidate or purge the vnode underneath * because elements under the mount will be given their own glue * namecache record. */ if (!error) { if (mp->mnt_ncmountpt.ncp == NULL) { /* * allocate, then unlock, but leave the ref intact */ cache_allocroot(&mp->mnt_ncmountpt, mp, NULL); cache_unlock(&mp->mnt_ncmountpt); } mp->mnt_ncmounton = nch; /* inherits ref */ nch.ncp->nc_flag |= NCF_ISMOUNTPT; /* XXX get the root of the fs and cache_setvp(mnt_ncmountpt...) */ vclrflags(vp, VMOUNT); mountlist_insert(mp, MNTINS_LAST); vn_unlock(vp); //checkdirs(&mp->mnt_ncmounton, &mp->mnt_ncmountpt); error = vfs_allocate_syncvnode(mp); if (error) { devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: vfs_allocate_syncvnode failed\n"); } vfs_unbusy(mp); error = VFS_START(mp, 0); vrele(vp); } else { vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_coherency_ops); vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_journal_ops); vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_norm_ops); vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_spec_ops); vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_fifo_ops); vclrflags(vp, VMOUNT); mp->mnt_vfc->vfc_refcount--; vfs_unbusy(mp); kfree(mp, M_MOUNT); cache_drop(&nch); vput(vp); devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: mount failed\n"); } devfs_debug(DEVFS_DEBUG_DEBUG, "rootmount_devfs done with error: %d\n", error); return (error); }
int domount(kthread_t *td, vnode_t *vp, const char *fstype, char *fspath, char *fspec, int fsflags) { struct mount *mp; struct vfsconf *vfsp; struct ucred *newcr, *oldcr; int error; /* * Be ultra-paranoid about making sure the type and fspath * variables will fit in our mp buffers, including the * terminating NUL. */ if (strlen(fstype) >= MFSNAMELEN || strlen(fspath) >= MNAMELEN) return (ENAMETOOLONG); vfsp = vfs_byname_kld(fstype, td, &error); if (vfsp == NULL) return (ENODEV); if (vp->v_type != VDIR) return (ENOTDIR); simple_lock(&vp->v_interlock); if ((vp->v_iflag & VI_MOUNT) != 0 || vp->v_mountedhere != NULL) { simple_unlock(&vp->v_interlock); return (EBUSY); } vp->v_iflag |= VI_MOUNT; simple_unlock(&vp->v_interlock); /* * Allocate and initialize the filesystem. */ vn_lock(vp, LK_SHARED | LK_RETRY); mp = vfs_mount_alloc(vp, vfsp, fspath, td); VOP_UNLOCK(vp); mp->mnt_optnew = NULL; vfs_setmntopt(mp, "from", fspec, 0); mp->mnt_optnew = mp->mnt_opt; mp->mnt_opt = NULL; /* * Set the mount level flags. * crdup() can sleep, so do it before acquiring a mutex. */ newcr = crdup(kcred); MNT_ILOCK(mp); if (fsflags & MNT_RDONLY) mp->mnt_flag |= MNT_RDONLY; mp->mnt_flag &=~ MNT_UPDATEMASK; mp->mnt_flag |= fsflags & (MNT_UPDATEMASK | MNT_FORCE | MNT_ROOTFS); /* * Unprivileged user can trigger mounting a snapshot, but we don't want * him to unmount it, so we switch to privileged credentials. */ oldcr = mp->mnt_cred; mp->mnt_cred = newcr; mp->mnt_stat.f_owner = mp->mnt_cred->cr_uid; MNT_IUNLOCK(mp); crfree(oldcr); /* * Mount the filesystem. * XXX The final recipients of VFS_MOUNT just overwrite the ndp they * get. No freeing of cn_pnbuf. */ error = VFS_MOUNT(mp, td); if (!error) { if (mp->mnt_opt != NULL) vfs_freeopts(mp->mnt_opt); mp->mnt_opt = mp->mnt_optnew; (void)VFS_STATFS(mp, &mp->mnt_stat, td); } /* * Prevent external consumers of mount options from reading * mnt_optnew. */ mp->mnt_optnew = NULL; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); /* * Put the new filesystem on the mount list after root. */ #ifdef FREEBSD_NAMECACHE cache_purge(vp); #endif if (!error) { vnode_t *mvp; simple_lock(&vp->v_interlock); vp->v_iflag &= ~VI_MOUNT; simple_unlock(&vp->v_interlock); vp->v_mountedhere = mp; mutex_enter(&mountlist_lock); CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); mutex_exit(&mountlist_lock); vfs_event_signal(NULL, VQ_MOUNT, 0); if (VFS_ROOT(mp, LK_EXCLUSIVE, &mvp, td)) panic("mount: lost mount"); mountcheckdirs(vp, mvp); vput(mvp); VOP_UNLOCK(vp); if ((mp->mnt_flag & MNT_RDONLY) == 0) error = vfs_allocate_syncvnode(mp); vfs_unbusy(mp, td); if (error) vrele(vp); else vfs_mountedfrom(mp, fspec); } else { simple_lock(&vp->v_interlock); vp->v_iflag &= ~VI_MOUNT; simple_unlock(&vp->v_interlock); VOP_UNLOCK(vp); vfs_unbusy(mp, td); vfs_mount_destroy(mp); } return (error); }