예제 #1
0
/*
 * Unmount the filesystem described by mp.
 */
int
msdosfs_unmount(struct mount *mp, int mntflags)
{
	struct msdosfsmount *pmp;
	int error, flags;

	flags = 0;
	if (mntflags & MNT_FORCE)
		flags |= FORCECLOSE;
	if ((error = vflush(mp, NULLVP, flags)) != 0)
		return (error);
	pmp = VFSTOMSDOSFS(mp);
	if (pmp->pm_devvp->v_type != VBAD)
		spec_node_setmountedfs(pmp->pm_devvp, NULL);
#ifdef MSDOSFS_DEBUG
	{
		struct vnode *vp = pmp->pm_devvp;

		printf("msdosfs_umount(): just before calling VOP_CLOSE()\n");
		printf("flag %08x, usecount %d, writecount %d, holdcnt %d\n",
		    vp->v_vflag | vp->v_iflag | vp->v_uflag, vp->v_usecount,
		    vp->v_writecount, vp->v_holdcnt);
		printf("mount %p, op %p\n",
		    vp->v_mount, vp->v_op);
		printf("freef %p, freeb %p, mount %p\n",
		    vp->v_freelist.tqe_next, vp->v_freelist.tqe_prev,
		    vp->v_mount);
		printf("cleanblkhd %p, dirtyblkhd %p, numoutput %d, type %d\n",
		    vp->v_cleanblkhd.lh_first,
		    vp->v_dirtyblkhd.lh_first,
		    vp->v_numoutput, vp->v_type);
		printf("union %p, tag %d, data[0] %08x, data[1] %08x\n",
		    vp->v_socket, vp->v_tag,
		    ((u_int *)vp->v_data)[0],
		    ((u_int *)vp->v_data)[1]);
	}
#endif
	vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY);
	(void) VOP_CLOSE(pmp->pm_devvp,
	    pmp->pm_flags & MSDOSFSMNT_RONLY ? FREAD : FREAD|FWRITE, NOCRED);
	vput(pmp->pm_devvp);
	msdosfs_fh_destroy(pmp);
	free(pmp->pm_inusemap, M_MSDOSFSFAT);
	free(pmp, M_MSDOSFSMNT);
	mp->mnt_data = NULL;
	mp->mnt_flag &= ~MNT_LOCAL;
	fstrans_unmount(mp);
	return (0);
}
예제 #2
0
/*
 * This opens /dev/tty.  Because multiple opens of /dev/tty only
 * generate a single open to the actual tty, the file modes are
 * locked to FREAD|FWRITE.
 */
static	int
cttyopen(struct dev_open_args *ap)
{
	struct proc *p = curproc;
	struct vnode *ttyvp;
	int error;

	KKASSERT(p);
retry:
	if ((ttyvp = cttyvp(p)) == NULL)
		return (ENXIO);
	if (ttyvp->v_flag & VCTTYISOPEN)
		return (0);

	/*
	 * Messy interlock, don't let the vnode go away while we try to
	 * lock it and check for race after we might have blocked.
	 *
	 * WARNING! The device open (devfs_spec_open()) temporarily
	 *	    releases the vnode lock on ttyvp when issuing the
	 *	    dev_dopen(), which means that the VCTTYISOPEn flag
	 *	    can race during the VOP_OPEN().
	 *
	 *	    If something does race we have to undo our potentially
	 *	    extra open.
	 */
	vhold(ttyvp);
	vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY);
	if (ttyvp != cttyvp(p) || (ttyvp->v_flag & VCTTYISOPEN)) {
		kprintf("Warning: cttyopen: race-1 avoided\n");
		vn_unlock(ttyvp);
		vdrop(ttyvp);
		goto retry;
	}
	error = VOP_OPEN(ttyvp, FREAD|FWRITE, ap->a_cred, NULL);
	if (ttyvp != cttyvp(p) || (ttyvp->v_flag & VCTTYISOPEN)) {
		kprintf("Warning: cttyopen: race-2 avoided\n");
		if (error == 0)
			VOP_CLOSE(ttyvp, FREAD|FWRITE);
		vn_unlock(ttyvp);
		vdrop(ttyvp);
		goto retry;
	}
	if (error == 0)
		vsetflags(ttyvp, VCTTYISOPEN);
	vn_unlock(ttyvp);
	vdrop(ttyvp);
	return(error);
}
예제 #3
0
static void
spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl)
{
	size_t buflen;
	char *buf;
	vnode_t *vp;
	int oflags = FWRITE | FTRUNC | FCREAT | FOFFMAX;
	char *temp;

	/*
	 * If the nvlist is empty (NULL), then remove the old cachefile.
	 */
	if (nvl == NULL) {
		(void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE);
		return;
	}

	/*
	 * Pack the configuration into a buffer.
	 */
	VERIFY(nvlist_size(nvl, &buflen, NV_ENCODE_XDR) == 0);

	buf = kmem_alloc(buflen, KM_SLEEP);
	temp = kmem_zalloc(MAXPATHLEN, KM_SLEEP);

	VERIFY(nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_XDR,
	    KM_SLEEP) == 0);

	/*
	 * Write the configuration to disk.  We need to do the traditional
	 * 'write to temporary file, sync, move over original' to make sure we
	 * always have a consistent view of the data.
	 */
	(void) snprintf(temp, MAXPATHLEN, "%s.tmp", dp->scd_path);

	if (vn_open(temp, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0) == 0) {
		if (vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE,
		    0, RLIM64_INFINITY, kcred, NULL) == 0 &&
		    VOP_FSYNC(vp, FSYNC, kcred, NULL) == 0) {
			(void) vn_rename(temp, dp->scd_path, UIO_SYSSPACE);
		}
		(void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL);
	}

	(void) vn_remove(temp, UIO_SYSSPACE, RMFILE);

	kmem_free(buf, buflen);
	kmem_free(temp, MAXPATHLEN);
}
예제 #4
0
/*
 * Vnode close call
 *
 * Note: takes an unlocked vnode, while VOP_CLOSE takes a locked node.
 */
