xref: /freebsd/sys/fs/msdosfs/msdosfs_vfsops.c (revision 6be1a4cc5ff5ff079ef513e141ed00f85ba59fd4)
1c3aac50fSPeter Wemm /* $FreeBSD$ */
2952a6212SJordan K. Hubbard /*	$NetBSD: msdosfs_vfsops.c,v 1.51 1997/11/17 15:36:58 ws Exp $	*/
327a0bc89SDoug Rabson 
427a0bc89SDoug Rabson /*-
5952a6212SJordan K. Hubbard  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
6952a6212SJordan K. Hubbard  * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
727a0bc89SDoug Rabson  * All rights reserved.
827a0bc89SDoug Rabson  * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
927a0bc89SDoug Rabson  *
1027a0bc89SDoug Rabson  * Redistribution and use in source and binary forms, with or without
1127a0bc89SDoug Rabson  * modification, are permitted provided that the following conditions
1227a0bc89SDoug Rabson  * are met:
1327a0bc89SDoug Rabson  * 1. Redistributions of source code must retain the above copyright
1427a0bc89SDoug Rabson  *    notice, this list of conditions and the following disclaimer.
1527a0bc89SDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
1627a0bc89SDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
1727a0bc89SDoug Rabson  *    documentation and/or other materials provided with the distribution.
1827a0bc89SDoug Rabson  * 3. All advertising materials mentioning features or use of this software
1927a0bc89SDoug Rabson  *    must display the following acknowledgement:
2027a0bc89SDoug Rabson  *	This product includes software developed by TooLs GmbH.
2127a0bc89SDoug Rabson  * 4. The name of TooLs GmbH may not be used to endorse or promote products
2227a0bc89SDoug Rabson  *    derived from this software without specific prior written permission.
2327a0bc89SDoug Rabson  *
2427a0bc89SDoug Rabson  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
2527a0bc89SDoug Rabson  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2627a0bc89SDoug Rabson  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2727a0bc89SDoug Rabson  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2827a0bc89SDoug Rabson  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2927a0bc89SDoug Rabson  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
3027a0bc89SDoug Rabson  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
3127a0bc89SDoug Rabson  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
3227a0bc89SDoug Rabson  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
3327a0bc89SDoug Rabson  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3427a0bc89SDoug Rabson  */
35d167cf6fSWarner Losh /*-
3627a0bc89SDoug Rabson  * Written by Paul Popelka (paulp@uts.amdahl.com)
3727a0bc89SDoug Rabson  *
3827a0bc89SDoug Rabson  * You can do anything you want with this software, just don't say you wrote
3927a0bc89SDoug Rabson  * it, and don't remove this notice.
4027a0bc89SDoug Rabson  *
4127a0bc89SDoug Rabson  * This software is provided "as is".
4227a0bc89SDoug Rabson  *
4327a0bc89SDoug Rabson  * The author supplies this software to be publicly redistributed on the
4427a0bc89SDoug Rabson  * understanding that the author is not responsible for the correct
4527a0bc89SDoug Rabson  * functioning of this software in any circumstances and is not liable for
4627a0bc89SDoug Rabson  * any damages caused by this software.
4727a0bc89SDoug Rabson  *
4827a0bc89SDoug Rabson  * October 1992
4927a0bc89SDoug Rabson  */
5027a0bc89SDoug Rabson 
5127a0bc89SDoug Rabson #include <sys/param.h>
5227a0bc89SDoug Rabson #include <sys/systm.h>
536becd1c8SBruce Evans #include <sys/buf.h>
5465baf8f0SBruce Evans #include <sys/conf.h>
5557b4252eSKonstantin Belousov #include <sys/fcntl.h>
566becd1c8SBruce Evans #include <sys/iconv.h>
576becd1c8SBruce Evans #include <sys/kernel.h>
581103771dSBruce Evans #include <sys/lock.h>
596becd1c8SBruce Evans #include <sys/malloc.h>
606becd1c8SBruce Evans #include <sys/mount.h>
611103771dSBruce Evans #include <sys/mutex.h>
6227a0bc89SDoug Rabson #include <sys/namei.h>
63acd3428bSRobert Watson #include <sys/priv.h>
6427a0bc89SDoug Rabson #include <sys/proc.h>
656becd1c8SBruce Evans #include <sys/stat.h>
6627a0bc89SDoug Rabson #include <sys/vnode.h>
6727a0bc89SDoug Rabson 
689a135592SPoul-Henning Kamp #include <geom/geom.h>
699a135592SPoul-Henning Kamp #include <geom/geom_vfs.h>
709a135592SPoul-Henning Kamp 
716becd1c8SBruce Evans #include <fs/msdosfs/bootsect.h>
726becd1c8SBruce Evans #include <fs/msdosfs/bpb.h>
736becd1c8SBruce Evans #include <fs/msdosfs/direntry.h>
746becd1c8SBruce Evans #include <fs/msdosfs/denode.h>
756becd1c8SBruce Evans #include <fs/msdosfs/fat.h>
766becd1c8SBruce Evans #include <fs/msdosfs/msdosfsmount.h>
776becd1c8SBruce Evans 
7823b6c230SKonstantin Belousov static const char msdosfs_lock_msg[] = "fatlk";
7923b6c230SKonstantin Belousov 
807c3fc9deSBruce Evans /* Mount options that we support. */
816a4b48f4SPoul-Henning Kamp static const char *msdosfs_opts[] = {
82cb65c1eeSBruce Evans 	"async", "noatime", "noclusterr", "noclusterw",
837c3fc9deSBruce Evans 	"export", "force", "from", "sync",
847c3fc9deSBruce Evans 	"cs_dos", "cs_local", "cs_win", "dirmask",
857c3fc9deSBruce Evans 	"gid", "kiconv", "large", "longname",
867c3fc9deSBruce Evans 	"longnames", "mask", "shortname", "shortnames",
877c3fc9deSBruce Evans 	"uid", "win95", "nowin95",
886a4b48f4SPoul-Henning Kamp 	NULL
896a4b48f4SPoul-Henning Kamp };
906a4b48f4SPoul-Henning Kamp 
9101f6cfbaSYoshihiro Takahashi #if 1 /*def PC98*/
9201f6cfbaSYoshihiro Takahashi /*
9301f6cfbaSYoshihiro Takahashi  * XXX - The boot signature formatted by NEC PC-98 DOS looks like a
9401f6cfbaSYoshihiro Takahashi  *       garbage or a random value :-{
9501f6cfbaSYoshihiro Takahashi  *       If you want to use that broken-signatured media, define the
9601f6cfbaSYoshihiro Takahashi  *       following symbol even though PC/AT.
9701f6cfbaSYoshihiro Takahashi  *       (ex. mount PC-98 DOS formatted FD on PC/AT)
9801f6cfbaSYoshihiro Takahashi  */
9901f6cfbaSYoshihiro Takahashi #define	MSDOSFS_NOCHECKSIG
10001f6cfbaSYoshihiro Takahashi #endif
10101f6cfbaSYoshihiro Takahashi 
1025bb84bc8SRobert Watson MALLOC_DEFINE(M_MSDOSFSMNT, "msdosfs_mount", "MSDOSFS mount structure");
1035bb84bc8SRobert Watson static MALLOC_DEFINE(M_MSDOSFSFAT, "msdosfs_fat", "MSDOSFS file allocation table");
10455166637SPoul-Henning Kamp 
1052d7c6b27SBruce Evans struct iconv_functions *msdosfs_iconv;
106c4f02a89SMax Khon 
1076a4b48f4SPoul-Henning Kamp static int	update_mp(struct mount *mp, struct thread *td);
1080d7935fdSAttilio Rao static int	mountmsdosfs(struct vnode *devvp, struct mount *mp);
1091be5bc74STom Rhodes static vfs_fhtovp_t	msdosfs_fhtovp;
1106a4b48f4SPoul-Henning Kamp static vfs_mount_t	msdosfs_mount;
1119bf1a756SPoul-Henning Kamp static vfs_root_t	msdosfs_root;
1129bf1a756SPoul-Henning Kamp static vfs_statfs_t	msdosfs_statfs;
1139bf1a756SPoul-Henning Kamp static vfs_sync_t	msdosfs_sync;
1149bf1a756SPoul-Henning Kamp static vfs_unmount_t	msdosfs_unmount;
115af482601SBruce Evans 
1161a9415afSTim J. Robbins /* Maximum length of a character set name (arbitrary). */
1171a9415afSTim J. Robbins #define	MAXCSLEN	64
1181a9415afSTim J. Robbins 
119952a6212SJordan K. Hubbard static int
120dc9a617aSCraig Rodrigues update_mp(struct mount *mp, struct thread *td)
121952a6212SJordan K. Hubbard {
122952a6212SJordan K. Hubbard 	struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
1236a4b48f4SPoul-Henning Kamp 	void *dos, *win, *local;
1246a4b48f4SPoul-Henning Kamp 	int error, v;
125952a6212SJordan K. Hubbard 
1266a4b48f4SPoul-Henning Kamp 	if (!vfs_getopt(mp->mnt_optnew, "kiconv", NULL, NULL)) {
1276a4b48f4SPoul-Henning Kamp 		if (msdosfs_iconv != NULL) {
1286a4b48f4SPoul-Henning Kamp 			error = vfs_getopt(mp->mnt_optnew,
1296a4b48f4SPoul-Henning Kamp 			    "cs_win", &win, NULL);
1306a4b48f4SPoul-Henning Kamp 			if (!error)
1316a4b48f4SPoul-Henning Kamp 				error = vfs_getopt(mp->mnt_optnew,
1326a4b48f4SPoul-Henning Kamp 				    "cs_local", &local, NULL);
1336a4b48f4SPoul-Henning Kamp 			if (!error)
1346a4b48f4SPoul-Henning Kamp 				error = vfs_getopt(mp->mnt_optnew,
1356a4b48f4SPoul-Henning Kamp 				    "cs_dos", &dos, NULL);
1366a4b48f4SPoul-Henning Kamp 			if (!error) {
1371a9415afSTim J. Robbins 				msdosfs_iconv->open(win, local, &pmp->pm_u2w);
1381a9415afSTim J. Robbins 				msdosfs_iconv->open(local, win, &pmp->pm_w2u);
1391a9415afSTim J. Robbins 				msdosfs_iconv->open(dos, local, &pmp->pm_u2d);
1401a9415afSTim J. Robbins 				msdosfs_iconv->open(local, dos, &pmp->pm_d2u);
1416a4b48f4SPoul-Henning Kamp 			}
1421a9415afSTim J. Robbins 			if (error != 0)
1431a9415afSTim J. Robbins 				return (error);
144c4f02a89SMax Khon 		} else {
145c4f02a89SMax Khon 			pmp->pm_w2u = NULL;
146c4f02a89SMax Khon 			pmp->pm_u2w = NULL;
147c4f02a89SMax Khon 			pmp->pm_d2u = NULL;
148c4f02a89SMax Khon 			pmp->pm_u2d = NULL;
1497391f611SAndrey A. Chernov 		}
1501a9415afSTim J. Robbins 	}
1511a9415afSTim J. Robbins 
1526a4b48f4SPoul-Henning Kamp 	if (1 == vfs_scanopt(mp->mnt_optnew, "gid", "%d", &v))
1536a4b48f4SPoul-Henning Kamp 		pmp->pm_gid = v;
1546a4b48f4SPoul-Henning Kamp 	if (1 == vfs_scanopt(mp->mnt_optnew, "uid", "%d", &v))
1556a4b48f4SPoul-Henning Kamp 		pmp->pm_uid = v;
1566a4b48f4SPoul-Henning Kamp 	if (1 == vfs_scanopt(mp->mnt_optnew, "mask", "%d", &v))
1576a4b48f4SPoul-Henning Kamp 		pmp->pm_mask = v & ALLPERMS;
1586a4b48f4SPoul-Henning Kamp 	if (1 == vfs_scanopt(mp->mnt_optnew, "dirmask", "%d", &v))
1596a4b48f4SPoul-Henning Kamp 		pmp->pm_dirmask = v & ALLPERMS;
1606a4b48f4SPoul-Henning Kamp 	vfs_flagopt(mp->mnt_optnew, "shortname",
1616a4b48f4SPoul-Henning Kamp 	    &pmp->pm_flags, MSDOSFSMNT_SHORTNAME);
1624ab12573SCraig Rodrigues 	vfs_flagopt(mp->mnt_optnew, "shortnames",
1634ab12573SCraig Rodrigues 	    &pmp->pm_flags, MSDOSFSMNT_SHORTNAME);
1646a4b48f4SPoul-Henning Kamp 	vfs_flagopt(mp->mnt_optnew, "longname",
1656a4b48f4SPoul-Henning Kamp 	    &pmp->pm_flags, MSDOSFSMNT_LONGNAME);
1664ab12573SCraig Rodrigues 	vfs_flagopt(mp->mnt_optnew, "longnames",
1674ab12573SCraig Rodrigues 	    &pmp->pm_flags, MSDOSFSMNT_LONGNAME);
1686a4b48f4SPoul-Henning Kamp 	vfs_flagopt(mp->mnt_optnew, "kiconv",
1696a4b48f4SPoul-Henning Kamp 	    &pmp->pm_flags, MSDOSFSMNT_KICONV);
1706a4b48f4SPoul-Henning Kamp 
171d75b2048SCraig Rodrigues 	if (vfs_getopt(mp->mnt_optnew, "nowin95", NULL, NULL) == 0)
1726a4b48f4SPoul-Henning Kamp 		pmp->pm_flags |= MSDOSFSMNT_NOWIN95;
173d75b2048SCraig Rodrigues 	else
174d75b2048SCraig Rodrigues 		pmp->pm_flags &= ~MSDOSFSMNT_NOWIN95;
175952a6212SJordan K. Hubbard 
176952a6212SJordan K. Hubbard 	if (pmp->pm_flags & MSDOSFSMNT_NOWIN95)
177952a6212SJordan K. Hubbard 		pmp->pm_flags |= MSDOSFSMNT_SHORTNAME;
178952a6212SJordan K. Hubbard 	else if (!(pmp->pm_flags &
179952a6212SJordan K. Hubbard 	    (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) {
180952a6212SJordan K. Hubbard 		struct vnode *rootvp;
181952a6212SJordan K. Hubbard 
182952a6212SJordan K. Hubbard 		/*
183952a6212SJordan K. Hubbard 		 * Try to divine whether to support Win'95 long filenames
184952a6212SJordan K. Hubbard 		 */
185952a6212SJordan K. Hubbard 		if (FAT32(pmp))
186952a6212SJordan K. Hubbard 			pmp->pm_flags |= MSDOSFSMNT_LONGNAME;
187952a6212SJordan K. Hubbard 		else {
188d9b2d9f7SJeff Roberson 			if ((error =
189dfd233edSAttilio Rao 			    msdosfs_root(mp, LK_EXCLUSIVE, &rootvp)) != 0)
190952a6212SJordan K. Hubbard 				return error;
1912d7c6b27SBruce Evans 			pmp->pm_flags |= findwin95(VTODE(rootvp)) ?
1922d7c6b27SBruce Evans 			    MSDOSFSMNT_LONGNAME : MSDOSFSMNT_SHORTNAME;
193952a6212SJordan K. Hubbard 			vput(rootvp);
194952a6212SJordan K. Hubbard 		}
195952a6212SJordan K. Hubbard 	}
196952a6212SJordan K. Hubbard 	return 0;
197952a6212SJordan K. Hubbard }
198952a6212SJordan K. Hubbard 
1996a4b48f4SPoul-Henning Kamp static int
200dfd233edSAttilio Rao msdosfs_cmount(struct mntarg *ma, void *data, int flags)
2016a4b48f4SPoul-Henning Kamp {
2026a4b48f4SPoul-Henning Kamp 	struct msdosfs_args args;
2036a4b48f4SPoul-Henning Kamp 	int error;
2046a4b48f4SPoul-Henning Kamp 
2056a4b48f4SPoul-Henning Kamp 	if (data == NULL)
2066a4b48f4SPoul-Henning Kamp 		return (EINVAL);
2076a4b48f4SPoul-Henning Kamp 	error = copyin(data, &args, sizeof args);
2086a4b48f4SPoul-Henning Kamp 	if (error)
2096a4b48f4SPoul-Henning Kamp 		return (error);
2106a4b48f4SPoul-Henning Kamp 
2116a4b48f4SPoul-Henning Kamp 	ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN);
2126a4b48f4SPoul-Henning Kamp 	ma = mount_arg(ma, "export", &args.export, sizeof args.export);
2136a4b48f4SPoul-Henning Kamp 	ma = mount_argf(ma, "uid", "%d", args.uid);
2146a4b48f4SPoul-Henning Kamp 	ma = mount_argf(ma, "gid", "%d", args.gid);
2156a4b48f4SPoul-Henning Kamp 	ma = mount_argf(ma, "mask", "%d", args.mask);
2166a4b48f4SPoul-Henning Kamp 	ma = mount_argf(ma, "dirmask", "%d", args.dirmask);
2176a4b48f4SPoul-Henning Kamp 
2186a4b48f4SPoul-Henning Kamp 	ma = mount_argb(ma, args.flags & MSDOSFSMNT_SHORTNAME, "noshortname");
2196a4b48f4SPoul-Henning Kamp 	ma = mount_argb(ma, args.flags & MSDOSFSMNT_LONGNAME, "nolongname");
2206a4b48f4SPoul-Henning Kamp 	ma = mount_argb(ma, !(args.flags & MSDOSFSMNT_NOWIN95), "nowin95");
2216a4b48f4SPoul-Henning Kamp 	ma = mount_argb(ma, args.flags & MSDOSFSMNT_KICONV, "nokiconv");
2226a4b48f4SPoul-Henning Kamp 
2236a4b48f4SPoul-Henning Kamp 	ma = mount_argsu(ma, "cs_win", args.cs_win, MAXCSLEN);
2246a4b48f4SPoul-Henning Kamp 	ma = mount_argsu(ma, "cs_dos", args.cs_dos, MAXCSLEN);
2256a4b48f4SPoul-Henning Kamp 	ma = mount_argsu(ma, "cs_local", args.cs_local, MAXCSLEN);
2266a4b48f4SPoul-Henning Kamp 
2276a4b48f4SPoul-Henning Kamp 	error = kernel_mount(ma, flags);
2286a4b48f4SPoul-Henning Kamp 
2296a4b48f4SPoul-Henning Kamp 	return (error);
2306a4b48f4SPoul-Henning Kamp }
2316a4b48f4SPoul-Henning Kamp 
23227a0bc89SDoug Rabson /*
23327a0bc89SDoug Rabson  * mp - path - addr in user space of mount point (ie /usr or whatever)
23427a0bc89SDoug Rabson  * data - addr in user space of mount params including the name of the block
23527a0bc89SDoug Rabson  * special file to treat as a filesystem.
23627a0bc89SDoug Rabson  */
2377fefffeeSPoul-Henning Kamp static int
238dfd233edSAttilio Rao msdosfs_mount(struct mount *mp)
23927a0bc89SDoug Rabson {
24027a0bc89SDoug Rabson 	struct vnode *devvp;	  /* vnode for blk device to mount */
241dfd233edSAttilio Rao 	struct thread *td;
242952a6212SJordan K. Hubbard 	/* msdosfs specific mount control block */
243952a6212SJordan K. Hubbard 	struct msdosfsmount *pmp = NULL;
2445e8c582aSPoul-Henning Kamp 	struct nameidata ndp;
245269c902fSPoul-Henning Kamp 	int error, flags;
24615bc6b2bSEdward Tomasz Napierala 	accmode_t accmode;
2476a4b48f4SPoul-Henning Kamp 	char *from;
24827a0bc89SDoug Rabson 
249dfd233edSAttilio Rao 	td = curthread;
2506a4b48f4SPoul-Henning Kamp 	if (vfs_filteropt(mp->mnt_optnew, msdosfs_opts))
2516a4b48f4SPoul-Henning Kamp 		return (EINVAL);
2526a4b48f4SPoul-Henning Kamp 
25327a0bc89SDoug Rabson 	/*
254952a6212SJordan K. Hubbard 	 * If updating, check whether changing from read-only to
255952a6212SJordan K. Hubbard 	 * read/write; if there is no device name, that's all we do.
25627a0bc89SDoug Rabson 	 */
25727a0bc89SDoug Rabson 	if (mp->mnt_flag & MNT_UPDATE) {
2582d7c6b27SBruce Evans 		pmp = VFSTOMSDOSFS(mp);
2595eb304a9SCraig Rodrigues 		if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) {
260e9022ef8SCraig Rodrigues 			/*
261e9022ef8SCraig Rodrigues 			 * Forbid export requests if filesystem has
262e9022ef8SCraig Rodrigues 			 * MSDOSFS_LARGEFS flag set.
263e9022ef8SCraig Rodrigues 			 */
264e9022ef8SCraig Rodrigues 			if ((pmp->pm_flags & MSDOSFS_LARGEFS) != 0) {
265e9022ef8SCraig Rodrigues 				vfs_mount_error(mp,
266e9022ef8SCraig Rodrigues 				    "MSDOSFS_LARGEFS flag set, cannot export");
267269c902fSPoul-Henning Kamp 				return (EOPNOTSUPP);
268e9022ef8SCraig Rodrigues 			}
269269c902fSPoul-Henning Kamp 		}
2709a135592SPoul-Henning Kamp 		if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) &&
2716a4b48f4SPoul-Henning Kamp 		    vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) {
272dfd233edSAttilio Rao 			error = VFS_SYNC(mp, MNT_WAIT);
273e83f1423SPoul-Henning Kamp 			if (error)
274e83f1423SPoul-Henning Kamp 				return (error);
27527a0bc89SDoug Rabson 			flags = WRITECLOSE;
27627a0bc89SDoug Rabson 			if (mp->mnt_flag & MNT_FORCE)
27727a0bc89SDoug Rabson 				flags |= FORCECLOSE;
278f257b7a5SAlfred Perlstein 			error = vflush(mp, 0, flags, td);
2796a4b48f4SPoul-Henning Kamp 			if (error)
2806a4b48f4SPoul-Henning Kamp 				return (error);
2813247c9ddSXin LI 
2823247c9ddSXin LI 			/*
2833247c9ddSXin LI 			 * Now the volume is clean.  Mark it so while the
2843247c9ddSXin LI 			 * device is still rw.
2853247c9ddSXin LI 			 */
2863247c9ddSXin LI 			error = markvoldirty(pmp, 0);
2873247c9ddSXin LI 			if (error) {
2883247c9ddSXin LI 				(void)markvoldirty(pmp, 1);
2893247c9ddSXin LI 				return (error);
2903247c9ddSXin LI 			}
2913247c9ddSXin LI 
2923247c9ddSXin LI 			/* Downgrade the device from rw to ro. */
2939a135592SPoul-Henning Kamp 			DROP_GIANT();
2949a135592SPoul-Henning Kamp 			g_topology_lock();
2954eb3abf0SBruce Evans 			error = g_access(pmp->pm_cp, 0, -1, 0);
2969a135592SPoul-Henning Kamp 			g_topology_unlock();
2979a135592SPoul-Henning Kamp 			PICKUP_GIANT();
2983247c9ddSXin LI 			if (error) {
2993247c9ddSXin LI 				(void)markvoldirty(pmp, 1);
3004eb3abf0SBruce Evans 				return (error);
3013247c9ddSXin LI 			}
3024eb3abf0SBruce Evans 
3033247c9ddSXin LI 			/*
3043247c9ddSXin LI 			 * Backing out after an error was painful in the
3053247c9ddSXin LI 			 * above.  Now we are committed to succeeding.
3063247c9ddSXin LI 			 */
3073247c9ddSXin LI 			pmp->pm_fmod = 0;
3083247c9ddSXin LI 			pmp->pm_flags |= MSDOSFSMNT_RONLY;
3093247c9ddSXin LI 			MNT_ILOCK(mp);
3103247c9ddSXin LI 			mp->mnt_flag |= MNT_RDONLY;
3113247c9ddSXin LI 			MNT_IUNLOCK(mp);
3126a4b48f4SPoul-Henning Kamp 		} else if ((pmp->pm_flags & MSDOSFSMNT_RONLY) &&
3136a4b48f4SPoul-Henning Kamp 		    !vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) {
314952a6212SJordan K. Hubbard 			/*
315952a6212SJordan K. Hubbard 			 * If upgrade to read-write by non-root, then verify
316952a6212SJordan K. Hubbard 			 * that user has necessary permissions on the device.
317952a6212SJordan K. Hubbard 			 */
318952a6212SJordan K. Hubbard 			devvp = pmp->pm_devvp;
319cb05b60aSAttilio Rao 			vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
320952a6212SJordan K. Hubbard 			error = VOP_ACCESS(devvp, VREAD | VWRITE,
321a854ed98SJohn Baldwin 			    td->td_ucred, td);
322acd3428bSRobert Watson 			if (error)
323acd3428bSRobert Watson 				error = priv_check(td, PRIV_VFS_MOUNT_PERM);
324952a6212SJordan K. Hubbard 			if (error) {
32522db15c0SAttilio Rao 				VOP_UNLOCK(devvp, 0);
326952a6212SJordan K. Hubbard 				return (error);
327952a6212SJordan K. Hubbard 			}
32822db15c0SAttilio Rao 			VOP_UNLOCK(devvp, 0);
3299a135592SPoul-Henning Kamp 			DROP_GIANT();
3309a135592SPoul-Henning Kamp 			g_topology_lock();
3319a135592SPoul-Henning Kamp 			error = g_access(pmp->pm_cp, 0, 1, 0);
3329a135592SPoul-Henning Kamp 			g_topology_unlock();
3339a135592SPoul-Henning Kamp 			PICKUP_GIANT();
3349a135592SPoul-Henning Kamp 			if (error)
3359a135592SPoul-Henning Kamp 				return (error);
336cede1f56STom Rhodes 
3373247c9ddSXin LI 			pmp->pm_fmod = 1;
3383247c9ddSXin LI 			pmp->pm_flags &= ~MSDOSFSMNT_RONLY;
3393247c9ddSXin LI 			MNT_ILOCK(mp);
3403247c9ddSXin LI 			mp->mnt_flag &= ~MNT_RDONLY;
3413247c9ddSXin LI 			MNT_IUNLOCK(mp);
34282c59ec6SCraig Rodrigues 
34382c59ec6SCraig Rodrigues 			/* Now that the volume is modifiable, mark it dirty. */
34482c59ec6SCraig Rodrigues 			error = markvoldirty(pmp, 1);
34582c59ec6SCraig Rodrigues 			if (error)
34682c59ec6SCraig Rodrigues 				return (error);
34782c59ec6SCraig Rodrigues 		}
348952a6212SJordan K. Hubbard 	}
34927a0bc89SDoug Rabson 	/*
350952a6212SJordan K. Hubbard 	 * Not an update, or updating the name: look up the name
351e9827c6dSBruce Evans 	 * and verify that it refers to a sensible disk device.
35227a0bc89SDoug Rabson 	 */
3536a4b48f4SPoul-Henning Kamp 	if (vfs_getopt(mp->mnt_optnew, "from", (void **)&from, NULL))
3546a4b48f4SPoul-Henning Kamp 		return (EINVAL);
35575d7ba93SSuleiman Souhlal 	NDINIT(&ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, from, td);
3565e8c582aSPoul-Henning Kamp 	error = namei(&ndp);
357952a6212SJordan K. Hubbard 	if (error)
358952a6212SJordan K. Hubbard 		return (error);
3595e8c582aSPoul-Henning Kamp 	devvp = ndp.ni_vp;
3605e8c582aSPoul-Henning Kamp 	NDFREE(&ndp, NDF_ONLY_PNBUF);
361952a6212SJordan K. Hubbard 
362ba4ad1fcSPoul-Henning Kamp 	if (!vn_isdisk(devvp, &error)) {
36375d7ba93SSuleiman Souhlal 		vput(devvp);
364ba4ad1fcSPoul-Henning Kamp 		return (error);
36527a0bc89SDoug Rabson 	}
36627a0bc89SDoug Rabson 	/*
367952a6212SJordan K. Hubbard 	 * If mount by non-root, then verify that user has necessary
368952a6212SJordan K. Hubbard 	 * permissions on the device.
36927a0bc89SDoug Rabson 	 */
37015bc6b2bSEdward Tomasz Napierala 	accmode = VREAD;
371952a6212SJordan K. Hubbard 	if ((mp->mnt_flag & MNT_RDONLY) == 0)
37215bc6b2bSEdward Tomasz Napierala 		accmode |= VWRITE;
37315bc6b2bSEdward Tomasz Napierala 	error = VOP_ACCESS(devvp, accmode, td->td_ucred, td);
374acd3428bSRobert Watson 	if (error)
375acd3428bSRobert Watson 		error = priv_check(td, PRIV_VFS_MOUNT_PERM);
376952a6212SJordan K. Hubbard 	if (error) {
377952a6212SJordan K. Hubbard 		vput(devvp);
378952a6212SJordan K. Hubbard 		return (error);
379952a6212SJordan K. Hubbard 	}
380952a6212SJordan K. Hubbard 	if ((mp->mnt_flag & MNT_UPDATE) == 0) {
3810d7935fdSAttilio Rao 		error = mountmsdosfs(devvp, mp);
382952a6212SJordan K. Hubbard #ifdef MSDOSFS_DEBUG		/* only needed for the printf below */
383952a6212SJordan K. Hubbard 		pmp = VFSTOMSDOSFS(mp);
384952a6212SJordan K. Hubbard #endif
385952a6212SJordan K. Hubbard 	} else {
38627a0bc89SDoug Rabson 		if (devvp != pmp->pm_devvp)
387952a6212SJordan K. Hubbard 			error = EINVAL;	/* XXX needs translation */
38827a0bc89SDoug Rabson 		else
38975d7ba93SSuleiman Souhlal 			vput(devvp);
39027a0bc89SDoug Rabson 	}
39127a0bc89SDoug Rabson 	if (error) {
39227a0bc89SDoug Rabson 		vrele(devvp);
393952a6212SJordan K. Hubbard 		return (error);
394952a6212SJordan K. Hubbard 	}
395952a6212SJordan K. Hubbard 
3966a4b48f4SPoul-Henning Kamp 	error = update_mp(mp, td);
397952a6212SJordan K. Hubbard 	if (error) {
3981a9415afSTim J. Robbins 		if ((mp->mnt_flag & MNT_UPDATE) == 0)
399dfd233edSAttilio Rao 			msdosfs_unmount(mp, MNT_FORCE);
40027a0bc89SDoug Rabson 		return error;
40127a0bc89SDoug Rabson 	}
4026a4b48f4SPoul-Henning Kamp 
4036a4b48f4SPoul-Henning Kamp 	vfs_mountedfrom(mp, from);
40427a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG
4056a4b48f4SPoul-Henning Kamp 	printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap);
40627a0bc89SDoug Rabson #endif
407952a6212SJordan K. Hubbard 	return (0);
40827a0bc89SDoug Rabson }
40927a0bc89SDoug Rabson 
4107fefffeeSPoul-Henning Kamp static int
4110d7935fdSAttilio Rao mountmsdosfs(struct vnode *devvp, struct mount *mp)
41227a0bc89SDoug Rabson {
413952a6212SJordan K. Hubbard 	struct msdosfsmount *pmp;
414952a6212SJordan K. Hubbard 	struct buf *bp;
415c72ae142SJohn Baldwin 	struct cdev *dev;
41627a0bc89SDoug Rabson 	union bootsector *bsp;
41727a0bc89SDoug Rabson 	struct byte_bpb33 *b33;
41827a0bc89SDoug Rabson 	struct byte_bpb50 *b50;
419952a6212SJordan K. Hubbard 	struct byte_bpb710 *b710;
420952a6212SJordan K. Hubbard 	u_int8_t SecPerClust;
421499d3ffaSBoris Popov 	u_long clusters;
422952a6212SJordan K. Hubbard 	int ronly, error;
4239a135592SPoul-Henning Kamp 	struct g_consumer *cp;
4249a135592SPoul-Henning Kamp 	struct bufobj *bo;
42527a0bc89SDoug Rabson 
426c72ae142SJohn Baldwin 	bp = NULL;		/* This and pmp both used in error_exit. */
427c72ae142SJohn Baldwin 	pmp = NULL;
4284eb3abf0SBruce Evans 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
429c72ae142SJohn Baldwin 
430c72ae142SJohn Baldwin 	dev = devvp->v_rdev;
431c72ae142SJohn Baldwin 	dev_ref(dev);
4329a135592SPoul-Henning Kamp 	DROP_GIANT();
4339a135592SPoul-Henning Kamp 	g_topology_lock();
4344eb3abf0SBruce Evans 	error = g_vfs_open(devvp, &cp, "msdosfs", ronly ? 0 : 1);
4359a135592SPoul-Henning Kamp 	g_topology_unlock();
4369a135592SPoul-Henning Kamp 	PICKUP_GIANT();
43722db15c0SAttilio Rao 	VOP_UNLOCK(devvp, 0);
438c3c6d51eSPoul-Henning Kamp 	if (error)
439c72ae142SJohn Baldwin 		goto error_exit;
440952a6212SJordan K. Hubbard 
4419a135592SPoul-Henning Kamp 	bo = &devvp->v_bufobj;
442952a6212SJordan K. Hubbard 
44327a0bc89SDoug Rabson 	/*
444952a6212SJordan K. Hubbard 	 * Read the boot sector of the filesystem, and then check the
445952a6212SJordan K. Hubbard 	 * boot signature.  If not a dos boot sector then error out.
44601f6cfbaSYoshihiro Takahashi 	 *
44793fe42b6SBruce Evans 	 * NOTE: 8192 is a magic size that works for ffs.
44827a0bc89SDoug Rabson 	 */
44993fe42b6SBruce Evans 	error = bread(devvp, 0, 8192, NOCRED, &bp);
450c3c6d51eSPoul-Henning Kamp 	if (error)
45127a0bc89SDoug Rabson 		goto error_exit;
452952a6212SJordan K. Hubbard 	bp->b_flags |= B_AGE;
453952a6212SJordan K. Hubbard 	bsp = (union bootsector *)bp->b_data;
45427a0bc89SDoug Rabson 	b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB;
45527a0bc89SDoug Rabson 	b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB;
45601a4d019SJohn Baldwin 	b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB;
457952a6212SJordan K. Hubbard 
45801f6cfbaSYoshihiro Takahashi #ifndef MSDOSFS_NOCHECKSIG
459952a6212SJordan K. Hubbard 	if (bsp->bs50.bsBootSectSig0 != BOOTSIG0
460952a6212SJordan K. Hubbard 	    || bsp->bs50.bsBootSectSig1 != BOOTSIG1) {
46127a0bc89SDoug Rabson 		error = EINVAL;
46227a0bc89SDoug Rabson 		goto error_exit;
46327a0bc89SDoug Rabson 	}
46401f6cfbaSYoshihiro Takahashi #endif
46527a0bc89SDoug Rabson 
466a163d034SWarner Losh 	pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK | M_ZERO);
46727a0bc89SDoug Rabson 	pmp->pm_mountp = mp;
4689a135592SPoul-Henning Kamp 	pmp->pm_cp = cp;
4699a135592SPoul-Henning Kamp 	pmp->pm_bo = bo;
47027a0bc89SDoug Rabson 
47123b6c230SKonstantin Belousov 	lockinit(&pmp->pm_fatlock, 0, msdosfs_lock_msg, 0, 0);
47223b6c230SKonstantin Belousov 
47327a0bc89SDoug Rabson 	/*
4744eb3abf0SBruce Evans 	 * Initialize ownerships and permissions, since nothing else will
47523c1e989SMaxim Konovalov 	 * initialize them iff we are mounting root.
4764eb3abf0SBruce Evans 	 */
4774eb3abf0SBruce Evans 	pmp->pm_uid = UID_ROOT;
4784eb3abf0SBruce Evans 	pmp->pm_gid = GID_WHEEL;
4794eb3abf0SBruce Evans 	pmp->pm_mask = pmp->pm_dirmask = S_IXUSR | S_IXGRP | S_IXOTH |
4804eb3abf0SBruce Evans 	    S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR;
4814eb3abf0SBruce Evans 
4824eb3abf0SBruce Evans 	/*
483f458f2a5SCraig Rodrigues 	 * Experimental support for large MS-DOS filesystems.
484f458f2a5SCraig Rodrigues 	 * WARNING: This uses at least 32 bytes of kernel memory (which is not
485f458f2a5SCraig Rodrigues 	 * reclaimed until the FS is unmounted) for each file on disk to map
486f458f2a5SCraig Rodrigues 	 * between the 32-bit inode numbers used by VFS and the 64-bit
487f458f2a5SCraig Rodrigues 	 * pseudo-inode numbers used internally by msdosfs. This is only
488f458f2a5SCraig Rodrigues 	 * safe to use in certain controlled situations (e.g. read-only FS
489f458f2a5SCraig Rodrigues 	 * with less than 1 million files).
490f458f2a5SCraig Rodrigues 	 * Since the mappings do not persist across unmounts (or reboots), these
491f458f2a5SCraig Rodrigues 	 * filesystems are not suitable for exporting through NFS, or any other
492f458f2a5SCraig Rodrigues 	 * application that requires fixed inode numbers.
493f458f2a5SCraig Rodrigues 	 */
4942d7c6b27SBruce Evans 	vfs_flagopt(mp->mnt_optnew, "large", &pmp->pm_flags, MSDOSFS_LARGEFS);
495f458f2a5SCraig Rodrigues 
496f458f2a5SCraig Rodrigues 	/*
49727a0bc89SDoug Rabson 	 * Compute several useful quantities from the bpb in the
49827a0bc89SDoug Rabson 	 * bootsector.  Copy in the dos 5 variant of the bpb then fix up
49927a0bc89SDoug Rabson 	 * the fields that are different between dos 5 and dos 3.3.
50027a0bc89SDoug Rabson 	 */
501952a6212SJordan K. Hubbard 	SecPerClust = b50->bpbSecPerClust;
50227a0bc89SDoug Rabson 	pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
503696f22f0SJohn Baldwin 	if (pmp->pm_BytesPerSec < DEV_BSIZE) {
504696f22f0SJohn Baldwin 		error = EINVAL;
505696f22f0SJohn Baldwin 		goto error_exit;
506696f22f0SJohn Baldwin 	}
50727a0bc89SDoug Rabson 	pmp->pm_ResSectors = getushort(b50->bpbResSectors);
50827a0bc89SDoug Rabson 	pmp->pm_FATs = b50->bpbFATs;
50927a0bc89SDoug Rabson 	pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
51027a0bc89SDoug Rabson 	pmp->pm_Sectors = getushort(b50->bpbSectors);
51127a0bc89SDoug Rabson 	pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
51227a0bc89SDoug Rabson 	pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
51327a0bc89SDoug Rabson 	pmp->pm_Heads = getushort(b50->bpbHeads);
514952a6212SJordan K. Hubbard 	pmp->pm_Media = b50->bpbMedia;
51527a0bc89SDoug Rabson 
51601f6cfbaSYoshihiro Takahashi 	/* calculate the ratio of sector size to DEV_BSIZE */
51701f6cfbaSYoshihiro Takahashi 	pmp->pm_BlkPerSec = pmp->pm_BytesPerSec / DEV_BSIZE;
51801f6cfbaSYoshihiro Takahashi 
519043ec583SMarcel Moolenaar 	/*
520043ec583SMarcel Moolenaar 	 * We don't check pm_Heads nor pm_SecPerTrack, because
521043ec583SMarcel Moolenaar 	 * these may not be set for EFI file systems. We don't
522043ec583SMarcel Moolenaar 	 * use these anyway, so we're unaffected if they are
523043ec583SMarcel Moolenaar 	 * invalid.
524043ec583SMarcel Moolenaar 	 */
525043ec583SMarcel Moolenaar 	if (!pmp->pm_BytesPerSec || !SecPerClust) {
52627a0bc89SDoug Rabson 		error = EINVAL;
52727a0bc89SDoug Rabson 		goto error_exit;
52827a0bc89SDoug Rabson 	}
52927a0bc89SDoug Rabson 
53027a0bc89SDoug Rabson 	if (pmp->pm_Sectors == 0) {
53127a0bc89SDoug Rabson 		pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
53227a0bc89SDoug Rabson 		pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
53327a0bc89SDoug Rabson 	} else {
53427a0bc89SDoug Rabson 		pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
53527a0bc89SDoug Rabson 		pmp->pm_HugeSectors = pmp->pm_Sectors;
53627a0bc89SDoug Rabson 	}
537f458f2a5SCraig Rodrigues 	if (!(pmp->pm_flags & MSDOSFS_LARGEFS)) {
538c681be37SDmitrij Tejblum 		if (pmp->pm_HugeSectors > 0xffffffff /
539c681be37SDmitrij Tejblum 		    (pmp->pm_BytesPerSec / sizeof(struct direntry)) + 1) {
540952a6212SJordan K. Hubbard 			/*
541952a6212SJordan K. Hubbard 			 * We cannot deal currently with this size of disk
542952a6212SJordan K. Hubbard 			 * due to fileid limitations (see msdosfs_getattr and
543952a6212SJordan K. Hubbard 			 * msdosfs_readdir)
544952a6212SJordan K. Hubbard 			 */
545952a6212SJordan K. Hubbard 			error = EINVAL;
546f458f2a5SCraig Rodrigues 			vfs_mount_error(mp,
547f458f2a5SCraig Rodrigues 			    "Disk too big, try '-o large' mount option");
548952a6212SJordan K. Hubbard 			goto error_exit;
549952a6212SJordan K. Hubbard 		}
550f458f2a5SCraig Rodrigues 	}
551952a6212SJordan K. Hubbard 
552952a6212SJordan K. Hubbard 	if (pmp->pm_RootDirEnts == 0) {
55320c5ba36SPeter Edwards 		if (pmp->pm_Sectors
554952a6212SJordan K. Hubbard 		    || pmp->pm_FATsecs
555952a6212SJordan K. Hubbard 		    || getushort(b710->bpbFSVers)) {
556952a6212SJordan K. Hubbard 			error = EINVAL;
557aaf0bb19SAndrey A. Chernov 			printf("mountmsdosfs(): bad FAT32 filesystem\n");
558952a6212SJordan K. Hubbard 			goto error_exit;
559952a6212SJordan K. Hubbard 		}
560952a6212SJordan K. Hubbard 		pmp->pm_fatmask = FAT32_MASK;
561952a6212SJordan K. Hubbard 		pmp->pm_fatmult = 4;
562952a6212SJordan K. Hubbard 		pmp->pm_fatdiv = 1;
563952a6212SJordan K. Hubbard 		pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs);
564952a6212SJordan K. Hubbard 		if (getushort(b710->bpbExtFlags) & FATMIRROR)
565952a6212SJordan K. Hubbard 			pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM;
566952a6212SJordan K. Hubbard 		else
567952a6212SJordan K. Hubbard 			pmp->pm_flags |= MSDOSFS_FATMIRROR;
568952a6212SJordan K. Hubbard 	} else
569952a6212SJordan K. Hubbard 		pmp->pm_flags |= MSDOSFS_FATMIRROR;
570952a6212SJordan K. Hubbard 
571952a6212SJordan K. Hubbard 	/*
572952a6212SJordan K. Hubbard 	 * Check a few values (could do some more):
573952a6212SJordan K. Hubbard 	 * - logical sector size: power of 2, >= block size
574952a6212SJordan K. Hubbard 	 * - sectors per cluster: power of 2, >= 1
575952a6212SJordan K. Hubbard 	 * - number of sectors:   >= 1, <= size of partition
576696f22f0SJohn Baldwin 	 * - number of FAT sectors: >= 1
577952a6212SJordan K. Hubbard 	 */
578952a6212SJordan K. Hubbard 	if ( (SecPerClust == 0)
579952a6212SJordan K. Hubbard 	  || (SecPerClust & (SecPerClust - 1))
58001f6cfbaSYoshihiro Takahashi 	  || (pmp->pm_BytesPerSec < DEV_BSIZE)
581952a6212SJordan K. Hubbard 	  || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1))
582952a6212SJordan K. Hubbard 	  || (pmp->pm_HugeSectors == 0)
583696f22f0SJohn Baldwin 	  || (pmp->pm_FATsecs == 0)
584952a6212SJordan K. Hubbard 	) {
585952a6212SJordan K. Hubbard 		error = EINVAL;
586952a6212SJordan K. Hubbard 		goto error_exit;
587952a6212SJordan K. Hubbard 	}
58801f6cfbaSYoshihiro Takahashi 
58901f6cfbaSYoshihiro Takahashi 	pmp->pm_HugeSectors *= pmp->pm_BlkPerSec;
59001f6cfbaSYoshihiro Takahashi 	pmp->pm_HiddenSects *= pmp->pm_BlkPerSec;	/* XXX not used? */
59101f6cfbaSYoshihiro Takahashi 	pmp->pm_FATsecs     *= pmp->pm_BlkPerSec;
59201f6cfbaSYoshihiro Takahashi 	SecPerClust         *= pmp->pm_BlkPerSec;
59301f6cfbaSYoshihiro Takahashi 
59401f6cfbaSYoshihiro Takahashi 	pmp->pm_fatblk = pmp->pm_ResSectors * pmp->pm_BlkPerSec;
59501f6cfbaSYoshihiro Takahashi 
596952a6212SJordan K. Hubbard 	if (FAT32(pmp)) {
597952a6212SJordan K. Hubbard 		pmp->pm_rootdirblk = getulong(b710->bpbRootClust);
598952a6212SJordan K. Hubbard 		pmp->pm_firstcluster = pmp->pm_fatblk
599952a6212SJordan K. Hubbard 			+ (pmp->pm_FATs * pmp->pm_FATsecs);
60001f6cfbaSYoshihiro Takahashi 		pmp->pm_fsinfo = getushort(b710->bpbFSInfo) * pmp->pm_BlkPerSec;
601952a6212SJordan K. Hubbard 	} else {
60227a0bc89SDoug Rabson 		pmp->pm_rootdirblk = pmp->pm_fatblk +
60327a0bc89SDoug Rabson 			(pmp->pm_FATs * pmp->pm_FATsecs);
604952a6212SJordan K. Hubbard 		pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)
60501f6cfbaSYoshihiro Takahashi 				       + DEV_BSIZE - 1)
60601f6cfbaSYoshihiro Takahashi 			/ DEV_BSIZE; /* in blocks */
60727a0bc89SDoug Rabson 		pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
608952a6212SJordan K. Hubbard 	}
609952a6212SJordan K. Hubbard 
610499d3ffaSBoris Popov 	pmp->pm_maxcluster = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
611499d3ffaSBoris Popov 	    SecPerClust + 1;
61201f6cfbaSYoshihiro Takahashi 	pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE;	/* XXX not used? */
613952a6212SJordan K. Hubbard 
614952a6212SJordan K. Hubbard 	if (pmp->pm_fatmask == 0) {
615952a6212SJordan K. Hubbard 		if (pmp->pm_maxcluster
616952a6212SJordan K. Hubbard 		    <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) {
61727a0bc89SDoug Rabson 			/*
618952a6212SJordan K. Hubbard 			 * This will usually be a floppy disk. This size makes
619952a6212SJordan K. Hubbard 			 * sure that one fat entry will not be split across
620952a6212SJordan K. Hubbard 			 * multiple blocks.
62127a0bc89SDoug Rabson 			 */
622952a6212SJordan K. Hubbard 			pmp->pm_fatmask = FAT12_MASK;
623952a6212SJordan K. Hubbard 			pmp->pm_fatmult = 3;
624952a6212SJordan K. Hubbard 			pmp->pm_fatdiv = 2;
625952a6212SJordan K. Hubbard 		} else {
626952a6212SJordan K. Hubbard 			pmp->pm_fatmask = FAT16_MASK;
627952a6212SJordan K. Hubbard 			pmp->pm_fatmult = 2;
628952a6212SJordan K. Hubbard 			pmp->pm_fatdiv = 1;
629952a6212SJordan K. Hubbard 		}
630952a6212SJordan K. Hubbard 	}
631499d3ffaSBoris Popov 
632499d3ffaSBoris Popov 	clusters = (pmp->pm_fatsize / pmp->pm_fatmult) * pmp->pm_fatdiv;
633499d3ffaSBoris Popov 	if (pmp->pm_maxcluster >= clusters) {
634499d3ffaSBoris Popov 		printf("Warning: number of clusters (%ld) exceeds FAT "
635499d3ffaSBoris Popov 		    "capacity (%ld)\n", pmp->pm_maxcluster + 1, clusters);
636499d3ffaSBoris Popov 		pmp->pm_maxcluster = clusters - 1;
637499d3ffaSBoris Popov 	}
638499d3ffaSBoris Popov 
639952a6212SJordan K. Hubbard 	if (FAT12(pmp))
64093fe42b6SBruce Evans 		pmp->pm_fatblocksize = 3 * 512;
64127a0bc89SDoug Rabson 	else
64293fe42b6SBruce Evans 		pmp->pm_fatblocksize = PAGE_SIZE;
64393fe42b6SBruce Evans 	pmp->pm_fatblocksize = roundup(pmp->pm_fatblocksize,
64493fe42b6SBruce Evans 	    pmp->pm_BytesPerSec);
64501f6cfbaSYoshihiro Takahashi 	pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE;
64601f6cfbaSYoshihiro Takahashi 	pmp->pm_bnshift = ffs(DEV_BSIZE) - 1;
64727a0bc89SDoug Rabson 
64827a0bc89SDoug Rabson 	/*
64927a0bc89SDoug Rabson 	 * Compute mask and shift value for isolating cluster relative byte
65027a0bc89SDoug Rabson 	 * offsets and cluster numbers from a file offset.
65127a0bc89SDoug Rabson 	 */
65201f6cfbaSYoshihiro Takahashi 	pmp->pm_bpcluster = SecPerClust * DEV_BSIZE;
653952a6212SJordan K. Hubbard 	pmp->pm_crbomask = pmp->pm_bpcluster - 1;
654952a6212SJordan K. Hubbard 	pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;
65527a0bc89SDoug Rabson 
656952a6212SJordan K. Hubbard 	/*
657952a6212SJordan K. Hubbard 	 * Check for valid cluster size
658952a6212SJordan K. Hubbard 	 * must be a power of 2
659952a6212SJordan K. Hubbard 	 */
660952a6212SJordan K. Hubbard 	if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) {
661952a6212SJordan K. Hubbard 		error = EINVAL;
662952a6212SJordan K. Hubbard 		goto error_exit;
663ad63a118SSatoshi Asami 	}
66427a0bc89SDoug Rabson 
66527a0bc89SDoug Rabson 	/*
66627a0bc89SDoug Rabson 	 * Release the bootsector buffer.
66727a0bc89SDoug Rabson 	 */
668952a6212SJordan K. Hubbard 	brelse(bp);
669952a6212SJordan K. Hubbard 	bp = NULL;
670952a6212SJordan K. Hubbard 
671952a6212SJordan K. Hubbard 	/*
6728d61a735SBruce Evans 	 * Check the fsinfo sector if we have one.  Silently fix up our
6738d61a735SBruce Evans 	 * in-core copy of fp->fsinxtfree if it is unknown (0xffffffff)
6748d61a735SBruce Evans 	 * or too large.  Ignore fp->fsinfree for now, since we need to
6758d61a735SBruce Evans 	 * read the entire FAT anyway to fill the inuse map.
676952a6212SJordan K. Hubbard 	 */
677952a6212SJordan K. Hubbard 	if (pmp->pm_fsinfo) {
678952a6212SJordan K. Hubbard 		struct fsinfo *fp;
679952a6212SJordan K. Hubbard 
68037269429SBruce Evans 		if ((error = bread(devvp, pmp->pm_fsinfo, pmp->pm_BytesPerSec,
68101f6cfbaSYoshihiro Takahashi 		    NOCRED, &bp)) != 0)
682952a6212SJordan K. Hubbard 			goto error_exit;
683952a6212SJordan K. Hubbard 		fp = (struct fsinfo *)bp->b_data;
684952a6212SJordan K. Hubbard 		if (!bcmp(fp->fsisig1, "RRaA", 4)
685952a6212SJordan K. Hubbard 		    && !bcmp(fp->fsisig2, "rrAa", 4)
686fd7c4230SBruce Evans 		    && !bcmp(fp->fsisig3, "\0\0\125\252", 4)) {
687952a6212SJordan K. Hubbard 			pmp->pm_nxtfree = getulong(fp->fsinxtfree);
6888d61a735SBruce Evans 			if (pmp->pm_nxtfree > pmp->pm_maxcluster)
6898bb386f2STim J. Robbins 				pmp->pm_nxtfree = CLUST_FIRST;
6908bb386f2STim J. Robbins 		} else
691952a6212SJordan K. Hubbard 			pmp->pm_fsinfo = 0;
692952a6212SJordan K. Hubbard 		brelse(bp);
693952a6212SJordan K. Hubbard 		bp = NULL;
694952a6212SJordan K. Hubbard 	}
695952a6212SJordan K. Hubbard 
696952a6212SJordan K. Hubbard 	/*
6978d61a735SBruce Evans 	 * Finish initializing pmp->pm_nxtfree (just in case the first few
6988d61a735SBruce Evans 	 * sectors aren't properly reserved in the FAT).  This completes
6998d61a735SBruce Evans 	 * the fixup for fp->fsinxtfree, and fixes up the zero-initialized
7008d61a735SBruce Evans 	 * value if there is no fsinfo.  We will use pmp->pm_nxtfree
7018d61a735SBruce Evans 	 * internally even if there is no fsinfo.
702952a6212SJordan K. Hubbard 	 */
7038d61a735SBruce Evans 	if (pmp->pm_nxtfree < CLUST_FIRST)
7048d61a735SBruce Evans 		pmp->pm_nxtfree = CLUST_FIRST;
70527a0bc89SDoug Rabson 
70627a0bc89SDoug Rabson 	/*
70727a0bc89SDoug Rabson 	 * Allocate memory for the bitmap of allocated clusters, and then
70827a0bc89SDoug Rabson 	 * fill it in.
70927a0bc89SDoug Rabson 	 */
7100ef0dd6fSBruce Evans 	pmp->pm_inusemap = malloc(howmany(pmp->pm_maxcluster + 1, N_INUSEBITS)
71127a0bc89SDoug Rabson 				  * sizeof(*pmp->pm_inusemap),
712a163d034SWarner Losh 				  M_MSDOSFSFAT, M_WAITOK);
71327a0bc89SDoug Rabson 
71427a0bc89SDoug Rabson 	/*
71527a0bc89SDoug Rabson 	 * fillinusemap() needs pm_devvp.
71627a0bc89SDoug Rabson 	 */
71727a0bc89SDoug Rabson 	pmp->pm_devvp = devvp;
718c72ae142SJohn Baldwin 	pmp->pm_dev = dev;
71927a0bc89SDoug Rabson 
72027a0bc89SDoug Rabson 	/*
72127a0bc89SDoug Rabson 	 * Have the inuse map filled in.
72227a0bc89SDoug Rabson 	 */
7236be1a4ccSKonstantin Belousov 	MSDOSFS_LOCK_MP(pmp);
7246be1a4ccSKonstantin Belousov 	error = fillinusemap(pmp);
7256be1a4ccSKonstantin Belousov 	MSDOSFS_UNLOCK_MP(pmp);
7266be1a4ccSKonstantin Belousov 	if (error != 0)
72727a0bc89SDoug Rabson 		goto error_exit;
72827a0bc89SDoug Rabson 
72927a0bc89SDoug Rabson 	/*
73027a0bc89SDoug Rabson 	 * If they want fat updates to be synchronous then let them suffer
73127a0bc89SDoug Rabson 	 * the performance degradation in exchange for the on disk copy of
73227a0bc89SDoug Rabson 	 * the fat being correct just about all the time.  I suppose this
73327a0bc89SDoug Rabson 	 * would be a good thing to turn on if the kernel is still flakey.
73427a0bc89SDoug Rabson 	 */
735952a6212SJordan K. Hubbard 	if (mp->mnt_flag & MNT_SYNCHRONOUS)
736952a6212SJordan K. Hubbard 		pmp->pm_flags |= MSDOSFSMNT_WAITONFAT;
73727a0bc89SDoug Rabson 
73827a0bc89SDoug Rabson 	/*
73927a0bc89SDoug Rabson 	 * Finish up.
74027a0bc89SDoug Rabson 	 */
741952a6212SJordan K. Hubbard 	if (ronly)
742952a6212SJordan K. Hubbard 		pmp->pm_flags |= MSDOSFSMNT_RONLY;
743cede1f56STom Rhodes 	else {
7443247c9ddSXin LI 		if ((error = markvoldirty(pmp, 1)) != 0) {
7453247c9ddSXin LI 			(void)markvoldirty(pmp, 0);
746cede1f56STom Rhodes 			goto error_exit;
7473247c9ddSXin LI 		}
74827a0bc89SDoug Rabson 		pmp->pm_fmod = 1;
749cede1f56STom Rhodes 	}
75077465d93SAlfred Perlstein 	mp->mnt_data =  pmp;
751939cb752SBruce Evans 	mp->mnt_stat.f_fsid.val[0] = dev2udev(dev);
752af3f60d5SBruce Evans 	mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
7535da56ddbSTor Egge 	MNT_ILOCK(mp);
754cc9d8990SPeter Wemm 	mp->mnt_flag |= MNT_LOCAL;
7555da56ddbSTor Egge 	MNT_IUNLOCK(mp);
75627a0bc89SDoug Rabson 
757f458f2a5SCraig Rodrigues 	if (pmp->pm_flags & MSDOSFS_LARGEFS)
7583bc482ecSTim J. Robbins 		msdosfs_fileno_init(mp);
7593bc482ecSTim J. Robbins 
76027a0bc89SDoug Rabson 	return 0;
76127a0bc89SDoug Rabson 
762952a6212SJordan K. Hubbard error_exit:
763952a6212SJordan K. Hubbard 	if (bp)
764952a6212SJordan K. Hubbard 		brelse(bp);
7659a135592SPoul-Henning Kamp 	if (cp != NULL) {
7669a135592SPoul-Henning Kamp 		DROP_GIANT();
7679a135592SPoul-Henning Kamp 		g_topology_lock();
7680d7935fdSAttilio Rao 		g_vfs_close(cp);
7699a135592SPoul-Henning Kamp 		g_topology_unlock();
7709a135592SPoul-Henning Kamp 		PICKUP_GIANT();
7719a135592SPoul-Henning Kamp 	}
77223b6c230SKonstantin Belousov 	lockdestroy(&pmp->pm_fatlock);
77327a0bc89SDoug Rabson 	if (pmp) {
77427a0bc89SDoug Rabson 		if (pmp->pm_inusemap)
775952a6212SJordan K. Hubbard 			free(pmp->pm_inusemap, M_MSDOSFSFAT);
776952a6212SJordan K. Hubbard 		free(pmp, M_MSDOSFSMNT);
77777465d93SAlfred Perlstein 		mp->mnt_data = NULL;
77827a0bc89SDoug Rabson 	}
779c72ae142SJohn Baldwin 	dev_rel(dev);
780952a6212SJordan K. Hubbard 	return (error);
78127a0bc89SDoug Rabson }
78227a0bc89SDoug Rabson 
78327a0bc89SDoug Rabson /*
78427a0bc89SDoug Rabson  * Unmount the filesystem described by mp.
78527a0bc89SDoug Rabson  */
7867fefffeeSPoul-Henning Kamp static int
787dfd233edSAttilio Rao msdosfs_unmount(struct mount *mp, int mntflags)
78827a0bc89SDoug Rabson {
789952a6212SJordan K. Hubbard 	struct msdosfsmount *pmp;
790952a6212SJordan K. Hubbard 	int error, flags;
79127a0bc89SDoug Rabson 
792952a6212SJordan K. Hubbard 	flags = 0;
793952a6212SJordan K. Hubbard 	if (mntflags & MNT_FORCE)
79427a0bc89SDoug Rabson 		flags |= FORCECLOSE;
795dfd233edSAttilio Rao 	error = vflush(mp, 0, flags, curthread);
7964f560d75SEdward Tomasz Napierala 	if (error && error != ENXIO)
79727a0bc89SDoug Rabson 		return error;
798952a6212SJordan K. Hubbard 	pmp = VFSTOMSDOSFS(mp);
7993247c9ddSXin LI 	if ((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0) {
8003247c9ddSXin LI 		error = markvoldirty(pmp, 0);
8014f560d75SEdward Tomasz Napierala 		if (error && error != ENXIO) {
8023247c9ddSXin LI 			(void)markvoldirty(pmp, 1);
8033247c9ddSXin LI 			return (error);
8043247c9ddSXin LI 		}
8053247c9ddSXin LI 	}
806c4f02a89SMax Khon 	if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) {
807c4f02a89SMax Khon 		if (pmp->pm_w2u)
808c4f02a89SMax Khon 			msdosfs_iconv->close(pmp->pm_w2u);
809c4f02a89SMax Khon 		if (pmp->pm_u2w)
810c4f02a89SMax Khon 			msdosfs_iconv->close(pmp->pm_u2w);
811c4f02a89SMax Khon 		if (pmp->pm_d2u)
812c4f02a89SMax Khon 			msdosfs_iconv->close(pmp->pm_d2u);
813c4f02a89SMax Khon 		if (pmp->pm_u2d)
814c4f02a89SMax Khon 			msdosfs_iconv->close(pmp->pm_u2d);
815c4f02a89SMax Khon 	}
816cede1f56STom Rhodes 
817952a6212SJordan K. Hubbard #ifdef MSDOSFS_DEBUG
818952a6212SJordan K. Hubbard 	{
819952a6212SJordan K. Hubbard 		struct vnode *vp = pmp->pm_devvp;
820698b1a66SJeff Roberson 		struct bufobj *bo;
821952a6212SJordan K. Hubbard 
822698b1a66SJeff Roberson 		bo = &vp->v_bufobj;
823698b1a66SJeff Roberson 		BO_LOCK(bo);
8244d93c0beSJeff Roberson 		VI_LOCK(vp);
825f69d42a1SPoul-Henning Kamp 		vn_printf(vp,
826f69d42a1SPoul-Henning Kamp 		    "msdosfs_umount(): just before calling VOP_CLOSE()\n");
827952a6212SJordan K. Hubbard 		printf("freef %p, freeb %p, mount %p\n",
828fc2ffbe6SPoul-Henning Kamp 		    TAILQ_NEXT(vp, v_freelist), vp->v_freelist.tqe_prev,
829952a6212SJordan K. Hubbard 		    vp->v_mount);
830952a6212SJordan K. Hubbard 		printf("cleanblkhd %p, dirtyblkhd %p, numoutput %ld, type %d\n",
831156cb265SPoul-Henning Kamp 		    TAILQ_FIRST(&vp->v_bufobj.bo_clean.bv_hd),
832156cb265SPoul-Henning Kamp 		    TAILQ_FIRST(&vp->v_bufobj.bo_dirty.bv_hd),
833156cb265SPoul-Henning Kamp 		    vp->v_bufobj.bo_numoutput, vp->v_type);
8344d93c0beSJeff Roberson 		VI_UNLOCK(vp);
835698b1a66SJeff Roberson 		BO_UNLOCK(bo);
836952a6212SJordan K. Hubbard 	}
837952a6212SJordan K. Hubbard #endif
8389a135592SPoul-Henning Kamp 	DROP_GIANT();
8399a135592SPoul-Henning Kamp 	g_topology_lock();
8400d7935fdSAttilio Rao 	g_vfs_close(pmp->pm_cp);
8419a135592SPoul-Henning Kamp 	g_topology_unlock();
8429a135592SPoul-Henning Kamp 	PICKUP_GIANT();
84327a0bc89SDoug Rabson 	vrele(pmp->pm_devvp);
844c72ae142SJohn Baldwin 	dev_rel(pmp->pm_dev);
845952a6212SJordan K. Hubbard 	free(pmp->pm_inusemap, M_MSDOSFSFAT);
8463247c9ddSXin LI 	if (pmp->pm_flags & MSDOSFS_LARGEFS)
8473bc482ecSTim J. Robbins 		msdosfs_fileno_free(mp);
84823b6c230SKonstantin Belousov 	lockdestroy(&pmp->pm_fatlock);
849952a6212SJordan K. Hubbard 	free(pmp, M_MSDOSFSMNT);
85077465d93SAlfred Perlstein 	mp->mnt_data = NULL;
8515da56ddbSTor Egge 	MNT_ILOCK(mp);
852cc9d8990SPeter Wemm 	mp->mnt_flag &= ~MNT_LOCAL;
8535da56ddbSTor Egge 	MNT_IUNLOCK(mp);
8544f560d75SEdward Tomasz Napierala 	return (error);
85527a0bc89SDoug Rabson }
85627a0bc89SDoug Rabson 
8577fefffeeSPoul-Henning Kamp static int
858dfd233edSAttilio Rao msdosfs_root(struct mount *mp, int flags, struct vnode **vpp)
85927a0bc89SDoug Rabson {
860952a6212SJordan K. Hubbard 	struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
86127a0bc89SDoug Rabson 	struct denode *ndep;
86227a0bc89SDoug Rabson 	int error;
86327a0bc89SDoug Rabson 
86427a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG
865952a6212SJordan K. Hubbard 	printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp);
86627a0bc89SDoug Rabson #endif
867952a6212SJordan K. Hubbard 	error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep);
868952a6212SJordan K. Hubbard 	if (error)
869952a6212SJordan K. Hubbard 		return (error);
87027a0bc89SDoug Rabson 	*vpp = DETOV(ndep);
871952a6212SJordan K. Hubbard 	return (0);
87227a0bc89SDoug Rabson }
87327a0bc89SDoug Rabson 
8747fefffeeSPoul-Henning Kamp static int
875dfd233edSAttilio Rao msdosfs_statfs(struct mount *mp, struct statfs *sbp)
87627a0bc89SDoug Rabson {
877952a6212SJordan K. Hubbard 	struct msdosfsmount *pmp;
87827a0bc89SDoug Rabson 
879952a6212SJordan K. Hubbard 	pmp = VFSTOMSDOSFS(mp);
88027a0bc89SDoug Rabson 	sbp->f_bsize = pmp->pm_bpcluster;
88127a0bc89SDoug Rabson 	sbp->f_iosize = pmp->pm_bpcluster;
882499d3ffaSBoris Popov 	sbp->f_blocks = pmp->pm_maxcluster + 1;
88327a0bc89SDoug Rabson 	sbp->f_bfree = pmp->pm_freeclustercount;
88427a0bc89SDoug Rabson 	sbp->f_bavail = pmp->pm_freeclustercount;
88527a0bc89SDoug Rabson 	sbp->f_files = pmp->pm_RootDirEnts;	/* XXX */
88627a0bc89SDoug Rabson 	sbp->f_ffree = 0;	/* what to put in here? */
887952a6212SJordan K. Hubbard 	return (0);
88827a0bc89SDoug Rabson }
88927a0bc89SDoug Rabson 
8907fefffeeSPoul-Henning Kamp static int
891dfd233edSAttilio Rao msdosfs_sync(struct mount *mp, int waitfor)
89227a0bc89SDoug Rabson {
893952a6212SJordan K. Hubbard 	struct vnode *vp, *nvp;
894dfd233edSAttilio Rao 	struct thread *td;
89527a0bc89SDoug Rabson 	struct denode *dep;
896952a6212SJordan K. Hubbard 	struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
897952a6212SJordan K. Hubbard 	int error, allerror = 0;
89827a0bc89SDoug Rabson 
899dfd233edSAttilio Rao 	td = curthread;
900dfd233edSAttilio Rao 
90127a0bc89SDoug Rabson 	/*
90227a0bc89SDoug Rabson 	 * If we ever switch to not updating all of the fats all the time,
90327a0bc89SDoug Rabson 	 * this would be the place to update them from the first one.
90427a0bc89SDoug Rabson 	 */
905dfd5dee1SPeter Wemm 	if (pmp->pm_fmod != 0) {
906952a6212SJordan K. Hubbard 		if (pmp->pm_flags & MSDOSFSMNT_RONLY)
90727a0bc89SDoug Rabson 			panic("msdosfs_sync: rofs mod");
90827a0bc89SDoug Rabson 		else {
90927a0bc89SDoug Rabson 			/* update fats here */
91027a0bc89SDoug Rabson 		}
911dfd5dee1SPeter Wemm 	}
91227a0bc89SDoug Rabson 	/*
913952a6212SJordan K. Hubbard 	 * Write back each (modified) denode.
91427a0bc89SDoug Rabson 	 */
915ca430f2eSAlexander Kabaev 	MNT_ILOCK(mp);
91627a0bc89SDoug Rabson loop:
917e3c5a7a4SPoul-Henning Kamp 	MNT_VNODE_FOREACH(vp, mp, nvp) {
9184d93c0beSJeff Roberson 		VI_LOCK(vp);
9198da00465SJeff Roberson 		if (vp->v_type == VNON || (vp->v_iflag & VI_DOOMED)) {
9204ab2c8bdSJeff Roberson 			VI_UNLOCK(vp);
9214ab2c8bdSJeff Roberson 			continue;
9224ab2c8bdSJeff Roberson 		}
923ca430f2eSAlexander Kabaev 		MNT_IUNLOCK(mp);
92427a0bc89SDoug Rabson 		dep = VTODE(vp);
925f00f5d71SPoul-Henning Kamp 		if ((dep->de_flag &
926c681be37SDmitrij Tejblum 		    (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0 &&
927156cb265SPoul-Henning Kamp 		    (vp->v_bufobj.bo_dirty.bv_cnt == 0 ||
928f00f5d71SPoul-Henning Kamp 		    waitfor == MNT_LAZY)) {
9294d93c0beSJeff Roberson 			VI_UNLOCK(vp);
930ca430f2eSAlexander Kabaev 			MNT_ILOCK(mp);
93127a0bc89SDoug Rabson 			continue;
932af3f60d5SBruce Evans 		}
933b40ce416SJulian Elischer 		error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, td);
934af3f60d5SBruce Evans 		if (error) {
935ca430f2eSAlexander Kabaev 			MNT_ILOCK(mp);
936af3f60d5SBruce Evans 			if (error == ENOENT)
93727a0bc89SDoug Rabson 				goto loop;
938af3f60d5SBruce Evans 			continue;
939af3f60d5SBruce Evans 		}
9408df6bac4SPoul-Henning Kamp 		error = VOP_FSYNC(vp, waitfor, td);
941c3c6d51eSPoul-Henning Kamp 		if (error)
94227a0bc89SDoug Rabson 			allerror = error;
94322db15c0SAttilio Rao 		VOP_UNLOCK(vp, 0);
944cb9ddc80SAlexander Kabaev 		vrele(vp);
945ca430f2eSAlexander Kabaev 		MNT_ILOCK(mp);
94627a0bc89SDoug Rabson 	}
947ca430f2eSAlexander Kabaev 	MNT_IUNLOCK(mp);
94827a0bc89SDoug Rabson 
94927a0bc89SDoug Rabson 	/*
95027a0bc89SDoug Rabson 	 * Flush filesystem control info.
95127a0bc89SDoug Rabson 	 */
952c681be37SDmitrij Tejblum 	if (waitfor != MNT_LAZY) {
953cb05b60aSAttilio Rao 		vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY);
9548df6bac4SPoul-Henning Kamp 		error = VOP_FSYNC(pmp->pm_devvp, waitfor, td);
955c3c6d51eSPoul-Henning Kamp 		if (error)
95627a0bc89SDoug Rabson 			allerror = error;
95722db15c0SAttilio Rao 		VOP_UNLOCK(pmp->pm_devvp, 0);
958c681be37SDmitrij Tejblum 	}
959952a6212SJordan K. Hubbard 	return (allerror);
96027a0bc89SDoug Rabson }
96127a0bc89SDoug Rabson 
9621be5bc74STom Rhodes static int
9631be5bc74STom Rhodes msdosfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
9641be5bc74STom Rhodes {
9651be5bc74STom Rhodes 	struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
9661be5bc74STom Rhodes 	struct defid *defhp = (struct defid *) fhp;
9671be5bc74STom Rhodes 	struct denode *dep;
9681be5bc74STom Rhodes 	int error;
9691be5bc74STom Rhodes 
9701be5bc74STom Rhodes 	error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep);
9711be5bc74STom Rhodes 	if (error) {
9721be5bc74STom Rhodes 		*vpp = NULLVP;
9731be5bc74STom Rhodes 		return (error);
9741be5bc74STom Rhodes 	}
9751be5bc74STom Rhodes 	*vpp = DETOV(dep);
9761be5bc74STom Rhodes 	vnode_create_vobject(*vpp, dep->de_FileSize, curthread);
9771be5bc74STom Rhodes 	return (0);
9781be5bc74STom Rhodes }
9791be5bc74STom Rhodes 
98030ffadf3SPoul-Henning Kamp static struct vfsops msdosfs_vfsops = {
9811be5bc74STom Rhodes 	.vfs_fhtovp =		msdosfs_fhtovp,
9826a4b48f4SPoul-Henning Kamp 	.vfs_mount =		msdosfs_mount,
9836a4b48f4SPoul-Henning Kamp 	.vfs_cmount =		msdosfs_cmount,
9847652131bSPoul-Henning Kamp 	.vfs_root =		msdosfs_root,
9857652131bSPoul-Henning Kamp 	.vfs_statfs =		msdosfs_statfs,
9867652131bSPoul-Henning Kamp 	.vfs_sync =		msdosfs_sync,
9877652131bSPoul-Henning Kamp 	.vfs_unmount =		msdosfs_unmount,
98827a0bc89SDoug Rabson };
989c901836cSGarrett Wollman 
9904ccd7546SRuslan Ermilov VFS_SET(msdosfs_vfsops, msdosfs, 0);
991c4f02a89SMax Khon MODULE_VERSION(msdosfs, 1);
992