msdosfs_vfsops.c revision 138689
150477Speter/* $FreeBSD: head/sys/fs/msdosfs/msdosfs_vfsops.c 138689 2004-12-11 20:37:48Z phk $ */ 233548Sjkh/* $NetBSD: msdosfs_vfsops.c,v 1.51 1997/11/17 15:36:58 ws Exp $ */ 32893Sdfr 42893Sdfr/*- 533548Sjkh * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. 633548Sjkh * Copyright (C) 1994, 1995, 1997 TooLs GmbH. 72893Sdfr * All rights reserved. 82893Sdfr * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 92893Sdfr * 102893Sdfr * Redistribution and use in source and binary forms, with or without 112893Sdfr * modification, are permitted provided that the following conditions 122893Sdfr * are met: 132893Sdfr * 1. Redistributions of source code must retain the above copyright 142893Sdfr * notice, this list of conditions and the following disclaimer. 152893Sdfr * 2. Redistributions in binary form must reproduce the above copyright 162893Sdfr * notice, this list of conditions and the following disclaimer in the 172893Sdfr * documentation and/or other materials provided with the distribution. 182893Sdfr * 3. All advertising materials mentioning features or use of this software 192893Sdfr * must display the following acknowledgement: 202893Sdfr * This product includes software developed by TooLs GmbH. 212893Sdfr * 4. The name of TooLs GmbH may not be used to endorse or promote products 222893Sdfr * derived from this software without specific prior written permission. 232893Sdfr * 242893Sdfr * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 252893Sdfr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 262893Sdfr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 272893Sdfr * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 282893Sdfr * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 292893Sdfr * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 302893Sdfr * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 312893Sdfr * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 322893Sdfr * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 332893Sdfr * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 342893Sdfr */ 352893Sdfr/* 362893Sdfr * Written by Paul Popelka (paulp@uts.amdahl.com) 378876Srgrimes * 382893Sdfr * You can do anything you want with this software, just don't say you wrote 392893Sdfr * it, and don't remove this notice. 408876Srgrimes * 412893Sdfr * This software is provided "as is". 428876Srgrimes * 432893Sdfr * The author supplies this software to be publicly redistributed on the 442893Sdfr * understanding that the author is not responsible for the correct 452893Sdfr * functioning of this software in any circumstances and is not liable for 462893Sdfr * any damages caused by this software. 478876Srgrimes * 482893Sdfr * October 1992 492893Sdfr */ 502893Sdfr 512893Sdfr#include <sys/param.h> 522893Sdfr#include <sys/systm.h> 5340651Sbde#include <sys/conf.h> 542893Sdfr#include <sys/namei.h> 552893Sdfr#include <sys/proc.h> 562893Sdfr#include <sys/kernel.h> 572893Sdfr#include <sys/vnode.h> 582893Sdfr#include <sys/mount.h> 5960041Sphk#include <sys/bio.h> 602893Sdfr#include <sys/buf.h> 6124131Sbde#include <sys/fcntl.h> 622893Sdfr#include <sys/malloc.h> 6333548Sjkh#include <sys/stat.h> /* defines ALLPERMS */ 64120492Sfjoe#include <sys/iconv.h> 65102391Sbde#include <sys/mutex.h> 662893Sdfr 6777162Sru#include <fs/msdosfs/bpb.h> 6877162Sru#include <fs/msdosfs/bootsect.h> 69120492Sfjoe#include <fs/msdosfs/msdosfsmount.h> 7077162Sru#include <fs/msdosfs/direntry.h> 7177162Sru#include <fs/msdosfs/denode.h> 7277162Sru#include <fs/msdosfs/fat.h> 732893Sdfr 74137036Sphk#include <geom/geom.h> 75137036Sphk#include <geom/geom_vfs.h> 76137036Sphk 77131523Stjr#include "opt_msdosfs.h" 78131523Stjr 79138471Sphk/* List of mount options we support */ 80138471Sphkstatic const char *msdosfs_opts[] = { 81138471Sphk "from", 82138471Sphk "export", 83138471Sphk "uid", "gid", "mask", "dirmask", 84138471Sphk "shortname", "longname", "win95", 85138471Sphk "kiconv", "cs_win", "cs_dos", "cs_local", 86138471Sphk NULL 87138471Sphk}; 88138471Sphk 89102391Sbde#define MSDOSFS_DFLTBSIZE 4096 90102391Sbde 9156674Snyan#if 1 /*def PC98*/ 9256674Snyan/* 9356674Snyan * XXX - The boot signature formatted by NEC PC-98 DOS looks like a 9456674Snyan * garbage or a random value :-{ 9556674Snyan * If you want to use that broken-signatured media, define the 9656674Snyan * following symbol even though PC/AT. 9756674Snyan * (ex. mount PC-98 DOS formatted FD on PC/AT) 9856674Snyan */ 9956674Snyan#define MSDOSFS_NOCHECKSIG 10056674Snyan#endif 10156674Snyan 10230354SphkMALLOC_DEFINE(M_MSDOSFSMNT, "MSDOSFS mount", "MSDOSFS mount structure"); 10330354Sphkstatic MALLOC_DEFINE(M_MSDOSFSFAT, "MSDOSFS FAT", "MSDOSFS file allocation table"); 10430309Sphk 105120492Sfjoestruct iconv_functions *msdosfs_iconv = NULL; 106120492Sfjoe 107138471Sphkstatic int update_mp(struct mount *mp, struct thread *td); 108138471Sphkstatic int mountmsdosfs(struct vnode *devvp, struct mount *mp, 109132023Salfred struct thread *td); 110101777Sphkstatic vfs_fhtovp_t msdosfs_fhtovp; 111138471Sphkstatic vfs_mount_t msdosfs_mount; 112101777Sphkstatic vfs_root_t msdosfs_root; 113101777Sphkstatic vfs_statfs_t msdosfs_statfs; 114101777Sphkstatic vfs_sync_t msdosfs_sync; 115101777Sphkstatic vfs_unmount_t msdosfs_unmount; 116101777Sphkstatic vfs_vptofh_t msdosfs_vptofh; 11712338Sbde 118134345Stjr/* Maximum length of a character set name (arbitrary). */ 119134345Stjr#define MAXCSLEN 64 120134345Stjr 12133548Sjkhstatic int 122138471Sphkupdate_mp(mp, td) 12333548Sjkh struct mount *mp; 124132023Salfred struct thread *td; 12533548Sjkh{ 12633548Sjkh struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 127138471Sphk void *dos, *win, *local; 128138471Sphk int error, v; 12933548Sjkh 130138471Sphk if (!vfs_getopt(mp->mnt_optnew, "kiconv", NULL, NULL)) { 131138471Sphk if (msdosfs_iconv != NULL) { 132138471Sphk error = vfs_getopt(mp->mnt_optnew, 133138471Sphk "cs_win", &win, NULL); 134138471Sphk if (!error) 135138471Sphk error = vfs_getopt(mp->mnt_optnew, 136138471Sphk "cs_local", &local, NULL); 137138471Sphk if (!error) 138138471Sphk error = vfs_getopt(mp->mnt_optnew, 139138471Sphk "cs_dos", &dos, NULL); 140138471Sphk if (!error) { 141138471Sphk msdosfs_iconv->open(win, local, &pmp->pm_u2w); 142138471Sphk msdosfs_iconv->open(local, win, &pmp->pm_w2u); 143138471Sphk msdosfs_iconv->open(dos, local, &pmp->pm_u2d); 144138471Sphk msdosfs_iconv->open(local, dos, &pmp->pm_d2u); 145138471Sphk } 146134345Stjr if (error != 0) 147134345Stjr return (error); 148134345Stjr } else { 149134345Stjr pmp->pm_w2u = NULL; 150134345Stjr pmp->pm_u2w = NULL; 151134345Stjr pmp->pm_d2u = NULL; 152134345Stjr pmp->pm_u2d = NULL; 153134345Stjr } 154134345Stjr } 155134345Stjr 156138471Sphk if (1 == vfs_scanopt(mp->mnt_optnew, "gid", "%d", &v)) 157138471Sphk pmp->pm_gid = v; 158138471Sphk if (1 == vfs_scanopt(mp->mnt_optnew, "uid", "%d", &v)) 159138471Sphk pmp->pm_uid = v; 160138471Sphk if (1 == vfs_scanopt(mp->mnt_optnew, "mask", "%d", &v)) 161138471Sphk pmp->pm_mask = v & ALLPERMS; 162138471Sphk if (1 == vfs_scanopt(mp->mnt_optnew, "dirmask", "%d", &v)) 163138471Sphk pmp->pm_dirmask = v & ALLPERMS; 164138471Sphk vfs_flagopt(mp->mnt_optnew, "shortname", 165138471Sphk &pmp->pm_flags, MSDOSFSMNT_SHORTNAME); 166138471Sphk vfs_flagopt(mp->mnt_optnew, "longname", 167138471Sphk &pmp->pm_flags, MSDOSFSMNT_LONGNAME); 168138471Sphk vfs_flagopt(mp->mnt_optnew, "kiconv", 169138471Sphk &pmp->pm_flags, MSDOSFSMNT_KICONV); 17033548Sjkh 171138471Sphk /* XXX: Can't use flagopt due to negative option */ 172138471Sphk if (!vfs_getopt(mp->mnt_optnew, "win95", NULL, NULL)) 173138471Sphk pmp->pm_flags &= ~MSDOSFSMNT_NOWIN95; 174138471Sphk else 175138471Sphk pmp->pm_flags |= MSDOSFSMNT_NOWIN95; 176138471Sphk 17733548Sjkh if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 17833548Sjkh pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 17933548Sjkh else if (!(pmp->pm_flags & 18033548Sjkh (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) { 18133548Sjkh struct vnode *rootvp; 18233548Sjkh 18333548Sjkh /* 18433548Sjkh * Try to divine whether to support Win'95 long filenames 18533548Sjkh */ 18633548Sjkh if (FAT32(pmp)) 18733548Sjkh pmp->pm_flags |= MSDOSFSMNT_LONGNAME; 18833548Sjkh else { 189132023Salfred if ((error = msdosfs_root(mp, &rootvp, td)) != 0) 19033548Sjkh return error; 19133548Sjkh pmp->pm_flags |= findwin95(VTODE(rootvp)) 19233548Sjkh ? MSDOSFSMNT_LONGNAME 19333548Sjkh : MSDOSFSMNT_SHORTNAME; 19433548Sjkh vput(rootvp); 19533548Sjkh } 19633548Sjkh } 19733548Sjkh return 0; 19833548Sjkh} 19933548Sjkh 200138471Sphkstatic int 201138471Sphkmsdosfs_cmount(struct mntarg *ma, void *data, int flags, struct thread *td) 202138471Sphk{ 203138471Sphk struct msdosfs_args args; 204138471Sphk int error; 205138471Sphk 206138471Sphk if (data == NULL) 207138471Sphk return (EINVAL); 208138471Sphk error = copyin(data, &args, sizeof args); 209138471Sphk if (error) 210138471Sphk return (error); 211138471Sphk 212138471Sphk ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN); 213138471Sphk ma = mount_arg(ma, "export", &args.export, sizeof args.export); 214138471Sphk ma = mount_argf(ma, "uid", "%d", args.uid); 215138471Sphk ma = mount_argf(ma, "gid", "%d", args.gid); 216138471Sphk ma = mount_argf(ma, "mask", "%d", args.mask); 217138471Sphk ma = mount_argf(ma, "dirmask", "%d", args.dirmask); 218138471Sphk 219138471Sphk ma = mount_argb(ma, args.flags & MSDOSFSMNT_SHORTNAME, "noshortname"); 220138471Sphk ma = mount_argb(ma, args.flags & MSDOSFSMNT_LONGNAME, "nolongname"); 221138471Sphk ma = mount_argb(ma, !(args.flags & MSDOSFSMNT_NOWIN95), "nowin95"); 222138471Sphk ma = mount_argb(ma, args.flags & MSDOSFSMNT_KICONV, "nokiconv"); 223138471Sphk 224138471Sphk ma = mount_argsu(ma, "cs_win", args.cs_win, MAXCSLEN); 225138471Sphk ma = mount_argsu(ma, "cs_dos", args.cs_dos, MAXCSLEN); 226138471Sphk ma = mount_argsu(ma, "cs_local", args.cs_local, MAXCSLEN); 227138471Sphk 228138471Sphk error = kernel_mount(ma, flags); 229138471Sphk 230138471Sphk return (error); 231138471Sphk} 232138471Sphk 2332893Sdfr/* 2348876Srgrimes * mp - path - addr in user space of mount point (ie /usr or whatever) 2352893Sdfr * data - addr in user space of mount params including the name of the block 2368876Srgrimes * special file to treat as a filesystem. 2372893Sdfr */ 23812144Sphkstatic int 239138471Sphkmsdosfs_mount(struct mount *mp, struct thread *td) 2402893Sdfr{ 2412893Sdfr struct vnode *devvp; /* vnode for blk device to mount */ 242138689Sphk struct export_args export; 24333548Sjkh /* msdosfs specific mount control block */ 24433548Sjkh struct msdosfsmount *pmp = NULL; 245132902Sphk struct nameidata ndp; 246138689Sphk int error, flags; 24733548Sjkh mode_t accessmode; 248138471Sphk char *from; 2492893Sdfr 250138471Sphk if (vfs_filteropt(mp->mnt_optnew, msdosfs_opts)) 251138471Sphk return (EINVAL); 252138471Sphk 2532893Sdfr /* 25433548Sjkh * If updating, check whether changing from read-only to 25533548Sjkh * read/write; if there is no device name, that's all we do. 2562893Sdfr */ 2572893Sdfr if (mp->mnt_flag & MNT_UPDATE) { 25833548Sjkh pmp = VFSTOMSDOSFS(mp); 259138689Sphk 260138689Sphk error = vfs_copyopt(mp->mnt_optnew, "export", 261138689Sphk &export, sizeof export); 262138689Sphk if (error == 0 && export.ex_flags != 0) { 263138689Sphk /* 264138689Sphk * Process export requests. 265138689Sphk */ 266138689Sphk if ((export.ex_flags & MNT_EXPORTED) != 0 && 267138689Sphk (pmp->pm_flags & MSDOSFS_LARGEFS) != 0) 268138689Sphk return (EOPNOTSUPP); 269138689Sphk return (vfs_export(mp, &export)); 270138689Sphk } 271137036Sphk if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && 272138471Sphk vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) { 273133287Sphk error = VFS_SYNC(mp, MNT_WAIT, td->td_ucred, td); 274133287Sphk if (error) 275133287Sphk return (error); 2762893Sdfr flags = WRITECLOSE; 2772893Sdfr if (mp->mnt_flag & MNT_FORCE) 2782893Sdfr flags |= FORCECLOSE; 279132023Salfred error = vflush(mp, 0, flags, td); 280138471Sphk if (error) 281138471Sphk return (error); 282137036Sphk DROP_GIANT(); 283137036Sphk g_topology_lock(); 284137036Sphk g_access(pmp->pm_cp, 0, -1, 0); 285137036Sphk g_topology_unlock(); 286137036Sphk PICKUP_GIANT(); 287138471Sphk } else if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && 288138471Sphk !vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) { 28933548Sjkh /* 29033548Sjkh * If upgrade to read-write by non-root, then verify 29133548Sjkh * that user has necessary permissions on the device. 29233548Sjkh */ 29393593Sjhb if (suser(td)) { 29433548Sjkh devvp = pmp->pm_devvp; 29583366Sjulian vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); 29633548Sjkh error = VOP_ACCESS(devvp, VREAD | VWRITE, 29791406Sjhb td->td_ucred, td); 29833548Sjkh if (error) { 29983366Sjulian VOP_UNLOCK(devvp, 0, td); 30033548Sjkh return (error); 30133548Sjkh } 30283366Sjulian VOP_UNLOCK(devvp, 0, td); 30333548Sjkh } 304137036Sphk DROP_GIANT(); 305137036Sphk g_topology_lock(); 306137036Sphk error = g_access(pmp->pm_cp, 0, 1, 0); 307137036Sphk g_topology_unlock(); 308137036Sphk PICKUP_GIANT(); 309137036Sphk if (error) 310137036Sphk return (error); 311123963Sbde 312123963Sbde /* Now that the volume is modifiable, mark it dirty. */ 313123873Strhodes error = markvoldirty(pmp, 1); 314123873Strhodes if (error) 315123963Sbde return (error); 31633548Sjkh } 317138471Sphk vfs_flagopt(mp->mnt_optnew, "ro", 318138471Sphk &pmp->pm_flags, MSDOSFSMNT_RONLY); 319138471Sphk vfs_flagopt(mp->mnt_optnew, "ro", 320138471Sphk &mp->mnt_flag, MNT_RDONLY); 321138471Sphk if (vfs_getopt(mp->mnt_optnew, "from", NULL, NULL)) { 32287068Sjhb#ifdef __notyet__ /* doesn't work correctly with current mountd XXX */ 32333548Sjkh if (args.flags & MSDOSFSMNT_MNTOPT) { 32433548Sjkh pmp->pm_flags &= ~MSDOSFSMNT_MNTOPT; 32533548Sjkh pmp->pm_flags |= args.flags & MSDOSFSMNT_MNTOPT; 32633548Sjkh if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 32733548Sjkh pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 32833548Sjkh } 32933548Sjkh#endif 3302893Sdfr } 3312893Sdfr } 3322893Sdfr /* 33333548Sjkh * Not an update, or updating the name: look up the name 334125796Sbde * and verify that it refers to a sensible disk device. 3352893Sdfr */ 336138471Sphk if (vfs_getopt(mp->mnt_optnew, "from", (void **)&from, NULL)) 337138471Sphk return (EINVAL); 338138471Sphk NDINIT(&ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, from, td); 339132902Sphk error = namei(&ndp); 34033548Sjkh if (error) 34133548Sjkh return (error); 342132902Sphk devvp = ndp.ni_vp; 343132902Sphk NDFREE(&ndp, NDF_ONLY_PNBUF); 3448876Srgrimes 34555756Sphk if (!vn_isdisk(devvp, &error)) { 3462893Sdfr vrele(devvp); 34755756Sphk return (error); 3482893Sdfr } 3492893Sdfr /* 35033548Sjkh * If mount by non-root, then verify that user has necessary 35133548Sjkh * permissions on the device. 3522893Sdfr */ 35393593Sjhb if (suser(td)) { 35433548Sjkh accessmode = VREAD; 35533548Sjkh if ((mp->mnt_flag & MNT_RDONLY) == 0) 35633548Sjkh accessmode |= VWRITE; 35783366Sjulian vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); 35891406Sjhb error = VOP_ACCESS(devvp, accessmode, td->td_ucred, td); 35933548Sjkh if (error) { 36033548Sjkh vput(devvp); 36133548Sjkh return (error); 36233548Sjkh } 36383366Sjulian VOP_UNLOCK(devvp, 0, td); 36433548Sjkh } 36533548Sjkh if ((mp->mnt_flag & MNT_UPDATE) == 0) { 366138471Sphk error = mountmsdosfs(devvp, mp, td); 36733548Sjkh#ifdef MSDOSFS_DEBUG /* only needed for the printf below */ 36833548Sjkh pmp = VFSTOMSDOSFS(mp); 36933548Sjkh#endif 37033548Sjkh } else { 3712893Sdfr if (devvp != pmp->pm_devvp) 37233548Sjkh error = EINVAL; /* XXX needs translation */ 3732893Sdfr else 3742893Sdfr vrele(devvp); 3752893Sdfr } 3762893Sdfr if (error) { 3772893Sdfr vrele(devvp); 37833548Sjkh return (error); 37933548Sjkh } 38033548Sjkh 381138471Sphk error = update_mp(mp, td); 38233548Sjkh if (error) { 383134345Stjr if ((mp->mnt_flag & MNT_UPDATE) == 0) 384134345Stjr msdosfs_unmount(mp, MNT_FORCE, td); 3852893Sdfr return error; 3862893Sdfr } 387138471Sphk 388138471Sphk vfs_mountedfrom(mp, from); 3892893Sdfr#ifdef MSDOSFS_DEBUG 390138471Sphk printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); 3912893Sdfr#endif 39233548Sjkh return (0); 3932893Sdfr} 3942893Sdfr 39512144Sphkstatic int 396138471Sphkmountmsdosfs(devvp, mp, td) 3972893Sdfr struct vnode *devvp; 3982893Sdfr struct mount *mp; 39983366Sjulian struct thread *td; 4002893Sdfr{ 40133548Sjkh struct msdosfsmount *pmp; 40233548Sjkh struct buf *bp; 403130585Sphk struct cdev *dev = devvp->v_rdev; 4042893Sdfr union bootsector *bsp; 4052893Sdfr struct byte_bpb33 *b33; 4062893Sdfr struct byte_bpb50 *b50; 40733548Sjkh struct byte_bpb710 *b710; 40833548Sjkh u_int8_t SecPerClust; 40955188Sbp u_long clusters; 41033548Sjkh int ronly, error; 411137036Sphk struct g_consumer *cp; 412137036Sphk struct bufobj *bo; 4132893Sdfr 414138471Sphk ronly = !vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL); 415137036Sphk /* XXX: use VOP_ACCESS to check FS perms */ 416137036Sphk DROP_GIANT(); 417137036Sphk g_topology_lock(); 418137036Sphk error = g_vfs_open(devvp, &cp, "msdos", ronly ? 0 : 1); 419137036Sphk g_topology_unlock(); 420137036Sphk PICKUP_GIANT(); 42183366Sjulian VOP_UNLOCK(devvp, 0, td); 4223152Sphk if (error) 42333548Sjkh return (error); 42433548Sjkh 425137036Sphk bo = &devvp->v_bufobj; 42633548Sjkh bp = NULL; /* both used in error_exit */ 42733548Sjkh pmp = NULL; 42833548Sjkh 4292893Sdfr /* 43033548Sjkh * Read the boot sector of the filesystem, and then check the 43133548Sjkh * boot signature. If not a dos boot sector then error out. 43256674Snyan * 433102391Sbde * NOTE: 2048 is a maximum sector size in current... 4342893Sdfr */ 435102391Sbde error = bread(devvp, 0, 2048, NOCRED, &bp); 4363152Sphk if (error) 4372893Sdfr goto error_exit; 43833548Sjkh bp->b_flags |= B_AGE; 43933548Sjkh bsp = (union bootsector *)bp->b_data; 44033548Sjkh b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB; 44133548Sjkh b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB; 442105655Sjhb b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB; 44333548Sjkh 44456674Snyan#ifndef MSDOSFS_NOCHECKSIG 44587068Sjhb if (bsp->bs50.bsBootSectSig0 != BOOTSIG0 44687068Sjhb || bsp->bs50.bsBootSectSig1 != BOOTSIG1) { 44787068Sjhb error = EINVAL; 44887068Sjhb goto error_exit; 44987068Sjhb } 45056674Snyan#endif 4512893Sdfr 452111119Simp pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK | M_ZERO); 4532893Sdfr pmp->pm_mountp = mp; 454137036Sphk pmp->pm_cp = cp; 455137036Sphk pmp->pm_bo = bo; 4562893Sdfr 4572893Sdfr /* 4582893Sdfr * Compute several useful quantities from the bpb in the 4592893Sdfr * bootsector. Copy in the dos 5 variant of the bpb then fix up 4602893Sdfr * the fields that are different between dos 5 and dos 3.3. 4612893Sdfr */ 46233548Sjkh SecPerClust = b50->bpbSecPerClust; 4632893Sdfr pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 464113979Sjhb if (pmp->pm_BytesPerSec < DEV_BSIZE) { 465113979Sjhb error = EINVAL; 466113979Sjhb goto error_exit; 467113979Sjhb } 4682893Sdfr pmp->pm_ResSectors = getushort(b50->bpbResSectors); 4692893Sdfr pmp->pm_FATs = b50->bpbFATs; 4702893Sdfr pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 4712893Sdfr pmp->pm_Sectors = getushort(b50->bpbSectors); 4722893Sdfr pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 4732893Sdfr pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 4742893Sdfr pmp->pm_Heads = getushort(b50->bpbHeads); 47533548Sjkh pmp->pm_Media = b50->bpbMedia; 4762893Sdfr 47756674Snyan /* calculate the ratio of sector size to DEV_BSIZE */ 47856674Snyan pmp->pm_BlkPerSec = pmp->pm_BytesPerSec / DEV_BSIZE; 47956674Snyan 48087068Sjhb /* XXX - We should probably check more values here */ 48187068Sjhb if (!pmp->pm_BytesPerSec || !SecPerClust 482126998Srwatson || !pmp->pm_Heads 48316363Sasami#ifdef PC98 48487068Sjhb || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) { 48516363Sasami#else 48687068Sjhb || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) { 48716363Sasami#endif 48887068Sjhb error = EINVAL; 48987068Sjhb goto error_exit; 49087068Sjhb } 4912893Sdfr 4922893Sdfr if (pmp->pm_Sectors == 0) { 4932893Sdfr pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 4942893Sdfr pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 4952893Sdfr } else { 4962893Sdfr pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 4972893Sdfr pmp->pm_HugeSectors = pmp->pm_Sectors; 4982893Sdfr } 499131523Stjr#ifndef MSDOSFS_LARGE 50035511Sdt if (pmp->pm_HugeSectors > 0xffffffff / 50135511Sdt (pmp->pm_BytesPerSec / sizeof(struct direntry)) + 1) { 50233548Sjkh /* 50333548Sjkh * We cannot deal currently with this size of disk 50433548Sjkh * due to fileid limitations (see msdosfs_getattr and 50533548Sjkh * msdosfs_readdir) 50633548Sjkh */ 50733548Sjkh error = EINVAL; 50835046Sache printf("mountmsdosfs(): disk too big, sorry\n"); 50933548Sjkh goto error_exit; 51033548Sjkh } 511131523Stjr#endif /* !MSDOSFS_LARGE */ 51233548Sjkh 51333548Sjkh if (pmp->pm_RootDirEnts == 0) { 51433548Sjkh if (bsp->bs710.bsBootSectSig2 != BOOTSIG2 51533548Sjkh || bsp->bs710.bsBootSectSig3 != BOOTSIG3 51633548Sjkh || pmp->pm_Sectors 51733548Sjkh || pmp->pm_FATsecs 51833548Sjkh || getushort(b710->bpbFSVers)) { 51933548Sjkh error = EINVAL; 52035046Sache printf("mountmsdosfs(): bad FAT32 filesystem\n"); 52133548Sjkh goto error_exit; 52233548Sjkh } 52333548Sjkh pmp->pm_fatmask = FAT32_MASK; 52433548Sjkh pmp->pm_fatmult = 4; 52533548Sjkh pmp->pm_fatdiv = 1; 52633548Sjkh pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs); 52733548Sjkh if (getushort(b710->bpbExtFlags) & FATMIRROR) 52833548Sjkh pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM; 52933548Sjkh else 53033548Sjkh pmp->pm_flags |= MSDOSFS_FATMIRROR; 53133548Sjkh } else 53233548Sjkh pmp->pm_flags |= MSDOSFS_FATMIRROR; 53333548Sjkh 53456674Snyan /* 53556674Snyan * Check a few values (could do some more): 53656674Snyan * - logical sector size: power of 2, >= block size 53756674Snyan * - sectors per cluster: power of 2, >= 1 53856674Snyan * - number of sectors: >= 1, <= size of partition 539113979Sjhb * - number of FAT sectors: >= 1 54056674Snyan */ 54156674Snyan if ( (SecPerClust == 0) 54256674Snyan || (SecPerClust & (SecPerClust - 1)) 54356674Snyan || (pmp->pm_BytesPerSec < DEV_BSIZE) 54456674Snyan || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) 54556674Snyan || (pmp->pm_HugeSectors == 0) 546113979Sjhb || (pmp->pm_FATsecs == 0) 54756674Snyan ) { 54856674Snyan error = EINVAL; 54956674Snyan goto error_exit; 55056674Snyan } 55133548Sjkh 55256674Snyan pmp->pm_HugeSectors *= pmp->pm_BlkPerSec; 55356674Snyan pmp->pm_HiddenSects *= pmp->pm_BlkPerSec; /* XXX not used? */ 55456674Snyan pmp->pm_FATsecs *= pmp->pm_BlkPerSec; 55556674Snyan SecPerClust *= pmp->pm_BlkPerSec; 55656674Snyan 55756674Snyan pmp->pm_fatblk = pmp->pm_ResSectors * pmp->pm_BlkPerSec; 55856674Snyan 55933548Sjkh if (FAT32(pmp)) { 56033548Sjkh pmp->pm_rootdirblk = getulong(b710->bpbRootClust); 56133548Sjkh pmp->pm_firstcluster = pmp->pm_fatblk 56233548Sjkh + (pmp->pm_FATs * pmp->pm_FATsecs); 56356674Snyan pmp->pm_fsinfo = getushort(b710->bpbFSInfo) * pmp->pm_BlkPerSec; 56433548Sjkh } else { 56533548Sjkh pmp->pm_rootdirblk = pmp->pm_fatblk + 56633548Sjkh (pmp->pm_FATs * pmp->pm_FATsecs); 56733548Sjkh pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry) 56856674Snyan + DEV_BSIZE - 1) 56956674Snyan / DEV_BSIZE; /* in blocks */ 57033548Sjkh pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 57133548Sjkh } 57233548Sjkh 57355188Sbp pmp->pm_maxcluster = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 57455188Sbp SecPerClust + 1; 57556674Snyan pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE; /* XXX not used? */ 57633548Sjkh 57733548Sjkh if (pmp->pm_fatmask == 0) { 57833548Sjkh if (pmp->pm_maxcluster 57933548Sjkh <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) { 58033548Sjkh /* 58133548Sjkh * This will usually be a floppy disk. This size makes 58233548Sjkh * sure that one fat entry will not be split across 58333548Sjkh * multiple blocks. 58433548Sjkh */ 58533548Sjkh pmp->pm_fatmask = FAT12_MASK; 58633548Sjkh pmp->pm_fatmult = 3; 58733548Sjkh pmp->pm_fatdiv = 2; 58833548Sjkh } else { 58933548Sjkh pmp->pm_fatmask = FAT16_MASK; 59033548Sjkh pmp->pm_fatmult = 2; 59133548Sjkh pmp->pm_fatdiv = 1; 59233548Sjkh } 59333548Sjkh } 59455188Sbp 59555188Sbp clusters = (pmp->pm_fatsize / pmp->pm_fatmult) * pmp->pm_fatdiv; 59655188Sbp if (pmp->pm_maxcluster >= clusters) { 59755188Sbp printf("Warning: number of clusters (%ld) exceeds FAT " 59855188Sbp "capacity (%ld)\n", pmp->pm_maxcluster + 1, clusters); 59955188Sbp pmp->pm_maxcluster = clusters - 1; 60055188Sbp } 60155188Sbp 60255188Sbp 6032893Sdfr if (FAT12(pmp)) 6042893Sdfr pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; 6052893Sdfr else 606102391Sbde pmp->pm_fatblocksize = MSDOSFS_DFLTBSIZE; 60733548Sjkh 60856674Snyan pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE; 60956674Snyan pmp->pm_bnshift = ffs(DEV_BSIZE) - 1; 6102893Sdfr 6112893Sdfr /* 6122893Sdfr * Compute mask and shift value for isolating cluster relative byte 6132893Sdfr * offsets and cluster numbers from a file offset. 6142893Sdfr */ 61556674Snyan pmp->pm_bpcluster = SecPerClust * DEV_BSIZE; 61633548Sjkh pmp->pm_crbomask = pmp->pm_bpcluster - 1; 61733548Sjkh pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1; 61833548Sjkh 61933548Sjkh /* 62033548Sjkh * Check for valid cluster size 62133548Sjkh * must be a power of 2 62233548Sjkh */ 62333548Sjkh if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) { 6242893Sdfr error = EINVAL; 6252893Sdfr goto error_exit; 6262893Sdfr } 6272893Sdfr 62833548Sjkh /* 62933548Sjkh * Release the bootsector buffer. 63033548Sjkh */ 63133548Sjkh brelse(bp); 63233548Sjkh bp = NULL; 63333548Sjkh 63433548Sjkh /* 63533548Sjkh * Check FSInfo. 63633548Sjkh */ 63733548Sjkh if (pmp->pm_fsinfo) { 63833548Sjkh struct fsinfo *fp; 63933548Sjkh 64056674Snyan if ((error = bread(devvp, pmp->pm_fsinfo, fsi_size(pmp), 64156674Snyan NOCRED, &bp)) != 0) 64233548Sjkh goto error_exit; 64333548Sjkh fp = (struct fsinfo *)bp->b_data; 64433548Sjkh if (!bcmp(fp->fsisig1, "RRaA", 4) 64533548Sjkh && !bcmp(fp->fsisig2, "rrAa", 4) 64633548Sjkh && !bcmp(fp->fsisig3, "\0\0\125\252", 4) 647125934Stjr && !bcmp(fp->fsisig4, "\0\0\125\252", 4)) { 64833548Sjkh pmp->pm_nxtfree = getulong(fp->fsinxtfree); 649125934Stjr if (pmp->pm_nxtfree == 0xffffffff) 650125934Stjr pmp->pm_nxtfree = CLUST_FIRST; 651125934Stjr } else 65233548Sjkh pmp->pm_fsinfo = 0; 65333548Sjkh brelse(bp); 65433548Sjkh bp = NULL; 65516363Sasami } 6562893Sdfr 6572893Sdfr /* 658102295Strhodes * Check and validate (or perhaps invalidate?) the fsinfo structure? 6592893Sdfr */ 660102295Strhodes if (pmp->pm_fsinfo && pmp->pm_nxtfree > pmp->pm_maxcluster) { 661102392Sbde printf( 662102392Sbde "Next free cluster in FSInfo (%lu) exceeds maxcluster (%lu)\n", 663102392Sbde pmp->pm_nxtfree, pmp->pm_maxcluster); 664102295Strhodes error = EINVAL; 665102295Strhodes goto error_exit; 666102295Strhodes } 6672893Sdfr 6682893Sdfr /* 6692893Sdfr * Allocate memory for the bitmap of allocated clusters, and then 6702893Sdfr * fill it in. 6712893Sdfr */ 672126086Sbde pmp->pm_inusemap = malloc(howmany(pmp->pm_maxcluster + 1, N_INUSEBITS) 6732893Sdfr * sizeof(*pmp->pm_inusemap), 674111119Simp M_MSDOSFSFAT, M_WAITOK); 6752893Sdfr 6762893Sdfr /* 6772893Sdfr * fillinusemap() needs pm_devvp. 6782893Sdfr */ 6792893Sdfr pmp->pm_dev = dev; 6802893Sdfr pmp->pm_devvp = devvp; 6812893Sdfr 6822893Sdfr /* 6832893Sdfr * Have the inuse map filled in. 6842893Sdfr */ 68533548Sjkh if ((error = fillinusemap(pmp)) != 0) 6862893Sdfr goto error_exit; 6872893Sdfr 6882893Sdfr /* 6892893Sdfr * If they want fat updates to be synchronous then let them suffer 6902893Sdfr * the performance degradation in exchange for the on disk copy of 6912893Sdfr * the fat being correct just about all the time. I suppose this 6922893Sdfr * would be a good thing to turn on if the kernel is still flakey. 6932893Sdfr */ 69433548Sjkh if (mp->mnt_flag & MNT_SYNCHRONOUS) 69533548Sjkh pmp->pm_flags |= MSDOSFSMNT_WAITONFAT; 6962893Sdfr 6972893Sdfr /* 6982893Sdfr * Finish up. 6992893Sdfr */ 70033548Sjkh if (ronly) 70133548Sjkh pmp->pm_flags |= MSDOSFSMNT_RONLY; 702123873Strhodes else { 703123963Sbde /* Mark the volume dirty while it is mounted read/write. */ 704123963Sbde if ((error = markvoldirty(pmp, 1)) != 0) 705123963Sbde goto error_exit; 7062893Sdfr pmp->pm_fmod = 1; 707123873Strhodes } 7082893Sdfr mp->mnt_data = (qaddr_t) pmp; 70950256Sbde mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); 71023134Sbde mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 71123997Speter mp->mnt_flag |= MNT_LOCAL; 7122893Sdfr 713131523Stjr#ifdef MSDOSFS_LARGE 714131523Stjr msdosfs_fileno_init(mp); 715131523Stjr#endif 716131523Stjr 7172893Sdfr return 0; 7182893Sdfr 71933548Sjkherror_exit: 72033548Sjkh if (bp) 72133548Sjkh brelse(bp); 722137036Sphk if (cp != NULL) { 723137036Sphk DROP_GIANT(); 724137036Sphk g_topology_lock(); 725137036Sphk g_wither_geom_close(cp->geom, ENXIO); 726137036Sphk g_topology_unlock(); 727137036Sphk PICKUP_GIANT(); 728137036Sphk } 7292893Sdfr if (pmp) { 7302893Sdfr if (pmp->pm_inusemap) 73133548Sjkh free(pmp->pm_inusemap, M_MSDOSFSFAT); 73233548Sjkh free(pmp, M_MSDOSFSMNT); 73333548Sjkh mp->mnt_data = (qaddr_t)0; 7342893Sdfr } 73533548Sjkh return (error); 7362893Sdfr} 7372893Sdfr 7382893Sdfr/* 7392893Sdfr * Unmount the filesystem described by mp. 7402893Sdfr */ 74112144Sphkstatic int 74283366Sjulianmsdosfs_unmount(mp, mntflags, td) 7432893Sdfr struct mount *mp; 7442893Sdfr int mntflags; 74583366Sjulian struct thread *td; 7462893Sdfr{ 74733548Sjkh struct msdosfsmount *pmp; 74833548Sjkh int error, flags; 7492893Sdfr 75033548Sjkh flags = 0; 75133548Sjkh if (mntflags & MNT_FORCE) 7522893Sdfr flags |= FORCECLOSE; 753132023Salfred error = vflush(mp, 0, flags, td); 7543152Sphk if (error) 7552893Sdfr return error; 75633548Sjkh pmp = VFSTOMSDOSFS(mp); 757120492Sfjoe if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) { 758120492Sfjoe if (pmp->pm_w2u) 759120492Sfjoe msdosfs_iconv->close(pmp->pm_w2u); 760120492Sfjoe if (pmp->pm_u2w) 761120492Sfjoe msdosfs_iconv->close(pmp->pm_u2w); 762120492Sfjoe if (pmp->pm_d2u) 763120492Sfjoe msdosfs_iconv->close(pmp->pm_d2u); 764120492Sfjoe if (pmp->pm_u2d) 765120492Sfjoe msdosfs_iconv->close(pmp->pm_u2d); 766120492Sfjoe } 767123873Strhodes 768123963Sbde /* If the volume was mounted read/write, mark it clean now. */ 769123963Sbde if ((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0) { 770123963Sbde error = markvoldirty(pmp, 0); 771123963Sbde if (error && (flags & FORCECLOSE) == 0) 772123963Sbde return (error); 773123963Sbde } 77433548Sjkh#ifdef MSDOSFS_DEBUG 77533548Sjkh { 77633548Sjkh struct vnode *vp = pmp->pm_devvp; 77733548Sjkh 778103936Sjeff VI_LOCK(vp); 77933548Sjkh printf("msdosfs_umount(): just before calling VOP_CLOSE()\n"); 780101308Sjeff printf("iflag %08lx, usecount %d, writecount %d, holdcnt %ld\n", 781101308Sjeff vp->vi_flag, vp->v_usecount, vp->v_writecount, 782101308Sjeff vp->v_holdcnt); 78351486Sdillon printf("id %lu, mount %p, op %p\n", 78451486Sdillon vp->v_id, vp->v_mount, vp->v_op); 78533548Sjkh printf("freef %p, freeb %p, mount %p\n", 78671999Sphk TAILQ_NEXT(vp, v_freelist), vp->v_freelist.tqe_prev, 78733548Sjkh vp->v_mount); 78833548Sjkh printf("cleanblkhd %p, dirtyblkhd %p, numoutput %ld, type %d\n", 789136943Sphk TAILQ_FIRST(&vp->v_bufobj.bo_clean.bv_hd), 790136943Sphk TAILQ_FIRST(&vp->v_bufobj.bo_dirty.bv_hd), 791136943Sphk vp->v_bufobj.bo_numoutput, vp->v_type); 792103314Snjl printf("union %p, tag %s, data[0] %08x, data[1] %08x\n", 79333548Sjkh vp->v_socket, vp->v_tag, 79433548Sjkh ((u_int *)vp->v_data)[0], 79533548Sjkh ((u_int *)vp->v_data)[1]); 796103936Sjeff VI_UNLOCK(vp); 79733548Sjkh } 79833548Sjkh#endif 799137036Sphk DROP_GIANT(); 800137036Sphk g_topology_lock(); 801137036Sphk g_wither_geom_close(pmp->pm_cp->geom, ENXIO); 802137036Sphk g_topology_unlock(); 803137036Sphk PICKUP_GIANT(); 8042893Sdfr vrele(pmp->pm_devvp); 80533548Sjkh free(pmp->pm_inusemap, M_MSDOSFSFAT); 806131523Stjr#ifdef MSDOSFS_LARGE 807131523Stjr msdosfs_fileno_free(mp); 808131523Stjr#endif 80933548Sjkh free(pmp, M_MSDOSFSMNT); 81033548Sjkh mp->mnt_data = (qaddr_t)0; 81123997Speter mp->mnt_flag &= ~MNT_LOCAL; 81233548Sjkh return (error); 8132893Sdfr} 8142893Sdfr 81512144Sphkstatic int 816132023Salfredmsdosfs_root(mp, vpp, td) 8172893Sdfr struct mount *mp; 8182893Sdfr struct vnode **vpp; 819132023Salfred struct thread *td; 8202893Sdfr{ 82133548Sjkh struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 8222893Sdfr struct denode *ndep; 8232893Sdfr int error; 8242893Sdfr 8252893Sdfr#ifdef MSDOSFS_DEBUG 82633548Sjkh printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp); 8272893Sdfr#endif 82833548Sjkh error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep); 82933548Sjkh if (error) 83033548Sjkh return (error); 83133548Sjkh *vpp = DETOV(ndep); 83233548Sjkh return (0); 8332893Sdfr} 8342893Sdfr 83512144Sphkstatic int 83683366Sjulianmsdosfs_statfs(mp, sbp, td) 8372893Sdfr struct mount *mp; 8382893Sdfr struct statfs *sbp; 83983366Sjulian struct thread *td; 8402893Sdfr{ 84133548Sjkh struct msdosfsmount *pmp; 8422893Sdfr 84333548Sjkh pmp = VFSTOMSDOSFS(mp); 8442893Sdfr sbp->f_bsize = pmp->pm_bpcluster; 8452893Sdfr sbp->f_iosize = pmp->pm_bpcluster; 84655188Sbp sbp->f_blocks = pmp->pm_maxcluster + 1; 8472893Sdfr sbp->f_bfree = pmp->pm_freeclustercount; 8482893Sdfr sbp->f_bavail = pmp->pm_freeclustercount; 8492893Sdfr sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ 8502893Sdfr sbp->f_ffree = 0; /* what to put in here? */ 85133548Sjkh return (0); 8522893Sdfr} 8532893Sdfr 85412144Sphkstatic int 85583366Sjulianmsdosfs_sync(mp, waitfor, cred, td) 8562893Sdfr struct mount *mp; 8572893Sdfr int waitfor; 8582893Sdfr struct ucred *cred; 85983366Sjulian struct thread *td; 8602893Sdfr{ 86133548Sjkh struct vnode *vp, *nvp; 8622893Sdfr struct denode *dep; 86333548Sjkh struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 86433548Sjkh int error, allerror = 0; 8652893Sdfr 8662893Sdfr /* 8672893Sdfr * If we ever switch to not updating all of the fats all the time, 8682893Sdfr * this would be the place to update them from the first one. 8692893Sdfr */ 87046568Speter if (pmp->pm_fmod != 0) { 87133548Sjkh if (pmp->pm_flags & MSDOSFSMNT_RONLY) 8722893Sdfr panic("msdosfs_sync: rofs mod"); 8732893Sdfr else { 8742893Sdfr /* update fats here */ 8752893Sdfr } 87646568Speter } 8772893Sdfr /* 87833548Sjkh * Write back each (modified) denode. 8792893Sdfr */ 880122091Skan MNT_ILOCK(mp); 8812893Sdfrloop: 882131551Sphk MNT_VNODE_FOREACH(vp, mp, nvp) { 883120733Sjeff VI_LOCK(vp); 884137008Sphk if (vp->v_type == VNON || (vp->v_iflag & VI_XLOCK)) { 885120785Sjeff VI_UNLOCK(vp); 886120785Sjeff continue; 887120785Sjeff } 888122091Skan MNT_IUNLOCK(mp); 8892893Sdfr dep = VTODE(vp); 890137008Sphk if ((dep->de_flag & 89135511Sdt (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0 && 892136943Sphk (vp->v_bufobj.bo_dirty.bv_cnt == 0 || 893137008Sphk waitfor == MNT_LAZY)) { 894103936Sjeff VI_UNLOCK(vp); 895122091Skan MNT_ILOCK(mp); 8962893Sdfr continue; 89723134Sbde } 89883366Sjulian error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, td); 89923134Sbde if (error) { 900122091Skan MNT_ILOCK(mp); 90123134Sbde if (error == ENOENT) 90223134Sbde goto loop; 90323134Sbde continue; 90423134Sbde } 90583366Sjulian error = VOP_FSYNC(vp, cred, waitfor, td); 9063152Sphk if (error) 9072893Sdfr allerror = error; 908121874Skan VOP_UNLOCK(vp, 0, td); 909121874Skan vrele(vp); 910122091Skan MNT_ILOCK(mp); 9112893Sdfr } 912122091Skan MNT_IUNLOCK(mp); 9132893Sdfr 9142893Sdfr /* 9152893Sdfr * Flush filesystem control info. 9162893Sdfr */ 91735511Sdt if (waitfor != MNT_LAZY) { 91883366Sjulian vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY, td); 91983366Sjulian error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, td); 92035511Sdt if (error) 92135511Sdt allerror = error; 92283366Sjulian VOP_UNLOCK(pmp->pm_devvp, 0, td); 92335511Sdt } 92433548Sjkh return (allerror); 9252893Sdfr} 9262893Sdfr 92712144Sphkstatic int 92851138Salfredmsdosfs_fhtovp(mp, fhp, vpp) 9292893Sdfr struct mount *mp; 9302893Sdfr struct fid *fhp; 9312893Sdfr struct vnode **vpp; 9322893Sdfr{ 93333548Sjkh struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 9342893Sdfr struct defid *defhp = (struct defid *) fhp; 9352893Sdfr struct denode *dep; 9362893Sdfr int error; 9372893Sdfr 93833548Sjkh error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep); 9392893Sdfr if (error) { 9402893Sdfr *vpp = NULLVP; 94133548Sjkh return (error); 9422893Sdfr } 9432893Sdfr *vpp = DETOV(dep); 94451138Salfred return (0); 94551138Salfred} 94651138Salfred 94751138Salfredstatic int 9482893Sdfrmsdosfs_vptofh(vp, fhp) 9492893Sdfr struct vnode *vp; 9502893Sdfr struct fid *fhp; 9512893Sdfr{ 95233548Sjkh struct denode *dep; 95333548Sjkh struct defid *defhp; 9542893Sdfr 95533548Sjkh dep = VTODE(vp); 95633548Sjkh defhp = (struct defid *)fhp; 9572893Sdfr defhp->defid_len = sizeof(struct defid); 9582893Sdfr defhp->defid_dirclust = dep->de_dirclust; 9592893Sdfr defhp->defid_dirofs = dep->de_diroffset; 96033548Sjkh /* defhp->defid_gen = dep->de_gen; */ 96133548Sjkh return (0); 9622893Sdfr} 9632893Sdfr 96412145Sphkstatic struct vfsops msdosfs_vfsops = { 965116271Sphk .vfs_fhtovp = msdosfs_fhtovp, 966116271Sphk .vfs_init = msdosfs_init, 967138471Sphk .vfs_mount = msdosfs_mount, 968138471Sphk .vfs_cmount = msdosfs_cmount, 969116271Sphk .vfs_root = msdosfs_root, 970116271Sphk .vfs_statfs = msdosfs_statfs, 971116271Sphk .vfs_sync = msdosfs_sync, 972116271Sphk .vfs_uninit = msdosfs_uninit, 973116271Sphk .vfs_unmount = msdosfs_unmount, 974116271Sphk .vfs_vptofh = msdosfs_vptofh, 9752893Sdfr}; 9762946Swollman 97777577SruVFS_SET(msdosfs_vfsops, msdosfs, 0); 978120492SfjoeMODULE_VERSION(msdosfs, 1); 979