int
vn_close(struct vnode *vp, int flags, kauth_cred_t cred)
{
	int error;

	if (flags & FWRITE) {
		mutex_enter(vp->v_interlock);
		KASSERT(vp->v_writecount > 0);
		vp->v_writecount--;
		mutex_exit(vp->v_interlock);
	}
	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
	error = VOP_CLOSE(vp, flags, cred);
	vput(vp);
	return (error);
}
예제 #5
0
static void
vdev_file_close(vdev_t *vd)
{
	vdev_file_t *vf = vd->vdev_tsd;

	if (vf == NULL)
		return;

	if (vf->vf_vnode != NULL) {
		(void) VOP_PUTPAGE(vf->vf_vnode, 0, 0, B_INVAL, kcred, NULL);
		(void) VOP_CLOSE(vf->vf_vnode, spa_mode, 1, 0, kcred, NULL);
		VN_RELE(vf->vf_vnode);
	}

	kmem_free(vf, sizeof (vdev_file_t));
	vd->vdev_tsd = NULL;
}
예제 #6
0
static void
vdev_file_close(vdev_t *vd)
{
	vdev_file_t *vf = vd->vdev_tsd;

	if (vd->vdev_reopening || vf == NULL)
		return;

	if (vf->vf_vnode != NULL) {
		(void) VOP_CLOSE(vf->vf_vnode, spa_mode(vd->vdev_spa), 1, 0,
		    kcred, NULL);
	}

	vd->vdev_delayed_close = B_FALSE;
	kmem_free(vf, sizeof (vdev_file_t));
	vd->vdev_tsd = NULL;
}
예제 #7
0
/*
 * unmount system call
 */
int
ffs_unmount(struct mount *mp, int mntflags, struct proc *p)
{
	struct ufsmount *ump;
	struct fs *fs;
	int error, flags;

	flags = 0;
	if (mntflags & MNT_FORCE)
		flags |= FORCECLOSE;

	ump = VFSTOUFS(mp);
	fs = ump->um_fs;
	if (mp->mnt_flag & MNT_SOFTDEP)
		error = softdep_flushfiles(mp, flags, p);
	else
		error = ffs_flushfiles(mp, flags, p);
	if (error != 0)
		return (error);

	if (fs->fs_ronly == 0) {
		fs->fs_clean = (fs->fs_flags & FS_UNCLEAN) ? 0 : 1;
		error = ffs_sbupdate(ump, MNT_WAIT);
		/* ignore write errors if mounted RW on read-only device */
		if (error && error != EROFS) {
			fs->fs_clean = 0;
			return (error);
		}
		free(fs->fs_contigdirs, M_UFSMNT);
	}
	ump->um_devvp->v_specmountpoint = NULL;

	vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p);
	vinvalbuf(ump->um_devvp, V_SAVE, NOCRED, p, 0, 0);
	error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE,
		NOCRED, p);
	VOP_UNLOCK(ump->um_devvp, 0, p);
	vrele(ump->um_devvp);
	free(fs->fs_csp, M_UFSMNT);
	free(fs, M_UFSMNT);
	free(ump, M_UFSMNT);
	mp->mnt_data = (qaddr_t)0;
	mp->mnt_flag &= ~MNT_LOCAL;
	return (error);
}
예제 #8
0
/*
 * If the cpr default file is invalid, then we must not be in reusable mode
 * if it is valid, it tells us our mode
 */
