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 */ 64c4f02a89SMax Khon #include <sys/iconv.h> 65152ffafeSBruce Evans #include <sys/mutex.h> 66a18b1f1dSJason Evans 671166fb51SRuslan Ermilov #include <fs/msdosfs/bpb.h> 681166fb51SRuslan Ermilov #include <fs/msdosfs/bootsect.h> 69c4f02a89SMax Khon #include <fs/msdosfs/msdosfsmount.h> 701166fb51SRuslan Ermilov #include <fs/msdosfs/direntry.h> 711166fb51SRuslan Ermilov #include <fs/msdosfs/denode.h> 721166fb51SRuslan Ermilov #include <fs/msdosfs/fat.h> 7327a0bc89SDoug Rabson 743bc482ecSTim J. Robbins #include "opt_msdosfs.h" 753bc482ecSTim J. Robbins 76152ffafeSBruce Evans #define MSDOSFS_DFLTBSIZE 4096 77152ffafeSBruce Evans 7801f6cfbaSYoshihiro Takahashi #if 1 /*def PC98*/ 7901f6cfbaSYoshihiro Takahashi /* 8001f6cfbaSYoshihiro Takahashi * XXX - The boot signature formatted by NEC PC-98 DOS looks like a 8101f6cfbaSYoshihiro Takahashi * garbage or a random value :-{ 8201f6cfbaSYoshihiro Takahashi * If you want to use that broken-signatured media, define the 8301f6cfbaSYoshihiro Takahashi * following symbol even though PC/AT. 8401f6cfbaSYoshihiro Takahashi * (ex. mount PC-98 DOS formatted FD on PC/AT) 8501f6cfbaSYoshihiro Takahashi */ 8601f6cfbaSYoshihiro Takahashi #define MSDOSFS_NOCHECKSIG 8701f6cfbaSYoshihiro Takahashi #endif 8801f6cfbaSYoshihiro Takahashi 89a1c995b6SPoul-Henning Kamp MALLOC_DEFINE(M_MSDOSFSMNT, "MSDOSFS mount", "MSDOSFS mount structure"); 90a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_MSDOSFSFAT, "MSDOSFS FAT", "MSDOSFS file allocation table"); 9155166637SPoul-Henning Kamp 92c4f02a89SMax Khon struct iconv_functions *msdosfs_iconv = NULL; 93c4f02a89SMax Khon 94f257b7a5SAlfred Perlstein static int update_mp(struct mount *mp, struct msdosfs_args *argp, 95f257b7a5SAlfred Perlstein struct thread *td); 9611caded3SAlfred Perlstein static int mountmsdosfs(struct vnode *devvp, struct mount *mp, 9711caded3SAlfred Perlstein struct thread *td, struct msdosfs_args *argp); 989bf1a756SPoul-Henning Kamp static vfs_fhtovp_t msdosfs_fhtovp; 995e8c582aSPoul-Henning Kamp static vfs_omount_t msdosfs_omount; 1009bf1a756SPoul-Henning Kamp static vfs_root_t msdosfs_root; 1019bf1a756SPoul-Henning Kamp static vfs_statfs_t msdosfs_statfs; 1029bf1a756SPoul-Henning Kamp static vfs_sync_t msdosfs_sync; 1039bf1a756SPoul-Henning Kamp static vfs_unmount_t msdosfs_unmount; 1049bf1a756SPoul-Henning Kamp static vfs_vptofh_t msdosfs_vptofh; 105af482601SBruce Evans 106952a6212SJordan K. Hubbard static int 107f257b7a5SAlfred Perlstein update_mp(mp, argp, td) 108952a6212SJordan K. Hubbard struct mount *mp; 109952a6212SJordan K. Hubbard struct msdosfs_args *argp; 110f257b7a5SAlfred Perlstein struct thread *td; 111952a6212SJordan K. Hubbard { 112952a6212SJordan K. Hubbard struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 113952a6212SJordan K. Hubbard int error; 114952a6212SJordan K. Hubbard 115952a6212SJordan K. Hubbard pmp->pm_gid = argp->gid; 116952a6212SJordan K. Hubbard pmp->pm_uid = argp->uid; 117952a6212SJordan K. Hubbard pmp->pm_mask = argp->mask & ALLPERMS; 118c98a31caSTom Rhodes pmp->pm_dirmask = argp->dirmask & ALLPERMS; 119952a6212SJordan K. Hubbard pmp->pm_flags |= argp->flags & MSDOSFSMNT_MNTOPT; 120c4f02a89SMax Khon if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) { 121c4f02a89SMax Khon msdosfs_iconv->open(argp->cs_win, argp->cs_local , &pmp->pm_u2w); 122c4f02a89SMax Khon msdosfs_iconv->open(argp->cs_local, argp->cs_win , &pmp->pm_w2u); 123c4f02a89SMax Khon msdosfs_iconv->open(argp->cs_dos, argp->cs_local , &pmp->pm_u2d); 124c4f02a89SMax Khon msdosfs_iconv->open(argp->cs_local, argp->cs_dos , &pmp->pm_d2u); 125c4f02a89SMax Khon } else { 126c4f02a89SMax Khon pmp->pm_w2u = NULL; 127c4f02a89SMax Khon pmp->pm_u2w = NULL; 128c4f02a89SMax Khon pmp->pm_d2u = NULL; 129c4f02a89SMax Khon pmp->pm_u2d = NULL; 1307391f611SAndrey A. Chernov } 131952a6212SJordan K. Hubbard 132952a6212SJordan K. Hubbard if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 133952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 134952a6212SJordan K. Hubbard else if (!(pmp->pm_flags & 135952a6212SJordan K. Hubbard (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) { 136952a6212SJordan K. Hubbard struct vnode *rootvp; 137952a6212SJordan K. Hubbard 138952a6212SJordan K. Hubbard /* 139952a6212SJordan K. Hubbard * Try to divine whether to support Win'95 long filenames 140952a6212SJordan K. Hubbard */ 141952a6212SJordan K. Hubbard if (FAT32(pmp)) 142952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_LONGNAME; 143952a6212SJordan K. Hubbard else { 144f257b7a5SAlfred Perlstein if ((error = msdosfs_root(mp, &rootvp, td)) != 0) 145952a6212SJordan K. Hubbard return error; 146952a6212SJordan K. Hubbard pmp->pm_flags |= findwin95(VTODE(rootvp)) 147952a6212SJordan K. Hubbard ? MSDOSFSMNT_LONGNAME 148952a6212SJordan K. Hubbard : MSDOSFSMNT_SHORTNAME; 149952a6212SJordan K. Hubbard vput(rootvp); 150952a6212SJordan K. Hubbard } 151952a6212SJordan K. Hubbard } 152952a6212SJordan K. Hubbard return 0; 153952a6212SJordan K. Hubbard } 154952a6212SJordan K. Hubbard 15527a0bc89SDoug Rabson /* 15627a0bc89SDoug Rabson * mp - path - addr in user space of mount point (ie /usr or whatever) 15727a0bc89SDoug Rabson * data - addr in user space of mount params including the name of the block 15827a0bc89SDoug Rabson * special file to treat as a filesystem. 15927a0bc89SDoug Rabson */ 1607fefffeeSPoul-Henning Kamp static int 1615e8c582aSPoul-Henning Kamp msdosfs_omount(mp, path, data, td) 16227a0bc89SDoug Rabson struct mount *mp; 16327a0bc89SDoug Rabson char *path; 16427a0bc89SDoug Rabson caddr_t data; 165b40ce416SJulian Elischer struct thread *td; 16627a0bc89SDoug Rabson { 16727a0bc89SDoug Rabson struct vnode *devvp; /* vnode for blk device to mount */ 16827a0bc89SDoug Rabson struct msdosfs_args args; /* will hold data from mount request */ 169952a6212SJordan K. Hubbard /* msdosfs specific mount control block */ 170952a6212SJordan K. Hubbard struct msdosfsmount *pmp = NULL; 1715e8c582aSPoul-Henning Kamp struct nameidata ndp; 172952a6212SJordan K. Hubbard size_t size; 17327a0bc89SDoug Rabson int error, flags; 174952a6212SJordan K. Hubbard mode_t accessmode; 17527a0bc89SDoug Rabson 176c3c6d51eSPoul-Henning Kamp error = copyin(data, (caddr_t)&args, sizeof(struct msdosfs_args)); 177c3c6d51eSPoul-Henning Kamp if (error) 178952a6212SJordan K. Hubbard return (error); 179206faeeeSDmitrij Tejblum if (args.magic != MSDOSFS_ARGSMAGIC) 180952a6212SJordan K. Hubbard args.flags = 0; 18127a0bc89SDoug Rabson /* 182952a6212SJordan K. Hubbard * If updating, check whether changing from read-only to 183952a6212SJordan K. Hubbard * read/write; if there is no device name, that's all we do. 18427a0bc89SDoug Rabson */ 18527a0bc89SDoug Rabson if (mp->mnt_flag & MNT_UPDATE) { 186952a6212SJordan K. Hubbard pmp = VFSTOMSDOSFS(mp); 18727a0bc89SDoug Rabson error = 0; 188952a6212SJordan K. Hubbard if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_flag & MNT_RDONLY)) { 189e83f1423SPoul-Henning Kamp error = VFS_SYNC(mp, MNT_WAIT, td->td_ucred, td); 190e83f1423SPoul-Henning Kamp if (error) 191e83f1423SPoul-Henning Kamp return (error); 19227a0bc89SDoug Rabson flags = WRITECLOSE; 19327a0bc89SDoug Rabson if (mp->mnt_flag & MNT_FORCE) 19427a0bc89SDoug Rabson flags |= FORCECLOSE; 195f257b7a5SAlfred Perlstein error = vflush(mp, 0, flags, td); 19627a0bc89SDoug Rabson } 19727a0bc89SDoug Rabson if (!error && (mp->mnt_flag & MNT_RELOAD)) 19827a0bc89SDoug Rabson /* not yet implemented */ 199952a6212SJordan K. Hubbard error = EOPNOTSUPP; 20027a0bc89SDoug Rabson if (error) 201952a6212SJordan K. Hubbard return (error); 202952a6212SJordan K. Hubbard if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_kern_flag & MNTK_WANTRDWR)) { 203952a6212SJordan K. Hubbard /* 204952a6212SJordan K. Hubbard * If upgrade to read-write by non-root, then verify 205952a6212SJordan K. Hubbard * that user has necessary permissions on the device. 206952a6212SJordan K. Hubbard */ 20744731cabSJohn Baldwin if (suser(td)) { 208952a6212SJordan K. Hubbard devvp = pmp->pm_devvp; 209b40ce416SJulian Elischer vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); 210952a6212SJordan K. Hubbard error = VOP_ACCESS(devvp, VREAD | VWRITE, 211a854ed98SJohn Baldwin td->td_ucred, td); 212952a6212SJordan K. Hubbard if (error) { 213b40ce416SJulian Elischer VOP_UNLOCK(devvp, 0, td); 214952a6212SJordan K. Hubbard return (error); 215952a6212SJordan K. Hubbard } 216b40ce416SJulian Elischer VOP_UNLOCK(devvp, 0, td); 217952a6212SJordan K. Hubbard } 218952a6212SJordan K. Hubbard pmp->pm_flags &= ~MSDOSFSMNT_RONLY; 219cede1f56STom Rhodes 220a78c9287SBruce Evans /* Now that the volume is modifiable, mark it dirty. */ 221cede1f56STom Rhodes error = markvoldirty(pmp, 1); 222cede1f56STom Rhodes if (error) 223a78c9287SBruce Evans return (error); 224952a6212SJordan K. Hubbard } 22527a0bc89SDoug Rabson if (args.fspec == 0) { 226952a6212SJordan K. Hubbard #ifdef __notyet__ /* doesn't work correctly with current mountd XXX */ 227952a6212SJordan K. Hubbard if (args.flags & MSDOSFSMNT_MNTOPT) { 228952a6212SJordan K. Hubbard pmp->pm_flags &= ~MSDOSFSMNT_MNTOPT; 229952a6212SJordan K. Hubbard pmp->pm_flags |= args.flags & MSDOSFSMNT_MNTOPT; 230952a6212SJordan K. Hubbard if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 231952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 232952a6212SJordan K. Hubbard } 233952a6212SJordan K. Hubbard #endif 23427a0bc89SDoug Rabson /* 23527a0bc89SDoug Rabson * Process export requests. 23627a0bc89SDoug Rabson */ 2373bc482ecSTim J. Robbins if ((args.export.ex_flags & MNT_EXPORTED) != 0 && 2383bc482ecSTim J. Robbins (pmp->pm_flags & MSDOSFS_LARGEFS) != 0) 2393bc482ecSTim J. Robbins return (EOPNOTSUPP); 240a13234bbSPoul-Henning Kamp return (vfs_export(mp, &args.export)); 24127a0bc89SDoug Rabson } 242952a6212SJordan K. Hubbard } 24327a0bc89SDoug Rabson /* 244952a6212SJordan K. Hubbard * Not an update, or updating the name: look up the name 245e9827c6dSBruce Evans * and verify that it refers to a sensible disk device. 24627a0bc89SDoug Rabson */ 2475e8c582aSPoul-Henning Kamp NDINIT(&ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, td); 2485e8c582aSPoul-Henning Kamp error = namei(&ndp); 249952a6212SJordan K. Hubbard if (error) 250952a6212SJordan K. Hubbard return (error); 2515e8c582aSPoul-Henning Kamp devvp = ndp.ni_vp; 2525e8c582aSPoul-Henning Kamp NDFREE(&ndp, NDF_ONLY_PNBUF); 253952a6212SJordan K. Hubbard 254ba4ad1fcSPoul-Henning Kamp if (!vn_isdisk(devvp, &error)) { 25527a0bc89SDoug Rabson vrele(devvp); 256ba4ad1fcSPoul-Henning Kamp return (error); 25727a0bc89SDoug Rabson } 25827a0bc89SDoug Rabson /* 259952a6212SJordan K. Hubbard * If mount by non-root, then verify that user has necessary 260952a6212SJordan K. Hubbard * permissions on the device. 26127a0bc89SDoug Rabson */ 26244731cabSJohn Baldwin if (suser(td)) { 263952a6212SJordan K. Hubbard accessmode = VREAD; 264952a6212SJordan K. Hubbard if ((mp->mnt_flag & MNT_RDONLY) == 0) 265952a6212SJordan K. Hubbard accessmode |= VWRITE; 266b40ce416SJulian Elischer vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); 267a854ed98SJohn Baldwin error = VOP_ACCESS(devvp, accessmode, td->td_ucred, td); 268952a6212SJordan K. Hubbard if (error) { 269952a6212SJordan K. Hubbard vput(devvp); 270952a6212SJordan K. Hubbard return (error); 271952a6212SJordan K. Hubbard } 272b40ce416SJulian Elischer VOP_UNLOCK(devvp, 0, td); 273952a6212SJordan K. Hubbard } 274952a6212SJordan K. Hubbard if ((mp->mnt_flag & MNT_UPDATE) == 0) { 275b40ce416SJulian Elischer error = mountmsdosfs(devvp, mp, td, &args); 276952a6212SJordan K. Hubbard #ifdef MSDOSFS_DEBUG /* only needed for the printf below */ 277952a6212SJordan K. Hubbard pmp = VFSTOMSDOSFS(mp); 278952a6212SJordan K. Hubbard #endif 279952a6212SJordan K. Hubbard } else { 28027a0bc89SDoug Rabson if (devvp != pmp->pm_devvp) 281952a6212SJordan K. Hubbard error = EINVAL; /* XXX needs translation */ 28227a0bc89SDoug Rabson else 28327a0bc89SDoug Rabson vrele(devvp); 28427a0bc89SDoug Rabson } 28527a0bc89SDoug Rabson if (error) { 28627a0bc89SDoug Rabson vrele(devvp); 287952a6212SJordan K. Hubbard return (error); 288952a6212SJordan K. Hubbard } 289952a6212SJordan K. Hubbard 290f257b7a5SAlfred Perlstein error = update_mp(mp, &args, td); 291952a6212SJordan K. Hubbard if (error) { 292b40ce416SJulian Elischer msdosfs_unmount(mp, MNT_FORCE, td); 29327a0bc89SDoug Rabson return error; 29427a0bc89SDoug Rabson } 295952a6212SJordan K. Hubbard (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 296952a6212SJordan K. Hubbard &size); 297952a6212SJordan K. Hubbard bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 298b40ce416SJulian Elischer (void) msdosfs_statfs(mp, &mp->mnt_stat, td); 29927a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 3005e8c582aSPoul-Henning Kamp printf("msdosfs_omount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); 30127a0bc89SDoug Rabson #endif 302952a6212SJordan K. Hubbard return (0); 30327a0bc89SDoug Rabson } 30427a0bc89SDoug Rabson 3057fefffeeSPoul-Henning Kamp static int 306b40ce416SJulian Elischer mountmsdosfs(devvp, mp, td, argp) 30727a0bc89SDoug Rabson struct vnode *devvp; 30827a0bc89SDoug Rabson struct mount *mp; 309b40ce416SJulian Elischer struct thread *td; 310952a6212SJordan K. Hubbard struct msdosfs_args *argp; 31127a0bc89SDoug Rabson { 312952a6212SJordan K. Hubbard struct msdosfsmount *pmp; 313952a6212SJordan K. Hubbard struct buf *bp; 31489c9c53dSPoul-Henning Kamp struct cdev *dev = devvp->v_rdev; 31527a0bc89SDoug Rabson union bootsector *bsp; 31627a0bc89SDoug Rabson struct byte_bpb33 *b33; 31727a0bc89SDoug Rabson struct byte_bpb50 *b50; 318952a6212SJordan K. Hubbard struct byte_bpb710 *b710; 319952a6212SJordan K. Hubbard u_int8_t SecPerClust; 320499d3ffaSBoris Popov u_long clusters; 321952a6212SJordan K. Hubbard int ronly, error; 32227a0bc89SDoug Rabson 32327a0bc89SDoug Rabson /* 324952a6212SJordan K. Hubbard * Disallow multiple mounts of the same device. 325952a6212SJordan K. Hubbard * Disallow mounting of a device that is currently in use 326952a6212SJordan K. Hubbard * (except for root, which might share swap device for miniroot). 327952a6212SJordan K. Hubbard * Flush out any old buffers remaining from a previous use. 32827a0bc89SDoug Rabson */ 329c3c6d51eSPoul-Henning Kamp error = vfs_mountedon(devvp); 330c3c6d51eSPoul-Henning Kamp if (error) 331952a6212SJordan K. Hubbard return (error); 332d634f693SPoul-Henning Kamp if (vcount(devvp) > 1) 333952a6212SJordan K. Hubbard return (EBUSY); 334b40ce416SJulian Elischer vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); 335a854ed98SJohn Baldwin error = vinvalbuf(devvp, V_SAVE, td->td_ucred, td, 0, 0); 336e9827c6dSBruce Evans if (error) { 337b40ce416SJulian Elischer VOP_UNLOCK(devvp, 0, td); 338952a6212SJordan K. Hubbard return (error); 339e9827c6dSBruce Evans } 34027a0bc89SDoug Rabson 341952a6212SJordan K. Hubbard ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 342ae620d44STim J. Robbins /* 34367406320SBruce Evans * XXX: open the device with read and write access even if only 34467406320SBruce Evans * read access is needed now. Write access is needed if the 34567406320SBruce Evans * filesystem is ever mounted read/write, and we don't change the 34667406320SBruce Evans * access mode for remounts. 347ae620d44STim J. Robbins */ 348ae620d44STim J. Robbins #ifdef notyet 349a8d43c90SPoul-Henning Kamp error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE, FSCRED, td, -1); 350ae620d44STim J. Robbins #else 351a8d43c90SPoul-Henning Kamp error = VOP_OPEN(devvp, FREAD | FWRITE, FSCRED, td, -1); 352ae620d44STim J. Robbins #endif 353b40ce416SJulian Elischer VOP_UNLOCK(devvp, 0, td); 354c3c6d51eSPoul-Henning Kamp if (error) 355952a6212SJordan K. Hubbard return (error); 356952a6212SJordan K. Hubbard 357952a6212SJordan K. Hubbard bp = NULL; /* both used in error_exit */ 358952a6212SJordan K. Hubbard pmp = NULL; 359952a6212SJordan K. Hubbard 36027a0bc89SDoug Rabson /* 361952a6212SJordan K. Hubbard * Read the boot sector of the filesystem, and then check the 362952a6212SJordan K. Hubbard * boot signature. If not a dos boot sector then error out. 36301f6cfbaSYoshihiro Takahashi * 364152ffafeSBruce Evans * NOTE: 2048 is a maximum sector size in current... 36527a0bc89SDoug Rabson */ 366152ffafeSBruce Evans error = bread(devvp, 0, 2048, NOCRED, &bp); 367c3c6d51eSPoul-Henning Kamp if (error) 36827a0bc89SDoug Rabson goto error_exit; 369952a6212SJordan K. Hubbard bp->b_flags |= B_AGE; 370952a6212SJordan K. Hubbard bsp = (union bootsector *)bp->b_data; 37127a0bc89SDoug Rabson b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB; 37227a0bc89SDoug Rabson b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB; 37301a4d019SJohn Baldwin b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB; 374952a6212SJordan K. Hubbard 37501f6cfbaSYoshihiro Takahashi #ifndef MSDOSFS_NOCHECKSIG 376952a6212SJordan K. Hubbard if (bsp->bs50.bsBootSectSig0 != BOOTSIG0 377952a6212SJordan K. Hubbard || bsp->bs50.bsBootSectSig1 != BOOTSIG1) { 37827a0bc89SDoug Rabson error = EINVAL; 37927a0bc89SDoug Rabson goto error_exit; 38027a0bc89SDoug Rabson } 38101f6cfbaSYoshihiro Takahashi #endif 38227a0bc89SDoug Rabson 383a163d034SWarner Losh pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK | M_ZERO); 38427a0bc89SDoug Rabson pmp->pm_mountp = mp; 38527a0bc89SDoug Rabson 38627a0bc89SDoug Rabson /* 38727a0bc89SDoug Rabson * Compute several useful quantities from the bpb in the 38827a0bc89SDoug Rabson * bootsector. Copy in the dos 5 variant of the bpb then fix up 38927a0bc89SDoug Rabson * the fields that are different between dos 5 and dos 3.3. 39027a0bc89SDoug Rabson */ 391952a6212SJordan K. Hubbard SecPerClust = b50->bpbSecPerClust; 39227a0bc89SDoug Rabson pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 393696f22f0SJohn Baldwin if (pmp->pm_BytesPerSec < DEV_BSIZE) { 394696f22f0SJohn Baldwin error = EINVAL; 395696f22f0SJohn Baldwin goto error_exit; 396696f22f0SJohn Baldwin } 39727a0bc89SDoug Rabson pmp->pm_ResSectors = getushort(b50->bpbResSectors); 39827a0bc89SDoug Rabson pmp->pm_FATs = b50->bpbFATs; 39927a0bc89SDoug Rabson pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 40027a0bc89SDoug Rabson pmp->pm_Sectors = getushort(b50->bpbSectors); 40127a0bc89SDoug Rabson pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 40227a0bc89SDoug Rabson pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 40327a0bc89SDoug Rabson pmp->pm_Heads = getushort(b50->bpbHeads); 404952a6212SJordan K. Hubbard pmp->pm_Media = b50->bpbMedia; 40527a0bc89SDoug Rabson 40601f6cfbaSYoshihiro Takahashi /* calculate the ratio of sector size to DEV_BSIZE */ 40701f6cfbaSYoshihiro Takahashi pmp->pm_BlkPerSec = pmp->pm_BytesPerSec / DEV_BSIZE; 40801f6cfbaSYoshihiro Takahashi 40927a0bc89SDoug Rabson /* XXX - We should probably check more values here */ 410952a6212SJordan K. Hubbard if (!pmp->pm_BytesPerSec || !SecPerClust 4110ff34b5eSRobert Watson || !pmp->pm_Heads 412ad63a118SSatoshi Asami #ifdef PC98 413952a6212SJordan K. Hubbard || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) { 414ad63a118SSatoshi Asami #else 415952a6212SJordan K. Hubbard || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) { 416ad63a118SSatoshi Asami #endif 41727a0bc89SDoug Rabson error = EINVAL; 41827a0bc89SDoug Rabson goto error_exit; 41927a0bc89SDoug Rabson } 42027a0bc89SDoug Rabson 42127a0bc89SDoug Rabson if (pmp->pm_Sectors == 0) { 42227a0bc89SDoug Rabson pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 42327a0bc89SDoug Rabson pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 42427a0bc89SDoug Rabson } else { 42527a0bc89SDoug Rabson pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 42627a0bc89SDoug Rabson pmp->pm_HugeSectors = pmp->pm_Sectors; 42727a0bc89SDoug Rabson } 4283bc482ecSTim J. Robbins #ifndef MSDOSFS_LARGE 429c681be37SDmitrij Tejblum if (pmp->pm_HugeSectors > 0xffffffff / 430c681be37SDmitrij Tejblum (pmp->pm_BytesPerSec / sizeof(struct direntry)) + 1) { 431952a6212SJordan K. Hubbard /* 432952a6212SJordan K. Hubbard * We cannot deal currently with this size of disk 433952a6212SJordan K. Hubbard * due to fileid limitations (see msdosfs_getattr and 434952a6212SJordan K. Hubbard * msdosfs_readdir) 435952a6212SJordan K. Hubbard */ 436952a6212SJordan K. Hubbard error = EINVAL; 437aaf0bb19SAndrey A. Chernov printf("mountmsdosfs(): disk too big, sorry\n"); 438952a6212SJordan K. Hubbard goto error_exit; 439952a6212SJordan K. Hubbard } 4403bc482ecSTim J. Robbins #endif /* !MSDOSFS_LARGE */ 441952a6212SJordan K. Hubbard 442952a6212SJordan K. Hubbard if (pmp->pm_RootDirEnts == 0) { 443952a6212SJordan K. Hubbard if (bsp->bs710.bsBootSectSig2 != BOOTSIG2 444952a6212SJordan K. Hubbard || bsp->bs710.bsBootSectSig3 != BOOTSIG3 445952a6212SJordan K. Hubbard || pmp->pm_Sectors 446952a6212SJordan K. Hubbard || pmp->pm_FATsecs 447952a6212SJordan K. Hubbard || getushort(b710->bpbFSVers)) { 448952a6212SJordan K. Hubbard error = EINVAL; 449aaf0bb19SAndrey A. Chernov printf("mountmsdosfs(): bad FAT32 filesystem\n"); 450952a6212SJordan K. Hubbard goto error_exit; 451952a6212SJordan K. Hubbard } 452952a6212SJordan K. Hubbard pmp->pm_fatmask = FAT32_MASK; 453952a6212SJordan K. Hubbard pmp->pm_fatmult = 4; 454952a6212SJordan K. Hubbard pmp->pm_fatdiv = 1; 455952a6212SJordan K. Hubbard pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs); 456952a6212SJordan K. Hubbard if (getushort(b710->bpbExtFlags) & FATMIRROR) 457952a6212SJordan K. Hubbard pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM; 458952a6212SJordan K. Hubbard else 459952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFS_FATMIRROR; 460952a6212SJordan K. Hubbard } else 461952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFS_FATMIRROR; 462952a6212SJordan K. Hubbard 463952a6212SJordan K. Hubbard /* 464952a6212SJordan K. Hubbard * Check a few values (could do some more): 465952a6212SJordan K. Hubbard * - logical sector size: power of 2, >= block size 466952a6212SJordan K. Hubbard * - sectors per cluster: power of 2, >= 1 467952a6212SJordan K. Hubbard * - number of sectors: >= 1, <= size of partition 468696f22f0SJohn Baldwin * - number of FAT sectors: >= 1 469952a6212SJordan K. Hubbard */ 470952a6212SJordan K. Hubbard if ( (SecPerClust == 0) 471952a6212SJordan K. Hubbard || (SecPerClust & (SecPerClust - 1)) 47201f6cfbaSYoshihiro Takahashi || (pmp->pm_BytesPerSec < DEV_BSIZE) 473952a6212SJordan K. Hubbard || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) 474952a6212SJordan K. Hubbard || (pmp->pm_HugeSectors == 0) 475696f22f0SJohn Baldwin || (pmp->pm_FATsecs == 0) 476952a6212SJordan K. Hubbard ) { 477952a6212SJordan K. Hubbard error = EINVAL; 478952a6212SJordan K. Hubbard goto error_exit; 479952a6212SJordan K. Hubbard } 48001f6cfbaSYoshihiro Takahashi 48101f6cfbaSYoshihiro Takahashi pmp->pm_HugeSectors *= pmp->pm_BlkPerSec; 48201f6cfbaSYoshihiro Takahashi pmp->pm_HiddenSects *= pmp->pm_BlkPerSec; /* XXX not used? */ 48301f6cfbaSYoshihiro Takahashi pmp->pm_FATsecs *= pmp->pm_BlkPerSec; 48401f6cfbaSYoshihiro Takahashi SecPerClust *= pmp->pm_BlkPerSec; 48501f6cfbaSYoshihiro Takahashi 48601f6cfbaSYoshihiro Takahashi pmp->pm_fatblk = pmp->pm_ResSectors * pmp->pm_BlkPerSec; 48701f6cfbaSYoshihiro Takahashi 488952a6212SJordan K. Hubbard if (FAT32(pmp)) { 489952a6212SJordan K. Hubbard pmp->pm_rootdirblk = getulong(b710->bpbRootClust); 490952a6212SJordan K. Hubbard pmp->pm_firstcluster = pmp->pm_fatblk 491952a6212SJordan K. Hubbard + (pmp->pm_FATs * pmp->pm_FATsecs); 49201f6cfbaSYoshihiro Takahashi pmp->pm_fsinfo = getushort(b710->bpbFSInfo) * pmp->pm_BlkPerSec; 493952a6212SJordan K. Hubbard } else { 49427a0bc89SDoug Rabson pmp->pm_rootdirblk = pmp->pm_fatblk + 49527a0bc89SDoug Rabson (pmp->pm_FATs * pmp->pm_FATsecs); 496952a6212SJordan K. Hubbard pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry) 49701f6cfbaSYoshihiro Takahashi + DEV_BSIZE - 1) 49801f6cfbaSYoshihiro Takahashi / DEV_BSIZE; /* in blocks */ 49927a0bc89SDoug Rabson pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 500952a6212SJordan K. Hubbard } 501952a6212SJordan K. Hubbard 502499d3ffaSBoris Popov pmp->pm_maxcluster = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 503499d3ffaSBoris Popov SecPerClust + 1; 50401f6cfbaSYoshihiro Takahashi pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE; /* XXX not used? */ 505952a6212SJordan K. Hubbard 506952a6212SJordan K. Hubbard if (pmp->pm_fatmask == 0) { 507952a6212SJordan K. Hubbard if (pmp->pm_maxcluster 508952a6212SJordan K. Hubbard <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) { 50927a0bc89SDoug Rabson /* 510952a6212SJordan K. Hubbard * This will usually be a floppy disk. This size makes 511952a6212SJordan K. Hubbard * sure that one fat entry will not be split across 512952a6212SJordan K. Hubbard * multiple blocks. 51327a0bc89SDoug Rabson */ 514952a6212SJordan K. Hubbard pmp->pm_fatmask = FAT12_MASK; 515952a6212SJordan K. Hubbard pmp->pm_fatmult = 3; 516952a6212SJordan K. Hubbard pmp->pm_fatdiv = 2; 517952a6212SJordan K. Hubbard } else { 518952a6212SJordan K. Hubbard pmp->pm_fatmask = FAT16_MASK; 519952a6212SJordan K. Hubbard pmp->pm_fatmult = 2; 520952a6212SJordan K. Hubbard pmp->pm_fatdiv = 1; 521952a6212SJordan K. Hubbard } 522952a6212SJordan K. Hubbard } 523499d3ffaSBoris Popov 524499d3ffaSBoris Popov clusters = (pmp->pm_fatsize / pmp->pm_fatmult) * pmp->pm_fatdiv; 525499d3ffaSBoris Popov if (pmp->pm_maxcluster >= clusters) { 526499d3ffaSBoris Popov printf("Warning: number of clusters (%ld) exceeds FAT " 527499d3ffaSBoris Popov "capacity (%ld)\n", pmp->pm_maxcluster + 1, clusters); 528499d3ffaSBoris Popov pmp->pm_maxcluster = clusters - 1; 529499d3ffaSBoris Popov } 530499d3ffaSBoris Popov 531499d3ffaSBoris Popov 532952a6212SJordan K. Hubbard if (FAT12(pmp)) 53327a0bc89SDoug Rabson pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; 53427a0bc89SDoug Rabson else 535152ffafeSBruce Evans pmp->pm_fatblocksize = MSDOSFS_DFLTBSIZE; 536952a6212SJordan K. Hubbard 53701f6cfbaSYoshihiro Takahashi pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE; 53801f6cfbaSYoshihiro Takahashi pmp->pm_bnshift = ffs(DEV_BSIZE) - 1; 53927a0bc89SDoug Rabson 54027a0bc89SDoug Rabson /* 54127a0bc89SDoug Rabson * Compute mask and shift value for isolating cluster relative byte 54227a0bc89SDoug Rabson * offsets and cluster numbers from a file offset. 54327a0bc89SDoug Rabson */ 54401f6cfbaSYoshihiro Takahashi pmp->pm_bpcluster = SecPerClust * DEV_BSIZE; 545952a6212SJordan K. Hubbard pmp->pm_crbomask = pmp->pm_bpcluster - 1; 546952a6212SJordan K. Hubbard pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1; 54727a0bc89SDoug Rabson 548952a6212SJordan K. Hubbard /* 549952a6212SJordan K. Hubbard * Check for valid cluster size 550952a6212SJordan K. Hubbard * must be a power of 2 551952a6212SJordan K. Hubbard */ 552952a6212SJordan K. Hubbard if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) { 553952a6212SJordan K. Hubbard error = EINVAL; 554952a6212SJordan K. Hubbard goto error_exit; 555ad63a118SSatoshi Asami } 55627a0bc89SDoug Rabson 55727a0bc89SDoug Rabson /* 55827a0bc89SDoug Rabson * Release the bootsector buffer. 55927a0bc89SDoug Rabson */ 560952a6212SJordan K. Hubbard brelse(bp); 561952a6212SJordan K. Hubbard bp = NULL; 562952a6212SJordan K. Hubbard 563952a6212SJordan K. Hubbard /* 564952a6212SJordan K. Hubbard * Check FSInfo. 565952a6212SJordan K. Hubbard */ 566952a6212SJordan K. Hubbard if (pmp->pm_fsinfo) { 567952a6212SJordan K. Hubbard struct fsinfo *fp; 568952a6212SJordan K. Hubbard 56901f6cfbaSYoshihiro Takahashi if ((error = bread(devvp, pmp->pm_fsinfo, fsi_size(pmp), 57001f6cfbaSYoshihiro Takahashi NOCRED, &bp)) != 0) 571952a6212SJordan K. Hubbard goto error_exit; 572952a6212SJordan K. Hubbard fp = (struct fsinfo *)bp->b_data; 573952a6212SJordan K. Hubbard if (!bcmp(fp->fsisig1, "RRaA", 4) 574952a6212SJordan K. Hubbard && !bcmp(fp->fsisig2, "rrAa", 4) 575952a6212SJordan K. Hubbard && !bcmp(fp->fsisig3, "\0\0\125\252", 4) 5768bb386f2STim J. Robbins && !bcmp(fp->fsisig4, "\0\0\125\252", 4)) { 577952a6212SJordan K. Hubbard pmp->pm_nxtfree = getulong(fp->fsinxtfree); 5788bb386f2STim J. Robbins if (pmp->pm_nxtfree == 0xffffffff) 5798bb386f2STim J. Robbins pmp->pm_nxtfree = CLUST_FIRST; 5808bb386f2STim J. Robbins } else 581952a6212SJordan K. Hubbard pmp->pm_fsinfo = 0; 582952a6212SJordan K. Hubbard brelse(bp); 583952a6212SJordan K. Hubbard bp = NULL; 584952a6212SJordan K. Hubbard } 585952a6212SJordan K. Hubbard 586952a6212SJordan K. Hubbard /* 587abe78e97STom Rhodes * Check and validate (or perhaps invalidate?) the fsinfo structure? 588952a6212SJordan K. Hubbard */ 589abe78e97STom Rhodes if (pmp->pm_fsinfo && pmp->pm_nxtfree > pmp->pm_maxcluster) { 59034bdf0dcSBruce Evans printf( 59134bdf0dcSBruce Evans "Next free cluster in FSInfo (%lu) exceeds maxcluster (%lu)\n", 592abe78e97STom Rhodes pmp->pm_nxtfree, pmp->pm_maxcluster); 593abe78e97STom Rhodes error = EINVAL; 594abe78e97STom Rhodes goto error_exit; 595abe78e97STom Rhodes } 59627a0bc89SDoug Rabson 59727a0bc89SDoug Rabson /* 59827a0bc89SDoug Rabson * Allocate memory for the bitmap of allocated clusters, and then 59927a0bc89SDoug Rabson * fill it in. 60027a0bc89SDoug Rabson */ 6010ef0dd6fSBruce Evans pmp->pm_inusemap = malloc(howmany(pmp->pm_maxcluster + 1, N_INUSEBITS) 60227a0bc89SDoug Rabson * sizeof(*pmp->pm_inusemap), 603a163d034SWarner Losh M_MSDOSFSFAT, M_WAITOK); 60427a0bc89SDoug Rabson 60527a0bc89SDoug Rabson /* 60627a0bc89SDoug Rabson * fillinusemap() needs pm_devvp. 60727a0bc89SDoug Rabson */ 60827a0bc89SDoug Rabson pmp->pm_dev = dev; 60927a0bc89SDoug Rabson pmp->pm_devvp = devvp; 61027a0bc89SDoug Rabson 61127a0bc89SDoug Rabson /* 61227a0bc89SDoug Rabson * Have the inuse map filled in. 61327a0bc89SDoug Rabson */ 614952a6212SJordan K. Hubbard if ((error = fillinusemap(pmp)) != 0) 61527a0bc89SDoug Rabson goto error_exit; 61627a0bc89SDoug Rabson 61727a0bc89SDoug Rabson /* 61827a0bc89SDoug Rabson * If they want fat updates to be synchronous then let them suffer 61927a0bc89SDoug Rabson * the performance degradation in exchange for the on disk copy of 62027a0bc89SDoug Rabson * the fat being correct just about all the time. I suppose this 62127a0bc89SDoug Rabson * would be a good thing to turn on if the kernel is still flakey. 62227a0bc89SDoug Rabson */ 623952a6212SJordan K. Hubbard if (mp->mnt_flag & MNT_SYNCHRONOUS) 624952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_WAITONFAT; 62527a0bc89SDoug Rabson 62627a0bc89SDoug Rabson /* 62727a0bc89SDoug Rabson * Finish up. 62827a0bc89SDoug Rabson */ 629952a6212SJordan K. Hubbard if (ronly) 630952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_RONLY; 631cede1f56STom Rhodes else { 632a78c9287SBruce Evans /* Mark the volume dirty while it is mounted read/write. */ 633cede1f56STom Rhodes if ((error = markvoldirty(pmp, 1)) != 0) 634cede1f56STom Rhodes goto error_exit; 63527a0bc89SDoug Rabson pmp->pm_fmod = 1; 636cede1f56STom Rhodes } 63727a0bc89SDoug Rabson mp->mnt_data = (qaddr_t) pmp; 638939cb752SBruce Evans mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); 639af3f60d5SBruce Evans mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 640cc9d8990SPeter Wemm mp->mnt_flag |= MNT_LOCAL; 6417eb9fca5SEivind Eklund devvp->v_rdev->si_mountpoint = mp; 64227a0bc89SDoug Rabson 6433bc482ecSTim J. Robbins #ifdef MSDOSFS_LARGE 6443bc482ecSTim J. Robbins msdosfs_fileno_init(mp); 6453bc482ecSTim J. Robbins #endif 6463bc482ecSTim J. Robbins 64727a0bc89SDoug Rabson return 0; 64827a0bc89SDoug Rabson 649952a6212SJordan K. Hubbard error_exit: 650952a6212SJordan K. Hubbard if (bp) 651952a6212SJordan K. Hubbard brelse(bp); 65267406320SBruce Evans /* XXX: see comment above VOP_OPEN. */ 653ae620d44STim J. Robbins #ifdef notyet 654b40ce416SJulian Elischer (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE, NOCRED, td); 655ae620d44STim J. Robbins #else 656ae620d44STim J. Robbins (void)VOP_CLOSE(devvp, FREAD | FWRITE, NOCRED, td); 657ae620d44STim J. Robbins #endif 65827a0bc89SDoug Rabson if (pmp) { 65927a0bc89SDoug Rabson if (pmp->pm_inusemap) 660952a6212SJordan K. Hubbard free(pmp->pm_inusemap, M_MSDOSFSFAT); 661952a6212SJordan K. Hubbard free(pmp, M_MSDOSFSMNT); 66227a0bc89SDoug Rabson mp->mnt_data = (qaddr_t)0; 66327a0bc89SDoug Rabson } 664952a6212SJordan K. Hubbard return (error); 66527a0bc89SDoug Rabson } 66627a0bc89SDoug Rabson 66727a0bc89SDoug Rabson /* 66827a0bc89SDoug Rabson * Unmount the filesystem described by mp. 66927a0bc89SDoug Rabson */ 6707fefffeeSPoul-Henning Kamp static int 671b40ce416SJulian Elischer msdosfs_unmount(mp, mntflags, td) 67227a0bc89SDoug Rabson struct mount *mp; 67327a0bc89SDoug Rabson int mntflags; 674b40ce416SJulian Elischer struct thread *td; 67527a0bc89SDoug Rabson { 676952a6212SJordan K. Hubbard struct msdosfsmount *pmp; 677952a6212SJordan K. Hubbard int error, flags; 67827a0bc89SDoug Rabson 679952a6212SJordan K. Hubbard flags = 0; 680952a6212SJordan K. Hubbard if (mntflags & MNT_FORCE) 68127a0bc89SDoug Rabson flags |= FORCECLOSE; 682f257b7a5SAlfred Perlstein error = vflush(mp, 0, flags, td); 683c3c6d51eSPoul-Henning Kamp if (error) 68427a0bc89SDoug Rabson return error; 685952a6212SJordan K. Hubbard pmp = VFSTOMSDOSFS(mp); 686c4f02a89SMax Khon if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) { 687c4f02a89SMax Khon if (pmp->pm_w2u) 688c4f02a89SMax Khon msdosfs_iconv->close(pmp->pm_w2u); 689c4f02a89SMax Khon if (pmp->pm_u2w) 690c4f02a89SMax Khon msdosfs_iconv->close(pmp->pm_u2w); 691c4f02a89SMax Khon if (pmp->pm_d2u) 692c4f02a89SMax Khon msdosfs_iconv->close(pmp->pm_d2u); 693c4f02a89SMax Khon if (pmp->pm_u2d) 694c4f02a89SMax Khon msdosfs_iconv->close(pmp->pm_u2d); 695c4f02a89SMax Khon } 6967eb9fca5SEivind Eklund pmp->pm_devvp->v_rdev->si_mountpoint = NULL; 697cede1f56STom Rhodes 698a78c9287SBruce Evans /* If the volume was mounted read/write, mark it clean now. */ 699cede1f56STom Rhodes if ((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0) { 700cede1f56STom Rhodes error = markvoldirty(pmp, 0); 701a78c9287SBruce Evans if (error && (flags & FORCECLOSE) == 0) 702cede1f56STom Rhodes return (error); 703cede1f56STom Rhodes } 704952a6212SJordan K. Hubbard #ifdef MSDOSFS_DEBUG 705952a6212SJordan K. Hubbard { 706952a6212SJordan K. Hubbard struct vnode *vp = pmp->pm_devvp; 707952a6212SJordan K. Hubbard 7084d93c0beSJeff Roberson VI_LOCK(vp); 709952a6212SJordan K. Hubbard printf("msdosfs_umount(): just before calling VOP_CLOSE()\n"); 710e6e370a7SJeff Roberson printf("iflag %08lx, usecount %d, writecount %d, holdcnt %ld\n", 711e6e370a7SJeff Roberson vp->vi_flag, vp->v_usecount, vp->v_writecount, 712e6e370a7SJeff Roberson vp->v_holdcnt); 71367ddfcafSMatthew Dillon printf("id %lu, mount %p, op %p\n", 71467ddfcafSMatthew Dillon vp->v_id, vp->v_mount, vp->v_op); 715952a6212SJordan K. Hubbard printf("freef %p, freeb %p, mount %p\n", 716fc2ffbe6SPoul-Henning Kamp TAILQ_NEXT(vp, v_freelist), vp->v_freelist.tqe_prev, 717952a6212SJordan K. Hubbard vp->v_mount); 718952a6212SJordan K. Hubbard printf("cleanblkhd %p, dirtyblkhd %p, numoutput %ld, type %d\n", 71940c8cfe5SPeter Wemm TAILQ_FIRST(&vp->v_cleanblkhd), 72040c8cfe5SPeter Wemm TAILQ_FIRST(&vp->v_dirtyblkhd), 721952a6212SJordan K. Hubbard vp->v_numoutput, vp->v_type); 72206be2aaaSNate Lawson printf("union %p, tag %s, data[0] %08x, data[1] %08x\n", 723952a6212SJordan K. Hubbard vp->v_socket, vp->v_tag, 724952a6212SJordan K. Hubbard ((u_int *)vp->v_data)[0], 725952a6212SJordan K. Hubbard ((u_int *)vp->v_data)[1]); 7264d93c0beSJeff Roberson VI_UNLOCK(vp); 727952a6212SJordan K. Hubbard } 728952a6212SJordan K. Hubbard #endif 72967406320SBruce Evans /* XXX: see comment above VOP_OPEN. */ 730ae620d44STim J. Robbins #ifdef notyet 731b1897c19SJulian Elischer error = VOP_CLOSE(pmp->pm_devvp, 732b1897c19SJulian Elischer (pmp->pm_flags & MSDOSFSMNT_RONLY) ? FREAD : FREAD | FWRITE, 733b40ce416SJulian Elischer NOCRED, td); 734ae620d44STim J. Robbins #else 735ae620d44STim J. Robbins error = VOP_CLOSE(pmp->pm_devvp, FREAD | FWRITE, NOCRED, td); 736ae620d44STim J. Robbins #endif 73727a0bc89SDoug Rabson vrele(pmp->pm_devvp); 738952a6212SJordan K. Hubbard free(pmp->pm_inusemap, M_MSDOSFSFAT); 7393bc482ecSTim J. Robbins #ifdef MSDOSFS_LARGE 7403bc482ecSTim J. Robbins msdosfs_fileno_free(mp); 7413bc482ecSTim J. Robbins #endif 742952a6212SJordan K. Hubbard free(pmp, M_MSDOSFSMNT); 74327a0bc89SDoug Rabson mp->mnt_data = (qaddr_t)0; 744cc9d8990SPeter Wemm mp->mnt_flag &= ~MNT_LOCAL; 745952a6212SJordan K. Hubbard return (error); 74627a0bc89SDoug Rabson } 74727a0bc89SDoug Rabson 7487fefffeeSPoul-Henning Kamp static int 749f257b7a5SAlfred Perlstein msdosfs_root(mp, vpp, td) 75027a0bc89SDoug Rabson struct mount *mp; 75127a0bc89SDoug Rabson struct vnode **vpp; 752f257b7a5SAlfred Perlstein struct thread *td; 75327a0bc89SDoug Rabson { 754952a6212SJordan K. Hubbard struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 75527a0bc89SDoug Rabson struct denode *ndep; 75627a0bc89SDoug Rabson int error; 75727a0bc89SDoug Rabson 75827a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 759952a6212SJordan K. Hubbard printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp); 76027a0bc89SDoug Rabson #endif 761952a6212SJordan K. Hubbard error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep); 762952a6212SJordan K. Hubbard if (error) 763952a6212SJordan K. Hubbard return (error); 76427a0bc89SDoug Rabson *vpp = DETOV(ndep); 765952a6212SJordan K. Hubbard return (0); 76627a0bc89SDoug Rabson } 76727a0bc89SDoug Rabson 7687fefffeeSPoul-Henning Kamp static int 769b40ce416SJulian Elischer msdosfs_statfs(mp, sbp, td) 77027a0bc89SDoug Rabson struct mount *mp; 77127a0bc89SDoug Rabson struct statfs *sbp; 772b40ce416SJulian Elischer struct thread *td; 77327a0bc89SDoug Rabson { 774952a6212SJordan K. Hubbard struct msdosfsmount *pmp; 77527a0bc89SDoug Rabson 776952a6212SJordan K. Hubbard pmp = VFSTOMSDOSFS(mp); 77727a0bc89SDoug Rabson sbp->f_bsize = pmp->pm_bpcluster; 77827a0bc89SDoug Rabson sbp->f_iosize = pmp->pm_bpcluster; 779499d3ffaSBoris Popov sbp->f_blocks = pmp->pm_maxcluster + 1; 78027a0bc89SDoug Rabson sbp->f_bfree = pmp->pm_freeclustercount; 78127a0bc89SDoug Rabson sbp->f_bavail = pmp->pm_freeclustercount; 78227a0bc89SDoug Rabson sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ 78327a0bc89SDoug Rabson sbp->f_ffree = 0; /* what to put in here? */ 78427a0bc89SDoug Rabson if (sbp != &mp->mnt_stat) { 785af3f60d5SBruce Evans sbp->f_type = mp->mnt_vfc->vfc_typenum; 786952a6212SJordan K. Hubbard bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 787952a6212SJordan K. Hubbard bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 78827a0bc89SDoug Rabson } 789952a6212SJordan K. Hubbard strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN); 790952a6212SJordan K. Hubbard return (0); 79127a0bc89SDoug Rabson } 79227a0bc89SDoug Rabson 7937fefffeeSPoul-Henning Kamp static int 794b40ce416SJulian Elischer msdosfs_sync(mp, waitfor, cred, td) 79527a0bc89SDoug Rabson struct mount *mp; 79627a0bc89SDoug Rabson int waitfor; 79727a0bc89SDoug Rabson struct ucred *cred; 798b40ce416SJulian Elischer struct thread *td; 79927a0bc89SDoug Rabson { 800952a6212SJordan K. Hubbard struct vnode *vp, *nvp; 80127a0bc89SDoug Rabson struct denode *dep; 802952a6212SJordan K. Hubbard struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 803952a6212SJordan K. Hubbard int error, allerror = 0; 80427a0bc89SDoug Rabson 80527a0bc89SDoug Rabson /* 80627a0bc89SDoug Rabson * If we ever switch to not updating all of the fats all the time, 80727a0bc89SDoug Rabson * this would be the place to update them from the first one. 80827a0bc89SDoug Rabson */ 809dfd5dee1SPeter Wemm if (pmp->pm_fmod != 0) { 810952a6212SJordan K. Hubbard if (pmp->pm_flags & MSDOSFSMNT_RONLY) 81127a0bc89SDoug Rabson panic("msdosfs_sync: rofs mod"); 81227a0bc89SDoug Rabson else { 81327a0bc89SDoug Rabson /* update fats here */ 81427a0bc89SDoug Rabson } 815dfd5dee1SPeter Wemm } 81627a0bc89SDoug Rabson /* 817952a6212SJordan K. Hubbard * Write back each (modified) denode. 81827a0bc89SDoug Rabson */ 819ca430f2eSAlexander Kabaev MNT_ILOCK(mp); 82027a0bc89SDoug Rabson loop: 821e3c5a7a4SPoul-Henning Kamp MNT_VNODE_FOREACH(vp, mp, nvp) { 8224d93c0beSJeff Roberson VI_LOCK(vp); 8234ab2c8bdSJeff Roberson if (vp->v_iflag & VI_XLOCK) { 8244ab2c8bdSJeff Roberson VI_UNLOCK(vp); 8254ab2c8bdSJeff Roberson continue; 8264ab2c8bdSJeff Roberson } 827ca430f2eSAlexander Kabaev MNT_IUNLOCK(mp); 82827a0bc89SDoug Rabson dep = VTODE(vp); 829c681be37SDmitrij Tejblum if (vp->v_type == VNON || 830831a80b0SMatthew Dillon ((dep->de_flag & 831c681be37SDmitrij Tejblum (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0 && 832152ffafeSBruce Evans (TAILQ_EMPTY(&vp->v_dirtyblkhd) || waitfor == MNT_LAZY))) { 8334d93c0beSJeff Roberson VI_UNLOCK(vp); 834ca430f2eSAlexander Kabaev MNT_ILOCK(mp); 83527a0bc89SDoug Rabson continue; 836af3f60d5SBruce Evans } 837b40ce416SJulian Elischer error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, td); 838af3f60d5SBruce Evans if (error) { 839ca430f2eSAlexander Kabaev MNT_ILOCK(mp); 840af3f60d5SBruce Evans if (error == ENOENT) 84127a0bc89SDoug Rabson goto loop; 842af3f60d5SBruce Evans continue; 843af3f60d5SBruce Evans } 844b40ce416SJulian Elischer error = VOP_FSYNC(vp, cred, waitfor, td); 845c3c6d51eSPoul-Henning Kamp if (error) 84627a0bc89SDoug Rabson allerror = error; 847cb9ddc80SAlexander Kabaev VOP_UNLOCK(vp, 0, td); 848cb9ddc80SAlexander Kabaev vrele(vp); 849ca430f2eSAlexander Kabaev MNT_ILOCK(mp); 85027a0bc89SDoug Rabson } 851ca430f2eSAlexander Kabaev MNT_IUNLOCK(mp); 85227a0bc89SDoug Rabson 85327a0bc89SDoug Rabson /* 85427a0bc89SDoug Rabson * Flush filesystem control info. 85527a0bc89SDoug Rabson */ 856c681be37SDmitrij Tejblum if (waitfor != MNT_LAZY) { 857b40ce416SJulian Elischer vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY, td); 858b40ce416SJulian Elischer error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, td); 859c3c6d51eSPoul-Henning Kamp if (error) 86027a0bc89SDoug Rabson allerror = error; 861b40ce416SJulian Elischer VOP_UNLOCK(pmp->pm_devvp, 0, td); 862c681be37SDmitrij Tejblum } 863952a6212SJordan K. Hubbard return (allerror); 86427a0bc89SDoug Rabson } 86527a0bc89SDoug Rabson 8667fefffeeSPoul-Henning Kamp static int 867c24fda81SAlfred Perlstein msdosfs_fhtovp(mp, fhp, vpp) 86827a0bc89SDoug Rabson struct mount *mp; 86927a0bc89SDoug Rabson struct fid *fhp; 87027a0bc89SDoug Rabson struct vnode **vpp; 87127a0bc89SDoug Rabson { 872952a6212SJordan K. Hubbard struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 87327a0bc89SDoug Rabson struct defid *defhp = (struct defid *) fhp; 87427a0bc89SDoug Rabson struct denode *dep; 87527a0bc89SDoug Rabson int error; 87627a0bc89SDoug Rabson 877952a6212SJordan K. Hubbard error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep); 87827a0bc89SDoug Rabson if (error) { 87927a0bc89SDoug Rabson *vpp = NULLVP; 880952a6212SJordan K. Hubbard return (error); 88127a0bc89SDoug Rabson } 88227a0bc89SDoug Rabson *vpp = DETOV(dep); 883c24fda81SAlfred Perlstein return (0); 884c24fda81SAlfred Perlstein } 885c24fda81SAlfred Perlstein 886c24fda81SAlfred Perlstein static int 88727a0bc89SDoug Rabson msdosfs_vptofh(vp, fhp) 88827a0bc89SDoug Rabson struct vnode *vp; 88927a0bc89SDoug Rabson struct fid *fhp; 89027a0bc89SDoug Rabson { 891952a6212SJordan K. Hubbard struct denode *dep; 892952a6212SJordan K. Hubbard struct defid *defhp; 89327a0bc89SDoug Rabson 894952a6212SJordan K. Hubbard dep = VTODE(vp); 895952a6212SJordan K. Hubbard defhp = (struct defid *)fhp; 89627a0bc89SDoug Rabson defhp->defid_len = sizeof(struct defid); 89727a0bc89SDoug Rabson defhp->defid_dirclust = dep->de_dirclust; 89827a0bc89SDoug Rabson defhp->defid_dirofs = dep->de_diroffset; 899952a6212SJordan K. Hubbard /* defhp->defid_gen = dep->de_gen; */ 900952a6212SJordan K. Hubbard return (0); 90127a0bc89SDoug Rabson } 90227a0bc89SDoug Rabson 90330ffadf3SPoul-Henning Kamp static struct vfsops msdosfs_vfsops = { 9047652131bSPoul-Henning Kamp .vfs_fhtovp = msdosfs_fhtovp, 9057652131bSPoul-Henning Kamp .vfs_init = msdosfs_init, 9065e8c582aSPoul-Henning Kamp .vfs_omount = msdosfs_omount, 9077652131bSPoul-Henning Kamp .vfs_root = msdosfs_root, 9087652131bSPoul-Henning Kamp .vfs_statfs = msdosfs_statfs, 9097652131bSPoul-Henning Kamp .vfs_sync = msdosfs_sync, 9107652131bSPoul-Henning Kamp .vfs_uninit = msdosfs_uninit, 9117652131bSPoul-Henning Kamp .vfs_unmount = msdosfs_unmount, 9127652131bSPoul-Henning Kamp .vfs_vptofh = msdosfs_vptofh, 91327a0bc89SDoug Rabson }; 914c901836cSGarrett Wollman 9154ccd7546SRuslan Ermilov VFS_SET(msdosfs_vfsops, msdosfs, 0); 916c4f02a89SMax Khon MODULE_VERSION(msdosfs, 1); 917