Esempio n. 1
0
struct vnode *
getsynthvnode(const char *devname)
{
	struct vnode *vp;
	struct nchandle nch;
	struct nlookupdata nd;
	struct ucred *cred = proc0.p_ucred;
	int error;

	KKASSERT(synth_inited != 0);
	KKASSERT(synth_mp != NULL);
	KKASSERT(synth_mp->mnt_ncmountpt.mount != NULL);

	/* Sync devfs/disks twice to make sure all devices are around */
	if (synth_synced < 2) {
		sync_devs();
		++synth_synced;
	}

	error = nlookup_init_root(&nd,
	     devname, UIO_SYSSPACE, NLC_FOLLOW,
	     cred, &synth_mp->mnt_ncmountpt,
	     &synth_mp->mnt_ncmountpt);

	if (error) {
		panic("synth: nlookup_init_root failed with %d", error);
		/* NOTREACHED */
	}

	error = nlookup(&nd);
	if (error == 0) {
		if (nd.nl_nch.ncp->nc_vp == NULL) {
			kprintf("synth: nc_vp == NULL\n");
			return (NULL);
		}
		nch = nd.nl_nch;
		cache_zero(&nd.nl_nch);
	}

	nlookup_done(&nd);
	if (error) {
		if (error != ENOENT) { /* Don't bother warning about ENOENT */
			kprintf("synth: nlookup of %s failed with %d\n",
			    devname, error);
		}
		return (NULL);
	}

	vp = nch.ncp->nc_vp;
	/* A VX locked & refd vnode must be returned. */
	error = vget(vp, LK_EXCLUSIVE);
	cache_unlock(&nch);

	if (error) {
		kprintf("synth: could not vget vnode\n");
		return (NULL);
	}

	return (vp);
}
static int
hammer_setup_device(struct vnode **devvpp, const char *dev_path, int ronly)
{
	int error;
	struct nlookupdata nd;

	/*
	 * Get the device vnode
	 */
	if (*devvpp == NULL) {
		error = nlookup_init(&nd, dev_path, UIO_SYSSPACE, NLC_FOLLOW);
		if (error == 0)
			error = nlookup(&nd);
		if (error == 0)
			error = cache_vref(&nd.nl_nch, nd.nl_cred, devvpp);
		nlookup_done(&nd);
	} else {
		error = 0;
	}

	if (error == 0) {
		if (vn_isdisk(*devvpp, &error)) {
			error = vfs_mountedon(*devvpp);
		}
	}
	if (error == 0 && vcount(*devvpp) > 0)
		error = EBUSY;
	if (error == 0) {
		vn_lock(*devvpp, LK_EXCLUSIVE | LK_RETRY);
		error = vinvalbuf(*devvpp, V_SAVE, 0, 0);
		if (error == 0) {
			error = VOP_OPEN(*devvpp,
					 (ronly ? FREAD : FREAD|FWRITE),
					 FSCRED, NULL);
		}
		vn_unlock(*devvpp);
	}
	if (error && *devvpp) {
		vrele(*devvpp);
		*devvpp = NULL;
	}
	return (error);
}
Esempio n. 3
0
/*
 * Simple all-in-one nlookup.  Returns a locked namecache structure or NULL
 * if an error occured. 
 *
 * Note that the returned ncp is not checked for permissions, though VEXEC
 * is checked on the directory path leading up to the result.  The caller
 * must call naccess() to check the permissions of the returned leaf.
 */
