18994ca3cSBruce Evans /* $Id: msdosfs_vfsops.c,v 1.35 1998/05/06 05:29:38 msmith Exp $ */ 2952a6212SJordan K. Hubbard /* $NetBSD: msdosfs_vfsops.c,v 1.51 1997/11/17 15:36:58 ws Exp $ */ 327a0bc89SDoug Rabson 427a0bc89SDoug Rabson /*- 5952a6212SJordan K. Hubbard * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. 6952a6212SJordan K. Hubbard * Copyright (C) 1994, 1995, 1997 TooLs GmbH. 727a0bc89SDoug Rabson * All rights reserved. 827a0bc89SDoug Rabson * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 927a0bc89SDoug Rabson * 1027a0bc89SDoug Rabson * Redistribution and use in source and binary forms, with or without 1127a0bc89SDoug Rabson * modification, are permitted provided that the following conditions 1227a0bc89SDoug Rabson * are met: 1327a0bc89SDoug Rabson * 1. Redistributions of source code must retain the above copyright 1427a0bc89SDoug Rabson * notice, this list of conditions and the following disclaimer. 1527a0bc89SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 1627a0bc89SDoug Rabson * notice, this list of conditions and the following disclaimer in the 1727a0bc89SDoug Rabson * documentation and/or other materials provided with the distribution. 1827a0bc89SDoug Rabson * 3. All advertising materials mentioning features or use of this software 1927a0bc89SDoug Rabson * must display the following acknowledgement: 2027a0bc89SDoug Rabson * This product includes software developed by TooLs GmbH. 2127a0bc89SDoug Rabson * 4. The name of TooLs GmbH may not be used to endorse or promote products 2227a0bc89SDoug Rabson * derived from this software without specific prior written permission. 2327a0bc89SDoug Rabson * 2427a0bc89SDoug Rabson * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 2527a0bc89SDoug Rabson * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2627a0bc89SDoug Rabson * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2727a0bc89SDoug Rabson * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2827a0bc89SDoug Rabson * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2927a0bc89SDoug Rabson * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 3027a0bc89SDoug Rabson * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 3127a0bc89SDoug Rabson * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 3227a0bc89SDoug Rabson * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 3327a0bc89SDoug Rabson * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3427a0bc89SDoug Rabson */ 3527a0bc89SDoug Rabson /* 3627a0bc89SDoug Rabson * Written by Paul Popelka (paulp@uts.amdahl.com) 3727a0bc89SDoug Rabson * 3827a0bc89SDoug Rabson * You can do anything you want with this software, just don't say you wrote 3927a0bc89SDoug Rabson * it, and don't remove this notice. 4027a0bc89SDoug Rabson * 4127a0bc89SDoug Rabson * This software is provided "as is". 4227a0bc89SDoug Rabson * 4327a0bc89SDoug Rabson * The author supplies this software to be publicly redistributed on the 4427a0bc89SDoug Rabson * understanding that the author is not responsible for the correct 4527a0bc89SDoug Rabson * functioning of this software in any circumstances and is not liable for 4627a0bc89SDoug Rabson * any damages caused by this software. 4727a0bc89SDoug Rabson * 4827a0bc89SDoug Rabson * October 1992 4927a0bc89SDoug Rabson */ 5027a0bc89SDoug Rabson 5127a0bc89SDoug Rabson #include <sys/param.h> 5227a0bc89SDoug Rabson #include <sys/systm.h> 5327a0bc89SDoug Rabson #include <sys/namei.h> 5427a0bc89SDoug Rabson #include <sys/proc.h> 5527a0bc89SDoug Rabson #include <sys/kernel.h> 5627a0bc89SDoug Rabson #include <sys/vnode.h> 5727a0bc89SDoug Rabson #include <miscfs/specfs/specdev.h> /* XXX */ /* defines v_rdev */ 5827a0bc89SDoug Rabson #include <sys/mount.h> 5927a0bc89SDoug Rabson #include <sys/buf.h> 603ac4d1efSBruce Evans #include <sys/fcntl.h> 6127a0bc89SDoug Rabson #include <sys/malloc.h> 62952a6212SJordan K. Hubbard #include <sys/stat.h> /* defines ALLPERMS */ 6327a0bc89SDoug Rabson 6427a0bc89SDoug Rabson #include <msdosfs/bpb.h> 6527a0bc89SDoug Rabson #include <msdosfs/bootsect.h> 6627a0bc89SDoug Rabson #include <msdosfs/direntry.h> 6727a0bc89SDoug Rabson #include <msdosfs/denode.h> 6827a0bc89SDoug Rabson #include <msdosfs/msdosfsmount.h> 6927a0bc89SDoug Rabson #include <msdosfs/fat.h> 7027a0bc89SDoug Rabson 71a1c995b6SPoul-Henning Kamp MALLOC_DEFINE(M_MSDOSFSMNT, "MSDOSFS mount", "MSDOSFS mount structure"); 72a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_MSDOSFSFAT, "MSDOSFS FAT", "MSDOSFS file allocation table"); 7355166637SPoul-Henning Kamp 74952a6212SJordan K. Hubbard static int update_mp __P((struct mount *mp, struct msdosfs_args *argp)); 75af482601SBruce Evans static int mountmsdosfs __P((struct vnode *devvp, struct mount *mp, 76952a6212SJordan K. Hubbard struct proc *p, struct msdosfs_args *argp)); 77af482601SBruce Evans static int msdosfs_fhtovp __P((struct mount *, struct fid *, 7857bf258eSGarrett Wollman struct sockaddr *, struct vnode **, int *, 79af482601SBruce Evans struct ucred **)); 80af482601SBruce Evans static int msdosfs_mount __P((struct mount *, char *, caddr_t, 81af482601SBruce Evans struct nameidata *, struct proc *)); 82af482601SBruce Evans static int msdosfs_quotactl __P((struct mount *, int, uid_t, caddr_t, 83af482601SBruce Evans struct proc *)); 84af482601SBruce Evans static int msdosfs_root __P((struct mount *, struct vnode **)); 85af482601SBruce Evans static int msdosfs_start __P((struct mount *, int, struct proc *)); 86af482601SBruce Evans static int msdosfs_statfs __P((struct mount *, struct statfs *, 87af482601SBruce Evans struct proc *)); 88af482601SBruce Evans static int msdosfs_sync __P((struct mount *, int, struct ucred *, 89af482601SBruce Evans struct proc *)); 90af482601SBruce Evans static int msdosfs_unmount __P((struct mount *, int, struct proc *)); 91af482601SBruce Evans static int msdosfs_vget __P((struct mount *mp, ino_t ino, 92af482601SBruce Evans struct vnode **vpp)); 93af482601SBruce Evans static int msdosfs_vptofh __P((struct vnode *, struct fid *)); 94af482601SBruce Evans 95952a6212SJordan K. Hubbard static int 96952a6212SJordan K. Hubbard update_mp(mp, argp) 97952a6212SJordan K. Hubbard struct mount *mp; 98952a6212SJordan K. Hubbard struct msdosfs_args *argp; 99952a6212SJordan K. Hubbard { 100952a6212SJordan K. Hubbard struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 101952a6212SJordan K. Hubbard int error; 102952a6212SJordan K. Hubbard 103952a6212SJordan K. Hubbard pmp->pm_gid = argp->gid; 104952a6212SJordan K. Hubbard pmp->pm_uid = argp->uid; 105952a6212SJordan K. Hubbard pmp->pm_mask = argp->mask & ALLPERMS; 106952a6212SJordan K. Hubbard pmp->pm_flags |= argp->flags & MSDOSFSMNT_MNTOPT; 1077391f611SAndrey A. Chernov if (pmp->pm_flags & MSDOSFSMNT_U2WTABLE) { 10813df76f2SAndrey A. Chernov bcopy(argp->u2w, pmp->pm_u2w, sizeof(pmp->pm_u2w)); 1097391f611SAndrey A. Chernov bcopy(argp->d2u, pmp->pm_d2u, sizeof(pmp->pm_d2u)); 1107391f611SAndrey A. Chernov bcopy(argp->u2d, pmp->pm_u2d, sizeof(pmp->pm_u2d)); 1117391f611SAndrey A. Chernov } 1127391f611SAndrey A. Chernov if (pmp->pm_flags & MSDOSFSMNT_ULTABLE) { 11364fb806cSAndrey A. Chernov bcopy(argp->ul, pmp->pm_ul, sizeof(pmp->pm_ul)); 1147391f611SAndrey A. Chernov bcopy(argp->lu, pmp->pm_lu, sizeof(pmp->pm_lu)); 1157391f611SAndrey A. Chernov } 116952a6212SJordan K. Hubbard 117952a6212SJordan K. Hubbard #ifndef __FreeBSD__ 118952a6212SJordan K. Hubbard /* 119952a6212SJordan K. Hubbard * GEMDOS knows nothing (yet) about win95 120952a6212SJordan K. Hubbard */ 121952a6212SJordan K. Hubbard if (pmp->pm_flags & MSDOSFSMNT_GEMDOSFS) 122952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_NOWIN95; 123952a6212SJordan K. Hubbard #endif 124952a6212SJordan K. Hubbard 125952a6212SJordan K. Hubbard if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 126952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 127952a6212SJordan K. Hubbard else if (!(pmp->pm_flags & 128952a6212SJordan K. Hubbard (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) { 129952a6212SJordan K. Hubbard struct vnode *rootvp; 130952a6212SJordan K. Hubbard 131952a6212SJordan K. Hubbard /* 132952a6212SJordan K. Hubbard * Try to divine whether to support Win'95 long filenames 133952a6212SJordan K. Hubbard */ 134952a6212SJordan K. Hubbard if (FAT32(pmp)) 135952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_LONGNAME; 136952a6212SJordan K. Hubbard else { 137952a6212SJordan K. Hubbard if ((error = msdosfs_root(mp, &rootvp)) != 0) 138952a6212SJordan K. Hubbard return error; 139952a6212SJordan K. Hubbard pmp->pm_flags |= findwin95(VTODE(rootvp)) 140952a6212SJordan K. Hubbard ? MSDOSFSMNT_LONGNAME 141952a6212SJordan K. Hubbard : MSDOSFSMNT_SHORTNAME; 142952a6212SJordan K. Hubbard vput(rootvp); 143952a6212SJordan K. Hubbard } 144952a6212SJordan K. Hubbard } 145952a6212SJordan K. Hubbard return 0; 146952a6212SJordan K. Hubbard } 147952a6212SJordan K. Hubbard 148952a6212SJordan K. Hubbard #ifndef __FreeBSD__ 149952a6212SJordan K. Hubbard int 150952a6212SJordan K. Hubbard msdosfs_mountroot() 151952a6212SJordan K. Hubbard { 152952a6212SJordan K. Hubbard register struct mount *mp; 153952a6212SJordan K. Hubbard struct proc *p = curproc; /* XXX */ 154952a6212SJordan K. Hubbard size_t size; 155952a6212SJordan K. Hubbard int error; 156952a6212SJordan K. Hubbard struct msdosfs_args args; 157952a6212SJordan K. Hubbard 158952a6212SJordan K. Hubbard if (root_device->dv_class != DV_DISK) 159952a6212SJordan K. Hubbard return (ENODEV); 160952a6212SJordan K. Hubbard 161952a6212SJordan K. Hubbard /* 162952a6212SJordan K. Hubbard * Get vnodes for swapdev and rootdev. 163952a6212SJordan K. Hubbard */ 164952a6212SJordan K. Hubbard if (bdevvp(rootdev, &rootvp)) 165952a6212SJordan K. Hubbard panic("msdosfs_mountroot: can't setup rootvp"); 166952a6212SJordan K. Hubbard 167952a6212SJordan K. Hubbard mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); 168952a6212SJordan K. Hubbard bzero((char *)mp, (u_long)sizeof(struct mount)); 169952a6212SJordan K. Hubbard mp->mnt_op = &msdosfs_vfsops; 170952a6212SJordan K. Hubbard mp->mnt_flag = 0; 171952a6212SJordan K. Hubbard LIST_INIT(&mp->mnt_vnodelist); 172952a6212SJordan K. Hubbard 173952a6212SJordan K. Hubbard args.flags = 0; 174952a6212SJordan K. Hubbard args.uid = 0; 175952a6212SJordan K. Hubbard args.gid = 0; 176952a6212SJordan K. Hubbard args.mask = 0777; 177952a6212SJordan K. Hubbard 178952a6212SJordan K. Hubbard if ((error = mountmsdosfs(rootvp, mp, p, &args)) != 0) { 179952a6212SJordan K. Hubbard free(mp, M_MOUNT); 180952a6212SJordan K. Hubbard return (error); 181952a6212SJordan K. Hubbard } 182952a6212SJordan K. Hubbard 183952a6212SJordan K. Hubbard if ((error = update_mp(mp, &args)) != 0) { 184952a6212SJordan K. Hubbard (void)msdosfs_unmount(mp, 0, p); 185952a6212SJordan K. Hubbard free(mp, M_MOUNT); 186952a6212SJordan K. Hubbard return (error); 187952a6212SJordan K. Hubbard } 188952a6212SJordan K. Hubbard 189952a6212SJordan K. Hubbard if ((error = vfs_lock(mp)) != 0) { 190952a6212SJordan K. Hubbard (void)msdosfs_unmount(mp, 0, p); 191952a6212SJordan K. Hubbard free(mp, M_MOUNT); 192952a6212SJordan K. Hubbard return (error); 193952a6212SJordan K. Hubbard } 194952a6212SJordan K. Hubbard 195952a6212SJordan K. Hubbard CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); 196952a6212SJordan K. Hubbard mp->mnt_vnodecovered = NULLVP; 197952a6212SJordan K. Hubbard (void) copystr("/", mp->mnt_stat.f_mntonname, MNAMELEN - 1, 198952a6212SJordan K. Hubbard &size); 199952a6212SJordan K. Hubbard bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 200952a6212SJordan K. Hubbard (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 201952a6212SJordan K. Hubbard &size); 202952a6212SJordan K. Hubbard bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 203952a6212SJordan K. Hubbard (void)msdosfs_statfs(mp, &mp->mnt_stat, p); 204952a6212SJordan K. Hubbard vfs_unlock(mp); 205952a6212SJordan K. Hubbard return (0); 206952a6212SJordan K. Hubbard } 207952a6212SJordan K. Hubbard #endif 208952a6212SJordan K. Hubbard 20927a0bc89SDoug Rabson /* 21027a0bc89SDoug Rabson * mp - path - addr in user space of mount point (ie /usr or whatever) 21127a0bc89SDoug Rabson * data - addr in user space of mount params including the name of the block 21227a0bc89SDoug Rabson * special file to treat as a filesystem. 21327a0bc89SDoug Rabson */ 2147fefffeeSPoul-Henning Kamp static int 21527a0bc89SDoug Rabson msdosfs_mount(mp, path, data, ndp, p) 21627a0bc89SDoug Rabson struct mount *mp; 21727a0bc89SDoug Rabson char *path; 21827a0bc89SDoug Rabson caddr_t data; 21927a0bc89SDoug Rabson struct nameidata *ndp; 22027a0bc89SDoug Rabson struct proc *p; 22127a0bc89SDoug Rabson { 22227a0bc89SDoug Rabson struct vnode *devvp; /* vnode for blk device to mount */ 22327a0bc89SDoug Rabson struct msdosfs_args args; /* will hold data from mount request */ 224952a6212SJordan K. Hubbard /* msdosfs specific mount control block */ 225952a6212SJordan K. Hubbard struct msdosfsmount *pmp = NULL; 226952a6212SJordan K. Hubbard size_t size; 22727a0bc89SDoug Rabson int error, flags; 228952a6212SJordan K. Hubbard mode_t accessmode; 22927a0bc89SDoug Rabson 230c3c6d51eSPoul-Henning Kamp error = copyin(data, (caddr_t)&args, sizeof(struct msdosfs_args)); 231c3c6d51eSPoul-Henning Kamp if (error) 232952a6212SJordan K. Hubbard return (error); 233206faeeeSDmitrij Tejblum if (args.magic != MSDOSFS_ARGSMAGIC) 234952a6212SJordan K. Hubbard args.flags = 0; 23527a0bc89SDoug Rabson /* 236952a6212SJordan K. Hubbard * If updating, check whether changing from read-only to 237952a6212SJordan K. Hubbard * read/write; if there is no device name, that's all we do. 23827a0bc89SDoug Rabson */ 23927a0bc89SDoug Rabson if (mp->mnt_flag & MNT_UPDATE) { 240952a6212SJordan K. Hubbard pmp = VFSTOMSDOSFS(mp); 24127a0bc89SDoug Rabson error = 0; 242952a6212SJordan K. Hubbard if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_flag & MNT_RDONLY)) { 24327a0bc89SDoug Rabson flags = WRITECLOSE; 24427a0bc89SDoug Rabson if (mp->mnt_flag & MNT_FORCE) 24527a0bc89SDoug Rabson flags |= FORCECLOSE; 24627a0bc89SDoug Rabson error = vflush(mp, NULLVP, flags); 24727a0bc89SDoug Rabson } 24827a0bc89SDoug Rabson if (!error && (mp->mnt_flag & MNT_RELOAD)) 24927a0bc89SDoug Rabson /* not yet implemented */ 250952a6212SJordan K. Hubbard error = EOPNOTSUPP; 25127a0bc89SDoug Rabson if (error) 252952a6212SJordan K. Hubbard return (error); 253952a6212SJordan K. Hubbard if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_kern_flag & MNTK_WANTRDWR)) { 254952a6212SJordan K. Hubbard /* 255952a6212SJordan K. Hubbard * If upgrade to read-write by non-root, then verify 256952a6212SJordan K. Hubbard * that user has necessary permissions on the device. 257952a6212SJordan K. Hubbard */ 258952a6212SJordan K. Hubbard if (p->p_ucred->cr_uid != 0) { 259952a6212SJordan K. Hubbard devvp = pmp->pm_devvp; 260206faeeeSDmitrij Tejblum vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 261952a6212SJordan K. Hubbard error = VOP_ACCESS(devvp, VREAD | VWRITE, 262952a6212SJordan K. Hubbard p->p_ucred, p); 263952a6212SJordan K. Hubbard if (error) { 264952a6212SJordan K. Hubbard VOP_UNLOCK(devvp, 0, p); 265952a6212SJordan K. Hubbard return (error); 266952a6212SJordan K. Hubbard } 267952a6212SJordan K. Hubbard VOP_UNLOCK(devvp, 0, p); 268952a6212SJordan K. Hubbard } 269952a6212SJordan K. Hubbard pmp->pm_flags &= ~MSDOSFSMNT_RONLY; 270952a6212SJordan K. Hubbard } 27127a0bc89SDoug Rabson if (args.fspec == 0) { 272952a6212SJordan K. Hubbard #ifdef __notyet__ /* doesn't work correctly with current mountd XXX */ 273952a6212SJordan K. Hubbard if (args.flags & MSDOSFSMNT_MNTOPT) { 274952a6212SJordan K. Hubbard pmp->pm_flags &= ~MSDOSFSMNT_MNTOPT; 275952a6212SJordan K. Hubbard pmp->pm_flags |= args.flags & MSDOSFSMNT_MNTOPT; 276952a6212SJordan K. Hubbard if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 277952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 278952a6212SJordan K. Hubbard } 279952a6212SJordan K. Hubbard #endif 28027a0bc89SDoug Rabson /* 28127a0bc89SDoug Rabson * Process export requests. 28227a0bc89SDoug Rabson */ 283952a6212SJordan K. Hubbard return (vfs_export(mp, &pmp->pm_export, &args.export)); 28427a0bc89SDoug Rabson } 285952a6212SJordan K. Hubbard } 28627a0bc89SDoug Rabson /* 287952a6212SJordan K. Hubbard * Not an update, or updating the name: look up the name 288952a6212SJordan K. Hubbard * and verify that it refers to a sensible block device. 28927a0bc89SDoug Rabson */ 29027a0bc89SDoug Rabson NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 29127a0bc89SDoug Rabson error = namei(ndp); 292952a6212SJordan K. Hubbard if (error) 293952a6212SJordan K. Hubbard return (error); 29427a0bc89SDoug Rabson devvp = ndp->ni_vp; 295952a6212SJordan K. Hubbard 29627a0bc89SDoug Rabson if (devvp->v_type != VBLK) { 29727a0bc89SDoug Rabson vrele(devvp); 298952a6212SJordan K. Hubbard return (ENOTBLK); 29927a0bc89SDoug Rabson } 30027a0bc89SDoug Rabson if (major(devvp->v_rdev) >= nblkdev) { 30127a0bc89SDoug Rabson vrele(devvp); 302952a6212SJordan K. Hubbard return (ENXIO); 30327a0bc89SDoug Rabson } 30427a0bc89SDoug Rabson /* 305952a6212SJordan K. Hubbard * If mount by non-root, then verify that user has necessary 306952a6212SJordan K. Hubbard * permissions on the device. 30727a0bc89SDoug Rabson */ 308952a6212SJordan K. Hubbard if (p->p_ucred->cr_uid != 0) { 309952a6212SJordan K. Hubbard accessmode = VREAD; 310952a6212SJordan K. Hubbard if ((mp->mnt_flag & MNT_RDONLY) == 0) 311952a6212SJordan K. Hubbard accessmode |= VWRITE; 312952a6212SJordan K. Hubbard vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 313952a6212SJordan K. Hubbard error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p); 314952a6212SJordan K. Hubbard if (error) { 315952a6212SJordan K. Hubbard vput(devvp); 316952a6212SJordan K. Hubbard return (error); 317952a6212SJordan K. Hubbard } 318952a6212SJordan K. Hubbard VOP_UNLOCK(devvp, 0, p); 319952a6212SJordan K. Hubbard } 320952a6212SJordan K. Hubbard if ((mp->mnt_flag & MNT_UPDATE) == 0) { 321952a6212SJordan K. Hubbard error = mountmsdosfs(devvp, mp, p, &args); 322952a6212SJordan K. Hubbard #ifdef MSDOSFS_DEBUG /* only needed for the printf below */ 323952a6212SJordan K. Hubbard pmp = VFSTOMSDOSFS(mp); 324952a6212SJordan K. Hubbard #endif 325952a6212SJordan K. Hubbard } else { 32627a0bc89SDoug Rabson if (devvp != pmp->pm_devvp) 327952a6212SJordan K. Hubbard error = EINVAL; /* XXX needs translation */ 32827a0bc89SDoug Rabson else 32927a0bc89SDoug Rabson vrele(devvp); 33027a0bc89SDoug Rabson } 33127a0bc89SDoug Rabson if (error) { 33227a0bc89SDoug Rabson vrele(devvp); 333952a6212SJordan K. Hubbard return (error); 334952a6212SJordan K. Hubbard } 335952a6212SJordan K. Hubbard 336952a6212SJordan K. Hubbard error = update_mp(mp, &args); 337952a6212SJordan K. Hubbard if (error) { 338952a6212SJordan K. Hubbard msdosfs_unmount(mp, MNT_FORCE, p); 33927a0bc89SDoug Rabson return error; 34027a0bc89SDoug Rabson } 34127a0bc89SDoug Rabson 342952a6212SJordan K. Hubbard (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); 343952a6212SJordan K. Hubbard bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 344952a6212SJordan K. Hubbard (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 345952a6212SJordan K. Hubbard &size); 346952a6212SJordan K. Hubbard bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 34727a0bc89SDoug Rabson (void) msdosfs_statfs(mp, &mp->mnt_stat, p); 34827a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 349623ae52eSPoul-Henning Kamp printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); 35027a0bc89SDoug Rabson #endif 351952a6212SJordan K. Hubbard return (0); 35227a0bc89SDoug Rabson } 35327a0bc89SDoug Rabson 3547fefffeeSPoul-Henning Kamp static int 355952a6212SJordan K. Hubbard mountmsdosfs(devvp, mp, p, argp) 35627a0bc89SDoug Rabson struct vnode *devvp; 35727a0bc89SDoug Rabson struct mount *mp; 35827a0bc89SDoug Rabson struct proc *p; 359952a6212SJordan K. Hubbard struct msdosfs_args *argp; 36027a0bc89SDoug Rabson { 361952a6212SJordan K. Hubbard struct msdosfsmount *pmp; 362952a6212SJordan K. Hubbard struct buf *bp; 36327a0bc89SDoug Rabson dev_t dev = devvp->v_rdev; 364952a6212SJordan K. Hubbard #ifndef __FreeBSD__ 365952a6212SJordan K. Hubbard struct partinfo dpart; 366952a6212SJordan K. Hubbard #endif 36727a0bc89SDoug Rabson union bootsector *bsp; 36827a0bc89SDoug Rabson struct byte_bpb33 *b33; 36927a0bc89SDoug Rabson struct byte_bpb50 *b50; 370952a6212SJordan K. Hubbard struct byte_bpb710 *b710; 371952a6212SJordan K. Hubbard u_int8_t SecPerClust; 372952a6212SJordan K. Hubbard int ronly, error; 373952a6212SJordan K. Hubbard int bsize = 0, dtype = 0, tmp; 37427a0bc89SDoug Rabson 37527a0bc89SDoug Rabson /* 376952a6212SJordan K. Hubbard * Disallow multiple mounts of the same device. 377952a6212SJordan K. Hubbard * Disallow mounting of a device that is currently in use 378952a6212SJordan K. Hubbard * (except for root, which might share swap device for miniroot). 379952a6212SJordan K. Hubbard * Flush out any old buffers remaining from a previous use. 38027a0bc89SDoug Rabson */ 381c3c6d51eSPoul-Henning Kamp error = vfs_mountedon(devvp); 382c3c6d51eSPoul-Henning Kamp if (error) 383952a6212SJordan K. Hubbard return (error); 384952a6212SJordan K. Hubbard if (vcount(devvp) > 1 && devvp != rootvp) 385952a6212SJordan K. Hubbard return (EBUSY); 386952a6212SJordan K. Hubbard vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 387c3c6d51eSPoul-Henning Kamp error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0); 388952a6212SJordan K. Hubbard VOP_UNLOCK(devvp, 0, p); 389c3c6d51eSPoul-Henning Kamp if (error) 390952a6212SJordan K. Hubbard return (error); 39127a0bc89SDoug Rabson 392952a6212SJordan K. Hubbard ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 393c3c6d51eSPoul-Henning Kamp error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p); 394c3c6d51eSPoul-Henning Kamp if (error) 395952a6212SJordan K. Hubbard return (error); 396952a6212SJordan K. Hubbard 397952a6212SJordan K. Hubbard bp = NULL; /* both used in error_exit */ 398952a6212SJordan K. Hubbard pmp = NULL; 399952a6212SJordan K. Hubbard 400952a6212SJordan K. Hubbard #ifndef __FreeBSD__ 401952a6212SJordan K. Hubbard if (argp->flags & MSDOSFSMNT_GEMDOSFS) { 40227a0bc89SDoug Rabson /* 403952a6212SJordan K. Hubbard * We need the disklabel to calculate the size of a FAT entry 404952a6212SJordan K. Hubbard * later on. Also make sure the partition contains a filesystem 405952a6212SJordan K. Hubbard * of type FS_MSDOS. This doesn't work for floppies, so we have 406952a6212SJordan K. Hubbard * to check for them too. 407952a6212SJordan K. Hubbard * 408952a6212SJordan K. Hubbard * At least some parts of the msdos fs driver seem to assume 409952a6212SJordan K. Hubbard * that the size of a disk block will always be 512 bytes. 410952a6212SJordan K. Hubbard * Let's check it... 41127a0bc89SDoug Rabson */ 412952a6212SJordan K. Hubbard error = VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, 413952a6212SJordan K. Hubbard FREAD, NOCRED, p); 414952a6212SJordan K. Hubbard if (error) 415952a6212SJordan K. Hubbard goto error_exit; 416952a6212SJordan K. Hubbard tmp = dpart.part->p_fstype; 417952a6212SJordan K. Hubbard dtype = dpart.disklab->d_type; 418952a6212SJordan K. Hubbard bsize = dpart.disklab->d_secsize; 419952a6212SJordan K. Hubbard if (bsize != 512 || (dtype!=DTYPE_FLOPPY && tmp!=FS_MSDOS)) { 420952a6212SJordan K. Hubbard error = EINVAL; 421952a6212SJordan K. Hubbard goto error_exit; 422952a6212SJordan K. Hubbard } 42327a0bc89SDoug Rabson } 42427a0bc89SDoug Rabson #endif 42527a0bc89SDoug Rabson 42627a0bc89SDoug Rabson /* 427952a6212SJordan K. Hubbard * Read the boot sector of the filesystem, and then check the 428952a6212SJordan K. Hubbard * boot signature. If not a dos boot sector then error out. 42927a0bc89SDoug Rabson */ 430ad63a118SSatoshi Asami #ifdef PC98 431952a6212SJordan K. Hubbard error = bread(devvp, 0, 1024, NOCRED, &bp); 432ad63a118SSatoshi Asami #else 433952a6212SJordan K. Hubbard error = bread(devvp, 0, 512, NOCRED, &bp); 434ad63a118SSatoshi Asami #endif 435c3c6d51eSPoul-Henning Kamp if (error) 43627a0bc89SDoug Rabson goto error_exit; 437952a6212SJordan K. Hubbard bp->b_flags |= B_AGE; 438952a6212SJordan K. Hubbard bsp = (union bootsector *)bp->b_data; 43927a0bc89SDoug Rabson b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB; 44027a0bc89SDoug Rabson b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB; 441952a6212SJordan K. Hubbard b710 = (struct byte_bpb710 *)bsp->bs710.bsPBP; 442952a6212SJordan K. Hubbard 443952a6212SJordan K. Hubbard #ifndef __FreeBSD__ 444952a6212SJordan K. Hubbard if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) { 445952a6212SJordan K. Hubbard #endif 446ad63a118SSatoshi Asami #ifdef PC98 447efa0ac5bSKATO Takenori if ((bsp->bs50.bsBootSectSig0 != BOOTSIG0 448efa0ac5bSKATO Takenori || bsp->bs50.bsBootSectSig1 != BOOTSIG1) 449efa0ac5bSKATO Takenori && (bsp->bs50.bsBootSectSig0 != 0 /* PC98 DOS 3.3x */ 450efa0ac5bSKATO Takenori || bsp->bs50.bsBootSectSig1 != 0) 451efa0ac5bSKATO Takenori && (bsp->bs50.bsBootSectSig0 != 0x90 /* PC98 DOS 5.0 */ 452efa0ac5bSKATO Takenori || bsp->bs50.bsBootSectSig1 != 0x3d) 453efa0ac5bSKATO Takenori && (bsp->bs50.bsBootSectSig0 != 0x46 /* PC98 DOS 3.3B */ 454efa0ac5bSKATO Takenori || bsp->bs50.bsBootSectSig1 != 0xfa)) { 455ad63a118SSatoshi Asami #else 456952a6212SJordan K. Hubbard if (bsp->bs50.bsBootSectSig0 != BOOTSIG0 457952a6212SJordan K. Hubbard || bsp->bs50.bsBootSectSig1 != BOOTSIG1) { 458ad63a118SSatoshi Asami #endif 45927a0bc89SDoug Rabson error = EINVAL; 460aaf0bb19SAndrey A. Chernov printf("mountmsdosfs(): bad signature\n"); 46127a0bc89SDoug Rabson goto error_exit; 46227a0bc89SDoug Rabson } 463952a6212SJordan K. Hubbard #ifndef __FreeBSD__ 46427a0bc89SDoug Rabson } 465952a6212SJordan K. Hubbard #endif 46627a0bc89SDoug Rabson 46727a0bc89SDoug Rabson pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK); 46827a0bc89SDoug Rabson bzero((caddr_t)pmp, sizeof *pmp); 46927a0bc89SDoug Rabson pmp->pm_mountp = mp; 47027a0bc89SDoug Rabson 47127a0bc89SDoug Rabson /* 47227a0bc89SDoug Rabson * Compute several useful quantities from the bpb in the 47327a0bc89SDoug Rabson * bootsector. Copy in the dos 5 variant of the bpb then fix up 47427a0bc89SDoug Rabson * the fields that are different between dos 5 and dos 3.3. 47527a0bc89SDoug Rabson */ 476952a6212SJordan K. Hubbard SecPerClust = b50->bpbSecPerClust; 47727a0bc89SDoug Rabson pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 47827a0bc89SDoug Rabson pmp->pm_ResSectors = getushort(b50->bpbResSectors); 47927a0bc89SDoug Rabson pmp->pm_FATs = b50->bpbFATs; 48027a0bc89SDoug Rabson pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 48127a0bc89SDoug Rabson pmp->pm_Sectors = getushort(b50->bpbSectors); 48227a0bc89SDoug Rabson pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 48327a0bc89SDoug Rabson pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 48427a0bc89SDoug Rabson pmp->pm_Heads = getushort(b50->bpbHeads); 485952a6212SJordan K. Hubbard pmp->pm_Media = b50->bpbMedia; 48627a0bc89SDoug Rabson 487952a6212SJordan K. Hubbard #ifndef __FreeBSD__ 488952a6212SJordan K. Hubbard if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) { 489952a6212SJordan K. Hubbard #endif 49027a0bc89SDoug Rabson /* XXX - We should probably check more values here */ 491952a6212SJordan K. Hubbard if (!pmp->pm_BytesPerSec || !SecPerClust 492952a6212SJordan K. Hubbard || !pmp->pm_Heads || pmp->pm_Heads > 255 493ad63a118SSatoshi Asami #ifdef PC98 494952a6212SJordan K. Hubbard || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) { 495ad63a118SSatoshi Asami #else 496952a6212SJordan K. Hubbard || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) { 497ad63a118SSatoshi Asami #endif 49827a0bc89SDoug Rabson error = EINVAL; 499aaf0bb19SAndrey A. Chernov printf("mountmsdosfs(): bad bpb\n"); 50027a0bc89SDoug Rabson goto error_exit; 50127a0bc89SDoug Rabson } 502952a6212SJordan K. Hubbard #ifndef __FreeBSD__ 503952a6212SJordan K. Hubbard } 504952a6212SJordan K. Hubbard #endif 50527a0bc89SDoug Rabson 50627a0bc89SDoug Rabson if (pmp->pm_Sectors == 0) { 50727a0bc89SDoug Rabson pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 50827a0bc89SDoug Rabson pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 50927a0bc89SDoug Rabson } else { 51027a0bc89SDoug Rabson pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 51127a0bc89SDoug Rabson pmp->pm_HugeSectors = pmp->pm_Sectors; 51227a0bc89SDoug Rabson } 513c681be37SDmitrij Tejblum if (pmp->pm_HugeSectors > 0xffffffff / 514c681be37SDmitrij Tejblum (pmp->pm_BytesPerSec / sizeof(struct direntry)) + 1) { 515952a6212SJordan K. Hubbard /* 516952a6212SJordan K. Hubbard * We cannot deal currently with this size of disk 517952a6212SJordan K. Hubbard * due to fileid limitations (see msdosfs_getattr and 518952a6212SJordan K. Hubbard * msdosfs_readdir) 519952a6212SJordan K. Hubbard */ 520952a6212SJordan K. Hubbard error = EINVAL; 521aaf0bb19SAndrey A. Chernov printf("mountmsdosfs(): disk too big, sorry\n"); 522952a6212SJordan K. Hubbard goto error_exit; 523952a6212SJordan K. Hubbard } 524952a6212SJordan K. Hubbard 525952a6212SJordan K. Hubbard if (pmp->pm_RootDirEnts == 0) { 526952a6212SJordan K. Hubbard if (bsp->bs710.bsBootSectSig2 != BOOTSIG2 527952a6212SJordan K. Hubbard || bsp->bs710.bsBootSectSig3 != BOOTSIG3 528952a6212SJordan K. Hubbard || pmp->pm_Sectors 529952a6212SJordan K. Hubbard || pmp->pm_FATsecs 530952a6212SJordan K. Hubbard || getushort(b710->bpbFSVers)) { 531952a6212SJordan K. Hubbard error = EINVAL; 532aaf0bb19SAndrey A. Chernov printf("mountmsdosfs(): bad FAT32 filesystem\n"); 533952a6212SJordan K. Hubbard goto error_exit; 534952a6212SJordan K. Hubbard } 535952a6212SJordan K. Hubbard pmp->pm_fatmask = FAT32_MASK; 536952a6212SJordan K. Hubbard pmp->pm_fatmult = 4; 537952a6212SJordan K. Hubbard pmp->pm_fatdiv = 1; 538952a6212SJordan K. Hubbard pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs); 539952a6212SJordan K. Hubbard if (getushort(b710->bpbExtFlags) & FATMIRROR) 540952a6212SJordan K. Hubbard pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM; 541952a6212SJordan K. Hubbard else 542952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFS_FATMIRROR; 543952a6212SJordan K. Hubbard } else 544952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFS_FATMIRROR; 545952a6212SJordan K. Hubbard 546952a6212SJordan K. Hubbard #ifndef __FreeBSD__ 547952a6212SJordan K. Hubbard if (argp->flags & MSDOSFSMNT_GEMDOSFS) { 548952a6212SJordan K. Hubbard if (FAT32(pmp)) { 549952a6212SJordan K. Hubbard /* 550952a6212SJordan K. Hubbard * GEMDOS doesn't know fat32. 551952a6212SJordan K. Hubbard */ 552952a6212SJordan K. Hubbard error = EINVAL; 553952a6212SJordan K. Hubbard goto error_exit; 554952a6212SJordan K. Hubbard } 555952a6212SJordan K. Hubbard 556952a6212SJordan K. Hubbard /* 557952a6212SJordan K. Hubbard * Check a few values (could do some more): 558952a6212SJordan K. Hubbard * - logical sector size: power of 2, >= block size 559952a6212SJordan K. Hubbard * - sectors per cluster: power of 2, >= 1 560952a6212SJordan K. Hubbard * - number of sectors: >= 1, <= size of partition 561952a6212SJordan K. Hubbard */ 562952a6212SJordan K. Hubbard if ( (SecPerClust == 0) 563952a6212SJordan K. Hubbard || (SecPerClust & (SecPerClust - 1)) 564952a6212SJordan K. Hubbard || (pmp->pm_BytesPerSec < bsize) 565952a6212SJordan K. Hubbard || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) 566952a6212SJordan K. Hubbard || (pmp->pm_HugeSectors == 0) 567952a6212SJordan K. Hubbard || (pmp->pm_HugeSectors * (pmp->pm_BytesPerSec / bsize) 568952a6212SJordan K. Hubbard > dpart.part->p_size) 569952a6212SJordan K. Hubbard ) { 570952a6212SJordan K. Hubbard error = EINVAL; 571952a6212SJordan K. Hubbard goto error_exit; 572952a6212SJordan K. Hubbard } 573952a6212SJordan K. Hubbard /* 574952a6212SJordan K. Hubbard * XXX - Many parts of the msdos fs driver seem to assume that 575952a6212SJordan K. Hubbard * the number of bytes per logical sector (BytesPerSec) will 576952a6212SJordan K. Hubbard * always be the same as the number of bytes per disk block 577952a6212SJordan K. Hubbard * Let's pretend it is. 578952a6212SJordan K. Hubbard */ 579952a6212SJordan K. Hubbard tmp = pmp->pm_BytesPerSec / bsize; 580952a6212SJordan K. Hubbard pmp->pm_BytesPerSec = bsize; 581952a6212SJordan K. Hubbard pmp->pm_HugeSectors *= tmp; 582952a6212SJordan K. Hubbard pmp->pm_HiddenSects *= tmp; 583952a6212SJordan K. Hubbard pmp->pm_ResSectors *= tmp; 584952a6212SJordan K. Hubbard pmp->pm_Sectors *= tmp; 585952a6212SJordan K. Hubbard pmp->pm_FATsecs *= tmp; 586952a6212SJordan K. Hubbard SecPerClust *= tmp; 587952a6212SJordan K. Hubbard } 588952a6212SJordan K. Hubbard #endif 58927a0bc89SDoug Rabson pmp->pm_fatblk = pmp->pm_ResSectors; 590952a6212SJordan K. Hubbard if (FAT32(pmp)) { 591952a6212SJordan K. Hubbard pmp->pm_rootdirblk = getulong(b710->bpbRootClust); 592952a6212SJordan K. Hubbard pmp->pm_firstcluster = pmp->pm_fatblk 593952a6212SJordan K. Hubbard + (pmp->pm_FATs * pmp->pm_FATsecs); 594952a6212SJordan K. Hubbard pmp->pm_fsinfo = getushort(b710->bpbFSInfo); 595952a6212SJordan K. Hubbard } else { 59627a0bc89SDoug Rabson pmp->pm_rootdirblk = pmp->pm_fatblk + 59727a0bc89SDoug Rabson (pmp->pm_FATs * pmp->pm_FATsecs); 598952a6212SJordan K. Hubbard pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry) 599952a6212SJordan K. Hubbard + pmp->pm_BytesPerSec - 1) 600952a6212SJordan K. Hubbard / pmp->pm_BytesPerSec;/* in sectors */ 60127a0bc89SDoug Rabson pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 602952a6212SJordan K. Hubbard } 603952a6212SJordan K. Hubbard 60427a0bc89SDoug Rabson pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 605952a6212SJordan K. Hubbard SecPerClust; 60627a0bc89SDoug Rabson pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1; 60727a0bc89SDoug Rabson pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec; 608952a6212SJordan K. Hubbard 609952a6212SJordan K. Hubbard #ifndef __FreeBSD__ 610952a6212SJordan K. Hubbard if (argp->flags & MSDOSFSMNT_GEMDOSFS) { 611952a6212SJordan K. Hubbard if ((pmp->pm_nmbrofclusters <= (0xff0 - 2)) 612952a6212SJordan K. Hubbard && ((dtype == DTYPE_FLOPPY) || ((dtype == DTYPE_VNODE) 613952a6212SJordan K. Hubbard && ((pmp->pm_Heads == 1) || (pmp->pm_Heads == 2)))) 614952a6212SJordan K. Hubbard ) { 615952a6212SJordan K. Hubbard pmp->pm_fatmask = FAT12_MASK; 616952a6212SJordan K. Hubbard pmp->pm_fatmult = 3; 617952a6212SJordan K. Hubbard pmp->pm_fatdiv = 2; 618952a6212SJordan K. Hubbard } else { 619952a6212SJordan K. Hubbard pmp->pm_fatmask = FAT16_MASK; 620952a6212SJordan K. Hubbard pmp->pm_fatmult = 2; 621952a6212SJordan K. Hubbard pmp->pm_fatdiv = 1; 622952a6212SJordan K. Hubbard } 623952a6212SJordan K. Hubbard } else 624952a6212SJordan K. Hubbard #endif 625952a6212SJordan K. Hubbard if (pmp->pm_fatmask == 0) { 626952a6212SJordan K. Hubbard if (pmp->pm_maxcluster 627952a6212SJordan K. Hubbard <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) { 62827a0bc89SDoug Rabson /* 629952a6212SJordan K. Hubbard * This will usually be a floppy disk. This size makes 630952a6212SJordan K. Hubbard * sure that one fat entry will not be split across 631952a6212SJordan K. Hubbard * multiple blocks. 63227a0bc89SDoug Rabson */ 633952a6212SJordan K. Hubbard pmp->pm_fatmask = FAT12_MASK; 634952a6212SJordan K. Hubbard pmp->pm_fatmult = 3; 635952a6212SJordan K. Hubbard pmp->pm_fatdiv = 2; 636952a6212SJordan K. Hubbard } else { 637952a6212SJordan K. Hubbard pmp->pm_fatmask = FAT16_MASK; 638952a6212SJordan K. Hubbard pmp->pm_fatmult = 2; 639952a6212SJordan K. Hubbard pmp->pm_fatdiv = 1; 640952a6212SJordan K. Hubbard } 641952a6212SJordan K. Hubbard } 642952a6212SJordan K. Hubbard if (FAT12(pmp)) 64327a0bc89SDoug Rabson pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; 64427a0bc89SDoug Rabson else 645c681be37SDmitrij Tejblum pmp->pm_fatblocksize = DFLTBSIZE; 646952a6212SJordan K. Hubbard 64727a0bc89SDoug Rabson pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec; 648952a6212SJordan K. Hubbard pmp->pm_bnshift = ffs(pmp->pm_BytesPerSec) - 1; 64927a0bc89SDoug Rabson 65027a0bc89SDoug Rabson /* 65127a0bc89SDoug Rabson * Compute mask and shift value for isolating cluster relative byte 65227a0bc89SDoug Rabson * offsets and cluster numbers from a file offset. 65327a0bc89SDoug Rabson */ 654952a6212SJordan K. Hubbard pmp->pm_bpcluster = SecPerClust * pmp->pm_BytesPerSec; 655952a6212SJordan K. Hubbard pmp->pm_crbomask = pmp->pm_bpcluster - 1; 656952a6212SJordan K. Hubbard pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1; 65727a0bc89SDoug Rabson 658952a6212SJordan K. Hubbard /* 659952a6212SJordan K. Hubbard * Check for valid cluster size 660952a6212SJordan K. Hubbard * must be a power of 2 661952a6212SJordan K. Hubbard */ 662952a6212SJordan K. Hubbard if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) { 663952a6212SJordan K. Hubbard error = EINVAL; 664952a6212SJordan K. Hubbard goto error_exit; 665ad63a118SSatoshi Asami } 66627a0bc89SDoug Rabson 66727a0bc89SDoug Rabson /* 66827a0bc89SDoug Rabson * Release the bootsector buffer. 66927a0bc89SDoug Rabson */ 670952a6212SJordan K. Hubbard brelse(bp); 671952a6212SJordan K. Hubbard bp = NULL; 672952a6212SJordan K. Hubbard 673952a6212SJordan K. Hubbard /* 674952a6212SJordan K. Hubbard * Check FSInfo. 675952a6212SJordan K. Hubbard */ 676952a6212SJordan K. Hubbard if (pmp->pm_fsinfo) { 677952a6212SJordan K. Hubbard struct fsinfo *fp; 678952a6212SJordan K. Hubbard 679952a6212SJordan K. Hubbard if ((error = bread(devvp, pmp->pm_fsinfo, 1024, NOCRED, &bp)) != 0) 680952a6212SJordan K. Hubbard goto error_exit; 681952a6212SJordan K. Hubbard fp = (struct fsinfo *)bp->b_data; 682952a6212SJordan K. Hubbard if (!bcmp(fp->fsisig1, "RRaA", 4) 683952a6212SJordan K. Hubbard && !bcmp(fp->fsisig2, "rrAa", 4) 684952a6212SJordan K. Hubbard && !bcmp(fp->fsisig3, "\0\0\125\252", 4) 685952a6212SJordan K. Hubbard && !bcmp(fp->fsisig4, "\0\0\125\252", 4)) 686952a6212SJordan K. Hubbard pmp->pm_nxtfree = getulong(fp->fsinxtfree); 687952a6212SJordan K. Hubbard else 688952a6212SJordan K. Hubbard pmp->pm_fsinfo = 0; 689952a6212SJordan K. Hubbard brelse(bp); 690952a6212SJordan K. Hubbard bp = NULL; 691952a6212SJordan K. Hubbard } 692952a6212SJordan K. Hubbard 693952a6212SJordan K. Hubbard /* 694952a6212SJordan K. Hubbard * Check and validate (or perhaps invalidate?) the fsinfo structure? XXX 695952a6212SJordan K. Hubbard */ 69627a0bc89SDoug Rabson 69727a0bc89SDoug Rabson /* 69827a0bc89SDoug Rabson * Allocate memory for the bitmap of allocated clusters, and then 69927a0bc89SDoug Rabson * fill it in. 70027a0bc89SDoug Rabson */ 70127a0bc89SDoug Rabson pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS - 1) 70227a0bc89SDoug Rabson / N_INUSEBITS) 70327a0bc89SDoug Rabson * sizeof(*pmp->pm_inusemap), 70427a0bc89SDoug Rabson M_MSDOSFSFAT, M_WAITOK); 70527a0bc89SDoug Rabson 70627a0bc89SDoug Rabson /* 70727a0bc89SDoug Rabson * fillinusemap() needs pm_devvp. 70827a0bc89SDoug Rabson */ 70927a0bc89SDoug Rabson pmp->pm_dev = dev; 71027a0bc89SDoug Rabson pmp->pm_devvp = devvp; 71127a0bc89SDoug Rabson 71227a0bc89SDoug Rabson /* 71327a0bc89SDoug Rabson * Have the inuse map filled in. 71427a0bc89SDoug Rabson */ 715952a6212SJordan K. Hubbard if ((error = fillinusemap(pmp)) != 0) 71627a0bc89SDoug Rabson goto error_exit; 71727a0bc89SDoug Rabson 71827a0bc89SDoug Rabson /* 71927a0bc89SDoug Rabson * If they want fat updates to be synchronous then let them suffer 72027a0bc89SDoug Rabson * the performance degradation in exchange for the on disk copy of 72127a0bc89SDoug Rabson * the fat being correct just about all the time. I suppose this 72227a0bc89SDoug Rabson * would be a good thing to turn on if the kernel is still flakey. 72327a0bc89SDoug Rabson */ 724952a6212SJordan K. Hubbard if (mp->mnt_flag & MNT_SYNCHRONOUS) 725952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_WAITONFAT; 72627a0bc89SDoug Rabson 72727a0bc89SDoug Rabson /* 72827a0bc89SDoug Rabson * Finish up. 72927a0bc89SDoug Rabson */ 730952a6212SJordan K. Hubbard if (ronly) 731952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_RONLY; 732952a6212SJordan K. Hubbard else 73327a0bc89SDoug Rabson pmp->pm_fmod = 1; 73427a0bc89SDoug Rabson mp->mnt_data = (qaddr_t) pmp; 73527a0bc89SDoug Rabson mp->mnt_stat.f_fsid.val[0] = (long)dev; 736af3f60d5SBruce Evans mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 737cc9d8990SPeter Wemm mp->mnt_flag |= MNT_LOCAL; 738b1897c19SJulian Elischer devvp->v_specmountpoint = mp; 73927a0bc89SDoug Rabson 74027a0bc89SDoug Rabson return 0; 74127a0bc89SDoug Rabson 742952a6212SJordan K. Hubbard error_exit: 743952a6212SJordan K. Hubbard if (bp) 744952a6212SJordan K. Hubbard brelse(bp); 745952a6212SJordan K. Hubbard (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE, NOCRED, p); 74627a0bc89SDoug Rabson if (pmp) { 74727a0bc89SDoug Rabson if (pmp->pm_inusemap) 748952a6212SJordan K. Hubbard free(pmp->pm_inusemap, M_MSDOSFSFAT); 749952a6212SJordan K. Hubbard free(pmp, M_MSDOSFSMNT); 75027a0bc89SDoug Rabson mp->mnt_data = (qaddr_t)0; 75127a0bc89SDoug Rabson } 752952a6212SJordan K. Hubbard return (error); 75327a0bc89SDoug Rabson } 75427a0bc89SDoug Rabson 7557fefffeeSPoul-Henning Kamp static int 75627a0bc89SDoug Rabson msdosfs_start(mp, flags, p) 75727a0bc89SDoug Rabson struct mount *mp; 75827a0bc89SDoug Rabson int flags; 75927a0bc89SDoug Rabson struct proc *p; 76027a0bc89SDoug Rabson { 761952a6212SJordan K. Hubbard 762952a6212SJordan K. Hubbard return (0); 76327a0bc89SDoug Rabson } 76427a0bc89SDoug Rabson 76527a0bc89SDoug Rabson /* 76627a0bc89SDoug Rabson * Unmount the filesystem described by mp. 76727a0bc89SDoug Rabson */ 7687fefffeeSPoul-Henning Kamp static int 76927a0bc89SDoug Rabson msdosfs_unmount(mp, mntflags, p) 77027a0bc89SDoug Rabson struct mount *mp; 77127a0bc89SDoug Rabson int mntflags; 77227a0bc89SDoug Rabson struct proc *p; 77327a0bc89SDoug Rabson { 774952a6212SJordan K. Hubbard struct msdosfsmount *pmp; 775952a6212SJordan K. Hubbard int error, flags; 77627a0bc89SDoug Rabson 777952a6212SJordan K. Hubbard flags = 0; 778952a6212SJordan K. Hubbard if (mntflags & MNT_FORCE) 77927a0bc89SDoug Rabson flags |= FORCECLOSE; 780c3c6d51eSPoul-Henning Kamp error = vflush(mp, NULLVP, flags); 781c3c6d51eSPoul-Henning Kamp if (error) 78227a0bc89SDoug Rabson return error; 783952a6212SJordan K. Hubbard pmp = VFSTOMSDOSFS(mp); 784b1897c19SJulian Elischer pmp->pm_devvp->v_specmountpoint = NULL; 785952a6212SJordan K. Hubbard #ifdef MSDOSFS_DEBUG 786952a6212SJordan K. Hubbard { 787952a6212SJordan K. Hubbard struct vnode *vp = pmp->pm_devvp; 788952a6212SJordan K. Hubbard 789952a6212SJordan K. Hubbard printf("msdosfs_umount(): just before calling VOP_CLOSE()\n"); 790952a6212SJordan K. Hubbard printf("flag %08lx, usecount %d, writecount %d, holdcnt %ld\n", 791952a6212SJordan K. Hubbard vp->v_flag, vp->v_usecount, vp->v_writecount, vp->v_holdcnt); 792952a6212SJordan K. Hubbard printf("lastr %d, id %lu, mount %p, op %p\n", 793952a6212SJordan K. Hubbard vp->v_lastr, vp->v_id, vp->v_mount, vp->v_op); 794952a6212SJordan K. Hubbard printf("freef %p, freeb %p, mount %p\n", 795952a6212SJordan K. Hubbard vp->v_freelist.tqe_next, vp->v_freelist.tqe_prev, 796952a6212SJordan K. Hubbard vp->v_mount); 797952a6212SJordan K. Hubbard printf("cleanblkhd %p, dirtyblkhd %p, numoutput %ld, type %d\n", 798952a6212SJordan K. Hubbard vp->v_cleanblkhd.lh_first, 799952a6212SJordan K. Hubbard vp->v_dirtyblkhd.lh_first, 800952a6212SJordan K. Hubbard vp->v_numoutput, vp->v_type); 801952a6212SJordan K. Hubbard printf("union %p, tag %d, data[0] %08x, data[1] %08x\n", 802952a6212SJordan K. Hubbard vp->v_socket, vp->v_tag, 803952a6212SJordan K. Hubbard ((u_int *)vp->v_data)[0], 804952a6212SJordan K. Hubbard ((u_int *)vp->v_data)[1]); 805952a6212SJordan K. Hubbard } 806952a6212SJordan K. Hubbard #endif 807b1897c19SJulian Elischer error = VOP_CLOSE(pmp->pm_devvp, 808b1897c19SJulian Elischer (pmp->pm_flags&MSDOSFSMNT_RONLY) ? FREAD : FREAD | FWRITE, 80927a0bc89SDoug Rabson NOCRED, p); 81027a0bc89SDoug Rabson vrele(pmp->pm_devvp); 811952a6212SJordan K. Hubbard free(pmp->pm_inusemap, M_MSDOSFSFAT); 812952a6212SJordan K. Hubbard free(pmp, M_MSDOSFSMNT); 81327a0bc89SDoug Rabson mp->mnt_data = (qaddr_t)0; 814cc9d8990SPeter Wemm mp->mnt_flag &= ~MNT_LOCAL; 815952a6212SJordan K. Hubbard return (error); 81627a0bc89SDoug Rabson } 81727a0bc89SDoug Rabson 8187fefffeeSPoul-Henning Kamp static int 81927a0bc89SDoug Rabson msdosfs_root(mp, vpp) 82027a0bc89SDoug Rabson struct mount *mp; 82127a0bc89SDoug Rabson struct vnode **vpp; 82227a0bc89SDoug Rabson { 823952a6212SJordan K. Hubbard struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 82427a0bc89SDoug Rabson struct denode *ndep; 82527a0bc89SDoug Rabson int error; 82627a0bc89SDoug Rabson 82727a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 828952a6212SJordan K. Hubbard printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp); 82927a0bc89SDoug Rabson #endif 830952a6212SJordan K. Hubbard error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep); 831952a6212SJordan K. Hubbard if (error) 832952a6212SJordan K. Hubbard return (error); 83327a0bc89SDoug Rabson *vpp = DETOV(ndep); 834952a6212SJordan K. Hubbard return (0); 83527a0bc89SDoug Rabson } 83627a0bc89SDoug Rabson 8377fefffeeSPoul-Henning Kamp static int 83827a0bc89SDoug Rabson msdosfs_quotactl(mp, cmds, uid, arg, p) 83927a0bc89SDoug Rabson struct mount *mp; 84027a0bc89SDoug Rabson int cmds; 84127a0bc89SDoug Rabson uid_t uid; 84227a0bc89SDoug Rabson caddr_t arg; 84327a0bc89SDoug Rabson struct proc *p; 84427a0bc89SDoug Rabson { 845c3c6d51eSPoul-Henning Kamp return EOPNOTSUPP; 84627a0bc89SDoug Rabson } 84727a0bc89SDoug Rabson 8487fefffeeSPoul-Henning Kamp static int 84927a0bc89SDoug Rabson msdosfs_statfs(mp, sbp, p) 85027a0bc89SDoug Rabson struct mount *mp; 85127a0bc89SDoug Rabson struct statfs *sbp; 85227a0bc89SDoug Rabson struct proc *p; 85327a0bc89SDoug Rabson { 854952a6212SJordan K. Hubbard struct msdosfsmount *pmp; 85527a0bc89SDoug Rabson 856952a6212SJordan K. Hubbard pmp = VFSTOMSDOSFS(mp); 85727a0bc89SDoug Rabson sbp->f_bsize = pmp->pm_bpcluster; 85827a0bc89SDoug Rabson sbp->f_iosize = pmp->pm_bpcluster; 85927a0bc89SDoug Rabson sbp->f_blocks = pmp->pm_nmbrofclusters; 86027a0bc89SDoug Rabson sbp->f_bfree = pmp->pm_freeclustercount; 86127a0bc89SDoug Rabson sbp->f_bavail = pmp->pm_freeclustercount; 86227a0bc89SDoug Rabson sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ 86327a0bc89SDoug Rabson sbp->f_ffree = 0; /* what to put in here? */ 86427a0bc89SDoug Rabson if (sbp != &mp->mnt_stat) { 865af3f60d5SBruce Evans sbp->f_type = mp->mnt_vfc->vfc_typenum; 866952a6212SJordan K. Hubbard bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 867952a6212SJordan K. Hubbard bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 86827a0bc89SDoug Rabson } 869952a6212SJordan K. Hubbard strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN); 870952a6212SJordan K. Hubbard return (0); 87127a0bc89SDoug Rabson } 87227a0bc89SDoug Rabson 8737fefffeeSPoul-Henning Kamp static int 87427a0bc89SDoug Rabson msdosfs_sync(mp, waitfor, cred, p) 87527a0bc89SDoug Rabson struct mount *mp; 87627a0bc89SDoug Rabson int waitfor; 87727a0bc89SDoug Rabson struct ucred *cred; 87827a0bc89SDoug Rabson struct proc *p; 87927a0bc89SDoug Rabson { 880952a6212SJordan K. Hubbard struct vnode *vp, *nvp; 88127a0bc89SDoug Rabson struct denode *dep; 882952a6212SJordan K. Hubbard struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 883952a6212SJordan K. Hubbard int error, allerror = 0; 88427a0bc89SDoug Rabson 88527a0bc89SDoug Rabson /* 88627a0bc89SDoug Rabson * If we ever switch to not updating all of the fats all the time, 88727a0bc89SDoug Rabson * this would be the place to update them from the first one. 88827a0bc89SDoug Rabson */ 889952a6212SJordan K. Hubbard if (pmp->pm_fmod != 0) 890952a6212SJordan K. Hubbard if (pmp->pm_flags & MSDOSFSMNT_RONLY) 89127a0bc89SDoug Rabson panic("msdosfs_sync: rofs mod"); 89227a0bc89SDoug Rabson else { 89327a0bc89SDoug Rabson /* update fats here */ 89427a0bc89SDoug Rabson } 89527a0bc89SDoug Rabson /* 896952a6212SJordan K. Hubbard * Write back each (modified) denode. 89727a0bc89SDoug Rabson */ 898af3f60d5SBruce Evans simple_lock(&mntvnode_slock); 89927a0bc89SDoug Rabson loop: 900c681be37SDmitrij Tejblum for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { 901952a6212SJordan K. Hubbard /* 902952a6212SJordan K. Hubbard * If the vnode that we are about to sync is no longer 903c681be37SDmitrij Tejblum * associated with this mount point, start over. 904952a6212SJordan K. Hubbard */ 905952a6212SJordan K. Hubbard if (vp->v_mount != mp) 90627a0bc89SDoug Rabson goto loop; 907952a6212SJordan K. Hubbard 908af3f60d5SBruce Evans simple_lock(&vp->v_interlock); 909952a6212SJordan K. Hubbard nvp = vp->v_mntvnodes.le_next; 91027a0bc89SDoug Rabson dep = VTODE(vp); 911c681be37SDmitrij Tejblum if (vp->v_type == VNON || 912c681be37SDmitrij Tejblum (dep->de_flag & 913c681be37SDmitrij Tejblum (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0 && 914c681be37SDmitrij Tejblum (vp->v_dirtyblkhd.lh_first == NULL || 915c681be37SDmitrij Tejblum waitfor == MNT_LAZY)) { 916af3f60d5SBruce Evans simple_unlock(&vp->v_interlock); 91727a0bc89SDoug Rabson continue; 918af3f60d5SBruce Evans } 919af3f60d5SBruce Evans simple_unlock(&mntvnode_slock); 920af3f60d5SBruce Evans error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); 921af3f60d5SBruce Evans if (error) { 922af3f60d5SBruce Evans simple_lock(&mntvnode_slock); 923af3f60d5SBruce Evans if (error == ENOENT) 92427a0bc89SDoug Rabson goto loop; 925af3f60d5SBruce Evans continue; 926af3f60d5SBruce Evans } 927c3c6d51eSPoul-Henning Kamp error = VOP_FSYNC(vp, cred, waitfor, p); 928c3c6d51eSPoul-Henning Kamp if (error) 92927a0bc89SDoug Rabson allerror = error; 930af3f60d5SBruce Evans VOP_UNLOCK(vp, 0, p); 931c681be37SDmitrij Tejblum vrele(vp); 932af3f60d5SBruce Evans simple_lock(&mntvnode_slock); 93327a0bc89SDoug Rabson } 934af3f60d5SBruce Evans simple_unlock(&mntvnode_slock); 93527a0bc89SDoug Rabson 93627a0bc89SDoug Rabson /* 93727a0bc89SDoug Rabson * Flush filesystem control info. 93827a0bc89SDoug Rabson */ 939c681be37SDmitrij Tejblum if (waitfor != MNT_LAZY) { 940c681be37SDmitrij Tejblum vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY, p); 941c3c6d51eSPoul-Henning Kamp error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p); 942c3c6d51eSPoul-Henning Kamp if (error) 94327a0bc89SDoug Rabson allerror = error; 944c681be37SDmitrij Tejblum VOP_UNLOCK(pmp->pm_devvp, 0, p); 945c681be37SDmitrij Tejblum } 946952a6212SJordan K. Hubbard return (allerror); 94727a0bc89SDoug Rabson } 94827a0bc89SDoug Rabson 9497fefffeeSPoul-Henning Kamp static int 95027a0bc89SDoug Rabson msdosfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 95127a0bc89SDoug Rabson struct mount *mp; 95227a0bc89SDoug Rabson struct fid *fhp; 95357bf258eSGarrett Wollman struct sockaddr *nam; 95427a0bc89SDoug Rabson struct vnode **vpp; 95527a0bc89SDoug Rabson int *exflagsp; 95627a0bc89SDoug Rabson struct ucred **credanonp; 95727a0bc89SDoug Rabson { 958952a6212SJordan K. Hubbard struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 95927a0bc89SDoug Rabson struct defid *defhp = (struct defid *) fhp; 96027a0bc89SDoug Rabson struct denode *dep; 96127a0bc89SDoug Rabson struct netcred *np; 96227a0bc89SDoug Rabson int error; 96327a0bc89SDoug Rabson 96427a0bc89SDoug Rabson np = vfs_export_lookup(mp, &pmp->pm_export, nam); 96527a0bc89SDoug Rabson if (np == NULL) 966952a6212SJordan K. Hubbard return (EACCES); 967952a6212SJordan K. Hubbard error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep); 96827a0bc89SDoug Rabson if (error) { 96927a0bc89SDoug Rabson *vpp = NULLVP; 970952a6212SJordan K. Hubbard return (error); 97127a0bc89SDoug Rabson } 97227a0bc89SDoug Rabson *vpp = DETOV(dep); 97327a0bc89SDoug Rabson *exflagsp = np->netc_exflags; 97427a0bc89SDoug Rabson *credanonp = &np->netc_anon; 975952a6212SJordan K. Hubbard return (0); 97627a0bc89SDoug Rabson } 97727a0bc89SDoug Rabson 9787fefffeeSPoul-Henning Kamp static int 97927a0bc89SDoug Rabson msdosfs_vptofh(vp, fhp) 98027a0bc89SDoug Rabson struct vnode *vp; 98127a0bc89SDoug Rabson struct fid *fhp; 98227a0bc89SDoug Rabson { 983952a6212SJordan K. Hubbard struct denode *dep; 984952a6212SJordan K. Hubbard struct defid *defhp; 98527a0bc89SDoug Rabson 986952a6212SJordan K. Hubbard dep = VTODE(vp); 987952a6212SJordan K. Hubbard defhp = (struct defid *)fhp; 98827a0bc89SDoug Rabson defhp->defid_len = sizeof(struct defid); 98927a0bc89SDoug Rabson defhp->defid_dirclust = dep->de_dirclust; 99027a0bc89SDoug Rabson defhp->defid_dirofs = dep->de_diroffset; 991952a6212SJordan K. Hubbard /* defhp->defid_gen = dep->de_gen; */ 992952a6212SJordan K. Hubbard return (0); 99327a0bc89SDoug Rabson } 99427a0bc89SDoug Rabson 9957fefffeeSPoul-Henning Kamp static int 99627a0bc89SDoug Rabson msdosfs_vget(mp, ino, vpp) 99727a0bc89SDoug Rabson struct mount *mp; 99827a0bc89SDoug Rabson ino_t ino; 99927a0bc89SDoug Rabson struct vnode **vpp; 100027a0bc89SDoug Rabson { 100127a0bc89SDoug Rabson return EOPNOTSUPP; 100227a0bc89SDoug Rabson } 100327a0bc89SDoug Rabson 100430ffadf3SPoul-Henning Kamp static struct vfsops msdosfs_vfsops = { 100527a0bc89SDoug Rabson msdosfs_mount, 100627a0bc89SDoug Rabson msdosfs_start, 100727a0bc89SDoug Rabson msdosfs_unmount, 100827a0bc89SDoug Rabson msdosfs_root, 100927a0bc89SDoug Rabson msdosfs_quotactl, 101027a0bc89SDoug Rabson msdosfs_statfs, 101127a0bc89SDoug Rabson msdosfs_sync, 101227a0bc89SDoug Rabson msdosfs_vget, 101327a0bc89SDoug Rabson msdosfs_fhtovp, 101427a0bc89SDoug Rabson msdosfs_vptofh, 101527a0bc89SDoug Rabson msdosfs_init 101627a0bc89SDoug Rabson }; 1017c901836cSGarrett Wollman 10188994ca3cSBruce Evans VFS_SET(msdosfs_vfsops, msdos, 0); 1019