/* Remove registration of a filesystem type */
static int
vfs_unregister(struct vfsconf *vfc)
{
	struct vfsconf *vfsp;
	int error, i, maxtypenum;

	i = vfc->vfc_typenum;

	vfsp = vfs_byname(vfc->vfc_name);
	if (vfsp == NULL)
		return EINVAL;
	if (vfsp->vfc_refcount)
		return EBUSY;
	if (vfc->vfc_vfsops->vfs_uninit != NULL) {
		error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp);
		if (error)
			return (error);
	}
	TAILQ_REMOVE(&vfsconf, vfsp, vfc_list);
	maxtypenum = VFS_GENERIC;
	TAILQ_FOREACH(vfsp, &vfsconf, vfc_list)
		if (maxtypenum < vfsp->vfc_typenum)
			maxtypenum = vfsp->vfc_typenum;
	maxvfsconf = maxtypenum + 1;
	return 0;
}
struct vfsconf *
vfs_byname_kld(const char *fstype, struct thread *td, int *error)
{
	struct vfsconf *vfsp;
	int fileid;

	vfsp = vfs_byname(fstype);
	if (vfsp != NULL)
		return (vfsp);

	/* Try to load the respective module. */
	*error = kern_kldload(td, fstype, &fileid);
	if (*error)
		return (NULL);

	/* Look up again to see if the VFS was loaded. */
	vfsp = vfs_byname(fstype);
	if (vfsp == NULL) {
		(void)kern_kldunload(td, fileid, LINKER_UNLOAD_FORCE);
		*error = ENODEV;
		return (NULL);
	}
	return (vfsp);
}
Example #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);
}
Example #4
0
static int
parse_mount(char **conf)
{
	char *errmsg;
	struct mntarg *ma;
	char *dev, *fs, *opts, *tok;
	int delay, error, timeout;

	error = parse_token(conf, &tok);
	if (error)
		return (error);
	fs = tok;
	error = parse_skipto(&tok, ':');
	if (error) {
		free(fs, M_TEMP);
		return (error);
	}
	parse_poke(&tok, '\0');
	parse_advance(&tok);
	dev = tok;

	if (root_mount_mddev != -1) {
		/* Handle substitution for the md unit number. */
		tok = strstr(dev, "md#");
		if (tok != NULL)
			tok[2] = '0' + root_mount_mddev;
	}

	/* Parse options. */
	error = parse_token(conf, &tok);
	opts = (error == 0) ? tok : NULL;

	printf("Trying to mount root from %s:%s [%s]...\n", fs, dev,
	    (opts != NULL) ? opts : "");

	errmsg = malloc(ERRMSGL, M_TEMP, M_WAITOK | M_ZERO);

	if (vfs_byname(fs) == NULL) {
		strlcpy(errmsg, "unknown file system", ERRMSGL);
		error = ENOENT;
		goto out;
	}

	if (strcmp(fs, "zfs") != 0 && strstr(fs, "nfs") == NULL && 
	    dev[0] != '\0' && !parse_mount_dev_present(dev)) {
		printf("mountroot: waiting for device %s ...\n", dev);
		delay = hz / 10;
		timeout = root_mount_timeout * hz;
		do {
			pause("rmdev", delay);
			timeout -= delay;
		} while (timeout > 0 && !parse_mount_dev_present(dev));
		if (timeout <= 0) {
			error = ENODEV;
			goto out;
		}
	}

	ma = NULL;
	ma = mount_arg(ma, "fstype", fs, -1);
	ma = mount_arg(ma, "fspath", "/", -1);
	ma = mount_arg(ma, "from", dev, -1);
	ma = mount_arg(ma, "errmsg", errmsg, ERRMSGL);
	ma = mount_arg(ma, "ro", NULL, 0);
	ma = parse_mountroot_options(ma, opts);
	error = kernel_mount(ma, MNT_ROOTFS);

 out:
	if (error) {
		printf("Mounting from %s:%s failed with error %d",
		    fs, dev, error);
		if (errmsg[0] != '\0')
			printf(": %s", errmsg);
		printf(".\n");
	}
	free(fs, M_TEMP);
	free(errmsg, M_TEMP);
	if (opts != NULL)
		free(opts, M_TEMP);
	/* kernel_mount can return -1 on error. */
	return ((error < 0) ? EDOOFUS : error);
}
/* Register a new filesystem type in the global table */
static int
vfs_register(struct vfsconf *vfc)
{
	struct sysctl_oid *oidp;
	struct vfsops *vfsops;
	static int once;

	if (!once) {
		vattr_null(&va_null);
		once = 1;
	}
	
	if (vfc->vfc_version != VFS_VERSION) {
		printf("ERROR: filesystem %s, unsupported ABI version %x\n",
		    vfc->vfc_name, vfc->vfc_version);
		return (EINVAL);
	}
	if (vfs_byname(vfc->vfc_name) != NULL)
		return EEXIST;

	vfc->vfc_typenum = maxvfsconf++;
	TAILQ_INSERT_TAIL(&vfsconf, vfc, vfc_list);

	/*
	 * If this filesystem has a sysctl node under vfs
	 * (i.e. vfs.xxfs), then change the oid number of that node to 
	 * match the filesystem's type number.  This allows user code
	 * which uses the type number to read sysctl variables defined
	 * by the filesystem to continue working. Since the oids are
	 * in a sorted list, we need to make sure the order is
	 * preserved by re-registering the oid after modifying its
	 * number.
	 */
	sysctl_lock();
	SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link)
		if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) {
			sysctl_unregister_oid(oidp);
			oidp->oid_number = vfc->vfc_typenum;
			sysctl_register_oid(oidp);
			break;
		}
	sysctl_unlock();

	/*
	 * Initialise unused ``struct vfsops'' fields, to use
	 * the vfs_std*() functions.  Note, we need the mount
	 * and unmount operations, at the least.  The check
	 * for vfsops available is just a debugging aid.
	 */
	KASSERT(vfc->vfc_vfsops != NULL,
	    ("Filesystem %s has no vfsops", vfc->vfc_name));
	/*
	 * Check the mount and unmount operations.
	 */
	vfsops = vfc->vfc_vfsops;
	KASSERT(vfsops->vfs_mount != NULL,
	    ("Filesystem %s has no mount op", vfc->vfc_name));
	KASSERT(vfsops->vfs_unmount != NULL,
	    ("Filesystem %s has no unmount op", vfc->vfc_name));

	if (vfsops->vfs_root == NULL)
		/* return file system's root vnode */
		vfsops->vfs_root =	vfs_stdroot;
	if (vfsops->vfs_quotactl == NULL)
		/* quota control */
		vfsops->vfs_quotactl =	vfs_stdquotactl;
	if (vfsops->vfs_statfs == NULL)
		/* return file system's status */
		vfsops->vfs_statfs =	vfs_stdstatfs;
	if (vfsops->vfs_sync == NULL)
		/*
		 * flush unwritten data (nosync)
		 * file systems can use vfs_stdsync
		 * explicitly by setting it in the
		 * vfsop vector.
		 */
		vfsops->vfs_sync =	vfs_stdnosync;
	if (vfsops->vfs_vget == NULL)
		/* convert an inode number to a vnode */
		vfsops->vfs_vget =	vfs_stdvget;
	if (vfsops->vfs_fhtovp == NULL)
		/* turn an NFS file handle into a vnode */
		vfsops->vfs_fhtovp =	vfs_stdfhtovp;
	if (vfsops->vfs_checkexp == NULL)
		/* check if file system is exported */
		vfsops->vfs_checkexp =	vfs_stdcheckexp;
	if (vfsops->vfs_init == NULL)
		/* file system specific initialisation */
		vfsops->vfs_init =	vfs_stdinit;
	if (vfsops->vfs_uninit == NULL)
		/* file system specific uninitialisation */
		vfsops->vfs_uninit =	vfs_stduninit;
	if (vfsops->vfs_extattrctl == NULL)
		/* extended attribute control */
		vfsops->vfs_extattrctl = vfs_stdextattrctl;
	if (vfsops->vfs_sysctl == NULL)
		vfsops->vfs_sysctl = vfs_stdsysctl;
	
	/*
	 * Call init function for this VFS...
	 */
	(*(vfc->vfc_vfsops->vfs_init))(vfc);

	return 0;
}