msdosfs_vfsops.c revision 49679
1139826Simp/* $Id: msdosfs_vfsops.c,v 1.46 1999/08/08 18:42:54 phk Exp $ */ 253541Sshin/* $NetBSD: msdosfs_vfsops.c,v 1.51 1997/11/17 15:36:58 ws Exp $ */ 353541Sshin 453541Sshin/*- 553541Sshin * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. 653541Sshin * Copyright (C) 1994, 1995, 1997 TooLs GmbH. 753541Sshin * All rights reserved. 853541Sshin * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 953541Sshin * 1053541Sshin * Redistribution and use in source and binary forms, with or without 1153541Sshin * modification, are permitted provided that the following conditions 1253541Sshin * are met: 1353541Sshin * 1. Redistributions of source code must retain the above copyright 1453541Sshin * notice, this list of conditions and the following disclaimer. 1553541Sshin * 2. Redistributions in binary form must reproduce the above copyright 1653541Sshin * notice, this list of conditions and the following disclaimer in the 1753541Sshin * documentation and/or other materials provided with the distribution. 1853541Sshin * 3. All advertising materials mentioning features or use of this software 1953541Sshin * must display the following acknowledgement: 2053541Sshin * This product includes software developed by TooLs GmbH. 2153541Sshin * 4. The name of TooLs GmbH may not be used to endorse or promote products 2253541Sshin * derived from this software without specific prior written permission. 2353541Sshin * 2453541Sshin * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 2553541Sshin * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2653541Sshin * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2753541Sshin * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2853541Sshin * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2953541Sshin * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 30139826Simp * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 3153541Sshin * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 32180305Srwatson * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 33180305Srwatson * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3453541Sshin */ 3553541Sshin/* 3653541Sshin * Written by Paul Popelka (paulp@uts.amdahl.com) 3753541Sshin * 3853541Sshin * You can do anything you want with this software, just don't say you wrote 3953541Sshin * it, and don't remove this notice. 4053541Sshin * 4153541Sshin * This software is provided "as is". 4253541Sshin * 4353541Sshin * The author supplies this software to be publicly redistributed on the 4453541Sshin * understanding that the author is not responsible for the correct 4553541Sshin * functioning of this software in any circumstances and is not liable for 4653541Sshin * any damages caused by this software. 4753541Sshin * 4853541Sshin * October 1992 4953541Sshin */ 5053541Sshin 5153541Sshin#include <sys/param.h> 5253541Sshin#include <sys/systm.h> 5353541Sshin#include <sys/conf.h> 5453541Sshin#include <sys/namei.h> 5553541Sshin#include <sys/proc.h> 5653541Sshin#include <sys/kernel.h> 5753541Sshin#include <sys/vnode.h> 5853541Sshin#include <sys/mount.h> 5953541Sshin#include <sys/buf.h> 6053541Sshin#include <sys/fcntl.h> 6153541Sshin#include <sys/malloc.h> 62174510Sobrien#include <sys/stat.h> /* defines ALLPERMS */ 63174510Sobrien 64174510Sobrien#include <msdosfs/bpb.h> 6555009Sshin#include <msdosfs/bootsect.h> 6678064Sume#include <msdosfs/direntry.h> 6755009Sshin#include <msdosfs/denode.h> 6853541Sshin#include <msdosfs/msdosfsmount.h> 6995759Stanimura#include <msdosfs/fat.h> 70185435Sbz 7195759StanimuraMALLOC_DEFINE(M_MSDOSFSMNT, "MSDOSFS mount", "MSDOSFS mount structure"); 7253541Sshinstatic MALLOC_DEFINE(M_MSDOSFSFAT, "MSDOSFS FAT", "MSDOSFS file allocation table"); 7395759Stanimura 74170689Srwatsonstatic int update_mp __P((struct mount *mp, struct msdosfs_args *argp)); 7553541Sshinstatic int mountmsdosfs __P((struct vnode *devvp, struct mount *mp, 7695759Stanimura struct proc *p, struct msdosfs_args *argp)); 7795759Stanimurastatic int msdosfs_fhtovp __P((struct mount *, struct fid *, 7853541Sshin struct sockaddr *, struct vnode **, int *, 7953541Sshin struct ucred **)); 8095759Stanimurastatic int msdosfs_mount __P((struct mount *, char *, caddr_t, 81148385Sume struct nameidata *, struct proc *)); 8253541Sshinstatic int msdosfs_quotactl __P((struct mount *, int, uid_t, caddr_t, 8353541Sshin struct proc *)); 8495759Stanimurastatic int msdosfs_root __P((struct mount *, struct vnode **)); 8553541Sshinstatic int msdosfs_start __P((struct mount *, int, struct proc *)); 86185571Sbzstatic int msdosfs_statfs __P((struct mount *, struct statfs *, 8753541Sshin struct proc *)); 8853541Sshinstatic int msdosfs_sync __P((struct mount *, int, struct ucred *, 8953541Sshin struct proc *)); 9053541Sshinstatic int msdosfs_unmount __P((struct mount *, int, struct proc *)); 91185571Sbzstatic int msdosfs_vget __P((struct mount *mp, ino_t ino, 92185571Sbz struct vnode **vpp)); 9395759Stanimurastatic int msdosfs_vptofh __P((struct vnode *, struct fid *)); 9462587Sitojun 95211501Sanchiestatic int 9695759Stanimuraupdate_mp(mp, argp) 9756723Sshin struct mount *mp; 9853541Sshin struct msdosfs_args *argp; 9995759Stanimura{ 10053541Sshin struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 10195759Stanimura int error; 10262587Sitojun 103211501Sanchie pmp->pm_gid = argp->gid; 10453541Sshin pmp->pm_uid = argp->uid; 105171167Sgnn pmp->pm_mask = argp->mask & ALLPERMS; 106105199Ssam pmp->pm_flags |= argp->flags & MSDOSFSMNT_MNTOPT; 107105199Ssam if (pmp->pm_flags & MSDOSFSMNT_U2WTABLE) { 108171167Sgnn bcopy(argp->u2w, pmp->pm_u2w, sizeof(pmp->pm_u2w)); 109105199Ssam bcopy(argp->d2u, pmp->pm_d2u, sizeof(pmp->pm_d2u)); 11053541Sshin bcopy(argp->u2d, pmp->pm_u2d, sizeof(pmp->pm_u2d)); 11153541Sshin } 11253541Sshin if (pmp->pm_flags & MSDOSFSMNT_ULTABLE) { 11353541Sshin bcopy(argp->ul, pmp->pm_ul, sizeof(pmp->pm_ul)); 11453541Sshin bcopy(argp->lu, pmp->pm_lu, sizeof(pmp->pm_lu)); 11553541Sshin } 11653541Sshin 11753541Sshin#ifndef __FreeBSD__ 11853541Sshin /* 119195699Srwatson * GEMDOS knows nothing (yet) about win95 120195699Srwatson */ 121195727Srwatson if (pmp->pm_flags & MSDOSFSMNT_GEMDOSFS) 122195727Srwatson pmp->pm_flags |= MSDOSFSMNT_NOWIN95; 123185348Szec#endif 12453541Sshin 12553541Sshin if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 12653541Sshin pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 127207369Sbz else if (!(pmp->pm_flags & 128207369Sbz (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) { 12953541Sshin struct vnode *rootvp; 130191672Sbms 131191672Sbms /* 132166938Sbms * Try to divine whether to support Win'95 long filenames 133191672Sbms */ 134191672Sbms if (FAT32(pmp)) 135191672Sbms pmp->pm_flags |= MSDOSFSMNT_LONGNAME; 136191672Sbms else { 137195699Srwatson if ((error = msdosfs_root(mp, &rootvp)) != 0) 138191672Sbms return error; 139191672Sbms pmp->pm_flags |= findwin95(VTODE(rootvp)) 140191672Sbms ? MSDOSFSMNT_LONGNAME 141191672Sbms : MSDOSFSMNT_SHORTNAME; 142166938Sbms vput(rootvp); 143166938Sbms } 144166938Sbms } 145166938Sbms return 0; 146194581Srdivacky} 147166938Sbms 148166938Sbms#ifndef __FreeBSD__ 149180305Srwatsonint 150180305Srwatsonmsdosfs_mountroot() 15153541Sshin{ 15253541Sshin register struct mount *mp; 153171259Sdelphij struct proc *p = curproc; /* XXX */ 15453541Sshin size_t size; 155191672Sbms int error; 15653541Sshin struct msdosfs_args args; 15753541Sshin 15853541Sshin if (root_device->dv_class != DV_DISK) 15953541Sshin return (ENODEV); 16078064Sume 161121901Sume /* 16253541Sshin * Get vnodes for swapdev and rootdev. 163181803Sbz */ 16478064Sume if (bdevvp(rootdev, &rootvp)) 16583934Sbrooks panic("msdosfs_mountroot: can't setup rootvp"); 166180305Srwatson 16778064Sume mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); 168180305Srwatson bzero((char *)mp, (u_long)sizeof(struct mount)); 16953541Sshin mp->mnt_op = &msdosfs_vfsops; 17078064Sume mp->mnt_flag = 0; 171121901Sume LIST_INIT(&mp->mnt_vnodelist); 17253541Sshin 173191672Sbms args.flags = 0; 174191672Sbms args.uid = 0; 175181803Sbz args.gid = 0; 176181803Sbz args.mask = 0777; 177185435Sbz 178186141Sbz if ((error = mountmsdosfs(rootvp, mp, p, &args)) != 0) { 17953541Sshin free(mp, M_MOUNT); 180186141Sbz return (error); 181186141Sbz } 182180850Smav 18353541Sshin if ((error = update_mp(mp, &args)) != 0) { 18453541Sshin (void)msdosfs_unmount(mp, 0, p); 185180850Smav free(mp, M_MOUNT); 18653541Sshin return (error); 18753541Sshin } 188180850Smav 189200473Sbz if ((error = vfs_lock(mp)) != 0) { 190191672Sbms (void)msdosfs_unmount(mp, 0, p); 191191672Sbms free(mp, M_MOUNT); 192191672Sbms return (error); 193191672Sbms } 194191672Sbms 195191672Sbms CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); 196191672Sbms mp->mnt_vnodecovered = NULLVP; 197191672Sbms (void) copystr("/", mp->mnt_stat.f_mntonname, MNAMELEN - 1, 198191672Sbms &size); 199191672Sbms bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 20078064Sume (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 201181803Sbz &size); 202151459Ssuz bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 20378064Sume (void)msdosfs_statfs(mp, &mp->mnt_stat, p); 204180932Smav vfs_unlock(mp); 205181803Sbz return (0); 206180850Smav} 20778064Sume#endif 20853541Sshin 209191672Sbms/* 210191672Sbms * mp - path - addr in user space of mount point (ie /usr or whatever) 211191672Sbms * data - addr in user space of mount params including the name of the block 212191672Sbms * special file to treat as a filesystem. 213191672Sbms */ 214191672Sbmsstatic int 215191672Sbmsmsdosfs_mount(mp, path, data, ndp, p) 216191672Sbms struct mount *mp; 217191672Sbms char *path; 218199518Sbms caddr_t data; 219199518Sbms struct nameidata *ndp; 220199518Sbms struct proc *p; 221199518Sbms{ 222199518Sbms struct vnode *devvp; /* vnode for blk device to mount */ 223199518Sbms struct msdosfs_args args; /* will hold data from mount request */ 224199518Sbms /* msdosfs specific mount control block */ 225199518Sbms struct msdosfsmount *pmp = NULL; 226199518Sbms size_t size; 227199518Sbms int error, flags; 228199518Sbms mode_t accessmode; 229199518Sbms 230199518Sbms error = copyin(data, (caddr_t)&args, sizeof(struct msdosfs_args)); 231199518Sbms if (error) 232199518Sbms return (error); 233199518Sbms if (args.magic != MSDOSFS_ARGSMAGIC) 234199518Sbms args.flags = 0; 235191672Sbms /* 236191672Sbms * If updating, check whether changing from read-only to 237199518Sbms * read/write; if there is no device name, that's all we do. 238199518Sbms */ 239199518Sbms if (mp->mnt_flag & MNT_UPDATE) { 240191672Sbms pmp = VFSTOMSDOSFS(mp); 241199518Sbms error = 0; 242199518Sbms if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_flag & MNT_RDONLY)) { 243199518Sbms flags = WRITECLOSE; 244199518Sbms if (mp->mnt_flag & MNT_FORCE) 245199518Sbms flags |= FORCECLOSE; 246199518Sbms error = vflush(mp, NULLVP, flags); 247199518Sbms } 248199518Sbms if (!error && (mp->mnt_flag & MNT_RELOAD)) 249199518Sbms /* not yet implemented */ 250199518Sbms error = EOPNOTSUPP; 251191672Sbms if (error) 252191672Sbms return (error); 253211301Sbz if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_kern_flag & MNTK_WANTRDWR)) { 254191672Sbms /* 255191672Sbms * If upgrade to read-write by non-root, then verify 256191672Sbms * that user has necessary permissions on the device. 257186163Skmacy */ 25853541Sshin if (p->p_ucred->cr_uid != 0) { 25978064Sume devvp = pmp->pm_devvp; 260171167Sgnn vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 26178064Sume error = VOP_ACCESS(devvp, VREAD | VWRITE, 26278064Sume p->p_ucred, p); 26378064Sume if (error) { 264125396Sume VOP_UNLOCK(devvp, 0, p); 26578064Sume return (error); 266181803Sbz } 267180305Srwatson VOP_UNLOCK(devvp, 0, p); 268105199Ssam } 269171167Sgnn pmp->pm_flags &= ~MSDOSFSMNT_RONLY; 27053541Sshin } 271186223Sbz if (args.fspec == 0) { 272186141Sbz#ifdef __notyet__ /* doesn't work correctly with current mountd XXX */ 273121674Sume if (args.flags & MSDOSFSMNT_MNTOPT) { 27453541Sshin pmp->pm_flags &= ~MSDOSFSMNT_MNTOPT; 27553541Sshin pmp->pm_flags |= args.flags & MSDOSFSMNT_MNTOPT; 276186141Sbz if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 277121901Sume pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 27853541Sshin } 27953541Sshin#endif 28053541Sshin /* 28153541Sshin * Process export requests. 282181803Sbz */ 28397658Stanimura return (vfs_export(mp, &pmp->pm_export, &args.export)); 284186141Sbz } 28553541Sshin } 28653541Sshin /* 287178377Srwatson * Not an update, or updating the name: look up the name 28853541Sshin * and verify that it refers to a sensible block device. 28953541Sshin */ 29053541Sshin NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 291181803Sbz error = namei(ndp); 292171167Sgnn if (error) 29378064Sume return (error); 29478064Sume devvp = ndp->ni_vp; 29578064Sume 296186170Skmacy if (devvp->v_type != VBLK) { 29778064Sume vrele(devvp); 298181803Sbz return (ENOTBLK); 299181803Sbz } 300180305Srwatson if (devsw(devvp->v_rdev) == NULL) { 301178377Srwatson vrele(devvp); 302105199Ssam return (ENXIO); 303171167Sgnn } 304186163Skmacy /* 305186223Sbz * If mount by non-root, then verify that user has necessary 306186141Sbz * permissions on the device. 307121674Sume */ 308180305Srwatson if (p->p_ucred->cr_uid != 0) { 30953541Sshin accessmode = VREAD; 310186141Sbz if ((mp->mnt_flag & MNT_RDONLY) == 0) 311180305Srwatson accessmode |= VWRITE; 31253541Sshin vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 31353541Sshin error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p); 31453541Sshin if (error) { 315181803Sbz vput(devvp); 31697658Stanimura return (error); 317186141Sbz } 318178377Srwatson VOP_UNLOCK(devvp, 0, p); 31953541Sshin } 320181803Sbz if ((mp->mnt_flag & MNT_UPDATE) == 0) { 32178064Sume error = mountmsdosfs(devvp, mp, p, &args); 322181803Sbz#ifdef MSDOSFS_DEBUG /* only needed for the printf below */ 32353541Sshin pmp = VFSTOMSDOSFS(mp); 32453541Sshin#endif 32553541Sshin } else { 32653541Sshin if (devvp != pmp->pm_devvp) 32753541Sshin error = EINVAL; /* XXX needs translation */ 328180305Srwatson else 329180305Srwatson vrele(devvp); 33053541Sshin } 331181803Sbz if (error) { 33253541Sshin vrele(devvp); 333180305Srwatson return (error); 33453541Sshin } 33553541Sshin 33662587Sitojun error = update_mp(mp, &args); 337171259Sdelphij if (error) { 33862587Sitojun msdosfs_unmount(mp, MNT_FORCE, p); 33962587Sitojun return error; 34062587Sitojun } 34162587Sitojun 34278064Sume (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); 34378064Sume bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 344125776Sume (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 345175162Sobrien &size); 34662587Sitojun bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 34762587Sitojun (void) msdosfs_statfs(mp, &mp->mnt_stat, p); 34862587Sitojun#ifdef MSDOSFS_DEBUG 34962587Sitojun printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); 35062587Sitojun#endif 35162587Sitojun return (0); 35262587Sitojun} 35362587Sitojun 35462587Sitojunstatic int 35562587Sitojunmountmsdosfs(devvp, mp, p, argp) 35662587Sitojun struct vnode *devvp; 35762587Sitojun struct mount *mp; 35862587Sitojun struct proc *p; 35962587Sitojun struct msdosfs_args *argp; 360180305Srwatson{ 361180305Srwatson struct msdosfsmount *pmp; 362180305Srwatson struct buf *bp; 36362587Sitojun dev_t dev = devvp->v_rdev; 36478064Sume#ifndef __FreeBSD__ 36562587Sitojun struct partinfo dpart; 36662587Sitojun int bsize = 0, dtype = 0, tmp; 36762587Sitojun#endif 368125776Sume union bootsector *bsp; 36978064Sume struct byte_bpb33 *b33; 37062587Sitojun struct byte_bpb50 *b50; 37162587Sitojun struct byte_bpb710 *b710; 37262587Sitojun u_int8_t SecPerClust; 373125776Sume int ronly, error; 37478064Sume 37562587Sitojun /* 37662587Sitojun * Disallow multiple mounts of the same device. 377181803Sbz * Disallow mounting of a device that is currently in use 378180305Srwatson * (except for root, which might share swap device for miniroot). 37962587Sitojun * Flush out any old buffers remaining from a previous use. 38062587Sitojun */ 38153541Sshin error = vfs_mountedon(devvp); 382180305Srwatson if (error) 383180305Srwatson return (error); 38453541Sshin if (vcount(devvp) > 1 && devvp != rootvp) 38553541Sshin return (EBUSY); 38653541Sshin vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 38753541Sshin error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0); 38853541Sshin VOP_UNLOCK(devvp, 0, p); 38953541Sshin if (error) 39053541Sshin return (error); 39153541Sshin 39253541Sshin ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 39353541Sshin error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p); 394120941Sume if (error) 395211501Sanchie return (error); 39653541Sshin 39753541Sshin bp = NULL; /* both used in error_exit */ 39853541Sshin pmp = NULL; 39953541Sshin 40053541Sshin#ifndef __FreeBSD__ 40153541Sshin if (argp->flags & MSDOSFSMNT_GEMDOSFS) { 40253541Sshin /* 403148247Sume * We need the disklabel to calculate the size of a FAT entry 40453541Sshin * later on. Also make sure the partition contains a filesystem 40553541Sshin * of type FS_MSDOS. This doesn't work for floppies, so we have 406148385Sume * to check for them too. 407211435Sume * 408194777Sbz * At least some parts of the msdos fs driver seem to assume 40953541Sshin * that the size of a disk block will always be 512 bytes. 41053541Sshin * Let's check it... 41153541Sshin */ 41253541Sshin error = VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, 41353541Sshin FREAD, NOCRED, p); 41453541Sshin if (error) 41553541Sshin goto error_exit; 41653541Sshin tmp = dpart.part->p_fstype; 417186141Sbz dtype = dpart.disklab->d_type; 418178285Srwatson bsize = dpart.disklab->d_secsize; 41953541Sshin if (bsize != 512 || (dtype!=DTYPE_FLOPPY && tmp!=FS_MSDOS)) { 42053541Sshin error = EINVAL; 421186170Skmacy goto error_exit; 422148242Sume } 423175630Sbz } 424175630Sbz#endif 42553541Sshin 426121472Sume /* 427148247Sume * Read the boot sector of the filesystem, and then check the 428148247Sume * boot signature. If not a dos boot sector then error out. 429148247Sume */ 43053541Sshin#ifdef PC98 43153541Sshin error = bread(devvp, 0, 1024, NOCRED, &bp); 432148385Sume#else 433180305Srwatson error = bread(devvp, 0, 512, NOCRED, &bp); 434148385Sume#endif 435148385Sume if (error) 436148385Sume goto error_exit; 437211530Sume bp->b_flags |= B_AGE; 438211530Sume bsp = (union bootsector *)bp->b_data; 439211435Sume b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB; 440211435Sume b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB; 441148385Sume b710 = (struct byte_bpb710 *)bsp->bs710.bsPBP; 442211435Sume 443148385Sume#ifndef __FreeBSD__ 444148385Sume if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) { 445148385Sume#endif 446148385Sume#ifdef PC98 447180305Srwatson if ((bsp->bs50.bsBootSectSig0 != BOOTSIG0 448180305Srwatson || bsp->bs50.bsBootSectSig1 != BOOTSIG1) 44953541Sshin && (bsp->bs50.bsBootSectSig0 != 0 /* PC98 DOS 3.3x */ 45053541Sshin || bsp->bs50.bsBootSectSig1 != 0) 45153541Sshin && (bsp->bs50.bsBootSectSig0 != 0x90 /* PC98 DOS 5.0 */ 45253541Sshin || bsp->bs50.bsBootSectSig1 != 0x3d) 45353541Sshin && (bsp->bs50.bsBootSectSig0 != 0x46 /* PC98 DOS 3.3B */ 45453541Sshin || bsp->bs50.bsBootSectSig1 != 0xfa)) { 45553541Sshin#else 45653541Sshin if (bsp->bs50.bsBootSectSig0 != BOOTSIG0 45753541Sshin || bsp->bs50.bsBootSectSig1 != BOOTSIG1) { 45853541Sshin#endif 45953541Sshin error = EINVAL; 46053541Sshin goto error_exit; 46153541Sshin } 462133592Srwatson#ifndef __FreeBSD__ 463133592Srwatson } 464133592Srwatson#endif 465133592Srwatson 466133592Srwatson pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK); 46753541Sshin bzero((caddr_t)pmp, sizeof *pmp); 46853541Sshin pmp->pm_mountp = mp; 46953541Sshin 47053541Sshin /* 47153541Sshin * Compute several useful quantities from the bpb in the 472194777Sbz * bootsector. Copy in the dos 5 variant of the bpb then fix up 473194777Sbz * the fields that are different between dos 5 and dos 3.3. 474194777Sbz */ 475121472Sume SecPerClust = b50->bpbSecPerClust; 476207277Sbz pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 477188144Sjamie pmp->pm_ResSectors = getushort(b50->bpbResSectors); 478188144Sjamie pmp->pm_FATs = b50->bpbFATs; 479194777Sbz pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 480148385Sume pmp->pm_Sectors = getushort(b50->bpbSectors); 481148385Sume pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 482148385Sume pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 483148385Sume pmp->pm_Heads = getushort(b50->bpbHeads); 484148385Sume pmp->pm_Media = b50->bpbMedia; 485148385Sume 486148385Sume#ifndef __FreeBSD__ 487148385Sume if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) { 488148385Sume#endif 489148385Sume /* XXX - We should probably check more values here */ 490148385Sume if (!pmp->pm_BytesPerSec || !SecPerClust 491148385Sume || !pmp->pm_Heads || pmp->pm_Heads > 255 492148385Sume#ifdef PC98 493148385Sume || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) { 494148385Sume#else 495148385Sume || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) { 496180305Srwatson#endif 497180305Srwatson error = EINVAL; 498180305Srwatson goto error_exit; 49955009Sshin } 500186141Sbz#ifndef __FreeBSD__ 50155009Sshin } 502180305Srwatson#endif 503180305Srwatson 504180305Srwatson if (pmp->pm_Sectors == 0) { 505180305Srwatson pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 506180305Srwatson pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 507186141Sbz } else { 50853541Sshin pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 50953541Sshin pmp->pm_HugeSectors = pmp->pm_Sectors; 51053541Sshin } 51153541Sshin if (pmp->pm_HugeSectors > 0xffffffff / 51253541Sshin (pmp->pm_BytesPerSec / sizeof(struct direntry)) + 1) { 51353541Sshin /* 51453541Sshin * We cannot deal currently with this size of disk 51553541Sshin * due to fileid limitations (see msdosfs_getattr and 516180305Srwatson * msdosfs_readdir) 51753541Sshin */ 51853541Sshin error = EINVAL; 51953541Sshin printf("mountmsdosfs(): disk too big, sorry\n"); 52053541Sshin goto error_exit; 52153541Sshin } 52253541Sshin 52353541Sshin if (pmp->pm_RootDirEnts == 0) { 52453541Sshin if (bsp->bs710.bsBootSectSig2 != BOOTSIG2 52553541Sshin || bsp->bs710.bsBootSectSig3 != BOOTSIG3 52653541Sshin || pmp->pm_Sectors 52753541Sshin || pmp->pm_FATsecs 52853541Sshin || getushort(b710->bpbFSVers)) { 52953541Sshin error = EINVAL; 53053541Sshin printf("mountmsdosfs(): bad FAT32 filesystem\n"); 53153541Sshin goto error_exit; 53253541Sshin } 53353541Sshin pmp->pm_fatmask = FAT32_MASK; 53453541Sshin pmp->pm_fatmult = 4; 53553541Sshin pmp->pm_fatdiv = 1; 53653541Sshin pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs); 53753541Sshin if (getushort(b710->bpbExtFlags) & FATMIRROR) 53853541Sshin pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM; 539211501Sanchie else 540211501Sanchie pmp->pm_flags |= MSDOSFS_FATMIRROR; 541211501Sanchie } else 542211501Sanchie pmp->pm_flags |= MSDOSFS_FATMIRROR; 543211501Sanchie 544211501Sanchie#ifndef __FreeBSD__ 545211501Sanchie if (argp->flags & MSDOSFSMNT_GEMDOSFS) { 546211501Sanchie if (FAT32(pmp)) { 547211501Sanchie /* 548211501Sanchie * GEMDOS doesn't know fat32. 549211501Sanchie */ 550211501Sanchie error = EINVAL; 551211501Sanchie goto error_exit; 552211501Sanchie } 553211501Sanchie 554211501Sanchie /* 555211501Sanchie * Check a few values (could do some more): 556148247Sume * - logical sector size: power of 2, >= block size 55753541Sshin * - sectors per cluster: power of 2, >= 1 55853541Sshin * - number of sectors: >= 1, <= size of partition 55953541Sshin */ 560190964Srwatson if ( (SecPerClust == 0) 56178064Sume || (SecPerClust & (SecPerClust - 1)) 562181803Sbz || (pmp->pm_BytesPerSec < bsize) 56353541Sshin || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) 56453541Sshin || (pmp->pm_HugeSectors == 0) 56553541Sshin || (pmp->pm_HugeSectors * (pmp->pm_BytesPerSec / bsize) 56653541Sshin > dpart.part->p_size) 56753541Sshin ) { 56853541Sshin error = EINVAL; 56953541Sshin goto error_exit; 57053541Sshin } 571186170Skmacy /* 572148247Sume * XXX - Many parts of the msdos fs driver seem to assume that 57353541Sshin * the number of bytes per logical sector (BytesPerSec) will 57478064Sume * always be the same as the number of bytes per disk block 575178285Srwatson * Let's pretend it is. 576120856Sume */ 57753541Sshin tmp = pmp->pm_BytesPerSec / bsize; 57853541Sshin pmp->pm_BytesPerSec = bsize; 57953541Sshin pmp->pm_HugeSectors *= tmp; 58053541Sshin pmp->pm_HiddenSects *= tmp; 58153541Sshin pmp->pm_ResSectors *= tmp; 58253541Sshin pmp->pm_Sectors *= tmp; 583171259Sdelphij pmp->pm_FATsecs *= tmp; 58453541Sshin SecPerClust *= tmp; 58553541Sshin } 58653541Sshin#endif 58753541Sshin pmp->pm_fatblk = pmp->pm_ResSectors; 58853541Sshin if (FAT32(pmp)) { 58953541Sshin pmp->pm_rootdirblk = getulong(b710->bpbRootClust); 59053541Sshin pmp->pm_firstcluster = pmp->pm_fatblk 59153541Sshin + (pmp->pm_FATs * pmp->pm_FATsecs); 592120856Sume pmp->pm_fsinfo = getushort(b710->bpbFSInfo); 59353541Sshin } else { 59453541Sshin pmp->pm_rootdirblk = pmp->pm_fatblk + 59553541Sshin (pmp->pm_FATs * pmp->pm_FATsecs); 59653541Sshin pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry) 59753541Sshin + pmp->pm_BytesPerSec - 1) 59853541Sshin / pmp->pm_BytesPerSec;/* in sectors */ 59953541Sshin pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 60053541Sshin } 60156723Sshin 60256723Sshin pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 60356723Sshin SecPerClust; 60456723Sshin pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1; 60556723Sshin pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec; 60656723Sshin 60756723Sshin#ifndef __FreeBSD__ 608166938Sbms if (argp->flags & MSDOSFSMNT_GEMDOSFS) { 609166938Sbms if ((pmp->pm_nmbrofclusters <= (0xff0 - 2)) 61056723Sshin && ((dtype == DTYPE_FLOPPY) || ((dtype == DTYPE_VNODE) 611121578Sume && ((pmp->pm_Heads == 1) || (pmp->pm_Heads == 2)))) 612121578Sume ) { 613121578Sume pmp->pm_fatmask = FAT12_MASK; 61453541Sshin pmp->pm_fatmult = 3; 61553541Sshin pmp->pm_fatdiv = 2; 61653541Sshin } else { 61753541Sshin pmp->pm_fatmask = FAT16_MASK; 61853541Sshin pmp->pm_fatmult = 2; 61953541Sshin pmp->pm_fatdiv = 1; 62053541Sshin } 62153541Sshin } else 62256723Sshin#endif 62356723Sshin if (pmp->pm_fatmask == 0) { 62456723Sshin if (pmp->pm_maxcluster 62556723Sshin <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) { 62656723Sshin /* 62756723Sshin * This will usually be a floppy disk. This size makes 62856723Sshin * sure that one fat entry will not be split across 629166938Sbms * multiple blocks. 630166938Sbms */ 63156723Sshin pmp->pm_fatmask = FAT12_MASK; 632121578Sume pmp->pm_fatmult = 3; 633121578Sume pmp->pm_fatdiv = 2; 634121578Sume } else { 63553541Sshin pmp->pm_fatmask = FAT16_MASK; 63653541Sshin pmp->pm_fatmult = 2; 63753541Sshin pmp->pm_fatdiv = 1; 63853541Sshin } 63953541Sshin } 64053541Sshin if (FAT12(pmp)) 64153541Sshin pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; 64253541Sshin else 64353541Sshin pmp->pm_fatblocksize = DFLTBSIZE; 64453541Sshin 64553541Sshin pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec; 64683366Sjulian pmp->pm_bnshift = ffs(pmp->pm_BytesPerSec) - 1; 64753541Sshin 64853541Sshin /* 649144261Ssam * Compute mask and shift value for isolating cluster relative byte 650157676Srwatson * offsets and cluster numbers from a file offset. 65153541Sshin */ 65253541Sshin pmp->pm_bpcluster = SecPerClust * pmp->pm_BytesPerSec; 653157374Srwatson pmp->pm_crbomask = pmp->pm_bpcluster - 1; 654180305Srwatson pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1; 655175630Sbz 656175630Sbz /* 657180305Srwatson * Check for valid cluster size 65855009Sshin * must be a power of 2 659157374Srwatson */ 660180305Srwatson if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) { 661184214Sdes error = EINVAL; 662157374Srwatson goto error_exit; 663180305Srwatson } 664181803Sbz 665181803Sbz /* 666132714Srwatson * Release the bootsector buffer. 667181803Sbz */ 668184205Sdes brelse(bp); 669180305Srwatson bp = NULL; 670132714Srwatson 67153541Sshin /* 672181803Sbz * Check FSInfo. 67353541Sshin */ 674186141Sbz if (pmp->pm_fsinfo) { 67553541Sshin struct fsinfo *fp; 67653541Sshin 677144261Ssam if ((error = bread(devvp, pmp->pm_fsinfo, 1024, NOCRED, &bp)) != 0) 67853541Sshin goto error_exit; 679178285Srwatson fp = (struct fsinfo *)bp->b_data; 680180305Srwatson if (!bcmp(fp->fsisig1, "RRaA", 4) 68153541Sshin && !bcmp(fp->fsisig2, "rrAa", 4) 68253541Sshin && !bcmp(fp->fsisig3, "\0\0\125\252", 4) 683157370Srwatson && !bcmp(fp->fsisig4, "\0\0\125\252", 4)) 68453541Sshin pmp->pm_nxtfree = getulong(fp->fsinxtfree); 68553541Sshin else 68653541Sshin pmp->pm_fsinfo = 0; 68753541Sshin brelse(bp); 68853541Sshin bp = NULL; 689157374Srwatson } 690160549Srwatson 691191672Sbms /* 692166938Sbms * Check and validate (or perhaps invalidate?) the fsinfo structure? XXX 69353541Sshin */ 694181803Sbz 695178285Srwatson /* 696184205Sdes * Allocate memory for the bitmap of allocated clusters, and then 697185344Sbz * fill it in. 698185370Sbz */ 699181803Sbz pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS - 1) 70053541Sshin / N_INUSEBITS) 70153541Sshin * sizeof(*pmp->pm_inusemap), 702160549Srwatson M_MSDOSFSFAT, M_WAITOK); 703157366Srwatson 70453541Sshin /* 70553541Sshin * fillinusemap() needs pm_devvp. 706160549Srwatson */ 707160549Srwatson pmp->pm_dev = dev; 708160549Srwatson pmp->pm_devvp = devvp; 709160549Srwatson 710160549Srwatson /* 71153541Sshin * Have the inuse map filled in. 71253541Sshin */ 71353541Sshin if ((error = fillinusemap(pmp)) != 0) 714160549Srwatson goto error_exit; 715160549Srwatson 716160549Srwatson /* 717160549Srwatson * If they want fat updates to be synchronous then let them suffer 718160549Srwatson * the performance degradation in exchange for the on disk copy of 719160549Srwatson * the fat being correct just about all the time. I suppose this 720160549Srwatson * would be a good thing to turn on if the kernel is still flakey. 721160549Srwatson */ 722160549Srwatson if (mp->mnt_flag & MNT_SYNCHRONOUS) 723160549Srwatson pmp->pm_flags |= MSDOSFSMNT_WAITONFAT; 724160549Srwatson 72553541Sshin /* 72653541Sshin * Finish up. 72753541Sshin */ 728180305Srwatson if (ronly) 72953541Sshin pmp->pm_flags |= MSDOSFSMNT_RONLY; 730180305Srwatson else 731180305Srwatson pmp->pm_fmod = 1; 732180305Srwatson mp->mnt_data = (qaddr_t) pmp; 73397658Stanimura mp->mnt_stat.f_fsid.val[0] = (long)dev; 734180305Srwatson mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 73553541Sshin mp->mnt_flag |= MNT_LOCAL; 736157366Srwatson devvp->v_specmountpoint = mp; 737157374Srwatson 73853541Sshin return 0; 73953541Sshin 74053541Sshinerror_exit: 74183366Sjulian if (bp) 74253541Sshin brelse(bp); 743180305Srwatson (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE, NOCRED, p); 74453541Sshin if (pmp) { 745194760Srwatson if (pmp->pm_inusemap) 746148385Sume free(pmp->pm_inusemap, M_MSDOSFSFAT); 74753541Sshin free(pmp, M_MSDOSFSMNT); 748180305Srwatson mp->mnt_data = (qaddr_t)0; 749157374Srwatson } 750180305Srwatson return (error); 75153541Sshin} 752180305Srwatson 753188144Sjamiestatic int 754188144Sjamiemsdosfs_start(mp, flags, p) 755181803Sbz struct mount *mp; 756180305Srwatson int flags; 757181803Sbz struct proc *p; 758180305Srwatson{ 759148385Sume 76053541Sshin return (0); 761194760Srwatson} 762180305Srwatson 763194760Srwatson/* 764194760Srwatson * Unmount the filesystem described by mp. 76553541Sshin */ 76653541Sshinstatic int 767194760Srwatsonmsdosfs_unmount(mp, mntflags, p) 768120856Sume struct mount *mp; 76953541Sshin int mntflags; 770194760Srwatson struct proc *p; 771194760Srwatson{ 772181803Sbz struct msdosfsmount *pmp; 773178285Srwatson int error, flags; 77453541Sshin 775178285Srwatson flags = 0; 776181803Sbz if (mntflags & MNT_FORCE) 777180305Srwatson flags |= FORCECLOSE; 77853541Sshin error = vflush(mp, NULLVP, flags); 77953541Sshin if (error) 78053541Sshin return error; 78183366Sjulian pmp = VFSTOMSDOSFS(mp); 78253541Sshin pmp->pm_devvp->v_specmountpoint = NULL; 783180305Srwatson#ifdef MSDOSFS_DEBUG 78453541Sshin { 785194777Sbz struct vnode *vp = pmp->pm_devvp; 786148385Sume 787148385Sume printf("msdosfs_umount(): just before calling VOP_CLOSE()\n"); 78853541Sshin printf("flag %08lx, usecount %d, writecount %d, holdcnt %ld\n", 789180305Srwatson vp->v_flag, vp->v_usecount, vp->v_writecount, vp->v_holdcnt); 790157374Srwatson printf("lastr %d, id %lu, mount %p, op %p\n", 791180305Srwatson vp->v_lastr, vp->v_id, vp->v_mount, vp->v_op); 79253541Sshin printf("freef %p, freeb %p, mount %p\n", 793180305Srwatson vp->v_freelist.tqe_next, vp->v_freelist.tqe_prev, 794181803Sbz vp->v_mount); 795180305Srwatson printf("cleanblkhd %p, dirtyblkhd %p, numoutput %ld, type %d\n", 79653541Sshin TAILQ_FIRST(&vp->v_cleanblkhd), 797180305Srwatson TAILQ_FIRST(&vp->v_dirtyblkhd), 798148385Sume vp->v_numoutput, vp->v_type); 799148385Sume printf("union %p, tag %d, data[0] %08x, data[1] %08x\n", 800180305Srwatson vp->v_socket, vp->v_tag, 801180305Srwatson ((u_int *)vp->v_data)[0], 802180305Srwatson ((u_int *)vp->v_data)[1]); 803180305Srwatson } 804180305Srwatson#endif 805180305Srwatson error = VOP_CLOSE(pmp->pm_devvp, 806148385Sume (pmp->pm_flags&MSDOSFSMNT_RONLY) ? FREAD : FREAD | FWRITE, 807181803Sbz NOCRED, p); 808148385Sume vrele(pmp->pm_devvp); 809181803Sbz free(pmp->pm_inusemap, M_MSDOSFSFAT); 810180305Srwatson free(pmp, M_MSDOSFSMNT); 811148385Sume mp->mnt_data = (qaddr_t)0; 812181803Sbz mp->mnt_flag &= ~MNT_LOCAL; 813178285Srwatson return (error); 81453541Sshin} 815194777Sbz 816194777Sbzstatic int 817194777Sbzmsdosfs_root(mp, vpp) 818178285Srwatson struct mount *mp; 819181803Sbz struct vnode **vpp; 820194777Sbz{ 821132714Srwatson struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 822148385Sume struct denode *ndep; 823148385Sume int error; 824148385Sume 825148385Sume#ifdef MSDOSFS_DEBUG 826178285Srwatson printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp); 827181803Sbz#endif 828180305Srwatson error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep); 829148385Sume if (error) 830148385Sume return (error); 831194777Sbz *vpp = DETOV(ndep); 83253541Sshin return (0); 833178285Srwatson} 834181803Sbz 835180305Srwatsonstatic int 83653541Sshinmsdosfs_quotactl(mp, cmds, uid, arg, p) 83753541Sshin struct mount *mp; 83853541Sshin int cmds; 83953541Sshin uid_t uid; 84053541Sshin caddr_t arg; 841132714Srwatson struct proc *p; 842132714Srwatson{ 843132714Srwatson return EOPNOTSUPP; 844157374Srwatson} 845180305Srwatson 846178285Srwatsonstatic int 84753541Sshinmsdosfs_statfs(mp, sbp, p) 848178285Srwatson struct mount *mp; 849180305Srwatson struct statfs *sbp; 85053541Sshin struct proc *p; 85153541Sshin{ 85253541Sshin struct msdosfsmount *pmp; 85353541Sshin 854171260Sdelphij pmp = VFSTOMSDOSFS(mp); 85553541Sshin sbp->f_bsize = pmp->pm_bpcluster; 856180305Srwatson sbp->f_iosize = pmp->pm_bpcluster; 85753541Sshin sbp->f_blocks = pmp->pm_nmbrofclusters; 85853541Sshin sbp->f_bfree = pmp->pm_freeclustercount; 859132714Srwatson sbp->f_bavail = pmp->pm_freeclustercount; 86053541Sshin sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ 861180305Srwatson sbp->f_ffree = 0; /* what to put in here? */ 862157374Srwatson if (sbp != &mp->mnt_stat) { 863180305Srwatson sbp->f_type = mp->mnt_vfc->vfc_typenum; 864180305Srwatson bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 865132714Srwatson bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 86653541Sshin } 86753541Sshin strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN); 86853541Sshin return (0); 869180305Srwatson} 87053541Sshin 87153541Sshinstatic int 87253541Sshinmsdosfs_sync(mp, waitfor, cred, p) 87353541Sshin struct mount *mp; 87453541Sshin int waitfor; 875180990Srwatson struct ucred *cred; 87653541Sshin struct proc *p; 877180990Srwatson{ 878180990Srwatson struct vnode *vp, *nvp; 87953541Sshin struct denode *dep; 88053541Sshin struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 88153541Sshin int error, allerror = 0; 88253541Sshin 883180305Srwatson /* 88453541Sshin * If we ever switch to not updating all of the fats all the time, 885148385Sume * this would be the place to update them from the first one. 886148385Sume */ 887180305Srwatson if (pmp->pm_fmod != 0) { 888148385Sume if (pmp->pm_flags & MSDOSFSMNT_RONLY) 88962587Sitojun panic("msdosfs_sync: rofs mod"); 89062587Sitojun else { 891148385Sume /* update fats here */ 892148385Sume } 893148385Sume } 894148385Sume /* 895148385Sume * Write back each (modified) denode. 896148385Sume */ 897148385Sume simple_lock(&mntvnode_slock); 898148385Sumeloop: 899148385Sume for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { 900148385Sume /* 901148385Sume * If the vnode that we are about to sync is no longer 902148385Sume * associated with this mount point, start over. 903148385Sume */ 904148385Sume if (vp->v_mount != mp) 90553541Sshin goto loop; 906132714Srwatson 907132714Srwatson simple_lock(&vp->v_interlock); 90853541Sshin nvp = vp->v_mntvnodes.le_next; 90953541Sshin dep = VTODE(vp); 91053541Sshin if (vp->v_type == VNON || 911137386Sphk ((dep->de_flag & 912137386Sphk (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0 && 913137386Sphk (TAILQ_EMPTY(&vp->v_dirtyblkhd) || waitfor == MNT_LAZY))) { 914137386Sphk simple_unlock(&vp->v_interlock); 915137386Sphk continue; 916137386Sphk } 917137386Sphk simple_unlock(&mntvnode_slock); 918169462Srwatson error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); 919137386Sphk if (error) { 920137386Sphk simple_lock(&mntvnode_slock); 921169462Srwatson if (error == ENOENT) 922160549Srwatson goto loop; 92353541Sshin continue; 924 } 925 error = VOP_FSYNC(vp, cred, waitfor, p); 926 if (error) 927 allerror = error; 928 VOP_UNLOCK(vp, 0, p); 929 vrele(vp); 930 simple_lock(&mntvnode_slock); 931 } 932 simple_unlock(&mntvnode_slock); 933 934 /* 935 * Flush filesystem control info. 936 */ 937 if (waitfor != MNT_LAZY) { 938 vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY, p); 939 error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p); 940 if (error) 941 allerror = error; 942 VOP_UNLOCK(pmp->pm_devvp, 0, p); 943 } 944 return (allerror); 945} 946 947static int 948msdosfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 949 struct mount *mp; 950 struct fid *fhp; 951 struct sockaddr *nam; 952 struct vnode **vpp; 953 int *exflagsp; 954 struct ucred **credanonp; 955{ 956 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 957 struct defid *defhp = (struct defid *) fhp; 958 struct denode *dep; 959 struct netcred *np; 960 int error; 961 962 np = vfs_export_lookup(mp, &pmp->pm_export, nam); 963 if (np == NULL) 964 return (EACCES); 965 error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep); 966 if (error) { 967 *vpp = NULLVP; 968 return (error); 969 } 970 *vpp = DETOV(dep); 971 *exflagsp = np->netc_exflags; 972 *credanonp = &np->netc_anon; 973 return (0); 974} 975 976static int 977msdosfs_vptofh(vp, fhp) 978 struct vnode *vp; 979 struct fid *fhp; 980{ 981 struct denode *dep; 982 struct defid *defhp; 983 984 dep = VTODE(vp); 985 defhp = (struct defid *)fhp; 986 defhp->defid_len = sizeof(struct defid); 987 defhp->defid_dirclust = dep->de_dirclust; 988 defhp->defid_dirofs = dep->de_diroffset; 989 /* defhp->defid_gen = dep->de_gen; */ 990 return (0); 991} 992 993static int 994msdosfs_vget(mp, ino, vpp) 995 struct mount *mp; 996 ino_t ino; 997 struct vnode **vpp; 998{ 999 return EOPNOTSUPP; 1000} 1001 1002static struct vfsops msdosfs_vfsops = { 1003 msdosfs_mount, 1004 msdosfs_start, 1005 msdosfs_unmount, 1006 msdosfs_root, 1007 msdosfs_quotactl, 1008 msdosfs_statfs, 1009 msdosfs_sync, 1010 msdosfs_vget, 1011 msdosfs_fhtovp, 1012 msdosfs_vptofh, 1013 msdosfs_init 1014}; 1015 1016VFS_SET(msdosfs_vfsops, msdos, 0); 1017