int
cpr_get_reusable_mode(void)
{
	struct vnode *vp;
	cmini_t mini;
	int rc;

	if (cpr_open(cpr_default_path, FREAD, &vp))
		return (0);

	rc = cpr_rdwr(UIO_READ, vp, &mini, sizeof (mini));
	(void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
	VN_RELE(vp);
	if (rc == 0 && mini.magic == CPR_DEFAULT_MAGIC)
		return (mini.reusable);

	return (0);
}
/*
 * Helper function for findroot():
 * Return non-zero if disk device matches bootinfo.
 */
static int
match_bootdisk(device_t dv, struct btinfo_bootdisk *bid)
{
	struct vnode *tmpvn;
	int error;
	struct disklabel label;
	int found = 0;

	if (device_is_a(dv, "dk"))
		return 0;

	/*
	 * A disklabel is required here.  The boot loader doesn't refuse
	 * to boot from a disk without a label, but this is normally not
	 * wanted.
	 */
	if (bid->labelsector == -1)
		return (0);
	
	if ((tmpvn = opendisk(dv)) == NULL)
		return 0;

	error = VOP_IOCTL(tmpvn, DIOCGDINFO, &label, FREAD, NOCRED);
	if (error) {
		/*
		 * XXX Can't happen -- open() would have errored out
		 * or faked one up.
		 */
		printf("findroot: can't get label for dev %s (%d)\n",
		    device_xname(dv), error);
		goto closeout;
	}

	/* Compare with our data. */
	if (label.d_type == bid->label.type &&
	    label.d_checksum == bid->label.checksum &&
	    strncmp(label.d_packname, bid->label.packname, 16) == 0)
		found = 1;

 closeout:
	VOP_CLOSE(tmpvn, FREAD, NOCRED);
	vput(tmpvn);
	return (found);
}
/*
 * Helper function for findroot():
 * Return non-zero if wedge device matches bootinfo.
 */
static int
match_bootwedge(device_t dv, struct btinfo_bootwedge *biw)
{
	MD5_CTX ctx;
	struct vnode *tmpvn;
	int error;
	uint8_t bf[DEV_BSIZE];
	uint8_t hash[16];
	int found = 0;
	daddr_t blk;
	uint64_t nblks;

	/*
	 * If the boot loader didn't specify the sector, abort.
	 */
	if (biw->matchblk == -1)
		return (0);

	if ((tmpvn = opendisk(dv)) == NULL)
		return 0;

	MD5Init(&ctx);
	for (blk = biw->matchblk, nblks = biw->matchnblks;
	     nblks != 0; nblks--, blk++) {
		error = vn_rdwr(UIO_READ, tmpvn, (void *) bf,
		    sizeof(bf), blk * DEV_BSIZE, UIO_SYSSPACE,
		    0, NOCRED, NULL, NULL);
		if (error) {
			printf("findroot: unable to read block %" PRId64 " "
			    "of dev %s (%d)\n", blk, device_xname(dv), error);
			goto closeout;
		}
		MD5Update(&ctx, bf, sizeof(bf));
	}
	MD5Final(hash, &ctx);

	/* Compare with the provided hash. */
	found = memcmp(biw->matchhash, hash, sizeof(hash)) == 0;

 closeout:
	VOP_CLOSE(tmpvn, FREAD, NOCRED);
	vput(tmpvn);
	return (found);
}
예제 #11
0
static int
splat_vnode_test6(struct file *file, void *arg)
{
	vnode_t *vp;
	char buf[32] = "SPL VNode Interface Test File\n";
	int rc;

	if ((rc = splat_vnode_unlink_all(file, arg, SPLAT_VNODE_TEST6_NAME)))
		return rc;

	if ((rc = vn_open(SPLAT_VNODE_TEST_FILE_RW, UIO_SYSSPACE,
			  FWRITE | FCREAT | FEXCL, 0644, &vp, 0, 0))) {
		splat_vprint(file, SPLAT_VNODE_TEST6_NAME,
			     "Failed to vn_open test file: %s (%d)\n",
			     SPLAT_VNODE_TEST_FILE_RW, rc);
		return -rc;
	}

        rc = vn_rdwr(UIO_WRITE, vp, buf, strlen(buf), 0,
                     UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL);
	if (rc) {
		splat_vprint(file, SPLAT_VNODE_TEST6_NAME,
			     "Failed vn_rdwr write of test file: %s (%d)\n",
			     SPLAT_VNODE_TEST_FILE_RW, rc);
		goto out;
	}

	rc = vn_fsync(vp, 0, 0, 0);
	if (rc) {
		splat_vprint(file, SPLAT_VNODE_TEST6_NAME,
			     "Failed vn_fsync of test file: %s (%d)\n",
			     SPLAT_VNODE_TEST_FILE_RW, rc);
		goto out;
	}

	rc = 0;
	splat_vprint(file, SPLAT_VNODE_TEST6_NAME, "Successfully "
		     "fsync'ed test file %s\n", SPLAT_VNODE_TEST_FILE_RW);
out:
        VOP_CLOSE(vp, 0, 0, 0, 0, 0);
	vn_remove(SPLAT_VNODE_TEST_FILE_RW, UIO_SYSSPACE, RMFILE);

        return -rc;
} /* splat_vnode_test6() */
예제 #12
0
/* ARGSUSED */
static void
acct_shutdown(zoneid_t zoneid, void *arg)
{
	struct acct_globals *ag = arg;

	mutex_enter(&ag->aclock);
	if (ag->acctvp) {
		/*
		 * This needs to be done as a shutdown callback, otherwise this
		 * held vnode may cause filesystems to be busy, and the zone
		 * shutdown operation to fail.
		 */
		(void) VOP_CLOSE(ag->acctvp, FWRITE, 1, (offset_t)0, kcred,
		    NULL);
		VN_RELE(ag->acctvp);
	}
	ag->acctvp = NULL;
	mutex_exit(&ag->aclock);
}
예제 #13
0
int
udf_unmount(struct mount *mp, int mntflags, struct proc *p)
{
	struct umount *ump;
	struct vnode *devvp;
	int error, flags = 0;

	ump = VFSTOUDFFS(mp);
	devvp = ump->um_devvp;

	if (mntflags & MNT_FORCE)
		flags |= FORCECLOSE;

	if ((error = vflush(mp, NULL, flags)))
		return (error);

	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
	vinvalbuf(devvp, V_SAVE, NOCRED, p, 0, 0);
	error = VOP_CLOSE(devvp, FREAD, NOCRED, p);
	VOP_UNLOCK(devvp, 0, p);
	if (error)
		return (error);

	devvp->v_specmountpoint = NULL;
	vrele(devvp);

	if (ump->um_flags & UDF_MNT_USES_VAT)
		free(ump->um_vat, M_UDFMOUNT);

	if (ump->um_stbl != NULL)
		free(ump->um_stbl, M_UDFMOUNT);

	if (ump->um_hashtbl != NULL)
		free(ump->um_hashtbl, M_UDFMOUNT);

	free(ump, M_UDFMOUNT);

	mp->mnt_data = (qaddr_t)0;
	mp->mnt_flag &= ~MNT_LOCAL;

	return (0);
}
예제 #14
0
파일: cons.c 프로젝트: goroutines/rumprun
int
cnclose(dev_t dev, int flag, int mode, struct lwp *l)
{
	struct vnode *vp;
	int unit, error;

	unit = minor(dev);

	if (cn_tab == NULL)
		return (0);

	vp = cn_devvp[unit];
	cn_devvp[unit] = NULL;
	error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
	if (error == 0) {
		error = VOP_CLOSE(vp, flag, kauth_cred_get());
		VOP_UNLOCK(vp);
	}
	return error;
}
예제 #15
0
파일: vdev_file.c 프로젝트: BjoKaSH/zfs-osx
static void
vdev_file_close(vdev_t *vd)
{
	vdev_file_t *vf = vd->vdev_tsd;

	if (vd->vdev_reopening || vf == NULL)
		return;

	if (vf->vf_vnode != NULL) {
        vnode_getwithvid(vf->vf_vnode, vf->vf_vid);
        // Also commented out in MacZFS
		//(void) VOP_PUTPAGE(vf->vf_vnode, 0, 0, B_INVAL, kcred, NULL);
		(void) VOP_CLOSE(vf->vf_vnode, spa_mode(vd->vdev_spa), 1, 0,
		    kcred, NULL);
	}

	vd->vdev_delayed_close = B_FALSE;
	kmem_free(vf, sizeof (vdev_file_t));
	vd->vdev_tsd = NULL;
}
예제 #16
0
/*
 * This closes /dev/tty.  Because multiple opens of /dev/tty only
 * generate a single open to the actual tty, the file modes are
 * locked to FREAD|FWRITE.
 */
static int
cttyclose(struct dev_close_args *ap)
{
	struct proc *p = curproc;
	struct vnode *ttyvp;
	int error;

	KKASSERT(p);
retry:
	/*
	 * The tty may have been TIOCNOTTY'd, don't return an
	 * error on close.  We just have nothing to do.
	 */
	if ((ttyvp = cttyvp(p)) == NULL)
		return(0);
	if (ttyvp->v_flag & VCTTYISOPEN) {
		/*
		 * Avoid a nasty race if we block while getting the lock.
		 */
		vref(ttyvp);
		error = vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY |
				       LK_FAILRECLAIM);
		if (error) {
			vrele(ttyvp);
			goto retry;
		}
		if (ttyvp != cttyvp(p) || (ttyvp->v_flag & VCTTYISOPEN) == 0) {
			kprintf("Warning: cttyclose: race avoided\n");
			vn_unlock(ttyvp);
			vrele(ttyvp);
			goto retry;
		}
		vclrflags(ttyvp, VCTTYISOPEN);
		error = VOP_CLOSE(ttyvp, FREAD|FWRITE);
		vn_unlock(ttyvp);
		vrele(ttyvp);
	} else {
		error = 0;
	}
	return(error);
}
예제 #17
0
void
hfs_libcb_closedev(hfs_volume* in_vol, hfs_callback_args* cbargs)
{
	struct vnode *devvp;
	
	if (in_vol == NULL)
		return;
	
	if (in_vol->cbdata != NULL) {
		devvp = ((hfs_libcb_data*)in_vol->cbdata)->devvp;
		if (devvp != NULL) {
			vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
			(void)VOP_CLOSE(devvp,
			    in_vol->readonly ? FREAD : FREAD | FWRITE, NOCRED);
			/* XXX do we need a VOP_UNLOCK() here? */
		}

		free(in_vol->cbdata, M_HFSMNT);
		in_vol->cbdata = NULL;
	}
}
예제 #18
0
파일: xattr.c 프로젝트: pcd1193182/openzfs
/* ARGSUSED */
static int
xattr_dir_close(vnode_t *vp, int flags, int count, offset_t off, cred_t *cr,
    caller_context_t *ct)
{
	vnode_t *realvp;
	int error;

	/*
	 * If there is a real extended attribute directory,
	 * let the underlying FS see the VOP_CLOSE call;
	 * otherwise just return zero.
	 */
	error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct);
	if (error == 0) {
		error = VOP_CLOSE(realvp, flags, count, off, cr, ct);
	} else {
		error = 0;
	}

	return (error);
}
예제 #19
0
static int
splat_vnode_test5(struct file *file, void *arg)
{
	vnode_t *vp;
	vattr_t vap;
	int rc;

	if ((rc = vn_open(SPLAT_VNODE_TEST_FILE, UIO_SYSSPACE,
			  FREAD, 0644, &vp, 0, 0))) {
		splat_vprint(file, SPLAT_VNODE_TEST5_NAME,
			     "Failed to vn_open test file: %s (%d)\n",
			     SPLAT_VNODE_TEST_FILE, rc);
		return -rc;
	}

	rc = VOP_GETATTR(vp, &vap, 0, 0, NULL);
	if (rc) {
		splat_vprint(file, SPLAT_VNODE_TEST5_NAME,
			     "Failed to vn_getattr test file: %s (%d)\n",
			     SPLAT_VNODE_TEST_FILE, rc);
		goto out;
	}

	if (vap.va_type != VREG) {
		rc = EINVAL;
		splat_vprint(file, SPLAT_VNODE_TEST5_NAME,
			     "Failed expected regular file type "
			     "(%d != VREG): %s (%d)\n", vap.va_type,
			     SPLAT_VNODE_TEST_FILE, rc);
		goto out;
	}

	splat_vprint(file, SPLAT_VNODE_TEST1_NAME, "Successfully "
		     "vn_getattr'ed test file: %s\n", SPLAT_VNODE_TEST_FILE);

out:
        VOP_CLOSE(vp, 0, 0, 0, 0, 0);

        return -rc;
} /* splat_vnode_test5() */
예제 #20
0
/*
 * write cdef_t to disk.  This contains the original values of prom
 * properties that we modify.  We fill in the magic number of the file
 * here as a signal to the booter code that the state file is valid.
 * Be sure the file gets synced, since we may be shutting down the OS.
 */
