1c3aac50fSPeter Wemm /* $FreeBSD$ */ 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> 5365baf8f0SBruce Evans #include <sys/conf.h> 5427a0bc89SDoug Rabson #include <sys/namei.h> 5527a0bc89SDoug Rabson #include <sys/proc.h> 5627a0bc89SDoug Rabson #include <sys/kernel.h> 5727a0bc89SDoug Rabson #include <sys/vnode.h> 5827a0bc89SDoug Rabson #include <sys/mount.h> 599626b608SPoul-Henning Kamp #include <sys/bio.h> 6027a0bc89SDoug Rabson #include <sys/buf.h> 613ac4d1efSBruce Evans #include <sys/fcntl.h> 6227a0bc89SDoug Rabson #include <sys/malloc.h> 63952a6212SJordan K. Hubbard #include <sys/stat.h> /* defines ALLPERMS */ 641b367556SJason Evans #include <sys/mutex.h> 65a18b1f1dSJason Evans 661166fb51SRuslan Ermilov #include <fs/msdosfs/bpb.h> 671166fb51SRuslan Ermilov #include <fs/msdosfs/bootsect.h> 681166fb51SRuslan Ermilov #include <fs/msdosfs/direntry.h> 691166fb51SRuslan Ermilov #include <fs/msdosfs/denode.h> 701166fb51SRuslan Ermilov #include <fs/msdosfs/msdosfsmount.h> 711166fb51SRuslan Ermilov #include <fs/msdosfs/fat.h> 7227a0bc89SDoug Rabson 737c58e473SMatthew Dillon #define MSDOSFS_DFLTBSIZE 4096 747c58e473SMatthew Dillon 7501f6cfbaSYoshihiro Takahashi #if 1 /*def PC98*/ 7601f6cfbaSYoshihiro Takahashi /* 7701f6cfbaSYoshihiro Takahashi * XXX - The boot signature formatted by NEC PC-98 DOS looks like a 7801f6cfbaSYoshihiro Takahashi * garbage or a random value :-{ 7901f6cfbaSYoshihiro Takahashi * If you want to use that broken-signatured media, define the 8001f6cfbaSYoshihiro Takahashi * following symbol even though PC/AT. 8101f6cfbaSYoshihiro Takahashi * (ex. mount PC-98 DOS formatted FD on PC/AT) 8201f6cfbaSYoshihiro Takahashi */ 8301f6cfbaSYoshihiro Takahashi #define MSDOSFS_NOCHECKSIG 8401f6cfbaSYoshihiro Takahashi #endif 8501f6cfbaSYoshihiro Takahashi 86a1c995b6SPoul-Henning Kamp MALLOC_DEFINE(M_MSDOSFSMNT, "MSDOSFS mount", "MSDOSFS mount structure"); 87a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_MSDOSFSFAT, "MSDOSFS FAT", "MSDOSFS file allocation table"); 8855166637SPoul-Henning Kamp 89952a6212SJordan K. Hubbard static int update_mp __P((struct mount *mp, struct msdosfs_args *argp)); 90af482601SBruce Evans static int mountmsdosfs __P((struct vnode *devvp, struct mount *mp, 91952a6212SJordan K. Hubbard struct proc *p, struct msdosfs_args *argp)); 92af482601SBruce Evans static int msdosfs_fhtovp __P((struct mount *, struct fid *, 93c24fda81SAlfred Perlstein struct vnode **)); 94af482601SBruce Evans static int msdosfs_mount __P((struct mount *, char *, caddr_t, 95af482601SBruce Evans struct nameidata *, struct proc *)); 96af482601SBruce Evans static int msdosfs_root __P((struct mount *, struct vnode **)); 97af482601SBruce Evans static int msdosfs_statfs __P((struct mount *, struct statfs *, 98af482601SBruce Evans struct proc *)); 99af482601SBruce Evans static int msdosfs_sync __P((struct mount *, int, struct ucred *, 100af482601SBruce Evans struct proc *)); 101af482601SBruce Evans static int msdosfs_unmount __P((struct mount *, int, struct proc *)); 102af482601SBruce Evans static int msdosfs_vptofh __P((struct vnode *, struct fid *)); 103af482601SBruce Evans 104952a6212SJordan K. Hubbard static int 105952a6212SJordan K. Hubbard update_mp(mp, argp) 106952a6212SJordan K. Hubbard struct mount *mp; 107952a6212SJordan K. Hubbard struct msdosfs_args *argp; 108952a6212SJordan K. Hubbard { 109952a6212SJordan K. Hubbard struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 110952a6212SJordan K. Hubbard int error; 111952a6212SJordan K. Hubbard 112952a6212SJordan K. Hubbard pmp->pm_gid = argp->gid; 113952a6212SJordan K. Hubbard pmp->pm_uid = argp->uid; 114952a6212SJordan K. Hubbard pmp->pm_mask = argp->mask & ALLPERMS; 115952a6212SJordan K. Hubbard pmp->pm_flags |= argp->flags & MSDOSFSMNT_MNTOPT; 1167391f611SAndrey A. Chernov if (pmp->pm_flags & MSDOSFSMNT_U2WTABLE) { 11713df76f2SAndrey A. Chernov bcopy(argp->u2w, pmp->pm_u2w, sizeof(pmp->pm_u2w)); 1187391f611SAndrey A. Chernov bcopy(argp->d2u, pmp->pm_d2u, sizeof(pmp->pm_d2u)); 1197391f611SAndrey A. Chernov bcopy(argp->u2d, pmp->pm_u2d, sizeof(pmp->pm_u2d)); 1207391f611SAndrey A. Chernov } 1217391f611SAndrey A. Chernov if (pmp->pm_flags & MSDOSFSMNT_ULTABLE) { 12264fb806cSAndrey A. Chernov bcopy(argp->ul, pmp->pm_ul, sizeof(pmp->pm_ul)); 1237391f611SAndrey A. Chernov bcopy(argp->lu, pmp->pm_lu, sizeof(pmp->pm_lu)); 1247391f611SAndrey A. Chernov } 125952a6212SJordan K. Hubbard 126952a6212SJordan K. Hubbard #ifndef __FreeBSD__ 127952a6212SJordan K. Hubbard /* 128952a6212SJordan K. Hubbard * GEMDOS knows nothing (yet) about win95 129952a6212SJordan K. Hubbard */ 130952a6212SJordan K. Hubbard if (pmp->pm_flags & MSDOSFSMNT_GEMDOSFS) 131952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_NOWIN95; 132952a6212SJordan K. Hubbard #endif 133952a6212SJordan K. Hubbard 134952a6212SJordan K. Hubbard if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 135952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 136952a6212SJordan K. Hubbard else if (!(pmp->pm_flags & 137952a6212SJordan K. Hubbard (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) { 138952a6212SJordan K. Hubbard struct vnode *rootvp; 139952a6212SJordan K. Hubbard 140952a6212SJordan K. Hubbard /* 141952a6212SJordan K. Hubbard * Try to divine whether to support Win'95 long filenames 142952a6212SJordan K. Hubbard */ 143952a6212SJordan K. Hubbard if (FAT32(pmp)) 144952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_LONGNAME; 145952a6212SJordan K. Hubbard else { 146952a6212SJordan K. Hubbard if ((error = msdosfs_root(mp, &rootvp)) != 0) 147952a6212SJordan K. Hubbard return error; 148952a6212SJordan K. Hubbard pmp->pm_flags |= findwin95(VTODE(rootvp)) 149952a6212SJordan K. Hubbard ? MSDOSFSMNT_LONGNAME 150952a6212SJordan K. Hubbard : MSDOSFSMNT_SHORTNAME; 151952a6212SJordan K. Hubbard vput(rootvp); 152952a6212SJordan K. Hubbard } 153952a6212SJordan K. Hubbard } 154952a6212SJordan K. Hubbard return 0; 155952a6212SJordan K. Hubbard } 156952a6212SJordan K. Hubbard 157952a6212SJordan K. Hubbard #ifndef __FreeBSD__ 158952a6212SJordan K. Hubbard int 159952a6212SJordan K. Hubbard msdosfs_mountroot() 160952a6212SJordan K. Hubbard { 161952a6212SJordan K. Hubbard register struct mount *mp; 162952a6212SJordan K. Hubbard struct proc *p = curproc; /* XXX */ 163952a6212SJordan K. Hubbard size_t size; 164952a6212SJordan K. Hubbard int error; 165952a6212SJordan K. Hubbard struct msdosfs_args args; 166952a6212SJordan K. Hubbard 167952a6212SJordan K. Hubbard if (root_device->dv_class != DV_DISK) 168952a6212SJordan K. Hubbard return (ENODEV); 169952a6212SJordan K. Hubbard 170952a6212SJordan K. Hubbard /* 171952a6212SJordan K. Hubbard * Get vnodes for swapdev and rootdev. 172952a6212SJordan K. Hubbard */ 173952a6212SJordan K. Hubbard if (bdevvp(rootdev, &rootvp)) 174952a6212SJordan K. Hubbard panic("msdosfs_mountroot: can't setup rootvp"); 175952a6212SJordan K. Hubbard 1767cc0979fSDavid Malone mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK | M_ZERO); 177952a6212SJordan K. Hubbard mp->mnt_op = &msdosfs_vfsops; 178952a6212SJordan K. Hubbard mp->mnt_flag = 0; 179952a6212SJordan K. Hubbard LIST_INIT(&mp->mnt_vnodelist); 180952a6212SJordan K. Hubbard 181952a6212SJordan K. Hubbard args.flags = 0; 182952a6212SJordan K. Hubbard args.uid = 0; 183952a6212SJordan K. Hubbard args.gid = 0; 184952a6212SJordan K. Hubbard args.mask = 0777; 185952a6212SJordan K. Hubbard 186952a6212SJordan K. Hubbard if ((error = mountmsdosfs(rootvp, mp, p, &args)) != 0) { 187952a6212SJordan K. Hubbard free(mp, M_MOUNT); 188952a6212SJordan K. Hubbard return (error); 189952a6212SJordan K. Hubbard } 190952a6212SJordan K. Hubbard 191952a6212SJordan K. Hubbard if ((error = update_mp(mp, &args)) != 0) { 192952a6212SJordan K. Hubbard (void)msdosfs_unmount(mp, 0, p); 193952a6212SJordan K. Hubbard free(mp, M_MOUNT); 194952a6212SJordan K. Hubbard return (error); 195952a6212SJordan K. Hubbard } 196952a6212SJordan K. Hubbard 197952a6212SJordan K. Hubbard if ((error = vfs_lock(mp)) != 0) { 198952a6212SJordan K. Hubbard (void)msdosfs_unmount(mp, 0, p); 199952a6212SJordan K. Hubbard free(mp, M_MOUNT); 200952a6212SJordan K. Hubbard return (error); 201952a6212SJordan K. Hubbard } 202952a6212SJordan K. Hubbard 2030429e37aSPoul-Henning Kamp TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); 204952a6212SJordan K. Hubbard mp->mnt_vnodecovered = NULLVP; 205952a6212SJordan K. Hubbard (void) copystr("/", mp->mnt_stat.f_mntonname, MNAMELEN - 1, 206952a6212SJordan K. Hubbard &size); 207952a6212SJordan K. Hubbard bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 208952a6212SJordan K. Hubbard (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 209952a6212SJordan K. Hubbard &size); 210952a6212SJordan K. Hubbard bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 211952a6212SJordan K. Hubbard (void)msdosfs_statfs(mp, &mp->mnt_stat, p); 212952a6212SJordan K. Hubbard vfs_unlock(mp); 213952a6212SJordan K. Hubbard return (0); 214952a6212SJordan K. Hubbard } 215952a6212SJordan K. Hubbard #endif 216952a6212SJordan K. Hubbard 21727a0bc89SDoug Rabson /* 21827a0bc89SDoug Rabson * mp - path - addr in user space of mount point (ie /usr or whatever) 21927a0bc89SDoug Rabson * data - addr in user space of mount params including the name of the block 22027a0bc89SDoug Rabson * special file to treat as a filesystem. 22127a0bc89SDoug Rabson */ 2227fefffeeSPoul-Henning Kamp static int 22327a0bc89SDoug Rabson msdosfs_mount(mp, path, data, ndp, p) 22427a0bc89SDoug Rabson struct mount *mp; 22527a0bc89SDoug Rabson char *path; 22627a0bc89SDoug Rabson caddr_t data; 22727a0bc89SDoug Rabson struct nameidata *ndp; 22827a0bc89SDoug Rabson struct proc *p; 22927a0bc89SDoug Rabson { 23027a0bc89SDoug Rabson struct vnode *devvp; /* vnode for blk device to mount */ 23127a0bc89SDoug Rabson struct msdosfs_args args; /* will hold data from mount request */ 232952a6212SJordan K. Hubbard /* msdosfs specific mount control block */ 233952a6212SJordan K. Hubbard struct msdosfsmount *pmp = NULL; 234952a6212SJordan K. Hubbard size_t size; 23527a0bc89SDoug Rabson int error, flags; 236952a6212SJordan K. Hubbard mode_t accessmode; 23727a0bc89SDoug Rabson 238c3c6d51eSPoul-Henning Kamp error = copyin(data, (caddr_t)&args, sizeof(struct msdosfs_args)); 239c3c6d51eSPoul-Henning Kamp if (error) 240952a6212SJordan K. Hubbard return (error); 241206faeeeSDmitrij Tejblum if (args.magic != MSDOSFS_ARGSMAGIC) 242952a6212SJordan K. Hubbard args.flags = 0; 24327a0bc89SDoug Rabson /* 244952a6212SJordan K. Hubbard * If updating, check whether changing from read-only to 245952a6212SJordan K. Hubbard * read/write; if there is no device name, that's all we do. 24627a0bc89SDoug Rabson */ 24727a0bc89SDoug Rabson if (mp->mnt_flag & MNT_UPDATE) { 248952a6212SJordan K. Hubbard pmp = VFSTOMSDOSFS(mp); 24927a0bc89SDoug Rabson error = 0; 250952a6212SJordan K. Hubbard if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_flag & MNT_RDONLY)) { 25127a0bc89SDoug Rabson flags = WRITECLOSE; 25227a0bc89SDoug Rabson if (mp->mnt_flag & MNT_FORCE) 25327a0bc89SDoug Rabson flags |= FORCECLOSE; 2540864ef1eSIan Dowse error = vflush(mp, 0, flags); 25527a0bc89SDoug Rabson } 25627a0bc89SDoug Rabson if (!error && (mp->mnt_flag & MNT_RELOAD)) 25727a0bc89SDoug Rabson /* not yet implemented */ 258952a6212SJordan K. Hubbard error = EOPNOTSUPP; 25927a0bc89SDoug Rabson if (error) 260952a6212SJordan K. Hubbard return (error); 261952a6212SJordan K. Hubbard if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_kern_flag & MNTK_WANTRDWR)) { 262952a6212SJordan K. Hubbard /* 263952a6212SJordan K. Hubbard * If upgrade to read-write by non-root, then verify 264952a6212SJordan K. Hubbard * that user has necessary permissions on the device. 265952a6212SJordan K. Hubbard */ 266952a6212SJordan K. Hubbard if (p->p_ucred->cr_uid != 0) { 267952a6212SJordan K. Hubbard devvp = pmp->pm_devvp; 268206faeeeSDmitrij Tejblum vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 269952a6212SJordan K. Hubbard error = VOP_ACCESS(devvp, VREAD | VWRITE, 270952a6212SJordan K. Hubbard p->p_ucred, p); 271952a6212SJordan K. Hubbard if (error) { 272952a6212SJordan K. Hubbard VOP_UNLOCK(devvp, 0, p); 273952a6212SJordan K. Hubbard return (error); 274952a6212SJordan K. Hubbard } 275952a6212SJordan K. Hubbard VOP_UNLOCK(devvp, 0, p); 276952a6212SJordan K. Hubbard } 277952a6212SJordan K. Hubbard pmp->pm_flags &= ~MSDOSFSMNT_RONLY; 278952a6212SJordan K. Hubbard } 27927a0bc89SDoug Rabson if (args.fspec == 0) { 280952a6212SJordan K. Hubbard #ifdef __notyet__ /* doesn't work correctly with current mountd XXX */ 281952a6212SJordan K. Hubbard if (args.flags & MSDOSFSMNT_MNTOPT) { 282952a6212SJordan K. Hubbard pmp->pm_flags &= ~MSDOSFSMNT_MNTOPT; 283952a6212SJordan K. Hubbard pmp->pm_flags |= args.flags & MSDOSFSMNT_MNTOPT; 284952a6212SJordan K. Hubbard if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 285952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 286952a6212SJordan K. Hubbard } 287952a6212SJordan K. Hubbard #endif 28827a0bc89SDoug Rabson /* 28927a0bc89SDoug Rabson * Process export requests. 29027a0bc89SDoug Rabson */ 291a13234bbSPoul-Henning Kamp return (vfs_export(mp, &args.export)); 29227a0bc89SDoug Rabson } 293952a6212SJordan K. Hubbard } 29427a0bc89SDoug Rabson /* 295952a6212SJordan K. Hubbard * Not an update, or updating the name: look up the name 296952a6212SJordan K. Hubbard * and verify that it refers to a sensible block device. 29727a0bc89SDoug Rabson */ 29827a0bc89SDoug Rabson NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 29927a0bc89SDoug Rabson error = namei(ndp); 300952a6212SJordan K. Hubbard if (error) 301952a6212SJordan K. Hubbard return (error); 30227a0bc89SDoug Rabson devvp = ndp->ni_vp; 303762e6b85SEivind Eklund NDFREE(ndp, NDF_ONLY_PNBUF); 304952a6212SJordan K. Hubbard 305ba4ad1fcSPoul-Henning Kamp if (!vn_isdisk(devvp, &error)) { 30627a0bc89SDoug Rabson vrele(devvp); 307ba4ad1fcSPoul-Henning Kamp return (error); 30827a0bc89SDoug Rabson } 30927a0bc89SDoug Rabson /* 310952a6212SJordan K. Hubbard * If mount by non-root, then verify that user has necessary 311952a6212SJordan K. Hubbard * permissions on the device. 31227a0bc89SDoug Rabson */ 313952a6212SJordan K. Hubbard if (p->p_ucred->cr_uid != 0) { 314952a6212SJordan K. Hubbard accessmode = VREAD; 315952a6212SJordan K. Hubbard if ((mp->mnt_flag & MNT_RDONLY) == 0) 316952a6212SJordan K. Hubbard accessmode |= VWRITE; 317952a6212SJordan K. Hubbard vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 318952a6212SJordan K. Hubbard error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p); 319952a6212SJordan K. Hubbard if (error) { 320952a6212SJordan K. Hubbard vput(devvp); 321952a6212SJordan K. Hubbard return (error); 322952a6212SJordan K. Hubbard } 323952a6212SJordan K. Hubbard VOP_UNLOCK(devvp, 0, p); 324952a6212SJordan K. Hubbard } 325952a6212SJordan K. Hubbard if ((mp->mnt_flag & MNT_UPDATE) == 0) { 326952a6212SJordan K. Hubbard error = mountmsdosfs(devvp, mp, p, &args); 327952a6212SJordan K. Hubbard #ifdef MSDOSFS_DEBUG /* only needed for the printf below */ 328952a6212SJordan K. Hubbard pmp = VFSTOMSDOSFS(mp); 329952a6212SJordan K. Hubbard #endif 330952a6212SJordan K. Hubbard } else { 33127a0bc89SDoug Rabson if (devvp != pmp->pm_devvp) 332952a6212SJordan K. Hubbard error = EINVAL; /* XXX needs translation */ 33327a0bc89SDoug Rabson else 33427a0bc89SDoug Rabson vrele(devvp); 33527a0bc89SDoug Rabson } 33627a0bc89SDoug Rabson if (error) { 33727a0bc89SDoug Rabson vrele(devvp); 338952a6212SJordan K. Hubbard return (error); 339952a6212SJordan K. Hubbard } 340952a6212SJordan K. Hubbard 341952a6212SJordan K. Hubbard error = update_mp(mp, &args); 342952a6212SJordan K. Hubbard if (error) { 343952a6212SJordan K. Hubbard msdosfs_unmount(mp, MNT_FORCE, p); 34427a0bc89SDoug Rabson return error; 34527a0bc89SDoug Rabson } 346952a6212SJordan K. Hubbard (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 347952a6212SJordan K. Hubbard &size); 348952a6212SJordan K. Hubbard bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 34927a0bc89SDoug Rabson (void) msdosfs_statfs(mp, &mp->mnt_stat, p); 35027a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 351623ae52eSPoul-Henning Kamp printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); 35227a0bc89SDoug Rabson #endif 353952a6212SJordan K. Hubbard return (0); 35427a0bc89SDoug Rabson } 35527a0bc89SDoug Rabson 3567fefffeeSPoul-Henning Kamp static int 357952a6212SJordan K. Hubbard mountmsdosfs(devvp, mp, p, argp) 35827a0bc89SDoug Rabson struct vnode *devvp; 35927a0bc89SDoug Rabson struct mount *mp; 36027a0bc89SDoug Rabson struct proc *p; 361952a6212SJordan K. Hubbard struct msdosfs_args *argp; 36227a0bc89SDoug Rabson { 363952a6212SJordan K. Hubbard struct msdosfsmount *pmp; 364952a6212SJordan K. Hubbard struct buf *bp; 36527a0bc89SDoug Rabson dev_t dev = devvp->v_rdev; 366952a6212SJordan K. Hubbard #ifndef __FreeBSD__ 367952a6212SJordan K. Hubbard struct partinfo dpart; 368f1d19042SArchie Cobbs int bsize = 0, dtype = 0, tmp; 369952a6212SJordan K. Hubbard #endif 37027a0bc89SDoug Rabson union bootsector *bsp; 37127a0bc89SDoug Rabson struct byte_bpb33 *b33; 37227a0bc89SDoug Rabson struct byte_bpb50 *b50; 373952a6212SJordan K. Hubbard struct byte_bpb710 *b710; 374952a6212SJordan K. Hubbard u_int8_t SecPerClust; 375499d3ffaSBoris Popov u_long clusters; 376952a6212SJordan K. Hubbard int ronly, error; 37727a0bc89SDoug Rabson 37827a0bc89SDoug Rabson /* 379952a6212SJordan K. Hubbard * Disallow multiple mounts of the same device. 380952a6212SJordan K. Hubbard * Disallow mounting of a device that is currently in use 381952a6212SJordan K. Hubbard * (except for root, which might share swap device for miniroot). 382952a6212SJordan K. Hubbard * Flush out any old buffers remaining from a previous use. 38327a0bc89SDoug Rabson */ 384c3c6d51eSPoul-Henning Kamp error = vfs_mountedon(devvp); 385c3c6d51eSPoul-Henning Kamp if (error) 386952a6212SJordan K. Hubbard return (error); 387952a6212SJordan K. Hubbard if (vcount(devvp) > 1 && devvp != rootvp) 388952a6212SJordan K. Hubbard return (EBUSY); 389952a6212SJordan K. Hubbard vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 390c3c6d51eSPoul-Henning Kamp error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0); 391952a6212SJordan K. Hubbard VOP_UNLOCK(devvp, 0, p); 392c3c6d51eSPoul-Henning Kamp if (error) 393952a6212SJordan K. Hubbard return (error); 39427a0bc89SDoug Rabson 395952a6212SJordan K. Hubbard ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 396698f9cf8SPoul-Henning Kamp vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 397c3c6d51eSPoul-Henning Kamp error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p); 398698f9cf8SPoul-Henning Kamp VOP_UNLOCK(devvp, 0, p); 399c3c6d51eSPoul-Henning Kamp if (error) 400952a6212SJordan K. Hubbard return (error); 401952a6212SJordan K. Hubbard 402952a6212SJordan K. Hubbard bp = NULL; /* both used in error_exit */ 403952a6212SJordan K. Hubbard pmp = NULL; 404952a6212SJordan K. Hubbard 405952a6212SJordan K. Hubbard #ifndef __FreeBSD__ 406952a6212SJordan K. Hubbard if (argp->flags & MSDOSFSMNT_GEMDOSFS) { 40727a0bc89SDoug Rabson /* 408952a6212SJordan K. Hubbard * We need the disklabel to calculate the size of a FAT entry 409952a6212SJordan K. Hubbard * later on. Also make sure the partition contains a filesystem 410952a6212SJordan K. Hubbard * of type FS_MSDOS. This doesn't work for floppies, so we have 411952a6212SJordan K. Hubbard * to check for them too. 412952a6212SJordan K. Hubbard * 413952a6212SJordan K. Hubbard * At least some parts of the msdos fs driver seem to assume 414952a6212SJordan K. Hubbard * that the size of a disk block will always be 512 bytes. 415952a6212SJordan K. Hubbard * Let's check it... 41627a0bc89SDoug Rabson */ 417952a6212SJordan K. Hubbard error = VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, 418952a6212SJordan K. Hubbard FREAD, NOCRED, p); 419952a6212SJordan K. Hubbard if (error) 420952a6212SJordan K. Hubbard goto error_exit; 421952a6212SJordan K. Hubbard tmp = dpart.part->p_fstype; 422952a6212SJordan K. Hubbard dtype = dpart.disklab->d_type; 423952a6212SJordan K. Hubbard bsize = dpart.disklab->d_secsize; 424952a6212SJordan K. Hubbard if (bsize != 512 || (dtype!=DTYPE_FLOPPY && tmp!=FS_MSDOS)) { 425952a6212SJordan K. Hubbard error = EINVAL; 426952a6212SJordan K. Hubbard goto error_exit; 427952a6212SJordan K. Hubbard } 42827a0bc89SDoug Rabson } 42927a0bc89SDoug Rabson #endif 43027a0bc89SDoug Rabson 43127a0bc89SDoug Rabson /* 432952a6212SJordan K. Hubbard * Read the boot sector of the filesystem, and then check the 433952a6212SJordan K. Hubbard * boot signature. If not a dos boot sector then error out. 43401f6cfbaSYoshihiro Takahashi * 43501f6cfbaSYoshihiro Takahashi * NOTE: 2048 is a maximum sector size in current... 43627a0bc89SDoug Rabson */ 43701f6cfbaSYoshihiro Takahashi error = bread(devvp, 0, 2048, NOCRED, &bp); 438c3c6d51eSPoul-Henning Kamp if (error) 43927a0bc89SDoug Rabson goto error_exit; 440952a6212SJordan K. Hubbard bp->b_flags |= B_AGE; 441952a6212SJordan K. Hubbard bsp = (union bootsector *)bp->b_data; 44227a0bc89SDoug Rabson b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB; 44327a0bc89SDoug Rabson b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB; 444952a6212SJordan K. Hubbard b710 = (struct byte_bpb710 *)bsp->bs710.bsPBP; 445952a6212SJordan K. Hubbard 446952a6212SJordan K. Hubbard #ifndef __FreeBSD__ 447952a6212SJordan K. Hubbard if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) { 448952a6212SJordan K. Hubbard #endif 44901f6cfbaSYoshihiro Takahashi #ifndef MSDOSFS_NOCHECKSIG 450952a6212SJordan K. Hubbard if (bsp->bs50.bsBootSectSig0 != BOOTSIG0 451952a6212SJordan K. Hubbard || bsp->bs50.bsBootSectSig1 != BOOTSIG1) { 45227a0bc89SDoug Rabson error = EINVAL; 45327a0bc89SDoug Rabson goto error_exit; 45427a0bc89SDoug Rabson } 45501f6cfbaSYoshihiro Takahashi #endif 456952a6212SJordan K. Hubbard #ifndef __FreeBSD__ 45727a0bc89SDoug Rabson } 458952a6212SJordan K. Hubbard #endif 45927a0bc89SDoug Rabson 4607cc0979fSDavid Malone pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK | M_ZERO); 46127a0bc89SDoug Rabson pmp->pm_mountp = mp; 46227a0bc89SDoug Rabson 46327a0bc89SDoug Rabson /* 46427a0bc89SDoug Rabson * Compute several useful quantities from the bpb in the 46527a0bc89SDoug Rabson * bootsector. Copy in the dos 5 variant of the bpb then fix up 46627a0bc89SDoug Rabson * the fields that are different between dos 5 and dos 3.3. 46727a0bc89SDoug Rabson */ 468952a6212SJordan K. Hubbard SecPerClust = b50->bpbSecPerClust; 46927a0bc89SDoug Rabson pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 47027a0bc89SDoug Rabson pmp->pm_ResSectors = getushort(b50->bpbResSectors); 47127a0bc89SDoug Rabson pmp->pm_FATs = b50->bpbFATs; 47227a0bc89SDoug Rabson pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 47327a0bc89SDoug Rabson pmp->pm_Sectors = getushort(b50->bpbSectors); 47427a0bc89SDoug Rabson pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 47527a0bc89SDoug Rabson pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 47627a0bc89SDoug Rabson pmp->pm_Heads = getushort(b50->bpbHeads); 477952a6212SJordan K. Hubbard pmp->pm_Media = b50->bpbMedia; 47827a0bc89SDoug Rabson 47901f6cfbaSYoshihiro Takahashi /* calculate the ratio of sector size to DEV_BSIZE */ 48001f6cfbaSYoshihiro Takahashi pmp->pm_BlkPerSec = pmp->pm_BytesPerSec / DEV_BSIZE; 48101f6cfbaSYoshihiro Takahashi 482952a6212SJordan K. Hubbard #ifndef __FreeBSD__ 483952a6212SJordan K. Hubbard if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) { 484952a6212SJordan K. Hubbard #endif 48527a0bc89SDoug Rabson /* XXX - We should probably check more values here */ 486952a6212SJordan K. Hubbard if (!pmp->pm_BytesPerSec || !SecPerClust 487952a6212SJordan K. Hubbard || !pmp->pm_Heads || pmp->pm_Heads > 255 488ad63a118SSatoshi Asami #ifdef PC98 489952a6212SJordan K. Hubbard || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) { 490ad63a118SSatoshi Asami #else 491952a6212SJordan K. Hubbard || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) { 492ad63a118SSatoshi Asami #endif 49327a0bc89SDoug Rabson error = EINVAL; 49427a0bc89SDoug Rabson goto error_exit; 49527a0bc89SDoug Rabson } 496952a6212SJordan K. Hubbard #ifndef __FreeBSD__ 497952a6212SJordan K. Hubbard } 498952a6212SJordan K. Hubbard #endif 49927a0bc89SDoug Rabson 50027a0bc89SDoug Rabson if (pmp->pm_Sectors == 0) { 50127a0bc89SDoug Rabson pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 50227a0bc89SDoug Rabson pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 50327a0bc89SDoug Rabson } else { 50427a0bc89SDoug Rabson pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 50527a0bc89SDoug Rabson pmp->pm_HugeSectors = pmp->pm_Sectors; 50627a0bc89SDoug Rabson } 507c681be37SDmitrij Tejblum if (pmp->pm_HugeSectors > 0xffffffff / 508c681be37SDmitrij Tejblum (pmp->pm_BytesPerSec / sizeof(struct direntry)) + 1) { 509952a6212SJordan K. Hubbard /* 510952a6212SJordan K. Hubbard * We cannot deal currently with this size of disk 511952a6212SJordan K. Hubbard * due to fileid limitations (see msdosfs_getattr and 512952a6212SJordan K. Hubbard * msdosfs_readdir) 513952a6212SJordan K. Hubbard */ 514952a6212SJordan K. Hubbard error = EINVAL; 515aaf0bb19SAndrey A. Chernov printf("mountmsdosfs(): disk too big, sorry\n"); 516952a6212SJordan K. Hubbard goto error_exit; 517952a6212SJordan K. Hubbard } 518952a6212SJordan K. Hubbard 519952a6212SJordan K. Hubbard if (pmp->pm_RootDirEnts == 0) { 520952a6212SJordan K. Hubbard if (bsp->bs710.bsBootSectSig2 != BOOTSIG2 521952a6212SJordan K. Hubbard || bsp->bs710.bsBootSectSig3 != BOOTSIG3 522952a6212SJordan K. Hubbard || pmp->pm_Sectors 523952a6212SJordan K. Hubbard || pmp->pm_FATsecs 524952a6212SJordan K. Hubbard || getushort(b710->bpbFSVers)) { 525952a6212SJordan K. Hubbard error = EINVAL; 526aaf0bb19SAndrey A. Chernov printf("mountmsdosfs(): bad FAT32 filesystem\n"); 527952a6212SJordan K. Hubbard goto error_exit; 528952a6212SJordan K. Hubbard } 529952a6212SJordan K. Hubbard pmp->pm_fatmask = FAT32_MASK; 530952a6212SJordan K. Hubbard pmp->pm_fatmult = 4; 531952a6212SJordan K. Hubbard pmp->pm_fatdiv = 1; 532952a6212SJordan K. Hubbard pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs); 533952a6212SJordan K. Hubbard if (getushort(b710->bpbExtFlags) & FATMIRROR) 534952a6212SJordan K. Hubbard pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM; 535952a6212SJordan K. Hubbard else 536952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFS_FATMIRROR; 537952a6212SJordan K. Hubbard } else 538952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFS_FATMIRROR; 539952a6212SJordan K. Hubbard 540952a6212SJordan K. Hubbard /* 541952a6212SJordan K. Hubbard * Check a few values (could do some more): 542952a6212SJordan K. Hubbard * - logical sector size: power of 2, >= block size 543952a6212SJordan K. Hubbard * - sectors per cluster: power of 2, >= 1 544952a6212SJordan K. Hubbard * - number of sectors: >= 1, <= size of partition 545952a6212SJordan K. Hubbard */ 546952a6212SJordan K. Hubbard if ( (SecPerClust == 0) 547952a6212SJordan K. Hubbard || (SecPerClust & (SecPerClust - 1)) 54801f6cfbaSYoshihiro Takahashi || (pmp->pm_BytesPerSec < DEV_BSIZE) 549952a6212SJordan K. Hubbard || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) 550952a6212SJordan K. Hubbard || (pmp->pm_HugeSectors == 0) 551952a6212SJordan K. Hubbard ) { 552952a6212SJordan K. Hubbard error = EINVAL; 553952a6212SJordan K. Hubbard goto error_exit; 554952a6212SJordan K. Hubbard } 55501f6cfbaSYoshihiro Takahashi 55601f6cfbaSYoshihiro Takahashi pmp->pm_HugeSectors *= pmp->pm_BlkPerSec; 55701f6cfbaSYoshihiro Takahashi pmp->pm_HiddenSects *= pmp->pm_BlkPerSec; /* XXX not used? */ 55801f6cfbaSYoshihiro Takahashi pmp->pm_FATsecs *= pmp->pm_BlkPerSec; 55901f6cfbaSYoshihiro Takahashi SecPerClust *= pmp->pm_BlkPerSec; 56001f6cfbaSYoshihiro Takahashi 56101f6cfbaSYoshihiro Takahashi pmp->pm_fatblk = pmp->pm_ResSectors * pmp->pm_BlkPerSec; 56201f6cfbaSYoshihiro Takahashi 563952a6212SJordan K. Hubbard if (FAT32(pmp)) { 564952a6212SJordan K. Hubbard pmp->pm_rootdirblk = getulong(b710->bpbRootClust); 565952a6212SJordan K. Hubbard pmp->pm_firstcluster = pmp->pm_fatblk 566952a6212SJordan K. Hubbard + (pmp->pm_FATs * pmp->pm_FATsecs); 56701f6cfbaSYoshihiro Takahashi pmp->pm_fsinfo = getushort(b710->bpbFSInfo) * pmp->pm_BlkPerSec; 568952a6212SJordan K. Hubbard } else { 56927a0bc89SDoug Rabson pmp->pm_rootdirblk = pmp->pm_fatblk + 57027a0bc89SDoug Rabson (pmp->pm_FATs * pmp->pm_FATsecs); 571952a6212SJordan K. Hubbard pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry) 57201f6cfbaSYoshihiro Takahashi + DEV_BSIZE - 1) 57301f6cfbaSYoshihiro Takahashi / DEV_BSIZE; /* in blocks */ 57427a0bc89SDoug Rabson pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 575952a6212SJordan K. Hubbard } 576952a6212SJordan K. Hubbard 577499d3ffaSBoris Popov pmp->pm_maxcluster = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 578499d3ffaSBoris Popov SecPerClust + 1; 57901f6cfbaSYoshihiro Takahashi pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE; /* XXX not used? */ 580952a6212SJordan K. Hubbard 581952a6212SJordan K. Hubbard #ifndef __FreeBSD__ 582952a6212SJordan K. Hubbard if (argp->flags & MSDOSFSMNT_GEMDOSFS) { 583499d3ffaSBoris Popov if ((pmp->pm_maxcluster <= (0xff0 - 2)) 584952a6212SJordan K. Hubbard && ((dtype == DTYPE_FLOPPY) || ((dtype == DTYPE_VNODE) 585952a6212SJordan K. Hubbard && ((pmp->pm_Heads == 1) || (pmp->pm_Heads == 2)))) 586952a6212SJordan K. Hubbard ) { 587952a6212SJordan K. Hubbard pmp->pm_fatmask = FAT12_MASK; 588952a6212SJordan K. Hubbard pmp->pm_fatmult = 3; 589952a6212SJordan K. Hubbard pmp->pm_fatdiv = 2; 590952a6212SJordan K. Hubbard } else { 591952a6212SJordan K. Hubbard pmp->pm_fatmask = FAT16_MASK; 592952a6212SJordan K. Hubbard pmp->pm_fatmult = 2; 593952a6212SJordan K. Hubbard pmp->pm_fatdiv = 1; 594952a6212SJordan K. Hubbard } 595952a6212SJordan K. Hubbard } else 596952a6212SJordan K. Hubbard #endif 597952a6212SJordan K. Hubbard if (pmp->pm_fatmask == 0) { 598952a6212SJordan K. Hubbard if (pmp->pm_maxcluster 599952a6212SJordan K. Hubbard <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) { 60027a0bc89SDoug Rabson /* 601952a6212SJordan K. Hubbard * This will usually be a floppy disk. This size makes 602952a6212SJordan K. Hubbard * sure that one fat entry will not be split across 603952a6212SJordan K. Hubbard * multiple blocks. 60427a0bc89SDoug Rabson */ 605952a6212SJordan K. Hubbard pmp->pm_fatmask = FAT12_MASK; 606952a6212SJordan K. Hubbard pmp->pm_fatmult = 3; 607952a6212SJordan K. Hubbard pmp->pm_fatdiv = 2; 608952a6212SJordan K. Hubbard } else { 609952a6212SJordan K. Hubbard pmp->pm_fatmask = FAT16_MASK; 610952a6212SJordan K. Hubbard pmp->pm_fatmult = 2; 611952a6212SJordan K. Hubbard pmp->pm_fatdiv = 1; 612952a6212SJordan K. Hubbard } 613952a6212SJordan K. Hubbard } 614499d3ffaSBoris Popov 615499d3ffaSBoris Popov clusters = (pmp->pm_fatsize / pmp->pm_fatmult) * pmp->pm_fatdiv; 616499d3ffaSBoris Popov if (pmp->pm_maxcluster >= clusters) { 617499d3ffaSBoris Popov printf("Warning: number of clusters (%ld) exceeds FAT " 618499d3ffaSBoris Popov "capacity (%ld)\n", pmp->pm_maxcluster + 1, clusters); 619499d3ffaSBoris Popov pmp->pm_maxcluster = clusters - 1; 620499d3ffaSBoris Popov } 621499d3ffaSBoris Popov 622499d3ffaSBoris Popov 623952a6212SJordan K. Hubbard if (FAT12(pmp)) 62427a0bc89SDoug Rabson pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; 62527a0bc89SDoug Rabson else 6267c58e473SMatthew Dillon pmp->pm_fatblocksize = MSDOSFS_DFLTBSIZE; 627952a6212SJordan K. Hubbard 62801f6cfbaSYoshihiro Takahashi pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE; 62901f6cfbaSYoshihiro Takahashi pmp->pm_bnshift = ffs(DEV_BSIZE) - 1; 63027a0bc89SDoug Rabson 63127a0bc89SDoug Rabson /* 63227a0bc89SDoug Rabson * Compute mask and shift value for isolating cluster relative byte 63327a0bc89SDoug Rabson * offsets and cluster numbers from a file offset. 63427a0bc89SDoug Rabson */ 63501f6cfbaSYoshihiro Takahashi pmp->pm_bpcluster = SecPerClust * DEV_BSIZE; 636952a6212SJordan K. Hubbard pmp->pm_crbomask = pmp->pm_bpcluster - 1; 637952a6212SJordan K. Hubbard pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1; 63827a0bc89SDoug Rabson 639952a6212SJordan K. Hubbard /* 640952a6212SJordan K. Hubbard * Check for valid cluster size 641952a6212SJordan K. Hubbard * must be a power of 2 642952a6212SJordan K. Hubbard */ 643952a6212SJordan K. Hubbard if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) { 644952a6212SJordan K. Hubbard error = EINVAL; 645952a6212SJordan K. Hubbard goto error_exit; 646ad63a118SSatoshi Asami } 64727a0bc89SDoug Rabson 64827a0bc89SDoug Rabson /* 64927a0bc89SDoug Rabson * Release the bootsector buffer. 65027a0bc89SDoug Rabson */ 651952a6212SJordan K. Hubbard brelse(bp); 652952a6212SJordan K. Hubbard bp = NULL; 653952a6212SJordan K. Hubbard 654952a6212SJordan K. Hubbard /* 655952a6212SJordan K. Hubbard * Check FSInfo. 656952a6212SJordan K. Hubbard */ 657952a6212SJordan K. Hubbard if (pmp->pm_fsinfo) { 658952a6212SJordan K. Hubbard struct fsinfo *fp; 659952a6212SJordan K. Hubbard 66001f6cfbaSYoshihiro Takahashi if ((error = bread(devvp, pmp->pm_fsinfo, fsi_size(pmp), 66101f6cfbaSYoshihiro Takahashi NOCRED, &bp)) != 0) 662952a6212SJordan K. Hubbard goto error_exit; 663952a6212SJordan K. Hubbard fp = (struct fsinfo *)bp->b_data; 664952a6212SJordan K. Hubbard if (!bcmp(fp->fsisig1, "RRaA", 4) 665952a6212SJordan K. Hubbard && !bcmp(fp->fsisig2, "rrAa", 4) 666952a6212SJordan K. Hubbard && !bcmp(fp->fsisig3, "\0\0\125\252", 4) 667952a6212SJordan K. Hubbard && !bcmp(fp->fsisig4, "\0\0\125\252", 4)) 668952a6212SJordan K. Hubbard pmp->pm_nxtfree = getulong(fp->fsinxtfree); 669952a6212SJordan K. Hubbard else 670952a6212SJordan K. Hubbard pmp->pm_fsinfo = 0; 671952a6212SJordan K. Hubbard brelse(bp); 672952a6212SJordan K. Hubbard bp = NULL; 673952a6212SJordan K. Hubbard } 674952a6212SJordan K. Hubbard 675952a6212SJordan K. Hubbard /* 676952a6212SJordan K. Hubbard * Check and validate (or perhaps invalidate?) the fsinfo structure? XXX 677952a6212SJordan K. Hubbard */ 67827a0bc89SDoug Rabson 67927a0bc89SDoug Rabson /* 68027a0bc89SDoug Rabson * Allocate memory for the bitmap of allocated clusters, and then 68127a0bc89SDoug Rabson * fill it in. 68227a0bc89SDoug Rabson */ 68327a0bc89SDoug Rabson pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS - 1) 68427a0bc89SDoug Rabson / N_INUSEBITS) 68527a0bc89SDoug Rabson * sizeof(*pmp->pm_inusemap), 68627a0bc89SDoug Rabson M_MSDOSFSFAT, M_WAITOK); 68727a0bc89SDoug Rabson 68827a0bc89SDoug Rabson /* 68927a0bc89SDoug Rabson * fillinusemap() needs pm_devvp. 69027a0bc89SDoug Rabson */ 69127a0bc89SDoug Rabson pmp->pm_dev = dev; 69227a0bc89SDoug Rabson pmp->pm_devvp = devvp; 69327a0bc89SDoug Rabson 69427a0bc89SDoug Rabson /* 69527a0bc89SDoug Rabson * Have the inuse map filled in. 69627a0bc89SDoug Rabson */ 697952a6212SJordan K. Hubbard if ((error = fillinusemap(pmp)) != 0) 69827a0bc89SDoug Rabson goto error_exit; 69927a0bc89SDoug Rabson 70027a0bc89SDoug Rabson /* 70127a0bc89SDoug Rabson * If they want fat updates to be synchronous then let them suffer 70227a0bc89SDoug Rabson * the performance degradation in exchange for the on disk copy of 70327a0bc89SDoug Rabson * the fat being correct just about all the time. I suppose this 70427a0bc89SDoug Rabson * would be a good thing to turn on if the kernel is still flakey. 70527a0bc89SDoug Rabson */ 706952a6212SJordan K. Hubbard if (mp->mnt_flag & MNT_SYNCHRONOUS) 707952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_WAITONFAT; 70827a0bc89SDoug Rabson 70927a0bc89SDoug Rabson /* 71027a0bc89SDoug Rabson * Finish up. 71127a0bc89SDoug Rabson */ 712952a6212SJordan K. Hubbard if (ronly) 713952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_RONLY; 714952a6212SJordan K. Hubbard else 71527a0bc89SDoug Rabson pmp->pm_fmod = 1; 71627a0bc89SDoug Rabson mp->mnt_data = (qaddr_t) pmp; 717939cb752SBruce Evans mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); 718af3f60d5SBruce Evans mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 719cc9d8990SPeter Wemm mp->mnt_flag |= MNT_LOCAL; 7207eb9fca5SEivind Eklund devvp->v_rdev->si_mountpoint = mp; 72127a0bc89SDoug Rabson 72227a0bc89SDoug Rabson return 0; 72327a0bc89SDoug Rabson 724952a6212SJordan K. Hubbard error_exit: 725952a6212SJordan K. Hubbard if (bp) 726952a6212SJordan K. Hubbard brelse(bp); 727952a6212SJordan K. Hubbard (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE, NOCRED, p); 72827a0bc89SDoug Rabson if (pmp) { 72927a0bc89SDoug Rabson if (pmp->pm_inusemap) 730952a6212SJordan K. Hubbard free(pmp->pm_inusemap, M_MSDOSFSFAT); 731952a6212SJordan K. Hubbard free(pmp, M_MSDOSFSMNT); 73227a0bc89SDoug Rabson mp->mnt_data = (qaddr_t)0; 73327a0bc89SDoug Rabson } 734952a6212SJordan K. Hubbard return (error); 73527a0bc89SDoug Rabson } 73627a0bc89SDoug Rabson 73727a0bc89SDoug Rabson /* 73827a0bc89SDoug Rabson * Unmount the filesystem described by mp. 73927a0bc89SDoug Rabson */ 7407fefffeeSPoul-Henning Kamp static int 74127a0bc89SDoug Rabson msdosfs_unmount(mp, mntflags, p) 74227a0bc89SDoug Rabson struct mount *mp; 74327a0bc89SDoug Rabson int mntflags; 74427a0bc89SDoug Rabson struct proc *p; 74527a0bc89SDoug Rabson { 746952a6212SJordan K. Hubbard struct msdosfsmount *pmp; 747952a6212SJordan K. Hubbard int error, flags; 74827a0bc89SDoug Rabson 749952a6212SJordan K. Hubbard flags = 0; 750952a6212SJordan K. Hubbard if (mntflags & MNT_FORCE) 75127a0bc89SDoug Rabson flags |= FORCECLOSE; 7520864ef1eSIan Dowse error = vflush(mp, 0, flags); 753c3c6d51eSPoul-Henning Kamp if (error) 75427a0bc89SDoug Rabson return error; 755952a6212SJordan K. Hubbard pmp = VFSTOMSDOSFS(mp); 7567eb9fca5SEivind Eklund pmp->pm_devvp->v_rdev->si_mountpoint = NULL; 757952a6212SJordan K. Hubbard #ifdef MSDOSFS_DEBUG 758952a6212SJordan K. Hubbard { 759952a6212SJordan K. Hubbard struct vnode *vp = pmp->pm_devvp; 760952a6212SJordan K. Hubbard 761952a6212SJordan K. Hubbard printf("msdosfs_umount(): just before calling VOP_CLOSE()\n"); 762952a6212SJordan K. Hubbard printf("flag %08lx, usecount %d, writecount %d, holdcnt %ld\n", 763952a6212SJordan K. Hubbard vp->v_flag, vp->v_usecount, vp->v_writecount, vp->v_holdcnt); 76467ddfcafSMatthew Dillon printf("id %lu, mount %p, op %p\n", 76567ddfcafSMatthew Dillon vp->v_id, vp->v_mount, vp->v_op); 766952a6212SJordan K. Hubbard printf("freef %p, freeb %p, mount %p\n", 767fc2ffbe6SPoul-Henning Kamp TAILQ_NEXT(vp, v_freelist), vp->v_freelist.tqe_prev, 768952a6212SJordan K. Hubbard vp->v_mount); 769952a6212SJordan K. Hubbard printf("cleanblkhd %p, dirtyblkhd %p, numoutput %ld, type %d\n", 77040c8cfe5SPeter Wemm TAILQ_FIRST(&vp->v_cleanblkhd), 77140c8cfe5SPeter Wemm TAILQ_FIRST(&vp->v_dirtyblkhd), 772952a6212SJordan K. Hubbard vp->v_numoutput, vp->v_type); 773952a6212SJordan K. Hubbard printf("union %p, tag %d, data[0] %08x, data[1] %08x\n", 774952a6212SJordan K. Hubbard vp->v_socket, vp->v_tag, 775952a6212SJordan K. Hubbard ((u_int *)vp->v_data)[0], 776952a6212SJordan K. Hubbard ((u_int *)vp->v_data)[1]); 777952a6212SJordan K. Hubbard } 778952a6212SJordan K. Hubbard #endif 779b1897c19SJulian Elischer error = VOP_CLOSE(pmp->pm_devvp, 780b1897c19SJulian Elischer (pmp->pm_flags&MSDOSFSMNT_RONLY) ? FREAD : FREAD | FWRITE, 78127a0bc89SDoug Rabson NOCRED, p); 78227a0bc89SDoug Rabson vrele(pmp->pm_devvp); 783952a6212SJordan K. Hubbard free(pmp->pm_inusemap, M_MSDOSFSFAT); 784952a6212SJordan K. Hubbard free(pmp, M_MSDOSFSMNT); 78527a0bc89SDoug Rabson mp->mnt_data = (qaddr_t)0; 786cc9d8990SPeter Wemm mp->mnt_flag &= ~MNT_LOCAL; 787952a6212SJordan K. Hubbard return (error); 78827a0bc89SDoug Rabson } 78927a0bc89SDoug Rabson 7907fefffeeSPoul-Henning Kamp static int 79127a0bc89SDoug Rabson msdosfs_root(mp, vpp) 79227a0bc89SDoug Rabson struct mount *mp; 79327a0bc89SDoug Rabson struct vnode **vpp; 79427a0bc89SDoug Rabson { 795952a6212SJordan K. Hubbard struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 79627a0bc89SDoug Rabson struct denode *ndep; 79727a0bc89SDoug Rabson int error; 79827a0bc89SDoug Rabson 79927a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 800952a6212SJordan K. Hubbard printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp); 80127a0bc89SDoug Rabson #endif 802952a6212SJordan K. Hubbard error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep); 803952a6212SJordan K. Hubbard if (error) 804952a6212SJordan K. Hubbard return (error); 80527a0bc89SDoug Rabson *vpp = DETOV(ndep); 806952a6212SJordan K. Hubbard return (0); 80727a0bc89SDoug Rabson } 80827a0bc89SDoug Rabson 8097fefffeeSPoul-Henning Kamp static int 81027a0bc89SDoug Rabson msdosfs_statfs(mp, sbp, p) 81127a0bc89SDoug Rabson struct mount *mp; 81227a0bc89SDoug Rabson struct statfs *sbp; 81327a0bc89SDoug Rabson struct proc *p; 81427a0bc89SDoug Rabson { 815952a6212SJordan K. Hubbard struct msdosfsmount *pmp; 81627a0bc89SDoug Rabson 817952a6212SJordan K. Hubbard pmp = VFSTOMSDOSFS(mp); 81827a0bc89SDoug Rabson sbp->f_bsize = pmp->pm_bpcluster; 81927a0bc89SDoug Rabson sbp->f_iosize = pmp->pm_bpcluster; 820499d3ffaSBoris Popov sbp->f_blocks = pmp->pm_maxcluster + 1; 82127a0bc89SDoug Rabson sbp->f_bfree = pmp->pm_freeclustercount; 82227a0bc89SDoug Rabson sbp->f_bavail = pmp->pm_freeclustercount; 82327a0bc89SDoug Rabson sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ 82427a0bc89SDoug Rabson sbp->f_ffree = 0; /* what to put in here? */ 82527a0bc89SDoug Rabson if (sbp != &mp->mnt_stat) { 826af3f60d5SBruce Evans sbp->f_type = mp->mnt_vfc->vfc_typenum; 827952a6212SJordan K. Hubbard bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 828952a6212SJordan K. Hubbard bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 82927a0bc89SDoug Rabson } 830952a6212SJordan K. Hubbard strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN); 831952a6212SJordan K. Hubbard return (0); 83227a0bc89SDoug Rabson } 83327a0bc89SDoug Rabson 8347fefffeeSPoul-Henning Kamp static int 83527a0bc89SDoug Rabson msdosfs_sync(mp, waitfor, cred, p) 83627a0bc89SDoug Rabson struct mount *mp; 83727a0bc89SDoug Rabson int waitfor; 83827a0bc89SDoug Rabson struct ucred *cred; 83927a0bc89SDoug Rabson struct proc *p; 84027a0bc89SDoug Rabson { 841952a6212SJordan K. Hubbard struct vnode *vp, *nvp; 84227a0bc89SDoug Rabson struct denode *dep; 843952a6212SJordan K. Hubbard struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 844952a6212SJordan K. Hubbard int error, allerror = 0; 84527a0bc89SDoug Rabson 84627a0bc89SDoug Rabson /* 84727a0bc89SDoug Rabson * If we ever switch to not updating all of the fats all the time, 84827a0bc89SDoug Rabson * this would be the place to update them from the first one. 84927a0bc89SDoug Rabson */ 850dfd5dee1SPeter Wemm if (pmp->pm_fmod != 0) { 851952a6212SJordan K. Hubbard if (pmp->pm_flags & MSDOSFSMNT_RONLY) 85227a0bc89SDoug Rabson panic("msdosfs_sync: rofs mod"); 85327a0bc89SDoug Rabson else { 85427a0bc89SDoug Rabson /* update fats here */ 85527a0bc89SDoug Rabson } 856dfd5dee1SPeter Wemm } 85727a0bc89SDoug Rabson /* 858952a6212SJordan K. Hubbard * Write back each (modified) denode. 85927a0bc89SDoug Rabson */ 8609ed346baSBosko Milekic mtx_lock(&mntvnode_mtx); 86127a0bc89SDoug Rabson loop: 86249851cc7SPoul-Henning Kamp for (vp = LIST_FIRST(&mp->mnt_vnodelist); vp != NULL; vp = nvp) { 863952a6212SJordan K. Hubbard /* 864952a6212SJordan K. Hubbard * If the vnode that we are about to sync is no longer 865c681be37SDmitrij Tejblum * associated with this mount point, start over. 866952a6212SJordan K. Hubbard */ 867952a6212SJordan K. Hubbard if (vp->v_mount != mp) 86827a0bc89SDoug Rabson goto loop; 869952a6212SJordan K. Hubbard 8709ed346baSBosko Milekic mtx_lock(&vp->v_interlock); 87149851cc7SPoul-Henning Kamp nvp = LIST_NEXT(vp, v_mntvnodes); 87227a0bc89SDoug Rabson dep = VTODE(vp); 873c681be37SDmitrij Tejblum if (vp->v_type == VNON || 874831a80b0SMatthew Dillon ((dep->de_flag & 875c681be37SDmitrij Tejblum (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0 && 876831a80b0SMatthew Dillon (TAILQ_EMPTY(&vp->v_dirtyblkhd) || waitfor == MNT_LAZY))) { 8779ed346baSBosko Milekic mtx_unlock(&vp->v_interlock); 87827a0bc89SDoug Rabson continue; 879af3f60d5SBruce Evans } 8809ed346baSBosko Milekic mtx_unlock(&mntvnode_mtx); 881af3f60d5SBruce Evans error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); 882af3f60d5SBruce Evans if (error) { 8839ed346baSBosko Milekic mtx_lock(&mntvnode_mtx); 884af3f60d5SBruce Evans if (error == ENOENT) 88527a0bc89SDoug Rabson goto loop; 886af3f60d5SBruce Evans continue; 887af3f60d5SBruce Evans } 888c3c6d51eSPoul-Henning Kamp error = VOP_FSYNC(vp, cred, waitfor, p); 889c3c6d51eSPoul-Henning Kamp if (error) 89027a0bc89SDoug Rabson allerror = error; 891af3f60d5SBruce Evans VOP_UNLOCK(vp, 0, p); 892c681be37SDmitrij Tejblum vrele(vp); 8939ed346baSBosko Milekic mtx_lock(&mntvnode_mtx); 89427a0bc89SDoug Rabson } 8959ed346baSBosko Milekic mtx_unlock(&mntvnode_mtx); 89627a0bc89SDoug Rabson 89727a0bc89SDoug Rabson /* 89827a0bc89SDoug Rabson * Flush filesystem control info. 89927a0bc89SDoug Rabson */ 900c681be37SDmitrij Tejblum if (waitfor != MNT_LAZY) { 901c681be37SDmitrij Tejblum vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY, p); 902c3c6d51eSPoul-Henning Kamp error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p); 903c3c6d51eSPoul-Henning Kamp if (error) 90427a0bc89SDoug Rabson allerror = error; 905c681be37SDmitrij Tejblum VOP_UNLOCK(pmp->pm_devvp, 0, p); 906c681be37SDmitrij Tejblum } 907952a6212SJordan K. Hubbard return (allerror); 90827a0bc89SDoug Rabson } 90927a0bc89SDoug Rabson 9107fefffeeSPoul-Henning Kamp static int 911c24fda81SAlfred Perlstein msdosfs_fhtovp(mp, fhp, vpp) 91227a0bc89SDoug Rabson struct mount *mp; 91327a0bc89SDoug Rabson struct fid *fhp; 91427a0bc89SDoug Rabson struct vnode **vpp; 91527a0bc89SDoug Rabson { 916952a6212SJordan K. Hubbard struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 91727a0bc89SDoug Rabson struct defid *defhp = (struct defid *) fhp; 91827a0bc89SDoug Rabson struct denode *dep; 91927a0bc89SDoug Rabson int error; 92027a0bc89SDoug Rabson 921952a6212SJordan K. Hubbard error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep); 92227a0bc89SDoug Rabson if (error) { 92327a0bc89SDoug Rabson *vpp = NULLVP; 924952a6212SJordan K. Hubbard return (error); 92527a0bc89SDoug Rabson } 92627a0bc89SDoug Rabson *vpp = DETOV(dep); 927c24fda81SAlfred Perlstein return (0); 928c24fda81SAlfred Perlstein } 929c24fda81SAlfred Perlstein 930c24fda81SAlfred Perlstein static int 93127a0bc89SDoug Rabson msdosfs_vptofh(vp, fhp) 93227a0bc89SDoug Rabson struct vnode *vp; 93327a0bc89SDoug Rabson struct fid *fhp; 93427a0bc89SDoug Rabson { 935952a6212SJordan K. Hubbard struct denode *dep; 936952a6212SJordan K. Hubbard struct defid *defhp; 93727a0bc89SDoug Rabson 938952a6212SJordan K. Hubbard dep = VTODE(vp); 939952a6212SJordan K. Hubbard defhp = (struct defid *)fhp; 94027a0bc89SDoug Rabson defhp->defid_len = sizeof(struct defid); 94127a0bc89SDoug Rabson defhp->defid_dirclust = dep->de_dirclust; 94227a0bc89SDoug Rabson defhp->defid_dirofs = dep->de_diroffset; 943952a6212SJordan K. Hubbard /* defhp->defid_gen = dep->de_gen; */ 944952a6212SJordan K. Hubbard return (0); 94527a0bc89SDoug Rabson } 94627a0bc89SDoug Rabson 94730ffadf3SPoul-Henning Kamp static struct vfsops msdosfs_vfsops = { 94827a0bc89SDoug Rabson msdosfs_mount, 9495a5fccc8SAlfred Perlstein vfs_stdstart, 95027a0bc89SDoug Rabson msdosfs_unmount, 95127a0bc89SDoug Rabson msdosfs_root, 9525a5fccc8SAlfred Perlstein vfs_stdquotactl, 95327a0bc89SDoug Rabson msdosfs_statfs, 95427a0bc89SDoug Rabson msdosfs_sync, 9555a5fccc8SAlfred Perlstein vfs_stdvget, 95627a0bc89SDoug Rabson msdosfs_fhtovp, 957a13234bbSPoul-Henning Kamp vfs_stdcheckexp, 95827a0bc89SDoug Rabson msdosfs_vptofh, 95991f37dcbSRobert Watson msdosfs_init, 960432a8400SBoris Popov msdosfs_uninit, 96191f37dcbSRobert Watson vfs_stdextattrctl, 96227a0bc89SDoug Rabson }; 963c901836cSGarrett Wollman 9648994ca3cSBruce Evans VFS_SET(msdosfs_vfsops, msdos, 0); 965