1 /* $FreeBSD: /usr/local/www/cvsroot/FreeBSD/src/sys/msdosfs/Attic/msdosfs_vfsops.c,v 1.60.2.8 2004/03/02 09:43:04 tjr Exp $ */
2 /* $DragonFly: src/sys/vfs/msdosfs/msdosfs_vfsops.c,v 1.51.2.1 2008/09/25 02:20:52 dillon Exp $ */
3 /* $NetBSD: msdosfs_vfsops.c,v 1.51 1997/11/17 15:36:58 ws Exp $ */
6 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
7 * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
9 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by TooLs GmbH.
22 * 4. The name of TooLs GmbH may not be used to endorse or promote products
23 * derived from this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
31 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
33 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
34 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 * Written by Paul Popelka (paulp@uts.amdahl.com)
39 * You can do anything you want with this software, just don't say you wrote
40 * it, and don't remove this notice.
42 * This software is provided "as is".
44 * The author supplies this software to be publicly redistributed on the
45 * understanding that the author is not responsible for the correct
46 * functioning of this software in any circumstances and is not liable for
47 * any damages caused by this software.
52 #include <sys/param.h>
53 #include <sys/systm.h>
56 #include <sys/nlookup.h>
57 #include <sys/kernel.h>
58 #include <sys/vnode.h>
59 #include <sys/mount.h>
61 #include <sys/fcntl.h>
62 #include <sys/malloc.h>
63 #include <sys/stat.h> /* defines ALLPERMS */
64 #include <vm/vm_zone.h>
70 #include "msdosfsmount.h"
73 extern struct vop_ops msdosfs_vnode_vops
;
75 #define MSDOSFS_DFLTBSIZE 4096
79 * XXX - The boot signature formatted by NEC PC-98 DOS looks like a
80 * garbage or a random value :-{
81 * If you want to use that broken-signatured media, define the
82 * following symbol even though PC/AT.
83 * (ex. mount PC-98 DOS formatted FD on PC/AT)
85 #define MSDOSFS_NOCHECKSIG
88 MALLOC_DEFINE(M_MSDOSFSMNT
, "MSDOSFS mount", "MSDOSFS mount structure");
89 static MALLOC_DEFINE(M_MSDOSFSFAT
, "MSDOSFS FAT", "MSDOSFS file allocation table");
91 static int update_mp (struct mount
*mp
, struct msdosfs_args
*argp
);
92 static int mountmsdosfs (struct vnode
*devvp
, struct mount
*mp
,
93 struct msdosfs_args
*argp
);
94 static int msdosfs_fhtovp (struct mount
*, struct vnode
*,
95 struct fid
*, struct vnode
**);
96 static int msdosfs_checkexp (struct mount
*, struct sockaddr
*,
97 int *, struct ucred
**);
98 static int msdosfs_mount (struct mount
*, char *, caddr_t
,
100 static int msdosfs_root (struct mount
*, struct vnode
**);
101 static int msdosfs_statfs (struct mount
*, struct statfs
*,
103 static int msdosfs_sync (struct mount
*, int);
104 static int msdosfs_unmount (struct mount
*, int);
105 static int msdosfs_vptofh (struct vnode
*, struct fid
*);
108 update_mp(struct mount
*mp
, struct msdosfs_args
*argp
)
110 struct msdosfsmount
*pmp
= VFSTOMSDOSFS(mp
);
113 pmp
->pm_gid
= argp
->gid
;
114 pmp
->pm_uid
= argp
->uid
;
115 pmp
->pm_mask
= argp
->mask
& ALLPERMS
;
116 pmp
->pm_flags
|= argp
->flags
& MSDOSFSMNT_MNTOPT
;
117 if (pmp
->pm_flags
& MSDOSFSMNT_U2WTABLE
) {
118 bcopy(argp
->u2w
, pmp
->pm_u2w
, sizeof(pmp
->pm_u2w
));
119 bcopy(argp
->d2u
, pmp
->pm_d2u
, sizeof(pmp
->pm_d2u
));
120 bcopy(argp
->u2d
, pmp
->pm_u2d
, sizeof(pmp
->pm_u2d
));
122 if (pmp
->pm_flags
& MSDOSFSMNT_ULTABLE
) {
123 bcopy(argp
->ul
, pmp
->pm_ul
, sizeof(pmp
->pm_ul
));
124 bcopy(argp
->lu
, pmp
->pm_lu
, sizeof(pmp
->pm_lu
));
127 #ifndef __DragonFly__
129 * GEMDOS knows nothing (yet) about win95
131 if (pmp
->pm_flags
& MSDOSFSMNT_GEMDOSFS
)
132 pmp
->pm_flags
|= MSDOSFSMNT_NOWIN95
;
135 if (pmp
->pm_flags
& MSDOSFSMNT_NOWIN95
)
136 pmp
->pm_flags
|= MSDOSFSMNT_SHORTNAME
;
137 else if (!(pmp
->pm_flags
&
138 (MSDOSFSMNT_SHORTNAME
| MSDOSFSMNT_LONGNAME
))) {
139 struct vnode
*rootvp
;
142 * Try to divine whether to support Win'95 long filenames
145 pmp
->pm_flags
|= MSDOSFSMNT_LONGNAME
;
147 if ((error
= msdosfs_root(mp
, &rootvp
)) != 0)
149 pmp
->pm_flags
|= findwin95(VTODE(rootvp
))
150 ? MSDOSFSMNT_LONGNAME
151 : MSDOSFSMNT_SHORTNAME
;
159 * mp - path - addr in user space of mount point (ie /usr or whatever)
160 * data - addr in user space of mount params including the name of the block
161 * special file to treat as a filesystem.
164 msdosfs_mount(struct mount
*mp
, char *path
, caddr_t data
, struct ucred
*cred
)
166 struct vnode
*devvp
; /* vnode for blk device to mount */
167 struct msdosfs_args args
; /* will hold data from mount request */
168 /* msdosfs specific mount control block */
169 struct msdosfsmount
*pmp
= NULL
;
173 struct nlookupdata nd
;
175 error
= copyin(data
, (caddr_t
)&args
, sizeof(struct msdosfs_args
));
178 if (args
.magic
!= MSDOSFS_ARGSMAGIC
)
181 * If updating, check whether changing from read-only to
182 * read/write; if there is no device name, that's all we do.
184 if (mp
->mnt_flag
& MNT_UPDATE
) {
185 pmp
= VFSTOMSDOSFS(mp
);
187 if (!(pmp
->pm_flags
& MSDOSFSMNT_RONLY
) && (mp
->mnt_flag
& MNT_RDONLY
)) {
189 if (mp
->mnt_flag
& MNT_FORCE
)
191 error
= vflush(mp
, 0, flags
);
193 devvp
= pmp
->pm_devvp
;
194 VOP_OPEN(devvp
, FREAD
, FSCRED
, NULL
);
195 VOP_CLOSE(devvp
, FREAD
|FWRITE
);
196 pmp
->pm_flags
|= MSDOSFSMNT_RONLY
;
199 if (!error
&& (mp
->mnt_flag
& MNT_RELOAD
))
200 /* not yet implemented */
204 if ((pmp
->pm_flags
& MSDOSFSMNT_RONLY
) && (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)) {
206 * If upgrade to read-write by non-root, then verify
207 * that user has necessary permissions on the device.
209 devvp
= pmp
->pm_devvp
;
210 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
211 if (cred
->cr_uid
!= 0) {
212 error
= VOP_ACCESS(devvp
, VREAD
| VWRITE
, cred
);
218 VOP_OPEN(devvp
, FREAD
|FWRITE
, FSCRED
, NULL
);
219 VOP_CLOSE(devvp
, FREAD
);
221 pmp
->pm_flags
&= ~MSDOSFSMNT_RONLY
;
223 if (args
.fspec
== 0) {
224 #ifdef __notyet__ /* doesn't work correctly with current mountd XXX */
225 if (args
.flags
& MSDOSFSMNT_MNTOPT
) {
226 pmp
->pm_flags
&= ~MSDOSFSMNT_MNTOPT
;
227 pmp
->pm_flags
|= args
.flags
& MSDOSFSMNT_MNTOPT
;
228 if (pmp
->pm_flags
& MSDOSFSMNT_NOWIN95
)
229 pmp
->pm_flags
|= MSDOSFSMNT_SHORTNAME
;
233 * Process export requests.
235 return (vfs_export(mp
, &pmp
->pm_export
, &args
.export
));
239 * Not an update, or updating the name: look up the name
240 * and verify that it refers to a sensible block device.
243 error
= nlookup_init(&nd
, args
.fspec
, UIO_USERSPACE
, NLC_FOLLOW
);
245 error
= nlookup(&nd
);
247 error
= cache_vref(&nd
.nl_nch
, nd
.nl_cred
, &devvp
);
252 if (!vn_isdisk(devvp
, &error
)) {
257 * If mount by non-root, then verify that user has necessary
258 * permissions on the device.
260 if (cred
->cr_uid
!= 0) {
262 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
263 accessmode
|= VWRITE
;
264 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
265 error
= VOP_ACCESS(devvp
, accessmode
, cred
);
272 if ((mp
->mnt_flag
& MNT_UPDATE
) == 0) {
273 error
= mountmsdosfs(devvp
, mp
, &args
);
274 #ifdef MSDOSFS_DEBUG /* only needed for the kprintf below */
275 pmp
= VFSTOMSDOSFS(mp
);
278 if (devvp
!= pmp
->pm_devvp
)
279 error
= EINVAL
; /* XXX needs translation */
288 error
= update_mp(mp
, &args
);
290 msdosfs_unmount(mp
, MNT_FORCE
);
294 copyinstr(args
.fspec
, mp
->mnt_stat
.f_mntfromname
, MNAMELEN
- 1, &size
);
295 bzero(mp
->mnt_stat
.f_mntfromname
+ size
, MNAMELEN
- size
);
296 msdosfs_statfs(mp
, &mp
->mnt_stat
, cred
);
298 kprintf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp
, pmp
, pmp
->pm_inusemap
);
304 mountmsdosfs(struct vnode
*devvp
, struct mount
*mp
, struct msdosfs_args
*argp
)
306 struct msdosfsmount
*pmp
;
309 union bootsector
*bsp
;
310 struct byte_bpb33
*b33
;
311 struct byte_bpb50
*b50
;
312 struct byte_bpb710
*b710
;
313 u_int8_t SecPerClust
;
318 * Disallow multiple mounts of the same device.
319 * Disallow mounting of a device that is currently in use
320 * Flush out any old buffers remaining from a previous use.
322 error
= vfs_mountedon(devvp
);
325 if (count_udev(devvp
->v_umajor
, devvp
->v_uminor
) > 0)
327 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
328 error
= vinvalbuf(devvp
, V_SAVE
, 0, 0);
333 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
334 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
335 error
= VOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, FSCRED
, NULL
);
340 bp
= NULL
; /* both used in error_exit */
344 * Read the boot sector of the filesystem, and then check the
345 * boot signature. If not a dos boot sector then error out.
347 * NOTE: 2048 is a maximum sector size in current...
349 error
= bread(devvp
, 0, 2048, &bp
);
352 bp
->b_flags
|= B_AGE
;
353 bsp
= (union bootsector
*)bp
->b_data
;
354 b33
= (struct byte_bpb33
*)bsp
->bs33
.bsBPB
;
355 b50
= (struct byte_bpb50
*)bsp
->bs50
.bsBPB
;
356 b710
= (struct byte_bpb710
*)bsp
->bs710
.bsPBP
;
358 #ifndef __DragonFly__
359 if (!(argp
->flags
& MSDOSFSMNT_GEMDOSFS
)) {
361 #ifndef MSDOSFS_NOCHECKSIG
362 if (bsp
->bs50
.bsBootSectSig0
!= BOOTSIG0
363 || bsp
->bs50
.bsBootSectSig1
!= BOOTSIG1
) {
368 #ifndef __DragonFly__
372 pmp
= kmalloc(sizeof *pmp
, M_MSDOSFSMNT
, M_WAITOK
| M_ZERO
);
376 * Compute several useful quantities from the bpb in the
377 * bootsector. Copy in the dos 5 variant of the bpb then fix up
378 * the fields that are different between dos 5 and dos 3.3.
380 SecPerClust
= b50
->bpbSecPerClust
;
381 pmp
->pm_BytesPerSec
= getushort(b50
->bpbBytesPerSec
);
382 pmp
->pm_ResSectors
= getushort(b50
->bpbResSectors
);
383 pmp
->pm_FATs
= b50
->bpbFATs
;
384 pmp
->pm_RootDirEnts
= getushort(b50
->bpbRootDirEnts
);
385 pmp
->pm_Sectors
= getushort(b50
->bpbSectors
);
386 pmp
->pm_FATsecs
= getushort(b50
->bpbFATsecs
);
387 pmp
->pm_SecPerTrack
= getushort(b50
->bpbSecPerTrack
);
388 pmp
->pm_Heads
= getushort(b50
->bpbHeads
);
389 pmp
->pm_Media
= b50
->bpbMedia
;
391 /* calculate the ratio of sector size to DEV_BSIZE */
392 pmp
->pm_BlkPerSec
= pmp
->pm_BytesPerSec
/ DEV_BSIZE
;
394 #ifndef __DragonFly__
395 if (!(argp
->flags
& MSDOSFSMNT_GEMDOSFS
)) {
397 /* XXX - We should probably check more values here */
398 if (!pmp
->pm_BytesPerSec
|| !SecPerClust
400 || !pmp
->pm_SecPerTrack
|| pmp
->pm_SecPerTrack
> 63) {
404 #ifndef __DragonFly__
408 if (pmp
->pm_Sectors
== 0) {
409 pmp
->pm_HiddenSects
= getulong(b50
->bpbHiddenSecs
);
410 pmp
->pm_HugeSectors
= getulong(b50
->bpbHugeSectors
);
412 pmp
->pm_HiddenSects
= getushort(b33
->bpbHiddenSecs
);
413 pmp
->pm_HugeSectors
= pmp
->pm_Sectors
;
416 if (pmp
->pm_RootDirEnts
== 0) {
417 if (bsp
->bs710
.bsBootSectSig2
!= BOOTSIG2
418 || bsp
->bs710
.bsBootSectSig3
!= BOOTSIG3
421 || getushort(b710
->bpbFSVers
)) {
423 kprintf("mountmsdosfs(): bad FAT32 filesystem\n");
426 pmp
->pm_fatmask
= FAT32_MASK
;
429 pmp
->pm_FATsecs
= getulong(b710
->bpbBigFATsecs
);
430 if (getushort(b710
->bpbExtFlags
) & FATMIRROR
)
431 pmp
->pm_curfat
= getushort(b710
->bpbExtFlags
) & FATNUM
;
433 pmp
->pm_flags
|= MSDOSFS_FATMIRROR
;
435 pmp
->pm_flags
|= MSDOSFS_FATMIRROR
;
438 * Check a few values (could do some more):
439 * - logical sector size: power of 2, >= block size
440 * - sectors per cluster: power of 2, >= 1
441 * - number of sectors: >= 1, <= size of partition
443 if ( (SecPerClust
== 0)
444 || (SecPerClust
& (SecPerClust
- 1))
445 || (pmp
->pm_BytesPerSec
< DEV_BSIZE
)
446 || (pmp
->pm_BytesPerSec
& (pmp
->pm_BytesPerSec
- 1))
447 || (pmp
->pm_HugeSectors
== 0)
453 pmp
->pm_HugeSectors
*= pmp
->pm_BlkPerSec
;
454 pmp
->pm_HiddenSects
*= pmp
->pm_BlkPerSec
; /* XXX not used? */
455 pmp
->pm_FATsecs
*= pmp
->pm_BlkPerSec
;
456 SecPerClust
*= pmp
->pm_BlkPerSec
;
458 pmp
->pm_fatblk
= pmp
->pm_ResSectors
* pmp
->pm_BlkPerSec
;
461 pmp
->pm_rootdirblk
= getulong(b710
->bpbRootClust
);
462 pmp
->pm_firstcluster
= pmp
->pm_fatblk
463 + (pmp
->pm_FATs
* pmp
->pm_FATsecs
);
464 pmp
->pm_fsinfo
= getushort(b710
->bpbFSInfo
) * pmp
->pm_BlkPerSec
;
466 pmp
->pm_rootdirblk
= pmp
->pm_fatblk
+
467 (pmp
->pm_FATs
* pmp
->pm_FATsecs
);
468 pmp
->pm_rootdirsize
= (pmp
->pm_RootDirEnts
* sizeof(struct direntry
)
470 / DEV_BSIZE
; /* in blocks */
471 pmp
->pm_firstcluster
= pmp
->pm_rootdirblk
+ pmp
->pm_rootdirsize
;
474 pmp
->pm_maxcluster
= (pmp
->pm_HugeSectors
- pmp
->pm_firstcluster
) /
476 pmp
->pm_fatsize
= pmp
->pm_FATsecs
* DEV_BSIZE
; /* XXX not used? */
478 #ifndef __DragonFly__
479 if (argp
->flags
& MSDOSFSMNT_GEMDOSFS
) {
480 if ((pmp
->pm_maxcluster
<= (0xff0 - 2))
481 && ((dtype
== DTYPE_FLOPPY
) || ((dtype
== DTYPE_VNODE
)
482 && ((pmp
->pm_Heads
== 1) || (pmp
->pm_Heads
== 2))))
484 pmp
->pm_fatmask
= FAT12_MASK
;
488 pmp
->pm_fatmask
= FAT16_MASK
;
494 if (pmp
->pm_fatmask
== 0) {
495 if (pmp
->pm_maxcluster
496 <= ((CLUST_RSRVD
- CLUST_FIRST
) & FAT12_MASK
)) {
498 * This will usually be a floppy disk. This size makes
499 * sure that one fat entry will not be split across
502 pmp
->pm_fatmask
= FAT12_MASK
;
506 pmp
->pm_fatmask
= FAT16_MASK
;
512 clusters
= (pmp
->pm_fatsize
/ pmp
->pm_fatmult
) * pmp
->pm_fatdiv
;
513 if (pmp
->pm_maxcluster
>= clusters
) {
514 kprintf("Warning: number of clusters (%ld) exceeds FAT "
515 "capacity (%ld)\n", pmp
->pm_maxcluster
+ 1, clusters
);
516 pmp
->pm_maxcluster
= clusters
- 1;
521 pmp
->pm_fatblocksize
= 3 * pmp
->pm_BytesPerSec
;
523 pmp
->pm_fatblocksize
= MSDOSFS_DFLTBSIZE
;
525 pmp
->pm_fatblocksec
= pmp
->pm_fatblocksize
/ DEV_BSIZE
;
526 pmp
->pm_bnshift
= DEV_BSHIFT
;
529 * Compute mask and shift value for isolating cluster relative byte
530 * offsets and cluster numbers from a file offset.
532 pmp
->pm_bpcluster
= SecPerClust
* DEV_BSIZE
;
533 pmp
->pm_crbomask
= pmp
->pm_bpcluster
- 1;
534 pmp
->pm_cnshift
= ffs(pmp
->pm_bpcluster
) - 1;
537 * Check for valid cluster size
538 * must be a power of 2
540 if (pmp
->pm_bpcluster
^ (1 << pmp
->pm_cnshift
)) {
546 * Release the bootsector buffer.
554 if (pmp
->pm_fsinfo
) {
557 if ((error
= bread(devvp
, de_bntodoff(pmp
, pmp
->pm_fsinfo
), fsi_size(pmp
), &bp
)) != 0)
559 fp
= (struct fsinfo
*)bp
->b_data
;
560 if (!bcmp(fp
->fsisig1
, "RRaA", 4)
561 && !bcmp(fp
->fsisig2
, "rrAa", 4)
562 && !bcmp(fp
->fsisig3
, "\0\0\125\252", 4)
563 && !bcmp(fp
->fsisig4
, "\0\0\125\252", 4)) {
564 pmp
->pm_nxtfree
= getulong(fp
->fsinxtfree
);
565 if (pmp
->pm_nxtfree
== 0xffffffff)
566 pmp
->pm_nxtfree
= CLUST_FIRST
;
574 * Check and validate (or perhaps invalidate?) the fsinfo structure?
576 if (pmp
->pm_fsinfo
&& pmp
->pm_nxtfree
> pmp
->pm_maxcluster
) {
578 "Next free cluster in FSInfo (%lu) exceeds maxcluster (%lu)\n",
579 pmp
->pm_nxtfree
, pmp
->pm_maxcluster
);
585 * Allocate memory for the bitmap of allocated clusters, and then
588 pmp
->pm_inusemap
= kmalloc(((pmp
->pm_maxcluster
+ N_INUSEBITS
- 1)
590 * sizeof(*pmp
->pm_inusemap
),
591 M_MSDOSFSFAT
, M_WAITOK
);
594 * fillinusemap() needs pm_devvp.
597 pmp
->pm_devvp
= devvp
;
600 * Have the inuse map filled in.
602 if ((error
= fillinusemap(pmp
)) != 0)
606 * If they want fat updates to be synchronous then let them suffer
607 * the performance degradation in exchange for the on disk copy of
608 * the fat being correct just about all the time. I suppose this
609 * would be a good thing to turn on if the kernel is still flakey.
611 if (mp
->mnt_flag
& MNT_SYNCHRONOUS
)
612 pmp
->pm_flags
|= MSDOSFSMNT_WAITONFAT
;
618 pmp
->pm_flags
|= MSDOSFSMNT_RONLY
;
621 mp
->mnt_data
= (qaddr_t
) pmp
;
622 mp
->mnt_stat
.f_fsid
.val
[0] = dev2udev(dev
);
623 mp
->mnt_stat
.f_fsid
.val
[1] = mp
->mnt_vfc
->vfc_typenum
;
624 mp
->mnt_flag
|= MNT_LOCAL
;
625 vfs_add_vnodeops(mp
, &msdosfs_vnode_vops
, &mp
->mnt_vn_norm_ops
);
626 dev
->si_mountpoint
= mp
;
633 VOP_CLOSE(devvp
, ronly
? FREAD
: FREAD
| FWRITE
);
635 if (pmp
->pm_inusemap
)
636 kfree(pmp
->pm_inusemap
, M_MSDOSFSFAT
);
637 kfree(pmp
, M_MSDOSFSMNT
);
638 mp
->mnt_data
= (qaddr_t
)0;
644 * Unmount the filesystem described by mp.
647 msdosfs_unmount(struct mount
*mp
, int mntflags
)
649 struct msdosfsmount
*pmp
;
653 if (mntflags
& MNT_FORCE
)
655 error
= vflush(mp
, 0, flags
);
658 pmp
= VFSTOMSDOSFS(mp
);
659 pmp
->pm_devvp
->v_rdev
->si_mountpoint
= NULL
;
662 struct vnode
*vp
= pmp
->pm_devvp
;
664 kprintf("msdosfs_umount(): just before calling VOP_CLOSE()\n");
665 kprintf("flag %08x, sysrefs %d, writecount %d, auxrefs %d\n",
666 vp
->v_flag
, vp
->v_sysref
.refcnt
,
667 vp
->v_writecount
, vp
->v_auxrefs
);
668 kprintf("mount %p, op %p\n", vp
->v_mount
, vp
->v_ops
);
669 kprintf("mount %p\n", vp
->v_mount
);
670 kprintf("cleanblkhd %p, dirtyblkhd %p, numoutput %d, type %d\n",
671 RB_ROOT(&vp
->v_rbclean_tree
),
672 RB_ROOT(&vp
->v_rbdirty_tree
),
673 vp
->v_track_write
.bk_active
, vp
->v_type
);
674 kprintf("union %p, tag %d, data[0] %08x, data[1] %08x\n",
675 vp
->v_socket
, vp
->v_tag
,
676 ((u_int
*)vp
->v_data
)[0],
677 ((u_int
*)vp
->v_data
)[1]);
680 error
= VOP_CLOSE(pmp
->pm_devvp
,
681 (pmp
->pm_flags
&MSDOSFSMNT_RONLY
) ? FREAD
: FREAD
| FWRITE
);
682 vrele(pmp
->pm_devvp
);
683 kfree(pmp
->pm_inusemap
, M_MSDOSFSFAT
);
684 kfree(pmp
, M_MSDOSFSMNT
);
685 mp
->mnt_data
= (qaddr_t
)0;
686 mp
->mnt_flag
&= ~MNT_LOCAL
;
691 msdosfs_root(struct mount
*mp
, struct vnode
**vpp
)
693 struct msdosfsmount
*pmp
= VFSTOMSDOSFS(mp
);
698 kprintf("msdosfs_root(); mp %p, pmp %p\n", mp
, pmp
);
700 error
= deget(pmp
, MSDOSFSROOT
, MSDOSFSROOT_OFS
, &ndep
);
708 msdosfs_statfs(struct mount
*mp
, struct statfs
*sbp
, struct ucred
*cred
)
710 struct msdosfsmount
*pmp
;
712 pmp
= VFSTOMSDOSFS(mp
);
713 sbp
->f_bsize
= pmp
->pm_bpcluster
;
714 sbp
->f_iosize
= pmp
->pm_bpcluster
;
715 sbp
->f_blocks
= pmp
->pm_maxcluster
+ 1;
716 sbp
->f_bfree
= pmp
->pm_freeclustercount
;
717 sbp
->f_bavail
= pmp
->pm_freeclustercount
;
718 sbp
->f_files
= pmp
->pm_RootDirEnts
; /* XXX */
719 sbp
->f_ffree
= 0; /* what to put in here? */
720 if (sbp
!= &mp
->mnt_stat
) {
721 sbp
->f_type
= mp
->mnt_vfc
->vfc_typenum
;
722 bcopy(mp
->mnt_stat
.f_mntfromname
, sbp
->f_mntfromname
, MNAMELEN
);
724 strncpy(sbp
->f_fstypename
, mp
->mnt_vfc
->vfc_name
, MFSNAMELEN
);
734 static int msdosfs_sync_scan(struct mount
*mp
, struct vnode
*vp
, void *data
);
737 msdosfs_sync(struct mount
*mp
, int waitfor
)
739 struct msdosfsmount
*pmp
= VFSTOMSDOSFS(mp
);
740 struct scaninfo scaninfo
;
744 * If we ever switch to not updating all of the fats all the time,
745 * this would be the place to update them from the first one.
747 if (pmp
->pm_fmod
!= 0) {
748 if (pmp
->pm_flags
& MSDOSFSMNT_RONLY
)
749 panic("msdosfs_sync: rofs mod");
751 /* update fats here */
755 * Write back each (modified) denode.
757 scaninfo
.allerror
= 0;
759 while (scaninfo
.rescan
) {
761 vmntvnodescan(mp
, VMSC_GETVP
|VMSC_NOWAIT
, NULL
, msdosfs_sync_scan
, &scaninfo
);
765 * Flush filesystem control info.
767 if (waitfor
!= MNT_LAZY
) {
768 vn_lock(pmp
->pm_devvp
, LK_EXCLUSIVE
| LK_RETRY
);
769 if ((error
= VOP_FSYNC(pmp
->pm_devvp
, waitfor
)) != 0)
770 scaninfo
.allerror
= error
;
771 vn_unlock(pmp
->pm_devvp
);
773 return (scaninfo
.allerror
);
777 msdosfs_sync_scan(struct mount
*mp
, struct vnode
*vp
, void *data
)
779 struct scaninfo
*info
= data
;
784 if (vp
->v_type
== VNON
|| vp
->v_type
== VBAD
||
786 (DE_ACCESS
| DE_CREATE
| DE_UPDATE
| DE_MODIFIED
)) == 0 &&
787 (RB_EMPTY(&vp
->v_rbdirty_tree
) || info
->waitfor
== MNT_LAZY
))) {
790 if ((error
= VOP_FSYNC(vp
, info
->waitfor
)) != 0)
791 info
->allerror
= error
;
796 msdosfs_fhtovp(struct mount
*mp
, struct vnode
*rootvp
,
797 struct fid
*fhp
, struct vnode
**vpp
)
799 struct msdosfsmount
*pmp
= VFSTOMSDOSFS(mp
);
800 struct defid
*defhp
= (struct defid
*) fhp
;
804 error
= deget(pmp
, defhp
->defid_dirclust
, defhp
->defid_dirofs
, &dep
);
814 msdosfs_checkexp(struct mount
*mp
, struct sockaddr
*nam
, int *exflagsp
,
815 struct ucred
**credanonp
)
817 struct msdosfsmount
*pmp
= VFSTOMSDOSFS(mp
);
820 np
= vfs_export_lookup(mp
, &pmp
->pm_export
, nam
);
823 *exflagsp
= np
->netc_exflags
;
824 *credanonp
= &np
->netc_anon
;
829 msdosfs_vptofh(struct vnode
*vp
, struct fid
*fhp
)
835 defhp
= (struct defid
*)fhp
;
836 defhp
->defid_len
= sizeof(struct defid
);
837 defhp
->defid_dirclust
= dep
->de_dirclust
;
838 defhp
->defid_dirofs
= dep
->de_diroffset
;
839 /* defhp->defid_gen = dep->de_gen; */
843 static struct vfsops msdosfs_vfsops
= {
844 .vfs_mount
= msdosfs_mount
,
845 .vfs_unmount
= msdosfs_unmount
,
846 .vfs_root
= msdosfs_root
,
847 .vfs_statfs
= msdosfs_statfs
,
848 .vfs_sync
= msdosfs_sync
,
849 .vfs_fhtovp
= msdosfs_fhtovp
,
850 .vfs_checkexp
= msdosfs_checkexp
,
851 .vfs_vptofh
= msdosfs_vptofh
,
852 .vfs_init
= msdosfs_init
,
853 .vfs_uninit
= msdosfs_uninit
856 VFS_SET(msdosfs_vfsops
, msdos
, 0);