msdosfs_vfsops.c revision 55756
150477Speter/* $FreeBSD: head/sys/fs/msdosfs/msdosfs_vfsops.c 55756 2000-01-10 12:04:27Z phk $ */ 233548Sjkh/* $NetBSD: msdosfs_vfsops.c,v 1.51 1997/11/17 15:36:58 ws Exp $ */ 32893Sdfr 42893Sdfr/*- 533548Sjkh * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. 633548Sjkh * Copyright (C) 1994, 1995, 1997 TooLs GmbH. 72893Sdfr * All rights reserved. 82893Sdfr * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 92893Sdfr * 102893Sdfr * Redistribution and use in source and binary forms, with or without 112893Sdfr * modification, are permitted provided that the following conditions 122893Sdfr * are met: 132893Sdfr * 1. Redistributions of source code must retain the above copyright 142893Sdfr * notice, this list of conditions and the following disclaimer. 152893Sdfr * 2. Redistributions in binary form must reproduce the above copyright 162893Sdfr * notice, this list of conditions and the following disclaimer in the 172893Sdfr * documentation and/or other materials provided with the distribution. 182893Sdfr * 3. All advertising materials mentioning features or use of this software 192893Sdfr * must display the following acknowledgement: 202893Sdfr * This product includes software developed by TooLs GmbH. 212893Sdfr * 4. The name of TooLs GmbH may not be used to endorse or promote products 222893Sdfr * derived from this software without specific prior written permission. 232893Sdfr * 242893Sdfr * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 252893Sdfr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 262893Sdfr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 272893Sdfr * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 282893Sdfr * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 292893Sdfr * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 302893Sdfr * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 312893Sdfr * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 322893Sdfr * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 332893Sdfr * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 342893Sdfr */ 352893Sdfr/* 362893Sdfr * Written by Paul Popelka (paulp@uts.amdahl.com) 378876Srgrimes * 382893Sdfr * You can do anything you want with this software, just don't say you wrote 392893Sdfr * it, and don't remove this notice. 408876Srgrimes * 412893Sdfr * This software is provided "as is". 428876Srgrimes * 432893Sdfr * The author supplies this software to be publicly redistributed on the 442893Sdfr * understanding that the author is not responsible for the correct 452893Sdfr * functioning of this software in any circumstances and is not liable for 462893Sdfr * any damages caused by this software. 478876Srgrimes * 482893Sdfr * October 1992 492893Sdfr */ 502893Sdfr 512893Sdfr#include <sys/param.h> 522893Sdfr#include <sys/systm.h> 5340651Sbde#include <sys/conf.h> 542893Sdfr#include <sys/namei.h> 552893Sdfr#include <sys/proc.h> 562893Sdfr#include <sys/kernel.h> 572893Sdfr#include <sys/vnode.h> 582893Sdfr#include <sys/mount.h> 592893Sdfr#include <sys/buf.h> 6024131Sbde#include <sys/fcntl.h> 612893Sdfr#include <sys/malloc.h> 6233548Sjkh#include <sys/stat.h> /* defines ALLPERMS */ 6354655Seivind#include <vm/vm_zone.h> 642893Sdfr 652893Sdfr#include <msdosfs/bpb.h> 662893Sdfr#include <msdosfs/bootsect.h> 672893Sdfr#include <msdosfs/direntry.h> 682893Sdfr#include <msdosfs/denode.h> 692893Sdfr#include <msdosfs/msdosfsmount.h> 702893Sdfr#include <msdosfs/fat.h> 712893Sdfr 7230354SphkMALLOC_DEFINE(M_MSDOSFSMNT, "MSDOSFS mount", "MSDOSFS mount structure"); 7330354Sphkstatic MALLOC_DEFINE(M_MSDOSFSFAT, "MSDOSFS FAT", "MSDOSFS file allocation table"); 7430309Sphk 7533548Sjkhstatic int update_mp __P((struct mount *mp, struct msdosfs_args *argp)); 7612338Sbdestatic int mountmsdosfs __P((struct vnode *devvp, struct mount *mp, 7733548Sjkh struct proc *p, struct msdosfs_args *argp)); 7812338Sbdestatic int msdosfs_fhtovp __P((struct mount *, struct fid *, 7951138Salfred struct vnode **)); 8051138Salfredstatic int msdosfs_checkexp __P((struct mount *, struct sockaddr *, 8151138Salfred int *, struct ucred **)); 8212338Sbdestatic int msdosfs_mount __P((struct mount *, char *, caddr_t, 8312338Sbde struct nameidata *, struct proc *)); 8412338Sbdestatic int msdosfs_root __P((struct mount *, struct vnode **)); 8512338Sbdestatic int msdosfs_statfs __P((struct mount *, struct statfs *, 8612338Sbde struct proc *)); 8712338Sbdestatic int msdosfs_sync __P((struct mount *, int, struct ucred *, 8812338Sbde struct proc *)); 8912338Sbdestatic int msdosfs_unmount __P((struct mount *, int, struct proc *)); 9012338Sbdestatic int msdosfs_vptofh __P((struct vnode *, struct fid *)); 9112338Sbde 9233548Sjkhstatic int 9333548Sjkhupdate_mp(mp, argp) 9433548Sjkh struct mount *mp; 9533548Sjkh struct msdosfs_args *argp; 9633548Sjkh{ 9733548Sjkh struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 9833548Sjkh int error; 9933548Sjkh 10033548Sjkh pmp->pm_gid = argp->gid; 10133548Sjkh pmp->pm_uid = argp->uid; 10233548Sjkh pmp->pm_mask = argp->mask & ALLPERMS; 10333548Sjkh pmp->pm_flags |= argp->flags & MSDOSFSMNT_MNTOPT; 10433768Sache if (pmp->pm_flags & MSDOSFSMNT_U2WTABLE) { 10533747Sache bcopy(argp->u2w, pmp->pm_u2w, sizeof(pmp->pm_u2w)); 10633768Sache bcopy(argp->d2u, pmp->pm_d2u, sizeof(pmp->pm_d2u)); 10733768Sache bcopy(argp->u2d, pmp->pm_u2d, sizeof(pmp->pm_u2d)); 10833768Sache } 10933768Sache if (pmp->pm_flags & MSDOSFSMNT_ULTABLE) { 11033762Sache bcopy(argp->ul, pmp->pm_ul, sizeof(pmp->pm_ul)); 11133768Sache bcopy(argp->lu, pmp->pm_lu, sizeof(pmp->pm_lu)); 11233768Sache } 11333548Sjkh 11433548Sjkh#ifndef __FreeBSD__ 11533548Sjkh /* 11633548Sjkh * GEMDOS knows nothing (yet) about win95 11733548Sjkh */ 11833548Sjkh if (pmp->pm_flags & MSDOSFSMNT_GEMDOSFS) 11933548Sjkh pmp->pm_flags |= MSDOSFSMNT_NOWIN95; 12033548Sjkh#endif 12133548Sjkh 12233548Sjkh if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 12333548Sjkh pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 12433548Sjkh else if (!(pmp->pm_flags & 12533548Sjkh (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) { 12633548Sjkh struct vnode *rootvp; 12733548Sjkh 12833548Sjkh /* 12933548Sjkh * Try to divine whether to support Win'95 long filenames 13033548Sjkh */ 13133548Sjkh if (FAT32(pmp)) 13233548Sjkh pmp->pm_flags |= MSDOSFSMNT_LONGNAME; 13333548Sjkh else { 13433548Sjkh if ((error = msdosfs_root(mp, &rootvp)) != 0) 13533548Sjkh return error; 13633548Sjkh pmp->pm_flags |= findwin95(VTODE(rootvp)) 13733548Sjkh ? MSDOSFSMNT_LONGNAME 13833548Sjkh : MSDOSFSMNT_SHORTNAME; 13933548Sjkh vput(rootvp); 14033548Sjkh } 14133548Sjkh } 14233548Sjkh return 0; 14333548Sjkh} 14433548Sjkh 14533548Sjkh#ifndef __FreeBSD__ 14633548Sjkhint 14733548Sjkhmsdosfs_mountroot() 14833548Sjkh{ 14933548Sjkh register struct mount *mp; 15033548Sjkh struct proc *p = curproc; /* XXX */ 15133548Sjkh size_t size; 15233548Sjkh int error; 15333548Sjkh struct msdosfs_args args; 15433548Sjkh 15533548Sjkh if (root_device->dv_class != DV_DISK) 15633548Sjkh return (ENODEV); 15733548Sjkh 15833548Sjkh /* 15933548Sjkh * Get vnodes for swapdev and rootdev. 16033548Sjkh */ 16133548Sjkh if (bdevvp(rootdev, &rootvp)) 16233548Sjkh panic("msdosfs_mountroot: can't setup rootvp"); 16333548Sjkh 16433548Sjkh mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); 16533548Sjkh bzero((char *)mp, (u_long)sizeof(struct mount)); 16633548Sjkh mp->mnt_op = &msdosfs_vfsops; 16733548Sjkh mp->mnt_flag = 0; 16833548Sjkh LIST_INIT(&mp->mnt_vnodelist); 16933548Sjkh 17033548Sjkh args.flags = 0; 17133548Sjkh args.uid = 0; 17233548Sjkh args.gid = 0; 17333548Sjkh args.mask = 0777; 17433548Sjkh 17533548Sjkh if ((error = mountmsdosfs(rootvp, mp, p, &args)) != 0) { 17633548Sjkh free(mp, M_MOUNT); 17733548Sjkh return (error); 17833548Sjkh } 17933548Sjkh 18033548Sjkh if ((error = update_mp(mp, &args)) != 0) { 18133548Sjkh (void)msdosfs_unmount(mp, 0, p); 18233548Sjkh free(mp, M_MOUNT); 18333548Sjkh return (error); 18433548Sjkh } 18533548Sjkh 18633548Sjkh if ((error = vfs_lock(mp)) != 0) { 18733548Sjkh (void)msdosfs_unmount(mp, 0, p); 18833548Sjkh free(mp, M_MOUNT); 18933548Sjkh return (error); 19033548Sjkh } 19133548Sjkh 19253452Sphk TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); 19333548Sjkh mp->mnt_vnodecovered = NULLVP; 19433548Sjkh (void) copystr("/", mp->mnt_stat.f_mntonname, MNAMELEN - 1, 19533548Sjkh &size); 19633548Sjkh bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 19733548Sjkh (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 19833548Sjkh &size); 19933548Sjkh bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 20033548Sjkh (void)msdosfs_statfs(mp, &mp->mnt_stat, p); 20133548Sjkh vfs_unlock(mp); 20233548Sjkh return (0); 20333548Sjkh} 20433548Sjkh#endif 20533548Sjkh 2062893Sdfr/* 2078876Srgrimes * mp - path - addr in user space of mount point (ie /usr or whatever) 2082893Sdfr * data - addr in user space of mount params including the name of the block 2098876Srgrimes * special file to treat as a filesystem. 2102893Sdfr */ 21112144Sphkstatic int 2122893Sdfrmsdosfs_mount(mp, path, data, ndp, p) 2132893Sdfr struct mount *mp; 2142893Sdfr char *path; 2152893Sdfr caddr_t data; 2162893Sdfr struct nameidata *ndp; 2172893Sdfr struct proc *p; 2182893Sdfr{ 2192893Sdfr struct vnode *devvp; /* vnode for blk device to mount */ 2202893Sdfr struct msdosfs_args args; /* will hold data from mount request */ 22133548Sjkh /* msdosfs specific mount control block */ 22233548Sjkh struct msdosfsmount *pmp = NULL; 22333548Sjkh size_t size; 2242893Sdfr int error, flags; 22533548Sjkh mode_t accessmode; 2262893Sdfr 22733548Sjkh error = copyin(data, (caddr_t)&args, sizeof(struct msdosfs_args)); 2283152Sphk if (error) 22933548Sjkh return (error); 23035202Sdt if (args.magic != MSDOSFS_ARGSMAGIC) 23133548Sjkh args.flags = 0; 2322893Sdfr /* 23333548Sjkh * If updating, check whether changing from read-only to 23433548Sjkh * read/write; if there is no device name, that's all we do. 2352893Sdfr */ 2362893Sdfr if (mp->mnt_flag & MNT_UPDATE) { 23733548Sjkh pmp = VFSTOMSDOSFS(mp); 2382893Sdfr error = 0; 23933548Sjkh if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_flag & MNT_RDONLY)) { 2402893Sdfr flags = WRITECLOSE; 2412893Sdfr if (mp->mnt_flag & MNT_FORCE) 2422893Sdfr flags |= FORCECLOSE; 2432893Sdfr error = vflush(mp, NULLVP, flags); 2442893Sdfr } 2452893Sdfr if (!error && (mp->mnt_flag & MNT_RELOAD)) 2462893Sdfr /* not yet implemented */ 24733548Sjkh error = EOPNOTSUPP; 2482893Sdfr if (error) 24933548Sjkh return (error); 25033548Sjkh if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_kern_flag & MNTK_WANTRDWR)) { 25133548Sjkh /* 25233548Sjkh * If upgrade to read-write by non-root, then verify 25333548Sjkh * that user has necessary permissions on the device. 25433548Sjkh */ 25533548Sjkh if (p->p_ucred->cr_uid != 0) { 25633548Sjkh devvp = pmp->pm_devvp; 25735202Sdt vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 25833548Sjkh error = VOP_ACCESS(devvp, VREAD | VWRITE, 25933548Sjkh p->p_ucred, p); 26033548Sjkh if (error) { 26133548Sjkh VOP_UNLOCK(devvp, 0, p); 26233548Sjkh return (error); 26333548Sjkh } 26433548Sjkh VOP_UNLOCK(devvp, 0, p); 26533548Sjkh } 26633548Sjkh pmp->pm_flags &= ~MSDOSFSMNT_RONLY; 26733548Sjkh } 2682893Sdfr if (args.fspec == 0) { 26933548Sjkh#ifdef __notyet__ /* doesn't work correctly with current mountd XXX */ 27033548Sjkh if (args.flags & MSDOSFSMNT_MNTOPT) { 27133548Sjkh pmp->pm_flags &= ~MSDOSFSMNT_MNTOPT; 27233548Sjkh pmp->pm_flags |= args.flags & MSDOSFSMNT_MNTOPT; 27333548Sjkh if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 27433548Sjkh pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 27533548Sjkh } 27633548Sjkh#endif 2772893Sdfr /* 2782893Sdfr * Process export requests. 2792893Sdfr */ 28033548Sjkh return (vfs_export(mp, &pmp->pm_export, &args.export)); 2812893Sdfr } 2822893Sdfr } 2832893Sdfr /* 28433548Sjkh * Not an update, or updating the name: look up the name 28533548Sjkh * and verify that it refers to a sensible block device. 2862893Sdfr */ 2872893Sdfr NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 2882893Sdfr error = namei(ndp); 28933548Sjkh if (error) 29033548Sjkh return (error); 29133548Sjkh devvp = ndp->ni_vp; 29254655Seivind NDFREE(ndp, NDF_ONLY_PNBUF); 2938876Srgrimes 29455756Sphk if (!vn_isdisk(devvp, &error)) { 2952893Sdfr vrele(devvp); 29655756Sphk return (error); 2972893Sdfr } 2982893Sdfr /* 29933548Sjkh * If mount by non-root, then verify that user has necessary 30033548Sjkh * permissions on the device. 3012893Sdfr */ 30233548Sjkh if (p->p_ucred->cr_uid != 0) { 30333548Sjkh accessmode = VREAD; 30433548Sjkh if ((mp->mnt_flag & MNT_RDONLY) == 0) 30533548Sjkh accessmode |= VWRITE; 30633548Sjkh vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 30733548Sjkh error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p); 30833548Sjkh if (error) { 30933548Sjkh vput(devvp); 31033548Sjkh return (error); 31133548Sjkh } 31233548Sjkh VOP_UNLOCK(devvp, 0, p); 31333548Sjkh } 31433548Sjkh if ((mp->mnt_flag & MNT_UPDATE) == 0) { 31533548Sjkh error = mountmsdosfs(devvp, mp, p, &args); 31633548Sjkh#ifdef MSDOSFS_DEBUG /* only needed for the printf below */ 31733548Sjkh pmp = VFSTOMSDOSFS(mp); 31833548Sjkh#endif 31933548Sjkh } else { 3202893Sdfr if (devvp != pmp->pm_devvp) 32133548Sjkh error = EINVAL; /* XXX needs translation */ 3222893Sdfr else 3232893Sdfr vrele(devvp); 3242893Sdfr } 3252893Sdfr if (error) { 3262893Sdfr vrele(devvp); 32733548Sjkh return (error); 32833548Sjkh } 32933548Sjkh 33033548Sjkh error = update_mp(mp, &args); 33133548Sjkh if (error) { 33233548Sjkh msdosfs_unmount(mp, MNT_FORCE, p); 3332893Sdfr return error; 3342893Sdfr } 3352893Sdfr 33633548Sjkh (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); 33733548Sjkh bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 33833548Sjkh (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 33933548Sjkh &size); 34033548Sjkh bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 3412893Sdfr (void) msdosfs_statfs(mp, &mp->mnt_stat, p); 3422893Sdfr#ifdef MSDOSFS_DEBUG 3433311Sphk printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); 3442893Sdfr#endif 34533548Sjkh return (0); 3462893Sdfr} 3472893Sdfr 34812144Sphkstatic int 34933548Sjkhmountmsdosfs(devvp, mp, p, argp) 3502893Sdfr struct vnode *devvp; 3512893Sdfr struct mount *mp; 3522893Sdfr struct proc *p; 35333548Sjkh struct msdosfs_args *argp; 3542893Sdfr{ 35533548Sjkh struct msdosfsmount *pmp; 35633548Sjkh struct buf *bp; 3572893Sdfr dev_t dev = devvp->v_rdev; 35833548Sjkh#ifndef __FreeBSD__ 35933548Sjkh struct partinfo dpart; 36041591Sarchie int bsize = 0, dtype = 0, tmp; 36133548Sjkh#endif 3622893Sdfr union bootsector *bsp; 3632893Sdfr struct byte_bpb33 *b33; 3642893Sdfr struct byte_bpb50 *b50; 36533548Sjkh struct byte_bpb710 *b710; 36633548Sjkh u_int8_t SecPerClust; 36755188Sbp u_long clusters; 36833548Sjkh int ronly, error; 3692893Sdfr 3702893Sdfr /* 37133548Sjkh * Disallow multiple mounts of the same device. 37233548Sjkh * Disallow mounting of a device that is currently in use 37333548Sjkh * (except for root, which might share swap device for miniroot). 37433548Sjkh * Flush out any old buffers remaining from a previous use. 3752893Sdfr */ 3763152Sphk error = vfs_mountedon(devvp); 3773152Sphk if (error) 37833548Sjkh return (error); 37933548Sjkh if (vcount(devvp) > 1 && devvp != rootvp) 38033548Sjkh return (EBUSY); 38133548Sjkh vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 3823152Sphk error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0); 38333548Sjkh VOP_UNLOCK(devvp, 0, p); 3843152Sphk if (error) 38533548Sjkh return (error); 3862893Sdfr 38733548Sjkh ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 38853059Sphk vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 38933548Sjkh error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p); 39053059Sphk VOP_UNLOCK(devvp, 0, p); 3913152Sphk if (error) 39233548Sjkh return (error); 39333548Sjkh 39433548Sjkh bp = NULL; /* both used in error_exit */ 39533548Sjkh pmp = NULL; 39633548Sjkh 39733548Sjkh#ifndef __FreeBSD__ 39833548Sjkh if (argp->flags & MSDOSFSMNT_GEMDOSFS) { 39933548Sjkh /* 40033548Sjkh * We need the disklabel to calculate the size of a FAT entry 40133548Sjkh * later on. Also make sure the partition contains a filesystem 40233548Sjkh * of type FS_MSDOS. This doesn't work for floppies, so we have 40333548Sjkh * to check for them too. 40433548Sjkh * 40533548Sjkh * At least some parts of the msdos fs driver seem to assume 40633548Sjkh * that the size of a disk block will always be 512 bytes. 40733548Sjkh * Let's check it... 40833548Sjkh */ 40933548Sjkh error = VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, 41033548Sjkh FREAD, NOCRED, p); 41133548Sjkh if (error) 41233548Sjkh goto error_exit; 41333548Sjkh tmp = dpart.part->p_fstype; 41433548Sjkh dtype = dpart.disklab->d_type; 41533548Sjkh bsize = dpart.disklab->d_secsize; 41633548Sjkh if (bsize != 512 || (dtype!=DTYPE_FLOPPY && tmp!=FS_MSDOS)) { 41733548Sjkh error = EINVAL; 41833548Sjkh goto error_exit; 41933548Sjkh } 4202893Sdfr } 4212893Sdfr#endif 4222893Sdfr 4232893Sdfr /* 42433548Sjkh * Read the boot sector of the filesystem, and then check the 42533548Sjkh * boot signature. If not a dos boot sector then error out. 4262893Sdfr */ 42716363Sasami#ifdef PC98 42833548Sjkh error = bread(devvp, 0, 1024, NOCRED, &bp); 42916363Sasami#else 43033548Sjkh error = bread(devvp, 0, 512, NOCRED, &bp); 43116363Sasami#endif 4323152Sphk if (error) 4332893Sdfr goto error_exit; 43433548Sjkh bp->b_flags |= B_AGE; 43533548Sjkh bsp = (union bootsector *)bp->b_data; 43633548Sjkh b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB; 43733548Sjkh b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB; 43833548Sjkh b710 = (struct byte_bpb710 *)bsp->bs710.bsPBP; 43933548Sjkh 44033548Sjkh#ifndef __FreeBSD__ 44133548Sjkh if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) { 44233548Sjkh#endif 44333548Sjkh#ifdef PC98 44433765Skato if ((bsp->bs50.bsBootSectSig0 != BOOTSIG0 44533765Skato || bsp->bs50.bsBootSectSig1 != BOOTSIG1) 44633765Skato && (bsp->bs50.bsBootSectSig0 != 0 /* PC98 DOS 3.3x */ 44733765Skato || bsp->bs50.bsBootSectSig1 != 0) 44833765Skato && (bsp->bs50.bsBootSectSig0 != 0x90 /* PC98 DOS 5.0 */ 44933765Skato || bsp->bs50.bsBootSectSig1 != 0x3d) 45033765Skato && (bsp->bs50.bsBootSectSig0 != 0x46 /* PC98 DOS 3.3B */ 45133765Skato || bsp->bs50.bsBootSectSig1 != 0xfa)) { 45216363Sasami#else 45333548Sjkh if (bsp->bs50.bsBootSectSig0 != BOOTSIG0 45433548Sjkh || bsp->bs50.bsBootSectSig1 != BOOTSIG1) { 45516363Sasami#endif 45633548Sjkh error = EINVAL; 45733548Sjkh goto error_exit; 45833548Sjkh } 45933548Sjkh#ifndef __FreeBSD__ 4602893Sdfr } 4612893Sdfr#endif 4622893Sdfr 4632893Sdfr pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK); 4642893Sdfr bzero((caddr_t)pmp, sizeof *pmp); 4652893Sdfr pmp->pm_mountp = mp; 4662893Sdfr 4672893Sdfr /* 4682893Sdfr * Compute several useful quantities from the bpb in the 4692893Sdfr * bootsector. Copy in the dos 5 variant of the bpb then fix up 4702893Sdfr * the fields that are different between dos 5 and dos 3.3. 4712893Sdfr */ 47233548Sjkh SecPerClust = b50->bpbSecPerClust; 4732893Sdfr pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 4742893Sdfr pmp->pm_ResSectors = getushort(b50->bpbResSectors); 4752893Sdfr pmp->pm_FATs = b50->bpbFATs; 4762893Sdfr pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 4772893Sdfr pmp->pm_Sectors = getushort(b50->bpbSectors); 4782893Sdfr pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 4792893Sdfr pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 4802893Sdfr pmp->pm_Heads = getushort(b50->bpbHeads); 48133548Sjkh pmp->pm_Media = b50->bpbMedia; 4822893Sdfr 48333548Sjkh#ifndef __FreeBSD__ 48433548Sjkh if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) { 48533548Sjkh#endif 48633548Sjkh /* XXX - We should probably check more values here */ 48733548Sjkh if (!pmp->pm_BytesPerSec || !SecPerClust 48833548Sjkh || !pmp->pm_Heads || pmp->pm_Heads > 255 48916363Sasami#ifdef PC98 49033548Sjkh || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) { 49116363Sasami#else 49233548Sjkh || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) { 49316363Sasami#endif 49433548Sjkh error = EINVAL; 49533548Sjkh goto error_exit; 49633548Sjkh } 49733548Sjkh#ifndef __FreeBSD__ 4982893Sdfr } 49933548Sjkh#endif 5002893Sdfr 5012893Sdfr if (pmp->pm_Sectors == 0) { 5022893Sdfr pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 5032893Sdfr pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 5042893Sdfr } else { 5052893Sdfr pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 5062893Sdfr pmp->pm_HugeSectors = pmp->pm_Sectors; 5072893Sdfr } 50835511Sdt if (pmp->pm_HugeSectors > 0xffffffff / 50935511Sdt (pmp->pm_BytesPerSec / sizeof(struct direntry)) + 1) { 51033548Sjkh /* 51133548Sjkh * We cannot deal currently with this size of disk 51233548Sjkh * due to fileid limitations (see msdosfs_getattr and 51333548Sjkh * msdosfs_readdir) 51433548Sjkh */ 51533548Sjkh error = EINVAL; 51635046Sache printf("mountmsdosfs(): disk too big, sorry\n"); 51733548Sjkh goto error_exit; 51833548Sjkh } 51933548Sjkh 52033548Sjkh if (pmp->pm_RootDirEnts == 0) { 52133548Sjkh if (bsp->bs710.bsBootSectSig2 != BOOTSIG2 52233548Sjkh || bsp->bs710.bsBootSectSig3 != BOOTSIG3 52333548Sjkh || pmp->pm_Sectors 52433548Sjkh || pmp->pm_FATsecs 52533548Sjkh || getushort(b710->bpbFSVers)) { 52633548Sjkh error = EINVAL; 52735046Sache printf("mountmsdosfs(): bad FAT32 filesystem\n"); 52833548Sjkh goto error_exit; 52933548Sjkh } 53033548Sjkh pmp->pm_fatmask = FAT32_MASK; 53133548Sjkh pmp->pm_fatmult = 4; 53233548Sjkh pmp->pm_fatdiv = 1; 53333548Sjkh pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs); 53433548Sjkh if (getushort(b710->bpbExtFlags) & FATMIRROR) 53533548Sjkh pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM; 53633548Sjkh else 53733548Sjkh pmp->pm_flags |= MSDOSFS_FATMIRROR; 53833548Sjkh } else 53933548Sjkh pmp->pm_flags |= MSDOSFS_FATMIRROR; 54033548Sjkh 54133548Sjkh#ifndef __FreeBSD__ 54233548Sjkh if (argp->flags & MSDOSFSMNT_GEMDOSFS) { 54333548Sjkh if (FAT32(pmp)) { 54433548Sjkh /* 54533548Sjkh * GEMDOS doesn't know fat32. 54633548Sjkh */ 54733548Sjkh error = EINVAL; 54833548Sjkh goto error_exit; 54933548Sjkh } 55033548Sjkh 55133548Sjkh /* 55233548Sjkh * Check a few values (could do some more): 55333548Sjkh * - logical sector size: power of 2, >= block size 55433548Sjkh * - sectors per cluster: power of 2, >= 1 55533548Sjkh * - number of sectors: >= 1, <= size of partition 55633548Sjkh */ 55733548Sjkh if ( (SecPerClust == 0) 55833548Sjkh || (SecPerClust & (SecPerClust - 1)) 55933548Sjkh || (pmp->pm_BytesPerSec < bsize) 56033548Sjkh || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) 56133548Sjkh || (pmp->pm_HugeSectors == 0) 56233548Sjkh || (pmp->pm_HugeSectors * (pmp->pm_BytesPerSec / bsize) 56333548Sjkh > dpart.part->p_size) 56433548Sjkh ) { 56533548Sjkh error = EINVAL; 56633548Sjkh goto error_exit; 56733548Sjkh } 56833548Sjkh /* 56933548Sjkh * XXX - Many parts of the msdos fs driver seem to assume that 57033548Sjkh * the number of bytes per logical sector (BytesPerSec) will 57133548Sjkh * always be the same as the number of bytes per disk block 57233548Sjkh * Let's pretend it is. 57333548Sjkh */ 57433548Sjkh tmp = pmp->pm_BytesPerSec / bsize; 57533548Sjkh pmp->pm_BytesPerSec = bsize; 57633548Sjkh pmp->pm_HugeSectors *= tmp; 57733548Sjkh pmp->pm_HiddenSects *= tmp; 57833548Sjkh pmp->pm_ResSectors *= tmp; 57933548Sjkh pmp->pm_Sectors *= tmp; 58033548Sjkh pmp->pm_FATsecs *= tmp; 58133548Sjkh SecPerClust *= tmp; 58233548Sjkh } 58333548Sjkh#endif 5842893Sdfr pmp->pm_fatblk = pmp->pm_ResSectors; 58533548Sjkh if (FAT32(pmp)) { 58633548Sjkh pmp->pm_rootdirblk = getulong(b710->bpbRootClust); 58733548Sjkh pmp->pm_firstcluster = pmp->pm_fatblk 58833548Sjkh + (pmp->pm_FATs * pmp->pm_FATsecs); 58933548Sjkh pmp->pm_fsinfo = getushort(b710->bpbFSInfo); 59033548Sjkh } else { 59133548Sjkh pmp->pm_rootdirblk = pmp->pm_fatblk + 59233548Sjkh (pmp->pm_FATs * pmp->pm_FATsecs); 59333548Sjkh pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry) 59433548Sjkh + pmp->pm_BytesPerSec - 1) 59533548Sjkh / pmp->pm_BytesPerSec;/* in sectors */ 59633548Sjkh pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 59733548Sjkh } 59833548Sjkh 59955188Sbp pmp->pm_maxcluster = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 60055188Sbp SecPerClust + 1; 6012893Sdfr pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec; 60233548Sjkh 60333548Sjkh#ifndef __FreeBSD__ 60433548Sjkh if (argp->flags & MSDOSFSMNT_GEMDOSFS) { 60555188Sbp if ((pmp->pm_maxcluster <= (0xff0 - 2)) 60633548Sjkh && ((dtype == DTYPE_FLOPPY) || ((dtype == DTYPE_VNODE) 60733548Sjkh && ((pmp->pm_Heads == 1) || (pmp->pm_Heads == 2)))) 60833548Sjkh ) { 60933548Sjkh pmp->pm_fatmask = FAT12_MASK; 61033548Sjkh pmp->pm_fatmult = 3; 61133548Sjkh pmp->pm_fatdiv = 2; 61233548Sjkh } else { 61333548Sjkh pmp->pm_fatmask = FAT16_MASK; 61433548Sjkh pmp->pm_fatmult = 2; 61533548Sjkh pmp->pm_fatdiv = 1; 61633548Sjkh } 61733548Sjkh } else 61833548Sjkh#endif 61933548Sjkh if (pmp->pm_fatmask == 0) { 62033548Sjkh if (pmp->pm_maxcluster 62133548Sjkh <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) { 62233548Sjkh /* 62333548Sjkh * This will usually be a floppy disk. This size makes 62433548Sjkh * sure that one fat entry will not be split across 62533548Sjkh * multiple blocks. 62633548Sjkh */ 62733548Sjkh pmp->pm_fatmask = FAT12_MASK; 62833548Sjkh pmp->pm_fatmult = 3; 62933548Sjkh pmp->pm_fatdiv = 2; 63033548Sjkh } else { 63133548Sjkh pmp->pm_fatmask = FAT16_MASK; 63233548Sjkh pmp->pm_fatmult = 2; 63333548Sjkh pmp->pm_fatdiv = 1; 63433548Sjkh } 63533548Sjkh } 63655188Sbp 63755188Sbp clusters = (pmp->pm_fatsize / pmp->pm_fatmult) * pmp->pm_fatdiv; 63855188Sbp if (pmp->pm_maxcluster >= clusters) { 63955188Sbp printf("Warning: number of clusters (%ld) exceeds FAT " 64055188Sbp "capacity (%ld)\n", pmp->pm_maxcluster + 1, clusters); 64155188Sbp pmp->pm_maxcluster = clusters - 1; 64255188Sbp } 64355188Sbp 64455188Sbp 6452893Sdfr if (FAT12(pmp)) 6462893Sdfr pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; 6472893Sdfr else 64835511Sdt pmp->pm_fatblocksize = DFLTBSIZE; 64933548Sjkh 6502893Sdfr pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec; 65133548Sjkh pmp->pm_bnshift = ffs(pmp->pm_BytesPerSec) - 1; 6522893Sdfr 6532893Sdfr /* 6542893Sdfr * Compute mask and shift value for isolating cluster relative byte 6552893Sdfr * offsets and cluster numbers from a file offset. 6562893Sdfr */ 65733548Sjkh pmp->pm_bpcluster = SecPerClust * pmp->pm_BytesPerSec; 65833548Sjkh pmp->pm_crbomask = pmp->pm_bpcluster - 1; 65933548Sjkh pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1; 66033548Sjkh 66133548Sjkh /* 66233548Sjkh * Check for valid cluster size 66333548Sjkh * must be a power of 2 66433548Sjkh */ 66533548Sjkh if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) { 6662893Sdfr error = EINVAL; 6672893Sdfr goto error_exit; 6682893Sdfr } 6692893Sdfr 67033548Sjkh /* 67133548Sjkh * Release the bootsector buffer. 67233548Sjkh */ 67333548Sjkh brelse(bp); 67433548Sjkh bp = NULL; 67533548Sjkh 67633548Sjkh /* 67733548Sjkh * Check FSInfo. 67833548Sjkh */ 67933548Sjkh if (pmp->pm_fsinfo) { 68033548Sjkh struct fsinfo *fp; 68133548Sjkh 68233548Sjkh if ((error = bread(devvp, pmp->pm_fsinfo, 1024, NOCRED, &bp)) != 0) 68333548Sjkh goto error_exit; 68433548Sjkh fp = (struct fsinfo *)bp->b_data; 68533548Sjkh if (!bcmp(fp->fsisig1, "RRaA", 4) 68633548Sjkh && !bcmp(fp->fsisig2, "rrAa", 4) 68733548Sjkh && !bcmp(fp->fsisig3, "\0\0\125\252", 4) 68833548Sjkh && !bcmp(fp->fsisig4, "\0\0\125\252", 4)) 68933548Sjkh pmp->pm_nxtfree = getulong(fp->fsinxtfree); 69033548Sjkh else 69133548Sjkh pmp->pm_fsinfo = 0; 69233548Sjkh brelse(bp); 69333548Sjkh bp = NULL; 69416363Sasami } 6952893Sdfr 6962893Sdfr /* 69733548Sjkh * Check and validate (or perhaps invalidate?) the fsinfo structure? XXX 6982893Sdfr */ 6992893Sdfr 7002893Sdfr /* 7012893Sdfr * Allocate memory for the bitmap of allocated clusters, and then 7022893Sdfr * fill it in. 7032893Sdfr */ 7042893Sdfr pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS - 1) 7052893Sdfr / N_INUSEBITS) 7062893Sdfr * sizeof(*pmp->pm_inusemap), 7072893Sdfr M_MSDOSFSFAT, M_WAITOK); 7082893Sdfr 7092893Sdfr /* 7102893Sdfr * fillinusemap() needs pm_devvp. 7112893Sdfr */ 7122893Sdfr pmp->pm_dev = dev; 7132893Sdfr pmp->pm_devvp = devvp; 7142893Sdfr 7152893Sdfr /* 7162893Sdfr * Have the inuse map filled in. 7172893Sdfr */ 71833548Sjkh if ((error = fillinusemap(pmp)) != 0) 7192893Sdfr goto error_exit; 7202893Sdfr 7212893Sdfr /* 7222893Sdfr * If they want fat updates to be synchronous then let them suffer 7232893Sdfr * the performance degradation in exchange for the on disk copy of 7242893Sdfr * the fat being correct just about all the time. I suppose this 7252893Sdfr * would be a good thing to turn on if the kernel is still flakey. 7262893Sdfr */ 72733548Sjkh if (mp->mnt_flag & MNT_SYNCHRONOUS) 72833548Sjkh pmp->pm_flags |= MSDOSFSMNT_WAITONFAT; 7292893Sdfr 7302893Sdfr /* 7312893Sdfr * Finish up. 7322893Sdfr */ 73333548Sjkh if (ronly) 73433548Sjkh pmp->pm_flags |= MSDOSFSMNT_RONLY; 73533548Sjkh else 7362893Sdfr pmp->pm_fmod = 1; 7372893Sdfr mp->mnt_data = (qaddr_t) pmp; 73850256Sbde mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); 73923134Sbde mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 74023997Speter mp->mnt_flag |= MNT_LOCAL; 74134266Sjulian devvp->v_specmountpoint = mp; 7422893Sdfr 7432893Sdfr return 0; 7442893Sdfr 74533548Sjkherror_exit: 74633548Sjkh if (bp) 74733548Sjkh brelse(bp); 74833548Sjkh (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE, NOCRED, p); 7492893Sdfr if (pmp) { 7502893Sdfr if (pmp->pm_inusemap) 75133548Sjkh free(pmp->pm_inusemap, M_MSDOSFSFAT); 75233548Sjkh free(pmp, M_MSDOSFSMNT); 75333548Sjkh mp->mnt_data = (qaddr_t)0; 7542893Sdfr } 75533548Sjkh return (error); 7562893Sdfr} 7572893Sdfr 7582893Sdfr/* 7592893Sdfr * Unmount the filesystem described by mp. 7602893Sdfr */ 76112144Sphkstatic int 7622893Sdfrmsdosfs_unmount(mp, mntflags, p) 7632893Sdfr struct mount *mp; 7642893Sdfr int mntflags; 7652893Sdfr struct proc *p; 7662893Sdfr{ 76733548Sjkh struct msdosfsmount *pmp; 76833548Sjkh int error, flags; 7692893Sdfr 77033548Sjkh flags = 0; 77133548Sjkh if (mntflags & MNT_FORCE) 7722893Sdfr flags |= FORCECLOSE; 7733152Sphk error = vflush(mp, NULLVP, flags); 7743152Sphk if (error) 7752893Sdfr return error; 77633548Sjkh pmp = VFSTOMSDOSFS(mp); 77734266Sjulian pmp->pm_devvp->v_specmountpoint = NULL; 77833548Sjkh#ifdef MSDOSFS_DEBUG 77933548Sjkh { 78033548Sjkh struct vnode *vp = pmp->pm_devvp; 78133548Sjkh 78233548Sjkh printf("msdosfs_umount(): just before calling VOP_CLOSE()\n"); 78333548Sjkh printf("flag %08lx, usecount %d, writecount %d, holdcnt %ld\n", 78433548Sjkh vp->v_flag, vp->v_usecount, vp->v_writecount, vp->v_holdcnt); 78551486Sdillon printf("id %lu, mount %p, op %p\n", 78651486Sdillon vp->v_id, vp->v_mount, vp->v_op); 78733548Sjkh printf("freef %p, freeb %p, mount %p\n", 78833548Sjkh vp->v_freelist.tqe_next, vp->v_freelist.tqe_prev, 78933548Sjkh vp->v_mount); 79033548Sjkh printf("cleanblkhd %p, dirtyblkhd %p, numoutput %ld, type %d\n", 79140790Speter TAILQ_FIRST(&vp->v_cleanblkhd), 79240790Speter TAILQ_FIRST(&vp->v_dirtyblkhd), 79333548Sjkh vp->v_numoutput, vp->v_type); 79433548Sjkh printf("union %p, tag %d, data[0] %08x, data[1] %08x\n", 79533548Sjkh vp->v_socket, vp->v_tag, 79633548Sjkh ((u_int *)vp->v_data)[0], 79733548Sjkh ((u_int *)vp->v_data)[1]); 79833548Sjkh } 79933548Sjkh#endif 80034266Sjulian error = VOP_CLOSE(pmp->pm_devvp, 80134266Sjulian (pmp->pm_flags&MSDOSFSMNT_RONLY) ? FREAD : FREAD | FWRITE, 80234266Sjulian NOCRED, p); 8032893Sdfr vrele(pmp->pm_devvp); 80433548Sjkh free(pmp->pm_inusemap, M_MSDOSFSFAT); 80533548Sjkh free(pmp, M_MSDOSFSMNT); 80633548Sjkh mp->mnt_data = (qaddr_t)0; 80723997Speter mp->mnt_flag &= ~MNT_LOCAL; 80833548Sjkh return (error); 8092893Sdfr} 8102893Sdfr 81112144Sphkstatic int 8122893Sdfrmsdosfs_root(mp, vpp) 8132893Sdfr struct mount *mp; 8142893Sdfr struct vnode **vpp; 8152893Sdfr{ 81633548Sjkh struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 8172893Sdfr struct denode *ndep; 8182893Sdfr int error; 8192893Sdfr 8202893Sdfr#ifdef MSDOSFS_DEBUG 82133548Sjkh printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp); 8222893Sdfr#endif 82333548Sjkh error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep); 82433548Sjkh if (error) 82533548Sjkh return (error); 82633548Sjkh *vpp = DETOV(ndep); 82733548Sjkh return (0); 8282893Sdfr} 8292893Sdfr 83012144Sphkstatic int 8312893Sdfrmsdosfs_statfs(mp, sbp, p) 8322893Sdfr struct mount *mp; 8332893Sdfr struct statfs *sbp; 8342893Sdfr struct proc *p; 8352893Sdfr{ 83633548Sjkh struct msdosfsmount *pmp; 8372893Sdfr 83833548Sjkh pmp = VFSTOMSDOSFS(mp); 8392893Sdfr sbp->f_bsize = pmp->pm_bpcluster; 8402893Sdfr sbp->f_iosize = pmp->pm_bpcluster; 84155188Sbp sbp->f_blocks = pmp->pm_maxcluster + 1; 8422893Sdfr sbp->f_bfree = pmp->pm_freeclustercount; 8432893Sdfr sbp->f_bavail = pmp->pm_freeclustercount; 8442893Sdfr sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ 8452893Sdfr sbp->f_ffree = 0; /* what to put in here? */ 8462893Sdfr if (sbp != &mp->mnt_stat) { 84723134Sbde sbp->f_type = mp->mnt_vfc->vfc_typenum; 84833548Sjkh bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 84933548Sjkh bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 8502893Sdfr } 85133548Sjkh strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN); 85233548Sjkh return (0); 8532893Sdfr} 8542893Sdfr 85512144Sphkstatic int 8562893Sdfrmsdosfs_sync(mp, waitfor, cred, p) 8572893Sdfr struct mount *mp; 8582893Sdfr int waitfor; 8592893Sdfr struct ucred *cred; 8602893Sdfr struct proc *p; 8612893Sdfr{ 86233548Sjkh struct vnode *vp, *nvp; 8632893Sdfr struct denode *dep; 86433548Sjkh struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 86533548Sjkh int error, allerror = 0; 8662893Sdfr 8672893Sdfr /* 8682893Sdfr * If we ever switch to not updating all of the fats all the time, 8692893Sdfr * this would be the place to update them from the first one. 8702893Sdfr */ 87146568Speter if (pmp->pm_fmod != 0) { 87233548Sjkh if (pmp->pm_flags & MSDOSFSMNT_RONLY) 8732893Sdfr panic("msdosfs_sync: rofs mod"); 8742893Sdfr else { 8752893Sdfr /* update fats here */ 8762893Sdfr } 87746568Speter } 8782893Sdfr /* 87933548Sjkh * Write back each (modified) denode. 8802893Sdfr */ 88123134Sbde simple_lock(&mntvnode_slock); 8822893Sdfrloop: 88335511Sdt for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { 88433548Sjkh /* 88533548Sjkh * If the vnode that we are about to sync is no longer 88635511Sdt * associated with this mount point, start over. 88733548Sjkh */ 88833548Sjkh if (vp->v_mount != mp) 8892893Sdfr goto loop; 89033548Sjkh 89123134Sbde simple_lock(&vp->v_interlock); 89233548Sjkh nvp = vp->v_mntvnodes.le_next; 8932893Sdfr dep = VTODE(vp); 89435511Sdt if (vp->v_type == VNON || 89543305Sdillon ((dep->de_flag & 89635511Sdt (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0 && 89743305Sdillon (TAILQ_EMPTY(&vp->v_dirtyblkhd) || waitfor == MNT_LAZY))) { 89823134Sbde simple_unlock(&vp->v_interlock); 8992893Sdfr continue; 90023134Sbde } 90123134Sbde simple_unlock(&mntvnode_slock); 90223134Sbde error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); 90323134Sbde if (error) { 90423134Sbde simple_lock(&mntvnode_slock); 90523134Sbde if (error == ENOENT) 90623134Sbde goto loop; 90723134Sbde continue; 90823134Sbde } 9093152Sphk error = VOP_FSYNC(vp, cred, waitfor, p); 9103152Sphk if (error) 9112893Sdfr allerror = error; 91223134Sbde VOP_UNLOCK(vp, 0, p); 91335511Sdt vrele(vp); 91423134Sbde simple_lock(&mntvnode_slock); 9152893Sdfr } 91623134Sbde simple_unlock(&mntvnode_slock); 9172893Sdfr 9182893Sdfr /* 9192893Sdfr * Flush filesystem control info. 9202893Sdfr */ 92135511Sdt if (waitfor != MNT_LAZY) { 92235511Sdt vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY, p); 92335511Sdt error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p); 92435511Sdt if (error) 92535511Sdt allerror = error; 92635511Sdt VOP_UNLOCK(pmp->pm_devvp, 0, p); 92735511Sdt } 92833548Sjkh return (allerror); 9292893Sdfr} 9302893Sdfr 93112144Sphkstatic int 93251138Salfredmsdosfs_fhtovp(mp, fhp, vpp) 9332893Sdfr struct mount *mp; 9342893Sdfr struct fid *fhp; 9352893Sdfr struct vnode **vpp; 9362893Sdfr{ 93733548Sjkh struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 9382893Sdfr struct defid *defhp = (struct defid *) fhp; 9392893Sdfr struct denode *dep; 9402893Sdfr int error; 9412893Sdfr 94233548Sjkh error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep); 9432893Sdfr if (error) { 9442893Sdfr *vpp = NULLVP; 94533548Sjkh return (error); 9462893Sdfr } 9472893Sdfr *vpp = DETOV(dep); 94851138Salfred return (0); 94951138Salfred} 95051138Salfred 95151138Salfredstatic int 95251138Salfredmsdosfs_checkexp(mp, nam, exflagsp, credanonp) 95351138Salfred struct mount *mp; 95451138Salfred struct sockaddr *nam; 95551138Salfred int *exflagsp; 95651138Salfred struct ucred **credanonp; 95751138Salfred{ 95851138Salfred struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 95951138Salfred struct netcred *np; 96051138Salfred 96151138Salfred np = vfs_export_lookup(mp, &pmp->pm_export, nam); 96251138Salfred if (np == NULL) 96351138Salfred return (EACCES); 9642893Sdfr *exflagsp = np->netc_exflags; 9652893Sdfr *credanonp = &np->netc_anon; 96633548Sjkh return (0); 9672893Sdfr} 9682893Sdfr 96912144Sphkstatic int 9702893Sdfrmsdosfs_vptofh(vp, fhp) 9712893Sdfr struct vnode *vp; 9722893Sdfr struct fid *fhp; 9732893Sdfr{ 97433548Sjkh struct denode *dep; 97533548Sjkh struct defid *defhp; 9762893Sdfr 97733548Sjkh dep = VTODE(vp); 97833548Sjkh defhp = (struct defid *)fhp; 9792893Sdfr defhp->defid_len = sizeof(struct defid); 9802893Sdfr defhp->defid_dirclust = dep->de_dirclust; 9812893Sdfr defhp->defid_dirofs = dep->de_diroffset; 98233548Sjkh /* defhp->defid_gen = dep->de_gen; */ 98333548Sjkh return (0); 9842893Sdfr} 9852893Sdfr 98612145Sphkstatic struct vfsops msdosfs_vfsops = { 9872893Sdfr msdosfs_mount, 98851068Salfred vfs_stdstart, 9892893Sdfr msdosfs_unmount, 9902893Sdfr msdosfs_root, 99151068Salfred vfs_stdquotactl, 9922893Sdfr msdosfs_statfs, 9932893Sdfr msdosfs_sync, 99451068Salfred vfs_stdvget, 9952893Sdfr msdosfs_fhtovp, 99651138Salfred msdosfs_checkexp, 9972893Sdfr msdosfs_vptofh, 99854803Srwatson msdosfs_init, 99954803Srwatson vfs_stduninit, 100054803Srwatson vfs_stdextattrctl, 10012893Sdfr}; 10022946Swollman 100338909SbdeVFS_SET(msdosfs_vfsops, msdos, 0); 1004