1*5a0ec814Smiod /* $OpenBSD: msdosfs_vfsops.c,v 1.98 2024/10/18 05:52:32 miod Exp $ */ 2b099d67bSprovos /* $NetBSD: msdosfs_vfsops.c,v 1.48 1997/10/18 02:54:57 briggs Exp $ */ 3df930be7Sderaadt 4df930be7Sderaadt /*- 5b099d67bSprovos * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. 6b099d67bSprovos * Copyright (C) 1994, 1995, 1997 TooLs GmbH. 7df930be7Sderaadt * All rights reserved. 8df930be7Sderaadt * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 9df930be7Sderaadt * 10df930be7Sderaadt * Redistribution and use in source and binary forms, with or without 11df930be7Sderaadt * modification, are permitted provided that the following conditions 12df930be7Sderaadt * are met: 13df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright 14df930be7Sderaadt * notice, this list of conditions and the following disclaimer. 15df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 16df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the 17df930be7Sderaadt * documentation and/or other materials provided with the distribution. 18df930be7Sderaadt * 3. All advertising materials mentioning features or use of this software 19df930be7Sderaadt * must display the following acknowledgement: 20df930be7Sderaadt * This product includes software developed by TooLs GmbH. 21df930be7Sderaadt * 4. The name of TooLs GmbH may not be used to endorse or promote products 22df930be7Sderaadt * derived from this software without specific prior written permission. 23df930be7Sderaadt * 24df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 25df930be7Sderaadt * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26df930be7Sderaadt * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27df930be7Sderaadt * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28df930be7Sderaadt * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 29df930be7Sderaadt * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 30df930be7Sderaadt * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 31df930be7Sderaadt * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 32df930be7Sderaadt * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 33df930be7Sderaadt * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34df930be7Sderaadt */ 35df930be7Sderaadt /* 36df930be7Sderaadt * Written by Paul Popelka (paulp@uts.amdahl.com) 37df930be7Sderaadt * 38df930be7Sderaadt * You can do anything you want with this software, just don't say you wrote 39df930be7Sderaadt * it, and don't remove this notice. 40df930be7Sderaadt * 41df930be7Sderaadt * This software is provided "as is". 42df930be7Sderaadt * 43df930be7Sderaadt * The author supplies this software to be publicly redistributed on the 44df930be7Sderaadt * understanding that the author is not responsible for the correct 45df930be7Sderaadt * functioning of this software in any circumstances and is not liable for 46df930be7Sderaadt * any damages caused by this software. 47df930be7Sderaadt * 48df930be7Sderaadt * October 1992 49df930be7Sderaadt */ 50df930be7Sderaadt 51df930be7Sderaadt #include <sys/param.h> 52df930be7Sderaadt #include <sys/systm.h> 53df930be7Sderaadt #include <sys/namei.h> 54df930be7Sderaadt #include <sys/proc.h> 55df930be7Sderaadt #include <sys/kernel.h> 56df930be7Sderaadt #include <sys/vnode.h> 57fde894e5Stedu #include <sys/lock.h> 58544451c3Sderaadt #include <sys/specdev.h> /* XXX */ /* defines v_rdev */ 59df930be7Sderaadt #include <sys/mount.h> 60df930be7Sderaadt #include <sys/buf.h> 61c0cd3489Sguenther #include <sys/fcntl.h> 62df930be7Sderaadt #include <sys/disklabel.h> 63df930be7Sderaadt #include <sys/ioctl.h> 64df930be7Sderaadt #include <sys/malloc.h> 6516bf7bd1Sderaadt #include <sys/dirent.h> 6661a4b61eSjsing #include <sys/disk.h> 67a34a8c9cSsf #include <sys/dkio.h> 68da6640c1Smillert #include <sys/stdint.h> 69df930be7Sderaadt 70df930be7Sderaadt #include <msdosfs/bpb.h> 71df930be7Sderaadt #include <msdosfs/bootsect.h> 72df930be7Sderaadt #include <msdosfs/direntry.h> 73df930be7Sderaadt #include <msdosfs/denode.h> 74df930be7Sderaadt #include <msdosfs/msdosfsmount.h> 75df930be7Sderaadt #include <msdosfs/fat.h> 76df930be7Sderaadt 77c4071fd1Smillert int msdosfs_mount(struct mount *, const char *, void *, struct nameidata *, 78c4071fd1Smillert struct proc *); 79c4071fd1Smillert int msdosfs_start(struct mount *, int, struct proc *); 80c4071fd1Smillert int msdosfs_unmount(struct mount *, int, struct proc *); 81c4071fd1Smillert int msdosfs_root(struct mount *, struct vnode **); 82c4071fd1Smillert int msdosfs_statfs(struct mount *, struct statfs *, struct proc *); 83976e9839Sderaadt int msdosfs_sync(struct mount *, int, int, struct ucred *, struct proc *); 84c4071fd1Smillert int msdosfs_fhtovp(struct mount *, struct fid *, struct vnode **); 85c4071fd1Smillert int msdosfs_vptofh(struct vnode *, struct fid *); 86c4071fd1Smillert int msdosfs_check_export(struct mount *mp, struct mbuf *nam, 87c4071fd1Smillert int *extflagsp, struct ucred **credanonp); 88879b3eabSniklas 89c4071fd1Smillert int msdosfs_mountfs(struct vnode *, struct mount *, struct proc *, 90c4071fd1Smillert struct msdosfs_args *); 91879b3eabSniklas 921881de8bScsapuntz int msdosfs_sync_vnode(struct vnode *, void *); 931881de8bScsapuntz 94df930be7Sderaadt /* 95df930be7Sderaadt * mp - path - addr in user space of mount point (ie /usr or whatever) 96df930be7Sderaadt * data - addr in user space of mount params including the name of the block 97df930be7Sderaadt * special file to treat as a filesystem. 98df930be7Sderaadt */ 99df930be7Sderaadt int 1007d80fe84Sjasper msdosfs_mount(struct mount *mp, const char *path, void *data, 1017d80fe84Sjasper struct nameidata *ndp, struct proc *p) 102df930be7Sderaadt { 103df930be7Sderaadt struct vnode *devvp; /* vnode for blk device to mount */ 1047efda1a1Sderaadt struct msdosfs_args *args = data; /* will hold data from mount request */ 105879b3eabSniklas /* msdosfs specific mount control block */ 106879b3eabSniklas struct msdosfsmount *pmp = NULL; 107aec3986eSjsing char fname[MNAMELEN]; 108a93bb724Sjsing char fspec[MNAMELEN]; 109df930be7Sderaadt int error, flags; 110df930be7Sderaadt 111df930be7Sderaadt /* 112df930be7Sderaadt * If updating, check whether changing from read-only to 113df930be7Sderaadt * read/write; if there is no device name, that's all we do. 114df930be7Sderaadt */ 115df930be7Sderaadt if (mp->mnt_flag & MNT_UPDATE) { 116df930be7Sderaadt pmp = VFSTOMSDOSFS(mp); 117df930be7Sderaadt error = 0; 11861a4b61eSjsing if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && 11961a4b61eSjsing (mp->mnt_flag & MNT_RDONLY)) { 120d4a31c87Ssf mp->mnt_flag &= ~MNT_RDONLY; 121976e9839Sderaadt VFS_SYNC(mp, MNT_WAIT, 0, p->p_ucred, p); 122d4a31c87Ssf mp->mnt_flag |= MNT_RDONLY; 123d4a31c87Ssf 124df930be7Sderaadt flags = WRITECLOSE; 125df930be7Sderaadt if (mp->mnt_flag & MNT_FORCE) 126df930be7Sderaadt flags |= FORCECLOSE; 127df930be7Sderaadt error = vflush(mp, NULLVP, flags); 128a34a8c9cSsf if (!error) { 129a34a8c9cSsf int force = 0; 130a34a8c9cSsf 131d4a31c87Ssf pmp->pm_flags |= MSDOSFSMNT_RONLY; 132a34a8c9cSsf /* may be not supported, ignore error */ 133a34a8c9cSsf VOP_IOCTL(pmp->pm_devvp, DIOCCACHESYNC, 134a34a8c9cSsf &force, FWRITE, FSCRED, p); 135a34a8c9cSsf } 136df930be7Sderaadt } 137df930be7Sderaadt if (!error && (mp->mnt_flag & MNT_RELOAD)) 138df930be7Sderaadt /* not yet implemented */ 139df930be7Sderaadt error = EOPNOTSUPP; 140df930be7Sderaadt if (error) 141df930be7Sderaadt return (error); 14261a4b61eSjsing if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && 143685efd6eSnatano (mp->mnt_flag & MNT_WANTRDWR)) 14416bf7bd1Sderaadt pmp->pm_flags &= ~MSDOSFSMNT_RONLY; 145685efd6eSnatano 1467efda1a1Sderaadt if (args && args->fspec == NULL) { 147df930be7Sderaadt /* 148df930be7Sderaadt * Process export requests. 149df930be7Sderaadt */ 150ef9317a4Sespie return (vfs_export(mp, &pmp->pm_export, 1517efda1a1Sderaadt &args->export_info)); 152df930be7Sderaadt } 1537efda1a1Sderaadt if (args == NULL) 1547efda1a1Sderaadt return (0); 155df930be7Sderaadt } 15661a4b61eSjsing 157df930be7Sderaadt /* 158df930be7Sderaadt * Not an update, or updating the name: look up the name 159df930be7Sderaadt * and verify that it refers to a sensible block device. 160df930be7Sderaadt */ 1617efda1a1Sderaadt error = copyinstr(args->fspec, fspec, sizeof(fspec), NULL); 16261a4b61eSjsing if (error) 16361a4b61eSjsing goto error; 16461a4b61eSjsing 165aec3986eSjsing if (disk_map(fspec, fname, sizeof(fname), DM_OPENBLCK) == -1) 166aec3986eSjsing bcopy(fspec, fname, sizeof(fname)); 167aec3986eSjsing 168aec3986eSjsing NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fname, p); 169879b3eabSniklas if ((error = namei(ndp)) != 0) 17061a4b61eSjsing goto error; 17161a4b61eSjsing 172df930be7Sderaadt devvp = ndp->ni_vp; 173df930be7Sderaadt 174df930be7Sderaadt if (devvp->v_type != VBLK) { 17561a4b61eSjsing error = ENOTBLK; 17661a4b61eSjsing goto error_devvp; 177df930be7Sderaadt } 178df930be7Sderaadt if (major(devvp->v_rdev) >= nblkdev) { 17961a4b61eSjsing error = ENXIO; 18061a4b61eSjsing goto error_devvp; 181df930be7Sderaadt } 18261a4b61eSjsing 183df930be7Sderaadt if ((mp->mnt_flag & MNT_UPDATE) == 0) 1847efda1a1Sderaadt error = msdosfs_mountfs(devvp, mp, p, args); 185df930be7Sderaadt else { 186df930be7Sderaadt if (devvp != pmp->pm_devvp) 1875ceeea7fSkstailey error = EINVAL; /* XXX needs translation */ 188df930be7Sderaadt else 189df930be7Sderaadt vrele(devvp); 190df930be7Sderaadt } 19161a4b61eSjsing if (error) 19261a4b61eSjsing goto error_devvp; 19361a4b61eSjsing 194df930be7Sderaadt pmp = VFSTOMSDOSFS(mp); 1957efda1a1Sderaadt pmp->pm_gid = args->gid; 1967efda1a1Sderaadt pmp->pm_uid = args->uid; 1977efda1a1Sderaadt pmp->pm_mask = args->mask; 1987efda1a1Sderaadt pmp->pm_flags |= args->flags & MSDOSFSMNT_MNTOPT; 199c58a9e9cSderaadt 20016bf7bd1Sderaadt if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 20116bf7bd1Sderaadt pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 20261a4b61eSjsing else if (!(pmp->pm_flags & 2035970a935Skn (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) 204b099d67bSprovos pmp->pm_flags |= MSDOSFSMNT_LONGNAME; 20561a4b61eSjsing 206f28dec03Snatano if (pmp->pm_flags & MSDOSFSMNT_LONGNAME) 207f28dec03Snatano mp->mnt_stat.f_namemax = WIN_MAXLEN; 208f28dec03Snatano else 209f28dec03Snatano mp->mnt_stat.f_namemax = 12; 210f28dec03Snatano 211a93bb724Sjsing bzero(mp->mnt_stat.f_mntonname, MNAMELEN); 212a93bb724Sjsing strlcpy(mp->mnt_stat.f_mntonname, path, MNAMELEN); 213a93bb724Sjsing bzero(mp->mnt_stat.f_mntfromname, MNAMELEN); 214aec3986eSjsing strlcpy(mp->mnt_stat.f_mntfromname, fname, MNAMELEN); 215aec3986eSjsing bzero(mp->mnt_stat.f_mntfromspec, MNAMELEN); 216aec3986eSjsing strlcpy(mp->mnt_stat.f_mntfromspec, fspec, MNAMELEN); 2177efda1a1Sderaadt bcopy(args, &mp->mnt_stat.mount_info.msdosfs_args, sizeof(*args)); 218a93bb724Sjsing 219df930be7Sderaadt #ifdef MSDOSFS_DEBUG 22081ad5374Skrw printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, 22161a4b61eSjsing pmp, pmp->pm_inusemap); 222df930be7Sderaadt #endif 223a93bb724Sjsing 224df930be7Sderaadt return (0); 22561a4b61eSjsing 22661a4b61eSjsing error_devvp: 22761a4b61eSjsing vrele(devvp); 22861a4b61eSjsing 22961a4b61eSjsing error: 23061a4b61eSjsing return (error); 231df930be7Sderaadt } 232df930be7Sderaadt 233df930be7Sderaadt int 2347d80fe84Sjasper msdosfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, 2357d80fe84Sjasper struct msdosfs_args *argp) 236df930be7Sderaadt { 237df930be7Sderaadt struct msdosfsmount *pmp; 238df930be7Sderaadt struct buf *bp; 239df930be7Sderaadt dev_t dev = devvp->v_rdev; 240df930be7Sderaadt union bootsector *bsp; 241df930be7Sderaadt struct byte_bpb33 *b33; 242df930be7Sderaadt struct byte_bpb50 *b50; 243b099d67bSprovos struct byte_bpb710 *b710; 244df930be7Sderaadt extern struct vnode *rootvp; 24516bf7bd1Sderaadt u_int8_t SecPerClust; 246eade1deaSderaadt int ronly, error, bmapsiz; 247a64fed60Stom uint32_t fat_max_clusters; 248df930be7Sderaadt 249df930be7Sderaadt /* 250df930be7Sderaadt * Disallow multiple mounts of the same device. 251df930be7Sderaadt * Disallow mounting of a device that is currently in use 252df930be7Sderaadt * (except for root, which might share swap device for miniroot). 253df930be7Sderaadt * Flush out any old buffers remaining from a previous use. 254df930be7Sderaadt */ 255879b3eabSniklas if ((error = vfs_mountedon(devvp)) != 0) 256df930be7Sderaadt return (error); 257df930be7Sderaadt if (vcount(devvp) > 1 && devvp != rootvp) 258df930be7Sderaadt return (EBUSY); 2596e880534Svisa vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 260a8d7c3beScheloha error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, INFSLP); 26136bb23f1Svisa VOP_UNLOCK(devvp); 262975d7019Smillert if (error) 263df930be7Sderaadt return (error); 264df930be7Sderaadt 265df930be7Sderaadt ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 266879b3eabSniklas error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p); 267879b3eabSniklas if (error) 268df930be7Sderaadt return (error); 269c58a9e9cSderaadt 270df930be7Sderaadt bp = NULL; /* both used in error_exit */ 271df930be7Sderaadt pmp = NULL; 272c58a9e9cSderaadt 273df930be7Sderaadt /* 274c58a9e9cSderaadt * Read the boot sector of the filesystem, and then check the 275c58a9e9cSderaadt * boot signature. If not a dos boot sector then error out. 276df930be7Sderaadt */ 27793f62a9eStedu if ((error = bread(devvp, 0, 4096, &bp)) != 0) 278df930be7Sderaadt goto error_exit; 279df930be7Sderaadt bsp = (union bootsector *)bp->b_data; 280df930be7Sderaadt b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB; 281df930be7Sderaadt b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB; 282ba4520ccSbluhm b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB; 283df930be7Sderaadt 284bc9397c2Skrw pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK | M_ZERO); 285df930be7Sderaadt pmp->pm_mountp = mp; 286df930be7Sderaadt 287df930be7Sderaadt /* 288df930be7Sderaadt * Compute several useful quantities from the bpb in the 289df930be7Sderaadt * bootsector. Copy in the dos 5 variant of the bpb then fix up 290df930be7Sderaadt * the fields that are different between dos 5 and dos 3.3. 291df930be7Sderaadt */ 29216bf7bd1Sderaadt SecPerClust = b50->bpbSecPerClust; 293df930be7Sderaadt pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 294df930be7Sderaadt pmp->pm_ResSectors = getushort(b50->bpbResSectors); 295df930be7Sderaadt pmp->pm_FATs = b50->bpbFATs; 296df930be7Sderaadt pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 297df930be7Sderaadt pmp->pm_Sectors = getushort(b50->bpbSectors); 298df930be7Sderaadt pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 299df930be7Sderaadt pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 300df930be7Sderaadt pmp->pm_Heads = getushort(b50->bpbHeads); 301df930be7Sderaadt pmp->pm_Media = b50->bpbMedia; 302df930be7Sderaadt 303402c79f7Skrw /* Determine the number of DEV_BSIZE blocks in a MSDOSFS sector */ 304402c79f7Skrw pmp->pm_BlkPerSec = pmp->pm_BytesPerSec / DEV_BSIZE; 305402c79f7Skrw 3060aa71678Sbluhm if (!pmp->pm_BytesPerSec || !SecPerClust) { 307c34741d6Sjsg error = EINVAL; 308df930be7Sderaadt goto error_exit; 309df930be7Sderaadt } 310df930be7Sderaadt 311df930be7Sderaadt if (pmp->pm_Sectors == 0) { 312df930be7Sderaadt pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 313df930be7Sderaadt pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 314df930be7Sderaadt } else { 315df930be7Sderaadt pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 316df930be7Sderaadt pmp->pm_HugeSectors = pmp->pm_Sectors; 317df930be7Sderaadt } 318bfd75fc5Saaron 319b099d67bSprovos if (pmp->pm_RootDirEnts == 0) { 32095f427a9Sderaadt if (pmp->pm_Sectors || pmp->pm_FATsecs || 32195f427a9Sderaadt getushort(b710->bpbFSVers)) { 322b099d67bSprovos error = EINVAL; 323b099d67bSprovos goto error_exit; 324b099d67bSprovos } 325b099d67bSprovos pmp->pm_fatmask = FAT32_MASK; 326b099d67bSprovos pmp->pm_fatmult = 4; 327b099d67bSprovos pmp->pm_fatdiv = 1; 328b099d67bSprovos pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs); 329b099d67bSprovos if (getushort(b710->bpbExtFlags) & FATMIRROR) 330b099d67bSprovos pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM; 331b099d67bSprovos else 332b099d67bSprovos pmp->pm_flags |= MSDOSFS_FATMIRROR; 333b099d67bSprovos } else 334b099d67bSprovos pmp->pm_flags |= MSDOSFS_FATMIRROR; 335c58a9e9cSderaadt 336402c79f7Skrw /* 337402c79f7Skrw * More sanity checks: 338402c79f7Skrw * MSDOSFS sectors per cluster: >0 && power of 2 339402c79f7Skrw * MSDOSFS sector size: >= DEV_BSIZE && power of 2 340402c79f7Skrw * HUGE sector count: >0 341402c79f7Skrw * FAT sectors: >0 342402c79f7Skrw */ 343402c79f7Skrw if ((SecPerClust == 0) || (SecPerClust & (SecPerClust - 1)) || 344402c79f7Skrw (pmp->pm_BytesPerSec < DEV_BSIZE) || 345402c79f7Skrw (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) || 346701ac683Stobias (pmp->pm_HugeSectors == 0) || (pmp->pm_FATsecs == 0) || 347701ac683Stobias (SecPerClust * pmp->pm_BlkPerSec > MAXBSIZE / DEV_BSIZE)) { 348402c79f7Skrw error = EINVAL; 349402c79f7Skrw goto error_exit; 350402c79f7Skrw } 351402c79f7Skrw 352402c79f7Skrw pmp->pm_HugeSectors *= pmp->pm_BlkPerSec; 353402c79f7Skrw pmp->pm_HiddenSects *= pmp->pm_BlkPerSec; 354402c79f7Skrw pmp->pm_FATsecs *= pmp->pm_BlkPerSec; 355402c79f7Skrw pmp->pm_fatblk = pmp->pm_ResSectors * pmp->pm_BlkPerSec; 356402c79f7Skrw SecPerClust *= pmp->pm_BlkPerSec; 357402c79f7Skrw 358b099d67bSprovos if (FAT32(pmp)) { 359b099d67bSprovos pmp->pm_rootdirblk = getulong(b710->bpbRootClust); 360b099d67bSprovos pmp->pm_firstcluster = pmp->pm_fatblk 361b099d67bSprovos + (pmp->pm_FATs * pmp->pm_FATsecs); 362402c79f7Skrw pmp->pm_fsinfo = getushort(b710->bpbFSInfo) * pmp->pm_BlkPerSec; 363b099d67bSprovos } else { 364df930be7Sderaadt pmp->pm_rootdirblk = pmp->pm_fatblk + 365df930be7Sderaadt (pmp->pm_FATs * pmp->pm_FATsecs); 36616bf7bd1Sderaadt pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry) 367402c79f7Skrw + DEV_BSIZE - 1) / DEV_BSIZE; 368df930be7Sderaadt pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 369b099d67bSprovos } 370b099d67bSprovos 371df930be7Sderaadt pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 37216bf7bd1Sderaadt SecPerClust; 373df930be7Sderaadt pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1; 374402c79f7Skrw pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE; 375c58a9e9cSderaadt 3764f86468aSkrw if (pmp->pm_fatmask == 0) { 377879b3eabSniklas if (pmp->pm_maxcluster 378b099d67bSprovos <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) { 379c58a9e9cSderaadt /* 380c58a9e9cSderaadt * This will usually be a floppy disk. This size makes 381c58a9e9cSderaadt * sure that one fat entry will not be split across 382c58a9e9cSderaadt * multiple blocks. 383c58a9e9cSderaadt */ 384b099d67bSprovos pmp->pm_fatmask = FAT12_MASK; 385b099d67bSprovos pmp->pm_fatmult = 3; 386b099d67bSprovos pmp->pm_fatdiv = 2; 387b099d67bSprovos } else { 388b099d67bSprovos pmp->pm_fatmask = FAT16_MASK; 389b099d67bSprovos pmp->pm_fatmult = 2; 390b099d67bSprovos pmp->pm_fatdiv = 1; 391b099d67bSprovos } 392c58a9e9cSderaadt } 393df930be7Sderaadt if (FAT12(pmp)) 394df930be7Sderaadt pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; 395879b3eabSniklas else 396879b3eabSniklas pmp->pm_fatblocksize = MAXBSIZE; 397c58a9e9cSderaadt 398a64fed60Stom /* 399a64fed60Stom * We now have the number of sectors in each FAT, so can work 400a64fed60Stom * out how many clusters can be represented in a FAT. Let's 401a64fed60Stom * make sure the file system doesn't claim to have more clusters 402a64fed60Stom * than this. 403a64fed60Stom * 404a64fed60Stom * We perform the calculation like we do to avoid integer overflow. 405a64fed60Stom * 406a64fed60Stom * This will give us a count of clusters. They are numbered 407a64fed60Stom * from 0, so the max cluster value is one less than the value 408a64fed60Stom * we end up with. 409a64fed60Stom */ 410a64fed60Stom fat_max_clusters = pmp->pm_fatsize / pmp->pm_fatmult; 411a64fed60Stom fat_max_clusters *= pmp->pm_fatdiv; 412a64fed60Stom if (pmp->pm_maxcluster >= fat_max_clusters) { 413a64fed60Stom #ifndef SMALL_KERNEL 414a64fed60Stom printf("msdosfs: reducing max cluster to %d from %d " 415a64fed60Stom "due to FAT size\n", fat_max_clusters - 1, 416a64fed60Stom pmp->pm_maxcluster); 417a64fed60Stom #endif 418a64fed60Stom pmp->pm_maxcluster = fat_max_clusters - 1; 419a64fed60Stom } 420a64fed60Stom 421402c79f7Skrw pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE; 422402c79f7Skrw pmp->pm_bnshift = ffs(DEV_BSIZE) - 1; 423df930be7Sderaadt 424df930be7Sderaadt /* 425df930be7Sderaadt * Compute mask and shift value for isolating cluster relative byte 426df930be7Sderaadt * offsets and cluster numbers from a file offset. 427df930be7Sderaadt */ 428402c79f7Skrw pmp->pm_bpcluster = SecPerClust * DEV_BSIZE; 429df930be7Sderaadt pmp->pm_crbomask = pmp->pm_bpcluster - 1; 430df930be7Sderaadt pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1; 43116bf7bd1Sderaadt 43216bf7bd1Sderaadt /* 43316bf7bd1Sderaadt * Check for valid cluster size 43416bf7bd1Sderaadt * must be a power of 2 43516bf7bd1Sderaadt */ 43616bf7bd1Sderaadt if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) { 437c34741d6Sjsg error = EINVAL; 438df930be7Sderaadt goto error_exit; 439df930be7Sderaadt } 440df930be7Sderaadt 441df930be7Sderaadt /* 442df930be7Sderaadt * Release the bootsector buffer. 443df930be7Sderaadt */ 444df930be7Sderaadt brelse(bp); 445df930be7Sderaadt bp = NULL; 446df930be7Sderaadt 447df930be7Sderaadt /* 448b099d67bSprovos * Check FSInfo 449b099d67bSprovos */ 450b099d67bSprovos if (pmp->pm_fsinfo) { 451b099d67bSprovos struct fsinfo *fp; 452b099d67bSprovos 453402c79f7Skrw if ((error = bread(devvp, pmp->pm_fsinfo, fsi_size(pmp), 45493f62a9eStedu &bp)) != 0) 455b099d67bSprovos goto error_exit; 456b099d67bSprovos fp = (struct fsinfo *)bp->b_data; 457b099d67bSprovos if (!bcmp(fp->fsisig1, "RRaA", 4) 458b099d67bSprovos && !bcmp(fp->fsisig2, "rrAa", 4) 459b099d67bSprovos && !bcmp(fp->fsisig3, "\0\0\125\252", 4) 460b099d67bSprovos && !bcmp(fp->fsisig4, "\0\0\125\252", 4)) 4618bc3fffeSkrw /* Valid FSInfo. */ 4628bc3fffeSkrw ; 463b099d67bSprovos else 464b099d67bSprovos pmp->pm_fsinfo = 0; 46591b81d9eSkrw /* XXX make sure this tiny buf doesn't come back in fillinusemap! */ 46691b81d9eSkrw SET(bp->b_flags, B_INVAL); 467b099d67bSprovos brelse(bp); 468b099d67bSprovos bp = NULL; 469b099d67bSprovos } 470b099d67bSprovos 471b099d67bSprovos /* 472b099d67bSprovos * Check and validate (or perhaps invalidate?) the fsinfo structure? XXX 473b099d67bSprovos */ 474b099d67bSprovos 475b099d67bSprovos /* 476df930be7Sderaadt * Allocate memory for the bitmap of allocated clusters, and then 477df930be7Sderaadt * fill it in. 478df930be7Sderaadt */ 4792a90c622Stobias bmapsiz = howmany(pmp->pm_maxcluster + 1, N_INUSEBITS); 480eade1deaSderaadt if (bmapsiz == 0 || SIZE_MAX / bmapsiz < sizeof(*pmp->pm_inusemap)) { 481eade1deaSderaadt /* detect multiplicative integer overflow */ 482eade1deaSderaadt error = EINVAL; 483eade1deaSderaadt goto error_exit; 484eade1deaSderaadt } 4850f0d0f95Sdoug pmp->pm_inusemap = mallocarray(bmapsiz, sizeof(*pmp->pm_inusemap), 4862ba0f8d8Spedro M_MSDOSFSFAT, M_WAITOK | M_CANFAIL); 4872ba0f8d8Spedro if (pmp->pm_inusemap == NULL) { 4882ba0f8d8Spedro error = EINVAL; 4892ba0f8d8Spedro goto error_exit; 4902ba0f8d8Spedro } 491df930be7Sderaadt 492df930be7Sderaadt /* 493df930be7Sderaadt * fillinusemap() needs pm_devvp. 494df930be7Sderaadt */ 495df930be7Sderaadt pmp->pm_dev = dev; 496df930be7Sderaadt pmp->pm_devvp = devvp; 497df930be7Sderaadt 498df930be7Sderaadt /* 499df930be7Sderaadt * Have the inuse map filled in. 500df930be7Sderaadt */ 501879b3eabSniklas if ((error = fillinusemap(pmp)) != 0) 502df930be7Sderaadt goto error_exit; 503df930be7Sderaadt 504df930be7Sderaadt /* 505df930be7Sderaadt * If they want fat updates to be synchronous then let them suffer 506df930be7Sderaadt * the performance degradation in exchange for the on disk copy of 507df930be7Sderaadt * the fat being correct just about all the time. I suppose this 508df930be7Sderaadt * would be a good thing to turn on if the kernel is still flakey. 509df930be7Sderaadt */ 51016bf7bd1Sderaadt if (mp->mnt_flag & MNT_SYNCHRONOUS) 51116bf7bd1Sderaadt pmp->pm_flags |= MSDOSFSMNT_WAITONFAT; 512df930be7Sderaadt 513df930be7Sderaadt /* 514df930be7Sderaadt * Finish up. 515df930be7Sderaadt */ 51616bf7bd1Sderaadt if (ronly) 51716bf7bd1Sderaadt pmp->pm_flags |= MSDOSFSMNT_RONLY; 51816bf7bd1Sderaadt else 519df930be7Sderaadt pmp->pm_fmod = 1; 52041e0c475Sguenther mp->mnt_data = pmp; 521df930be7Sderaadt mp->mnt_stat.f_fsid.val[0] = (long)dev; 522fe680c2eSprovos mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 5231414b0faSart #ifdef QUOTA 5241414b0faSart /* 5251414b0faSart * If we ever do quotas for DOS filesystems this would be a place 5261414b0faSart * to fill in the info in the msdosfsmount structure. You dolt, 5271414b0faSart * quotas on dos filesystems make no sense because files have no 5281414b0faSart * owners on dos filesystems. of course there is some empty space 5291414b0faSart * in the directory entry where we could put uid's and gid's. 5301414b0faSart */ 5311414b0faSart #endif 53207feb63cScsapuntz devvp->v_specmountpoint = mp; 533df930be7Sderaadt 534df930be7Sderaadt return (0); 535df930be7Sderaadt 536fe680c2eSprovos error_exit: 5379ee302b8Sbluhm if (devvp->v_specinfo) 538fe680c2eSprovos devvp->v_specmountpoint = NULL; 539df930be7Sderaadt if (bp) 540df930be7Sderaadt brelse(bp); 54124f9a445Skrw 5426e880534Svisa vn_lock(devvp, LK_EXCLUSIVE|LK_RETRY); 543df930be7Sderaadt (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p); 54436bb23f1Svisa VOP_UNLOCK(devvp); 54524f9a445Skrw 546df930be7Sderaadt if (pmp) { 547df930be7Sderaadt if (pmp->pm_inusemap) 5486c33c037Stedu free(pmp->pm_inusemap, M_MSDOSFSFAT, 0); 5496c33c037Stedu free(pmp, M_MSDOSFSMNT, 0); 550200e77f4Sbluhm mp->mnt_data = NULL; 551df930be7Sderaadt } 552df930be7Sderaadt return (error); 553df930be7Sderaadt } 554df930be7Sderaadt 555df930be7Sderaadt int 5567d80fe84Sjasper msdosfs_start(struct mount *mp, int flags, struct proc *p) 557df930be7Sderaadt { 558df930be7Sderaadt 559df930be7Sderaadt return (0); 560df930be7Sderaadt } 561df930be7Sderaadt 562df930be7Sderaadt /* 563df930be7Sderaadt * Unmount the filesystem described by mp. 564df930be7Sderaadt */ 565df930be7Sderaadt int 5667d80fe84Sjasper msdosfs_unmount(struct mount *mp, int mntflags,struct proc *p) 567df930be7Sderaadt { 568df930be7Sderaadt struct msdosfsmount *pmp; 569df930be7Sderaadt int error, flags; 5709f051f0fSart struct vnode *vp; 571df930be7Sderaadt 572df930be7Sderaadt flags = 0; 573df930be7Sderaadt if (mntflags & MNT_FORCE) 574df930be7Sderaadt flags |= FORCECLOSE; 575879b3eabSniklas if ((error = vflush(mp, NULLVP, flags)) != 0) 576df930be7Sderaadt return (error); 577df930be7Sderaadt pmp = VFSTOMSDOSFS(mp); 57807feb63cScsapuntz pmp->pm_devvp->v_specmountpoint = NULL; 5799f051f0fSart vp = pmp->pm_devvp; 580*5a0ec814Smiod #if defined(MSDOSFS_DEBUG) && (defined(DEBUG) || defined(DIAGNOSTIC)) 5819f051f0fSart vprint("msdosfs_umount(): just before calling VOP_CLOSE()\n", vp); 582df930be7Sderaadt #endif 5836e880534Svisa vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 5844b1ae25eSbluhm (void)VOP_CLOSE(vp, 58516bf7bd1Sderaadt pmp->pm_flags & MSDOSFSMNT_RONLY ? FREAD : FREAD|FWRITE, NOCRED, p); 586da391b1aSthib vput(vp); 5876c33c037Stedu free(pmp->pm_inusemap, M_MSDOSFSFAT, 0); 5886c33c037Stedu free(pmp, M_MSDOSFSMNT, 0); 589200e77f4Sbluhm mp->mnt_data = NULL; 590df930be7Sderaadt mp->mnt_flag &= ~MNT_LOCAL; 5914b1ae25eSbluhm return (0); 592df930be7Sderaadt } 593df930be7Sderaadt 594df930be7Sderaadt int 5957d80fe84Sjasper msdosfs_root(struct mount *mp, struct vnode **vpp) 596df930be7Sderaadt { 597df930be7Sderaadt struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 598df930be7Sderaadt struct denode *ndep; 599df930be7Sderaadt int error; 600df930be7Sderaadt 6014fcb5d54Smickey if ((error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep)) != 0) 6024fcb5d54Smickey return (error); 6034fcb5d54Smickey 604df930be7Sderaadt #ifdef MSDOSFS_DEBUG 60581ad5374Skrw printf("msdosfs_root(); mp %p, pmp %p, ndep %p, vp %p\n", 606df930be7Sderaadt mp, pmp, ndep, DETOV(ndep)); 607df930be7Sderaadt #endif 6084fcb5d54Smickey 609df930be7Sderaadt *vpp = DETOV(ndep); 610df930be7Sderaadt return (0); 611df930be7Sderaadt } 612df930be7Sderaadt 613df930be7Sderaadt int 6147d80fe84Sjasper msdosfs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p) 615df930be7Sderaadt { 616df930be7Sderaadt struct msdosfsmount *pmp; 617df930be7Sderaadt 618df930be7Sderaadt pmp = VFSTOMSDOSFS(mp); 619df930be7Sderaadt sbp->f_bsize = pmp->pm_bpcluster; 620df930be7Sderaadt sbp->f_iosize = pmp->pm_bpcluster; 621df930be7Sderaadt sbp->f_blocks = pmp->pm_nmbrofclusters; 622df930be7Sderaadt sbp->f_bfree = pmp->pm_freeclustercount; 623df930be7Sderaadt sbp->f_bavail = pmp->pm_freeclustercount; 624df930be7Sderaadt sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ 625f28dec03Snatano sbp->f_ffree = sbp->f_favail = 0; /* what to put in here? */ 626f28dec03Snatano copy_statfs_info(sbp, mp); 627f28dec03Snatano 628df930be7Sderaadt return (0); 629df930be7Sderaadt } 630df930be7Sderaadt 6311881de8bScsapuntz 6321881de8bScsapuntz struct msdosfs_sync_arg { 6331881de8bScsapuntz struct proc *p; 6341881de8bScsapuntz struct ucred *cred; 6351881de8bScsapuntz int allerror; 6361881de8bScsapuntz int waitfor; 6371881de8bScsapuntz }; 6381881de8bScsapuntz 6391881de8bScsapuntz int 6401881de8bScsapuntz msdosfs_sync_vnode(struct vnode *vp, void *arg) 6411881de8bScsapuntz { 6421881de8bScsapuntz struct msdosfs_sync_arg *msa = arg; 6431881de8bScsapuntz struct denode *dep; 6444b515238Svisa int error; 6454b515238Svisa int s, skip = 0; 6461881de8bScsapuntz 6471881de8bScsapuntz dep = VTODE(vp); 6484b515238Svisa s = splbio(); 6491414b0faSart if (vp->v_type == VNON || 6501414b0faSart ((dep->de_flag & (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0 6519d08f8e5Smiod && LIST_EMPTY(&vp->v_dirtyblkhd)) || 6521414b0faSart msa->waitfor == MNT_LAZY) { 6534b515238Svisa skip = 1; 6541881de8bScsapuntz } 6554b515238Svisa splx(s); 6564b515238Svisa 6574b515238Svisa if (skip) 6584b515238Svisa return (0); 6591881de8bScsapuntz 66008107a0bSvisa if (vget(vp, LK_EXCLUSIVE | LK_NOWAIT)) 6611881de8bScsapuntz return (0); 6621881de8bScsapuntz 6631881de8bScsapuntz if ((error = VOP_FSYNC(vp, msa->cred, msa->waitfor, msa->p)) != 0) 6641881de8bScsapuntz msa->allerror = error; 66536bb23f1Svisa VOP_UNLOCK(vp); 6666b1440e2Scsapuntz vrele(vp); 6671881de8bScsapuntz 6681881de8bScsapuntz return (0); 6691881de8bScsapuntz } 6701881de8bScsapuntz 6711881de8bScsapuntz 672df930be7Sderaadt int 673976e9839Sderaadt msdosfs_sync(struct mount *mp, int waitfor, int stall, struct ucred *cred, 674976e9839Sderaadt struct proc *p) 675df930be7Sderaadt { 676df930be7Sderaadt struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 6771881de8bScsapuntz struct msdosfs_sync_arg msa; 6781881de8bScsapuntz int error; 6791881de8bScsapuntz 6801881de8bScsapuntz msa.allerror = 0; 6811881de8bScsapuntz msa.p = p; 6821881de8bScsapuntz msa.cred = cred; 6831881de8bScsapuntz msa.waitfor = waitfor; 684df930be7Sderaadt 685df930be7Sderaadt /* 686df930be7Sderaadt * If we ever switch to not updating all of the fats all the time, 687df930be7Sderaadt * this would be the place to update them from the first one. 688df930be7Sderaadt */ 68976d2c29eSniklas if (pmp->pm_fmod != 0) { 69016bf7bd1Sderaadt if (pmp->pm_flags & MSDOSFSMNT_RONLY) 691df930be7Sderaadt panic("msdosfs_sync: rofs mod"); 692df930be7Sderaadt else { 693df930be7Sderaadt /* update fats here */ 694df930be7Sderaadt } 69576d2c29eSniklas } 696df930be7Sderaadt /* 697df930be7Sderaadt * Write back each (modified) denode. 698df930be7Sderaadt */ 6991881de8bScsapuntz vfs_mount_foreach_vnode(mp, msdosfs_sync_vnode, &msa); 700975d7019Smillert 701df930be7Sderaadt /* 702df930be7Sderaadt * Force stale file system control information to be flushed. 703df930be7Sderaadt */ 704975d7019Smillert if (waitfor != MNT_LAZY) { 7056e880534Svisa vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY); 706879b3eabSniklas if ((error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p)) != 0) 7071881de8bScsapuntz msa.allerror = error; 70836bb23f1Svisa VOP_UNLOCK(pmp->pm_devvp); 709975d7019Smillert } 7101881de8bScsapuntz 7111881de8bScsapuntz return (msa.allerror); 712df930be7Sderaadt } 713df930be7Sderaadt 714df930be7Sderaadt int 7157d80fe84Sjasper msdosfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) 716df930be7Sderaadt { 717df930be7Sderaadt struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 718df930be7Sderaadt struct defid *defhp = (struct defid *) fhp; 719df930be7Sderaadt struct denode *dep; 720df930be7Sderaadt int error; 721df930be7Sderaadt 72216bf7bd1Sderaadt error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep); 723df930be7Sderaadt if (error) { 724df930be7Sderaadt *vpp = NULLVP; 725df930be7Sderaadt return (error); 726df930be7Sderaadt } 727df930be7Sderaadt *vpp = DETOV(dep); 728df930be7Sderaadt return (0); 729df930be7Sderaadt } 730df930be7Sderaadt 731df930be7Sderaadt int 7327d80fe84Sjasper msdosfs_vptofh(struct vnode *vp, struct fid *fhp) 733df930be7Sderaadt { 734df930be7Sderaadt struct denode *dep; 735df930be7Sderaadt struct defid *defhp; 736df930be7Sderaadt 737df930be7Sderaadt dep = VTODE(vp); 738df930be7Sderaadt defhp = (struct defid *)fhp; 739df930be7Sderaadt defhp->defid_len = sizeof(struct defid); 740df930be7Sderaadt defhp->defid_dirclust = dep->de_dirclust; 741df930be7Sderaadt defhp->defid_dirofs = dep->de_diroffset; 742df930be7Sderaadt /* defhp->defid_gen = dep->de_gen; */ 743df930be7Sderaadt return (0); 744df930be7Sderaadt } 745df930be7Sderaadt 746b99d154aSassar int 7477d80fe84Sjasper msdosfs_check_export(struct mount *mp, struct mbuf *nam, int *exflagsp, 7487d80fe84Sjasper struct ucred **credanonp) 749b99d154aSassar { 750cc2a7e83Sjasper struct netcred *np; 751cc2a7e83Sjasper struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 752b99d154aSassar 753b99d154aSassar /* 754b99d154aSassar * Get the export permission structure for this <mp, client> tuple. 755b99d154aSassar */ 756b99d154aSassar np = vfs_export_lookup(mp, &pmp->pm_export, nam); 757b99d154aSassar if (np == NULL) 758b99d154aSassar return (EACCES); 759b99d154aSassar 760b99d154aSassar *exflagsp = np->netc_exflags; 761b99d154aSassar *credanonp = &np->netc_anon; 762b99d154aSassar return (0); 763b99d154aSassar } 764b99d154aSassar 765e4b1e213Smickey const struct vfsops msdosfs_vfsops = { 76641f642fcSbluhm .vfs_mount = msdosfs_mount, 76741f642fcSbluhm .vfs_start = msdosfs_start, 76841f642fcSbluhm .vfs_unmount = msdosfs_unmount, 76941f642fcSbluhm .vfs_root = msdosfs_root, 7707196c146Ssemarie .vfs_quotactl = (void *)eopnotsupp, 77141f642fcSbluhm .vfs_statfs = msdosfs_statfs, 77241f642fcSbluhm .vfs_sync = msdosfs_sync, 7737196c146Ssemarie .vfs_vget = (void *)eopnotsupp, 77441f642fcSbluhm .vfs_fhtovp = msdosfs_fhtovp, 77541f642fcSbluhm .vfs_vptofh = msdosfs_vptofh, 77641f642fcSbluhm .vfs_init = msdosfs_init, 7777196c146Ssemarie .vfs_sysctl = (void *)eopnotsupp, 77841f642fcSbluhm .vfs_checkexp = msdosfs_check_export, 779df930be7Sderaadt }; 780