struct nchandle
nlookup_simple(const char *str, enum uio_seg seg,
	       int niflags, int *error)
{
    struct nlookupdata nd;
    struct nchandle nch;

    *error = nlookup_init(&nd, str, seg, niflags);
    if (*error == 0) {
	    if ((*error = nlookup(&nd)) == 0) {
		    nch = nd.nl_nch;	/* keep hold ref from structure */
		    cache_zero(&nd.nl_nch); /* and NULL out */
	    } else {
		    cache_zero(&nch);
	    }
	    nlookup_done(&nd);
    } else {
	    cache_zero(&nch);
    }
    return(nch);
}
static int
ntfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred)
{
	size_t		size;
	int		error;
	struct vnode	*devvp;
	struct ntfs_args args;
	struct nlookupdata nd;
	struct vnode *rootvp;

	error = 0;
	/*
	 * Use NULL path to flag a root mount
	 */
	if( path == NULL) {
		/*
		 ***
		 * Mounting root file system
		 ***
		 */

		/* Get vnode for root device*/
		if( bdevvp( rootdev, &rootvp))
			panic("ffs_mountroot: can't setup bdevvp for root");

		/*
		 * FS specific handling
		 */
		mp->mnt_flag |= MNT_RDONLY;	/* XXX globally applicable?*/

		/*
		 * Attempt mount
		 */
		if( ( error = ntfs_mountfs(rootvp, mp, &args, cred)) != 0) {
			/* fs specific cleanup (if any)*/
			goto error_1;
		}

		goto dostatfs;		/* success*/

	}

	/*
	 ***
	 * Mounting non-root file system or updating a file system
	 ***
	 */

	/* copy in user arguments*/
	error = copyin(data, (caddr_t)&args, sizeof (struct ntfs_args));
	if (error)
		goto error_1;		/* can't get arguments*/

	/*
	 * 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) {
		/* if not updating name...*/
		if (args.fspec == NULL) {
			/*
			 * Process export requests.  Jumping to "success"
			 * will return the vfs_export() error code.
			 */
			struct ntfsmount *ntm = VFSTONTFS(mp);
			error = vfs_export(mp, &ntm->ntm_export, &args.export);
			goto success;
		}

		kprintf("ntfs_mount(): MNT_UPDATE not supported\n");
		error = EINVAL;
		goto error_1;
	}

	/*
	 * Not an update, or updating the name: look up the name
	 * and verify that it refers to a sensible block device.
	 */
	devvp = NULL;
	error = nlookup_init(&nd, args.fspec, UIO_USERSPACE, NLC_FOLLOW);
	if (error == 0)
		error = nlookup(&nd);
	if (error == 0)
		error = cache_vref(&nd.nl_nch, nd.nl_cred, &devvp);
	nlookup_done(&nd);
	if (error)
		goto error_1;

	if (!vn_isdisk(devvp, &error))
		goto error_2;

	if (mp->mnt_flag & MNT_UPDATE) {
#if 0
		/*
		 ********************
		 * UPDATE
		 ********************
		 */

		if (devvp != ntmp->um_devvp)
			error = EINVAL;	/* needs translation */
		else
			vrele(devvp);
		/*
		 * Update device name only on success
		 */
		if( !error) {
			/* Save "mounted from" info for mount point (NULL pad)*/
			copyinstr(	args.fspec,
					mp->mnt_stat.f_mntfromname,
					MNAMELEN - 1,
					&size);
			bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
		}
#endif
	} else {
		/*
		 ********************
		 * NEW MOUNT
		 ********************
		 */

		/* Save "mounted from" info for mount point (NULL pad)*/
		copyinstr(	args.fspec,			/* device name*/
				mp->mnt_stat.f_mntfromname,	/* save area*/
				MNAMELEN - 1,			/* max size*/
				&size);				/* real size*/
		bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);

		error = ntfs_mountfs(devvp, mp, &args, cred);
	}
	if (error) {
		goto error_2;
	}

dostatfs:
	/*
	 * Initialize FS stat information in mount struct; uses
	 * mp->mnt_stat.f_mntfromname.
	 *
	 * This code is common to root and non-root mounts
	 */
	(void)VFS_STATFS(mp, &mp->mnt_stat, cred);

	goto success;


error_2:	/* error with devvp held*/

	/* release devvp before failing*/
	vrele(devvp);

error_1:	/* no state to back out*/

success:
	return(error);
}
Esempio n. 5
0
/************************************************************************
 *				VOLUMES					*
 ************************************************************************
 *
 * Load a HAMMER volume by name.  Returns 0 on success or a positive error
 * code on failure.  Volumes must be loaded at mount time, get_volume() will
 * not load a new volume.
 *
 * The passed devvp is vref()'d but not locked.  This function consumes the
 * ref (typically by associating it with the volume structure).
 *
 * Calls made to hammer_load_volume() or single-threaded
 */
int
hammer_install_volume(struct hammer_mount *hmp, const char *volname,
		      struct vnode *devvp)
{
	struct mount *mp;
	hammer_volume_t volume;
	struct hammer_volume_ondisk *ondisk;
	struct nlookupdata nd;
	struct buf *bp = NULL;
	int error;
	int ronly;
	int setmp = 0;

	mp = hmp->mp;
	ronly = ((mp->mnt_flag & MNT_RDONLY) ? 1 : 0);

