msdosfs_vfsops.c revision 15033
11556Srgrimes/*	$Id: msdosfs_vfsops.c,v 1.11 1996/01/05 18:31:43 wollman Exp $ */
21556Srgrimes/*	$NetBSD: msdosfs_vfsops.c,v 1.19 1994/08/21 18:44:10 ws Exp $	*/
31556Srgrimes
41556Srgrimes/*-
51556Srgrimes * Copyright (C) 1994 Wolfgang Solfrank.
61556Srgrimes * Copyright (C) 1994 TooLs GmbH.
71556Srgrimes * All rights reserved.
81556Srgrimes * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
91556Srgrimes *
101556Srgrimes * Redistribution and use in source and binary forms, with or without
111556Srgrimes * modification, are permitted provided that the following conditions
121556Srgrimes * are met:
131556Srgrimes * 1. Redistributions of source code must retain the above copyright
141556Srgrimes *    notice, this list of conditions and the following disclaimer.
151556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161556Srgrimes *    notice, this list of conditions and the following disclaimer in the
171556Srgrimes *    documentation and/or other materials provided with the distribution.
181556Srgrimes * 3. All advertising materials mentioning features or use of this software
191556Srgrimes *    must display the following acknowledgement:
201556Srgrimes *	This product includes software developed by TooLs GmbH.
211556Srgrimes * 4. The name of TooLs GmbH may not be used to endorse or promote products
221556Srgrimes *    derived from this software without specific prior written permission.
231556Srgrimes *
241556Srgrimes * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
251556Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
261556Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
271556Srgrimes * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
281556Srgrimes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
291556Srgrimes * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
301556Srgrimes * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
311556Srgrimes * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
321556Srgrimes * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
331556Srgrimes * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3436150Scharnier */
3536150Scharnier/*
3636150Scharnier * Written by Paul Popelka (paulp@uts.amdahl.com)
371556Srgrimes *
3899110Sobrien * You can do anything you want with this software, just don't say you wrote
3999110Sobrien * it, and don't remove this notice.
401556Srgrimes *
41100437Stjr * This software is provided "as is".
4217987Speter *
43102576Skeramida * The author supplies this software to be publicly redistributed on the
4417987Speter * understanding that the author is not responsible for the correct
4545266Scracauer * functioning of this software in any circumstances and is not liable for
4653891Scracauer * any damages caused by this software.
4717987Speter *
481556Srgrimes * October 1992
491556Srgrimes */
501556Srgrimes
511556Srgrimes#include <sys/param.h>
521556Srgrimes#include <sys/systm.h>
531556Srgrimes#include <sys/namei.h>
541556Srgrimes#include <sys/proc.h>
551556Srgrimes#include <sys/kernel.h>
561556Srgrimes#include <sys/vnode.h>
571556Srgrimes#include <miscfs/specfs/specdev.h> /* XXX */	/* defines v_rdev */
581556Srgrimes#include <sys/mount.h>
591556Srgrimes#include <sys/buf.h>
601556Srgrimes#include <sys/file.h>
611556Srgrimes#include <sys/malloc.h>
621556Srgrimes
631556Srgrimes#include <msdosfs/bpb.h>
641556Srgrimes#include <msdosfs/bootsect.h>
651556Srgrimes#include <msdosfs/direntry.h>
661556Srgrimes#include <msdosfs/denode.h>
671556Srgrimes#include <msdosfs/msdosfsmount.h>
681556Srgrimes#include <msdosfs/fat.h>
6917987Speter
701556Srgrimesstatic int msdosfsdoforce = 1;		/* 1 = force unmount */
7117987Speter
721556Srgrimesstatic int	mountmsdosfs __P((struct vnode *devvp, struct mount *mp,
7317987Speter				  struct proc *p));
741556Srgrimesstatic int	msdosfs_fhtovp __P((struct mount *, struct fid *,
751556Srgrimes				    struct mbuf *, struct vnode **, int *,
761556Srgrimes				    struct ucred **));
771556Srgrimesstatic int	msdosfs_mount __P((struct mount *, char *, caddr_t,
781556Srgrimes				   struct nameidata *, struct proc *));
791556Srgrimesstatic int	msdosfs_quotactl __P((struct mount *, int, uid_t, caddr_t,
801556Srgrimes				      struct proc *));
811556Srgrimesstatic int	msdosfs_root __P((struct mount *, struct vnode **));
821556Srgrimesstatic int	msdosfs_start __P((struct mount *, int, struct proc *));
831556Srgrimesstatic int	msdosfs_statfs __P((struct mount *, struct statfs *,
841556Srgrimes				    struct proc *));
851556Srgrimesstatic int	msdosfs_sync __P((struct mount *, int, struct ucred *,
861556Srgrimes				  struct proc *));
871556Srgrimesstatic int	msdosfs_unmount __P((struct mount *, int, struct proc *));
881556Srgrimesstatic int	msdosfs_vget __P((struct mount *mp, ino_t ino,
891556Srgrimes				  struct vnode **vpp));
9017987Speterstatic int	msdosfs_vptofh __P((struct vnode *, struct fid *));
911556Srgrimes
921556Srgrimes/*
93149933Sstefanf * mp - path - addr in user space of mount point (ie /usr or whatever)
94149933Sstefanf * data - addr in user space of mount params including the name of the block
9590111Simp * special file to treat as a filesystem.
9690111Simp */
9790111Simpstatic int
9890111Simpmsdosfs_mount(mp, path, data, ndp, p)
9990111Simp	struct mount *mp;
10090111Simp	char *path;
1011556Srgrimes	caddr_t data;
1021556Srgrimes	struct nameidata *ndp;
1031556Srgrimes	struct proc *p;
1041556Srgrimes{
1051556Srgrimes	struct vnode *devvp;	  /* vnode for blk device to mount */
1061556Srgrimes	struct msdosfs_args args; /* will hold data from mount request */
1071556Srgrimes	struct msdosfsmount *pmp; /* msdosfs specific mount control block */
1081556Srgrimes	int error, flags;
1091556Srgrimes	u_int size;
1101556Srgrimes	struct ucred *cred, *scred;
1111556Srgrimes	struct vattr va;
1121556Srgrimes
1131556Srgrimes	/*
1141556Srgrimes	 * Copy in the args for the mount request.
1151556Srgrimes	 */
1161556Srgrimes	error = copyin(data, (caddr_t) & args, sizeof(struct msdosfs_args));
1171556Srgrimes	if (error)
1181556Srgrimes		return error;
1191556Srgrimes
1201556Srgrimes	/*
1211556Srgrimes	 * If they just want to update then be sure we can do what is
1221556Srgrimes	 * asked.  Can't change a filesystem from read/write to read only.
1231556Srgrimes	 * Why? And if they've supplied a new device file name then we
12446684Skris	 * continue, otherwise return.
1251556Srgrimes	 */
1261556Srgrimes	if (mp->mnt_flag & MNT_UPDATE) {
12717987Speter		pmp = (struct msdosfsmount *) mp->mnt_data;
12890111Simp		error = 0;
1291556Srgrimes		if (pmp->pm_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
1301556Srgrimes			flags = WRITECLOSE;
1311556Srgrimes			if (mp->mnt_flag & MNT_FORCE)
1321556Srgrimes				flags |= FORCECLOSE;
1331556Srgrimes			if (vfs_busy(mp))
1341556Srgrimes				return EBUSY;
1351556Srgrimes			error = vflush(mp, NULLVP, flags);
1361556Srgrimes			vfs_unbusy(mp);
1371556Srgrimes		}
1381556Srgrimes		if (!error && (mp->mnt_flag & MNT_RELOAD))
1391556Srgrimes			/* not yet implemented */
1401556Srgrimes			error = EINVAL;
1411556Srgrimes		if (error)
1421556Srgrimes			return error;
1431556Srgrimes		if (pmp->pm_ronly && (mp->mnt_flag & MNT_RDONLY) == 0)
1441556Srgrimes			pmp->pm_ronly = 0;
1451556Srgrimes		if (args.fspec == 0) {
1461556Srgrimes			/*
1471556Srgrimes			 * Process export requests.
1481556Srgrimes			 */
1491556Srgrimes			return vfs_export(mp, &pmp->pm_export, &args.export);
1501556Srgrimes		}
1511556Srgrimes	} else
1521556Srgrimes		pmp = NULL;
1531556Srgrimes
1541556Srgrimes	/*
1551556Srgrimes	 * check to see that the user in owns the target directory.
1561556Srgrimes	 * Note the very XXX trick to make sure we're checking as the
1571556Srgrimes	 * real user -- were mount() executable by anyone, this wouldn't
1581556Srgrimes	 * be a problem.
1591556Srgrimes	 *
16090111Simp	 * XXX there should be one consistent error out.
16190111Simp	 */
1621556Srgrimes	cred = crdup(p->p_ucred);			/* XXX */
1631556Srgrimes	cred->cr_uid = p->p_cred->p_ruid;		/* XXX */
1641556Srgrimes	error = VOP_GETATTR(mp->mnt_vnodecovered, &va, cred, p);
1651556Srgrimes	if (error) {
1661556Srgrimes		crfree(cred);				/* XXX */
1671556Srgrimes		return error;
1681556Srgrimes	}
1691556Srgrimes	if (cred->cr_uid != 0) {
1701556Srgrimes		if (va.va_uid != cred->cr_uid) {
1711556Srgrimes			error = EACCES;
1721556Srgrimes			crfree(cred);			/* XXX */
1731556Srgrimes			return error;
1741556Srgrimes		}
1751556Srgrimes
1761556Srgrimes		/* a user mounted it; we'll verify permissions when unmounting */
1771556Srgrimes		mp->mnt_flag |= MNT_USER;
1781556Srgrimes	}
1791556Srgrimes
1801556Srgrimes	/*
1811556Srgrimes	 * Now, lookup the name of the block device this mount or name
1821556Srgrimes	 * update request is to apply to.
18390111Simp	 */
18417987Speter	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
185149927Sstefanf	scred = p->p_ucred;				/* XXX */
186149927Sstefanf	p->p_ucred = cred;				/* XXX */
187149927Sstefanf	error = namei(ndp);
1881556Srgrimes	p->p_ucred = scred;				/* XXX */
1891556Srgrimes	crfree(cred);					/* XXX */
1901556Srgrimes	if (error != 0)
1911556Srgrimes		return error;
1921556Srgrimes
19317987Speter	/*
1941556Srgrimes	 * Be sure they've given us a block device to treat as a
19517987Speter	 * filesystem.  And, that its major number is within the bdevsw
196149802Sstefanf	 * table.
1971556Srgrimes	 */
1981556Srgrimes	devvp = ndp->ni_vp;
199149932Sstefanf	if (devvp->v_type != VBLK) {
2001556Srgrimes		vrele(devvp);
2011556Srgrimes		return ENOTBLK;
2021556Srgrimes	}
2031556Srgrimes	if (major(devvp->v_rdev) >= nblkdev) {
2041556Srgrimes		vrele(devvp);
2051556Srgrimes		return ENXIO;
20618754Ssteve	}
2071556Srgrimes
20818754Ssteve	/*
2091556Srgrimes	 * If this is an update, then make sure the vnode for the block
2101556Srgrimes	 * special device is the same as the one our filesystem is in.
2111556Srgrimes	 */
2121556Srgrimes	if (mp->mnt_flag & MNT_UPDATE) {
2131556Srgrimes		if (devvp != pmp->pm_devvp)
2141556Srgrimes			error = EINVAL;
2151556Srgrimes		else
2161556Srgrimes			vrele(devvp);
2171556Srgrimes	} else {
2181556Srgrimes
2191556Srgrimes		/*
2201556Srgrimes		 * Well, it's not an update, it's a real mount request.
2211556Srgrimes		 * Time to get dirty.
2221556Srgrimes		 */
2231556Srgrimes		error = mountmsdosfs(devvp, mp, p);
2241556Srgrimes	}
225149927Sstefanf	if (error) {
2261556Srgrimes		vrele(devvp);
2271556Srgrimes		return error;
2281556Srgrimes	}
2291556Srgrimes
2301556Srgrimes	/*
2311556Srgrimes	 * Copy in the name of the directory the filesystem is to be
2321556Srgrimes	 * mounted on. Then copy in the name of the block special file
2331556Srgrimes	 * representing the filesystem being mounted. And we clear the
23420425Ssteve	 * remainder of the character strings to be tidy. Set up the
2351556Srgrimes	 * user id/group id/mask as specified by the user. Then, we try to
23617987Speter	 * fill in the filesystem stats structure as best we can with
2371556Srgrimes	 * whatever applies from a dos file system.
23820425Ssteve	 */
23920425Ssteve	pmp = (struct msdosfsmount *) mp->mnt_data;
2401556Srgrimes	copyinstr(path, (caddr_t) mp->mnt_stat.f_mntonname,
2411556Srgrimes	    sizeof(mp->mnt_stat.f_mntonname) - 1, &size);
2421556Srgrimes	bzero(mp->mnt_stat.f_mntonname + size,
2431556Srgrimes	    sizeof(mp->mnt_stat.f_mntonname) - size);
244149933Sstefanf	copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
2451556Srgrimes	bzero(mp->mnt_stat.f_mntfromname + size,
2461556Srgrimes	    MNAMELEN - size);
247149933Sstefanf	pmp->pm_mounter = p->p_cred->p_ruid;
2481556Srgrimes	pmp->pm_gid = args.gid;
2491556Srgrimes	pmp->pm_uid = args.uid;
2501556Srgrimes	pmp->pm_mask = args.mask;
2511556Srgrimes	(void) msdosfs_statfs(mp, &mp->mnt_stat, p);
2521556Srgrimes#ifdef MSDOSFS_DEBUG
2531556Srgrimes	printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap);
2541556Srgrimes#endif
2551556Srgrimes	return 0;
2561556Srgrimes}
2571556Srgrimes
2581556Srgrimesstatic int
2591556Srgrimesmountmsdosfs(devvp, mp, p)
2601556Srgrimes	struct vnode *devvp;
2611556Srgrimes	struct mount *mp;
2621556Srgrimes	struct proc *p;
263149927Sstefanf{
2641556Srgrimes	int i;
2651556Srgrimes	int bpc;
2661556Srgrimes	int bit;
267149927Sstefanf	int error;
2681556Srgrimes	int needclose;
2691556Srgrimes	int ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
2701556Srgrimes	dev_t dev = devvp->v_rdev;
2711556Srgrimes	union bootsector *bsp;
2721556Srgrimes	struct msdosfsmount *pmp = NULL;
2731556Srgrimes	struct buf *bp0 = NULL;
2741556Srgrimes	struct byte_bpb33 *b33;
2751556Srgrimes	struct byte_bpb50 *b50;
2761556Srgrimes
277149927Sstefanf	/*
2781556Srgrimes	 * Multiple mounts of the same block special file aren't allowed.
2791556Srgrimes	 * Make sure no one else has the special file open.  And flush any
2801556Srgrimes	 * old buffers from this filesystem.  Presumably this prevents us
2811556Srgrimes	 * from running into buffers that are the wrong blocksize.
2821556Srgrimes	 */
283149933Sstefanf	error = vfs_mountedon(devvp);
28417987Speter	if (error)
2851556Srgrimes		return error;
2861556Srgrimes	if (vcount(devvp) > 1)
2871556Srgrimes		return EBUSY;
2881556Srgrimes	error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
2891556Srgrimes	if (error)
2901556Srgrimes		return error;
2911556Srgrimes
2921556Srgrimes	/*
2931556Srgrimes	 * Now open the block special file.
2941556Srgrimes	 */
2951556Srgrimes	error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE, FSCRED, p);
2961556Srgrimes	if (error)
2971556Srgrimes		return error;
2981556Srgrimes	needclose = 1;
2991556Srgrimes#ifdef HDSUPPORT
3001556Srgrimes	/*
3011556Srgrimes	 * Put this in when we support reading dos filesystems from
3021556Srgrimes	 * partitioned harddisks.
3031556Srgrimes	 */
3041556Srgrimes	if (VOP_IOCTL(devvp, DIOCGPART, &msdosfspart, FREAD, NOCRED, p) == 0) {
3051556Srgrimes	}
3061556Srgrimes#endif
307149933Sstefanf
3081556Srgrimes	/*
3091556Srgrimes	 * Read the boot sector of the filesystem, and then check the boot
3101556Srgrimes	 * signature.  If not a dos boot sector then error out.  We could
3111556Srgrimes	 * also add some checking on the bsOemName field.  So far I've seen
3121556Srgrimes	 * the following values: "IBM  3.3" "MSDOS3.3" "MSDOS5.0"
3131556Srgrimes	 */
3141556Srgrimes	error = bread(devvp, 0, 512, NOCRED, &bp0);
3151556Srgrimes	if (error)
3161556Srgrimes		goto error_exit;
3171556Srgrimes	bp0->b_flags |= B_AGE;
3181556Srgrimes	bsp = (union bootsector *) bp0->b_data;
319149933Sstefanf	b33 = (struct byte_bpb33 *) bsp->bs33.bsBPB;
32017987Speter	b50 = (struct byte_bpb50 *) bsp->bs50.bsBPB;
3211556Srgrimes#ifdef MSDOSFS_CHECKSIG
3221556Srgrimes	if (bsp->bs50.bsBootSectSig != BOOTSIG) {
3231556Srgrimes		error = EINVAL;
3241556Srgrimes		goto error_exit;
3251556Srgrimes	}
3261556Srgrimes#endif
3271556Srgrimes	if ( bsp->bs50.bsJump[0] != 0xe9 &&
3281556Srgrimes	    (bsp->bs50.bsJump[0] != 0xeb || bsp->bs50.bsJump[2] != 0x90)) {
32917987Speter		error = EINVAL;
3301556Srgrimes		goto error_exit;
3311556Srgrimes	}
3321556Srgrimes
3331556Srgrimes	pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK);
3341556Srgrimes	bzero((caddr_t)pmp, sizeof *pmp);
3351556Srgrimes	pmp->pm_mountp = mp;
3361556Srgrimes
3371556Srgrimes	/*
3381556Srgrimes	 * Compute several useful quantities from the bpb in the
3391556Srgrimes	 * bootsector.  Copy in the dos 5 variant of the bpb then fix up
340149933Sstefanf	 * the fields that are different between dos 5 and dos 3.3.
3411556Srgrimes	 */
3421556Srgrimes	pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
3431556Srgrimes	pmp->pm_SectPerClust = b50->bpbSecPerClust;
3441556Srgrimes	pmp->pm_ResSectors = getushort(b50->bpbResSectors);
3451556Srgrimes	pmp->pm_FATs = b50->bpbFATs;
3461556Srgrimes	pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
3471556Srgrimes	pmp->pm_Sectors = getushort(b50->bpbSectors);
3481556Srgrimes	pmp->pm_Media = b50->bpbMedia;
3491556Srgrimes	pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
3501556Srgrimes	pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
3511556Srgrimes	pmp->pm_Heads = getushort(b50->bpbHeads);
3521556Srgrimes
3531556Srgrimes	/* XXX - We should probably check more values here */
3541556Srgrimes    	if (!pmp->pm_BytesPerSec || !pmp->pm_SectPerClust ||
3551556Srgrimes	    !pmp->pm_Heads || pmp->pm_Heads > 255 ||
3561556Srgrimes	    !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) {
3571556Srgrimes		error = EINVAL;
3581556Srgrimes		goto error_exit;
35990111Simp	}
36017987Speter
3611556Srgrimes	if (pmp->pm_Sectors == 0) {
3621556Srgrimes		pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
3631556Srgrimes		pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
3641556Srgrimes	} else {
3651556Srgrimes		pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
3661556Srgrimes		pmp->pm_HugeSectors = pmp->pm_Sectors;
3671556Srgrimes	}
36817987Speter	pmp->pm_fatblk = pmp->pm_ResSectors;
3691556Srgrimes	pmp->pm_rootdirblk = pmp->pm_fatblk +
3701556Srgrimes	    (pmp->pm_FATs * pmp->pm_FATsecs);
3711556Srgrimes	pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry))
3721556Srgrimes	    /
3731556Srgrimes	    pmp->pm_BytesPerSec;/* in sectors */
3741556Srgrimes	pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
3751556Srgrimes	pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
3761556Srgrimes	    pmp->pm_SectPerClust;
3771556Srgrimes	pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1;
3781556Srgrimes	pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec;
3791556Srgrimes	if (FAT12(pmp))
3801556Srgrimes		/*
3811556Srgrimes		 * This will usually be a floppy disk. This size makes sure
3821556Srgrimes		 * that one fat entry will not be split across multiple
3831556Srgrimes		 * blocks.
3841556Srgrimes		 */
3851556Srgrimes		pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
3861556Srgrimes	else
3871556Srgrimes		/*
3881556Srgrimes		 * This will usually be a hard disk. Reading or writing one
3891556Srgrimes		 * block should be quite fast.
3901556Srgrimes		 */
39190111Simp		pmp->pm_fatblocksize = MAXBSIZE;
39217987Speter	pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec;
3931556Srgrimes
3941556Srgrimes
3951556Srgrimes	if ((pmp->pm_rootdirsize % pmp->pm_SectPerClust) != 0)
3961556Srgrimes		printf("mountmsdosfs(): Warning: root directory is not a multiple of the clustersize in length\n");
3971556Srgrimes
3981556Srgrimes	/*
3991556Srgrimes	 * Compute mask and shift value for isolating cluster relative byte
4001556Srgrimes	 * offsets and cluster numbers from a file offset.
4011556Srgrimes	 */
4021556Srgrimes	bpc = pmp->pm_SectPerClust * pmp->pm_BytesPerSec;
4031556Srgrimes	pmp->pm_bpcluster = bpc;
4041556Srgrimes	pmp->pm_depclust = bpc / sizeof(struct direntry);
4051556Srgrimes	pmp->pm_crbomask = bpc - 1;
40645916Scracauer	if (bpc == 0) {
4071556Srgrimes		error = EINVAL;
4081556Srgrimes		goto error_exit;
4091556Srgrimes	}
4101556Srgrimes	bit = 1;
4111556Srgrimes	for (i = 0; i < 32; i++) {
4121556Srgrimes		if (bit & bpc) {
4131556Srgrimes			if (bit ^ bpc) {
4141556Srgrimes				error = EINVAL;
4151556Srgrimes				goto error_exit;
4161556Srgrimes			}
4171556Srgrimes			pmp->pm_cnshift = i;
41890111Simp			break;
41917987Speter		}
42025222Ssteve		bit <<= 1;
4211556Srgrimes	}
4221556Srgrimes
42317987Speter	pmp->pm_brbomask = 0x01ff;	/* 512 byte blocks only (so far) */
42417987Speter	pmp->pm_bnshift = 9;	/* shift right 9 bits to get bn */
42517987Speter
42617987Speter	/*
42717987Speter	 * Release the bootsector buffer.
42817987Speter	 */
42966612Sbrian	brelse(bp0);
43017987Speter	bp0 = NULL;
43196922Stjr
4321556Srgrimes	/*
4331556Srgrimes	 * Allocate memory for the bitmap of allocated clusters, and then
43417987Speter	 * fill it in.
43517987Speter	 */
43617987Speter	pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS - 1)
43717987Speter				   / N_INUSEBITS)
43817987Speter				  * sizeof(*pmp->pm_inusemap),
43917987Speter				  M_MSDOSFSFAT, M_WAITOK);
44017987Speter
44117987Speter	/*
4421556Srgrimes	 * fillinusemap() needs pm_devvp.
4431556Srgrimes	 */
4441556Srgrimes	pmp->pm_dev = dev;
4451556Srgrimes	pmp->pm_devvp = devvp;
4461556Srgrimes
4471556Srgrimes	/*
4481556Srgrimes	 * Have the inuse map filled in.
4491556Srgrimes	 */
4501556Srgrimes	error = fillinusemap(pmp);
4511556Srgrimes	if (error)
4521556Srgrimes		goto error_exit;
4531556Srgrimes
4541556Srgrimes	/*
4551556Srgrimes	 * If they want fat updates to be synchronous then let them suffer
45690111Simp	 * the performance degradation in exchange for the on disk copy of
45717987Speter	 * the fat being correct just about all the time.  I suppose this
4581556Srgrimes	 * would be a good thing to turn on if the kernel is still flakey.
4591556Srgrimes	 */
4601556Srgrimes	pmp->pm_waitonfat = mp->mnt_flag & MNT_SYNCHRONOUS;
4611556Srgrimes
4621556Srgrimes	/*
4631556Srgrimes	 * Finish up.
464149802Sstefanf	 */
4651556Srgrimes	pmp->pm_ronly = ronly;
4661556Srgrimes	if (ronly == 0)
4671556Srgrimes		pmp->pm_fmod = 1;
4681556Srgrimes	mp->mnt_data = (qaddr_t) pmp;
4691556Srgrimes        mp->mnt_stat.f_fsid.val[0] = (long)dev;
4701556Srgrimes        mp->mnt_stat.f_fsid.val[1] = MOUNT_MSDOS;
4711556Srgrimes	mp->mnt_flag |= MNT_LOCAL;
4721556Srgrimes	devvp->v_specflags |= SI_MOUNTEDON;
4731556Srgrimes
4741556Srgrimes	return 0;
4751556Srgrimes
4761556Srgrimeserror_exit:;
47753891Scracauer	if (bp0)
4781556Srgrimes		brelse(bp0);
4791556Srgrimes	if (needclose)
4801556Srgrimes		(void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE,
4811556Srgrimes		    NOCRED, p);
4821556Srgrimes	if (pmp) {
483124780Sdes		if (pmp->pm_inusemap)
4841556Srgrimes			free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT);
4851556Srgrimes		free((caddr_t) pmp, M_MSDOSFSMNT);
4861556Srgrimes		mp->mnt_data = (qaddr_t) 0;
48753282Scracauer	}
48852900Scracauer	return error;
4891556Srgrimes}
490124780Sdes
4911556Srgrimesstatic int
4921556Srgrimesmsdosfs_start(mp, flags, p)
4931556Srgrimes	struct mount *mp;
4941556Srgrimes	int flags;
4951556Srgrimes	struct proc *p;
4961556Srgrimes{
4971556Srgrimes	return 0;
4981556Srgrimes}
4991556Srgrimes
5001556Srgrimes/*
5011556Srgrimes * Unmount the filesystem described by mp.
5021556Srgrimes */
5031556Srgrimesstatic int
50445916Scracauermsdosfs_unmount(mp, mntflags, p)
5051556Srgrimes	struct mount *mp;
5061556Srgrimes	int mntflags;
5071556Srgrimes	struct proc *p;
5081556Srgrimes{
5091556Srgrimes	int flags = 0;
5101556Srgrimes	int error;
5111556Srgrimes	struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data;
5121556Srgrimes
5131556Srgrimes	/* only the mounter, or superuser can unmount */
5141556Srgrimes	if ((p->p_cred->p_ruid != pmp->pm_mounter) &&
5151556Srgrimes	    (error = suser(p->p_ucred, &p->p_acflag)))
5161556Srgrimes		return error;
5171556Srgrimes
5181556Srgrimes	if (mntflags & MNT_FORCE) {
5191556Srgrimes		if (!msdosfsdoforce)
52090111Simp			return EINVAL;
52117987Speter		flags |= FORCECLOSE;
5221556Srgrimes	}
5231556Srgrimes	error = vflush(mp, NULLVP, flags);
5241556Srgrimes	if (error)
5251556Srgrimes		return error;
5261556Srgrimes	pmp->pm_devvp->v_specflags &= ~SI_MOUNTEDON;
5271556Srgrimes	error = VOP_CLOSE(pmp->pm_devvp, pmp->pm_ronly ? FREAD : FREAD | FWRITE,
5281556Srgrimes	    NOCRED, p);
5291556Srgrimes	vrele(pmp->pm_devvp);
5301556Srgrimes	free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT);
53117987Speter	free((caddr_t) pmp, M_MSDOSFSMNT);
53217987Speter	mp->mnt_data = (qaddr_t) 0;
5331556Srgrimes	mp->mnt_flag &= ~MNT_LOCAL;
53417987Speter	return error;
5351556Srgrimes}
53617987Speter
5371556Srgrimesstatic int
5381556Srgrimesmsdosfs_root(mp, vpp)
53917987Speter	struct mount *mp;
5401556Srgrimes	struct vnode **vpp;
54153891Scracauer{
5421556Srgrimes	struct denode *ndep;
5431556Srgrimes	struct msdosfsmount *pmp = (struct msdosfsmount *) (mp->mnt_data);
5441556Srgrimes	int error;
5451556Srgrimes
5461556Srgrimes	error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, NULL, &ndep);
547124780Sdes#ifdef MSDOSFS_DEBUG
5481556Srgrimes	printf("msdosfs_root(); mp %p, pmp %p, ndep %p, vp %p\n",
5491556Srgrimes	    mp, pmp, ndep, DETOV(ndep));
5501556Srgrimes#endif
5511556Srgrimes	if (error == 0)
5521556Srgrimes		*vpp = DETOV(ndep);
5531556Srgrimes	return error;
5541556Srgrimes}
5551556Srgrimes
5561556Srgrimesstatic int
5571556Srgrimesmsdosfs_quotactl(mp, cmds, uid, arg, p)
558109627Stjr	struct mount *mp;
5591556Srgrimes	int cmds;
5601556Srgrimes	uid_t uid;
5611556Srgrimes	caddr_t arg;
5621556Srgrimes	struct proc *p;
5631556Srgrimes{
5641556Srgrimes	return EOPNOTSUPP;
5651556Srgrimes}
5661556Srgrimes
5671556Srgrimesstatic int
5681556Srgrimesmsdosfs_statfs(mp, sbp, p)
56990111Simp	struct mount *mp;
57017987Speter	struct statfs *sbp;
5711556Srgrimes	struct proc *p;
5721556Srgrimes{
5731556Srgrimes	struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data;
5741556Srgrimes
5751556Srgrimes	/*
5761556Srgrimes	 * Fill in the stat block.
5771556Srgrimes	 */
5781556Srgrimes	sbp->f_type = MOUNT_MSDOS;
5791556Srgrimes	sbp->f_bsize = pmp->pm_bpcluster;
5801556Srgrimes	sbp->f_iosize = pmp->pm_bpcluster;
5811556Srgrimes	sbp->f_blocks = pmp->pm_nmbrofclusters;
5821556Srgrimes	sbp->f_bfree = pmp->pm_freeclustercount;
5831556Srgrimes	sbp->f_bavail = pmp->pm_freeclustercount;
5841556Srgrimes	sbp->f_files = pmp->pm_RootDirEnts;			/* XXX */
5851556Srgrimes	sbp->f_ffree = 0;	/* what to put in here? */
5861556Srgrimes
5871556Srgrimes	/*
5881556Srgrimes	 * Copy the mounted on and mounted from names into the passed in
5891556Srgrimes	 * stat block, if it is not the one in the mount structure.
5901556Srgrimes	 */
59145916Scracauer	if (sbp != &mp->mnt_stat) {
59254884Scracauer		bcopy((caddr_t) mp->mnt_stat.f_mntonname,
59317987Speter		    (caddr_t) & sbp->f_mntonname[0], MNAMELEN);
59417987Speter		bcopy((caddr_t) mp->mnt_stat.f_mntfromname,
59517987Speter		    (caddr_t) & sbp->f_mntfromname[0], MNAMELEN);
59617987Speter	}
59717987Speter#if 0
59817987Speter	strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN);
59954884Scracauer	sbp->f_fstypename[MFSNAMELEN] = '\0';
60017987Speter#endif
6011556Srgrimes	return 0;
6021556Srgrimes}
603149802Sstefanf
6041556Srgrimesstatic int
6051556Srgrimesmsdosfs_sync(mp, waitfor, cred, p)
6061556Srgrimes	struct mount *mp;
6071556Srgrimes	int waitfor;
60854884Scracauer	struct ucred *cred;
60917987Speter	struct proc *p;
61017987Speter{
6111556Srgrimes	struct vnode *vp;
61217987Speter	struct denode *dep;
6131556Srgrimes	struct msdosfsmount *pmp;
6141556Srgrimes	int error;
6151556Srgrimes	int allerror = 0;
6161556Srgrimes
6171556Srgrimes	pmp = (struct msdosfsmount *) mp->mnt_data;
6181556Srgrimes
6191556Srgrimes	/*
6201556Srgrimes	 * If we ever switch to not updating all of the fats all the time,
6211556Srgrimes	 * this would be the place to update them from the first one.
6221556Srgrimes	 */
6231556Srgrimes	if (pmp->pm_fmod)
6241556Srgrimes		if (pmp->pm_ronly)
6251556Srgrimes			panic("msdosfs_sync: rofs mod");
6261556Srgrimes		else {
6271556Srgrimes			/* update fats here */
6281556Srgrimes		}
6291556Srgrimes
6301556Srgrimes	/*
6311556Srgrimes	 * Go thru in memory denodes and write them out along with
6321556Srgrimes	 * unwritten file blocks.
6331556Srgrimes	 */
6341556Srgrimesloop:
6351556Srgrimes	for (vp = mp->mnt_vnodelist.lh_first; vp;
6361556Srgrimes	    vp = vp->v_mntvnodes.le_next) {
6371556Srgrimes		if (vp->v_mount != mp)	/* not ours anymore	 */
6381556Srgrimes			goto loop;
6391556Srgrimes		if (VOP_ISLOCKED(vp))	/* file is busy		 */
6401556Srgrimes			continue;
6411556Srgrimes		dep = VTODE(vp);
6421556Srgrimes		if ((dep->de_flag & (DE_MODIFIED | DE_UPDATE)) == 0 &&
6431556Srgrimes		    vp->v_dirtyblkhd.lh_first == NULL)
6441556Srgrimes			continue;
6451556Srgrimes		if (vget(vp, 1))	/* not there anymore?	 */
6461556Srgrimes			goto loop;
6471556Srgrimes		error = VOP_FSYNC(vp, cred, waitfor, p);
6481556Srgrimes		if (error)
6491556Srgrimes			allerror = error;
6501556Srgrimes		vput(vp);	/* done with this one	 */
6511556Srgrimes	}
6521556Srgrimes
6531556Srgrimes	/*
6541556Srgrimes	 * Flush filesystem control info.
6551556Srgrimes	 */
6561556Srgrimes	error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p);
6571556Srgrimes	if (error)
6581556Srgrimes		allerror = error;
6591556Srgrimes	return allerror;
6601556Srgrimes}
6611556Srgrimes
6621556Srgrimesstatic int
66317987Spetermsdosfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
66417987Speter	struct mount *mp;
66517987Speter	struct fid *fhp;
66617987Speter	struct mbuf *nam;
66717987Speter	struct vnode **vpp;
66817987Speter	int *exflagsp;
66917987Speter	struct ucred **credanonp;
67017987Speter{
67154884Scracauer	struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data;
67217987Speter	struct defid *defhp = (struct defid *) fhp;
67354884Scracauer	struct denode *dep;
67454884Scracauer	struct netcred *np;
67554884Scracauer	int error;
67654884Scracauer
67754884Scracauer	np = vfs_export_lookup(mp, &pmp->pm_export, nam);
67854884Scracauer	if (np == NULL)
67954884Scracauer		return EACCES;
68054884Scracauer	error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs,
68154884Scracauer	    NULL, &dep);
68254884Scracauer	if (error) {
68354884Scracauer		*vpp = NULLVP;
68454884Scracauer		return error;
68554884Scracauer	}
68654884Scracauer	*vpp = DETOV(dep);
68754884Scracauer	*exflagsp = np->netc_exflags;
68854884Scracauer	*credanonp = &np->netc_anon;
689123996Smaxim	return 0;
69054884Scracauer}
69154884Scracauer
69254884Scracauer
69354884Scracauerstatic int
69417987Spetermsdosfs_vptofh(vp, fhp)
69517987Speter	struct vnode *vp;
6961556Srgrimes	struct fid *fhp;
69720425Ssteve{
6981556Srgrimes	struct denode *dep = VTODE(vp);
6991556Srgrimes	struct defid *defhp = (struct defid *) fhp;
7001556Srgrimes
7011556Srgrimes	defhp->defid_len = sizeof(struct defid);
7021556Srgrimes	defhp->defid_dirclust = dep->de_dirclust;
7031556Srgrimes	defhp->defid_dirofs = dep->de_diroffset;
7041556Srgrimes	/* defhp->defid_gen = ip->i_gen; */
7051556Srgrimes	return 0;
7061556Srgrimes}
7071556Srgrimes
7081556Srgrimesstatic int
70920425Sstevemsdosfs_vget(mp, ino, vpp)
7101556Srgrimes	struct mount *mp;
7111556Srgrimes	ino_t ino;
7121556Srgrimes	struct vnode **vpp;
7131556Srgrimes{
7141556Srgrimes	return EOPNOTSUPP;
7151556Srgrimes}
7161556Srgrimes
7171556Srgrimesstatic struct vfsops msdosfs_vfsops = {
7181556Srgrimes	msdosfs_mount,
7191556Srgrimes	msdosfs_start,
7201556Srgrimes	msdosfs_unmount,
72145221Scracauer	msdosfs_root,
72245221Scracauer	msdosfs_quotactl,
72317987Speter	msdosfs_statfs,
7241556Srgrimes	msdosfs_sync,
72548896Ssheldonh	msdosfs_vget,
7261556Srgrimes	msdosfs_fhtovp,
727100437Stjr	msdosfs_vptofh,
728100437Stjr	msdosfs_init
729100437Stjr};
7301556Srgrimes
7311556SrgrimesVFS_SET(msdosfs_vfsops, msdos, MOUNT_MSDOS, 0);
7321556Srgrimes