int
cpr_write_deffile(cdef_t *cdef)
{
	struct vnode *vp;
	char *str;
	int rc;

	if (rc = cpr_open_deffile(FCREAT|FWRITE, &vp))
		return (rc);

	if (rc = cpr_rdwr(UIO_WRITE, vp, cdef, sizeof (*cdef)))
		str = "write";
	else if (rc = VOP_FSYNC(vp, FSYNC, CRED(), NULL))
		str = "fsync";
	(void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED(), NULL);
	VN_RELE(vp);

	if (rc) {
		cpr_err(CE_WARN, "%s error %d, file \"%s\"",
		    str, rc, cpr_default_path);
	}
	return (rc);
}
예제 #21
0
int
i_cpr_check_cprinfo(void)
{
	struct vnode *vp;
	cmini_t mini;
	int rc = 0;

	if (rc = cpr_open_deffile(FREAD, &vp)) {
		if (rc == ENOENT)
			cpr_err(CE_NOTE, "cprinfo file does not "
			    "exist.  You must run 'uadmin %d %d' "
			    "command while / is mounted writeable,\n"
			    "then reboot and run 'uadmin %d %d' "
			    "to create a reusable statefile",
			    A_FREEZE, AD_REUSEINIT, A_FREEZE, AD_REUSABLE);
		return (rc);
	}

	rc = cpr_rdwr(UIO_READ, vp, &mini, sizeof (mini));
	(void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
	VN_RELE(vp);

	if (rc) {
		cpr_err(CE_WARN, "Failed reading %s, errno = %d",
		    cpr_default_path, rc);
	} else if (mini.magic != CPR_DEFAULT_MAGIC) {
		cpr_err(CE_CONT, "bad magic number in cprinfo file.\n"
		    "You must run 'uadmin %d %d' while / is mounted "
		    "writeable, then reboot and run 'uadmin %d %d' "
		    "to create a reusable statefile\n",
		    A_FREEZE, AD_REUSEINIT, A_FREEZE, AD_REUSABLE);
		rc = EINVAL;
	}

	return (rc);
}
예제 #22
0
int
v7fs_unmount(struct mount *mp, int mntflags)
{
    struct v7fs_mount *v7fsmount = (void *)mp->mnt_data;
    int error;

    DPRINTF("%p\n", v7fsmount);

    if ((error = vflush(mp, NULLVP,
                        mntflags & MNT_FORCE ? FORCECLOSE : 0)) != 0)
        return error;

    vn_lock(v7fsmount->devvp, LK_EXCLUSIVE | LK_RETRY);
    error = VOP_CLOSE(v7fsmount->devvp, FREAD, NOCRED);
    vput(v7fsmount->devvp);

    v7fs_io_fini(v7fsmount->core);

    kmem_free(v7fsmount, sizeof(*v7fsmount));
    mp->mnt_data = NULL;
    mp->mnt_flag &= ~MNT_LOCAL;

    return 0;
}
예제 #23
0
/*
 * Decrement the open count.
 * Called by VOP_DECOPEN.
 */
void
vnode_decopen(struct vnode *vn)
{
	int opencount, result;

	assert(vn!=NULL);
	lock_acquire(vn->vn_countlock);
	assert(vn->vn_opencount>0);
	vn->vn_opencount--;
	opencount = vn->vn_opencount;
	lock_release(vn->vn_countlock);

	if (opencount > 0) {
		return;
	}

	result = VOP_CLOSE(vn);
	if (result) {
		// XXX: also lame.
		// The FS should do what it can to make sure this code
		// doesn't get reached...
		kprintf("vfs: Warning: VOP_CLOSE: %s\n", strerror(result));
	}
}
예제 #24
0
/*
 * unmount system call
 */
int
cd9660_unmount(struct mount *mp, int mntflags)
{
	struct iso_mnt *isomp;
	int error, flags = 0;

	if (mntflags & MNT_FORCE)
		flags |= FORCECLOSE;
	if ((error = vflush(mp, NULLVP, flags)) != 0)
		return (error);

	isomp = VFSTOISOFS(mp);

	if (isomp->im_devvp->v_type != VBAD)
		spec_node_setmountedfs(isomp->im_devvp, NULL);

	vn_lock(isomp->im_devvp, LK_EXCLUSIVE | LK_RETRY);
	error = VOP_CLOSE(isomp->im_devvp, FREAD, NOCRED);
	vput(isomp->im_devvp);
	free(isomp, M_ISOFSMNT);
	mp->mnt_data = NULL;
	mp->mnt_flag &= ~MNT_LOCAL;
	return (error);
}
예제 #25
0
/*
 * reads config data into cprconfig
 */
static int
cpr_get_config(void)
{
	static char config_path[] = CPR_CONFIG;
	struct cprconfig *cf = &cprconfig;
	struct vnode *vp;
	char *fmt;
	int err;

	if (cprconfig_loaded)
		return (0);

	fmt = "cannot %s config file \"%s\", error %d\n";
	if (err = vn_open(config_path, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0)) {
		cpr_err(CE_CONT, fmt, "open", config_path, err);
		return (err);
	}

	err = cpr_rdwr(UIO_READ, vp, cf, sizeof (*cf));
	(void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
	VN_RELE(vp);
	if (err) {
		cpr_err(CE_CONT, fmt, "read", config_path, err);
		return (err);
	}

	if (cf->cf_magic == CPR_CONFIG_MAGIC)
		cprconfig_loaded = 1;
	else {
		cpr_err(CE_CONT, "invalid config file \"%s\", "
		    "rerun pmconfig(1M)\n", config_path);
		err = EINVAL;
	}

	return (err);
}
예제 #26
0
/*
 * unmount system call
 */
int
ext2fs_unmount(struct mount *mp, int mntflags, struct proc *p)
{
	struct ufsmount *ump;
	struct m_ext2fs *fs;
	int error, flags;
	size_t gdescs_space;

	flags = 0;
	if (mntflags & MNT_FORCE)
		flags |= FORCECLOSE;
	if ((error = ext2fs_flushfiles(mp, flags, p)) != 0)
		return (error);
	ump = VFSTOUFS(mp);
	fs = ump->um_e2fs;
	gdescs_space = fs->e2fs_ngdb * fs->e2fs_bsize;

	if (!fs->e2fs_ronly && ext2fs_cgupdate(ump, MNT_WAIT) == 0 &&
	    (fs->e2fs.e2fs_state & E2FS_ERRORS) == 0) {
		fs->e2fs.e2fs_state = E2FS_ISCLEAN;
		(void) ext2fs_sbupdate(ump, MNT_WAIT);
	}

	if (ump->um_devvp->v_type != VBAD)
		ump->um_devvp->v_specmountpoint = NULL;
	vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p);
	(void)VOP_CLOSE(ump->um_devvp, fs->e2fs_ronly ? FREAD : FREAD|FWRITE,
	    NOCRED, p);
	vput(ump->um_devvp);
	free(fs->e2fs_gd, M_UFSMNT, gdescs_space);
	free(fs, M_UFSMNT, sizeof *fs);
	free(ump, M_UFSMNT, sizeof *ump);
	mp->mnt_data = NULL;
	mp->mnt_flag &= ~MNT_LOCAL;
	return (0);
}
예제 #27
0
/*
 * Synchronize all pools to disk.  This must be called with the namespace lock
 * held.
 */
void
spa_config_sync(void)
{
	spa_t *spa = NULL;
	nvlist_t *config;
	size_t buflen;
	char *buf;
	vnode_t *vp;
	int oflags = FWRITE | FTRUNC | FCREAT | FOFFMAX;
	char pathname[128];
	char pathname2[128];

	ASSERT(MUTEX_HELD(&spa_namespace_lock));

	VERIFY(nvlist_alloc(&config, NV_UNIQUE_NAME, KM_SLEEP) == 0);

	/*
	 * Add all known pools to the configuration list, ignoring those with
	 * alternate root paths.
	 */
	spa = NULL;
	while ((spa = spa_next(spa)) != NULL) {
		mutex_enter(&spa->spa_config_cache_lock);
		if (spa->spa_config && spa->spa_name && spa->spa_root == NULL)
			VERIFY(nvlist_add_nvlist(config, spa->spa_name,
			    spa->spa_config) == 0);
		mutex_exit(&spa->spa_config_cache_lock);
	}

	/*
	 * Pack the configuration into a buffer.
	 */
	VERIFY(nvlist_size(config, &buflen, NV_ENCODE_XDR) == 0);

	buf = kmem_alloc(buflen, KM_SLEEP);

	VERIFY(nvlist_pack(config, &buf, &buflen, NV_ENCODE_XDR,
	    KM_SLEEP) == 0);

	/*
	 * Write the configuration to disk.  We need to do the traditional
	 * 'write to temporary file, sync, move over original' to make sure we
	 * always have a consistent view of the data.
	 */
	(void) snprintf(pathname, sizeof (pathname), "%s/%s", spa_config_dir,
	    ZPOOL_CACHE_TMP);

	if (vn_open(pathname, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0) != 0)
		goto out;

	if (vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE,
	    0, RLIM64_INFINITY, kcred, NULL) == 0 &&
	    VOP_FSYNC(vp, FSYNC, kcred) == 0) {
		(void) snprintf(pathname2, sizeof (pathname2), "%s/%s",
		    spa_config_dir, ZPOOL_CACHE_FILE);
		(void) vn_rename(pathname, pathname2, UIO_SYSSPACE);
	}

	(void) VOP_CLOSE(vp, oflags, 1, 0, kcred);
	VN_RELE(vp);

out:
	(void) vn_remove(pathname, UIO_SYSSPACE, RMFILE);
	spa_config_generation++;

	kmem_free(buf, buflen);
	nvlist_free(config);
}
예제 #28
0
파일: spa_config.c 프로젝트: koplover/zfs
static void
spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl)
{
	size_t buflen;
	char *buf;
	vnode_t *vp;
	int oflags = FWRITE | FTRUNC | FCREAT | FOFFMAX;
	int error;
	char *temp;

	/*
	 * If the nvlist is empty (NULL), then remove the old cachefile.
	 */
	if (nvl == NULL) {
		(void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE);
		return;
	}

	/*
	 * Pack the configuration into a buffer.
	 */
	VERIFY(nvlist_size(nvl, &buflen, NV_ENCODE_XDR) == 0);

	buf = vmem_alloc(buflen, KM_SLEEP);
	temp = kmem_zalloc(MAXPATHLEN, KM_SLEEP);

	VERIFY(nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_XDR,
	    KM_SLEEP) == 0);

