extern int vnlayer_linux_mount( VFS_T *vfsp, void *data_p ) { int err; CALL_DATA_T cd; MVFS_CALLER_INFO_STRUCT ctx; mdki_linux_init_call_data(&cd); BZERO(&ctx, sizeof(ctx)); /* VFS_MOUNT method must detect 32- or 64-bit caller, if necessary */ err = VFS_MOUNT(vfsp, NULL, NULL, vfsp->vfs_flag, data_p, 0, &cd, &ctx); err = mdki_errno_unix_to_linux(err); mdki_linux_destroy_call_data(&cd); return(err); }
extern int vnlayer_linux_mount( VFS_T *vfsp, void *data_p ) { int err; CRED_T *cred; MVFS_CALLER_INFO_STRUCT ctx; cred = MDKI_GET_UCRED(); BZERO(&ctx, sizeof(ctx)); /* VFS_MOUNT method must detect 32- or 64-bit caller, if necessary */ err = VFS_MOUNT(vfsp, NULL, NULL, vfsp->vfs_flag, data_p, 0, cred, &ctx); err = mdki_errno_unix_to_linux(err); MDKI_CRFREE(cred); return(err); }
static int vfs_mountroot_devfs(struct thread *td, struct mount **mpp) { struct vfsoptlist *opts; struct vfsconf *vfsp; struct mount *mp; int error; *mpp = NULL; vfsp = vfs_byname("devfs"); KASSERT(vfsp != NULL, ("Could not find devfs by name")); if (vfsp == NULL) return (ENOENT); mp = vfs_mount_alloc(NULLVP, vfsp, "/dev", td->td_ucred); error = VFS_MOUNT(mp); KASSERT(error == 0, ("VFS_MOUNT(devfs) failed %d", error)); if (error) return (error); opts = malloc(sizeof(struct vfsoptlist), M_MOUNT, M_WAITOK); TAILQ_INIT(opts); mp->mnt_opt = opts; mtx_lock(&mountlist_mtx); TAILQ_INSERT_HEAD(&mountlist, mp, mnt_list); mtx_unlock(&mountlist_mtx); *mpp = mp; rootdevmp = mp; set_rootvnode(); error = kern_symlinkat(td, "/", AT_FDCWD, "dev", UIO_SYSSPACE); if (error) printf("kern_symlink /dev -> / returns %d\n", error); return (error); }
/* * vfs_mountrootfs * * Common entry point for root mounts * * PARAMETERS: * NONE * * RETURNS: 0 Success * !0 error number (errno.h) * * LOCK STATE: * ENTRY * <no locks held> * EXIT * <no locks held> * * NOTES: * This code is currently supported only for use for * the FFS file system type. This is a matter of * fixing the other file systems, not this code! */ static void vfs_mountrootfs(void *unused) { struct mount *mp; int i, err; struct proc *p = curproc; /* XXX */ dev_t orootdev; #ifdef BOOTP bootpc_init(); #endif /* * New root mount structure */ if ((err = vfs_rootmountalloc(mountrootfsname, ROOTNAME, &mp))) { printf("error %d: ", err); panic("cannot mount root\n"); return ; } mp->mnt_flag |= MNT_ROOTFS; /* * Attempt the mount */ err = ENXIO; orootdev = rootdev; if (rootdevs[0] == NODEV) rootdevs[0] = rootdev; for (i = 0; i < sizeof(rootdevs) / sizeof(rootdevs[0]); i++) { if (rootdevs[i] == NODEV) break; rootdev = rootdevs[i]; if (rootdev != orootdev) { printf("changing root device to %s\n", rootdevnames[i]); orootdev = rootdev; } strncpy(mp->mnt_stat.f_mntfromname, rootdevnames[i] ? rootdevnames[i] : ROOTNAME, MNAMELEN - 1); err = VFS_MOUNT(mp, NULL, NULL, NULL, p); if (err != ENXIO) break; } if (err) { /* * XXX should ask the user for the name in some cases. * Why do we call vfs_unbusy() here and not after ENXIO * is returned above? */ vfs_unbusy(mp, p); /* * free mount struct before failing * (hardly worthwhile with the PANIC eh?) */ free( mp, M_MOUNT); printf("error %d: ", err); panic("cannot mount root (2)\n"); return; } simple_lock(&mountlist_slock); /* * Add fs to list of mounted file systems */ CIRCLEQ_INSERT_HEAD(&mountlist, mp, mnt_list); simple_unlock(&mountlist_slock); vfs_unbusy(mp, p); /* root mount, update system time from FS specific data*/ inittodr(mp->mnt_time); return; }
/* * 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 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 do_mount(char *spec, char *dir, int mflag, char *opt) { // VERIFY(mflag == 0); vfs_t *vfs = kmem_zalloc(sizeof(vfs_t), KM_SLEEP); if(vfs == NULL) return ENOMEM; VFS_INIT(vfs, zfs_vfsops, 0); VFS_HOLD(vfs); struct mounta uap = { .spec = spec, .dir = dir, .flags = mflag | MS_SYSSPACE, .fstype = "zfs-fuse", .dataptr = "", .datalen = 0, .optptr = opt, .optlen = strlen(opt) }; int ret; if ((ret = VFS_MOUNT(vfs, rootdir, &uap, kcred)) != 0) { kmem_free(vfs, sizeof(vfs_t)); return ret; } /* Actually, optptr is totally ignored by VFS_MOUNT. * So we are going to pass this with fuse_mount_options if possible */ if (fuse_mount_options == NULL) fuse_mount_options = ""; char real_opts[1024]; *real_opts = 0; if (*fuse_mount_options) strcat(real_opts,fuse_mount_options); // comes with a starting , if (*opt) sprintf(&real_opts[strlen(real_opts)],",%s",opt); #ifdef DEBUG atomic_inc_32(&mounted);; fprintf(stderr, "mounting %s\n", dir); #endif char *fuse_opts = NULL; int has_default_perm = 0; if (fuse_version() <= 27) { if(asprintf(&fuse_opts, FUSE_OPTIONS, spec, real_opts) == -1) { VERIFY(do_umount(vfs, B_FALSE) == 0); return ENOMEM; } } else { if(asprintf(&fuse_opts, FUSE_OPTIONS ",big_writes", spec, real_opts) == -1) { VERIFY(do_umount(vfs, B_FALSE) == 0); return ENOMEM; } } struct fuse_args args = FUSE_ARGS_INIT(0, NULL); if(fuse_opt_add_arg(&args, "") == -1 || fuse_opt_add_arg(&args, "-o") == -1 || fuse_opt_add_arg(&args, fuse_opts) == -1) { fuse_opt_free_args(&args); free(fuse_opts); VERIFY(do_umount(vfs, B_FALSE) == 0); return ENOMEM; } has_default_perm = detect_fuseoption(fuse_opts,"default_permissions"); free(fuse_opts); struct fuse_chan *ch = fuse_mount(dir, &args); if(ch == NULL) { VERIFY(do_umount(vfs, B_FALSE) == 0); return EIO; } if (has_default_perm) vfs->fuse_attribute = FUSE_VFS_HAS_DEFAULT_PERM; struct fuse_session *se = fuse_lowlevel_new(&args, &zfs_operations, sizeof(zfs_operations), vfs); fuse_opt_free_args(&args); if(se == NULL) { VERIFY(do_umount(vfs, B_FALSE) == 0); /* ZFSFUSE: FIXME?? */ fuse_unmount(dir,ch); return EIO; } fuse_session_add_chan(se, ch); if(zfsfuse_newfs(dir, ch) != 0) { fuse_session_destroy(se); fuse_unmount(dir,ch); return EIO; } return 0; }
STATIC int linvfs_fill_super( struct super_block *sb, void *data, int silent) { vnode_t *rootvp; struct vfs *vfsp = vfs_allocate(); struct xfs_mount_args *args = xfs_args_allocate(sb); struct kstatfs statvfs; int error; vfsp->vfs_super = sb; LINVFS_SET_VFS(sb, vfsp); if (sb->s_flags & MS_RDONLY) vfsp->vfs_flag |= VFS_RDONLY; bhv_insert_all_vfsops(vfsp); VFS_PARSEARGS(vfsp, (char *)data, args, 0, error); if (error) { bhv_remove_all_vfsops(vfsp, 1); goto fail_vfsop; } sb_min_blocksize(sb, BBSIZE); sb->s_export_op = &linvfs_export_ops; sb->s_qcop = &linvfs_qops; sb->s_op = &linvfs_sops; VFS_MOUNT(vfsp, args, NULL, error); if (error) { bhv_remove_all_vfsops(vfsp, 1); goto fail_vfsop; } VFS_STATVFS(vfsp, &statvfs, NULL, error); if (error) goto fail_unmount; sb->s_dirt = 1; sb->s_magic = statvfs.f_type; sb->s_blocksize = statvfs.f_bsize; sb->s_blocksize_bits = ffs(statvfs.f_bsize) - 1; sb->s_maxbytes = xfs_max_file_offset(sb->s_blocksize_bits); set_posix_acl_flag(sb); VFS_ROOT(vfsp, &rootvp, error); if (error) goto fail_unmount; sb->s_root = d_alloc_root(LINVFS_GET_IP(rootvp)); if (!sb->s_root) goto fail_vnrele; if (is_bad_inode(sb->s_root->d_inode)) goto fail_vnrele; if (linvfs_start_syncd(vfsp)) goto fail_vnrele; vn_trace_exit(rootvp, __FUNCTION__, (inst_t *)__return_address); kmem_free(args, sizeof(*args)); return 0; fail_vnrele: if (sb->s_root) { dput(sb->s_root); sb->s_root = NULL; } else { VN_RELE(rootvp); } fail_unmount: VFS_UNMOUNT(vfsp, 0, NULL, error); fail_vfsop: vfs_deallocate(vfsp); kmem_free(args, sizeof(*args)); 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); }
int mount_snapshot(kthread_t *td, vnode_t **vpp, const char *fstype, char *fspath, char *fspec, int fsflags) { struct vfsconf *vfsp; struct mount *mp; vnode_t *vp, *mvp; struct ucred *cr; 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); vp = *vpp; if (vp->v_type != VDIR) return (ENOTDIR); /* * We need vnode lock to protect v_mountedhere and vnode interlock * to protect v_iflag. */ vn_lock(vp, LK_SHARED | LK_RETRY); VI_LOCK(vp); if ((vp->v_iflag & VI_MOUNT) != 0 || vp->v_mountedhere != NULL) { VI_UNLOCK(vp); VOP_UNLOCK(vp, 0); return (EBUSY); } vp->v_iflag |= VI_MOUNT; VI_UNLOCK(vp); VOP_UNLOCK(vp, 0); /* * Allocate and initialize the filesystem. * We don't want regular user that triggered snapshot mount to be able * to unmount it, so pass credentials of the parent mount. */ mp = vfs_mount_alloc(vp, vfsp, fspath, vp->v_mount->mnt_cred); 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. */ mp->mnt_flag = fsflags & MNT_UPDATEMASK; /* * Snapshots are always read-only. */ mp->mnt_flag |= MNT_RDONLY; /* * We don't want snapshots to allow access to vulnerable setuid * programs, so we turn off setuid when mounting snapshots. */ mp->mnt_flag |= MNT_NOSUID; /* * We don't want snapshots to be visible in regular * mount(8) and df(1) output. */ mp->mnt_flag |= MNT_IGNORE; /* * XXX: This is evil, but we can't mount a snapshot as a regular user. * XXX: Is is safe when snapshot is mounted from within a jail? */ cr = td->td_ucred; td->td_ucred = kcred; error = VFS_MOUNT(mp); td->td_ucred = cr; if (error != 0) { VI_LOCK(vp); vp->v_iflag &= ~VI_MOUNT; VI_UNLOCK(vp); vrele(vp); vfs_unbusy(mp); vfs_mount_destroy(mp); *vpp = NULL; return (error); } if (mp->mnt_opt != NULL) vfs_freeopts(mp->mnt_opt); mp->mnt_opt = mp->mnt_optnew; (void)VFS_STATFS(mp, &mp->mnt_stat); /* * Prevent external consumers of mount options from reading * mnt_optnew. */ mp->mnt_optnew = NULL; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); #ifdef FREEBSD_NAMECACHE cache_purge(vp); #endif VI_LOCK(vp); vp->v_iflag &= ~VI_MOUNT; VI_UNLOCK(vp); vp->v_mountedhere = mp; /* Put the new filesystem on the mount list. */ mtx_lock(&mountlist_mtx); TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); mtx_unlock(&mountlist_mtx); vfs_event_signal(NULL, VQ_MOUNT, 0); if (VFS_ROOT(mp, LK_EXCLUSIVE, &mvp)) panic("mount: lost mount"); vput(vp); vfs_unbusy(mp); *vpp = mvp; return (0); }
static OSKIT_COMDECL filesystem_remount(oskit_filesystem_t *f, oskit_u32_t flags) { struct gfilesystem *fs = (struct gfilesystem *) f; struct mount *mp; struct proc *p; oskit_error_t ferror; int error, oflag; if (!fs || !fs->count || !fs->mp) return OSKIT_E_INVALIDARG; ferror = getproc(&p); if (ferror) return ferror; mp = fs->mp; /* * Only root, or the user that did the original mount is * permitted to update it. */ if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid && (error = suser(p->p_ucred, 0))) { prfree(p); return errno_to_oskit_error(error); } if (flags & OSKIT_FS_NOEXEC) mp->mnt_flag |= MNT_NOEXEC; if (flags & OSKIT_FS_NOSUID) mp->mnt_flag |= MNT_NOSUID; if (flags & OSKIT_FS_NODEV) mp->mnt_flag |= MNT_NODEV; oflag = mp->mnt_flag; if ((flags & OSKIT_FS_RDONLY) && ((mp->mnt_flag & MNT_RDONLY) == 0)) /* rdwr -> rdonly */ mp->mnt_flag |= (MNT_UPDATE | MNT_FORCE | MNT_RDONLY); if (((flags & OSKIT_FS_RDONLY) == 0) && (mp->mnt_flag & MNT_RDONLY)) /* rdonly -> rdwr */ mp->mnt_flag |= (MNT_UPDATE | MNT_RELOAD | MNT_WANTRDWR); error = 0; if (mp->mnt_flag & MNT_UPDATE) { struct nameidata nd; /* dummy to contain cred */ struct ucred cred; /* dummy, contents not actually used */ nd.ni_cnd.cn_cred = &cred; error = VFS_MOUNT(mp, 0, 0, &nd, p); if (mp->mnt_flag & MNT_WANTRDWR) mp->mnt_flag &= ~MNT_RDONLY; mp->mnt_flag &=~ (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); if (error) mp->mnt_flag = oflag; } prfree(p); if (error) return errno_to_oskit_error(error); return 0; }