150477Speter/* $FreeBSD: stable/11/sys/fs/msdosfs/msdosfs_vfsops.c 308545 2016-11-11 19:40:34Z kib $ */ 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 */ 35139776Simp/*- 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> 53171754Sbde#include <sys/buf.h> 5440651Sbde#include <sys/conf.h> 55177785Skib#include <sys/fcntl.h> 56171754Sbde#include <sys/iconv.h> 57171754Sbde#include <sys/kernel.h> 58171748Sbde#include <sys/lock.h> 59171754Sbde#include <sys/malloc.h> 60171754Sbde#include <sys/mount.h> 61171748Sbde#include <sys/mutex.h> 622893Sdfr#include <sys/namei.h> 63164033Srwatson#include <sys/priv.h> 642893Sdfr#include <sys/proc.h> 65171754Sbde#include <sys/stat.h> 662893Sdfr#include <sys/vnode.h> 672893Sdfr 68171754Sbde#include <geom/geom.h> 69171754Sbde#include <geom/geom_vfs.h> 70171754Sbde 71171754Sbde#include <fs/msdosfs/bootsect.h> 7277162Sru#include <fs/msdosfs/bpb.h> 7377162Sru#include <fs/msdosfs/direntry.h> 7477162Sru#include <fs/msdosfs/denode.h> 7577162Sru#include <fs/msdosfs/fat.h> 76171754Sbde#include <fs/msdosfs/msdosfsmount.h> 772893Sdfr 78204470Skibstatic const char msdosfs_lock_msg[] = "fatlk"; 79204470Skib 80172757Sbde/* Mount options that we support. */ 81138471Sphkstatic const char *msdosfs_opts[] = { 82172798Sbde "async", "noatime", "noclusterr", "noclusterw", 83172757Sbde "export", "force", "from", "sync", 84172757Sbde "cs_dos", "cs_local", "cs_win", "dirmask", 85172757Sbde "gid", "kiconv", "large", "longname", 86172757Sbde "longnames", "mask", "shortname", "shortnames", 87172757Sbde "uid", "win95", "nowin95", 88138471Sphk NULL 89138471Sphk}; 90138471Sphk 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 102151897SrwatsonMALLOC_DEFINE(M_MSDOSFSMNT, "msdosfs_mount", "MSDOSFS mount structure"); 103151897Srwatsonstatic MALLOC_DEFINE(M_MSDOSFSFAT, "msdosfs_fat", "MSDOSFS file allocation table"); 10430309Sphk 105171757Sbdestruct iconv_functions *msdosfs_iconv; 106120492Sfjoe 107138471Sphkstatic int update_mp(struct mount *mp, struct thread *td); 108183754Sattiliostatic int mountmsdosfs(struct vnode *devvp, struct mount *mp); 109170188Strhodesstatic vfs_fhtovp_t msdosfs_fhtovp; 110138471Sphkstatic vfs_mount_t msdosfs_mount; 111101777Sphkstatic vfs_root_t msdosfs_root; 112101777Sphkstatic vfs_statfs_t msdosfs_statfs; 113101777Sphkstatic vfs_sync_t msdosfs_sync; 114101777Sphkstatic vfs_unmount_t msdosfs_unmount; 11512338Sbde 116134345Stjr/* Maximum length of a character set name (arbitrary). */ 117134345Stjr#define MAXCSLEN 64 118134345Stjr 11933548Sjkhstatic int 120166558Srodrigcupdate_mp(struct mount *mp, struct thread *td) 12133548Sjkh{ 12233548Sjkh struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 123138471Sphk void *dos, *win, *local; 124138471Sphk int error, v; 12533548Sjkh 126138471Sphk if (!vfs_getopt(mp->mnt_optnew, "kiconv", NULL, NULL)) { 127138471Sphk if (msdosfs_iconv != NULL) { 128138471Sphk error = vfs_getopt(mp->mnt_optnew, 129138471Sphk "cs_win", &win, NULL); 130138471Sphk if (!error) 131138471Sphk error = vfs_getopt(mp->mnt_optnew, 132138471Sphk "cs_local", &local, NULL); 133138471Sphk if (!error) 134138471Sphk error = vfs_getopt(mp->mnt_optnew, 135138471Sphk "cs_dos", &dos, NULL); 136138471Sphk if (!error) { 137138471Sphk msdosfs_iconv->open(win, local, &pmp->pm_u2w); 138138471Sphk msdosfs_iconv->open(local, win, &pmp->pm_w2u); 139138471Sphk msdosfs_iconv->open(dos, local, &pmp->pm_u2d); 140138471Sphk msdosfs_iconv->open(local, dos, &pmp->pm_d2u); 141138471Sphk } 142134345Stjr if (error != 0) 143134345Stjr return (error); 144134345Stjr } else { 145134345Stjr pmp->pm_w2u = NULL; 146134345Stjr pmp->pm_u2w = NULL; 147134345Stjr pmp->pm_d2u = NULL; 148134345Stjr pmp->pm_u2d = NULL; 149134345Stjr } 150134345Stjr } 151134345Stjr 152232483Skevlo if (vfs_scanopt(mp->mnt_optnew, "gid", "%d", &v) == 1) 153138471Sphk pmp->pm_gid = v; 154232483Skevlo if (vfs_scanopt(mp->mnt_optnew, "uid", "%d", &v) == 1) 155138471Sphk pmp->pm_uid = v; 156232483Skevlo if (vfs_scanopt(mp->mnt_optnew, "mask", "%d", &v) == 1) 157138471Sphk pmp->pm_mask = v & ALLPERMS; 158232483Skevlo if (vfs_scanopt(mp->mnt_optnew, "dirmask", "%d", &v) == 1) 159138471Sphk pmp->pm_dirmask = v & ALLPERMS; 160138471Sphk vfs_flagopt(mp->mnt_optnew, "shortname", 161138471Sphk &pmp->pm_flags, MSDOSFSMNT_SHORTNAME); 162152595Srodrigc vfs_flagopt(mp->mnt_optnew, "shortnames", 163152595Srodrigc &pmp->pm_flags, MSDOSFSMNT_SHORTNAME); 164138471Sphk vfs_flagopt(mp->mnt_optnew, "longname", 165138471Sphk &pmp->pm_flags, MSDOSFSMNT_LONGNAME); 166152595Srodrigc vfs_flagopt(mp->mnt_optnew, "longnames", 167152595Srodrigc &pmp->pm_flags, MSDOSFSMNT_LONGNAME); 168138471Sphk vfs_flagopt(mp->mnt_optnew, "kiconv", 169138471Sphk &pmp->pm_flags, MSDOSFSMNT_KICONV); 17033548Sjkh 171152610Srodrigc if (vfs_getopt(mp->mnt_optnew, "nowin95", NULL, NULL) == 0) 172152610Srodrigc pmp->pm_flags |= MSDOSFSMNT_NOWIN95; 173152610Srodrigc else 174138471Sphk pmp->pm_flags &= ~MSDOSFSMNT_NOWIN95; 175138471Sphk 17633548Sjkh if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 17733548Sjkh pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 178307748Sasomers else 179307748Sasomers pmp->pm_flags |= MSDOSFSMNT_LONGNAME; 18033548Sjkh return 0; 18133548Sjkh} 18233548Sjkh 183138471Sphkstatic int 184230249Smckusickmsdosfs_cmount(struct mntarg *ma, void *data, uint64_t flags) 185138471Sphk{ 186138471Sphk struct msdosfs_args args; 187213664Skib struct export_args exp; 188138471Sphk int error; 189138471Sphk 190138471Sphk if (data == NULL) 191138471Sphk return (EINVAL); 192138471Sphk error = copyin(data, &args, sizeof args); 193138471Sphk if (error) 194138471Sphk return (error); 195213664Skib vfs_oexport_conv(&args.export, &exp); 196138471Sphk 197138471Sphk ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN); 198213664Skib ma = mount_arg(ma, "export", &exp, sizeof(exp)); 199138471Sphk ma = mount_argf(ma, "uid", "%d", args.uid); 200138471Sphk ma = mount_argf(ma, "gid", "%d", args.gid); 201138471Sphk ma = mount_argf(ma, "mask", "%d", args.mask); 202138471Sphk ma = mount_argf(ma, "dirmask", "%d", args.dirmask); 203138471Sphk 204171757Sbde ma = mount_argb(ma, args.flags & MSDOSFSMNT_SHORTNAME, "noshortname"); 205171757Sbde ma = mount_argb(ma, args.flags & MSDOSFSMNT_LONGNAME, "nolongname"); 206171757Sbde ma = mount_argb(ma, !(args.flags & MSDOSFSMNT_NOWIN95), "nowin95"); 207171757Sbde ma = mount_argb(ma, args.flags & MSDOSFSMNT_KICONV, "nokiconv"); 208138471Sphk 209171757Sbde ma = mount_argsu(ma, "cs_win", args.cs_win, MAXCSLEN); 210171757Sbde ma = mount_argsu(ma, "cs_dos", args.cs_dos, MAXCSLEN); 211171757Sbde ma = mount_argsu(ma, "cs_local", args.cs_local, MAXCSLEN); 212138471Sphk 213138471Sphk error = kernel_mount(ma, flags); 214138471Sphk 215138471Sphk return (error); 216138471Sphk} 217138471Sphk 2182893Sdfr/* 2198876Srgrimes * mp - path - addr in user space of mount point (ie /usr or whatever) 2202893Sdfr * data - addr in user space of mount params including the name of the block 2218876Srgrimes * special file to treat as a filesystem. 2222893Sdfr */ 22312144Sphkstatic int 224191990Sattiliomsdosfs_mount(struct mount *mp) 2252893Sdfr{ 2262893Sdfr struct vnode *devvp; /* vnode for blk device to mount */ 227191990Sattilio struct thread *td; 22833548Sjkh /* msdosfs specific mount control block */ 22933548Sjkh struct msdosfsmount *pmp = NULL; 230132902Sphk struct nameidata ndp; 231138689Sphk int error, flags; 232184413Strasz accmode_t accmode; 233138471Sphk char *from; 2342893Sdfr 235191990Sattilio td = curthread; 236138471Sphk if (vfs_filteropt(mp->mnt_optnew, msdosfs_opts)) 237138471Sphk return (EINVAL); 238138471Sphk 2392893Sdfr /* 24033548Sjkh * If updating, check whether changing from read-only to 24133548Sjkh * read/write; if there is no device name, that's all we do. 2422893Sdfr */ 2432893Sdfr if (mp->mnt_flag & MNT_UPDATE) { 24433548Sjkh pmp = VFSTOMSDOSFS(mp); 245158924Srodrigc if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) { 246165022Srodrigc /* 247165022Srodrigc * Forbid export requests if filesystem has 248165022Srodrigc * MSDOSFS_LARGEFS flag set. 249165022Srodrigc */ 250165022Srodrigc if ((pmp->pm_flags & MSDOSFS_LARGEFS) != 0) { 251165022Srodrigc vfs_mount_error(mp, 252165022Srodrigc "MSDOSFS_LARGEFS flag set, cannot export"); 253138689Sphk return (EOPNOTSUPP); 254165022Srodrigc } 255138689Sphk } 256137036Sphk if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && 257138471Sphk vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) { 258191990Sattilio error = VFS_SYNC(mp, MNT_WAIT); 259133287Sphk if (error) 260133287Sphk return (error); 2612893Sdfr flags = WRITECLOSE; 2622893Sdfr if (mp->mnt_flag & MNT_FORCE) 2632893Sdfr flags |= FORCECLOSE; 264132023Salfred error = vflush(mp, 0, flags, td); 265138471Sphk if (error) 266138471Sphk return (error); 267172883Sdelphij 268172883Sdelphij /* 269172883Sdelphij * Now the volume is clean. Mark it so while the 270172883Sdelphij * device is still rw. 271172883Sdelphij */ 272172883Sdelphij error = markvoldirty(pmp, 0); 273172883Sdelphij if (error) { 274172883Sdelphij (void)markvoldirty(pmp, 1); 275172883Sdelphij return (error); 276172883Sdelphij } 277172883Sdelphij 278172883Sdelphij /* Downgrade the device from rw to ro. */ 279137036Sphk g_topology_lock(); 280171551Sbde error = g_access(pmp->pm_cp, 0, -1, 0); 281137036Sphk g_topology_unlock(); 282172883Sdelphij if (error) { 283172883Sdelphij (void)markvoldirty(pmp, 1); 284171551Sbde return (error); 285172883Sdelphij } 286171551Sbde 287172883Sdelphij /* 288172883Sdelphij * Backing out after an error was painful in the 289172883Sdelphij * above. Now we are committed to succeeding. 290172883Sdelphij */ 291172883Sdelphij pmp->pm_fmod = 0; 292172883Sdelphij pmp->pm_flags |= MSDOSFSMNT_RONLY; 293172883Sdelphij MNT_ILOCK(mp); 294172883Sdelphij mp->mnt_flag |= MNT_RDONLY; 295172883Sdelphij MNT_IUNLOCK(mp); 296138471Sphk } else if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && 297138471Sphk !vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) { 29833548Sjkh /* 29933548Sjkh * If upgrade to read-write by non-root, then verify 30033548Sjkh * that user has necessary permissions on the device. 30133548Sjkh */ 302164033Srwatson devvp = pmp->pm_devvp; 303175202Sattilio vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 304164033Srwatson error = VOP_ACCESS(devvp, VREAD | VWRITE, 305171757Sbde td->td_ucred, td); 306164033Srwatson if (error) 307164033Srwatson error = priv_check(td, PRIV_VFS_MOUNT_PERM); 308164033Srwatson if (error) { 309175294Sattilio VOP_UNLOCK(devvp, 0); 310164033Srwatson return (error); 31133548Sjkh } 312175294Sattilio VOP_UNLOCK(devvp, 0); 313137036Sphk g_topology_lock(); 314137036Sphk error = g_access(pmp->pm_cp, 0, 1, 0); 315137036Sphk g_topology_unlock(); 316137036Sphk if (error) 317137036Sphk return (error); 318123963Sbde 319172883Sdelphij pmp->pm_fmod = 1; 320172883Sdelphij pmp->pm_flags &= ~MSDOSFSMNT_RONLY; 321172883Sdelphij MNT_ILOCK(mp); 322172883Sdelphij mp->mnt_flag &= ~MNT_RDONLY; 323172883Sdelphij MNT_IUNLOCK(mp); 324165836Srodrigc 325123963Sbde /* Now that the volume is modifiable, mark it dirty. */ 326123873Strhodes error = markvoldirty(pmp, 1); 327123873Strhodes if (error) 328172883Sdelphij return (error); 32933548Sjkh } 3302893Sdfr } 3312893Sdfr /* 33233548Sjkh * Not an update, or updating the name: look up the name 333125796Sbde * and verify that it refers to a sensible disk device. 3342893Sdfr */ 335138471Sphk if (vfs_getopt(mp->mnt_optnew, "from", (void **)&from, NULL)) 336138471Sphk return (EINVAL); 337149720Sssouhlal NDINIT(&ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, from, td); 338132902Sphk error = namei(&ndp); 33933548Sjkh if (error) 34033548Sjkh return (error); 341132902Sphk devvp = ndp.ni_vp; 342132902Sphk NDFREE(&ndp, NDF_ONLY_PNBUF); 3438876Srgrimes 34455756Sphk if (!vn_isdisk(devvp, &error)) { 345149720Sssouhlal vput(devvp); 34655756Sphk return (error); 3472893Sdfr } 3482893Sdfr /* 34933548Sjkh * If mount by non-root, then verify that user has necessary 35033548Sjkh * permissions on the device. 3512893Sdfr */ 352184413Strasz accmode = VREAD; 353164033Srwatson if ((mp->mnt_flag & MNT_RDONLY) == 0) 354184413Strasz accmode |= VWRITE; 355184413Strasz error = VOP_ACCESS(devvp, accmode, td->td_ucred, td); 356164033Srwatson if (error) 357164033Srwatson error = priv_check(td, PRIV_VFS_MOUNT_PERM); 358164033Srwatson if (error) { 359164033Srwatson vput(devvp); 360164033Srwatson return (error); 36133548Sjkh } 36233548Sjkh if ((mp->mnt_flag & MNT_UPDATE) == 0) { 363183754Sattilio error = mountmsdosfs(devvp, mp); 36433548Sjkh#ifdef MSDOSFS_DEBUG /* only needed for the printf below */ 36533548Sjkh pmp = VFSTOMSDOSFS(mp); 36633548Sjkh#endif 36733548Sjkh } else { 368204589Skib vput(devvp); 3692893Sdfr if (devvp != pmp->pm_devvp) 370204589Skib return (EINVAL); /* XXX needs translation */ 3712893Sdfr } 3722893Sdfr if (error) { 3732893Sdfr vrele(devvp); 37433548Sjkh return (error); 37533548Sjkh } 37633548Sjkh 377138471Sphk error = update_mp(mp, td); 37833548Sjkh if (error) { 379134345Stjr if ((mp->mnt_flag & MNT_UPDATE) == 0) 380191990Sattilio msdosfs_unmount(mp, MNT_FORCE); 3812893Sdfr return error; 3822893Sdfr } 383171757Sbde 384138471Sphk vfs_mountedfrom(mp, from); 3852893Sdfr#ifdef MSDOSFS_DEBUG 386138471Sphk printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); 3872893Sdfr#endif 38833548Sjkh return (0); 3892893Sdfr} 3902893Sdfr 39112144Sphkstatic int 392183754Sattiliomountmsdosfs(struct vnode *devvp, struct mount *mp) 3932893Sdfr{ 39433548Sjkh struct msdosfsmount *pmp; 39533548Sjkh struct buf *bp; 396189120Sjhb struct cdev *dev; 3972893Sdfr union bootsector *bsp; 3982893Sdfr struct byte_bpb33 *b33; 3992893Sdfr struct byte_bpb50 *b50; 40033548Sjkh struct byte_bpb710 *b710; 40133548Sjkh u_int8_t SecPerClust; 40255188Sbp u_long clusters; 403171757Sbde int ronly, error; 404137036Sphk struct g_consumer *cp; 405137036Sphk struct bufobj *bo; 4062893Sdfr 407189120Sjhb bp = NULL; /* This and pmp both used in error_exit. */ 408189120Sjhb pmp = NULL; 409171551Sbde ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 410189120Sjhb 411189120Sjhb dev = devvp->v_rdev; 412300371Skib if (atomic_cmpset_acq_ptr((uintptr_t *)&dev->si_mountpt, 0, 413300371Skib (uintptr_t)mp) == 0) { 414300371Skib VOP_UNLOCK(devvp, 0); 415300371Skib return (EBUSY); 416300371Skib } 417137036Sphk g_topology_lock(); 418171551Sbde error = g_vfs_open(devvp, &cp, "msdosfs", ronly ? 0 : 1); 419137036Sphk g_topology_unlock(); 420300371Skib if (error != 0) { 421300371Skib atomic_store_rel_ptr((uintptr_t *)&dev->si_mountpt, 0); 422300371Skib VOP_UNLOCK(devvp, 0); 423300371Skib return (error); 424300371Skib } 425300371Skib dev_ref(dev); 426175294Sattilio VOP_UNLOCK(devvp, 0); 42733548Sjkh 428137036Sphk bo = &devvp->v_bufobj; 42933548Sjkh 4302893Sdfr /* 43133548Sjkh * Read the boot sector of the filesystem, and then check the 43233548Sjkh * boot signature. If not a dos boot sector then error out. 43356674Snyan * 434171408Sbde * NOTE: 8192 is a magic size that works for ffs. 4352893Sdfr */ 436171408Sbde error = bread(devvp, 0, 8192, NOCRED, &bp); 4373152Sphk if (error) 4382893Sdfr goto error_exit; 43933548Sjkh bp->b_flags |= B_AGE; 44033548Sjkh bsp = (union bootsector *)bp->b_data; 44133548Sjkh b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB; 44233548Sjkh b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB; 443105655Sjhb b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB; 44433548Sjkh 44556674Snyan#ifndef MSDOSFS_NOCHECKSIG 44687068Sjhb if (bsp->bs50.bsBootSectSig0 != BOOTSIG0 44787068Sjhb || bsp->bs50.bsBootSectSig1 != BOOTSIG1) { 44887068Sjhb error = EINVAL; 44987068Sjhb goto error_exit; 45087068Sjhb } 45156674Snyan#endif 4522893Sdfr 453111119Simp pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK | M_ZERO); 4542893Sdfr pmp->pm_mountp = mp; 455137036Sphk pmp->pm_cp = cp; 456137036Sphk pmp->pm_bo = bo; 4572893Sdfr 458204470Skib lockinit(&pmp->pm_fatlock, 0, msdosfs_lock_msg, 0, 0); 459204470Skib 4602893Sdfr /* 461171551Sbde * Initialize ownerships and permissions, since nothing else will 462173728Smaxim * initialize them iff we are mounting root. 463171551Sbde */ 464171551Sbde pmp->pm_uid = UID_ROOT; 465171551Sbde pmp->pm_gid = GID_WHEEL; 466171551Sbde pmp->pm_mask = pmp->pm_dirmask = S_IXUSR | S_IXGRP | S_IXOTH | 467171551Sbde S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR; 468171551Sbde 469171551Sbde /* 470166340Srodrigc * Experimental support for large MS-DOS filesystems. 471166340Srodrigc * WARNING: This uses at least 32 bytes of kernel memory (which is not 472166340Srodrigc * reclaimed until the FS is unmounted) for each file on disk to map 473166340Srodrigc * between the 32-bit inode numbers used by VFS and the 64-bit 474166340Srodrigc * pseudo-inode numbers used internally by msdosfs. This is only 475166340Srodrigc * safe to use in certain controlled situations (e.g. read-only FS 476166340Srodrigc * with less than 1 million files). 477166340Srodrigc * Since the mappings do not persist across unmounts (or reboots), these 478166340Srodrigc * filesystems are not suitable for exporting through NFS, or any other 479166340Srodrigc * application that requires fixed inode numbers. 480166340Srodrigc */ 481171757Sbde vfs_flagopt(mp->mnt_optnew, "large", &pmp->pm_flags, MSDOSFS_LARGEFS); 482166340Srodrigc 483166340Srodrigc /* 4842893Sdfr * Compute several useful quantities from the bpb in the 4852893Sdfr * bootsector. Copy in the dos 5 variant of the bpb then fix up 4862893Sdfr * the fields that are different between dos 5 and dos 3.3. 4872893Sdfr */ 48833548Sjkh SecPerClust = b50->bpbSecPerClust; 4892893Sdfr pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 490113979Sjhb if (pmp->pm_BytesPerSec < DEV_BSIZE) { 491113979Sjhb error = EINVAL; 492113979Sjhb goto error_exit; 493113979Sjhb } 4942893Sdfr pmp->pm_ResSectors = getushort(b50->bpbResSectors); 4952893Sdfr pmp->pm_FATs = b50->bpbFATs; 4962893Sdfr pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 4972893Sdfr pmp->pm_Sectors = getushort(b50->bpbSectors); 4982893Sdfr pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 4992893Sdfr pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 5002893Sdfr pmp->pm_Heads = getushort(b50->bpbHeads); 50133548Sjkh pmp->pm_Media = b50->bpbMedia; 5022893Sdfr 50356674Snyan /* calculate the ratio of sector size to DEV_BSIZE */ 50456674Snyan pmp->pm_BlkPerSec = pmp->pm_BytesPerSec / DEV_BSIZE; 50556674Snyan 506176431Smarcel /* 507176431Smarcel * We don't check pm_Heads nor pm_SecPerTrack, because 508176431Smarcel * these may not be set for EFI file systems. We don't 509176431Smarcel * use these anyway, so we're unaffected if they are 510176431Smarcel * invalid. 511176431Smarcel */ 512176431Smarcel if (!pmp->pm_BytesPerSec || !SecPerClust) { 51387068Sjhb error = EINVAL; 51487068Sjhb goto error_exit; 51587068Sjhb } 5162893Sdfr 5172893Sdfr if (pmp->pm_Sectors == 0) { 5182893Sdfr pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 5192893Sdfr pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 5202893Sdfr } else { 5212893Sdfr pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 5222893Sdfr pmp->pm_HugeSectors = pmp->pm_Sectors; 5232893Sdfr } 524166340Srodrigc if (!(pmp->pm_flags & MSDOSFS_LARGEFS)) { 525171757Sbde if (pmp->pm_HugeSectors > 0xffffffff / 526166340Srodrigc (pmp->pm_BytesPerSec / sizeof(struct direntry)) + 1) { 527166340Srodrigc /* 528166340Srodrigc * We cannot deal currently with this size of disk 529166340Srodrigc * due to fileid limitations (see msdosfs_getattr and 530166340Srodrigc * msdosfs_readdir) 531166340Srodrigc */ 532166340Srodrigc error = EINVAL; 533166340Srodrigc vfs_mount_error(mp, 534166340Srodrigc "Disk too big, try '-o large' mount option"); 535166340Srodrigc goto error_exit; 536166340Srodrigc } 53733548Sjkh } 53833548Sjkh 53933548Sjkh if (pmp->pm_RootDirEnts == 0) { 540246216Skib if (pmp->pm_FATsecs 54133548Sjkh || getushort(b710->bpbFSVers)) { 54233548Sjkh error = EINVAL; 543227817Skib#ifdef MSDOSFS_DEBUG 54435046Sache printf("mountmsdosfs(): bad FAT32 filesystem\n"); 545227817Skib#endif 54633548Sjkh goto error_exit; 54733548Sjkh } 54833548Sjkh pmp->pm_fatmask = FAT32_MASK; 54933548Sjkh pmp->pm_fatmult = 4; 55033548Sjkh pmp->pm_fatdiv = 1; 55133548Sjkh pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs); 55233548Sjkh if (getushort(b710->bpbExtFlags) & FATMIRROR) 55333548Sjkh pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM; 55433548Sjkh else 55533548Sjkh pmp->pm_flags |= MSDOSFS_FATMIRROR; 55633548Sjkh } else 55733548Sjkh pmp->pm_flags |= MSDOSFS_FATMIRROR; 55833548Sjkh 55956674Snyan /* 56056674Snyan * Check a few values (could do some more): 56156674Snyan * - logical sector size: power of 2, >= block size 56256674Snyan * - sectors per cluster: power of 2, >= 1 56356674Snyan * - number of sectors: >= 1, <= size of partition 564113979Sjhb * - number of FAT sectors: >= 1 56556674Snyan */ 56656674Snyan if ( (SecPerClust == 0) 56756674Snyan || (SecPerClust & (SecPerClust - 1)) 56856674Snyan || (pmp->pm_BytesPerSec < DEV_BSIZE) 56956674Snyan || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) 57056674Snyan || (pmp->pm_HugeSectors == 0) 571113979Sjhb || (pmp->pm_FATsecs == 0) 572206098Savg || (SecPerClust * pmp->pm_BlkPerSec > MAXBSIZE / DEV_BSIZE) 57356674Snyan ) { 57456674Snyan error = EINVAL; 57556674Snyan goto error_exit; 57656674Snyan } 57733548Sjkh 57856674Snyan pmp->pm_HugeSectors *= pmp->pm_BlkPerSec; 579171757Sbde pmp->pm_HiddenSects *= pmp->pm_BlkPerSec; /* XXX not used? */ 58056674Snyan pmp->pm_FATsecs *= pmp->pm_BlkPerSec; 58156674Snyan SecPerClust *= pmp->pm_BlkPerSec; 58256674Snyan 58356674Snyan pmp->pm_fatblk = pmp->pm_ResSectors * pmp->pm_BlkPerSec; 58456674Snyan 58533548Sjkh if (FAT32(pmp)) { 58633548Sjkh pmp->pm_rootdirblk = getulong(b710->bpbRootClust); 58733548Sjkh pmp->pm_firstcluster = pmp->pm_fatblk 58833548Sjkh + (pmp->pm_FATs * pmp->pm_FATsecs); 58956674Snyan pmp->pm_fsinfo = getushort(b710->bpbFSInfo) * pmp->pm_BlkPerSec; 59033548Sjkh } else { 59133548Sjkh pmp->pm_rootdirblk = pmp->pm_fatblk + 59233548Sjkh (pmp->pm_FATs * pmp->pm_FATsecs); 593298649Spfg pmp->pm_rootdirsize = howmany(pmp->pm_RootDirEnts * 594298649Spfg sizeof(struct direntry), DEV_BSIZE); /* in blocks */ 59533548Sjkh pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 59633548Sjkh } 59733548Sjkh 59855188Sbp pmp->pm_maxcluster = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 59955188Sbp SecPerClust + 1; 600171757Sbde pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE; /* XXX not used? */ 60133548Sjkh 60233548Sjkh if (pmp->pm_fatmask == 0) { 60333548Sjkh if (pmp->pm_maxcluster 60433548Sjkh <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) { 60533548Sjkh /* 60633548Sjkh * This will usually be a floppy disk. This size makes 60733548Sjkh * sure that one fat entry will not be split across 60833548Sjkh * multiple blocks. 60933548Sjkh */ 61033548Sjkh pmp->pm_fatmask = FAT12_MASK; 61133548Sjkh pmp->pm_fatmult = 3; 61233548Sjkh pmp->pm_fatdiv = 2; 61333548Sjkh } else { 61433548Sjkh pmp->pm_fatmask = FAT16_MASK; 61533548Sjkh pmp->pm_fatmult = 2; 61633548Sjkh pmp->pm_fatdiv = 1; 61733548Sjkh } 61833548Sjkh } 61955188Sbp 62055188Sbp clusters = (pmp->pm_fatsize / pmp->pm_fatmult) * pmp->pm_fatdiv; 62155188Sbp if (pmp->pm_maxcluster >= clusters) { 622227817Skib#ifdef MSDOSFS_DEBUG 62355188Sbp printf("Warning: number of clusters (%ld) exceeds FAT " 62455188Sbp "capacity (%ld)\n", pmp->pm_maxcluster + 1, clusters); 625227817Skib#endif 62655188Sbp pmp->pm_maxcluster = clusters - 1; 62755188Sbp } 62855188Sbp 6292893Sdfr if (FAT12(pmp)) 630171408Sbde pmp->pm_fatblocksize = 3 * 512; 6312893Sdfr else 632171408Sbde pmp->pm_fatblocksize = PAGE_SIZE; 633171408Sbde pmp->pm_fatblocksize = roundup(pmp->pm_fatblocksize, 634171408Sbde pmp->pm_BytesPerSec); 63556674Snyan pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE; 63656674Snyan pmp->pm_bnshift = ffs(DEV_BSIZE) - 1; 6372893Sdfr 6382893Sdfr /* 6392893Sdfr * Compute mask and shift value for isolating cluster relative byte 6402893Sdfr * offsets and cluster numbers from a file offset. 6412893Sdfr */ 64256674Snyan pmp->pm_bpcluster = SecPerClust * DEV_BSIZE; 64333548Sjkh pmp->pm_crbomask = pmp->pm_bpcluster - 1; 64433548Sjkh pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1; 64533548Sjkh 64633548Sjkh /* 64733548Sjkh * Check for valid cluster size 64833548Sjkh * must be a power of 2 64933548Sjkh */ 65033548Sjkh if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) { 6512893Sdfr error = EINVAL; 6522893Sdfr goto error_exit; 6532893Sdfr } 6542893Sdfr 65533548Sjkh /* 65633548Sjkh * Release the bootsector buffer. 65733548Sjkh */ 65833548Sjkh brelse(bp); 65933548Sjkh bp = NULL; 66033548Sjkh 66133548Sjkh /* 662171731Sbde * Check the fsinfo sector if we have one. Silently fix up our 663171731Sbde * in-core copy of fp->fsinxtfree if it is unknown (0xffffffff) 664171731Sbde * or too large. Ignore fp->fsinfree for now, since we need to 665171731Sbde * read the entire FAT anyway to fill the inuse map. 66633548Sjkh */ 66733548Sjkh if (pmp->pm_fsinfo) { 66833548Sjkh struct fsinfo *fp; 66933548Sjkh 670171711Sbde if ((error = bread(devvp, pmp->pm_fsinfo, pmp->pm_BytesPerSec, 67156674Snyan NOCRED, &bp)) != 0) 67233548Sjkh goto error_exit; 67333548Sjkh fp = (struct fsinfo *)bp->b_data; 67433548Sjkh if (!bcmp(fp->fsisig1, "RRaA", 4) 67533548Sjkh && !bcmp(fp->fsisig2, "rrAa", 4) 676171406Sbde && !bcmp(fp->fsisig3, "\0\0\125\252", 4)) { 67733548Sjkh pmp->pm_nxtfree = getulong(fp->fsinxtfree); 678171731Sbde if (pmp->pm_nxtfree > pmp->pm_maxcluster) 679125934Stjr pmp->pm_nxtfree = CLUST_FIRST; 680125934Stjr } else 68133548Sjkh pmp->pm_fsinfo = 0; 68233548Sjkh brelse(bp); 68333548Sjkh bp = NULL; 68416363Sasami } 6852893Sdfr 6862893Sdfr /* 687171731Sbde * Finish initializing pmp->pm_nxtfree (just in case the first few 688171731Sbde * sectors aren't properly reserved in the FAT). This completes 689171731Sbde * the fixup for fp->fsinxtfree, and fixes up the zero-initialized 690171731Sbde * value if there is no fsinfo. We will use pmp->pm_nxtfree 691171731Sbde * internally even if there is no fsinfo. 6922893Sdfr */ 693171731Sbde if (pmp->pm_nxtfree < CLUST_FIRST) 694171731Sbde pmp->pm_nxtfree = CLUST_FIRST; 6952893Sdfr 6962893Sdfr /* 6972893Sdfr * Allocate memory for the bitmap of allocated clusters, and then 6982893Sdfr * fill it in. 6992893Sdfr */ 700126086Sbde pmp->pm_inusemap = malloc(howmany(pmp->pm_maxcluster + 1, N_INUSEBITS) 7012893Sdfr * sizeof(*pmp->pm_inusemap), 702111119Simp M_MSDOSFSFAT, M_WAITOK); 7032893Sdfr 7042893Sdfr /* 7052893Sdfr * fillinusemap() needs pm_devvp. 7062893Sdfr */ 7072893Sdfr pmp->pm_devvp = devvp; 708189120Sjhb pmp->pm_dev = dev; 7092893Sdfr 7102893Sdfr /* 7112893Sdfr * Have the inuse map filled in. 7122893Sdfr */ 713204471Skib MSDOSFS_LOCK_MP(pmp); 714204471Skib error = fillinusemap(pmp); 715204471Skib MSDOSFS_UNLOCK_MP(pmp); 716204471Skib if (error != 0) 7172893Sdfr goto error_exit; 7182893Sdfr 7192893Sdfr /* 7202893Sdfr * If they want fat updates to be synchronous then let them suffer 7212893Sdfr * the performance degradation in exchange for the on disk copy of 7222893Sdfr * the fat being correct just about all the time. I suppose this 7232893Sdfr * would be a good thing to turn on if the kernel is still flakey. 7242893Sdfr */ 72533548Sjkh if (mp->mnt_flag & MNT_SYNCHRONOUS) 72633548Sjkh pmp->pm_flags |= MSDOSFSMNT_WAITONFAT; 7272893Sdfr 7282893Sdfr /* 7292893Sdfr * Finish up. 7302893Sdfr */ 73133548Sjkh if (ronly) 73233548Sjkh pmp->pm_flags |= MSDOSFSMNT_RONLY; 733123873Strhodes else { 734172883Sdelphij if ((error = markvoldirty(pmp, 1)) != 0) { 735172883Sdelphij (void)markvoldirty(pmp, 0); 736123963Sbde goto error_exit; 737172883Sdelphij } 7382893Sdfr pmp->pm_fmod = 1; 739123873Strhodes } 740172697Salfred mp->mnt_data = pmp; 74150256Sbde mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); 74223134Sbde mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 743162647Stegge MNT_ILOCK(mp); 74423997Speter mp->mnt_flag |= MNT_LOCAL; 745308545Skib mp->mnt_kern_flag |= MNTK_USES_BCACHE | MNTK_NO_IOPF; 746162647Stegge MNT_IUNLOCK(mp); 7472893Sdfr 748166340Srodrigc if (pmp->pm_flags & MSDOSFS_LARGEFS) 749166340Srodrigc msdosfs_fileno_init(mp); 750131523Stjr 7512893Sdfr return 0; 7522893Sdfr 75333548Sjkherror_exit: 75433548Sjkh if (bp) 75533548Sjkh brelse(bp); 756137036Sphk if (cp != NULL) { 757137036Sphk g_topology_lock(); 758183754Sattilio g_vfs_close(cp); 759137036Sphk g_topology_unlock(); 760137036Sphk } 7612893Sdfr if (pmp) { 762204576Skib lockdestroy(&pmp->pm_fatlock); 763308539Skib free(pmp->pm_inusemap, M_MSDOSFSFAT); 76433548Sjkh free(pmp, M_MSDOSFSMNT); 765172697Salfred mp->mnt_data = NULL; 7662893Sdfr } 767300371Skib atomic_store_rel_ptr((uintptr_t *)&dev->si_mountpt, 0); 768189120Sjhb dev_rel(dev); 76933548Sjkh return (error); 7702893Sdfr} 7712893Sdfr 7722893Sdfr/* 7732893Sdfr * Unmount the filesystem described by mp. 7742893Sdfr */ 77512144Sphkstatic int 776191990Sattiliomsdosfs_unmount(struct mount *mp, int mntflags) 7772893Sdfr{ 77833548Sjkh struct msdosfsmount *pmp; 77933548Sjkh int error, flags; 7802893Sdfr 781281121Skib error = flags = 0; 782281121Skib pmp = VFSTOMSDOSFS(mp); 783281121Skib if ((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0) 784281121Skib error = msdosfs_sync(mp, MNT_WAIT); 785281121Skib if ((mntflags & MNT_FORCE) != 0) 7862893Sdfr flags |= FORCECLOSE; 787281121Skib else if (error != 0) 788275638Skib return (error); 789191990Sattilio error = vflush(mp, 0, flags, curthread); 790275638Skib if (error != 0 && error != ENXIO) 791275638Skib return (error); 792172883Sdelphij if ((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0) { 793172883Sdelphij error = markvoldirty(pmp, 0); 794188956Strasz if (error && error != ENXIO) { 795172883Sdelphij (void)markvoldirty(pmp, 1); 796172883Sdelphij return (error); 797172883Sdelphij } 798172883Sdelphij } 799120492Sfjoe if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) { 800120492Sfjoe if (pmp->pm_w2u) 801120492Sfjoe msdosfs_iconv->close(pmp->pm_w2u); 802120492Sfjoe if (pmp->pm_u2w) 803120492Sfjoe msdosfs_iconv->close(pmp->pm_u2w); 804120492Sfjoe if (pmp->pm_d2u) 805120492Sfjoe msdosfs_iconv->close(pmp->pm_d2u); 806120492Sfjoe if (pmp->pm_u2d) 807120492Sfjoe msdosfs_iconv->close(pmp->pm_u2d); 808120492Sfjoe } 809123873Strhodes 81033548Sjkh#ifdef MSDOSFS_DEBUG 81133548Sjkh { 81233548Sjkh struct vnode *vp = pmp->pm_devvp; 813177493Sjeff struct bufobj *bo; 81433548Sjkh 815177493Sjeff bo = &vp->v_bufobj; 816177493Sjeff BO_LOCK(bo); 817103936Sjeff VI_LOCK(vp); 818142235Sphk vn_printf(vp, 819142235Sphk "msdosfs_umount(): just before calling VOP_CLOSE()\n"); 82033548Sjkh printf("freef %p, freeb %p, mount %p\n", 821234482Smckusick TAILQ_NEXT(vp, v_actfreelist), vp->v_actfreelist.tqe_prev, 82233548Sjkh vp->v_mount); 82333548Sjkh printf("cleanblkhd %p, dirtyblkhd %p, numoutput %ld, type %d\n", 824136943Sphk TAILQ_FIRST(&vp->v_bufobj.bo_clean.bv_hd), 825136943Sphk TAILQ_FIRST(&vp->v_bufobj.bo_dirty.bv_hd), 826136943Sphk vp->v_bufobj.bo_numoutput, vp->v_type); 827103936Sjeff VI_UNLOCK(vp); 828177493Sjeff BO_UNLOCK(bo); 82933548Sjkh } 83033548Sjkh#endif 831137036Sphk g_topology_lock(); 832183754Sattilio g_vfs_close(pmp->pm_cp); 833137036Sphk g_topology_unlock(); 834300371Skib atomic_store_rel_ptr((uintptr_t *)&pmp->pm_dev->si_mountpt, 0); 8352893Sdfr vrele(pmp->pm_devvp); 836189120Sjhb dev_rel(pmp->pm_dev); 83733548Sjkh free(pmp->pm_inusemap, M_MSDOSFSFAT); 838172883Sdelphij if (pmp->pm_flags & MSDOSFS_LARGEFS) 839166340Srodrigc msdosfs_fileno_free(mp); 840204470Skib lockdestroy(&pmp->pm_fatlock); 84133548Sjkh free(pmp, M_MSDOSFSMNT); 842172697Salfred mp->mnt_data = NULL; 843162647Stegge MNT_ILOCK(mp); 84423997Speter mp->mnt_flag &= ~MNT_LOCAL; 845162647Stegge MNT_IUNLOCK(mp); 846188956Strasz return (error); 8472893Sdfr} 8482893Sdfr 84912144Sphkstatic int 850191990Sattiliomsdosfs_root(struct mount *mp, int flags, struct vnode **vpp) 8512893Sdfr{ 85233548Sjkh struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 8532893Sdfr struct denode *ndep; 8542893Sdfr int error; 8552893Sdfr 8562893Sdfr#ifdef MSDOSFS_DEBUG 85733548Sjkh printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp); 8582893Sdfr#endif 85933548Sjkh error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep); 86033548Sjkh if (error) 86133548Sjkh return (error); 86233548Sjkh *vpp = DETOV(ndep); 86333548Sjkh return (0); 8642893Sdfr} 8652893Sdfr 86612144Sphkstatic int 867191990Sattiliomsdosfs_statfs(struct mount *mp, struct statfs *sbp) 8682893Sdfr{ 86933548Sjkh struct msdosfsmount *pmp; 8702893Sdfr 87133548Sjkh pmp = VFSTOMSDOSFS(mp); 8722893Sdfr sbp->f_bsize = pmp->pm_bpcluster; 8732893Sdfr sbp->f_iosize = pmp->pm_bpcluster; 87455188Sbp sbp->f_blocks = pmp->pm_maxcluster + 1; 8752893Sdfr sbp->f_bfree = pmp->pm_freeclustercount; 8762893Sdfr sbp->f_bavail = pmp->pm_freeclustercount; 877171757Sbde sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ 8782893Sdfr sbp->f_ffree = 0; /* what to put in here? */ 87933548Sjkh return (0); 8802893Sdfr} 8812893Sdfr 882246921Skib/* 883246921Skib * If we have an FSInfo block, update it. 884246921Skib */ 88512144Sphkstatic int 886246921Skibmsdosfs_fsiflush(struct msdosfsmount *pmp, int waitfor) 887246921Skib{ 888246921Skib struct fsinfo *fp; 889246921Skib struct buf *bp; 890246921Skib int error; 891246921Skib 892246921Skib MSDOSFS_LOCK_MP(pmp); 893246921Skib if (pmp->pm_fsinfo == 0 || (pmp->pm_flags & MSDOSFS_FSIMOD) == 0) { 894246921Skib error = 0; 895246921Skib goto unlock; 896246921Skib } 897246921Skib error = bread(pmp->pm_devvp, pmp->pm_fsinfo, pmp->pm_BytesPerSec, 898246921Skib NOCRED, &bp); 899246921Skib if (error != 0) { 900246921Skib brelse(bp); 901246921Skib goto unlock; 902246921Skib } 903246921Skib fp = (struct fsinfo *)bp->b_data; 904246921Skib putulong(fp->fsinfree, pmp->pm_freeclustercount); 905246921Skib putulong(fp->fsinxtfree, pmp->pm_nxtfree); 906246921Skib pmp->pm_flags &= ~MSDOSFS_FSIMOD; 907246921Skib if (waitfor == MNT_WAIT) 908246921Skib error = bwrite(bp); 909246921Skib else 910246921Skib bawrite(bp); 911246921Skibunlock: 912246921Skib MSDOSFS_UNLOCK_MP(pmp); 913246921Skib return (error); 914246921Skib} 915246921Skib 916246921Skibstatic int 917191990Sattiliomsdosfs_sync(struct mount *mp, int waitfor) 9182893Sdfr{ 91933548Sjkh struct vnode *vp, *nvp; 920191990Sattilio struct thread *td; 9212893Sdfr struct denode *dep; 92233548Sjkh struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 92333548Sjkh int error, allerror = 0; 9242893Sdfr 925191990Sattilio td = curthread; 926191990Sattilio 9272893Sdfr /* 9282893Sdfr * If we ever switch to not updating all of the fats all the time, 9292893Sdfr * this would be the place to update them from the first one. 9302893Sdfr */ 93146568Speter if (pmp->pm_fmod != 0) { 93233548Sjkh if (pmp->pm_flags & MSDOSFSMNT_RONLY) 9332893Sdfr panic("msdosfs_sync: rofs mod"); 9342893Sdfr else { 9352893Sdfr /* update fats here */ 9362893Sdfr } 93746568Speter } 9382893Sdfr /* 93933548Sjkh * Write back each (modified) denode. 9402893Sdfr */ 9412893Sdfrloop: 942234386Smckusick MNT_VNODE_FOREACH_ALL(vp, mp, nvp) { 943234386Smckusick if (vp->v_type == VNON) { 944120785Sjeff VI_UNLOCK(vp); 945120785Sjeff continue; 946120785Sjeff } 9472893Sdfr dep = VTODE(vp); 948137008Sphk if ((dep->de_flag & 94935511Sdt (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0 && 950136943Sphk (vp->v_bufobj.bo_dirty.bv_cnt == 0 || 951137008Sphk waitfor == MNT_LAZY)) { 952103936Sjeff VI_UNLOCK(vp); 9532893Sdfr continue; 95423134Sbde } 95583366Sjulian error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, td); 95623134Sbde if (error) { 95723134Sbde if (error == ENOENT) 95823134Sbde goto loop; 95923134Sbde continue; 96023134Sbde } 961140048Sphk error = VOP_FSYNC(vp, waitfor, td); 9623152Sphk if (error) 9632893Sdfr allerror = error; 964175294Sattilio VOP_UNLOCK(vp, 0); 965121874Skan vrele(vp); 9662893Sdfr } 9672893Sdfr 9682893Sdfr /* 9692893Sdfr * Flush filesystem control info. 9702893Sdfr */ 97135511Sdt if (waitfor != MNT_LAZY) { 972175202Sattilio vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY); 973140048Sphk error = VOP_FSYNC(pmp->pm_devvp, waitfor, td); 97435511Sdt if (error) 97535511Sdt allerror = error; 976175294Sattilio VOP_UNLOCK(pmp->pm_devvp, 0); 97735511Sdt } 978246921Skib 979246921Skib error = msdosfs_fsiflush(pmp, waitfor); 980246921Skib if (error != 0) 981246921Skib allerror = error; 98233548Sjkh return (allerror); 9832893Sdfr} 9842893Sdfr 985170188Strhodesstatic int 986222167Srmacklemmsdosfs_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp) 987170188Strhodes{ 988170188Strhodes struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 989170188Strhodes struct defid *defhp = (struct defid *) fhp; 990170188Strhodes struct denode *dep; 991170188Strhodes int error; 992170188Strhodes 993170188Strhodes error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep); 994170188Strhodes if (error) { 995170188Strhodes *vpp = NULLVP; 996170188Strhodes return (error); 997170188Strhodes } 998170188Strhodes *vpp = DETOV(dep); 999170188Strhodes vnode_create_vobject(*vpp, dep->de_FileSize, curthread); 1000170188Strhodes return (0); 1001170188Strhodes} 1002170188Strhodes 100312145Sphkstatic struct vfsops msdosfs_vfsops = { 1004170188Strhodes .vfs_fhtovp = msdosfs_fhtovp, 1005138471Sphk .vfs_mount = msdosfs_mount, 1006138471Sphk .vfs_cmount = msdosfs_cmount, 1007116271Sphk .vfs_root = msdosfs_root, 1008116271Sphk .vfs_statfs = msdosfs_statfs, 1009116271Sphk .vfs_sync = msdosfs_sync, 1010116271Sphk .vfs_unmount = msdosfs_unmount, 10112893Sdfr}; 10122946Swollman 101377577SruVFS_SET(msdosfs_vfsops, msdosfs, 0); 1014120492SfjoeMODULE_VERSION(msdosfs, 1); 1015