	/*
	 * Allocate a volume structure
	 */
	++hammer_count_volumes;
	volume = kmalloc(sizeof(*volume), hmp->m_misc, M_WAITOK|M_ZERO);
	volume->vol_name = kstrdup(volname, hmp->m_misc);
	volume->io.hmp = hmp;	/* bootstrap */
	hammer_io_init(&volume->io, volume, HAMMER_STRUCTURE_VOLUME);
	volume->io.offset = 0LL;
	volume->io.bytes = HAMMER_BUFSIZE;

	/*
	 * Get the device vnode
	 */
	if (devvp == NULL) {
		error = nlookup_init(&nd, volume->vol_name, UIO_SYSSPACE, NLC_FOLLOW);
		if (error == 0)
			error = nlookup(&nd);
		if (error == 0)
			error = cache_vref(&nd.nl_nch, nd.nl_cred, &volume->devvp);
		nlookup_done(&nd);
	} else {
		error = 0;
		volume->devvp = devvp;
	}

	if (error == 0) {
		if (vn_isdisk(volume->devvp, &error)) {
			error = vfs_mountedon(volume->devvp);
		}
	}
	if (error == 0 && vcount(volume->devvp) > 0)
		error = EBUSY;
	if (error == 0) {
		vn_lock(volume->devvp, LK_EXCLUSIVE | LK_RETRY);
		error = vinvalbuf(volume->devvp, V_SAVE, 0, 0);
		if (error == 0) {
			error = VOP_OPEN(volume->devvp, 
					 (ronly ? FREAD : FREAD|FWRITE),
					 FSCRED, NULL);
		}
		vn_unlock(volume->devvp);
	}
	if (error) {
		hammer_free_volume(volume);
		return(error);
	}
	volume->devvp->v_rdev->si_mountpoint = mp;
	setmp = 1;

	/*
	 * Extract the volume number from the volume header and do various
	 * sanity checks.
	 */
	error = bread(volume->devvp, 0LL, HAMMER_BUFSIZE, &bp);
	if (error)
		goto late_failure;
	ondisk = (void *)bp->b_data;
	if (ondisk->vol_signature != HAMMER_FSBUF_VOLUME) {
		kprintf("hammer_mount: volume %s has an invalid header\n",
			volume->vol_name);
		error = EFTYPE;
		goto late_failure;
	}
	volume->vol_no = ondisk->vol_no;
	volume->buffer_base = ondisk->vol_buf_beg;
	volume->vol_flags = ondisk->vol_flags;
	volume->nblocks = ondisk->vol_nblocks; 
	volume->maxbuf_off = HAMMER_ENCODE_RAW_BUFFER(volume->vol_no,
				    ondisk->vol_buf_end - ondisk->vol_buf_beg);
	volume->maxraw_off = ondisk->vol_buf_end;

	if (RB_EMPTY(&hmp->rb_vols_root)) {
		hmp->fsid = ondisk->vol_fsid;
	} else if (bcmp(&hmp->fsid, &ondisk->vol_fsid, sizeof(uuid_t))) {
		kprintf("hammer_mount: volume %s's fsid does not match "
			"other volumes\n", volume->vol_name);
		error = EFTYPE;
		goto late_failure;
	}

	/*
	 * Insert the volume structure into the red-black tree.
	 */
	if (RB_INSERT(hammer_vol_rb_tree, &hmp->rb_vols_root, volume)) {
		kprintf("hammer_mount: volume %s has a duplicate vol_no %d\n",
			volume->vol_name, volume->vol_no);
		error = EEXIST;
	}

