msdosfs_vfsops.c revision 30309
1/*	$Id: msdosfs_vfsops.c,v 1.20 1997/08/16 19:15:24 wollman Exp $ */
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/fcntl.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
70MALLOC_DEFINE(M_MSDOSFSFAT, "MSDOSFS FAT", "MSDOSFS file allocation table");
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 sockaddr *, 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			error = vflush(mp, NULLVP, flags);
134		}
135		if (!error && (mp->mnt_flag & MNT_RELOAD))
136			/* not yet implemented */
137			error = EINVAL;
138		if (error)
139			return error;
140		if (pmp->pm_ronly && (mp->mnt_flag & MNT_WANTRDWR))
141			pmp->pm_ronly = 0;
142		if (args.fspec == 0) {
143			/*
144			 * Process export requests.
145			 */
146			return vfs_export(mp, &pmp->pm_export, &args.export);
147		}
148	} else
149		pmp = NULL;
150
151	/*
152	 * check to see that the user in owns the target directory.
153	 * Note the very XXX trick to make sure we're checking as the
154	 * real user -- were mount() executable by anyone, this wouldn't
155	 * be a problem.
156	 *
157	 * XXX there should be one consistent error out.
158	 */
159	cred = crdup(p->p_ucred);			/* XXX */
160	cred->cr_uid = p->p_cred->p_ruid;		/* XXX */
161	error = VOP_GETATTR(mp->mnt_vnodecovered, &va, cred, p);
162	if (error) {
163		crfree(cred);				/* XXX */
164		return error;
165	}
166	if (cred->cr_uid != 0) {
167		if (va.va_uid != cred->cr_uid) {
168			error = EACCES;
169			crfree(cred);			/* XXX */
170			return error;
171		}
172
173		/* a user mounted it; we'll verify permissions when unmounting */
174		mp->mnt_flag |= MNT_USER;
175	}
176
177	/*
178	 * Now, lookup the name of the block device this mount or name
179	 * update request is to apply to.
180	 */
181	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
182	scred = p->p_ucred;				/* XXX */
183	p->p_ucred = cred;				/* XXX */
184	error = namei(ndp);
185	p->p_ucred = scred;				/* XXX */
186	crfree(cred);					/* XXX */
187	if (error != 0)
188		return error;
189
190	/*
191	 * Be sure they've given us a block device to treat as a
192	 * filesystem.  And, that its major number is within the bdevsw
193	 * table.
194	 */
195	devvp = ndp->ni_vp;
196	if (devvp->v_type != VBLK) {
197		vrele(devvp);
198		return ENOTBLK;
199	}
200	if (major(devvp->v_rdev) >= nblkdev) {
201		vrele(devvp);
202		return ENXIO;
203	}
204
205	/*
206	 * If this is an update, then make sure the vnode for the block
207	 * special device is the same as the one our filesystem is in.
208	 */
209	if (mp->mnt_flag & MNT_UPDATE) {
210		if (devvp != pmp->pm_devvp)
211			error = EINVAL;
212		else
213			vrele(devvp);
214	} else {
215
216		/*
217		 * Well, it's not an update, it's a real mount request.
218		 * Time to get dirty.
219		 */
220		error = mountmsdosfs(devvp, mp, p);
221	}
222	if (error) {
223		vrele(devvp);
224		return error;
225	}
226
227	/*
228	 * Copy in the name of the directory the filesystem is to be
229	 * mounted on. Then copy in the name of the block special file
230	 * representing the filesystem being mounted. And we clear the
231	 * remainder of the character strings to be tidy. Set up the
232	 * user id/group id/mask as specified by the user. Then, we try to
233	 * fill in the filesystem stats structure as best we can with
234	 * whatever applies from a dos file system.
235	 */
236	pmp = (struct msdosfsmount *) mp->mnt_data;
237	copyinstr(path, (caddr_t) mp->mnt_stat.f_mntonname,
238	    sizeof(mp->mnt_stat.f_mntonname) - 1, &size);
239	bzero(mp->mnt_stat.f_mntonname + size,
240	    sizeof(mp->mnt_stat.f_mntonname) - size);
241	copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
242	bzero(mp->mnt_stat.f_mntfromname + size,
243	    MNAMELEN - size);
244	pmp->pm_mounter = p->p_cred->p_ruid;
245	pmp->pm_gid = args.gid;
246	pmp->pm_uid = args.uid;
247	pmp->pm_mask = args.mask;
248	(void) msdosfs_statfs(mp, &mp->mnt_stat, p);
249#ifdef MSDOSFS_DEBUG
250	printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap);
251#endif
252	return 0;
253}
254
255static int
256mountmsdosfs(devvp, mp, p)
257	struct vnode *devvp;
258	struct mount *mp;
259	struct proc *p;
260{
261	int i;
262	int bpc;
263	int bit;
264	int error;
265	int needclose;
266	int ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
267	dev_t dev = devvp->v_rdev;
268	union bootsector *bsp;
269	struct msdosfsmount *pmp = NULL;
270	struct buf *bp0 = NULL;
271	struct byte_bpb33 *b33;
272	struct byte_bpb50 *b50;
273#ifdef	PC98
274	u_int	pc98_wrk;
275	u_int	Phy_Sector_Size;
276#endif
277
278	/*
279	 * Multiple mounts of the same block special file aren't allowed.
280	 * Make sure no one else has the special file open.  And flush any
281	 * old buffers from this filesystem.  Presumably this prevents us
282	 * from running into buffers that are the wrong blocksize.
283	 */
284	error = vfs_mountedon(devvp);
285	if (error)
286		return error;
287	if (vcount(devvp) > 1)
288		return EBUSY;
289	error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
290	if (error)
291		return error;
292
293	/*
294	 * Now open the block special file.
295	 */
296	error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE, FSCRED, p);
297	if (error)
298		return error;
299	needclose = 1;
300#ifdef HDSUPPORT
301	/*
302	 * Put this in when we support reading dos filesystems from
303	 * partitioned harddisks.
304	 */
305	if (VOP_IOCTL(devvp, DIOCGPART, &msdosfspart, FREAD, NOCRED, p) == 0) {
306	}
307#endif
308
309	/*
310	 * Read the boot sector of the filesystem, and then check the boot
311	 * signature.  If not a dos boot sector then error out.  We could
312	 * also add some checking on the bsOemName field.  So far I've seen
313	 * the following values: "IBM  3.3" "MSDOS3.3" "MSDOS5.0"
314	 */
315#ifdef	PC98
316	devvp->v_flag &= 0xffff;
317	error = bread(devvp, 0, 1024, NOCRED, &bp0);
318#else
319	error = bread(devvp, 0, 512, NOCRED, &bp0);
320#endif
321	if (error)
322		goto error_exit;
323	bp0->b_flags |= B_AGE;
324	bsp = (union bootsector *) bp0->b_data;
325	b33 = (struct byte_bpb33 *) bsp->bs33.bsBPB;
326	b50 = (struct byte_bpb50 *) bsp->bs50.bsBPB;
327#ifdef MSDOSFS_CHECKSIG
328#ifdef	PC98
329	if (bsp->bs50.bsBootSectSig != BOOTSIG &&
330	    bsp->bs50.bsBootSectSig != 0 &&		/* PC98 DOS 3.3x */
331	    bsp->bs50.bsBootSectSig != 15760 &&		/* PC98 DOS 5.0	 */
332	    bsp->bs50.bsBootSectSig != 64070) {		/* PC98 DOS 3.3B */
333#else
334	if (bsp->bs50.bsBootSectSig != BOOTSIG) {
335#endif
336		error = EINVAL;
337		goto error_exit;
338	}
339#endif
340	if ( bsp->bs50.bsJump[0] != 0xe9 &&
341	    (bsp->bs50.bsJump[0] != 0xeb || bsp->bs50.bsJump[2] != 0x90)) {
342		error = EINVAL;
343		goto error_exit;
344	}
345
346	pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK);
347	bzero((caddr_t)pmp, sizeof *pmp);
348	pmp->pm_mountp = mp;
349
350	/*
351	 * Compute several useful quantities from the bpb in the
352	 * bootsector.  Copy in the dos 5 variant of the bpb then fix up
353	 * the fields that are different between dos 5 and dos 3.3.
354	 */
355	pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
356	pmp->pm_SectPerClust = b50->bpbSecPerClust;
357	pmp->pm_ResSectors = getushort(b50->bpbResSectors);
358	pmp->pm_FATs = b50->bpbFATs;
359	pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
360	pmp->pm_Sectors = getushort(b50->bpbSectors);
361	pmp->pm_Media = b50->bpbMedia;
362	pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
363	pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
364	pmp->pm_Heads = getushort(b50->bpbHeads);
365
366	/* XXX - We should probably check more values here */
367    	if (!pmp->pm_BytesPerSec || !pmp->pm_SectPerClust ||
368	    !pmp->pm_Heads || pmp->pm_Heads > 255 ||
369#ifdef PC98
370	    !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) {
371#else
372	    !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) {
373#endif
374		error = EINVAL;
375		goto error_exit;
376	}
377
378	if (pmp->pm_Sectors == 0) {
379		pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
380		pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
381	} else {
382		pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
383		pmp->pm_HugeSectors = pmp->pm_Sectors;
384	}
385#ifdef	PC98	/* for PC98		added Satoshi Yasuda	*/
386	Phy_Sector_Size = 512;
387	if ((devvp->v_rdev>>8) == 2) {	/* floppy check */
388		if (((devvp->v_rdev&077) == 2) && (pmp->pm_HugeSectors == 1232)) {
389				Phy_Sector_Size = 1024;	/* 2HD */
390				/*
391				 * 1024byte/sector support
392				 */
393				devvp->v_flag |= 0x10000;
394		} else {
395			if ((((devvp->v_rdev&077) == 3)	/* 2DD 8 or 9 sector */
396				&& (pmp->pm_HugeSectors == 1440)) /* 9 sector */
397				|| (((devvp->v_rdev&077) == 4)
398				&& (pmp->pm_HugeSectors == 1280)) /* 8 sector */
399				|| (((devvp->v_rdev&077) == 5)
400				&& (pmp->pm_HugeSectors == 2880))) { /* 1.44M */
401					Phy_Sector_Size = 512;
402			} else {
403				if (((devvp->v_rdev&077) != 1)
404				    && ((devvp->v_rdev&077) != 0)) { /* 2HC */
405					error = EINVAL;
406					goto error_exit;
407				}
408			}
409		}
410	}
411	pc98_wrk = pmp->pm_BytesPerSec / Phy_Sector_Size;
412	pmp->pm_BytesPerSec = Phy_Sector_Size;
413	pmp->pm_SectPerClust = pmp->pm_SectPerClust * pc98_wrk;
414	pmp->pm_HugeSectors = pmp->pm_HugeSectors * pc98_wrk;
415	pmp->pm_ResSectors = pmp->pm_ResSectors * pc98_wrk;
416	pmp->pm_FATsecs = pmp->pm_FATsecs * pc98_wrk;
417	pmp->pm_SecPerTrack = pmp->pm_SecPerTrack * pc98_wrk;
418	pmp->pm_HiddenSects = pmp->pm_HiddenSects * pc98_wrk;
419#endif			/*						*/
420	pmp->pm_fatblk = pmp->pm_ResSectors;
421	pmp->pm_rootdirblk = pmp->pm_fatblk +
422	    (pmp->pm_FATs * pmp->pm_FATsecs);
423	pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry))
424	    /
425	    pmp->pm_BytesPerSec;/* in sectors */
426	pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
427	pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
428	    pmp->pm_SectPerClust;
429	pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1;
430	pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec;
431	if (FAT12(pmp))
432		/*
433		 * This will usually be a floppy disk. This size makes sure
434		 * that one fat entry will not be split across multiple
435		 * blocks.
436		 */
437		pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
438	else
439		/*
440		 * This will usually be a hard disk. Reading or writing one
441		 * block should be quite fast.
442		 */
443		pmp->pm_fatblocksize = MAXBSIZE;
444	pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec;
445
446
447	if ((pmp->pm_rootdirsize % pmp->pm_SectPerClust) != 0)
448		printf("mountmsdosfs(): Warning: root directory is not a multiple of the clustersize in length\n");
449
450	/*
451	 * Compute mask and shift value for isolating cluster relative byte
452	 * offsets and cluster numbers from a file offset.
453	 */
454	bpc = pmp->pm_SectPerClust * pmp->pm_BytesPerSec;
455	pmp->pm_bpcluster = bpc;
456	pmp->pm_depclust = bpc / sizeof(struct direntry);
457	pmp->pm_crbomask = bpc - 1;
458	if (bpc == 0) {
459		error = EINVAL;
460		goto error_exit;
461	}
462	bit = 1;
463	for (i = 0; i < 32; i++) {
464		if (bit & bpc) {
465			if (bit ^ bpc) {
466				error = EINVAL;
467				goto error_exit;
468			}
469			pmp->pm_cnshift = i;
470			break;
471		}
472		bit <<= 1;
473	}
474
475#ifdef	PC98
476	if (Phy_Sector_Size == 512) {
477		pmp->pm_brbomask = 0x01ff;	/* 512 byte blocks only (so far) */
478		pmp->pm_bnshift = 9;	/* shift right 9 bits to get bn */
479	} else {
480		pmp->pm_brbomask = 0x03ff;
481		pmp->pm_bnshift = 10;
482	}
483#else
484	pmp->pm_brbomask = 0x01ff;	/* 512 byte blocks only (so far) */
485	pmp->pm_bnshift = 9;	/* shift right 9 bits to get bn */
486#endif
487
488	/*
489	 * Release the bootsector buffer.
490	 */
491	brelse(bp0);
492	bp0 = NULL;
493
494	/*
495	 * Allocate memory for the bitmap of allocated clusters, and then
496	 * fill it in.
497	 */
498	pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS - 1)
499				   / N_INUSEBITS)
500				  * sizeof(*pmp->pm_inusemap),
501				  M_MSDOSFSFAT, M_WAITOK);
502
503	/*
504	 * fillinusemap() needs pm_devvp.
505	 */
506	pmp->pm_dev = dev;
507	pmp->pm_devvp = devvp;
508
509	/*
510	 * Have the inuse map filled in.
511	 */
512	error = fillinusemap(pmp);
513	if (error)
514		goto error_exit;
515
516	/*
517	 * If they want fat updates to be synchronous then let them suffer
518	 * the performance degradation in exchange for the on disk copy of
519	 * the fat being correct just about all the time.  I suppose this
520	 * would be a good thing to turn on if the kernel is still flakey.
521	 */
522	pmp->pm_waitonfat = mp->mnt_flag & MNT_SYNCHRONOUS;
523
524	/*
525	 * Finish up.
526	 */
527	pmp->pm_ronly = ronly;
528	if (ronly == 0)
529		pmp->pm_fmod = 1;
530	mp->mnt_data = (qaddr_t) pmp;
531	mp->mnt_stat.f_fsid.val[0] = (long)dev;
532	mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
533	mp->mnt_flag |= MNT_LOCAL;
534	devvp->v_specflags |= SI_MOUNTEDON;
535
536	return 0;
537
538error_exit:;
539	if (bp0)
540		brelse(bp0);
541	if (needclose)
542		(void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE,
543		    NOCRED, p);
544	if (pmp) {
545		if (pmp->pm_inusemap)
546			free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT);
547		free((caddr_t) pmp, M_MSDOSFSMNT);
548		mp->mnt_data = (qaddr_t) 0;
549	}
550	return error;
551}
552
553static int
554msdosfs_start(mp, flags, p)
555	struct mount *mp;
556	int flags;
557	struct proc *p;
558{
559	return 0;
560}
561
562/*
563 * Unmount the filesystem described by mp.
564 */
565static int
566msdosfs_unmount(mp, mntflags, p)
567	struct mount *mp;
568	int mntflags;
569	struct proc *p;
570{
571	int flags = 0;
572	int error;
573	struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data;
574
575	/* only the mounter, or superuser can unmount */
576	if ((p->p_cred->p_ruid != pmp->pm_mounter) &&
577	    (error = suser(p->p_ucred, &p->p_acflag)))
578		return error;
579
580	if (mntflags & MNT_FORCE) {
581		flags |= FORCECLOSE;
582	}
583	error = vflush(mp, NULLVP, flags);
584	if (error)
585		return error;
586	pmp->pm_devvp->v_specflags &= ~SI_MOUNTEDON;
587	error = VOP_CLOSE(pmp->pm_devvp, pmp->pm_ronly ? FREAD : FREAD | FWRITE,
588	    NOCRED, p);
589	vrele(pmp->pm_devvp);
590	free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT);
591	free((caddr_t) pmp, M_MSDOSFSMNT);
592	mp->mnt_data = (qaddr_t) 0;
593	mp->mnt_flag &= ~MNT_LOCAL;
594	return error;
595}
596
597static int
598msdosfs_root(mp, vpp)
599	struct mount *mp;
600	struct vnode **vpp;
601{
602	struct denode *ndep;
603	struct msdosfsmount *pmp = (struct msdosfsmount *) (mp->mnt_data);
604	int error;
605
606	error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, NULL, &ndep);
607#ifdef MSDOSFS_DEBUG
608	printf("msdosfs_root(); mp %p, pmp %p, ndep %p, vp %p\n",
609	    mp, pmp, ndep, DETOV(ndep));
610#endif
611	if (error == 0)
612		*vpp = DETOV(ndep);
613	return error;
614}
615
616static int
617msdosfs_quotactl(mp, cmds, uid, arg, p)
618	struct mount *mp;
619	int cmds;
620	uid_t uid;
621	caddr_t arg;
622	struct proc *p;
623{
624	return EOPNOTSUPP;
625}
626
627static int
628msdosfs_statfs(mp, sbp, p)
629	struct mount *mp;
630	struct statfs *sbp;
631	struct proc *p;
632{
633	struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data;
634
635	/*
636	 * Fill in the stat block.
637	 */
638	sbp->f_bsize = pmp->pm_bpcluster;
639	sbp->f_iosize = pmp->pm_bpcluster;
640	sbp->f_blocks = pmp->pm_nmbrofclusters;
641	sbp->f_bfree = pmp->pm_freeclustercount;
642	sbp->f_bavail = pmp->pm_freeclustercount;
643	sbp->f_files = pmp->pm_RootDirEnts;			/* XXX */
644	sbp->f_ffree = 0;	/* what to put in here? */
645
646	/*
647	 * Copy the mounted on and mounted from names into the passed in
648	 * stat block, if it is not the one in the mount structure.
649	 */
650	if (sbp != &mp->mnt_stat) {
651		sbp->f_type = mp->mnt_vfc->vfc_typenum;
652		bcopy((caddr_t) mp->mnt_stat.f_mntonname,
653		    (caddr_t) & sbp->f_mntonname[0], MNAMELEN);
654		bcopy((caddr_t) mp->mnt_stat.f_mntfromname,
655		    (caddr_t) & sbp->f_mntfromname[0], MNAMELEN);
656	}
657#if 0
658	strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN);
659	sbp->f_fstypename[MFSNAMELEN] = '\0';
660#endif
661	return 0;
662}
663
664static int
665msdosfs_sync(mp, waitfor, cred, p)
666	struct mount *mp;
667	int waitfor;
668	struct ucred *cred;
669	struct proc *p;
670{
671	struct vnode *vp;
672	struct denode *dep;
673	struct msdosfsmount *pmp;
674	int error;
675	int allerror = 0;
676
677	pmp = (struct msdosfsmount *) mp->mnt_data;
678
679	/*
680	 * If we ever switch to not updating all of the fats all the time,
681	 * this would be the place to update them from the first one.
682	 */
683	if (pmp->pm_fmod)
684		if (pmp->pm_ronly)
685			panic("msdosfs_sync: rofs mod");
686		else {
687			/* update fats here */
688		}
689
690	/*
691	 * Go thru in memory denodes and write them out along with
692	 * unwritten file blocks.
693	 */
694	simple_lock(&mntvnode_slock);
695loop:
696	for (vp = mp->mnt_vnodelist.lh_first; vp;
697	    vp = vp->v_mntvnodes.le_next) {
698		if (vp->v_mount != mp)	/* not ours anymore	 */
699			goto loop;
700		simple_lock(&vp->v_interlock);
701		dep = VTODE(vp);
702		if ((dep->de_flag & (DE_MODIFIED | DE_UPDATE)) == 0 &&
703		    vp->v_dirtyblkhd.lh_first == NULL) {
704			simple_unlock(&vp->v_interlock);
705			continue;
706		}
707		simple_unlock(&mntvnode_slock);
708		error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
709		if (error) {
710			simple_lock(&mntvnode_slock);
711			if (error == ENOENT)
712				goto loop;
713			continue;
714		}
715		error = VOP_FSYNC(vp, cred, waitfor, p);
716		if (error)
717			allerror = error;
718		VOP_UNLOCK(vp, 0, p);
719		vrele(vp);	/* done with this one	 */
720		simple_lock(&mntvnode_slock);
721	}
722	simple_unlock(&mntvnode_slock);
723
724	/*
725	 * Flush filesystem control info.
726	 */
727	error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p);
728	if (error)
729		allerror = error;
730	return allerror;
731}
732
733static int
734msdosfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
735	struct mount *mp;
736	struct fid *fhp;
737	struct sockaddr *nam;
738	struct vnode **vpp;
739	int *exflagsp;
740	struct ucred **credanonp;
741{
742	struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data;
743	struct defid *defhp = (struct defid *) fhp;
744	struct denode *dep;
745	struct netcred *np;
746	int error;
747
748	np = vfs_export_lookup(mp, &pmp->pm_export, nam);
749	if (np == NULL)
750		return EACCES;
751	error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs,
752	    NULL, &dep);
753	if (error) {
754		*vpp = NULLVP;
755		return error;
756	}
757	*vpp = DETOV(dep);
758	*exflagsp = np->netc_exflags;
759	*credanonp = &np->netc_anon;
760	return 0;
761}
762
763
764static int
765msdosfs_vptofh(vp, fhp)
766	struct vnode *vp;
767	struct fid *fhp;
768{
769	struct denode *dep = VTODE(vp);
770	struct defid *defhp = (struct defid *) fhp;
771
772	defhp->defid_len = sizeof(struct defid);
773	defhp->defid_dirclust = dep->de_dirclust;
774	defhp->defid_dirofs = dep->de_diroffset;
775	/* defhp->defid_gen = ip->i_gen; */
776	return 0;
777}
778
779static int
780msdosfs_vget(mp, ino, vpp)
781	struct mount *mp;
782	ino_t ino;
783	struct vnode **vpp;
784{
785	return EOPNOTSUPP;
786}
787
788static struct vfsops msdosfs_vfsops = {
789	msdosfs_mount,
790	msdosfs_start,
791	msdosfs_unmount,
792	msdosfs_root,
793	msdosfs_quotactl,
794	msdosfs_statfs,
795	msdosfs_sync,
796	msdosfs_vget,
797	msdosfs_fhtovp,
798	msdosfs_vptofh,
799	msdosfs_init
800};
801
802VFS_SET(msdosfs_vfsops, msdos, MOUNT_MSDOS, 0);
803