static int
ntfs_unmount(struct mount *mp, int mntflags)
{
	struct ntfsmount *ntmp;
	int error, ronly, flags, i;

	dprintf(("ntfs_unmount: unmounting...\n"));
	ntmp = VFSTONTFS(mp);

	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
	flags = 0;
	if(mntflags & MNT_FORCE)
		flags |= FORCECLOSE;

	dprintf(("ntfs_unmount: vflushing...\n"));
	error = vflush(mp, 0, flags | SKIPSYSTEM);
	if (error) {
		kprintf("ntfs_unmount: vflush failed: %d\n",error);
		return (error);
	}

	/* Check if only system vnodes are left */
	for(i=0;i<NTFS_SYSNODESNUM;i++)
		 if((ntmp->ntm_sysvn[i]) &&
		    (VREFCNT(ntmp->ntm_sysvn[i]) > 1)) return (EBUSY);

	/* Dereference all system vnodes */
	for(i=0;i<NTFS_SYSNODESNUM;i++)
		 if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]);

	/* vflush system vnodes */
	error = vflush(mp, 0, flags);
	if (error)
		kprintf("ntfs_unmount: vflush failed(sysnodes): %d\n",error);

	/* Check if the type of device node isn't VBAD before
	 * touching v_cdevinfo.  If the device vnode is revoked, the
	 * field is NULL and touching it causes null pointer derefercence.
	 */
	if (ntmp->ntm_devvp->v_type != VBAD)
		ntmp->ntm_devvp->v_rdev->si_mountpoint = NULL;

	vn_lock(ntmp->ntm_devvp, LK_EXCLUSIVE | LK_RETRY);
	vinvalbuf(ntmp->ntm_devvp, V_SAVE, 0, 0);
	error = VOP_CLOSE(ntmp->ntm_devvp, ronly ? FREAD : FREAD|FWRITE, NULL);
	vn_unlock(ntmp->ntm_devvp);

	vrele(ntmp->ntm_devvp);

	/* free the toupper table, if this has been last mounted ntfs volume */
	ntfs_toupper_unuse();

	dprintf(("ntfs_umount: freeing memory...\n"));
	ntfs_u28_uninit(ntmp);
	ntfs_82u_uninit(ntmp);
	mp->mnt_data = (qaddr_t)0;
	mp->mnt_flag &= ~MNT_LOCAL;
	kfree(ntmp->ntm_ad, M_NTFSMNT);
	kfree(ntmp, M_NTFSMNT);
	return (error);
}
示例#2
0
static int
ntfs_unmount(
	struct mount *mp,
	int mntflags)
{
	struct lwp *l = curlwp;
	struct ntfsmount *ntmp;
	int error, ronly = 0, flags, i;

	dprintf(("ntfs_unmount: unmounting...\n"));
	ntmp = VFSTONTFS(mp);

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

	dprintf(("ntfs_unmount: vflushing...\n"));
	error = vflush(mp,NULLVP,flags | SKIPSYSTEM);
	if (error) {
		dprintf(("ntfs_unmount: vflush failed: %d\n",error));
		return (error);
	}

	/* Check if only system vnodes are rest */
	for(i=0;i<NTFS_SYSNODESNUM;i++)
		 if((ntmp->ntm_sysvn[i]) &&
		    (ntmp->ntm_sysvn[i]->v_usecount > 1)) return (EBUSY);

	/* Dereference all system vnodes */
	for(i=0;i<NTFS_SYSNODESNUM;i++)
		 if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]);

	/* vflush system vnodes */
	error = vflush(mp,NULLVP,flags);
	if (error) {
		panic("ntfs_unmount: vflush failed(sysnodes): %d\n",error);
	}

	/* Check if the type of device node isn't VBAD before
	 * touching v_specinfo.  If the device vnode is revoked, the
	 * field is NULL and touching it causes null pointer derefercence.
	 */
	if (ntmp->ntm_devvp->v_type != VBAD)
		spec_node_setmountedfs(ntmp->ntm_devvp, NULL);

	error = vinvalbuf(ntmp->ntm_devvp, V_SAVE, NOCRED, l, 0, 0);
	KASSERT(error == 0);

	/* lock the device vnode before calling VOP_CLOSE() */
	vn_lock(ntmp->ntm_devvp, LK_EXCLUSIVE | LK_RETRY);
	error = VOP_CLOSE(ntmp->ntm_devvp, ronly ? FREAD : FREAD|FWRITE,
		NOCRED);
	KASSERT(error == 0);
	VOP_UNLOCK(ntmp->ntm_devvp);

	vrele(ntmp->ntm_devvp);

	/* free the toupper table, if this has been last mounted ntfs volume */
	ntfs_toupper_unuse();

	dprintf(("ntfs_umount: freeing memory...\n"));
	mp->mnt_data = NULL;
	mp->mnt_flag &= ~MNT_LOCAL;
	free(ntmp->ntm_ad, M_NTFSMNT);
	free(ntmp, M_NTFSMNT);
	return (0);
}