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