1 /* $NetBSD: msdosfs_vfsops.c,v 1.75 2009/04/25 21:26:20 elad Exp $ */
4 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
5 * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
7 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by TooLs GmbH.
20 * 4. The name of TooLs GmbH may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 * Written by Paul Popelka (paulp@uts.amdahl.com)
37 * You can do anything you want with this software, just don't say you wrote
38 * it, and don't remove this notice.
40 * This software is provided "as is".
42 * The author supplies this software to be publicly redistributed on the
43 * understanding that the author is not responsible for the correct
44 * functioning of this software in any circumstances and is not liable for
45 * any damages caused by this software.
50 #include <sys/cdefs.h>
51 __KERNEL_RCSID(0, "$NetBSD: msdosfs_vfsops.c,v 1.75 2009/04/25 21:26:20 elad Exp $");
53 #if defined(_KERNEL_OPT)
54 #include "opt_compat_netbsd.h"
57 #include <sys/param.h>
58 #include <sys/systm.h>
59 #include <sys/sysctl.h>
60 #include <sys/namei.h>
62 #include <sys/kernel.h>
63 #include <sys/vnode.h>
64 #include <miscfs/genfs/genfs.h>
65 #include <miscfs/specfs/specdev.h> /* XXX */ /* defines v_rdev */
66 #include <sys/mount.h>
69 #include <sys/device.h>
70 #include <sys/disklabel.h>
72 #include <sys/ioctl.h>
73 #include <sys/malloc.h>
74 #include <sys/dirent.h>
77 #include <sys/kauth.h>
78 #include <sys/module.h>
80 #include <fs/msdosfs/bpb.h>
81 #include <fs/msdosfs/bootsect.h>
82 #include <fs/msdosfs/direntry.h>
83 #include <fs/msdosfs/denode.h>
84 #include <fs/msdosfs/msdosfsmount.h>
85 #include <fs/msdosfs/fat.h>
87 MODULE(MODULE_CLASS_VFS
, msdosfs
, NULL
);
90 #define DPRINTF(a) uprintf a
95 #define MSDOSFS_NAMEMAX(pmp) \
96 (pmp)->pm_flags & MSDOSFSMNT_LONGNAME ? WIN_MAXLEN : 12
100 int msdosfs_mountfs(struct vnode
*, struct mount
*, struct lwp
*,
101 struct msdosfs_args
*);
103 static int update_mp(struct mount
*, struct msdosfs_args
*);
105 MALLOC_JUSTDEFINE(M_MSDOSFSMNT
, "MSDOSFS mount", "MSDOS FS mount structure");
106 MALLOC_JUSTDEFINE(M_MSDOSFSFAT
, "MSDOSFS fat", "MSDOS FS fat table");
107 MALLOC_JUSTDEFINE(M_MSDOSFSTMP
, "MSDOSFS temp", "MSDOS FS temp. structures");
109 #define ROOTNAME "root_device"
111 static struct sysctllog
*msdosfs_sysctl_log
;
113 extern const struct vnodeopv_desc msdosfs_vnodeop_opv_desc
;
115 const struct vnodeopv_desc
* const msdosfs_vnodeopv_descs
[] = {
116 &msdosfs_vnodeop_opv_desc
,
120 struct vfsops msdosfs_vfsops
= {
122 sizeof (struct msdosfs_args
),
127 (void *)eopnotsupp
, /* vfs_quotactl */
137 (int (*)(struct mount
*, struct vnode
*, struct timespec
*)) eopnotsupp
,
139 (void *)eopnotsupp
, /* vfs_suspendctl */
140 genfs_renamelock_enter
,
141 genfs_renamelock_exit
,
143 msdosfs_vnodeopv_descs
,
149 msdosfs_modcmd(modcmd_t cmd
, void *arg
)
154 case MODULE_CMD_INIT
:
155 error
= vfs_attach(&msdosfs_vfsops
);
158 sysctl_createv(&msdosfs_sysctl_log
, 0, NULL
, NULL
,
160 CTLTYPE_NODE
, "vfs", NULL
,
163 sysctl_createv(&msdosfs_sysctl_log
, 0, NULL
, NULL
,
165 CTLTYPE_NODE
, "msdosfs",
166 SYSCTL_DESCR("MS-DOS file system"),
168 CTL_VFS
, 4, CTL_EOL
);
170 * XXX the "4" above could be dynamic, thereby eliminating one
171 * more instance of the "number to vfs" mapping problem, but
172 * "4" is the order as taken from sys/mount.h
175 case MODULE_CMD_FINI
:
176 error
= vfs_detach(&msdosfs_vfsops
);
179 sysctl_teardown(&msdosfs_sysctl_log
);
190 update_mp(struct mount
*mp
, struct msdosfs_args
*argp
)
192 struct msdosfsmount
*pmp
= VFSTOMSDOSFS(mp
);
195 pmp
->pm_gid
= argp
->gid
;
196 pmp
->pm_uid
= argp
->uid
;
197 pmp
->pm_mask
= argp
->mask
& ALLPERMS
;
198 pmp
->pm_dirmask
= argp
->dirmask
& ALLPERMS
;
199 pmp
->pm_gmtoff
= argp
->gmtoff
;
200 pmp
->pm_flags
|= argp
->flags
& MSDOSFSMNT_MNTOPT
;
203 * GEMDOS knows nothing about win95 long filenames
205 if (pmp
->pm_flags
& MSDOSFSMNT_GEMDOSFS
)
206 pmp
->pm_flags
|= MSDOSFSMNT_NOWIN95
;
208 if (pmp
->pm_flags
& MSDOSFSMNT_NOWIN95
)
209 pmp
->pm_flags
|= MSDOSFSMNT_SHORTNAME
;
210 else if (!(pmp
->pm_flags
&
211 (MSDOSFSMNT_SHORTNAME
| MSDOSFSMNT_LONGNAME
))) {
215 * Try to divine whether to support Win'95 long filenames
218 pmp
->pm_flags
|= MSDOSFSMNT_LONGNAME
;
220 if ((error
= msdosfs_root(mp
, &rtvp
)) != 0)
222 pmp
->pm_flags
|= findwin95(VTODE(rtvp
))
223 ? MSDOSFSMNT_LONGNAME
224 : MSDOSFSMNT_SHORTNAME
;
229 mp
->mnt_stat
.f_namemax
= MSDOSFS_NAMEMAX(pmp
);
235 msdosfs_mountroot(void)
238 struct lwp
*l
= curlwp
; /* XXX */
240 struct msdosfs_args args
;
242 if (device_class(root_device
) != DV_DISK
)
245 if ((error
= vfs_rootmountalloc(MOUNT_MSDOS
, "root_device", &mp
))) {
250 args
.flags
= MSDOSFSMNT_VERSIONED
;
254 args
.version
= MSDOSFSMNT_VERSION
;
257 if ((error
= msdosfs_mountfs(rootvp
, mp
, l
, &args
)) != 0) {
258 vfs_unbusy(mp
, false, NULL
);
263 if ((error
= update_mp(mp
, &args
)) != 0) {
264 (void)msdosfs_unmount(mp
, 0);
265 vfs_unbusy(mp
, false, NULL
);
271 mutex_enter(&mountlist_lock
);
272 CIRCLEQ_INSERT_TAIL(&mountlist
, mp
, mnt_list
);
273 mutex_exit(&mountlist_lock
);
274 (void)msdosfs_statvfs(mp
, &mp
->mnt_stat
);
275 vfs_unbusy(mp
, false, NULL
);
280 * mp - path - addr in user space of mount point (ie /usr or whatever)
281 * data - addr in user space of mount params including the name of the block
282 * special file to treat as a filesystem.
285 msdosfs_mount(struct mount
*mp
, const char *path
, void *data
, size_t *data_len
)
287 struct lwp
*l
= curlwp
;
288 struct vnode
*devvp
; /* vnode for blk device to mount */
289 struct msdosfs_args
*args
= data
; /* holds data from mount request */
290 /* msdosfs specific mount control block */
291 struct msdosfsmount
*pmp
= NULL
;
295 if (*data_len
< sizeof *args
)
298 if (mp
->mnt_flag
& MNT_GETARGS
) {
299 pmp
= VFSTOMSDOSFS(mp
);
303 args
->uid
= pmp
->pm_uid
;
304 args
->gid
= pmp
->pm_gid
;
305 args
->mask
= pmp
->pm_mask
;
306 args
->flags
= pmp
->pm_flags
;
307 args
->version
= MSDOSFSMNT_VERSION
;
308 args
->dirmask
= pmp
->pm_dirmask
;
309 args
->gmtoff
= pmp
->pm_gmtoff
;
310 *data_len
= sizeof *args
;
315 * If not versioned (i.e. using old mount_msdos(8)), fill in
316 * the additional structure items with suitable defaults.
318 if ((args
->flags
& MSDOSFSMNT_VERSIONED
) == 0) {
320 args
->dirmask
= args
->mask
;
324 * Reset GMT offset for pre-v3 mount structure args.
326 if (args
->version
< 3)
330 * If updating, check whether changing from read-only to
331 * read/write; if there is no device name, that's all we do.
333 if (mp
->mnt_flag
& MNT_UPDATE
) {
334 pmp
= VFSTOMSDOSFS(mp
);
336 if (!(pmp
->pm_flags
& MSDOSFSMNT_RONLY
) &&
337 (mp
->mnt_flag
& MNT_RDONLY
)) {
339 if (mp
->mnt_flag
& MNT_FORCE
)
341 error
= vflush(mp
, NULLVP
, flags
);
343 if (!error
&& (mp
->mnt_flag
& MNT_RELOAD
))
344 /* not yet implemented */
347 DPRINTF(("vflush %d\n", error
));
350 if ((pmp
->pm_flags
& MSDOSFSMNT_RONLY
) &&
351 (mp
->mnt_iflag
& IMNT_WANTRDWR
)) {
353 * If upgrade to read-write by non-root, then verify
354 * that user has necessary permissions on the device.
356 * Permission to update a mount is checked higher, so
357 * here we presume updating the mount is okay (for
358 * example, as far as securelevel goes) which leaves us
359 * with the normal check.
361 devvp
= pmp
->pm_devvp
;
362 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
363 error
= genfs_can_mount(devvp
, VREAD
| VWRITE
,
365 VOP_UNLOCK(devvp
, 0);
366 DPRINTF(("genfs_can_mount %d\n", error
));
370 pmp
->pm_flags
&= ~MSDOSFSMNT_RONLY
;
372 if (args
->fspec
== NULL
) {
373 DPRINTF(("missing fspec\n"));
378 * Not an update, or updating the name: look up the name
379 * and verify that it refers to a sensible block device.
381 error
= namei_simple_user(args
->fspec
,
382 NSM_FOLLOW_NOEMULROOT
, &devvp
);
384 DPRINTF(("namei %d\n", error
));
388 if (devvp
->v_type
!= VBLK
) {
389 DPRINTF(("not block\n"));
393 if (bdevsw_lookup(devvp
->v_rdev
) == NULL
) {
394 DPRINTF(("no block switch\n"));
399 * If mount by non-root, then verify that user has necessary
400 * permissions on the device.
403 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
404 accessmode
|= VWRITE
;
405 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
406 error
= genfs_can_mount(devvp
, accessmode
, l
->l_cred
);
407 VOP_UNLOCK(devvp
, 0);
409 DPRINTF(("genfs_can_mount %d\n", error
));
413 if ((mp
->mnt_flag
& MNT_UPDATE
) == 0) {
416 if (mp
->mnt_flag
& MNT_RDONLY
)
419 xflags
= FREAD
|FWRITE
;
420 error
= VOP_OPEN(devvp
, xflags
, FSCRED
);
422 DPRINTF(("VOP_OPEN %d\n", error
));
425 error
= msdosfs_mountfs(devvp
, mp
, l
, args
);
427 DPRINTF(("msdosfs_mountfs %d\n", error
));
428 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
429 (void) VOP_CLOSE(devvp
, xflags
, NOCRED
);
430 VOP_UNLOCK(devvp
, 0);
433 #ifdef MSDOSFS_DEBUG /* only needed for the printf below */
434 pmp
= VFSTOMSDOSFS(mp
);
438 if (devvp
!= pmp
->pm_devvp
) {
439 DPRINTF(("devvp %p pmp %p\n",
440 devvp
, pmp
->pm_devvp
));
441 return (EINVAL
); /* needs translation */
444 if ((error
= update_mp(mp
, args
)) != 0) {
445 msdosfs_unmount(mp
, MNT_FORCE
);
446 DPRINTF(("update_mp %d\n", error
));
451 printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp
, pmp
, pmp
->pm_inusemap
);
453 return set_statvfs_info(path
, UIO_USERSPACE
, args
->fspec
, UIO_USERSPACE
,
454 mp
->mnt_op
->vfs_name
, mp
, l
);
462 msdosfs_mountfs(struct vnode
*devvp
, struct mount
*mp
, struct lwp
*l
, struct msdosfs_args
*argp
)
464 struct msdosfsmount
*pmp
;
466 dev_t dev
= devvp
->v_rdev
;
467 struct partinfo dpart
;
468 union bootsector
*bsp
;
469 struct byte_bpb33
*b33
;
470 struct byte_bpb50
*b50
;
471 struct byte_bpb710
*b710
;
472 u_int8_t SecPerClust
;
473 int ronly
, error
, tmp
;
474 int bsize
, dtype
, fstype
, secsize
;
477 /* Flush out any old buffers remaining from a previous use. */
478 if ((error
= vinvalbuf(devvp
, V_SAVE
, l
->l_cred
, l
, 0, 0)) != 0)
481 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
483 bp
= NULL
; /* both used in error_exit */
487 * We need the disklabel to calculate the size of a FAT entry
488 * later on. Also make sure the partition contains a filesystem
489 * of type FS_MSDOS. This doesn't work for floppies, so we have
490 * to check for them too.
492 * There might still be parts of the msdos fs driver which assume
493 * that the size of a disk block will always be 512 bytes.
494 * Let's root them out...
496 error
= VOP_IOCTL(devvp
, DIOCGPART
, &dpart
, FREAD
, NOCRED
);
498 secsize
= dpart
.disklab
->d_secsize
;
499 dtype
= dpart
.disklab
->d_type
;
500 fstype
= dpart
.part
->p_fstype
;
501 psize
= dpart
.part
->p_size
;
503 struct dkwedge_info dkw
;
504 error
= VOP_IOCTL(devvp
, DIOCGWEDGEINFO
, &dkw
, FREAD
, NOCRED
);
505 secsize
= 512; /* XXX */
506 dtype
= DTYPE_FLOPPY
; /* XXX */
510 if (error
!= ENOTTY
) {
511 DPRINTF(("Error getting partition info %d\n",
516 fstype
= strcmp(dkw
.dkw_ptype
, DKW_PTYPE_FAT
) == 0 ?
518 psize
= dkw
.dkw_size
;
521 if (argp
->flags
& MSDOSFSMNT_GEMDOSFS
) {
524 DPRINTF(("bsize %d dtype %d fstype %d\n", bsize
, dtype
,
533 * Read the boot sector of the filesystem, and then check the
534 * boot signature. If not a dos boot sector then error out.
536 if ((error
= bread(devvp
, 0, secsize
, NOCRED
, 0, &bp
)) != 0)
538 bsp
= (union bootsector
*)bp
->b_data
;
539 b33
= (struct byte_bpb33
*)bsp
->bs33
.bsBPB
;
540 b50
= (struct byte_bpb50
*)bsp
->bs50
.bsBPB
;
541 b710
= (struct byte_bpb710
*)bsp
->bs710
.bsBPB
;
543 if (!(argp
->flags
& MSDOSFSMNT_GEMDOSFS
)) {
544 if (bsp
->bs50
.bsBootSectSig0
!= BOOTSIG0
545 || bsp
->bs50
.bsBootSectSig1
!= BOOTSIG1
) {
546 DPRINTF(("bootsig0 %d bootsig1 %d\n",
547 bsp
->bs50
.bsBootSectSig0
,
548 bsp
->bs50
.bsBootSectSig1
));
554 pmp
= malloc(sizeof *pmp
, M_MSDOSFSMNT
, M_WAITOK
);
555 memset(pmp
, 0, sizeof *pmp
);
559 * Compute several useful quantities from the bpb in the
560 * bootsector. Copy in the dos 5 variant of the bpb then fix up
561 * the fields that are different between dos 5 and dos 3.3.
563 SecPerClust
= b50
->bpbSecPerClust
;
564 pmp
->pm_BytesPerSec
= getushort(b50
->bpbBytesPerSec
);
565 pmp
->pm_ResSectors
= getushort(b50
->bpbResSectors
);
566 pmp
->pm_FATs
= b50
->bpbFATs
;
567 pmp
->pm_RootDirEnts
= getushort(b50
->bpbRootDirEnts
);
568 pmp
->pm_Sectors
= getushort(b50
->bpbSectors
);
569 pmp
->pm_FATsecs
= getushort(b50
->bpbFATsecs
);
570 pmp
->pm_SecPerTrack
= getushort(b50
->bpbSecPerTrack
);
571 pmp
->pm_Heads
= getushort(b50
->bpbHeads
);
572 pmp
->pm_Media
= b50
->bpbMedia
;
574 if (!(argp
->flags
& MSDOSFSMNT_GEMDOSFS
)) {
575 /* XXX - We should probably check more values here */
576 if (!pmp
->pm_BytesPerSec
|| !SecPerClust
577 || pmp
->pm_SecPerTrack
> 63) {
578 DPRINTF(("bytespersec %d secperclust %d "
580 pmp
->pm_BytesPerSec
, SecPerClust
,
581 pmp
->pm_SecPerTrack
));
587 if (pmp
->pm_Sectors
== 0) {
588 pmp
->pm_HiddenSects
= getulong(b50
->bpbHiddenSecs
);
589 pmp
->pm_HugeSectors
= getulong(b50
->bpbHugeSectors
);
591 pmp
->pm_HiddenSects
= getushort(b33
->bpbHiddenSecs
);
592 pmp
->pm_HugeSectors
= pmp
->pm_Sectors
;
595 if (pmp
->pm_RootDirEnts
== 0) {
596 unsigned short vers
= getushort(b710
->bpbFSVers
);
598 * Some say that bsBootSectSig[23] must be zero, but
599 * Windows does not require this and some digital cameras
600 * do not set these to zero. Therefore, do not insist.
602 if (pmp
->pm_Sectors
|| pmp
->pm_FATsecs
|| vers
) {
603 DPRINTF(("sectors %d fatsecs %lu vers %d\n",
604 pmp
->pm_Sectors
, pmp
->pm_FATsecs
, vers
));
608 pmp
->pm_fatmask
= FAT32_MASK
;
611 pmp
->pm_FATsecs
= getulong(b710
->bpbBigFATsecs
);
613 /* mirrorring is enabled if the FATMIRROR bit is not set */
614 if ((getushort(b710
->bpbExtFlags
) & FATMIRROR
) == 0)
615 pmp
->pm_flags
|= MSDOSFS_FATMIRROR
;
617 pmp
->pm_curfat
= getushort(b710
->bpbExtFlags
) & FATNUM
;
619 pmp
->pm_flags
|= MSDOSFS_FATMIRROR
;
621 if (argp
->flags
& MSDOSFSMNT_GEMDOSFS
) {
623 DPRINTF(("fat32 for gemdos\n"));
625 * GEMDOS doesn't know fat32.
632 * Check a few values (could do some more):
633 * - logical sector size: power of 2, >= block size
634 * - sectors per cluster: power of 2, >= 1
635 * - number of sectors: >= 1, <= size of partition
637 if ( (SecPerClust
== 0)
638 || (SecPerClust
& (SecPerClust
- 1))
639 || (pmp
->pm_BytesPerSec
< bsize
)
640 || (pmp
->pm_BytesPerSec
& (pmp
->pm_BytesPerSec
- 1))
641 || (pmp
->pm_HugeSectors
== 0)
642 || (pmp
->pm_HugeSectors
* (pmp
->pm_BytesPerSec
/ bsize
)
644 DPRINTF(("consistency checks for gemdos\n"));
649 * XXX - Many parts of the msdos fs driver seem to assume that
650 * the number of bytes per logical sector (BytesPerSec) will
651 * always be the same as the number of bytes per disk block
652 * Let's pretend it is.
654 tmp
= pmp
->pm_BytesPerSec
/ bsize
;
655 pmp
->pm_BytesPerSec
= bsize
;
656 pmp
->pm_HugeSectors
*= tmp
;
657 pmp
->pm_HiddenSects
*= tmp
;
658 pmp
->pm_ResSectors
*= tmp
;
659 pmp
->pm_Sectors
*= tmp
;
660 pmp
->pm_FATsecs
*= tmp
;
664 /* Check that fs has nonzero FAT size */
665 if (pmp
->pm_FATsecs
== 0) {
666 DPRINTF(("FATsecs is 0\n"));
671 pmp
->pm_fatblk
= pmp
->pm_ResSectors
;
673 pmp
->pm_rootdirblk
= getulong(b710
->bpbRootClust
);
674 pmp
->pm_firstcluster
= pmp
->pm_fatblk
675 + (pmp
->pm_FATs
* pmp
->pm_FATsecs
);
676 pmp
->pm_fsinfo
= getushort(b710
->bpbFSInfo
);
678 pmp
->pm_rootdirblk
= pmp
->pm_fatblk
+
679 (pmp
->pm_FATs
* pmp
->pm_FATsecs
);
680 pmp
->pm_rootdirsize
= (pmp
->pm_RootDirEnts
* sizeof(struct direntry
)
681 + pmp
->pm_BytesPerSec
- 1)
682 / pmp
->pm_BytesPerSec
;/* in sectors */
683 pmp
->pm_firstcluster
= pmp
->pm_rootdirblk
+ pmp
->pm_rootdirsize
;
686 pmp
->pm_nmbrofclusters
= (pmp
->pm_HugeSectors
- pmp
->pm_firstcluster
) /
688 pmp
->pm_maxcluster
= pmp
->pm_nmbrofclusters
+ 1;
689 pmp
->pm_fatsize
= pmp
->pm_FATsecs
* pmp
->pm_BytesPerSec
;
691 if (argp
->flags
& MSDOSFSMNT_GEMDOSFS
) {
692 if (pmp
->pm_nmbrofclusters
<= (0xff0 - 2)
693 && (dtype
== DTYPE_FLOPPY
694 || (dtype
== DTYPE_VND
695 && (pmp
->pm_Heads
== 1 || pmp
->pm_Heads
== 2)))
697 pmp
->pm_fatmask
= FAT12_MASK
;
701 pmp
->pm_fatmask
= FAT16_MASK
;
705 } else if (pmp
->pm_fatmask
== 0) {
706 if (pmp
->pm_maxcluster
707 <= ((CLUST_RSRVD
- CLUST_FIRST
) & FAT12_MASK
)) {
709 * This will usually be a floppy disk. This size makes
710 * sure that one fat entry will not be split across
713 pmp
->pm_fatmask
= FAT12_MASK
;
717 pmp
->pm_fatmask
= FAT16_MASK
;
723 pmp
->pm_fatblocksize
= 3 * pmp
->pm_BytesPerSec
;
725 pmp
->pm_fatblocksize
= MAXBSIZE
;
727 pmp
->pm_fatblocksec
= pmp
->pm_fatblocksize
/ pmp
->pm_BytesPerSec
;
728 pmp
->pm_bnshift
= ffs(pmp
->pm_BytesPerSec
) - 1;
731 * Compute mask and shift value for isolating cluster relative byte
732 * offsets and cluster numbers from a file offset.
734 pmp
->pm_bpcluster
= SecPerClust
* pmp
->pm_BytesPerSec
;
735 pmp
->pm_crbomask
= pmp
->pm_bpcluster
- 1;
736 pmp
->pm_cnshift
= ffs(pmp
->pm_bpcluster
) - 1;
739 * Check for valid cluster size
740 * must be a power of 2
742 if (pmp
->pm_bpcluster
^ (1 << pmp
->pm_cnshift
)) {
743 DPRINTF(("bpcluster %lu cnshift %lu\n",
744 pmp
->pm_bpcluster
, pmp
->pm_cnshift
));
750 * Release the bootsector buffer.
758 if (pmp
->pm_fsinfo
) {
762 * XXX If the fsinfo block is stored on media with
763 * 2KB or larger sectors, is the fsinfo structure
764 * padded at the end or in the middle?
766 if ((error
= bread(devvp
, de_bn2kb(pmp
, pmp
->pm_fsinfo
),
767 pmp
->pm_BytesPerSec
, NOCRED
, 0, &bp
)) != 0)
769 fp
= (struct fsinfo
*)bp
->b_data
;
770 if (!memcmp(fp
->fsisig1
, "RRaA", 4)
771 && !memcmp(fp
->fsisig2
, "rrAa", 4)
772 && !memcmp(fp
->fsisig3
, "\0\0\125\252", 4)
773 && !memcmp(fp
->fsisig4
, "\0\0\125\252", 4))
774 pmp
->pm_nxtfree
= getulong(fp
->fsinxtfree
);
782 * Check and validate (or perhaps invalidate?) the fsinfo structure?
785 if (pmp
->pm_fsinfo
) {
786 if (pmp
->pm_nxtfree
== (u_long
)-1)
791 * Allocate memory for the bitmap of allocated clusters, and then
794 pmp
->pm_inusemap
= malloc(((pmp
->pm_maxcluster
+ N_INUSEBITS
- 1)
796 * sizeof(*pmp
->pm_inusemap
),
797 M_MSDOSFSFAT
, M_WAITOK
);
800 * fillinusemap() needs pm_devvp.
803 pmp
->pm_devvp
= devvp
;
806 * Have the inuse map filled in.
808 if ((error
= fillinusemap(pmp
)) != 0) {
809 DPRINTF(("fillinusemap %d\n", error
));
814 * If they want fat updates to be synchronous then let them suffer
815 * the performance degradation in exchange for the on disk copy of
816 * the fat being correct just about all the time. I suppose this
817 * would be a good thing to turn on if the kernel is still flakey.
819 if (mp
->mnt_flag
& MNT_SYNCHRONOUS
)
820 pmp
->pm_flags
|= MSDOSFSMNT_WAITONFAT
;
826 pmp
->pm_flags
|= MSDOSFSMNT_RONLY
;
830 mp
->mnt_stat
.f_fsidx
.__fsid_val
[0] = (long)dev
;
831 mp
->mnt_stat
.f_fsidx
.__fsid_val
[1] = makefstype(MOUNT_MSDOS
);
832 mp
->mnt_stat
.f_fsid
= mp
->mnt_stat
.f_fsidx
.__fsid_val
[0];
833 mp
->mnt_stat
.f_namemax
= MSDOSFS_NAMEMAX(pmp
);
834 mp
->mnt_flag
|= MNT_LOCAL
;
835 mp
->mnt_dev_bshift
= pmp
->pm_bnshift
;
836 mp
->mnt_fs_bshift
= pmp
->pm_cnshift
;
839 * If we ever do quotas for DOS filesystems this would be a place
840 * to fill in the info in the msdosfsmount structure. You dolt,
841 * quotas on dos filesystems make no sense because files have no
842 * owners on dos filesystems. of course there is some empty space
843 * in the directory entry where we could put uid's and gid's.
846 devvp
->v_specmountpoint
= mp
;
854 if (pmp
->pm_inusemap
)
855 free(pmp
->pm_inusemap
, M_MSDOSFSFAT
);
856 free(pmp
, M_MSDOSFSMNT
);
863 msdosfs_start(struct mount
*mp
, int flags
)
870 * Unmount the filesystem described by mp.
873 msdosfs_unmount(struct mount
*mp
, int mntflags
)
875 struct msdosfsmount
*pmp
;
879 if (mntflags
& MNT_FORCE
)
881 if ((error
= vflush(mp
, NULLVP
, flags
)) != 0)
883 pmp
= VFSTOMSDOSFS(mp
);
884 if (pmp
->pm_devvp
->v_type
!= VBAD
)
885 pmp
->pm_devvp
->v_specmountpoint
= NULL
;
888 struct vnode
*vp
= pmp
->pm_devvp
;
890 printf("msdosfs_umount(): just before calling VOP_CLOSE()\n");
891 printf("flag %08x, usecount %d, writecount %d, holdcnt %d\n",
892 vp
->v_vflag
| vp
->v_iflag
| vp
->v_uflag
, vp
->v_usecount
,
893 vp
->v_writecount
, vp
->v_holdcnt
);
894 printf("mount %p, op %p\n",
895 vp
->v_mount
, vp
->v_op
);
896 printf("freef %p, freeb %p, mount %p\n",
897 vp
->v_freelist
.tqe_next
, vp
->v_freelist
.tqe_prev
,
899 printf("cleanblkhd %p, dirtyblkhd %p, numoutput %d, type %d\n",
900 vp
->v_cleanblkhd
.lh_first
,
901 vp
->v_dirtyblkhd
.lh_first
,
902 vp
->v_numoutput
, vp
->v_type
);
903 printf("union %p, tag %d, data[0] %08x, data[1] %08x\n",
904 vp
->v_socket
, vp
->v_tag
,
905 ((u_int
*)vp
->v_data
)[0],
906 ((u_int
*)vp
->v_data
)[1]);
909 vn_lock(pmp
->pm_devvp
, LK_EXCLUSIVE
| LK_RETRY
);
910 error
= VOP_CLOSE(pmp
->pm_devvp
,
911 pmp
->pm_flags
& MSDOSFSMNT_RONLY
? FREAD
: FREAD
|FWRITE
, NOCRED
);
913 free(pmp
->pm_inusemap
, M_MSDOSFSFAT
);
914 free(pmp
, M_MSDOSFSMNT
);
916 mp
->mnt_flag
&= ~MNT_LOCAL
;
921 msdosfs_root(struct mount
*mp
, struct vnode
**vpp
)
923 struct msdosfsmount
*pmp
= VFSTOMSDOSFS(mp
);
928 printf("msdosfs_root(); mp %p, pmp %p\n", mp
, pmp
);
930 if ((error
= deget(pmp
, MSDOSFSROOT
, MSDOSFSROOT_OFS
, &ndep
)) != 0)
937 msdosfs_statvfs(struct mount
*mp
, struct statvfs
*sbp
)
939 struct msdosfsmount
*pmp
;
941 pmp
= VFSTOMSDOSFS(mp
);
942 sbp
->f_bsize
= pmp
->pm_bpcluster
;
943 sbp
->f_frsize
= sbp
->f_bsize
;
944 sbp
->f_iosize
= pmp
->pm_bpcluster
;
945 sbp
->f_blocks
= pmp
->pm_nmbrofclusters
;
946 sbp
->f_bfree
= pmp
->pm_freeclustercount
;
947 sbp
->f_bavail
= pmp
->pm_freeclustercount
;
949 sbp
->f_files
= pmp
->pm_RootDirEnts
; /* XXX */
950 sbp
->f_ffree
= 0; /* what to put in here? */
951 sbp
->f_favail
= 0; /* what to put in here? */
953 copy_statvfs_info(sbp
, mp
);
958 msdosfs_sync(struct mount
*mp
, int waitfor
, kauth_cred_t cred
)
960 struct vnode
*vp
, *mvp
;
962 struct msdosfsmount
*pmp
= VFSTOMSDOSFS(mp
);
963 int error
, allerror
= 0;
966 * If we ever switch to not updating all of the fats all the time,
967 * this would be the place to update them from the first one.
969 if (pmp
->pm_fmod
!= 0) {
970 if (pmp
->pm_flags
& MSDOSFSMNT_RONLY
)
971 panic("msdosfs_sync: rofs mod");
973 /* update fats here */
976 /* Allocate a marker vnode. */
977 if ((mvp
= vnalloc(mp
)) == NULL
)
980 * Write back each (modified) denode.
982 mutex_enter(&mntvnode_lock
);
984 for (vp
= TAILQ_FIRST(&mp
->mnt_vnodelist
); vp
; vp
= vunmark(mvp
)) {
986 if (vp
->v_mount
!= mp
|| vismarker(vp
))
988 mutex_enter(&vp
->v_interlock
);
990 if (waitfor
== MNT_LAZY
|| vp
->v_type
== VNON
||
992 (DE_ACCESS
| DE_CREATE
| DE_UPDATE
| DE_MODIFIED
)) == 0) &&
993 (LIST_EMPTY(&vp
->v_dirtyblkhd
) &&
994 UVM_OBJ_IS_CLEAN(&vp
->v_uobj
)))) {
995 mutex_exit(&vp
->v_interlock
);
998 mutex_exit(&mntvnode_lock
);
999 error
= vget(vp
, LK_EXCLUSIVE
| LK_NOWAIT
| LK_INTERLOCK
);
1001 mutex_enter(&mntvnode_lock
);
1002 if (error
== ENOENT
) {
1008 if ((error
= VOP_FSYNC(vp
, cred
,
1009 waitfor
== MNT_WAIT
? FSYNC_WAIT
: 0, 0, 0)) != 0)
1012 mutex_enter(&mntvnode_lock
);
1014 mutex_exit(&mntvnode_lock
);
1018 * Force stale file system control information to be flushed.
1020 if ((error
= VOP_FSYNC(pmp
->pm_devvp
, cred
,
1021 waitfor
== MNT_WAIT
? FSYNC_WAIT
: 0, 0, 0)) != 0)
1027 msdosfs_fhtovp(struct mount
*mp
, struct fid
*fhp
, struct vnode
**vpp
)
1029 struct msdosfsmount
*pmp
= VFSTOMSDOSFS(mp
);
1034 if (fhp
->fid_len
!= sizeof(struct defid
)) {
1035 DPRINTF(("fid_len %d %zd\n", fhp
->fid_len
,
1036 sizeof(struct defid
)));
1040 memcpy(&defh
, fhp
, sizeof(defh
));
1041 error
= deget(pmp
, defh
.defid_dirclust
, defh
.defid_dirofs
, &dep
);
1043 DPRINTF(("deget %d\n", error
));
1052 msdosfs_vptofh(struct vnode
*vp
, struct fid
*fhp
, size_t *fh_size
)
1057 if (*fh_size
< sizeof(struct defid
)) {
1058 *fh_size
= sizeof(struct defid
);
1061 *fh_size
= sizeof(struct defid
);
1063 memset(&defh
, 0, sizeof(defh
));
1064 defh
.defid_len
= sizeof(struct defid
);
1065 defh
.defid_dirclust
= dep
->de_dirclust
;
1066 defh
.defid_dirofs
= dep
->de_diroffset
;
1067 /* defh.defid_gen = dep->de_gen; */
1068 memcpy(fhp
, &defh
, sizeof(defh
));
1073 msdosfs_vget(struct mount
*mp
, ino_t ino
,
1077 return (EOPNOTSUPP
);