#if defined(__linux__) && defined(_KERNEL)
	/*
	 * Write the configuration to disk.  Due to the complexity involved
	 * in performing a rename from within the kernel the file is truncated
	 * and overwritten in place.  In the event of an error the file is
	 * unlinked to make sure we always have a consistent view of the data.
	 */
	error = vn_open(dp->scd_path, UIO_SYSSPACE, oflags, 0644, &vp, 0, 0);
	if (error == 0) {
		error = vn_rdwr(UIO_WRITE, vp, buf, buflen, 0,
		    UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, NULL);
		if (error == 0)
			error = VOP_FSYNC(vp, FSYNC, kcred, NULL);

		(void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL);

		if (error)
			(void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE);
	}
#else
	/*
	 * Write the configuration to disk.  We need to do the traditional
	 * 'write to temporary file, sync, move over original' to make sure we
	 * always have a consistent view of the data.
	 */
	(void) snprintf(temp, MAXPATHLEN, "%s.tmp", dp->scd_path);

	error = vn_open(temp, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0);
	if (error == 0) {
		if (vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE,
		    0, RLIM64_INFINITY, kcred, NULL) == 0 &&
		    VOP_FSYNC(vp, FSYNC, kcred, NULL) == 0) {
			(void) vn_rename(temp, dp->scd_path, UIO_SYSSPACE);
		}
		(void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL);
	}

	(void) vn_remove(temp, UIO_SYSSPACE, RMFILE);