	/*
	 * Set the root volume .  HAMMER special cases rootvol the structure.
	 * We do not hold a ref because this would prevent related I/O
	 * from being flushed.
	 */
	if (error == 0 && ondisk->vol_rootvol == ondisk->vol_no) {
		hmp->rootvol = volume;
		hmp->nvolumes = ondisk->vol_count;
		if (bp) {
			brelse(bp);
			bp = NULL;
		}
		hmp->mp->mnt_stat.f_blocks += ondisk->vol0_stat_bigblocks *
			(HAMMER_LARGEBLOCK_SIZE / HAMMER_BUFSIZE);
		hmp->mp->mnt_vstat.f_blocks += ondisk->vol0_stat_bigblocks *
			(HAMMER_LARGEBLOCK_SIZE / HAMMER_BUFSIZE);
	}
late_failure:
	if (bp)
		brelse(bp);
	if (error) {
		/*vinvalbuf(volume->devvp, V_SAVE, 0, 0);*/
		if (setmp)
			volume->devvp->v_rdev->si_mountpoint = NULL;
		vn_lock(volume->devvp, LK_EXCLUSIVE | LK_RETRY);
		VOP_CLOSE(volume->devvp, ronly ? FREAD : FREAD|FWRITE);
		vn_unlock(volume->devvp);
		hammer_free_volume(volume);
	}
	return (error);
}
Esempio n. 6
0
/*
 * Common code for vnode open operations.  Check permissions, and call
 * the VOP_NOPEN or VOP_NCREATE routine.
 *
 * The caller is responsible for setting up nd with nlookup_init() and
 * for cleaning it up with nlookup_done(), whether we return an error
 * or not.
 *
 * On success nd->nl_open_vp will hold a referenced and, if requested,
 * locked vnode.  A locked vnode is requested via NLC_LOCKVP.  If fp
 * is non-NULL the vnode will be installed in the file pointer.
 *
 * NOTE: The vnode is referenced just once on return whether or not it
 * is also installed in the file pointer.
 */
