Beispiel #1
0
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);

}
Beispiel #2
0
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);

}
Beispiel #3
0
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);
}
Beispiel #4
0
/*
 * 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;
}
Beispiel #5
0
/*
 * 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);
}
Beispiel #6
0
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);
}
Beispiel #7
0
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;
}
Beispiel #8
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;
}
Beispiel #9
0
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);
}
Beispiel #11
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;    
}