#endif

	vmem_free(buf, buflen);
	kmem_free(temp, MAXPATHLEN);
}
예제 #29
0
int
msdosfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p,
    struct msdosfs_args *argp)
{
	struct msdosfsmount *pmp;
	struct buf *bp;
	dev_t dev = devvp->v_rdev;
	union bootsector *bsp;
	struct byte_bpb33 *b33;
	struct byte_bpb50 *b50;
	struct byte_bpb710 *b710;
	extern struct vnode *rootvp;
	u_int8_t SecPerClust;
	int	ronly, error, bmapsiz;
	uint32_t fat_max_clusters;

	/*
	 * Disallow multiple mounts of the same device.
	 * Disallow mounting of a device that is currently in use
	 * (except for root, which might share swap device for miniroot).
	 * Flush out any old buffers remaining from a previous use.
	 */
	if ((error = vfs_mountedon(devvp)) != 0)
		return (error);
	if (vcount(devvp) > 1 && devvp != rootvp)
		return (EBUSY);
	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
	error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
	VOP_UNLOCK(devvp, 0, p);
	if (error)
		return (error);

	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
	error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
	if (error)
		return (error);

	bp  = NULL; /* both used in error_exit */
	pmp = NULL;

	/*
	 * Read the boot sector of the filesystem, and then check the
	 * boot signature.  If not a dos boot sector then error out.
	 */
	if ((error = bread(devvp, 0, 4096, NOCRED, &bp)) != 0)
		goto error_exit;
	bp->b_flags |= B_AGE;
	bsp = (union bootsector *)bp->b_data;
	b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB;
	b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB;
	b710 = (struct byte_bpb710 *)bsp->bs710.bsPBP;

	pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK | M_ZERO);
	pmp->pm_mountp = mp;

	/*
	 * Compute several useful quantities from the bpb in the
	 * bootsector.  Copy in the dos 5 variant of the bpb then fix up
	 * the fields that are different between dos 5 and dos 3.3.
	 */
	SecPerClust = b50->bpbSecPerClust;
	pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
	pmp->pm_ResSectors = getushort(b50->bpbResSectors);
	pmp->pm_FATs = b50->bpbFATs;
	pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
	pmp->pm_Sectors = getushort(b50->bpbSectors);
	pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
	pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
	pmp->pm_Heads = getushort(b50->bpbHeads);
	pmp->pm_Media = b50->bpbMedia;

	/* Determine the number of DEV_BSIZE blocks in a MSDOSFS sector */
	pmp->pm_BlkPerSec = pmp->pm_BytesPerSec / DEV_BSIZE;

    	if (!pmp->pm_BytesPerSec || !SecPerClust || pmp->pm_SecPerTrack > 64) {
		error = EFTYPE;
		goto error_exit;
	}

	if (pmp->pm_Sectors == 0) {
		pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
		pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
	} else {
		pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
		pmp->pm_HugeSectors = pmp->pm_Sectors;
	}

	if (pmp->pm_RootDirEnts == 0) {
		if (pmp->pm_Sectors || pmp->pm_FATsecs ||
		    getushort(b710->bpbFSVers)) {
		        error = EINVAL;
			goto error_exit;
		}
		pmp->pm_fatmask = FAT32_MASK;
		pmp->pm_fatmult = 4;
		pmp->pm_fatdiv = 1;
		pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs);
		if (getushort(b710->bpbExtFlags) & FATMIRROR)
		        pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM;
		else
		        pmp->pm_flags |= MSDOSFS_FATMIRROR;
	} else
	        pmp->pm_flags |= MSDOSFS_FATMIRROR;

	/*
	 * More sanity checks:
	 *	MSDOSFS sectors per cluster: >0 && power of 2
	 *	MSDOSFS sector size: >= DEV_BSIZE && power of 2
	 *	HUGE sector count: >0
	 * 	FAT sectors: >0
	 */
	if ((SecPerClust == 0) || (SecPerClust & (SecPerClust - 1)) ||
	    (pmp->pm_BytesPerSec < DEV_BSIZE) ||
	    (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) ||
	    (pmp->pm_HugeSectors == 0) || (pmp->pm_FATsecs == 0)) {
		error = EINVAL;
		goto error_exit;
	}		
	
	pmp->pm_HugeSectors *= pmp->pm_BlkPerSec;
	pmp->pm_HiddenSects *= pmp->pm_BlkPerSec;
	pmp->pm_FATsecs *= pmp->pm_BlkPerSec;
	pmp->pm_fatblk = pmp->pm_ResSectors * pmp->pm_BlkPerSec;
	SecPerClust *= pmp->pm_BlkPerSec;

	if (FAT32(pmp)) {
	        pmp->pm_rootdirblk = getulong(b710->bpbRootClust);
		pmp->pm_firstcluster = pmp->pm_fatblk
		        + (pmp->pm_FATs * pmp->pm_FATsecs);
		pmp->pm_fsinfo = getushort(b710->bpbFSInfo) * pmp->pm_BlkPerSec;
	} else {
	        pmp->pm_rootdirblk = pmp->pm_fatblk +
		        (pmp->pm_FATs * pmp->pm_FATsecs);
		pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)
				       + DEV_BSIZE - 1) / DEV_BSIZE;
		pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
	}

	pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
	    SecPerClust;
	pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1;
	pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE;

	if (pmp->pm_fatmask == 0) {
		if (pmp->pm_maxcluster
		    <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) {
			/*
			 * This will usually be a floppy disk. This size makes
			 * sure that one fat entry will not be split across
			 * multiple blocks.
			 */
			pmp->pm_fatmask = FAT12_MASK;
			pmp->pm_fatmult = 3;
			pmp->pm_fatdiv = 2;
		} else {
			pmp->pm_fatmask = FAT16_MASK;
			pmp->pm_fatmult = 2;
			pmp->pm_fatdiv = 1;
		}
	}
	if (FAT12(pmp))
		pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
	else
		pmp->pm_fatblocksize = MAXBSIZE;

	/*
	 * We now have the number of sectors in each FAT, so can work
	 * out how many clusters can be represented in a FAT.  Let's
	 * make sure the file system doesn't claim to have more clusters
	 * than this.
	 *
	 * We perform the calculation like we do to avoid integer overflow.
	 *
	 * This will give us a count of clusters.  They are numbered
	 * from 0, so the max cluster value is one less than the value
	 * we end up with.
	 */
	fat_max_clusters = pmp->pm_fatsize / pmp->pm_fatmult;
	fat_max_clusters *= pmp->pm_fatdiv;
	if (pmp->pm_maxcluster >= fat_max_clusters) {
#ifndef SMALL_KERNEL
		printf("msdosfs: reducing max cluster to %d from %d "
		    "due to FAT size\n", fat_max_clusters - 1,
		    pmp->pm_maxcluster);
#endif
		pmp->pm_maxcluster = fat_max_clusters - 1;
	}

	pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE;
	pmp->pm_bnshift = ffs(DEV_BSIZE) - 1;

	/*
	 * Compute mask and shift value for isolating cluster relative byte
	 * offsets and cluster numbers from a file offset.
	 */
	pmp->pm_bpcluster = SecPerClust * DEV_BSIZE;
	pmp->pm_crbomask = pmp->pm_bpcluster - 1;
	pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;

	/*
	 * Check for valid cluster size
	 * must be a power of 2
	 */
	if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) {
		error = EFTYPE;
		goto error_exit;
	}

	/*
	 * Release the bootsector buffer.
	 */
	brelse(bp);
	bp = NULL;

	/*
	 * Check FSInfo
	 */
	if (pmp->pm_fsinfo) {
	        struct fsinfo *fp;

		if ((error = bread(devvp, pmp->pm_fsinfo, fsi_size(pmp),
		    NOCRED, &bp)) != 0)
		        goto error_exit;
		fp = (struct fsinfo *)bp->b_data;
		if (!bcmp(fp->fsisig1, "RRaA", 4)
		    && !bcmp(fp->fsisig2, "rrAa", 4)
		    && !bcmp(fp->fsisig3, "\0\0\125\252", 4)
		    && !bcmp(fp->fsisig4, "\0\0\125\252", 4))
		        /* Valid FSInfo. */
			;
		else
		        pmp->pm_fsinfo = 0;
		/* XXX make sure this tiny buf doesn't come back in fillinusemap! */
		SET(bp->b_flags, B_INVAL);
		brelse(bp);
		bp = NULL;
	}

	/*
	 * Check and validate (or perhaps invalidate?) the fsinfo structure? XXX
	 */

	/*
	 * Allocate memory for the bitmap of allocated clusters, and then
	 * fill it in.
	 */
	bmapsiz = (pmp->pm_maxcluster + N_INUSEBITS - 1) / N_INUSEBITS;
	if (bmapsiz == 0 || SIZE_MAX / bmapsiz < sizeof(*pmp->pm_inusemap)) {
		/* detect multiplicative integer overflow */
		error = EINVAL;
		goto error_exit;
	}
	pmp->pm_inusemap = malloc(bmapsiz * sizeof(*pmp->pm_inusemap),
	    M_MSDOSFSFAT, M_WAITOK | M_CANFAIL);
	if (pmp->pm_inusemap == NULL) {
		error = EINVAL;
		goto error_exit;
	}

	/*
	 * fillinusemap() needs pm_devvp.
	 */
	pmp->pm_dev = dev;
	pmp->pm_devvp = devvp;

	/*
	 * Have the inuse map filled in.
	 */
	if ((error = fillinusemap(pmp)) != 0)
		goto error_exit;

	/*
	 * If they want fat updates to be synchronous then let them suffer
	 * the performance degradation in exchange for the on disk copy of
	 * the fat being correct just about all the time.  I suppose this
	 * would be a good thing to turn on if the kernel is still flakey.
	 */
	if (mp->mnt_flag & MNT_SYNCHRONOUS)
		pmp->pm_flags |= MSDOSFSMNT_WAITONFAT;

	/*
	 * Finish up.
	 */
	if (ronly)
		pmp->pm_flags |= MSDOSFSMNT_RONLY;
	else
		pmp->pm_fmod = 1;
	mp->mnt_data = (qaddr_t)pmp;
        mp->mnt_stat.f_fsid.val[0] = (long)dev;
        mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
