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 */ 64152ffafeSBruce 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 73152ffafeSBruce Evans #define MSDOSFS_DFLTBSIZE 4096 74152ffafeSBruce Evans 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 8911caded3SAlfred Perlstein static int update_mp(struct mount *mp, struct msdosfs_args *argp); 9011caded3SAlfred Perlstein static int mountmsdosfs(struct vnode *devvp, struct mount *mp, 9111caded3SAlfred Perlstein struct thread *td, struct msdosfs_args *argp); 929bf1a756SPoul-Henning Kamp static vfs_fhtovp_t msdosfs_fhtovp; 939bf1a756SPoul-Henning Kamp static vfs_mount_t msdosfs_mount; 949bf1a756SPoul-Henning Kamp static vfs_root_t msdosfs_root; 959bf1a756SPoul-Henning Kamp static vfs_statfs_t msdosfs_statfs; 969bf1a756SPoul-Henning Kamp static vfs_sync_t msdosfs_sync; 979bf1a756SPoul-Henning Kamp static vfs_unmount_t msdosfs_unmount; 989bf1a756SPoul-Henning Kamp static vfs_vptofh_t msdosfs_vptofh; 99af482601SBruce Evans 100952a6212SJordan K. Hubbard static int 101952a6212SJordan K. Hubbard update_mp(mp, argp) 102952a6212SJordan K. Hubbard struct mount *mp; 103952a6212SJordan K. Hubbard struct msdosfs_args *argp; 104952a6212SJordan K. Hubbard { 105952a6212SJordan K. Hubbard struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 106952a6212SJordan K. Hubbard int error; 107952a6212SJordan K. Hubbard 108952a6212SJordan K. Hubbard pmp->pm_gid = argp->gid; 109952a6212SJordan K. Hubbard pmp->pm_uid = argp->uid; 110952a6212SJordan K. Hubbard pmp->pm_mask = argp->mask & ALLPERMS; 111952a6212SJordan K. Hubbard pmp->pm_flags |= argp->flags & MSDOSFSMNT_MNTOPT; 1127391f611SAndrey A. Chernov if (pmp->pm_flags & MSDOSFSMNT_U2WTABLE) { 11313df76f2SAndrey A. Chernov bcopy(argp->u2w, pmp->pm_u2w, sizeof(pmp->pm_u2w)); 1147391f611SAndrey A. Chernov bcopy(argp->d2u, pmp->pm_d2u, sizeof(pmp->pm_d2u)); 1157391f611SAndrey A. Chernov bcopy(argp->u2d, pmp->pm_u2d, sizeof(pmp->pm_u2d)); 1167391f611SAndrey A. Chernov } 1177391f611SAndrey A. Chernov if (pmp->pm_flags & MSDOSFSMNT_ULTABLE) { 11864fb806cSAndrey A. Chernov bcopy(argp->ul, pmp->pm_ul, sizeof(pmp->pm_ul)); 1197391f611SAndrey A. Chernov bcopy(argp->lu, pmp->pm_lu, sizeof(pmp->pm_lu)); 1207391f611SAndrey A. Chernov } 121952a6212SJordan K. Hubbard 122952a6212SJordan K. Hubbard if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 123952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 124952a6212SJordan K. Hubbard else if (!(pmp->pm_flags & 125952a6212SJordan K. Hubbard (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) { 126952a6212SJordan K. Hubbard struct vnode *rootvp; 127952a6212SJordan K. Hubbard 128952a6212SJordan K. Hubbard /* 129952a6212SJordan K. Hubbard * Try to divine whether to support Win'95 long filenames 130952a6212SJordan K. Hubbard */ 131952a6212SJordan K. Hubbard if (FAT32(pmp)) 132952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_LONGNAME; 133952a6212SJordan K. Hubbard else { 134952a6212SJordan K. Hubbard if ((error = msdosfs_root(mp, &rootvp)) != 0) 135952a6212SJordan K. Hubbard return error; 136952a6212SJordan K. Hubbard pmp->pm_flags |= findwin95(VTODE(rootvp)) 137952a6212SJordan K. Hubbard ? MSDOSFSMNT_LONGNAME 138952a6212SJordan K. Hubbard : MSDOSFSMNT_SHORTNAME; 139952a6212SJordan K. Hubbard vput(rootvp); 140952a6212SJordan K. Hubbard } 141952a6212SJordan K. Hubbard } 142952a6212SJordan K. Hubbard return 0; 143952a6212SJordan K. Hubbard } 144952a6212SJordan K. Hubbard 14527a0bc89SDoug Rabson /* 14627a0bc89SDoug Rabson * mp - path - addr in user space of mount point (ie /usr or whatever) 14727a0bc89SDoug Rabson * data - addr in user space of mount params including the name of the block 14827a0bc89SDoug Rabson * special file to treat as a filesystem. 14927a0bc89SDoug Rabson */ 1507fefffeeSPoul-Henning Kamp static int 151b40ce416SJulian Elischer msdosfs_mount(mp, path, data, ndp, td) 15227a0bc89SDoug Rabson struct mount *mp; 15327a0bc89SDoug Rabson char *path; 15427a0bc89SDoug Rabson caddr_t data; 15527a0bc89SDoug Rabson struct nameidata *ndp; 156b40ce416SJulian Elischer struct thread *td; 15727a0bc89SDoug Rabson { 15827a0bc89SDoug Rabson struct vnode *devvp; /* vnode for blk device to mount */ 15927a0bc89SDoug Rabson struct msdosfs_args args; /* will hold data from mount request */ 160952a6212SJordan K. Hubbard /* msdosfs specific mount control block */ 161952a6212SJordan K. Hubbard struct msdosfsmount *pmp = NULL; 162952a6212SJordan K. Hubbard size_t size; 16327a0bc89SDoug Rabson int error, flags; 164952a6212SJordan K. Hubbard mode_t accessmode; 16527a0bc89SDoug Rabson 166c3c6d51eSPoul-Henning Kamp error = copyin(data, (caddr_t)&args, sizeof(struct msdosfs_args)); 167c3c6d51eSPoul-Henning Kamp if (error) 168952a6212SJordan K. Hubbard return (error); 169206faeeeSDmitrij Tejblum if (args.magic != MSDOSFS_ARGSMAGIC) 170952a6212SJordan K. Hubbard args.flags = 0; 17127a0bc89SDoug Rabson /* 172952a6212SJordan K. Hubbard * If updating, check whether changing from read-only to 173952a6212SJordan K. Hubbard * read/write; if there is no device name, that's all we do. 17427a0bc89SDoug Rabson */ 17527a0bc89SDoug Rabson if (mp->mnt_flag & MNT_UPDATE) { 176952a6212SJordan K. Hubbard pmp = VFSTOMSDOSFS(mp); 17727a0bc89SDoug Rabson error = 0; 178952a6212SJordan K. Hubbard if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_flag & MNT_RDONLY)) { 17927a0bc89SDoug Rabson flags = WRITECLOSE; 18027a0bc89SDoug Rabson if (mp->mnt_flag & MNT_FORCE) 18127a0bc89SDoug Rabson flags |= FORCECLOSE; 1820864ef1eSIan Dowse error = vflush(mp, 0, flags); 18327a0bc89SDoug Rabson } 18427a0bc89SDoug Rabson if (!error && (mp->mnt_flag & MNT_RELOAD)) 18527a0bc89SDoug Rabson /* not yet implemented */ 186952a6212SJordan K. Hubbard error = EOPNOTSUPP; 18727a0bc89SDoug Rabson if (error) 188952a6212SJordan K. Hubbard return (error); 189952a6212SJordan K. Hubbard if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_kern_flag & MNTK_WANTRDWR)) { 190952a6212SJordan K. Hubbard /* 191952a6212SJordan K. Hubbard * If upgrade to read-write by non-root, then verify 192952a6212SJordan K. Hubbard * that user has necessary permissions on the device. 193952a6212SJordan K. Hubbard */ 19444731cabSJohn Baldwin if (suser(td)) { 195952a6212SJordan K. Hubbard devvp = pmp->pm_devvp; 196b40ce416SJulian Elischer vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); 197952a6212SJordan K. Hubbard error = VOP_ACCESS(devvp, VREAD | VWRITE, 198a854ed98SJohn Baldwin td->td_ucred, td); 199952a6212SJordan K. Hubbard if (error) { 200b40ce416SJulian Elischer VOP_UNLOCK(devvp, 0, td); 201952a6212SJordan K. Hubbard return (error); 202952a6212SJordan K. Hubbard } 203b40ce416SJulian Elischer VOP_UNLOCK(devvp, 0, td); 204952a6212SJordan K. Hubbard } 205952a6212SJordan K. Hubbard pmp->pm_flags &= ~MSDOSFSMNT_RONLY; 206952a6212SJordan K. Hubbard } 20727a0bc89SDoug Rabson if (args.fspec == 0) { 208952a6212SJordan K. Hubbard #ifdef __notyet__ /* doesn't work correctly with current mountd XXX */ 209952a6212SJordan K. Hubbard if (args.flags & MSDOSFSMNT_MNTOPT) { 210952a6212SJordan K. Hubbard pmp->pm_flags &= ~MSDOSFSMNT_MNTOPT; 211952a6212SJordan K. Hubbard pmp->pm_flags |= args.flags & MSDOSFSMNT_MNTOPT; 212952a6212SJordan K. Hubbard if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 213952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 214952a6212SJordan K. Hubbard } 215952a6212SJordan K. Hubbard #endif 21627a0bc89SDoug Rabson /* 21727a0bc89SDoug Rabson * Process export requests. 21827a0bc89SDoug Rabson */ 219a13234bbSPoul-Henning Kamp return (vfs_export(mp, &args.export)); 22027a0bc89SDoug Rabson } 221952a6212SJordan K. Hubbard } 22227a0bc89SDoug Rabson /* 223952a6212SJordan K. Hubbard * Not an update, or updating the name: look up the name 224952a6212SJordan K. Hubbard * and verify that it refers to a sensible block device. 22527a0bc89SDoug Rabson */ 226b40ce416SJulian Elischer NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, td); 22727a0bc89SDoug Rabson error = namei(ndp); 228952a6212SJordan K. Hubbard if (error) 229952a6212SJordan K. Hubbard return (error); 23027a0bc89SDoug Rabson devvp = ndp->ni_vp; 231762e6b85SEivind Eklund NDFREE(ndp, NDF_ONLY_PNBUF); 232952a6212SJordan K. Hubbard 233ba4ad1fcSPoul-Henning Kamp if (!vn_isdisk(devvp, &error)) { 23427a0bc89SDoug Rabson vrele(devvp); 235ba4ad1fcSPoul-Henning Kamp return (error); 23627a0bc89SDoug Rabson } 23727a0bc89SDoug Rabson /* 238952a6212SJordan K. Hubbard * If mount by non-root, then verify that user has necessary 239952a6212SJordan K. Hubbard * permissions on the device. 24027a0bc89SDoug Rabson */ 24144731cabSJohn Baldwin if (suser(td)) { 242952a6212SJordan K. Hubbard accessmode = VREAD; 243952a6212SJordan K. Hubbard if ((mp->mnt_flag & MNT_RDONLY) == 0) 244952a6212SJordan K. Hubbard accessmode |= VWRITE; 245b40ce416SJulian Elischer vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); 246a854ed98SJohn Baldwin error = VOP_ACCESS(devvp, accessmode, td->td_ucred, td); 247952a6212SJordan K. Hubbard if (error) { 248952a6212SJordan K. Hubbard vput(devvp); 249952a6212SJordan K. Hubbard return (error); 250952a6212SJordan K. Hubbard } 251b40ce416SJulian Elischer VOP_UNLOCK(devvp, 0, td); 252952a6212SJordan K. Hubbard } 253952a6212SJordan K. Hubbard if ((mp->mnt_flag & MNT_UPDATE) == 0) { 254b40ce416SJulian Elischer error = mountmsdosfs(devvp, mp, td, &args); 255952a6212SJordan K. Hubbard #ifdef MSDOSFS_DEBUG /* only needed for the printf below */ 256952a6212SJordan K. Hubbard pmp = VFSTOMSDOSFS(mp); 257952a6212SJordan K. Hubbard #endif 258952a6212SJordan K. Hubbard } else { 25927a0bc89SDoug Rabson if (devvp != pmp->pm_devvp) 260952a6212SJordan K. Hubbard error = EINVAL; /* XXX needs translation */ 26127a0bc89SDoug Rabson else 26227a0bc89SDoug Rabson vrele(devvp); 26327a0bc89SDoug Rabson } 26427a0bc89SDoug Rabson if (error) { 26527a0bc89SDoug Rabson vrele(devvp); 266952a6212SJordan K. Hubbard return (error); 267952a6212SJordan K. Hubbard } 268952a6212SJordan K. Hubbard 269952a6212SJordan K. Hubbard error = update_mp(mp, &args); 270952a6212SJordan K. Hubbard if (error) { 271b40ce416SJulian Elischer msdosfs_unmount(mp, MNT_FORCE, td); 27227a0bc89SDoug Rabson return error; 27327a0bc89SDoug Rabson } 274952a6212SJordan K. Hubbard (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 275952a6212SJordan K. Hubbard &size); 276952a6212SJordan K. Hubbard bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 277b40ce416SJulian Elischer (void) msdosfs_statfs(mp, &mp->mnt_stat, td); 27827a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 279623ae52eSPoul-Henning Kamp printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); 28027a0bc89SDoug Rabson #endif 281952a6212SJordan K. Hubbard return (0); 28227a0bc89SDoug Rabson } 28327a0bc89SDoug Rabson 2847fefffeeSPoul-Henning Kamp static int 285b40ce416SJulian Elischer mountmsdosfs(devvp, mp, td, argp) 28627a0bc89SDoug Rabson struct vnode *devvp; 28727a0bc89SDoug Rabson struct mount *mp; 288b40ce416SJulian Elischer struct thread *td; 289952a6212SJordan K. Hubbard struct msdosfs_args *argp; 29027a0bc89SDoug Rabson { 291952a6212SJordan K. Hubbard struct msdosfsmount *pmp; 292952a6212SJordan K. Hubbard struct buf *bp; 29327a0bc89SDoug Rabson dev_t dev = devvp->v_rdev; 29427a0bc89SDoug Rabson union bootsector *bsp; 29527a0bc89SDoug Rabson struct byte_bpb33 *b33; 29627a0bc89SDoug Rabson struct byte_bpb50 *b50; 297952a6212SJordan K. Hubbard struct byte_bpb710 *b710; 298952a6212SJordan K. Hubbard u_int8_t SecPerClust; 299499d3ffaSBoris Popov u_long clusters; 300952a6212SJordan K. Hubbard int ronly, error; 30127a0bc89SDoug Rabson 30227a0bc89SDoug Rabson /* 303952a6212SJordan K. Hubbard * Disallow multiple mounts of the same device. 304952a6212SJordan K. Hubbard * Disallow mounting of a device that is currently in use 305952a6212SJordan K. Hubbard * (except for root, which might share swap device for miniroot). 306952a6212SJordan K. Hubbard * Flush out any old buffers remaining from a previous use. 30727a0bc89SDoug Rabson */ 308c3c6d51eSPoul-Henning Kamp error = vfs_mountedon(devvp); 309c3c6d51eSPoul-Henning Kamp if (error) 310952a6212SJordan K. Hubbard return (error); 311952a6212SJordan K. Hubbard if (vcount(devvp) > 1 && devvp != rootvp) 312952a6212SJordan K. Hubbard return (EBUSY); 313b40ce416SJulian Elischer vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); 314a854ed98SJohn Baldwin error = vinvalbuf(devvp, V_SAVE, td->td_ucred, td, 0, 0); 315b40ce416SJulian Elischer VOP_UNLOCK(devvp, 0, td); 316c3c6d51eSPoul-Henning Kamp if (error) 317952a6212SJordan K. Hubbard return (error); 31827a0bc89SDoug Rabson 319952a6212SJordan K. Hubbard ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 320b40ce416SJulian Elischer vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); 321ae620d44STim J. Robbins /* 322ae620d44STim J. Robbins * XXX Open the device with write access even if the filesystem 323ae620d44STim J. Robbins * is read-only: someone may remount it read-write later, and 324ae620d44STim J. Robbins * we don't VOP_OPEN the device again in that case. 325ae620d44STim J. Robbins */ 326ae620d44STim J. Robbins #ifdef notyet 327a8d43c90SPoul-Henning Kamp error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, td, -1); 328ae620d44STim J. Robbins #else 329a8d43c90SPoul-Henning Kamp error = VOP_OPEN(devvp, FREAD|FWRITE, FSCRED, td, -1); 330ae620d44STim J. Robbins #endif 331b40ce416SJulian Elischer VOP_UNLOCK(devvp, 0, td); 332c3c6d51eSPoul-Henning Kamp if (error) 333952a6212SJordan K. Hubbard return (error); 334952a6212SJordan K. Hubbard 335952a6212SJordan K. Hubbard bp = NULL; /* both used in error_exit */ 336952a6212SJordan K. Hubbard pmp = NULL; 337952a6212SJordan K. Hubbard 33827a0bc89SDoug Rabson /* 339952a6212SJordan K. Hubbard * Read the boot sector of the filesystem, and then check the 340952a6212SJordan K. Hubbard * boot signature. If not a dos boot sector then error out. 34101f6cfbaSYoshihiro Takahashi * 342152ffafeSBruce Evans * NOTE: 2048 is a maximum sector size in current... 34327a0bc89SDoug Rabson */ 344152ffafeSBruce Evans error = bread(devvp, 0, 2048, NOCRED, &bp); 345c3c6d51eSPoul-Henning Kamp if (error) 34627a0bc89SDoug Rabson goto error_exit; 347952a6212SJordan K. Hubbard bp->b_flags |= B_AGE; 348952a6212SJordan K. Hubbard bsp = (union bootsector *)bp->b_data; 34927a0bc89SDoug Rabson b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB; 35027a0bc89SDoug Rabson b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB; 35101a4d019SJohn Baldwin b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB; 352952a6212SJordan K. Hubbard 35301f6cfbaSYoshihiro Takahashi #ifndef MSDOSFS_NOCHECKSIG 354952a6212SJordan K. Hubbard if (bsp->bs50.bsBootSectSig0 != BOOTSIG0 355952a6212SJordan K. Hubbard || bsp->bs50.bsBootSectSig1 != BOOTSIG1) { 35627a0bc89SDoug Rabson error = EINVAL; 35727a0bc89SDoug Rabson goto error_exit; 35827a0bc89SDoug Rabson } 35901f6cfbaSYoshihiro Takahashi #endif 36027a0bc89SDoug Rabson 361a163d034SWarner Losh pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK | M_ZERO); 36227a0bc89SDoug Rabson pmp->pm_mountp = mp; 36327a0bc89SDoug Rabson 36427a0bc89SDoug Rabson /* 36527a0bc89SDoug Rabson * Compute several useful quantities from the bpb in the 36627a0bc89SDoug Rabson * bootsector. Copy in the dos 5 variant of the bpb then fix up 36727a0bc89SDoug Rabson * the fields that are different between dos 5 and dos 3.3. 36827a0bc89SDoug Rabson */ 369952a6212SJordan K. Hubbard SecPerClust = b50->bpbSecPerClust; 37027a0bc89SDoug Rabson pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 371696f22f0SJohn Baldwin if (pmp->pm_BytesPerSec < DEV_BSIZE) { 372696f22f0SJohn Baldwin error = EINVAL; 373696f22f0SJohn Baldwin goto error_exit; 374696f22f0SJohn Baldwin } 37527a0bc89SDoug Rabson pmp->pm_ResSectors = getushort(b50->bpbResSectors); 37627a0bc89SDoug Rabson pmp->pm_FATs = b50->bpbFATs; 37727a0bc89SDoug Rabson pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 37827a0bc89SDoug Rabson pmp->pm_Sectors = getushort(b50->bpbSectors); 37927a0bc89SDoug Rabson pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 38027a0bc89SDoug Rabson pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 38127a0bc89SDoug Rabson pmp->pm_Heads = getushort(b50->bpbHeads); 382952a6212SJordan K. Hubbard pmp->pm_Media = b50->bpbMedia; 38327a0bc89SDoug Rabson 38401f6cfbaSYoshihiro Takahashi /* calculate the ratio of sector size to DEV_BSIZE */ 38501f6cfbaSYoshihiro Takahashi pmp->pm_BlkPerSec = pmp->pm_BytesPerSec / DEV_BSIZE; 38601f6cfbaSYoshihiro Takahashi 38727a0bc89SDoug Rabson /* XXX - We should probably check more values here */ 388952a6212SJordan K. Hubbard if (!pmp->pm_BytesPerSec || !SecPerClust 389952a6212SJordan K. Hubbard || !pmp->pm_Heads || pmp->pm_Heads > 255 390ad63a118SSatoshi Asami #ifdef PC98 391952a6212SJordan K. Hubbard || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) { 392ad63a118SSatoshi Asami #else 393952a6212SJordan K. Hubbard || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) { 394ad63a118SSatoshi Asami #endif 39527a0bc89SDoug Rabson error = EINVAL; 39627a0bc89SDoug Rabson goto error_exit; 39727a0bc89SDoug Rabson } 39827a0bc89SDoug Rabson 39927a0bc89SDoug Rabson if (pmp->pm_Sectors == 0) { 40027a0bc89SDoug Rabson pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 40127a0bc89SDoug Rabson pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 40227a0bc89SDoug Rabson } else { 40327a0bc89SDoug Rabson pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 40427a0bc89SDoug Rabson pmp->pm_HugeSectors = pmp->pm_Sectors; 40527a0bc89SDoug Rabson } 406c681be37SDmitrij Tejblum if (pmp->pm_HugeSectors > 0xffffffff / 407c681be37SDmitrij Tejblum (pmp->pm_BytesPerSec / sizeof(struct direntry)) + 1) { 408952a6212SJordan K. Hubbard /* 409952a6212SJordan K. Hubbard * We cannot deal currently with this size of disk 410952a6212SJordan K. Hubbard * due to fileid limitations (see msdosfs_getattr and 411952a6212SJordan K. Hubbard * msdosfs_readdir) 412952a6212SJordan K. Hubbard */ 413952a6212SJordan K. Hubbard error = EINVAL; 414aaf0bb19SAndrey A. Chernov printf("mountmsdosfs(): disk too big, sorry\n"); 415952a6212SJordan K. Hubbard goto error_exit; 416952a6212SJordan K. Hubbard } 417952a6212SJordan K. Hubbard 418952a6212SJordan K. Hubbard if (pmp->pm_RootDirEnts == 0) { 419952a6212SJordan K. Hubbard if (bsp->bs710.bsBootSectSig2 != BOOTSIG2 420952a6212SJordan K. Hubbard || bsp->bs710.bsBootSectSig3 != BOOTSIG3 421952a6212SJordan K. Hubbard || pmp->pm_Sectors 422952a6212SJordan K. Hubbard || pmp->pm_FATsecs 423952a6212SJordan K. Hubbard || getushort(b710->bpbFSVers)) { 424952a6212SJordan K. Hubbard error = EINVAL; 425aaf0bb19SAndrey A. Chernov printf("mountmsdosfs(): bad FAT32 filesystem\n"); 426952a6212SJordan K. Hubbard goto error_exit; 427952a6212SJordan K. Hubbard } 428952a6212SJordan K. Hubbard pmp->pm_fatmask = FAT32_MASK; 429952a6212SJordan K. Hubbard pmp->pm_fatmult = 4; 430952a6212SJordan K. Hubbard pmp->pm_fatdiv = 1; 431952a6212SJordan K. Hubbard pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs); 432952a6212SJordan K. Hubbard if (getushort(b710->bpbExtFlags) & FATMIRROR) 433952a6212SJordan K. Hubbard pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM; 434952a6212SJordan K. Hubbard else 435952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFS_FATMIRROR; 436952a6212SJordan K. Hubbard } else 437952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFS_FATMIRROR; 438952a6212SJordan K. Hubbard 439952a6212SJordan K. Hubbard /* 440952a6212SJordan K. Hubbard * Check a few values (could do some more): 441952a6212SJordan K. Hubbard * - logical sector size: power of 2, >= block size 442952a6212SJordan K. Hubbard * - sectors per cluster: power of 2, >= 1 443952a6212SJordan K. Hubbard * - number of sectors: >= 1, <= size of partition 444696f22f0SJohn Baldwin * - number of FAT sectors: >= 1 445952a6212SJordan K. Hubbard */ 446952a6212SJordan K. Hubbard if ( (SecPerClust == 0) 447952a6212SJordan K. Hubbard || (SecPerClust & (SecPerClust - 1)) 44801f6cfbaSYoshihiro Takahashi || (pmp->pm_BytesPerSec < DEV_BSIZE) 449952a6212SJordan K. Hubbard || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) 450952a6212SJordan K. Hubbard || (pmp->pm_HugeSectors == 0) 451696f22f0SJohn Baldwin || (pmp->pm_FATsecs == 0) 452952a6212SJordan K. Hubbard ) { 453952a6212SJordan K. Hubbard error = EINVAL; 454952a6212SJordan K. Hubbard goto error_exit; 455952a6212SJordan K. Hubbard } 45601f6cfbaSYoshihiro Takahashi 45701f6cfbaSYoshihiro Takahashi pmp->pm_HugeSectors *= pmp->pm_BlkPerSec; 45801f6cfbaSYoshihiro Takahashi pmp->pm_HiddenSects *= pmp->pm_BlkPerSec; /* XXX not used? */ 45901f6cfbaSYoshihiro Takahashi pmp->pm_FATsecs *= pmp->pm_BlkPerSec; 46001f6cfbaSYoshihiro Takahashi SecPerClust *= pmp->pm_BlkPerSec; 46101f6cfbaSYoshihiro Takahashi 46201f6cfbaSYoshihiro Takahashi pmp->pm_fatblk = pmp->pm_ResSectors * pmp->pm_BlkPerSec; 46301f6cfbaSYoshihiro Takahashi 464952a6212SJordan K. Hubbard if (FAT32(pmp)) { 465952a6212SJordan K. Hubbard pmp->pm_rootdirblk = getulong(b710->bpbRootClust); 466952a6212SJordan K. Hubbard pmp->pm_firstcluster = pmp->pm_fatblk 467952a6212SJordan K. Hubbard + (pmp->pm_FATs * pmp->pm_FATsecs); 46801f6cfbaSYoshihiro Takahashi pmp->pm_fsinfo = getushort(b710->bpbFSInfo) * pmp->pm_BlkPerSec; 469952a6212SJordan K. Hubbard } else { 47027a0bc89SDoug Rabson pmp->pm_rootdirblk = pmp->pm_fatblk + 47127a0bc89SDoug Rabson (pmp->pm_FATs * pmp->pm_FATsecs); 472952a6212SJordan K. Hubbard pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry) 47301f6cfbaSYoshihiro Takahashi + DEV_BSIZE - 1) 47401f6cfbaSYoshihiro Takahashi / DEV_BSIZE; /* in blocks */ 47527a0bc89SDoug Rabson pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 476952a6212SJordan K. Hubbard } 477952a6212SJordan K. Hubbard 478499d3ffaSBoris Popov pmp->pm_maxcluster = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 479499d3ffaSBoris Popov SecPerClust + 1; 48001f6cfbaSYoshihiro Takahashi pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE; /* XXX not used? */ 481952a6212SJordan K. Hubbard 482952a6212SJordan K. Hubbard if (pmp->pm_fatmask == 0) { 483952a6212SJordan K. Hubbard if (pmp->pm_maxcluster 484952a6212SJordan K. Hubbard <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) { 48527a0bc89SDoug Rabson /* 486952a6212SJordan K. Hubbard * This will usually be a floppy disk. This size makes 487952a6212SJordan K. Hubbard * sure that one fat entry will not be split across 488952a6212SJordan K. Hubbard * multiple blocks. 48927a0bc89SDoug Rabson */ 490952a6212SJordan K. Hubbard pmp->pm_fatmask = FAT12_MASK; 491952a6212SJordan K. Hubbard pmp->pm_fatmult = 3; 492952a6212SJordan K. Hubbard pmp->pm_fatdiv = 2; 493952a6212SJordan K. Hubbard } else { 494952a6212SJordan K. Hubbard pmp->pm_fatmask = FAT16_MASK; 495952a6212SJordan K. Hubbard pmp->pm_fatmult = 2; 496952a6212SJordan K. Hubbard pmp->pm_fatdiv = 1; 497952a6212SJordan K. Hubbard } 498952a6212SJordan K. Hubbard } 499499d3ffaSBoris Popov 500499d3ffaSBoris Popov clusters = (pmp->pm_fatsize / pmp->pm_fatmult) * pmp->pm_fatdiv; 501499d3ffaSBoris Popov if (pmp->pm_maxcluster >= clusters) { 502499d3ffaSBoris Popov printf("Warning: number of clusters (%ld) exceeds FAT " 503499d3ffaSBoris Popov "capacity (%ld)\n", pmp->pm_maxcluster + 1, clusters); 504499d3ffaSBoris Popov pmp->pm_maxcluster = clusters - 1; 505499d3ffaSBoris Popov } 506499d3ffaSBoris Popov 507499d3ffaSBoris Popov 508952a6212SJordan K. Hubbard if (FAT12(pmp)) 50927a0bc89SDoug Rabson pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; 51027a0bc89SDoug Rabson else 511152ffafeSBruce Evans pmp->pm_fatblocksize = MSDOSFS_DFLTBSIZE; 512952a6212SJordan K. Hubbard 51301f6cfbaSYoshihiro Takahashi pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE; 51401f6cfbaSYoshihiro Takahashi pmp->pm_bnshift = ffs(DEV_BSIZE) - 1; 51527a0bc89SDoug Rabson 51627a0bc89SDoug Rabson /* 51727a0bc89SDoug Rabson * Compute mask and shift value for isolating cluster relative byte 51827a0bc89SDoug Rabson * offsets and cluster numbers from a file offset. 51927a0bc89SDoug Rabson */ 52001f6cfbaSYoshihiro Takahashi pmp->pm_bpcluster = SecPerClust * DEV_BSIZE; 521952a6212SJordan K. Hubbard pmp->pm_crbomask = pmp->pm_bpcluster - 1; 522952a6212SJordan K. Hubbard pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1; 52327a0bc89SDoug Rabson 524952a6212SJordan K. Hubbard /* 525952a6212SJordan K. Hubbard * Check for valid cluster size 526952a6212SJordan K. Hubbard * must be a power of 2 527952a6212SJordan K. Hubbard */ 528952a6212SJordan K. Hubbard if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) { 529952a6212SJordan K. Hubbard error = EINVAL; 530952a6212SJordan K. Hubbard goto error_exit; 531ad63a118SSatoshi Asami } 53227a0bc89SDoug Rabson 53327a0bc89SDoug Rabson /* 53427a0bc89SDoug Rabson * Release the bootsector buffer. 53527a0bc89SDoug Rabson */ 536952a6212SJordan K. Hubbard brelse(bp); 537952a6212SJordan K. Hubbard bp = NULL; 538952a6212SJordan K. Hubbard 539952a6212SJordan K. Hubbard /* 540952a6212SJordan K. Hubbard * Check FSInfo. 541952a6212SJordan K. Hubbard */ 542952a6212SJordan K. Hubbard if (pmp->pm_fsinfo) { 543952a6212SJordan K. Hubbard struct fsinfo *fp; 544952a6212SJordan K. Hubbard 54501f6cfbaSYoshihiro Takahashi if ((error = bread(devvp, pmp->pm_fsinfo, fsi_size(pmp), 54601f6cfbaSYoshihiro Takahashi NOCRED, &bp)) != 0) 547952a6212SJordan K. Hubbard goto error_exit; 548952a6212SJordan K. Hubbard fp = (struct fsinfo *)bp->b_data; 549952a6212SJordan K. Hubbard if (!bcmp(fp->fsisig1, "RRaA", 4) 550952a6212SJordan K. Hubbard && !bcmp(fp->fsisig2, "rrAa", 4) 551952a6212SJordan K. Hubbard && !bcmp(fp->fsisig3, "\0\0\125\252", 4) 552952a6212SJordan K. Hubbard && !bcmp(fp->fsisig4, "\0\0\125\252", 4)) 553952a6212SJordan K. Hubbard pmp->pm_nxtfree = getulong(fp->fsinxtfree); 554952a6212SJordan K. Hubbard else 555952a6212SJordan K. Hubbard pmp->pm_fsinfo = 0; 556952a6212SJordan K. Hubbard brelse(bp); 557952a6212SJordan K. Hubbard bp = NULL; 558952a6212SJordan K. Hubbard } 559952a6212SJordan K. Hubbard 560952a6212SJordan K. Hubbard /* 561abe78e97STom Rhodes * Check and validate (or perhaps invalidate?) the fsinfo structure? 562952a6212SJordan K. Hubbard */ 563abe78e97STom Rhodes if (pmp->pm_fsinfo && pmp->pm_nxtfree > pmp->pm_maxcluster) { 56434bdf0dcSBruce Evans printf( 56534bdf0dcSBruce Evans "Next free cluster in FSInfo (%lu) exceeds maxcluster (%lu)\n", 566abe78e97STom Rhodes pmp->pm_nxtfree, pmp->pm_maxcluster); 567abe78e97STom Rhodes error = EINVAL; 568abe78e97STom Rhodes goto error_exit; 569abe78e97STom Rhodes } 57027a0bc89SDoug Rabson 57127a0bc89SDoug Rabson /* 57227a0bc89SDoug Rabson * Allocate memory for the bitmap of allocated clusters, and then 57327a0bc89SDoug Rabson * fill it in. 57427a0bc89SDoug Rabson */ 57527a0bc89SDoug Rabson pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS - 1) 57627a0bc89SDoug Rabson / N_INUSEBITS) 57727a0bc89SDoug Rabson * sizeof(*pmp->pm_inusemap), 578a163d034SWarner Losh M_MSDOSFSFAT, M_WAITOK); 57927a0bc89SDoug Rabson 58027a0bc89SDoug Rabson /* 58127a0bc89SDoug Rabson * fillinusemap() needs pm_devvp. 58227a0bc89SDoug Rabson */ 58327a0bc89SDoug Rabson pmp->pm_dev = dev; 58427a0bc89SDoug Rabson pmp->pm_devvp = devvp; 58527a0bc89SDoug Rabson 58627a0bc89SDoug Rabson /* 58727a0bc89SDoug Rabson * Have the inuse map filled in. 58827a0bc89SDoug Rabson */ 589952a6212SJordan K. Hubbard if ((error = fillinusemap(pmp)) != 0) 59027a0bc89SDoug Rabson goto error_exit; 59127a0bc89SDoug Rabson 59227a0bc89SDoug Rabson /* 59327a0bc89SDoug Rabson * If they want fat updates to be synchronous then let them suffer 59427a0bc89SDoug Rabson * the performance degradation in exchange for the on disk copy of 59527a0bc89SDoug Rabson * the fat being correct just about all the time. I suppose this 59627a0bc89SDoug Rabson * would be a good thing to turn on if the kernel is still flakey. 59727a0bc89SDoug Rabson */ 598952a6212SJordan K. Hubbard if (mp->mnt_flag & MNT_SYNCHRONOUS) 599952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_WAITONFAT; 60027a0bc89SDoug Rabson 60127a0bc89SDoug Rabson /* 60227a0bc89SDoug Rabson * Finish up. 60327a0bc89SDoug Rabson */ 604952a6212SJordan K. Hubbard if (ronly) 605952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_RONLY; 606952a6212SJordan K. Hubbard else 60727a0bc89SDoug Rabson pmp->pm_fmod = 1; 60827a0bc89SDoug Rabson mp->mnt_data = (qaddr_t) pmp; 609939cb752SBruce Evans mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); 610af3f60d5SBruce Evans mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 611cc9d8990SPeter Wemm mp->mnt_flag |= MNT_LOCAL; 6127eb9fca5SEivind Eklund devvp->v_rdev->si_mountpoint = mp; 61327a0bc89SDoug Rabson 61427a0bc89SDoug Rabson return 0; 61527a0bc89SDoug Rabson 616952a6212SJordan K. Hubbard error_exit: 617952a6212SJordan K. Hubbard if (bp) 618952a6212SJordan K. Hubbard brelse(bp); 619ae620d44STim J. Robbins /* XXX See comment at VOP_OPEN call */ 620ae620d44STim J. Robbins #ifdef notyet 621b40ce416SJulian Elischer (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE, NOCRED, td); 622ae620d44STim J. Robbins #else 623ae620d44STim J. Robbins (void) VOP_CLOSE(devvp, FREAD | FWRITE, NOCRED, td); 624ae620d44STim J. Robbins #endif 62527a0bc89SDoug Rabson if (pmp) { 62627a0bc89SDoug Rabson if (pmp->pm_inusemap) 627952a6212SJordan K. Hubbard free(pmp->pm_inusemap, M_MSDOSFSFAT); 628952a6212SJordan K. Hubbard free(pmp, M_MSDOSFSMNT); 62927a0bc89SDoug Rabson mp->mnt_data = (qaddr_t)0; 63027a0bc89SDoug Rabson } 631952a6212SJordan K. Hubbard return (error); 63227a0bc89SDoug Rabson } 63327a0bc89SDoug Rabson 63427a0bc89SDoug Rabson /* 63527a0bc89SDoug Rabson * Unmount the filesystem described by mp. 63627a0bc89SDoug Rabson */ 6377fefffeeSPoul-Henning Kamp static int 638b40ce416SJulian Elischer msdosfs_unmount(mp, mntflags, td) 63927a0bc89SDoug Rabson struct mount *mp; 64027a0bc89SDoug Rabson int mntflags; 641b40ce416SJulian Elischer struct thread *td; 64227a0bc89SDoug Rabson { 643952a6212SJordan K. Hubbard struct msdosfsmount *pmp; 644952a6212SJordan K. Hubbard int error, flags; 64527a0bc89SDoug Rabson 646952a6212SJordan K. Hubbard flags = 0; 647952a6212SJordan K. Hubbard if (mntflags & MNT_FORCE) 64827a0bc89SDoug Rabson flags |= FORCECLOSE; 6490864ef1eSIan Dowse error = vflush(mp, 0, flags); 650c3c6d51eSPoul-Henning Kamp if (error) 65127a0bc89SDoug Rabson return error; 652952a6212SJordan K. Hubbard pmp = VFSTOMSDOSFS(mp); 6537eb9fca5SEivind Eklund pmp->pm_devvp->v_rdev->si_mountpoint = NULL; 654952a6212SJordan K. Hubbard #ifdef MSDOSFS_DEBUG 655952a6212SJordan K. Hubbard { 656952a6212SJordan K. Hubbard struct vnode *vp = pmp->pm_devvp; 657952a6212SJordan K. Hubbard 6584d93c0beSJeff Roberson VI_LOCK(vp); 659952a6212SJordan K. Hubbard printf("msdosfs_umount(): just before calling VOP_CLOSE()\n"); 660e6e370a7SJeff Roberson printf("iflag %08lx, usecount %d, writecount %d, holdcnt %ld\n", 661e6e370a7SJeff Roberson vp->vi_flag, vp->v_usecount, vp->v_writecount, 662e6e370a7SJeff Roberson vp->v_holdcnt); 66367ddfcafSMatthew Dillon printf("id %lu, mount %p, op %p\n", 66467ddfcafSMatthew Dillon vp->v_id, vp->v_mount, vp->v_op); 665952a6212SJordan K. Hubbard printf("freef %p, freeb %p, mount %p\n", 666fc2ffbe6SPoul-Henning Kamp TAILQ_NEXT(vp, v_freelist), vp->v_freelist.tqe_prev, 667952a6212SJordan K. Hubbard vp->v_mount); 668952a6212SJordan K. Hubbard printf("cleanblkhd %p, dirtyblkhd %p, numoutput %ld, type %d\n", 66940c8cfe5SPeter Wemm TAILQ_FIRST(&vp->v_cleanblkhd), 67040c8cfe5SPeter Wemm TAILQ_FIRST(&vp->v_dirtyblkhd), 671952a6212SJordan K. Hubbard vp->v_numoutput, vp->v_type); 67206be2aaaSNate Lawson printf("union %p, tag %s, data[0] %08x, data[1] %08x\n", 673952a6212SJordan K. Hubbard vp->v_socket, vp->v_tag, 674952a6212SJordan K. Hubbard ((u_int *)vp->v_data)[0], 675952a6212SJordan K. Hubbard ((u_int *)vp->v_data)[1]); 6764d93c0beSJeff Roberson VI_UNLOCK(vp); 677952a6212SJordan K. Hubbard } 678952a6212SJordan K. Hubbard #endif 679ae620d44STim J. Robbins /* XXX See comment at VOP_OPEN call */ 680ae620d44STim J. Robbins #ifdef notyet 681b1897c19SJulian Elischer error = VOP_CLOSE(pmp->pm_devvp, 682b1897c19SJulian Elischer (pmp->pm_flags&MSDOSFSMNT_RONLY) ? FREAD : FREAD | FWRITE, 683b40ce416SJulian Elischer NOCRED, td); 684ae620d44STim J. Robbins #else 685ae620d44STim J. Robbins error = VOP_CLOSE(pmp->pm_devvp, FREAD | FWRITE, NOCRED, td); 686ae620d44STim J. Robbins #endif 68727a0bc89SDoug Rabson vrele(pmp->pm_devvp); 688952a6212SJordan K. Hubbard free(pmp->pm_inusemap, M_MSDOSFSFAT); 689952a6212SJordan K. Hubbard free(pmp, M_MSDOSFSMNT); 69027a0bc89SDoug Rabson mp->mnt_data = (qaddr_t)0; 691cc9d8990SPeter Wemm mp->mnt_flag &= ~MNT_LOCAL; 692952a6212SJordan K. Hubbard return (error); 69327a0bc89SDoug Rabson } 69427a0bc89SDoug Rabson 6957fefffeeSPoul-Henning Kamp static int 69627a0bc89SDoug Rabson msdosfs_root(mp, vpp) 69727a0bc89SDoug Rabson struct mount *mp; 69827a0bc89SDoug Rabson struct vnode **vpp; 69927a0bc89SDoug Rabson { 700952a6212SJordan K. Hubbard struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 70127a0bc89SDoug Rabson struct denode *ndep; 70227a0bc89SDoug Rabson int error; 70327a0bc89SDoug Rabson 70427a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 705952a6212SJordan K. Hubbard printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp); 70627a0bc89SDoug Rabson #endif 707952a6212SJordan K. Hubbard error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep); 708952a6212SJordan K. Hubbard if (error) 709952a6212SJordan K. Hubbard return (error); 71027a0bc89SDoug Rabson *vpp = DETOV(ndep); 711952a6212SJordan K. Hubbard return (0); 71227a0bc89SDoug Rabson } 71327a0bc89SDoug Rabson 7147fefffeeSPoul-Henning Kamp static int 715b40ce416SJulian Elischer msdosfs_statfs(mp, sbp, td) 71627a0bc89SDoug Rabson struct mount *mp; 71727a0bc89SDoug Rabson struct statfs *sbp; 718b40ce416SJulian Elischer struct thread *td; 71927a0bc89SDoug Rabson { 720952a6212SJordan K. Hubbard struct msdosfsmount *pmp; 72127a0bc89SDoug Rabson 722952a6212SJordan K. Hubbard pmp = VFSTOMSDOSFS(mp); 72327a0bc89SDoug Rabson sbp->f_bsize = pmp->pm_bpcluster; 72427a0bc89SDoug Rabson sbp->f_iosize = pmp->pm_bpcluster; 725499d3ffaSBoris Popov sbp->f_blocks = pmp->pm_maxcluster + 1; 72627a0bc89SDoug Rabson sbp->f_bfree = pmp->pm_freeclustercount; 72727a0bc89SDoug Rabson sbp->f_bavail = pmp->pm_freeclustercount; 72827a0bc89SDoug Rabson sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ 72927a0bc89SDoug Rabson sbp->f_ffree = 0; /* what to put in here? */ 73027a0bc89SDoug Rabson if (sbp != &mp->mnt_stat) { 731af3f60d5SBruce Evans sbp->f_type = mp->mnt_vfc->vfc_typenum; 732952a6212SJordan K. Hubbard bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 733952a6212SJordan K. Hubbard bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 73427a0bc89SDoug Rabson } 735952a6212SJordan K. Hubbard strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN); 736952a6212SJordan K. Hubbard return (0); 73727a0bc89SDoug Rabson } 73827a0bc89SDoug Rabson 7397fefffeeSPoul-Henning Kamp static int 740b40ce416SJulian Elischer msdosfs_sync(mp, waitfor, cred, td) 74127a0bc89SDoug Rabson struct mount *mp; 74227a0bc89SDoug Rabson int waitfor; 74327a0bc89SDoug Rabson struct ucred *cred; 744b40ce416SJulian Elischer struct thread *td; 74527a0bc89SDoug Rabson { 746952a6212SJordan K. Hubbard struct vnode *vp, *nvp; 74727a0bc89SDoug Rabson struct denode *dep; 748952a6212SJordan K. Hubbard struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 749952a6212SJordan K. Hubbard int error, allerror = 0; 75027a0bc89SDoug Rabson 75127a0bc89SDoug Rabson /* 75227a0bc89SDoug Rabson * If we ever switch to not updating all of the fats all the time, 75327a0bc89SDoug Rabson * this would be the place to update them from the first one. 75427a0bc89SDoug Rabson */ 755dfd5dee1SPeter Wemm if (pmp->pm_fmod != 0) { 756952a6212SJordan K. Hubbard if (pmp->pm_flags & MSDOSFSMNT_RONLY) 75727a0bc89SDoug Rabson panic("msdosfs_sync: rofs mod"); 75827a0bc89SDoug Rabson else { 75927a0bc89SDoug Rabson /* update fats here */ 76027a0bc89SDoug Rabson } 761dfd5dee1SPeter Wemm } 76227a0bc89SDoug Rabson /* 763952a6212SJordan K. Hubbard * Write back each (modified) denode. 76427a0bc89SDoug Rabson */ 7659ed346baSBosko Milekic mtx_lock(&mntvnode_mtx); 76627a0bc89SDoug Rabson loop: 767c72ccd01SMatthew Dillon for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist); vp != NULL; vp = nvp) { 768952a6212SJordan K. Hubbard /* 769952a6212SJordan K. Hubbard * If the vnode that we are about to sync is no longer 770c681be37SDmitrij Tejblum * associated with this mount point, start over. 771952a6212SJordan K. Hubbard */ 772952a6212SJordan K. Hubbard if (vp->v_mount != mp) 77327a0bc89SDoug Rabson goto loop; 774c72ccd01SMatthew Dillon nvp = TAILQ_NEXT(vp, v_nmntvnodes); 775797c3dbaSJohn Baldwin 776797c3dbaSJohn Baldwin mtx_unlock(&mntvnode_mtx); 7774d93c0beSJeff Roberson VI_LOCK(vp); 77827a0bc89SDoug Rabson dep = VTODE(vp); 779c681be37SDmitrij Tejblum if (vp->v_type == VNON || 780831a80b0SMatthew Dillon ((dep->de_flag & 781c681be37SDmitrij Tejblum (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0 && 782152ffafeSBruce Evans (TAILQ_EMPTY(&vp->v_dirtyblkhd) || waitfor == MNT_LAZY))) { 7834d93c0beSJeff Roberson VI_UNLOCK(vp); 784797c3dbaSJohn Baldwin mtx_lock(&mntvnode_mtx); 78527a0bc89SDoug Rabson continue; 786af3f60d5SBruce Evans } 787b40ce416SJulian Elischer error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, td); 788af3f60d5SBruce Evans if (error) { 7899ed346baSBosko Milekic mtx_lock(&mntvnode_mtx); 790af3f60d5SBruce Evans if (error == ENOENT) 79127a0bc89SDoug Rabson goto loop; 792af3f60d5SBruce Evans continue; 793af3f60d5SBruce Evans } 794b40ce416SJulian Elischer error = VOP_FSYNC(vp, cred, waitfor, td); 795c3c6d51eSPoul-Henning Kamp if (error) 79627a0bc89SDoug Rabson allerror = error; 797b40ce416SJulian Elischer VOP_UNLOCK(vp, 0, td); 798c681be37SDmitrij Tejblum vrele(vp); 7999ed346baSBosko Milekic mtx_lock(&mntvnode_mtx); 80027a0bc89SDoug Rabson } 8019ed346baSBosko Milekic mtx_unlock(&mntvnode_mtx); 80227a0bc89SDoug Rabson 80327a0bc89SDoug Rabson /* 80427a0bc89SDoug Rabson * Flush filesystem control info. 80527a0bc89SDoug Rabson */ 806c681be37SDmitrij Tejblum if (waitfor != MNT_LAZY) { 807b40ce416SJulian Elischer vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY, td); 808b40ce416SJulian Elischer error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, td); 809c3c6d51eSPoul-Henning Kamp if (error) 81027a0bc89SDoug Rabson allerror = error; 811b40ce416SJulian Elischer VOP_UNLOCK(pmp->pm_devvp, 0, td); 812c681be37SDmitrij Tejblum } 813952a6212SJordan K. Hubbard return (allerror); 81427a0bc89SDoug Rabson } 81527a0bc89SDoug Rabson 8167fefffeeSPoul-Henning Kamp static int 817c24fda81SAlfred Perlstein msdosfs_fhtovp(mp, fhp, vpp) 81827a0bc89SDoug Rabson struct mount *mp; 81927a0bc89SDoug Rabson struct fid *fhp; 82027a0bc89SDoug Rabson struct vnode **vpp; 82127a0bc89SDoug Rabson { 822952a6212SJordan K. Hubbard struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 82327a0bc89SDoug Rabson struct defid *defhp = (struct defid *) fhp; 82427a0bc89SDoug Rabson struct denode *dep; 82527a0bc89SDoug Rabson int error; 82627a0bc89SDoug Rabson 827952a6212SJordan K. Hubbard error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep); 82827a0bc89SDoug Rabson if (error) { 82927a0bc89SDoug Rabson *vpp = NULLVP; 830952a6212SJordan K. Hubbard return (error); 83127a0bc89SDoug Rabson } 83227a0bc89SDoug Rabson *vpp = DETOV(dep); 833c24fda81SAlfred Perlstein return (0); 834c24fda81SAlfred Perlstein } 835c24fda81SAlfred Perlstein 836c24fda81SAlfred Perlstein static int 83727a0bc89SDoug Rabson msdosfs_vptofh(vp, fhp) 83827a0bc89SDoug Rabson struct vnode *vp; 83927a0bc89SDoug Rabson struct fid *fhp; 84027a0bc89SDoug Rabson { 841952a6212SJordan K. Hubbard struct denode *dep; 842952a6212SJordan K. Hubbard struct defid *defhp; 84327a0bc89SDoug Rabson 844952a6212SJordan K. Hubbard dep = VTODE(vp); 845952a6212SJordan K. Hubbard defhp = (struct defid *)fhp; 84627a0bc89SDoug Rabson defhp->defid_len = sizeof(struct defid); 84727a0bc89SDoug Rabson defhp->defid_dirclust = dep->de_dirclust; 84827a0bc89SDoug Rabson defhp->defid_dirofs = dep->de_diroffset; 849952a6212SJordan K. Hubbard /* defhp->defid_gen = dep->de_gen; */ 850952a6212SJordan K. Hubbard return (0); 85127a0bc89SDoug Rabson } 85227a0bc89SDoug Rabson 85330ffadf3SPoul-Henning Kamp static struct vfsops msdosfs_vfsops = { 8547652131bSPoul-Henning Kamp .vfs_fhtovp = msdosfs_fhtovp, 8557652131bSPoul-Henning Kamp .vfs_init = msdosfs_init, 8567652131bSPoul-Henning Kamp .vfs_mount = msdosfs_mount, 8577652131bSPoul-Henning Kamp .vfs_root = msdosfs_root, 8587652131bSPoul-Henning Kamp .vfs_statfs = msdosfs_statfs, 8597652131bSPoul-Henning Kamp .vfs_sync = msdosfs_sync, 8607652131bSPoul-Henning Kamp .vfs_uninit = msdosfs_uninit, 8617652131bSPoul-Henning Kamp .vfs_unmount = msdosfs_unmount, 8627652131bSPoul-Henning Kamp .vfs_vptofh = msdosfs_vptofh, 86327a0bc89SDoug Rabson }; 864c901836cSGarrett Wollman 8654ccd7546SRuslan Ermilov VFS_SET(msdosfs_vfsops, msdosfs, 0); 866