msdosfs_vfsops.c revision 22521
1/*	$FreeBSD: head/sys/fs/msdosfs/msdosfs_vfsops.c 22521 1997-02-10 02:22:35Z dyson $ */
2/*	$NetBSD: msdosfs_vfsops.c,v 1.19 1994/08/21 18:44:10 ws Exp $	*/
3
4/*-
5 * Copyright (C) 1994 Wolfgang Solfrank.
6 * Copyright (C) 1994 TooLs GmbH.
7 * All rights reserved.
8 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *	This product includes software developed by TooLs GmbH.
21 * 4. The name of TooLs GmbH may not be used to endorse or promote products
22 *    derived from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
30 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35/*
36 * Written by Paul Popelka (paulp@uts.amdahl.com)
37 *
38 * You can do anything you want with this software, just don't say you wrote
39 * it, and don't remove this notice.
40 *
41 * This software is provided "as is".
42 *
43 * The author supplies this software to be publicly redistributed on the
44 * understanding that the author is not responsible for the correct
45 * functioning of this software in any circumstances and is not liable for
46 * any damages caused by this software.
47 *
48 * October 1992
49 */
50
51#include <sys/param.h>
52#include <sys/systm.h>
53#include <sys/namei.h>
54#include <sys/proc.h>
55#include <sys/kernel.h>
56#include <sys/vnode.h>
57#include <miscfs/specfs/specdev.h> /* XXX */	/* defines v_rdev */
58#include <sys/mount.h>
59#include <sys/buf.h>
60#include <sys/file.h>
61#include <sys/malloc.h>
62
63#include <msdosfs/bpb.h>
64#include <msdosfs/bootsect.h>
65#include <msdosfs/direntry.h>
66#include <msdosfs/denode.h>
67#include <msdosfs/msdosfsmount.h>
68#include <msdosfs/fat.h>
69
70static int msdosfsdoforce = 1;		/* 1 = force unmount */
71
72static int	mountmsdosfs __P((struct vnode *devvp, struct mount *mp,
73				  struct proc *p));
74static int	msdosfs_fhtovp __P((struct mount *, struct fid *,
75				    struct mbuf *, struct vnode **, int *,
76				    struct ucred **));
77static int	msdosfs_mount __P((struct mount *, char *, caddr_t,
78				   struct nameidata *, struct proc *));
79static int	msdosfs_quotactl __P((struct mount *, int, uid_t, caddr_t,
80				      struct proc *));
81static int	msdosfs_root __P((struct mount *, struct vnode **));
82static int	msdosfs_start __P((struct mount *, int, struct proc *));
83static int	msdosfs_statfs __P((struct mount *, struct statfs *,
84				    struct proc *));
85static int	msdosfs_sync __P((struct mount *, int, struct ucred *,
86				  struct proc *));
87static int	msdosfs_unmount __P((struct mount *, int, struct proc *));
88static int	msdosfs_vget __P((struct mount *mp, ino_t ino,
89				  struct vnode **vpp));
90static int	msdosfs_vptofh __P((struct vnode *, struct fid *));
91
92/*
93 * mp - path - addr in user space of mount point (ie /usr or whatever)
94 * data - addr in user space of mount params including the name of the block
95 * special file to treat as a filesystem.
96 */
97static int
98msdosfs_mount(mp, path, data, ndp, p)
99	struct mount *mp;
100	char *path;
101	caddr_t data;
102	struct nameidata *ndp;
103	struct proc *p;
104{
105	struct vnode *devvp;	  /* vnode for blk device to mount */
106	struct msdosfs_args args; /* will hold data from mount request */
107	struct msdosfsmount *pmp; /* msdosfs specific mount control block */
108	int error, flags;
109	u_int size;
110	struct ucred *cred, *scred;
111	struct vattr va;
112
113	/*
114	 * Copy in the args for the mount request.
115	 */
116	error = copyin(data, (caddr_t) & args, sizeof(struct msdosfs_args));
117	if (error)
118		return error;
119
120	/*
121	 * If they just want to update then be sure we can do what is
122	 * asked.  Can't change a filesystem from read/write to read only.
123	 * Why? And if they've supplied a new device file name then we
124	 * continue, otherwise return.
125	 */
126	if (mp->mnt_flag & MNT_UPDATE) {
127		pmp = (struct msdosfsmount *) mp->mnt_data;
128		error = 0;
129		if (pmp->pm_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
130			flags = WRITECLOSE;
131			if (mp->mnt_flag & MNT_FORCE)
132				flags |= FORCECLOSE;
133			if (vfs_busy(mp, LK_NOWAIT, 0, p))
134				return EBUSY;
135			error = vflush(mp, NULLVP, flags);
136			vfs_unbusy(mp, p);
137		}
138		if (!error && (mp->mnt_flag & MNT_RELOAD))
139			/* not yet implemented */
140			error = EINVAL;
141		if (error)
142			return error;
143		if (pmp->pm_ronly && (mp->mnt_flag & MNT_RDONLY) == 0)
144			pmp->pm_ronly = 0;
145		if (args.fspec == 0) {
146			/*
147			 * Process export requests.
148			 */
149			return vfs_export(mp, &pmp->pm_export, &args.export);
150		}
151	} else
152		pmp = NULL;
153
154	/*
155	 * check to see that the user in owns the target directory.
156	 * Note the very XXX trick to make sure we're checking as the
157	 * real user -- were mount() executable by anyone, this wouldn't
158	 * be a problem.
159	 *
160	 * XXX there should be one consistent error out.
161	 */
162	cred = crdup(p->p_ucred);			/* XXX */
163	cred->cr_uid = p->p_cred->p_ruid;		/* XXX */
164	error = VOP_GETATTR(mp->mnt_vnodecovered, &va, cred, p);
165	if (error) {
166		crfree(cred);				/* XXX */
167		return error;
168	}
169	if (cred->cr_uid != 0) {
170		if (va.va_uid != cred->cr_uid) {
171			error = EACCES;
172			crfree(cred);			/* XXX */
173			return error;
174		}
175
176		/* a user mounted it; we'll verify permissions when unmounting */
177		mp->mnt_flag |= MNT_USER;
178	}
179
180	/*
181	 * Now, lookup the name of the block device this mount or name
182	 * update request is to apply to.
183	 */
184	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
185	scred = p->p_ucred;				/* XXX */
186	p->p_ucred = cred;				/* XXX */
187	error = namei(ndp);
188	p->p_ucred = scred;				/* XXX */
189	crfree(cred);					/* XXX */
190	if (error != 0)
191		return error;
192
193	/*
194	 * Be sure they've given us a block device to treat as a
195	 * filesystem.  And, that its major number is within the bdevsw
196	 * table.
197	 */
198	devvp = ndp->ni_vp;
199	if (devvp->v_type != VBLK) {
200		vrele(devvp);
201		return ENOTBLK;
202	}
203	if (major(devvp->v_rdev) >= nblkdev) {
204		vrele(devvp);
205		return ENXIO;
206	}
207
208	/*
209	 * If this is an update, then make sure the vnode for the block
210	 * special device is the same as the one our filesystem is in.
211	 */
212	if (mp->mnt_flag & MNT_UPDATE) {
213		if (devvp != pmp->pm_devvp)
214			error = EINVAL;
215		else
216			vrele(devvp);
217	} else {
218
219		/*
220		 * Well, it's not an update, it's a real mount request.
221		 * Time to get dirty.
222		 */
223		error = mountmsdosfs(devvp, mp, p);
224	}
225	if (error) {
226		vrele(devvp);
227		return error;
228	}
229
230	/*
231	 * Copy in the name of the directory the filesystem is to be
232	 * mounted on. Then copy in the name of the block special file
233	 * representing the filesystem being mounted. And we clear the
234	 * remainder of the character strings to be tidy. Set up the
235	 * user id/group id/mask as specified by the user. Then, we try to
236	 * fill in the filesystem stats structure as best we can with
237	 * whatever applies from a dos file system.
238	 */
239	pmp = (struct msdosfsmount *) mp->mnt_data;
240	copyinstr(path, (caddr_t) mp->mnt_stat.f_mntonname,
241	    sizeof(mp->mnt_stat.f_mntonname) - 1, &size);
242	bzero(mp->mnt_stat.f_mntonname + size,
243	    sizeof(mp->mnt_stat.f_mntonname) - size);
244	copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
245	bzero(mp->mnt_stat.f_mntfromname + size,
246	    MNAMELEN - size);
247	pmp->pm_mounter = p->p_cred->p_ruid;
248	pmp->pm_gid = args.gid;
249	pmp->pm_uid = args.uid;
250	pmp->pm_mask = args.mask;
251	(void) msdosfs_statfs(mp, &mp->mnt_stat, p);
252#ifdef MSDOSFS_DEBUG
253	printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap);
254#endif
255	return 0;
256}
257
258static int
259mountmsdosfs(devvp, mp, p)
260	struct vnode *devvp;
261	struct mount *mp;
262	struct proc *p;
263{
264	int i;
265	int bpc;
266	int bit;
267	int error;
268	int needclose;
269	int ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
270	dev_t dev = devvp->v_rdev;
271	union bootsector *bsp;
272	struct msdosfsmount *pmp = NULL;
273	struct buf *bp0 = NULL;
274	struct byte_bpb33 *b33;
275	struct byte_bpb50 *b50;
276#ifdef	PC98
277	u_int	pc98_wrk;
278	u_int	Phy_Sector_Size;
279#endif
280
281	/*
282	 * Multiple mounts of the same block special file aren't allowed.
283	 * Make sure no one else has the special file open.  And flush any
284	 * old buffers from this filesystem.  Presumably this prevents us
285	 * from running into buffers that are the wrong blocksize.
286	 */
287	error = vfs_mountedon(devvp);
288	if (error)
289		return error;
290	if (vcount(devvp) > 1)
291		return EBUSY;
292	error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
293	if (error)
294		return error;
295
296	/*
297	 * Now open the block special file.
298	 */
299	error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE, FSCRED, p);
300	if (error)
301		return error;
302	needclose = 1;
303#ifdef HDSUPPORT
304	/*
305	 * Put this in when we support reading dos filesystems from
306	 * partitioned harddisks.
307	 */
308	if (VOP_IOCTL(devvp, DIOCGPART, &msdosfspart, FREAD, NOCRED, p) == 0) {
309	}
310#endif
311
312	/*
313	 * Read the boot sector of the filesystem, and then check the boot
314	 * signature.  If not a dos boot sector then error out.  We could
315	 * also add some checking on the bsOemName field.  So far I've seen
316	 * the following values: "IBM  3.3" "MSDOS3.3" "MSDOS5.0"
317	 */
318#ifdef	PC98
319	devvp->v_flag &= 0xffff;
320	error = bread(devvp, 0, 1024, NOCRED, &bp0);
321#else
322	error = bread(devvp, 0, 512, NOCRED, &bp0);
323#endif
324	if (error)
325		goto error_exit;
326	bp0->b_flags |= B_AGE;
327	bsp = (union bootsector *) bp0->b_data;
328	b33 = (struct byte_bpb33 *) bsp->bs33.bsBPB;
329	b50 = (struct byte_bpb50 *) bsp->bs50.bsBPB;
330#ifdef MSDOSFS_CHECKSIG
331#ifdef	PC98
332	if (bsp->bs50.bsBootSectSig != BOOTSIG &&
333	    bsp->bs50.bsBootSectSig != 0 &&		/* PC98 DOS 3.3x */
334	    bsp->bs50.bsBootSectSig != 15760 &&		/* PC98 DOS 5.0	 */
335	    bsp->bs50.bsBootSectSig != 64070) {		/* PC98 DOS 3.3B */
336#else
337	if (bsp->bs50.bsBootSectSig != BOOTSIG) {
338#endif
339		error = EINVAL;
340		goto error_exit;
341	}
342#endif
343	if ( bsp->bs50.bsJump[0] != 0xe9 &&
344	    (bsp->bs50.bsJump[0] != 0xeb || bsp->bs50.bsJump[2] != 0x90)) {
345		error = EINVAL;
346		goto error_exit;
347	}
348
349	pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK);
350	bzero((caddr_t)pmp, sizeof *pmp);
351	pmp->pm_mountp = mp;
352
353	/*
354	 * Compute several useful quantities from the bpb in the
355	 * bootsector.  Copy in the dos 5 variant of the bpb then fix up
356	 * the fields that are different between dos 5 and dos 3.3.
357	 */
358	pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
359	pmp->pm_SectPerClust = b50->bpbSecPerClust;
360	pmp->pm_ResSectors = getushort(b50->bpbResSectors);
361	pmp->pm_FATs = b50->bpbFATs;
362	pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
363	pmp->pm_Sectors = getushort(b50->bpbSectors);
364	pmp->pm_Media = b50->bpbMedia;
365	pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
366	pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
367	pmp->pm_Heads = getushort(b50->bpbHeads);
368
369	/* XXX - We should probably check more values here */
370    	if (!pmp->pm_BytesPerSec || !pmp->pm_SectPerClust ||
371	    !pmp->pm_Heads || pmp->pm_Heads > 255 ||
372#ifdef PC98
373	    !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) {
374#else
375	    !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) {
376#endif
377		error = EINVAL;
378		goto error_exit;
379	}
380
381	if (pmp->pm_Sectors == 0) {
382		pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
383		pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
384	} else {
385		pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
386		pmp->pm_HugeSectors = pmp->pm_Sectors;
387	}
388#ifdef	PC98	/* for PC98		added Satoshi Yasuda	*/
389	Phy_Sector_Size = 512;
390	if ((devvp->v_rdev>>8) == 2) {	/* floppy check */
391		if (((devvp->v_rdev&077) == 2) && (pmp->pm_HugeSectors == 1232)) {
392				Phy_Sector_Size = 1024;	/* 2HD */
393				/*
394				 * 1024byte/sector support
395				 */
396				devvp->v_flag |= 0x10000;
397		} else {
398			if ((((devvp->v_rdev&077) == 3)	/* 2DD 8 or 9 sector */
399				&& (pmp->pm_HugeSectors == 1440)) /* 9 sector */
400				|| (((devvp->v_rdev&077) == 4)
401				&& (pmp->pm_HugeSectors == 1280)) /* 8 sector */
402				|| (((devvp->v_rdev&077) == 5)
403				&& (pmp->pm_HugeSectors == 2880))) { /* 1.44M */
404					Phy_Sector_Size = 512;
405			} else {
406				if (((devvp->v_rdev&077) != 1)
407				    && ((devvp->v_rdev&077) != 0)) { /* 2HC */
408					error = EINVAL;
409					goto error_exit;
410				}
411			}
412		}
413	}
414	pc98_wrk = pmp->pm_BytesPerSec / Phy_Sector_Size;
415	pmp->pm_BytesPerSec = Phy_Sector_Size;
416	pmp->pm_SectPerClust = pmp->pm_SectPerClust * pc98_wrk;
417	pmp->pm_HugeSectors = pmp->pm_HugeSectors * pc98_wrk;
418	pmp->pm_ResSectors = pmp->pm_ResSectors * pc98_wrk;
419	pmp->pm_FATsecs = pmp->pm_FATsecs * pc98_wrk;
420	pmp->pm_SecPerTrack = pmp->pm_SecPerTrack * pc98_wrk;
421	pmp->pm_HiddenSects = pmp->pm_HiddenSects * pc98_wrk;
422#endif			/*						*/
423	pmp->pm_fatblk = pmp->pm_ResSectors;
424	pmp->pm_rootdirblk = pmp->pm_fatblk +
425	    (pmp->pm_FATs * pmp->pm_FATsecs);
426	pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry))
427	    /
428	    pmp->pm_BytesPerSec;/* in sectors */
429	pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
430	pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
431	    pmp->pm_SectPerClust;
432	pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1;
433	pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec;
434	if (FAT12(pmp))
435		/*
436		 * This will usually be a floppy disk. This size makes sure
437		 * that one fat entry will not be split across multiple
438		 * blocks.
439		 */
440		pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
441	else
442		/*
443		 * This will usually be a hard disk. Reading or writing one
444		 * block should be quite fast.
445		 */
446		pmp->pm_fatblocksize = MAXBSIZE;
447	pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec;
448
449
450	if ((pmp->pm_rootdirsize % pmp->pm_SectPerClust) != 0)
451		printf("mountmsdosfs(): Warning: root directory is not a multiple of the clustersize in length\n");
452
453	/*
454	 * Compute mask and shift value for isolating cluster relative byte
455	 * offsets and cluster numbers from a file offset.
456	 */
457	bpc = pmp->pm_SectPerClust * pmp->pm_BytesPerSec;
458	pmp->pm_bpcluster = bpc;
459	pmp->pm_depclust = bpc / sizeof(struct direntry);
460	pmp->pm_crbomask = bpc - 1;
461	if (bpc == 0) {
462		error = EINVAL;
463		goto error_exit;
464	}
465	bit = 1;
466	for (i = 0; i < 32; i++) {
467		if (bit & bpc) {
468			if (bit ^ bpc) {
469				error = EINVAL;
470				goto error_exit;
471			}
472			pmp->pm_cnshift = i;
473			break;
474		}
475		bit <<= 1;
476	}
477
478#ifdef	PC98
479	if (Phy_Sector_Size == 512) {
480		pmp->pm_brbomask = 0x01ff;	/* 512 byte blocks only (so far) */
481		pmp->pm_bnshift = 9;	/* shift right 9 bits to get bn */
482	} else {
483		pmp->pm_brbomask = 0x03ff;
484		pmp->pm_bnshift = 10;
485	}
486#else
487	pmp->pm_brbomask = 0x01ff;	/* 512 byte blocks only (so far) */
488	pmp->pm_bnshift = 9;	/* shift right 9 bits to get bn */
489#endif
490
491	/*
492	 * Release the bootsector buffer.
493	 */
494	brelse(bp0);
495	bp0 = NULL;
496
497	/*
498	 * Allocate memory for the bitmap of allocated clusters, and then
499	 * fill it in.
500	 */
501	pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS - 1)
502				   / N_INUSEBITS)
503				  * sizeof(*pmp->pm_inusemap),
504				  M_MSDOSFSFAT, M_WAITOK);
505
506	/*
507	 * fillinusemap() needs pm_devvp.
508	 */
509	pmp->pm_dev = dev;
510	pmp->pm_devvp = devvp;
511
512	/*
513	 * Have the inuse map filled in.
514	 */
515	error = fillinusemap(pmp);
516	if (error)
517		goto error_exit;
518
519	/*
520	 * If they want fat updates to be synchronous then let them suffer
521	 * the performance degradation in exchange for the on disk copy of
522	 * the fat being correct just about all the time.  I suppose this
523	 * would be a good thing to turn on if the kernel is still flakey.
524	 */
525	pmp->pm_waitonfat = mp->mnt_flag & MNT_SYNCHRONOUS;
526
527	/*
528	 * Finish up.
529	 */
530	pmp->pm_ronly = ronly;
531	if (ronly == 0)
532		pmp->pm_fmod = 1;
533	mp->mnt_data = (qaddr_t) pmp;
534        mp->mnt_stat.f_fsid.val[0] = (long)dev;
535        mp->mnt_stat.f_fsid.val[1] = MOUNT_MSDOS;
536	mp->mnt_flag |= MNT_LOCAL;
537	devvp->v_specflags |= SI_MOUNTEDON;
538
539	return 0;
540
541error_exit:;
542	if (bp0)
543		brelse(bp0);
544	if (needclose)
545		(void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE,
546		    NOCRED, p);
547	if (pmp) {
548		if (pmp->pm_inusemap)
549			free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT);
550		free((caddr_t) pmp, M_MSDOSFSMNT);
551		mp->mnt_data = (qaddr_t) 0;
552	}
553	return error;
554}
555
556static int
557msdosfs_start(mp, flags, p)
558	struct mount *mp;
559	int flags;
560	struct proc *p;
561{
562	return 0;
563}
564
565/*
566 * Unmount the filesystem described by mp.
567 */
568static int
569msdosfs_unmount(mp, mntflags, p)
570	struct mount *mp;
571	int mntflags;
572	struct proc *p;
573{
574	int flags = 0;
575	int error;
576	struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data;
577
578	/* only the mounter, or superuser can unmount */
579	if ((p->p_cred->p_ruid != pmp->pm_mounter) &&
580	    (error = suser(p->p_ucred, &p->p_acflag)))
581		return error;
582
583	if (mntflags & MNT_FORCE) {
584		if (!msdosfsdoforce)
585			return EINVAL;
586		flags |= FORCECLOSE;
587	}
588	error = vflush(mp, NULLVP, flags);
589	if (error)
590		return error;
591	pmp->pm_devvp->v_specflags &= ~SI_MOUNTEDON;
592	error = VOP_CLOSE(pmp->pm_devvp, pmp->pm_ronly ? FREAD : FREAD | FWRITE,
593	    NOCRED, p);
594	vrele(pmp->pm_devvp);
595	free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT);
596	free((caddr_t) pmp, M_MSDOSFSMNT);
597	mp->mnt_data = (qaddr_t) 0;
598	mp->mnt_flag &= ~MNT_LOCAL;
599	return error;
600}
601
602static int
603msdosfs_root(mp, vpp)
604	struct mount *mp;
605	struct vnode **vpp;
606{
607	struct denode *ndep;
608	struct msdosfsmount *pmp = (struct msdosfsmount *) (mp->mnt_data);
609	int error;
610
611	error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, NULL, &ndep);
612#ifdef MSDOSFS_DEBUG
613	printf("msdosfs_root(); mp %p, pmp %p, ndep %p, vp %p\n",
614	    mp, pmp, ndep, DETOV(ndep));
615#endif
616	if (error == 0)
617		*vpp = DETOV(ndep);
618	return error;
619}
620
621static int
622msdosfs_quotactl(mp, cmds, uid, arg, p)
623	struct mount *mp;
624	int cmds;
625	uid_t uid;
626	caddr_t arg;
627	struct proc *p;
628{
629	return EOPNOTSUPP;
630}
631
632static int
633msdosfs_statfs(mp, sbp, p)
634	struct mount *mp;
635	struct statfs *sbp;
636	struct proc *p;
637{
638	struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data;
639
640	/*
641	 * Fill in the stat block.
642	 */
643	sbp->f_type = MOUNT_MSDOS;
644	sbp->f_bsize = pmp->pm_bpcluster;
645	sbp->f_iosize = pmp->pm_bpcluster;
646	sbp->f_blocks = pmp->pm_nmbrofclusters;
647	sbp->f_bfree = pmp->pm_freeclustercount;
648	sbp->f_bavail = pmp->pm_freeclustercount;
649	sbp->f_files = pmp->pm_RootDirEnts;			/* XXX */
650	sbp->f_ffree = 0;	/* what to put in here? */
651
652	/*
653	 * Copy the mounted on and mounted from names into the passed in
654	 * stat block, if it is not the one in the mount structure.
655	 */
656	if (sbp != &mp->mnt_stat) {
657		bcopy((caddr_t) mp->mnt_stat.f_mntonname,
658		    (caddr_t) & sbp->f_mntonname[0], MNAMELEN);
659		bcopy((caddr_t) mp->mnt_stat.f_mntfromname,
660		    (caddr_t) & sbp->f_mntfromname[0], MNAMELEN);
661	}
662#if 0
663	strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN);
664	sbp->f_fstypename[MFSNAMELEN] = '\0';
665#endif
666	return 0;
667}
668
669static int
670msdosfs_sync(mp, waitfor, cred, p)
671	struct mount *mp;
672	int waitfor;
673	struct ucred *cred;
674	struct proc *p;
675{
676	struct vnode *vp;
677	struct denode *dep;
678	struct msdosfsmount *pmp;
679	int error;
680	int allerror = 0;
681
682	pmp = (struct msdosfsmount *) mp->mnt_data;
683
684	/*
685	 * If we ever switch to not updating all of the fats all the time,
686	 * this would be the place to update them from the first one.
687	 */
688	if (pmp->pm_fmod)
689		if (pmp->pm_ronly)
690			panic("msdosfs_sync: rofs mod");
691		else {
692			/* update fats here */
693		}
694
695	/*
696	 * Go thru in memory denodes and write them out along with
697	 * unwritten file blocks.
698	 */
699loop:
700	for (vp = mp->mnt_vnodelist.lh_first; vp;
701	    vp = vp->v_mntvnodes.le_next) {
702		if (vp->v_mount != mp)	/* not ours anymore	 */
703			goto loop;
704		if (VOP_ISLOCKED(vp))	/* file is busy		 */
705			continue;
706		dep = VTODE(vp);
707		if ((dep->de_flag & (DE_MODIFIED | DE_UPDATE)) == 0 &&
708		    vp->v_dirtyblkhd.lh_first == NULL)
709			continue;
710		if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p))	/* not there anymore?	 */
711			goto loop;
712		error = VOP_FSYNC(vp, cred, waitfor, p);
713		if (error)
714			allerror = error;
715		vput(vp);	/* done with this one	 */
716	}
717
718	/*
719	 * Flush filesystem control info.
720	 */
721	error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p);
722	if (error)
723		allerror = error;
724	return allerror;
725}
726
727static int
728msdosfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
729	struct mount *mp;
730	struct fid *fhp;
731	struct mbuf *nam;
732	struct vnode **vpp;
733	int *exflagsp;
734	struct ucred **credanonp;
735{
736	struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data;
737	struct defid *defhp = (struct defid *) fhp;
738	struct denode *dep;
739	struct netcred *np;
740	int error;
741
742	np = vfs_export_lookup(mp, &pmp->pm_export, nam);
743	if (np == NULL)
744		return EACCES;
745	error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs,
746	    NULL, &dep);
747	if (error) {
748		*vpp = NULLVP;
749		return error;
750	}
751	*vpp = DETOV(dep);
752	*exflagsp = np->netc_exflags;
753	*credanonp = &np->netc_anon;
754	return 0;
755}
756
757
758static int
759msdosfs_vptofh(vp, fhp)
760	struct vnode *vp;
761	struct fid *fhp;
762{
763	struct denode *dep = VTODE(vp);
764	struct defid *defhp = (struct defid *) fhp;
765
766	defhp->defid_len = sizeof(struct defid);
767	defhp->defid_dirclust = dep->de_dirclust;
768	defhp->defid_dirofs = dep->de_diroffset;
769	/* defhp->defid_gen = ip->i_gen; */
770	return 0;
771}
772
773static int
774msdosfs_vget(mp, ino, vpp)
775	struct mount *mp;
776	ino_t ino;
777	struct vnode **vpp;
778{
779	return EOPNOTSUPP;
780}
781
782static struct vfsops msdosfs_vfsops = {
783	msdosfs_mount,
784	msdosfs_start,
785	msdosfs_unmount,
786	msdosfs_root,
787	msdosfs_quotactl,
788	msdosfs_statfs,
789	msdosfs_sync,
790	msdosfs_vget,
791	msdosfs_fhtovp,
792	msdosfs_vptofh,
793	msdosfs_init
794};
795
796VFS_SET(msdosfs_vfsops, msdos, MOUNT_MSDOS, 0);
797