#ifdef QUOTA
	/*
	 * If we ever do quotas for DOS filesystems this would be a place
	 * to fill in the info in the msdosfsmount structure. You dolt,
	 * quotas on dos filesystems make no sense because files have no
	 * owners on dos filesystems. of course there is some empty space
	 * in the directory entry where we could put uid's and gid's.
	 */
#endif
	devvp->v_specmountpoint = mp;

	return (0);

error_exit:
	devvp->v_specmountpoint = NULL;
	if (bp)
		brelse(bp);

	vn_lock(devvp, LK_EXCLUSIVE|LK_RETRY, p);
	(void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
	VOP_UNLOCK(devvp, 0, p);

	if (pmp) {
		if (pmp->pm_inusemap)
			free(pmp->pm_inusemap, M_MSDOSFSFAT);
		free(pmp, M_MSDOSFSMNT);
		mp->mnt_data = (qaddr_t)0;
	}
	return (error);
}
예제 #30
0
int
udf_mountfs(struct vnode *devvp, struct mount *mp, uint32_t lb, struct proc *p)
{
	struct buf *bp = NULL;
	struct anchor_vdp avdp;
	struct umount *ump = NULL;
	struct part_desc *pd;
	struct logvol_desc *lvd;
	struct fileset_desc *fsd;
	struct extfile_entry *xfentry;
	struct file_entry *fentry;
	uint32_t sector, size, mvds_start, mvds_end;
	uint32_t fsd_offset = 0;
	uint16_t part_num = 0, fsd_part = 0;
	int error = EINVAL;
	int logvol_found = 0, part_found = 0, fsd_found = 0;
	int bsize;

	/*
	 * Disallow multiple mounts of the same device.
	 * Disallow mounting of a device that is currently in use
	 * (except for root, which might share swap device for miniroot).
	 * Flush out any old buffers remaining from a previous use.
	 */
	if ((error = vfs_mountedon(devvp)))
		return (error);
	if (vcount(devvp) > 1 && devvp != rootvp)
		return (EBUSY);
	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
	error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
	VOP_UNLOCK(devvp, 0, p);
	if (error)
		return (error);

	error = VOP_OPEN(devvp, FREAD, FSCRED, p);
	if (error)
		return (error);

	ump = malloc(sizeof(*ump), M_UDFMOUNT, M_WAITOK | M_ZERO);

	mp->mnt_data = (qaddr_t) ump;
	mp->mnt_stat.f_fsid.val[0] = devvp->v_rdev;
	mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_UDF);
	mp->mnt_flag |= MNT_LOCAL;

	ump->um_mountp = mp;
	ump->um_dev = devvp->v_rdev;
	ump->um_devvp = devvp;

	bsize = 2048;	/* Should probe the media for its size. */

	/* 
	 * Get the Anchor Volume Descriptor Pointer from sector 256.
	 * Should also check sector n - 256, n, and 512.
	 */
	sector = 256;
	if ((error = bread(devvp, sector * btodb(bsize), bsize, NOCRED,
			   &bp)) != 0)
		goto bail;
	if ((error = udf_checktag((struct desc_tag *)bp->b_data, TAGID_ANCHOR)))
		goto bail;

	bcopy(bp->b_data, &avdp, sizeof(struct anchor_vdp));
	brelse(bp);
	bp = NULL;

	/*
	 * Extract the Partition Descriptor and Logical Volume Descriptor
	 * from the Volume Descriptor Sequence.
	 * Should we care about the partition type right now?
	 * What about multiple partitions?
	 */
	mvds_start = letoh32(avdp.main_vds_ex.loc);
	mvds_end = mvds_start + (letoh32(avdp.main_vds_ex.len) - 1) / bsize;
	for (sector = mvds_start; sector < mvds_end; sector++) {
		if ((error = bread(devvp, sector * btodb(bsize), bsize, 
				   NOCRED, &bp)) != 0) {
			printf("Can't read sector %d of VDS\n", sector);
			goto bail;
		}
		lvd = (struct logvol_desc *)bp->b_data;
		if (!udf_checktag(&lvd->tag, TAGID_LOGVOL)) {
			ump->um_bsize = letoh32(lvd->lb_size);
			ump->um_bmask = ump->um_bsize - 1;
			ump->um_bshift = ffs(ump->um_bsize) - 1;
			fsd_part = letoh16(lvd->_lvd_use.fsd_loc.loc.part_num);
			fsd_offset = letoh32(lvd->_lvd_use.fsd_loc.loc.lb_num);
			if (udf_find_partmaps(ump, lvd))
				break;
			logvol_found = 1;
		}
		pd = (struct part_desc *)bp->b_data;
		if (!udf_checktag(&pd->tag, TAGID_PARTITION)) {
			part_found = 1;
			part_num = letoh16(pd->part_num);
			ump->um_len = ump->um_reallen = letoh32(pd->part_len);
			ump->um_start = ump->um_realstart = letoh32(pd->start_loc);
		}

		brelse(bp); 
		bp = NULL;
		if ((part_found) && (logvol_found))
			break;
	}

	if (!part_found || !logvol_found) {
		error = EINVAL;
		goto bail;
	}

	if (ISSET(ump->um_flags, UDF_MNT_USES_META)) {
		/* Read Metadata File 'File Entry' to find Metadata file. */
		struct long_ad *la;
		sector = ump->um_start + ump->um_meta_start; /* Set in udf_get_mpartmap() */
		if ((error = RDSECTOR(devvp, sector, ump->um_bsize, &bp)) != 0) {
			printf("Cannot read sector %d for Metadata File Entry\n", sector);
			error = EINVAL;
			goto bail;
		}
		xfentry = (struct extfile_entry *)bp->b_data;
		fentry = (struct file_entry *)bp->b_data;
		if (udf_checktag(&xfentry->tag, TAGID_EXTFENTRY) == 0)
			la = (struct long_ad *)&xfentry->data[letoh32(xfentry->l_ea)];
		else if (udf_checktag(&fentry->tag, TAGID_FENTRY) == 0)
			la = (struct long_ad *)&fentry->data[letoh32(fentry->l_ea)];
		else {
			printf("Invalid Metadata File FE @ sector %d! (tag.id %d)\n",
			    sector, fentry->tag.id);
			error = EINVAL;
			goto bail;
		}
		ump->um_meta_start = letoh32(la->loc.lb_num);
		ump->um_meta_len = letoh32(la->len);
		if (bp != NULL) {
			brelse(bp);
			bp = NULL;
		}
	} else if (fsd_part != part_num) {
		printf("FSD does not lie within the partition!\n");
		error = EINVAL;
		goto bail;
	}

	mtx_init(&ump->um_hashmtx, IPL_NONE);
	ump->um_hashtbl = hashinit(UDF_HASHTBLSIZE, M_UDFMOUNT, M_WAITOK,
	    &ump->um_hashsz);

	/* Get the VAT, if needed */
	if (ump->um_flags & UDF_MNT_FIND_VAT) {
		error = udf_vat_get(ump, lb);
		if (error)
			goto bail;
	}

	/*
	 * Grab the Fileset Descriptor
	 * Thanks to Chuck McCrobie <*****@*****.**> for pointing
	 * me in the right direction here.
	 */

	if (ISSET(ump->um_flags, UDF_MNT_USES_META))
		sector = ump->um_meta_start; 
	else
		sector = fsd_offset;
	udf_vat_map(ump, &sector);
	if ((error = RDSECTOR(devvp, sector, ump->um_bsize, &bp)) != 0) {
		printf("Cannot read sector %d of FSD\n", sector);
		goto bail;
	}
	fsd = (struct fileset_desc *)bp->b_data;
	if (!udf_checktag(&fsd->tag, TAGID_FSD)) {
		fsd_found = 1;
		bcopy(&fsd->rootdir_icb, &ump->um_root_icb,
		    sizeof(struct long_ad));
		if (ISSET(ump->um_flags, UDF_MNT_USES_META)) {
			ump->um_root_icb.loc.lb_num += ump->um_meta_start; 
			ump->um_root_icb.loc.part_num = part_num;
		}
	}

	brelse(bp);
	bp = NULL;

	if (!fsd_found) {
		printf("Couldn't find the fsd\n");
		error = EINVAL;
		goto bail;
	}

	/*
	 * Find the file entry for the root directory.
	 */
	sector = letoh32(ump->um_root_icb.loc.lb_num);
	size = letoh32(ump->um_root_icb.len);
	udf_vat_map(ump, &sector);
	if ((error = udf_readlblks(ump, sector, size, &bp)) != 0) {
		printf("Cannot read sector %d\n", sector);
		goto bail;
	}

	xfentry = (struct extfile_entry *)bp->b_data;
	fentry = (struct file_entry *)bp->b_data;
	error = udf_checktag(&xfentry->tag, TAGID_EXTFENTRY);
	if (error) {
	    	error = udf_checktag(&fentry->tag, TAGID_FENTRY);
		if (error) {
			printf("Invalid root file entry!\n");
			goto bail;
		}
	}

	brelse(bp);
	bp = NULL;

	devvp->v_specmountpoint = mp;

	return (0);

bail:
	if (ump->um_hashtbl != NULL)
		free(ump->um_hashtbl, M_UDFMOUNT);

	if (ump != NULL) {
		free(ump, M_UDFMOUNT);
		mp->mnt_data = NULL;
		mp->mnt_flag &= ~MNT_LOCAL;
	}
	if (bp != NULL)
		brelse(bp);

	vn_lock(devvp, LK_EXCLUSIVE|LK_RETRY, p);
	VOP_CLOSE(devvp, FREAD, FSCRED, p);
	VOP_UNLOCK(devvp, 0, p);

	return (error);
}