/* * Mount a pseudofs instance */ int pfs_mount(struct pfs_info *pi, struct mount *mp) { struct statfs *sbp; if (mp->mnt_flag & MNT_UPDATE) return (EOPNOTSUPP); MNT_ILOCK(mp); mp->mnt_flag |= MNT_LOCAL; mp->mnt_kern_flag |= MNTK_MPSAFE; MNT_IUNLOCK(mp); mp->mnt_data = pi; vfs_getnewfsid(mp); sbp = &mp->mnt_stat; vfs_mountedfrom(mp, pi->pi_name); sbp->f_bsize = PAGE_SIZE; sbp->f_iosize = PAGE_SIZE; sbp->f_blocks = 1; sbp->f_bfree = 0; sbp->f_bavail = 0; sbp->f_files = 1; sbp->f_ffree = 0; return (0); }
/* * Mount the filesystem */ static int devfs_mount(struct mount *mp) { int error; struct devfs_mount *fmp; struct vnode *rvp; if (devfs_unr == NULL) devfs_unr = new_unrhdr(0, INT_MAX, NULL); error = 0; if (mp->mnt_flag & (MNT_UPDATE | MNT_ROOTFS)) return (EOPNOTSUPP); fmp = malloc(sizeof *fmp, M_DEVFS, M_WAITOK | M_ZERO); fmp->dm_idx = alloc_unr(devfs_unr); sx_init(&fmp->dm_lock, "devfsmount"); fmp->dm_holdcnt = 1; MNT_ILOCK(mp); mp->mnt_flag |= MNT_LOCAL; mp->mnt_kern_flag |= MNTK_MPSAFE | MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED; #ifdef MAC mp->mnt_flag |= MNT_MULTILABEL; #endif MNT_IUNLOCK(mp); fmp->dm_mount = mp; mp->mnt_data = (void *) fmp; vfs_getnewfsid(mp); fmp->dm_rootdir = devfs_vmkdir(fmp, NULL, 0, NULL, DEVFS_ROOTINO); error = devfs_root(mp, LK_EXCLUSIVE, &rvp); if (error) { sx_destroy(&fmp->dm_lock); free_unr(devfs_unr, fmp->dm_idx); free(fmp, M_DEVFS); return (error); } VOP_UNLOCK(rvp, 0); vfs_mountedfrom(mp, "devfs"); return (0); }
/* * Mount the per-process file descriptors (/dev/fd) */ static int fdesc_mount(struct mount *mp) { int error = 0; struct fdescmount *fmp; struct vnode *rvp; /* * Update is a no-op */ if (mp->mnt_flag & (MNT_UPDATE | MNT_ROOTFS)) return (EOPNOTSUPP); fmp = malloc(sizeof(struct fdescmount), M_FDESCMNT, M_WAITOK); /* XXX */ /* * We need to initialize a few bits of our local mount point struct to * avoid confusion in allocvp. */ mp->mnt_data = (qaddr_t) fmp; fmp->flags = 0; error = fdesc_allocvp(Froot, -1, FD_ROOT, mp, &rvp); if (error) { free(fmp, M_FDESCMNT); mp->mnt_data = 0; return (error); } rvp->v_type = VDIR; rvp->v_vflag |= VV_ROOT; fmp->f_root = rvp; VOP_UNLOCK(rvp, 0); /* XXX -- don't mark as local to work around fts() problems */ /*mp->mnt_flag |= MNT_LOCAL;*/ MNT_ILOCK(mp); mp->mnt_kern_flag |= MNTK_MPSAFE; MNT_IUNLOCK(mp); vfs_getnewfsid(mp); vfs_mountedfrom(mp, "fdescfs"); return (0); }
static int udf_mount(struct mount *mp) { struct vnode *devvp; /* vnode of the mount device */ struct thread *td; struct udf_mnt *imp = NULL; struct vfsoptlist *opts; char *fspec, *cs_disk, *cs_local; int error, len, *udf_flags; struct nameidata nd, *ndp = &nd; td = curthread; opts = mp->mnt_optnew; /* * Unconditionally mount as read-only. */ MNT_ILOCK(mp); mp->mnt_flag |= MNT_RDONLY; MNT_IUNLOCK(mp); /* * No root filesystem support. Probably not a big deal, since the * bootloader doesn't understand UDF. */ if (mp->mnt_flag & MNT_ROOTFS) return (ENOTSUP); fspec = NULL; error = vfs_getopt(opts, "from", (void **)&fspec, &len); if (!error && fspec[len - 1] != '\0') return (EINVAL); if (mp->mnt_flag & MNT_UPDATE) { return (0); } /* Check that the mount device exists */ if (fspec == NULL) return (EINVAL); NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspec, td); if ((error = namei(ndp))) return (error); NDFREE(ndp, NDF_ONLY_PNBUF); devvp = ndp->ni_vp; if (vn_isdisk(devvp, &error) == 0) { vput(devvp); return (error); } /* Check the access rights on the mount device */ error = VOP_ACCESS(devvp, VREAD, td->td_ucred, td); if (error) error = priv_check(td, PRIV_VFS_MOUNT_PERM); if (error) { vput(devvp); return (error); } if ((error = udf_mountfs(devvp, mp))) { vrele(devvp); return (error); } imp = VFSTOUDFFS(mp); udf_flags = NULL; error = vfs_getopt(opts, "flags", (void **)&udf_flags, &len); if (error || len != sizeof(int)) return (EINVAL); imp->im_flags = *udf_flags; if (imp->im_flags & UDFMNT_KICONV && udf_iconv) { cs_disk = NULL; error = vfs_getopt(opts, "cs_disk", (void **)&cs_disk, &len); if (!error && cs_disk[len - 1] != '\0') return (EINVAL); cs_local = NULL; error = vfs_getopt(opts, "cs_local", (void **)&cs_local, &len); if (!error && cs_local[len - 1] != '\0') return (EINVAL); udf_iconv->open(cs_local, cs_disk, &imp->im_d2l); #if 0 udf_iconv->open(cs_disk, cs_local, &imp->im_l2d); #endif } vfs_mountedfrom(mp, fspec); return 0; };
/* * mp - path - addr in user space of mount point (ie /usr or whatever) * data - addr in user space of mount params including the name of the block * special file to treat as a filesystem. */ static int msdosfs_mount(struct mount *mp) { struct vnode *devvp; /* vnode for blk device to mount */ struct thread *td; /* msdosfs specific mount control block */ struct msdosfsmount *pmp = NULL; struct nameidata ndp; int error, flags; accmode_t accmode; char *from; td = curthread; if (vfs_filteropt(mp->mnt_optnew, msdosfs_opts)) return (EINVAL); /* * If updating, check whether changing from read-only to * read/write; if there is no device name, that's all we do. */ if (mp->mnt_flag & MNT_UPDATE) { pmp = VFSTOMSDOSFS(mp); if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) { /* * Forbid export requests if filesystem has * MSDOSFS_LARGEFS flag set. */ if ((pmp->pm_flags & MSDOSFS_LARGEFS) != 0) { vfs_mount_error(mp, "MSDOSFS_LARGEFS flag set, cannot export"); return (EOPNOTSUPP); } } if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) { error = VFS_SYNC(mp, MNT_WAIT); if (error) return (error); flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; error = vflush(mp, 0, flags, td); if (error) return (error); /* * Now the volume is clean. Mark it so while the * device is still rw. */ error = markvoldirty(pmp, 0); if (error) { (void)markvoldirty(pmp, 1); return (error); } /* Downgrade the device from rw to ro. */ DROP_GIANT(); g_topology_lock(); error = g_access(pmp->pm_cp, 0, -1, 0); g_topology_unlock(); PICKUP_GIANT(); if (error) { (void)markvoldirty(pmp, 1); return (error); } /* * Backing out after an error was painful in the * above. Now we are committed to succeeding. */ pmp->pm_fmod = 0; pmp->pm_flags |= MSDOSFSMNT_RONLY; MNT_ILOCK(mp); mp->mnt_flag |= MNT_RDONLY; MNT_IUNLOCK(mp); } else if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && !vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) { /* * If upgrade to read-write by non-root, then verify * that user has necessary permissions on the device. */ devvp = pmp->pm_devvp; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); error = VOP_ACCESS(devvp, VREAD | VWRITE, td->td_ucred, td); if (error) error = priv_check(td, PRIV_VFS_MOUNT_PERM); if (error) { VOP_UNLOCK(devvp, 0); return (error); } VOP_UNLOCK(devvp, 0); DROP_GIANT(); g_topology_lock(); error = g_access(pmp->pm_cp, 0, 1, 0); g_topology_unlock(); PICKUP_GIANT(); if (error) return (error); pmp->pm_fmod = 1; pmp->pm_flags &= ~MSDOSFSMNT_RONLY; MNT_ILOCK(mp); mp->mnt_flag &= ~MNT_RDONLY; MNT_IUNLOCK(mp); /* Now that the volume is modifiable, mark it dirty. */ error = markvoldirty(pmp, 1); if (error) return (error); } } /* * Not an update, or updating the name: look up the name * and verify that it refers to a sensible disk device. */ if (vfs_getopt(mp->mnt_optnew, "from", (void **)&from, NULL)) return (EINVAL); NDINIT(&ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, from, td); error = namei(&ndp); if (error) return (error); devvp = ndp.ni_vp; NDFREE(&ndp, NDF_ONLY_PNBUF); if (!vn_isdisk(devvp, &error)) { vput(devvp); return (error); } /* * If mount by non-root, then verify that user has necessary * permissions on the device. */ accmode = VREAD; if ((mp->mnt_flag & MNT_RDONLY) == 0) accmode |= VWRITE; error = VOP_ACCESS(devvp, accmode, td->td_ucred, td); if (error) error = priv_check(td, PRIV_VFS_MOUNT_PERM); if (error) { vput(devvp); return (error); } if ((mp->mnt_flag & MNT_UPDATE) == 0) { error = mountmsdosfs(devvp, mp); #ifdef MSDOSFS_DEBUG /* only needed for the printf below */ pmp = VFSTOMSDOSFS(mp); #endif } else { vput(devvp); if (devvp != pmp->pm_devvp) return (EINVAL); /* XXX needs translation */ } if (error) { vrele(devvp); return (error); } error = update_mp(mp, td); if (error) { if ((mp->mnt_flag & MNT_UPDATE) == 0) msdosfs_unmount(mp, MNT_FORCE); return error; } if (devvp->v_type == VCHR && devvp->v_rdev != NULL) devvp->v_rdev->si_mountpt = mp; vfs_mountedfrom(mp, from); #ifdef MSDOSFS_DEBUG printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); #endif return (0); }
/* * VFS Operations. * * mount system call */ static int ext2_mount(struct mount *mp) { struct vfsoptlist *opts; struct vnode *devvp; struct thread *td; struct ext2mount *ump = NULL; struct m_ext2fs *fs; struct nameidata nd, *ndp = &nd; accmode_t accmode; char *path, *fspec; int error, flags, len; td = curthread; opts = mp->mnt_optnew; if (vfs_filteropt(opts, ext2_opts)) return (EINVAL); vfs_getopt(opts, "fspath", (void **)&path, NULL); /* Double-check the length of path.. */ if (strlen(path) >= MAXMNTLEN - 1) return (ENAMETOOLONG); fspec = NULL; error = vfs_getopt(opts, "from", (void **)&fspec, &len); if (!error && fspec[len - 1] != '\0') return (EINVAL); /* * If updating, check whether changing from read-only to * read/write; if there is no device name, that's all we do. */ if (mp->mnt_flag & MNT_UPDATE) { ump = VFSTOEXT2(mp); fs = ump->um_e2fs; error = 0; if (fs->e2fs_ronly == 0 && vfs_flagopt(opts, "ro", NULL, 0)) { error = VFS_SYNC(mp, MNT_WAIT); if (error) return (error); flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; error = ext2_flushfiles(mp, flags, td); if ( error == 0 && fs->e2fs_wasvalid && ext2_cgupdate(ump, MNT_WAIT) == 0) { fs->e2fs->e2fs_state |= E2FS_ISCLEAN; ext2_sbupdate(ump, MNT_WAIT); } fs->e2fs_ronly = 1; vfs_flagopt(opts, "ro", &mp->mnt_flag, MNT_RDONLY); DROP_GIANT(); g_topology_lock(); g_access(ump->um_cp, 0, -1, 0); g_topology_unlock(); PICKUP_GIANT(); } if (!error && (mp->mnt_flag & MNT_RELOAD)) error = ext2_reload(mp, td); if (error) return (error); devvp = ump->um_devvp; if (fs->e2fs_ronly && !vfs_flagopt(opts, "ro", NULL, 0)) { if (ext2_check_sb_compat(fs->e2fs, devvp->v_rdev, 0)) return (EPERM); /* * If upgrade to read-write by non-root, then verify * that user has necessary permissions on the device. */ vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); error = VOP_ACCESS(devvp, VREAD | VWRITE, td->td_ucred, td); if (error) error = priv_check(td, PRIV_VFS_MOUNT_PERM); if (error) { VOP_UNLOCK(devvp, 0); return (error); } VOP_UNLOCK(devvp, 0); DROP_GIANT(); g_topology_lock(); error = g_access(ump->um_cp, 0, 1, 0); g_topology_unlock(); PICKUP_GIANT(); if (error) return (error); if ((fs->e2fs->e2fs_state & E2FS_ISCLEAN) == 0 || (fs->e2fs->e2fs_state & E2FS_ERRORS)) { if (mp->mnt_flag & MNT_FORCE) { printf( "WARNING: %s was not properly dismounted\n", fs->e2fs_fsmnt); } else { printf( "WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck\n", fs->e2fs_fsmnt); return (EPERM); } } fs->e2fs->e2fs_state &= ~E2FS_ISCLEAN; (void)ext2_cgupdate(ump, MNT_WAIT); fs->e2fs_ronly = 0; MNT_ILOCK(mp); mp->mnt_flag &= ~MNT_RDONLY; MNT_IUNLOCK(mp); } if (vfs_flagopt(opts, "export", NULL, 0)) { /* Process export requests in vfs_mount.c. */ return (error); } } /* * Not an update, or updating the name: look up the name * and verify that it refers to a sensible disk device. */ if (fspec == NULL) return (EINVAL); NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspec, td); if ((error = namei(ndp)) != 0) return (error); NDFREE(ndp, NDF_ONLY_PNBUF); devvp = ndp->ni_vp; if (!vn_isdisk(devvp, &error)) { vput(devvp); return (error); } /* * If mount by non-root, then verify that user has necessary * permissions on the device. * * XXXRW: VOP_ACCESS() enough? */ accmode = VREAD; if ((mp->mnt_flag & MNT_RDONLY) == 0) accmode |= VWRITE; error = VOP_ACCESS(devvp, accmode, td->td_ucred, td); if (error) error = priv_check(td, PRIV_VFS_MOUNT_PERM); if (error) { vput(devvp); return (error); } if ((mp->mnt_flag & MNT_UPDATE) == 0) { error = ext2_mountfs(devvp, mp); } else { if (devvp != ump->um_devvp) { vput(devvp); return (EINVAL); /* needs translation */ } else vput(devvp); } if (error) { vrele(devvp); return (error); } ump = VFSTOEXT2(mp); fs = ump->um_e2fs; /* * Note that this strncpy() is ok because of a check at the start * of ext2_mount(). */ strncpy(fs->e2fs_fsmnt, path, MAXMNTLEN); fs->e2fs_fsmnt[MAXMNTLEN - 1] = '\0'; vfs_mountedfrom(mp, fspec); return (0); }
/*ARGSUSED*/ int coda_mount(struct mount *vfsp) { struct vnode *dvp; struct cnode *cp; struct cdev *dev; struct coda_mntinfo *mi; struct vnode *rootvp; struct CodaFid rootfid = INVAL_FID; struct CodaFid ctlfid = CTL_FID; int error; struct nameidata ndp; ENTRY; char *from; if (vfs_filteropt(vfsp->mnt_optnew, coda_opts)) return (EINVAL); from = vfs_getopts(vfsp->mnt_optnew, "from", &error); if (error) return (error); coda_vfsopstats_init(); coda_vnodeopstats_init(); MARK_ENTRY(CODA_MOUNT_STATS); if (CODA_MOUNTED(vfsp)) { MARK_INT_FAIL(CODA_MOUNT_STATS); return (EBUSY); } /* * Validate mount device. Similar to getmdev(). */ NDINIT(&ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, from, curthread); error = namei(&ndp); dvp = ndp.ni_vp; if (error) { MARK_INT_FAIL(CODA_MOUNT_STATS); return (error); } if (dvp->v_type != VCHR) { MARK_INT_FAIL(CODA_MOUNT_STATS); vrele(dvp); NDFREE(&ndp, NDF_ONLY_PNBUF); return (ENXIO); } dev = dvp->v_rdev; vrele(dvp); NDFREE(&ndp, NDF_ONLY_PNBUF); /* * Initialize the mount record and link it to the vfs struct. */ mi = dev2coda_mntinfo(dev); if (!mi) { MARK_INT_FAIL(CODA_MOUNT_STATS); printf("Coda mount: %s is not a cfs device\n", from); return (ENXIO); } if (!VC_OPEN(&mi->mi_vcomm)) { MARK_INT_FAIL(CODA_MOUNT_STATS); return (ENODEV); } /* * No initialization (here) of mi_vcomm! */ vfsp->mnt_data = mi; vfs_getnewfsid (vfsp); mi->mi_vfsp = vfsp; mi->mi_started = 0; /* XXX See coda_root() */ /* * Make a root vnode to placate the Vnode interface, but don't * actually make the CODA_ROOT call to venus until the first call to * coda_root in case a server is down while venus is starting. */ cp = make_coda_node(&rootfid, vfsp, VDIR); rootvp = CTOV(cp); rootvp->v_vflag |= VV_ROOT; cp = make_coda_node(&ctlfid, vfsp, VREG); coda_ctlvp = CTOV(cp); /* * Add vfs and rootvp to chain of vfs hanging off mntinfo. */ mi->mi_vfsp = vfsp; mi->mi_rootvp = rootvp; vfs_mountedfrom(vfsp, from); /* * Error is currently guaranteed to be zero, but in case some code * changes... */ CODADEBUG(1, myprintf(("coda_mount returned %d\n", error)););
static int ntfs_mount(struct mount *mp) { int err = 0, error; struct vnode *devvp; struct nameidata ndp; struct thread *td; char *from; td = curthread; if (vfs_filteropt(mp->mnt_optnew, ntfs_opts)) return (EINVAL); /* Force mount as read-only. */ MNT_ILOCK(mp); mp->mnt_flag |= MNT_RDONLY; MNT_IUNLOCK(mp); from = vfs_getopts(mp->mnt_optnew, "from", &error); if (error) return (error); /* * If updating, check whether changing from read-only to * read/write. */ if (mp->mnt_flag & MNT_UPDATE) { if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) { /* Process export requests in vfs_mount.c */ return (0); } else { printf("ntfs_mount(): MNT_UPDATE not supported\n"); return (EINVAL); } } /* * Not an update, or updating the name: look up the name * and verify that it refers to a sensible block device. */ NDINIT(&ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, from, td); err = namei(&ndp); if (err) return (err); NDFREE(&ndp, NDF_ONLY_PNBUF); devvp = ndp.ni_vp; if (!vn_isdisk(devvp, &err)) { vput(devvp); return (err); } /* * If mount by non-root, then verify that user has necessary * permissions on the device. */ err = VOP_ACCESS(devvp, VREAD, td->td_ucred, td); if (err) err = priv_check(td, PRIV_VFS_MOUNT_PERM); if (err) { vput(devvp); return (err); } /* * Since this is a new mount, we want the names for the device and * the mount point copied in. If an error occurs, the mountpoint is * discarded by the upper level code. Note that vfs_mount() handles * copying the mountpoint f_mntonname for us, so we don't have to do * it here unless we want to set it to something other than "path" * for some rason. */ err = ntfs_mountfs(devvp, mp, td); if (err == 0) { /* Save "mounted from" info for mount point. */ vfs_mountedfrom(mp, from); } else vrele(devvp); return (err); }
static int _xfs_param_copyin(struct mount *mp, struct thread *td) { struct xfsmount *xmp = MNTTOXFS(mp); struct xfs_mount_args *args = &xmp->m_args; char *path; char *fsname; char *rtname; char *logname; int error; path = vfs_getopts(mp->mnt_optnew, "fspath", &error); if (error) return (error); bzero(args, sizeof(struct xfs_mount_args)); args->logbufs = -1; args->logbufsize = -1; parse_int(mp, "flags", &args->flags, &error); if (error != 0 && error != ENOENT) return error; args->flags |= XFSMNT_32BITINODES; parse_int(mp, "sunit", &args->sunit, &error); if (error != 0 && error != ENOENT) return error; parse_int(mp, "swidth", &args->swidth, &error); if (error != 0 && error != ENOENT) return error; parse_int(mp, "logbufs", &args->logbufs, &error); if (error != 0 && error != ENOENT) return error; parse_int(mp, "logbufsize", &args->logbufsize, &error); if (error != 0 && error != ENOENT) return error; fsname = vfs_getopts(mp->mnt_optnew, "from", &error); if (error == 0 && fsname != NULL) { strncpy(args->fsname, fsname, sizeof(args->fsname) - 1); } logname = vfs_getopts(mp->mnt_optnew, "logname", &error); if (error == 0 && logname != NULL) { strncpy(args->logname, logname, sizeof(args->logname) - 1); } rtname = vfs_getopts(mp->mnt_optnew, "rtname", &error); if (error == 0 && rtname != NULL) { strncpy(args->rtname, rtname, sizeof(args->rtname) - 1); } strncpy(args->mtpt, path, sizeof(args->mtpt)); printf("fsname '%s' logname '%s' rtname '%s'\n" "flags 0x%x sunit %d swidth %d logbufs %d logbufsize %d\n", args->fsname, args->logname, args->rtname, args->flags, args->sunit, args->swidth, args->logbufs, args->logbufsize); vfs_mountedfrom(mp, args->fsname); return (0); }
VMBlockVFSMount(struct mount *mp, // IN: mount(2) parameters struct thread *td) // IN: caller's thread context #endif { struct VMBlockMount *xmp; struct nameidata nd, *ndp = &nd; struct vnode *lowerrootvp, *vp; char *target; char *pathname; int len, error = 0; VMBLOCKDEBUG("VMBlockVFSMount(mp = %p)\n", (void *)mp); /* * TODO: Strip out extraneous export & other misc cruft. */ /* * Disallow the following: * 1. Mounting over the system root. * 2. Mount updates/remounts. (Reconsider for rw->ro, ro->rw?) * 3. Mounting VMBlock on top of a VMBlock. */ if ((mp->mnt_flag & MNT_ROOTFS) || (mp->mnt_flag & MNT_UPDATE) || (mp->mnt_vnodecovered->v_op == &VMBlockVnodeOps)) { return EOPNOTSUPP; } /* * XXX Should only be unlocked if mnt_flag & MNT_UPDATE. */ ASSERT_VOP_UNLOCKED(mp->mnt_vnodecovered, "Covered vnode already locked!"); /* * Look up path to lower layer (VMBlock source / DnD staging area). * (E.g., in the command "mount /tmp/VMwareDnD /var/run/vmblock", * /tmp/VMwareDnD is the staging area.) */ error = vfs_getopt(mp->mnt_optnew, "target", (void **)&target, &len); if (error || target[len - 1] != '\0') { return EINVAL; } pathname = uma_zalloc(VMBlockPathnameZone, M_WAITOK); if (pathname == NULL) { return ENOMEM; } if (strlcpy(pathname, target, MAXPATHLEN) >= MAXPATHLEN) { uma_zfree(VMBlockPathnameZone, pathname); return ENAMETOOLONG; } /* * Find lower node and lock if not already locked. */ NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, target, compat_td); error = namei(ndp); if (error) { NDFREE(ndp, 0); uma_zfree(VMBlockPathnameZone, pathname); return error; } NDFREE(ndp, NDF_ONLY_PNBUF); /* * Check multi VMBlock mount to avoid `lock against myself' panic. */ lowerrootvp = ndp->ni_vp; if (lowerrootvp == VPTOVMB(mp->mnt_vnodecovered)->lowerVnode) { VMBLOCKDEBUG("VMBlockVFSMount: multi vmblock mount?\n"); vput(lowerrootvp); uma_zfree(VMBlockPathnameZone, pathname); return EDEADLK; } xmp = malloc(sizeof *xmp, M_VMBLOCKFSMNT, M_WAITOK); /* * Record pointer (mountVFS) to the staging area's file system. Follow up * by grabbing a VMBlockNode for our layer's root. */ xmp->mountVFS = lowerrootvp->v_mount; error = VMBlockNodeGet(mp, lowerrootvp, &vp, pathname); /* * Make sure the node alias worked */ if (error) { COMPAT_VOP_UNLOCK(vp, 0, compat_td); vrele(lowerrootvp); free(xmp, M_VMBLOCKFSMNT); /* XXX */ uma_zfree(VMBlockPathnameZone, pathname); return error; } /* * Record a reference to the new filesystem's root vnode & mark it as such. */ xmp->rootVnode = vp; xmp->rootVnode->v_vflag |= VV_ROOT; /* * Unlock the node (either the lower or the alias) */ COMPAT_VOP_UNLOCK(vp, 0, compat_td); /* * If the staging area is a local filesystem, reflect that here, too. (We * could potentially allow NFS staging areas.) */ MNT_ILOCK(mp); mp->mnt_flag |= lowerrootvp->v_mount->mnt_flag & MNT_LOCAL; #if __FreeBSD_version >= 600000 && __FreeBSD_version < 1000000 mp->mnt_kern_flag |= lowerrootvp->v_mount->mnt_kern_flag & MNTK_MPSAFE; #endif MNT_IUNLOCK(mp); mp->mnt_data = (qaddr_t) xmp; vfs_getnewfsid(mp); vfs_mountedfrom(mp, target); VMBLOCKDEBUG("VMBlockVFSMount: lower %s, alias at %s\n", mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); return 0; }
/* * Mount the per-process file descriptors (/dev/fd) */ static int portal_mount(struct mount *mp) { struct file *fp; struct portalmount *fmp; struct socket *so; struct vnode *rvp; struct thread *td; struct portalnode *pn; int error, v; char *p; td = curthread; if (vfs_filteropt(mp->mnt_optnew, portal_opts)) return (EINVAL); error = vfs_scanopt(mp->mnt_optnew, "socket", "%d", &v); if (error != 1) return (EINVAL); error = vfs_getopt(mp->mnt_optnew, "config", (void **)&p, NULL); if (error) return (error); /* * Capsicum is not incompatible with portalfs, but we don't really * know what rights are required. In the spirit of "better safe than * sorry", pretend that all rights are required for now. */ if ((error = fget(td, v, CAP_MASK_VALID, &fp)) != 0) return (error); if (fp->f_type != DTYPE_SOCKET) { fdrop(fp, td); return(ENOTSOCK); } so = fp->f_data; /* XXX race against userland */ if (so->so_proto->pr_domain->dom_family != AF_UNIX) { fdrop(fp, td); return (ESOCKTNOSUPPORT); } pn = malloc(sizeof(struct portalnode), M_TEMP, M_WAITOK); fmp = malloc(sizeof(struct portalmount), M_PORTALFSMNT, M_WAITOK); /* XXX */ error = getnewvnode("portal", mp, &portal_vnodeops, &rvp); /* XXX */ if (error) { free(fmp, M_PORTALFSMNT); free(pn, M_TEMP); fdrop(fp, td); return (error); } error = insmntque(rvp, mp); /* XXX: Too early for mpsafe fs */ if (error != 0) { free(fmp, M_PORTALFSMNT); free(pn, M_TEMP); fdrop(fp, td); return (error); } rvp->v_data = pn; rvp->v_type = VDIR; rvp->v_vflag |= VV_ROOT; VTOPORTAL(rvp)->pt_arg = 0; VTOPORTAL(rvp)->pt_size = 0; VTOPORTAL(rvp)->pt_fileid = PORTAL_ROOTFILEID; fmp->pm_root = rvp; fhold(fp); fmp->pm_server = fp; MNT_ILOCK(mp); mp->mnt_flag |= MNT_LOCAL; MNT_IUNLOCK(mp); mp->mnt_data = fmp; vfs_getnewfsid(mp); vfs_mountedfrom(mp, p); fdrop(fp, td); return (0); }
static int zfs_domount(vfs_t *vfsp, char *osname) { uint64_t recordsize, readonly; int error = 0; int mode; zfsvfs_t *zfsvfs; znode_t *zp = NULL; ASSERT(vfsp); ASSERT(osname); /* * Initialize the zfs-specific filesystem structure. * Should probably make this a kmem cache, shuffle fields, * and just bzero up to z_hold_mtx[]. */ zfsvfs = kmem_zalloc(sizeof (zfsvfs_t), KM_SLEEP); zfsvfs->z_vfs = vfsp; zfsvfs->z_parent = zfsvfs; zfsvfs->z_assign = TXG_NOWAIT; zfsvfs->z_max_blksz = SPA_MAXBLOCKSIZE; zfsvfs->z_show_ctldir = ZFS_SNAPDIR_VISIBLE; mutex_init(&zfsvfs->z_znodes_lock, NULL, MUTEX_DEFAULT, NULL); mutex_init(&zfsvfs->z_online_recv_lock, NULL, MUTEX_DEFAULT, NULL); list_create(&zfsvfs->z_all_znodes, sizeof (znode_t), offsetof(znode_t, z_link_node)); rrw_init(&zfsvfs->z_teardown_lock); rw_init(&zfsvfs->z_teardown_inactive_lock, NULL, RW_DEFAULT, NULL); rw_init(&zfsvfs->z_fuid_lock, NULL, RW_DEFAULT, NULL); if (error = dsl_prop_get_integer(osname, "recordsize", &recordsize, NULL)) goto out; zfsvfs->z_vfs->vfs_bsize = recordsize; vfsp->vfs_data = zfsvfs; vfsp->mnt_flag |= MNT_LOCAL; vfsp->mnt_kern_flag |= MNTK_MPSAFE; vfsp->mnt_kern_flag |= MNTK_LOOKUP_SHARED; vfsp->mnt_kern_flag |= MNTK_SHARED_WRITES; if (error = dsl_prop_get_integer(osname, "readonly", &readonly, NULL)) goto out; mode = DS_MODE_OWNER; if (readonly) mode |= DS_MODE_READONLY; error = dmu_objset_open(osname, DMU_OST_ZFS, mode, &zfsvfs->z_os); if (error == EROFS) { mode = DS_MODE_OWNER | DS_MODE_READONLY; error = dmu_objset_open(osname, DMU_OST_ZFS, mode, &zfsvfs->z_os); } if (error) goto out; if (error = zfs_init_fs(zfsvfs, &zp)) goto out; /* * Set features for file system. */ zfsvfs->z_use_fuids = USE_FUIDS(zfsvfs->z_version, zfsvfs->z_os); if (zfsvfs->z_use_fuids) { vfs_set_feature(vfsp, VFSFT_XVATTR); vfs_set_feature(vfsp, VFSFT_SYSATTR_VIEWS); vfs_set_feature(vfsp, VFSFT_ACEMASKONACCESS); vfs_set_feature(vfsp, VFSFT_ACLONCREATE); } if (zfsvfs->z_case == ZFS_CASE_INSENSITIVE) { vfs_set_feature(vfsp, VFSFT_DIRENTFLAGS); vfs_set_feature(vfsp, VFSFT_CASEINSENSITIVE); vfs_set_feature(vfsp, VFSFT_NOCASESENSITIVE); } else if (zfsvfs->z_case == ZFS_CASE_MIXED) { vfs_set_feature(vfsp, VFSFT_DIRENTFLAGS); vfs_set_feature(vfsp, VFSFT_CASEINSENSITIVE); } if (dmu_objset_is_snapshot(zfsvfs->z_os)) { uint64_t pval; ASSERT(mode & DS_MODE_READONLY); atime_changed_cb(zfsvfs, B_FALSE); readonly_changed_cb(zfsvfs, B_TRUE); if (error = dsl_prop_get_integer(osname, "xattr", &pval, NULL)) goto out; xattr_changed_cb(zfsvfs, pval); zfsvfs->z_issnap = B_TRUE; } else { error = zfsvfs_setup(zfsvfs, B_TRUE); } vfs_mountedfrom(vfsp, osname); if (!zfsvfs->z_issnap) zfsctl_create(zfsvfs); out: if (error) { if (zfsvfs->z_os) dmu_objset_close(zfsvfs->z_os); zfs_freezfsvfs(zfsvfs); } else { atomic_add_32(&zfs_active_fs_count, 1); } 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; mountlist_append(mp); 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) vfs_syncer_add_to_worklist(mp); vfs_unbusy(mp, td); 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); }
/* * Mount null layer */ static int nullfs_mount(struct mount *mp) { int error = 0; struct vnode *lowerrootvp, *vp; struct vnode *nullm_rootvp; struct null_mount *xmp; struct thread *td = curthread; char *target; int isvnunlocked = 0, len; struct nameidata nd, *ndp = &nd; NULLFSDEBUG("nullfs_mount(mp = %p)\n", (void *)mp); if (!prison_allow(td->td_ucred, PR_ALLOW_MOUNT_NULLFS)) return (EPERM); if (mp->mnt_flag & MNT_ROOTFS) return (EOPNOTSUPP); /* * Update is a no-op */ if (mp->mnt_flag & MNT_UPDATE) { /* * Only support update mounts for NFS export. */ if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) return (0); else return (EOPNOTSUPP); } /* * Get argument */ error = vfs_getopt(mp->mnt_optnew, "target", (void **)&target, &len); if (error || target[len - 1] != '\0') return (EINVAL); /* * Unlock lower node to avoid possible deadlock. */ if ((mp->mnt_vnodecovered->v_op == &null_vnodeops) && VOP_ISLOCKED(mp->mnt_vnodecovered) == LK_EXCLUSIVE) { VOP_UNLOCK(mp->mnt_vnodecovered, 0); isvnunlocked = 1; } /* * Find lower node */ NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, target, curthread); error = namei(ndp); /* * Re-lock vnode. * XXXKIB This is deadlock-prone as well. */ if (isvnunlocked) vn_lock(mp->mnt_vnodecovered, LK_EXCLUSIVE | LK_RETRY); if (error) return (error); NDFREE(ndp, NDF_ONLY_PNBUF); /* * Sanity check on lower vnode */ lowerrootvp = ndp->ni_vp; /* * Check multi null mount to avoid `lock against myself' panic. */ if (lowerrootvp == VTONULL(mp->mnt_vnodecovered)->null_lowervp) { NULLFSDEBUG("nullfs_mount: multi null mount?\n"); vput(lowerrootvp); return (EDEADLK); } xmp = (struct null_mount *) malloc(sizeof(struct null_mount), M_NULLFSMNT, M_WAITOK | M_ZERO); /* * Save reference to underlying FS */ xmp->nullm_vfs = lowerrootvp->v_mount; /* * Save reference. Each mount also holds * a reference on the root vnode. */ error = null_nodeget(mp, lowerrootvp, &vp); /* * Make sure the node alias worked */ if (error) { free(xmp, M_NULLFSMNT); return (error); } /* * Keep a held reference to the root vnode. * It is vrele'd in nullfs_unmount. */ nullm_rootvp = vp; nullm_rootvp->v_vflag |= VV_ROOT; xmp->nullm_rootvp = nullm_rootvp; /* * Unlock the node (either the lower or the alias) */ VOP_UNLOCK(vp, 0); if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) { MNT_ILOCK(mp); mp->mnt_flag |= MNT_LOCAL; MNT_IUNLOCK(mp); } xmp->nullm_flags |= NULLM_CACHE; if (vfs_getopt(mp->mnt_optnew, "nocache", NULL, NULL) == 0) xmp->nullm_flags &= ~NULLM_CACHE; MNT_ILOCK(mp); if ((xmp->nullm_flags & NULLM_CACHE) != 0) { mp->mnt_kern_flag |= lowerrootvp->v_mount->mnt_kern_flag & (MNTK_SHARED_WRITES | MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED); } mp->mnt_kern_flag |= MNTK_LOOKUP_EXCL_DOTDOT; MNT_IUNLOCK(mp); mp->mnt_data = xmp; vfs_getnewfsid(mp); if ((xmp->nullm_flags & NULLM_CACHE) != 0) { MNT_ILOCK(xmp->nullm_vfs); TAILQ_INSERT_TAIL(&xmp->nullm_vfs->mnt_uppers, mp, mnt_upper_link); MNT_IUNLOCK(xmp->nullm_vfs); } vfs_mountedfrom(mp, target); NULLFSDEBUG("nullfs_mount: lower %s, alias at %s\n", mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); return (0); }
static int vboxvfs_mount(struct mount *mp, struct thread *td) { int rc; char *pszShare; int cbShare, cbOption; int uid = 0, gid = 0; struct sf_glob_info *pShFlGlobalInfo; SHFLSTRING *pShFlShareName = NULL; int cbShFlShareName; printf("%s: Enter\n", __FUNCTION__); if (mp->mnt_flag & (MNT_UPDATE | MNT_ROOTFS)) return EOPNOTSUPP; if (vfs_filteropt(mp->mnt_optnew, vboxvfs_opts)) { vfs_mount_error(mp, "%s", "Invalid option"); return EINVAL; } rc = vfs_getopt(mp->mnt_optnew, "from", (void **)&pszShare, &cbShare); if (rc || pszShare[cbShare-1] != '\0' || cbShare > 0xfffe) return EINVAL; rc = vfs_getopt(mp->mnt_optnew, "gid", (void **)&gid, &cbOption); if ((rc != ENOENT) && (rc || cbOption != sizeof(gid))) return EINVAL; rc = vfs_getopt(mp->mnt_optnew, "uid", (void **)&uid, &cbOption); if ((rc != ENOENT) && (rc || cbOption != sizeof(uid))) return EINVAL; pShFlGlobalInfo = RTMemAllocZ(sizeof(struct sf_glob_info)); if (!pShFlGlobalInfo) return ENOMEM; cbShFlShareName = offsetof (SHFLSTRING, String.utf8) + cbShare + 1; pShFlShareName = RTMemAllocZ(cbShFlShareName); if (!pShFlShareName) return VERR_NO_MEMORY; pShFlShareName->u16Length = cbShare; pShFlShareName->u16Size = cbShare + 1; memcpy (pShFlShareName->String.utf8, pszShare, cbShare + 1); rc = VbglR0SfMapFolder (&g_vboxSFClient, pShFlShareName, &pShFlGlobalInfo->map); RTMemFree(pShFlShareName); if (RT_FAILURE (rc)) { RTMemFree(pShFlGlobalInfo); printf("VbglR0SfMapFolder failed rc=%d\n", rc); return EPROTO; } pShFlGlobalInfo->uid = uid; pShFlGlobalInfo->gid = gid; mp->mnt_data = pShFlGlobalInfo; /** @todo root vnode. */ vfs_getnewfsid(mp); vfs_mountedfrom(mp, pszShare); printf("%s: Leave rc=0\n", __FUNCTION__); return 0; }
static int cd9660_mount(struct mount *mp, struct thread *td) { struct vnode *devvp; char *fspec; int error; mode_t accessmode; struct nameidata ndp; struct iso_mnt *imp = 0; /* * Unconditionally mount as read-only. */ MNT_ILOCK(mp); mp->mnt_flag |= MNT_RDONLY; MNT_IUNLOCK(mp); fspec = vfs_getopts(mp->mnt_optnew, "from", &error); if (error) return (error); imp = VFSTOISOFS(mp); if (mp->mnt_flag & MNT_UPDATE) { if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) return (0); } /* * Not an update, or updating the name: look up the name * and verify that it refers to a sensible block device. */ NDINIT(&ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspec, td); if ((error = namei(&ndp))) return (error); NDFREE(&ndp, NDF_ONLY_PNBUF); devvp = ndp.ni_vp; if (!vn_isdisk(devvp, &error)) { vput(devvp); return (error); } /* * Verify that user has necessary permissions on the device, * or has superuser abilities */ accessmode = VREAD; error = VOP_ACCESS(devvp, accessmode, td->td_ucred, td); if (error) error = priv_check(td, PRIV_VFS_MOUNT_PERM); if (error) { vput(devvp); return (error); } if ((mp->mnt_flag & MNT_UPDATE) == 0) { error = iso_mountfs(devvp, mp, td); if (error) vrele(devvp); } else { if (devvp != imp->im_devvp) error = EINVAL; /* needs translation */ vput(devvp); } if (error) return (error); vfs_mountedfrom(mp, fspec); return (0); }
/* * Mount null layer */ static int nullfs_mount(struct mount *mp) { int error = 0; struct vnode *lowerrootvp, *vp; struct vnode *nullm_rootvp; struct null_mount *xmp; char *target; int isvnunlocked = 0, len; struct nameidata nd, *ndp = &nd; NULLFSDEBUG("nullfs_mount(mp = %p)\n", (void *)mp); if (mp->mnt_flag & MNT_ROOTFS) return (EOPNOTSUPP); /* * Update is a no-op */ if (mp->mnt_flag & MNT_UPDATE) { /* * Only support update mounts for NFS export. */ if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) return (0); else return (EOPNOTSUPP); } /* * Get argument */ error = vfs_getopt(mp->mnt_optnew, "target", (void **)&target, &len); if (error || target[len - 1] != '\0') return (EINVAL); /* * Unlock lower node to avoid deadlock. * (XXX) VOP_ISLOCKED is needed? */ if ((mp->mnt_vnodecovered->v_op == &null_vnodeops) && VOP_ISLOCKED(mp->mnt_vnodecovered)) { VOP_UNLOCK(mp->mnt_vnodecovered, 0); isvnunlocked = 1; } /* * Find lower node */ NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, target, curthread); error = namei(ndp); /* * Re-lock vnode. */ if (isvnunlocked && !VOP_ISLOCKED(mp->mnt_vnodecovered)) vn_lock(mp->mnt_vnodecovered, LK_EXCLUSIVE | LK_RETRY); if (error) return (error); NDFREE(ndp, NDF_ONLY_PNBUF); /* * Sanity check on lower vnode */ lowerrootvp = ndp->ni_vp; /* * Check multi null mount to avoid `lock against myself' panic. */ if (lowerrootvp == VTONULL(mp->mnt_vnodecovered)->null_lowervp) { NULLFSDEBUG("nullfs_mount: multi null mount?\n"); vput(lowerrootvp); return (EDEADLK); } xmp = (struct null_mount *) malloc(sizeof(struct null_mount), M_NULLFSMNT, M_WAITOK); /* XXX */ /* * Save reference to underlying FS */ xmp->nullm_vfs = lowerrootvp->v_mount; /* * Save reference. Each mount also holds * a reference on the root vnode. */ error = null_nodeget(mp, lowerrootvp, &vp); /* * Make sure the node alias worked */ if (error) { VOP_UNLOCK(vp, 0); vrele(lowerrootvp); free(xmp, M_NULLFSMNT); /* XXX */ return (error); } /* * Keep a held reference to the root vnode. * It is vrele'd in nullfs_unmount. */ nullm_rootvp = vp; nullm_rootvp->v_vflag |= VV_ROOT; xmp->nullm_rootvp = nullm_rootvp; /* * Unlock the node (either the lower or the alias) */ VOP_UNLOCK(vp, 0); if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) { MNT_ILOCK(mp); mp->mnt_flag |= MNT_LOCAL; MNT_IUNLOCK(mp); } MNT_ILOCK(mp); mp->mnt_kern_flag |= lowerrootvp->v_mount->mnt_kern_flag & MNTK_MPSAFE; MNT_IUNLOCK(mp); mp->mnt_data = xmp; vfs_getnewfsid(mp); vfs_mountedfrom(mp, target); NULLFSDEBUG("nullfs_mount: lower %s, alias at %s\n", mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); return (0); }