int
vn_open(struct nlookupdata *nd, struct file *fp, int fmode, int cmode)
{
	struct vnode *vp;
	struct ucred *cred = nd->nl_cred;
	struct vattr vat;
	struct vattr *vap = &vat;
	int error;
	u_int flags;
	uint64_t osize;
	struct mount *mp;

	/*
	 * Certain combinations are illegal
	 */
	if ((fmode & (FWRITE | O_TRUNC)) == O_TRUNC)
		return(EACCES);

	/*
	 * Lookup the path and create or obtain the vnode.  After a
	 * successful lookup a locked nd->nl_nch will be returned.
	 *
	 * The result of this section should be a locked vnode.
	 *
	 * XXX with only a little work we should be able to avoid locking
	 * the vnode if FWRITE, O_CREAT, and O_TRUNC are *not* set.
	 */
	nd->nl_flags |= NLC_OPEN;
	if (fmode & O_APPEND)
		nd->nl_flags |= NLC_APPEND;
	if (fmode & O_TRUNC)
		nd->nl_flags |= NLC_TRUNCATE;
	if (fmode & FREAD)
		nd->nl_flags |= NLC_READ;
	if (fmode & FWRITE)
		nd->nl_flags |= NLC_WRITE;
	if ((fmode & O_EXCL) == 0 && (fmode & O_NOFOLLOW) == 0)
		nd->nl_flags |= NLC_FOLLOW;

	if (fmode & O_CREAT) {
		/*
		 * CONDITIONAL CREATE FILE CASE
		 *
		 * Setting NLC_CREATE causes a negative hit to store
		 * the negative hit ncp and not return an error.  Then
		 * nc_error or nc_vp may be checked to see if the ncp 
		 * represents a negative hit.  NLC_CREATE also requires
		 * write permission on the governing directory or EPERM
		 * is returned.
		 */
		nd->nl_flags |= NLC_CREATE;
		nd->nl_flags |= NLC_REFDVP;
		bwillinode(1);
		error = nlookup(nd);
	} else {
		/*
		 * NORMAL OPEN FILE CASE
		 */
		error = nlookup(nd);
	}

	if (error)
		return (error);

	/*
	 * split case to allow us to re-resolve and retry the ncp in case
	 * we get ESTALE.
	 */
again:
	if (fmode & O_CREAT) {
		if (nd->nl_nch.ncp->nc_vp == NULL) {
			if ((error = ncp_writechk(&nd->nl_nch)) != 0)
				return (error);
			VATTR_NULL(vap);
			vap->va_type = VREG;
			vap->va_mode = cmode;
			if (fmode & O_EXCL)
				vap->va_vaflags |= VA_EXCLUSIVE;
			error = VOP_NCREATE(&nd->nl_nch, nd->nl_dvp, &vp,
					    nd->nl_cred, vap);
			if (error)
				return (error);
			fmode &= ~O_TRUNC;
			/* locked vnode is returned */
		} else {
			if (fmode & O_EXCL) {
				error = EEXIST;
			} else {
				error = cache_vget(&nd->nl_nch, cred, 
						    LK_EXCLUSIVE, &vp);
			}
			if (error)
				return (error);
			fmode &= ~O_CREAT;
		}
	} else {
		error = cache_vget(&nd->nl_nch, cred, LK_EXCLUSIVE, &vp);
		if (error)
			return (error);
	}

	/*
	 * We have a locked vnode and ncp now.  Note that the ncp will
	 * be cleaned up by the caller if nd->nl_nch is left intact.
	 */
	if (vp->v_type == VLNK) {
		error = EMLINK;
		goto bad;
	}
	if (vp->v_type == VSOCK) {
		error = EOPNOTSUPP;
		goto bad;
	}
	if ((fmode & O_CREAT) == 0) {
		if (fmode & (FWRITE | O_TRUNC)) {
			if (vp->v_type == VDIR) {
				error = EISDIR;
				goto bad;
			}
			error = vn_writechk(vp, &nd->nl_nch);
			if (error) {
				/*
				 * Special stale handling, re-resolve the
				 * vnode.
				 */
				if (error == ESTALE) {
					vput(vp);
					vp = NULL;
					cache_setunresolved(&nd->nl_nch);
					error = cache_resolve(&nd->nl_nch, cred);
					if (error == 0)
						goto again;
				}
				goto bad;
			}
		}
	}
	if (fmode & O_TRUNC) {
		vn_unlock(vp);				/* XXX */
		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);	/* XXX */
		osize = vp->v_filesize;
		VATTR_NULL(vap);
		vap->va_size = 0;
		error = VOP_SETATTR(vp, vap, cred);
		if (error)
			goto bad;
		error = VOP_GETATTR(vp, vap);
		if (error)
			goto bad;
		mp = vq_vptomp(vp);
		VFS_ACCOUNT(mp, vap->va_uid, vap->va_gid, -osize);
	}

	/*
	 * Set or clear VNSWAPCACHE on the vp based on nd->nl_nch.ncp->nc_flag.
	 * These particular bits a tracked all the way from the root.
	 *
	 * NOTE: Might not work properly on NFS servers due to the
	 * disconnected namecache.
	 */
	flags = nd->nl_nch.ncp->nc_flag;
	if ((flags & (NCF_UF_CACHE | NCF_UF_PCACHE)) &&
	    (flags & (NCF_SF_NOCACHE | NCF_SF_PNOCACHE)) == 0) {
		vsetflags(vp, VSWAPCACHE);
	} else {
		vclrflags(vp, VSWAPCACHE);
	}

	/*
	 * Setup the fp so VOP_OPEN can override it.  No descriptor has been
	 * associated with the fp yet so we own it clean.  
	 *
	 * f_nchandle inherits nl_nch.  This used to be necessary only for
	 * directories but now we do it unconditionally so f*() ops
	 * such as fchmod() can access the actual namespace that was
	 * used to open the file.
	 */
	if (fp) {
		if (nd->nl_flags & NLC_APPENDONLY)
			fmode |= FAPPENDONLY;
		fp->f_nchandle = nd->nl_nch;
		cache_zero(&nd->nl_nch);
		cache_unlock(&fp->f_nchandle);
	}

	/*
	 * Get rid of nl_nch.  vn_open does not return it (it returns the
	 * vnode or the file pointer).  Note: we can't leave nl_nch locked
	 * through the VOP_OPEN anyway since the VOP_OPEN may block, e.g.
	 * on /dev/ttyd0
	 */
	if (nd->nl_nch.ncp)
		cache_put(&nd->nl_nch);

	error = VOP_OPEN(vp, fmode, cred, fp);
	if (error) {
		/*
		 * setting f_ops to &badfileops will prevent the descriptor
		 * code from trying to close and release the vnode, since
		 * the open failed we do not want to call close.
		 */
		if (fp) {
			fp->f_data = NULL;
			fp->f_ops = &badfileops;
		}
		goto bad;
	}

#if 0
	/*
	 * Assert that VREG files have been setup for vmio.
	 */
	KASSERT(vp->v_type != VREG || vp->v_object != NULL,
		("vn_open: regular file was not VMIO enabled!"));
#endif

	/*
	 * Return the vnode.  XXX needs some cleaning up.  The vnode is
	 * only returned in the fp == NULL case.
	 */
	if (fp == NULL) {
		nd->nl_open_vp = vp;
		nd->nl_vp_fmode = fmode;
		if ((nd->nl_flags & NLC_LOCKVP) == 0)
			vn_unlock(vp);
	} else {
		vput(vp);
	}
	return (0);
bad:
	if (vp)
		vput(vp);
	return (error);
}
Esempio n. 7
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);
}