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.48 2007/08/07 20:05:30 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 fid
*,
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 if (!error
&& (mp
->mnt_flag
& MNT_RELOAD
))
194 /* not yet implemented */
198 if ((pmp
->pm_flags
& MSDOSFSMNT_RONLY
) && (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)) {
200 * If upgrade to read-write by non-root, then verify
201 * that user has necessary permissions on the device.
203 if (cred
->cr_uid
!= 0) {
204 devvp
= pmp
->pm_devvp
;
205 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
206 error
= VOP_ACCESS(devvp
, VREAD
| VWRITE
, cred
);
213 pmp
->pm_flags
&= ~MSDOSFSMNT_RONLY
;
215 if (args
.fspec
== 0) {
216 #ifdef __notyet__ /* doesn't work correctly with current mountd XXX */
217 if (args
.flags
& MSDOSFSMNT_MNTOPT
) {
218 pmp
->pm_flags
&= ~MSDOSFSMNT_MNTOPT
;
219 pmp
->pm_flags
|= args
.flags
& MSDOSFSMNT_MNTOPT
;
220 if (pmp
->pm_flags
& MSDOSFSMNT_NOWIN95
)
221 pmp
->pm_flags
|= MSDOSFSMNT_SHORTNAME
;
225 * Process export requests.
227 return (vfs_export(mp
, &pmp
->pm_export
, &args
.export
));
231 * Not an update, or updating the name: look up the name
232 * and verify that it refers to a sensible block device.
235 error
= nlookup_init(&nd
, args
.fspec
, UIO_USERSPACE
, NLC_FOLLOW
);
237 error
= nlookup(&nd
);
239 error
= cache_vref(&nd
.nl_nch
, nd
.nl_cred
, &devvp
);
244 if (!vn_isdisk(devvp
, &error
)) {
249 * If mount by non-root, then verify that user has necessary
250 * permissions on the device.
252 if (cred
->cr_uid
!= 0) {
254 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
255 accessmode
|= VWRITE
;
256 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
257 error
= VOP_ACCESS(devvp
, accessmode
, cred
);
264 if ((mp
->mnt_flag
& MNT_UPDATE
) == 0) {
265 error
= mountmsdosfs(devvp
, mp
, &args
);
266 #ifdef MSDOSFS_DEBUG /* only needed for the kprintf below */
267 pmp
= VFSTOMSDOSFS(mp
);
270 if (devvp
!= pmp
->pm_devvp
)
271 error
= EINVAL
; /* XXX needs translation */
280 error
= update_mp(mp
, &args
);
282 msdosfs_unmount(mp
, MNT_FORCE
);
286 copyinstr(args
.fspec
, mp
->mnt_stat
.f_mntfromname
, MNAMELEN
- 1, &size
);
287 bzero(mp
->mnt_stat
.f_mntfromname
+ size
, MNAMELEN
- size
);
288 msdosfs_statfs(mp
, &mp
->mnt_stat
, cred
);
290 kprintf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp
, pmp
, pmp
->pm_inusemap
);
296 mountmsdosfs(struct vnode
*devvp
, struct mount
*mp
, struct msdosfs_args
*argp
)
298 struct msdosfsmount
*pmp
;
301 union bootsector
*bsp
;
302 struct byte_bpb33
*b33
;
303 struct byte_bpb50
*b50
;
304 struct byte_bpb710
*b710
;
305 u_int8_t SecPerClust
;
310 * Disallow multiple mounts of the same device.
311 * Disallow mounting of a device that is currently in use
312 * Flush out any old buffers remaining from a previous use.
314 error
= vfs_mountedon(devvp
);
317 if (count_udev(devvp
->v_umajor
, devvp
->v_uminor
) > 0)
319 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
320 error
= vinvalbuf(devvp
, V_SAVE
, 0, 0);
325 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
326 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
327 error
= VOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, FSCRED
, NULL
);
332 bp
= NULL
; /* both used in error_exit */
336 * Read the boot sector of the filesystem, and then check the
337 * boot signature. If not a dos boot sector then error out.
339 * NOTE: 2048 is a maximum sector size in current...
341 error
= bread(devvp
, 0, 2048, &bp
);
344 bp
->b_flags
|= B_AGE
;
345 bsp
= (union bootsector
*)bp
->b_data
;
346 b33
= (struct byte_bpb33
*)bsp
->bs33
.bsBPB
;
347 b50
= (struct byte_bpb50
*)bsp
->bs50
.bsBPB
;
348 b710
= (struct byte_bpb710
*)bsp
->bs710
.bsPBP
;
350 #ifndef __DragonFly__
351 if (!(argp
->flags
& MSDOSFSMNT_GEMDOSFS
)) {
353 #ifndef MSDOSFS_NOCHECKSIG
354 if (bsp
->bs50
.bsBootSectSig0
!= BOOTSIG0
355 || bsp
->bs50
.bsBootSectSig1
!= BOOTSIG1
) {
360 #ifndef __DragonFly__
364 pmp
= kmalloc(sizeof *pmp
, M_MSDOSFSMNT
, M_WAITOK
);
365 bzero((caddr_t
)pmp
, sizeof *pmp
);
369 * Compute several useful quantities from the bpb in the
370 * bootsector. Copy in the dos 5 variant of the bpb then fix up
371 * the fields that are different between dos 5 and dos 3.3.
373 SecPerClust
= b50
->bpbSecPerClust
;
374 pmp
->pm_BytesPerSec
= getushort(b50
->bpbBytesPerSec
);
375 pmp
->pm_ResSectors
= getushort(b50
->bpbResSectors
);
376 pmp
->pm_FATs
= b50
->bpbFATs
;
377 pmp
->pm_RootDirEnts
= getushort(b50
->bpbRootDirEnts
);
378 pmp
->pm_Sectors
= getushort(b50
->bpbSectors
);
379 pmp
->pm_FATsecs
= getushort(b50
->bpbFATsecs
);
380 pmp
->pm_SecPerTrack
= getushort(b50
->bpbSecPerTrack
);
381 pmp
->pm_Heads
= getushort(b50
->bpbHeads
);
382 pmp
->pm_Media
= b50
->bpbMedia
;
384 /* calculate the ratio of sector size to DEV_BSIZE */
385 pmp
->pm_BlkPerSec
= pmp
->pm_BytesPerSec
/ DEV_BSIZE
;
387 #ifndef __DragonFly__
388 if (!(argp
->flags
& MSDOSFSMNT_GEMDOSFS
)) {
390 /* XXX - We should probably check more values here */
391 if (!pmp
->pm_BytesPerSec
|| !SecPerClust
393 || !pmp
->pm_SecPerTrack
|| pmp
->pm_SecPerTrack
> 63) {
397 #ifndef __DragonFly__
401 if (pmp
->pm_Sectors
== 0) {
402 pmp
->pm_HiddenSects
= getulong(b50
->bpbHiddenSecs
);
403 pmp
->pm_HugeSectors
= getulong(b50
->bpbHugeSectors
);
405 pmp
->pm_HiddenSects
= getushort(b33
->bpbHiddenSecs
);
406 pmp
->pm_HugeSectors
= pmp
->pm_Sectors
;
409 if (pmp
->pm_RootDirEnts
== 0) {
410 if (bsp
->bs710
.bsBootSectSig2
!= BOOTSIG2
411 || bsp
->bs710
.bsBootSectSig3
!= BOOTSIG3
414 || getushort(b710
->bpbFSVers
)) {
416 kprintf("mountmsdosfs(): bad FAT32 filesystem\n");
419 pmp
->pm_fatmask
= FAT32_MASK
;
422 pmp
->pm_FATsecs
= getulong(b710
->bpbBigFATsecs
);
423 if (getushort(b710
->bpbExtFlags
) & FATMIRROR
)
424 pmp
->pm_curfat
= getushort(b710
->bpbExtFlags
) & FATNUM
;
426 pmp
->pm_flags
|= MSDOSFS_FATMIRROR
;
428 pmp
->pm_flags
|= MSDOSFS_FATMIRROR
;
431 * Check a few values (could do some more):
432 * - logical sector size: power of 2, >= block size
433 * - sectors per cluster: power of 2, >= 1
434 * - number of sectors: >= 1, <= size of partition
436 if ( (SecPerClust
== 0)
437 || (SecPerClust
& (SecPerClust
- 1))
438 || (pmp
->pm_BytesPerSec
< DEV_BSIZE
)
439 || (pmp
->pm_BytesPerSec
& (pmp
->pm_BytesPerSec
- 1))
440 || (pmp
->pm_HugeSectors
== 0)
446 pmp
->pm_HugeSectors
*= pmp
->pm_BlkPerSec
;
447 pmp
->pm_HiddenSects
*= pmp
->pm_BlkPerSec
; /* XXX not used? */
448 pmp
->pm_FATsecs
*= pmp
->pm_BlkPerSec
;
449 SecPerClust
*= pmp
->pm_BlkPerSec
;
451 pmp
->pm_fatblk
= pmp
->pm_ResSectors
* pmp
->pm_BlkPerSec
;
454 pmp
->pm_rootdirblk
= getulong(b710
->bpbRootClust
);
455 pmp
->pm_firstcluster
= pmp
->pm_fatblk
456 + (pmp
->pm_FATs
* pmp
->pm_FATsecs
);
457 pmp
->pm_fsinfo
= getushort(b710
->bpbFSInfo
) * pmp
->pm_BlkPerSec
;
459 pmp
->pm_rootdirblk
= pmp
->pm_fatblk
+
460 (pmp
->pm_FATs
* pmp
->pm_FATsecs
);
461 pmp
->pm_rootdirsize
= (pmp
->pm_RootDirEnts
* sizeof(struct direntry
)
463 / DEV_BSIZE
; /* in blocks */
464 pmp
->pm_firstcluster
= pmp
->pm_rootdirblk
+ pmp
->pm_rootdirsize
;
467 pmp
->pm_maxcluster
= (pmp
->pm_HugeSectors
- pmp
->pm_firstcluster
) /
469 pmp
->pm_fatsize
= pmp
->pm_FATsecs
* DEV_BSIZE
; /* XXX not used? */
471 #ifndef __DragonFly__
472 if (argp
->flags
& MSDOSFSMNT_GEMDOSFS
) {
473 if ((pmp
->pm_maxcluster
<= (0xff0 - 2))
474 && ((dtype
== DTYPE_FLOPPY
) || ((dtype
== DTYPE_VNODE
)
475 && ((pmp
->pm_Heads
== 1) || (pmp
->pm_Heads
== 2))))
477 pmp
->pm_fatmask
= FAT12_MASK
;
481 pmp
->pm_fatmask
= FAT16_MASK
;
487 if (pmp
->pm_fatmask
== 0) {
488 if (pmp
->pm_maxcluster
489 <= ((CLUST_RSRVD
- CLUST_FIRST
) & FAT12_MASK
)) {
491 * This will usually be a floppy disk. This size makes
492 * sure that one fat entry will not be split across
495 pmp
->pm_fatmask
= FAT12_MASK
;
499 pmp
->pm_fatmask
= FAT16_MASK
;
505 clusters
= (pmp
->pm_fatsize
/ pmp
->pm_fatmult
) * pmp
->pm_fatdiv
;
506 if (pmp
->pm_maxcluster
>= clusters
) {
507 kprintf("Warning: number of clusters (%ld) exceeds FAT "
508 "capacity (%ld)\n", pmp
->pm_maxcluster
+ 1, clusters
);
509 pmp
->pm_maxcluster
= clusters
- 1;
514 pmp
->pm_fatblocksize
= 3 * pmp
->pm_BytesPerSec
;
516 pmp
->pm_fatblocksize
= MSDOSFS_DFLTBSIZE
;
518 pmp
->pm_fatblocksec
= pmp
->pm_fatblocksize
/ DEV_BSIZE
;
519 pmp
->pm_bnshift
= DEV_BSHIFT
;
522 * Compute mask and shift value for isolating cluster relative byte
523 * offsets and cluster numbers from a file offset.
525 pmp
->pm_bpcluster
= SecPerClust
* DEV_BSIZE
;
526 pmp
->pm_crbomask
= pmp
->pm_bpcluster
- 1;
527 pmp
->pm_cnshift
= ffs(pmp
->pm_bpcluster
) - 1;
530 * Check for valid cluster size
531 * must be a power of 2
533 if (pmp
->pm_bpcluster
^ (1 << pmp
->pm_cnshift
)) {
539 * Release the bootsector buffer.
547 if (pmp
->pm_fsinfo
) {
550 if ((error
= bread(devvp
, de_bntodoff(pmp
, pmp
->pm_fsinfo
), fsi_size(pmp
), &bp
)) != 0)
552 fp
= (struct fsinfo
*)bp
->b_data
;
553 if (!bcmp(fp
->fsisig1
, "RRaA", 4)
554 && !bcmp(fp
->fsisig2
, "rrAa", 4)
555 && !bcmp(fp
->fsisig3
, "\0\0\125\252", 4)
556 && !bcmp(fp
->fsisig4
, "\0\0\125\252", 4)) {
557 pmp
->pm_nxtfree
= getulong(fp
->fsinxtfree
);
558 if (pmp
->pm_nxtfree
== 0xffffffff)
559 pmp
->pm_nxtfree
= CLUST_FIRST
;
567 * Check and validate (or perhaps invalidate?) the fsinfo structure?
569 if (pmp
->pm_fsinfo
&& pmp
->pm_nxtfree
> pmp
->pm_maxcluster
) {
571 "Next free cluster in FSInfo (%lu) exceeds maxcluster (%lu)\n",
572 pmp
->pm_nxtfree
, pmp
->pm_maxcluster
);
578 * Allocate memory for the bitmap of allocated clusters, and then
581 pmp
->pm_inusemap
= kmalloc(((pmp
->pm_maxcluster
+ N_INUSEBITS
- 1)
583 * sizeof(*pmp
->pm_inusemap
),
584 M_MSDOSFSFAT
, M_WAITOK
);
587 * fillinusemap() needs pm_devvp.
590 pmp
->pm_devvp
= devvp
;
593 * Have the inuse map filled in.
595 if ((error
= fillinusemap(pmp
)) != 0)
599 * If they want fat updates to be synchronous then let them suffer
600 * the performance degradation in exchange for the on disk copy of
601 * the fat being correct just about all the time. I suppose this
602 * would be a good thing to turn on if the kernel is still flakey.
604 if (mp
->mnt_flag
& MNT_SYNCHRONOUS
)
605 pmp
->pm_flags
|= MSDOSFSMNT_WAITONFAT
;
611 pmp
->pm_flags
|= MSDOSFSMNT_RONLY
;
614 mp
->mnt_data
= (qaddr_t
) pmp
;
615 mp
->mnt_stat
.f_fsid
.val
[0] = dev2udev(dev
);
616 mp
->mnt_stat
.f_fsid
.val
[1] = mp
->mnt_vfc
->vfc_typenum
;
617 mp
->mnt_flag
|= MNT_LOCAL
;
618 vfs_add_vnodeops(mp
, &msdosfs_vnode_vops
, &mp
->mnt_vn_norm_ops
);
619 dev
->si_mountpoint
= mp
;
626 VOP_CLOSE(devvp
, ronly
? FREAD
: FREAD
| FWRITE
);
628 if (pmp
->pm_inusemap
)
629 kfree(pmp
->pm_inusemap
, M_MSDOSFSFAT
);
630 kfree(pmp
, M_MSDOSFSMNT
);
631 mp
->mnt_data
= (qaddr_t
)0;
637 * Unmount the filesystem described by mp.
640 msdosfs_unmount(struct mount
*mp
, int mntflags
)
642 struct msdosfsmount
*pmp
;
646 if (mntflags
& MNT_FORCE
)
648 error
= vflush(mp
, 0, flags
);
651 pmp
= VFSTOMSDOSFS(mp
);
652 pmp
->pm_devvp
->v_rdev
->si_mountpoint
= NULL
;
655 struct vnode
*vp
= pmp
->pm_devvp
;
657 kprintf("msdosfs_umount(): just before calling VOP_CLOSE()\n");
658 kprintf("flag %08x, sysrefs %d, writecount %d, auxrefs %d\n",
659 vp
->v_flag
, vp
->v_sysref
.refcnt
,
660 vp
->v_writecount
, vp
->v_auxrefs
);
661 kprintf("mount %p, op %p\n", vp
->v_mount
, vp
->v_ops
);
662 kprintf("freef %p, freeb %p, mount %p\n",
663 TAILQ_NEXT(vp
, v_freelist
),
664 *vp
->v_freelist
.tqe_prev
,
666 kprintf("cleanblkhd %p, dirtyblkhd %p, numoutput %d, type %d\n",
667 RB_ROOT(&vp
->v_rbclean_tree
),
668 RB_ROOT(&vp
->v_rbdirty_tree
),
669 vp
->v_track_write
.bk_active
, vp
->v_type
);
670 kprintf("union %p, tag %d, data[0] %08x, data[1] %08x\n",
671 vp
->v_socket
, vp
->v_tag
,
672 ((u_int
*)vp
->v_data
)[0],
673 ((u_int
*)vp
->v_data
)[1]);
676 error
= VOP_CLOSE(pmp
->pm_devvp
,
677 (pmp
->pm_flags
&MSDOSFSMNT_RONLY
) ? FREAD
: FREAD
| FWRITE
);
678 vrele(pmp
->pm_devvp
);
679 kfree(pmp
->pm_inusemap
, M_MSDOSFSFAT
);
680 kfree(pmp
, M_MSDOSFSMNT
);
681 mp
->mnt_data
= (qaddr_t
)0;
682 mp
->mnt_flag
&= ~MNT_LOCAL
;
687 msdosfs_root(struct mount
*mp
, struct vnode
**vpp
)
689 struct msdosfsmount
*pmp
= VFSTOMSDOSFS(mp
);
694 kprintf("msdosfs_root(); mp %p, pmp %p\n", mp
, pmp
);
696 error
= deget(pmp
, MSDOSFSROOT
, MSDOSFSROOT_OFS
, &ndep
);
704 msdosfs_statfs(struct mount
*mp
, struct statfs
*sbp
, struct ucred
*cred
)
706 struct msdosfsmount
*pmp
;
708 pmp
= VFSTOMSDOSFS(mp
);
709 sbp
->f_bsize
= pmp
->pm_bpcluster
;
710 sbp
->f_iosize
= pmp
->pm_bpcluster
;
711 sbp
->f_blocks
= pmp
->pm_maxcluster
+ 1;
712 sbp
->f_bfree
= pmp
->pm_freeclustercount
;
713 sbp
->f_bavail
= pmp
->pm_freeclustercount
;
714 sbp
->f_files
= pmp
->pm_RootDirEnts
; /* XXX */
715 sbp
->f_ffree
= 0; /* what to put in here? */
716 if (sbp
!= &mp
->mnt_stat
) {
717 sbp
->f_type
= mp
->mnt_vfc
->vfc_typenum
;
718 bcopy(mp
->mnt_stat
.f_mntfromname
, sbp
->f_mntfromname
, MNAMELEN
);
720 strncpy(sbp
->f_fstypename
, mp
->mnt_vfc
->vfc_name
, MFSNAMELEN
);
730 static int msdosfs_sync_scan(struct mount
*mp
, struct vnode
*vp
, void *data
);
733 msdosfs_sync(struct mount
*mp
, int waitfor
)
735 struct msdosfsmount
*pmp
= VFSTOMSDOSFS(mp
);
736 struct scaninfo scaninfo
;
740 * If we ever switch to not updating all of the fats all the time,
741 * this would be the place to update them from the first one.
743 if (pmp
->pm_fmod
!= 0) {
744 if (pmp
->pm_flags
& MSDOSFSMNT_RONLY
)
745 panic("msdosfs_sync: rofs mod");
747 /* update fats here */
751 * Write back each (modified) denode.
753 scaninfo
.allerror
= 0;
755 while (scaninfo
.rescan
) {
757 vmntvnodescan(mp
, VMSC_GETVP
|VMSC_NOWAIT
, NULL
, msdosfs_sync_scan
, &scaninfo
);
761 * Flush filesystem control info.
763 if (waitfor
!= MNT_LAZY
) {
764 vn_lock(pmp
->pm_devvp
, LK_EXCLUSIVE
| LK_RETRY
);
765 if ((error
= VOP_FSYNC(pmp
->pm_devvp
, waitfor
)) != 0)
766 scaninfo
.allerror
= error
;
767 vn_unlock(pmp
->pm_devvp
);
769 return (scaninfo
.allerror
);
773 msdosfs_sync_scan(struct mount
*mp
, struct vnode
*vp
, void *data
)
775 struct scaninfo
*info
= data
;
780 if (vp
->v_type
== VNON
|| vp
->v_type
== VBAD
||
782 (DE_ACCESS
| DE_CREATE
| DE_UPDATE
| DE_MODIFIED
)) == 0 &&
783 (RB_EMPTY(&vp
->v_rbdirty_tree
) || info
->waitfor
== MNT_LAZY
))) {
786 if ((error
= VOP_FSYNC(vp
, info
->waitfor
)) != 0)
787 info
->allerror
= error
;
792 msdosfs_fhtovp(struct mount
*mp
, struct fid
*fhp
, struct vnode
**vpp
)
794 struct msdosfsmount
*pmp
= VFSTOMSDOSFS(mp
);
795 struct defid
*defhp
= (struct defid
*) fhp
;
799 error
= deget(pmp
, defhp
->defid_dirclust
, defhp
->defid_dirofs
, &dep
);
809 msdosfs_checkexp(struct mount
*mp
, struct sockaddr
*nam
, int *exflagsp
,
810 struct ucred
**credanonp
)
812 struct msdosfsmount
*pmp
= VFSTOMSDOSFS(mp
);
815 np
= vfs_export_lookup(mp
, &pmp
->pm_export
, nam
);
818 *exflagsp
= np
->netc_exflags
;
819 *credanonp
= &np
->netc_anon
;
824 msdosfs_vptofh(struct vnode
*vp
, struct fid
*fhp
)
830 defhp
= (struct defid
*)fhp
;
831 defhp
->defid_len
= sizeof(struct defid
);
832 defhp
->defid_dirclust
= dep
->de_dirclust
;
833 defhp
->defid_dirofs
= dep
->de_diroffset
;
834 /* defhp->defid_gen = dep->de_gen; */
838 static struct vfsops msdosfs_vfsops
= {
839 .vfs_mount
= msdosfs_mount
,
840 .vfs_unmount
= msdosfs_unmount
,
841 .vfs_root
= msdosfs_root
,
842 .vfs_statfs
= msdosfs_statfs
,
843 .vfs_sync
= msdosfs_sync
,
844 .vfs_fhtovp
= msdosfs_fhtovp
,
845 .vfs_checkexp
= msdosfs_checkexp
,
846 .vfs_vptofh
= msdosfs_vptofh
,
847 .vfs_init
= msdosfs_init
,
848 .vfs_uninit
= msdosfs_uninit
851 VFS_SET(msdosfs_vfsops
, msdos
, 0);