Annotation of sys/msdosfs/msdosfs_vfsops.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: msdosfs_vfsops.c,v 1.47 2007/03/21 17:29:32 thib Exp $ */
! 2: /* $NetBSD: msdosfs_vfsops.c,v 1.48 1997/10/18 02:54:57 briggs Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
! 6: * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
! 7: * All rights reserved.
! 8: * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
! 9: *
! 10: * Redistribution and use in source and binary forms, with or without
! 11: * modification, are permitted provided that the following conditions
! 12: * are met:
! 13: * 1. Redistributions of source code must retain the above copyright
! 14: * notice, this list of conditions and the following disclaimer.
! 15: * 2. Redistributions in binary form must reproduce the above copyright
! 16: * notice, this list of conditions and the following disclaimer in the
! 17: * documentation and/or other materials provided with the distribution.
! 18: * 3. All advertising materials mentioning features or use of this software
! 19: * must display the following acknowledgement:
! 20: * This product includes software developed by TooLs GmbH.
! 21: * 4. The name of TooLs GmbH may not be used to endorse or promote products
! 22: * derived from this software without specific prior written permission.
! 23: *
! 24: * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
! 25: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 26: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 27: * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
! 28: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
! 29: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
! 30: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
! 31: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
! 32: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
! 33: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 34: */
! 35: /*
! 36: * Written by Paul Popelka (paulp@uts.amdahl.com)
! 37: *
! 38: * You can do anything you want with this software, just don't say you wrote
! 39: * it, and don't remove this notice.
! 40: *
! 41: * This software is provided "as is".
! 42: *
! 43: * The author supplies this software to be publicly redistributed on the
! 44: * understanding that the author is not responsible for the correct
! 45: * functioning of this software in any circumstances and is not liable for
! 46: * any damages caused by this software.
! 47: *
! 48: * October 1992
! 49: */
! 50:
! 51: #include <sys/param.h>
! 52: #include <sys/systm.h>
! 53: #include <sys/namei.h>
! 54: #include <sys/proc.h>
! 55: #include <sys/kernel.h>
! 56: #include <sys/vnode.h>
! 57: #include <miscfs/specfs/specdev.h> /* XXX */ /* defines v_rdev */
! 58: #include <sys/mount.h>
! 59: #include <sys/buf.h>
! 60: #include <sys/file.h>
! 61: #include <sys/disklabel.h>
! 62: #include <sys/ioctl.h>
! 63: #include <sys/malloc.h>
! 64: #include <sys/dirent.h>
! 65:
! 66: #include <msdosfs/bpb.h>
! 67: #include <msdosfs/bootsect.h>
! 68: #include <msdosfs/direntry.h>
! 69: #include <msdosfs/denode.h>
! 70: #include <msdosfs/msdosfsmount.h>
! 71: #include <msdosfs/fat.h>
! 72:
! 73: int msdosfs_mount(struct mount *, const char *, void *, struct nameidata *,
! 74: struct proc *);
! 75: int msdosfs_start(struct mount *, int, struct proc *);
! 76: int msdosfs_unmount(struct mount *, int, struct proc *);
! 77: int msdosfs_root(struct mount *, struct vnode **);
! 78: int msdosfs_statfs(struct mount *, struct statfs *, struct proc *);
! 79: int msdosfs_sync(struct mount *, int, struct ucred *, struct proc *);
! 80: int msdosfs_fhtovp(struct mount *, struct fid *, struct vnode **);
! 81: int msdosfs_vptofh(struct vnode *, struct fid *);
! 82: int msdosfs_check_export(struct mount *mp, struct mbuf *nam,
! 83: int *extflagsp, struct ucred **credanonp);
! 84:
! 85: int msdosfs_mountfs(struct vnode *, struct mount *, struct proc *,
! 86: struct msdosfs_args *);
! 87:
! 88: int msdosfs_sync_vnode(struct vnode *, void *);
! 89:
! 90: /*
! 91: * mp - path - addr in user space of mount point (ie /usr or whatever)
! 92: * data - addr in user space of mount params including the name of the block
! 93: * special file to treat as a filesystem.
! 94: */
! 95: int
! 96: msdosfs_mount(mp, path, data, ndp, p)
! 97: struct mount *mp;
! 98: const char *path;
! 99: void *data;
! 100: struct nameidata *ndp;
! 101: struct proc *p;
! 102: {
! 103: struct vnode *devvp; /* vnode for blk device to mount */
! 104: struct msdosfs_args args; /* will hold data from mount request */
! 105: /* msdosfs specific mount control block */
! 106: struct msdosfsmount *pmp = NULL;
! 107: size_t size;
! 108: int error, flags;
! 109: mode_t accessmode;
! 110:
! 111: error = copyin(data, &args, sizeof(struct msdosfs_args));
! 112: if (error)
! 113: return (error);
! 114: /*
! 115: * If updating, check whether changing from read-only to
! 116: * read/write; if there is no device name, that's all we do.
! 117: */
! 118: if (mp->mnt_flag & MNT_UPDATE) {
! 119: pmp = VFSTOMSDOSFS(mp);
! 120: error = 0;
! 121: if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_flag & MNT_RDONLY)) {
! 122: flags = WRITECLOSE;
! 123: if (mp->mnt_flag & MNT_FORCE)
! 124: flags |= FORCECLOSE;
! 125: error = vflush(mp, NULLVP, flags);
! 126: }
! 127: if (!error && (mp->mnt_flag & MNT_RELOAD))
! 128: /* not yet implemented */
! 129: error = EOPNOTSUPP;
! 130: if (error)
! 131: return (error);
! 132: if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_flag & MNT_WANTRDWR)) {
! 133: /*
! 134: * If upgrade to read-write by non-root, then verify
! 135: * that user has necessary permissions on the device.
! 136: */
! 137: if (p->p_ucred->cr_uid != 0) {
! 138: devvp = pmp->pm_devvp;
! 139: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
! 140: error = VOP_ACCESS(devvp, VREAD | VWRITE,
! 141: p->p_ucred, p);
! 142: if (error) {
! 143: VOP_UNLOCK(devvp, 0, p);
! 144: return (error);
! 145: }
! 146: VOP_UNLOCK(devvp, 0, p);
! 147: }
! 148: pmp->pm_flags &= ~MSDOSFSMNT_RONLY;
! 149: }
! 150: if (args.fspec == 0) {
! 151: #ifdef __notyet__ /* doesn't work correctly with current mountd XXX */
! 152: if (args.flags & MSDOSFSMNT_MNTOPT) {
! 153: pmp->pm_flags &= ~MSDOSFSMNT_MNTOPT;
! 154: pmp->pm_flags |= args.flags & MSDOSFSMNT_MNTOPT;
! 155: if (pmp->pm_flags & MSDOSFSMNT_NOWIN95)
! 156: pmp->pm_flags |= MSDOSFSMNT_SHORTNAME;
! 157: }
! 158: #endif
! 159: /*
! 160: * Process export requests.
! 161: */
! 162: return (vfs_export(mp, &pmp->pm_export,
! 163: &args.export_info));
! 164: }
! 165: }
! 166: /*
! 167: * Not an update, or updating the name: look up the name
! 168: * and verify that it refers to a sensible block device.
! 169: */
! 170: NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
! 171: if ((error = namei(ndp)) != 0)
! 172: return (error);
! 173: devvp = ndp->ni_vp;
! 174:
! 175: if (devvp->v_type != VBLK) {
! 176: vrele(devvp);
! 177: return (ENOTBLK);
! 178: }
! 179: if (major(devvp->v_rdev) >= nblkdev) {
! 180: vrele(devvp);
! 181: return (ENXIO);
! 182: }
! 183: /*
! 184: * If mount by non-root, then verify that user has necessary
! 185: * permissions on the device.
! 186: */
! 187: if (p->p_ucred->cr_uid != 0) {
! 188: accessmode = VREAD;
! 189: if ((mp->mnt_flag & MNT_RDONLY) == 0)
! 190: accessmode |= VWRITE;
! 191: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
! 192: error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p);
! 193: if (error) {
! 194: vput(devvp);
! 195: return (error);
! 196: }
! 197: VOP_UNLOCK(devvp, 0, p);
! 198: }
! 199: if ((mp->mnt_flag & MNT_UPDATE) == 0)
! 200: error = msdosfs_mountfs(devvp, mp, p, &args);
! 201: else {
! 202: if (devvp != pmp->pm_devvp)
! 203: error = EINVAL; /* XXX needs translation */
! 204: else
! 205: vrele(devvp);
! 206: }
! 207: if (error) {
! 208: vrele(devvp);
! 209: return (error);
! 210: }
! 211: pmp = VFSTOMSDOSFS(mp);
! 212: pmp->pm_gid = args.gid;
! 213: pmp->pm_uid = args.uid;
! 214: pmp->pm_mask = args.mask;
! 215: pmp->pm_flags |= args.flags & MSDOSFSMNT_MNTOPT;
! 216:
! 217: if (pmp->pm_flags & MSDOSFSMNT_NOWIN95)
! 218: pmp->pm_flags |= MSDOSFSMNT_SHORTNAME;
! 219: else if (!(pmp->pm_flags & (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) {
! 220: struct vnode *rvp;
! 221:
! 222: /*
! 223: * Try to divine whether to support Win'95 long filenames
! 224: */
! 225: if (FAT32(pmp))
! 226: pmp->pm_flags |= MSDOSFSMNT_LONGNAME;
! 227: else {
! 228: if ((error = msdosfs_root(mp, &rvp)) != 0) {
! 229: msdosfs_unmount(mp, MNT_FORCE, p);
! 230: return (error);
! 231: }
! 232: pmp->pm_flags |= findwin95(VTODE(rvp))
! 233: ? MSDOSFSMNT_LONGNAME
! 234: : MSDOSFSMNT_SHORTNAME;
! 235: vput(rvp);
! 236: }
! 237: }
! 238: (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
! 239: bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
! 240: (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
! 241: &size);
! 242: bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
! 243: bcopy(&args, &mp->mnt_stat.mount_info.msdosfs_args, sizeof(args));
! 244: #ifdef MSDOSFS_DEBUG
! 245: printf("msdosfs_mount(): mp %x, pmp %x, inusemap %x\n", mp, pmp, pmp->pm_inusemap);
! 246: #endif
! 247: return (0);
! 248: }
! 249:
! 250: int
! 251: msdosfs_mountfs(devvp, mp, p, argp)
! 252: struct vnode *devvp;
! 253: struct mount *mp;
! 254: struct proc *p;
! 255: struct msdosfs_args *argp;
! 256: {
! 257: struct msdosfsmount *pmp;
! 258: struct buf *bp;
! 259: dev_t dev = devvp->v_rdev;
! 260: union bootsector *bsp;
! 261: struct byte_bpb33 *b33;
! 262: struct byte_bpb50 *b50;
! 263: struct byte_bpb710 *b710;
! 264: extern struct vnode *rootvp;
! 265: u_int8_t SecPerClust;
! 266: int ronly, error, bmapsiz;
! 267: uint32_t fat_max_clusters;
! 268:
! 269: /*
! 270: * Disallow multiple mounts of the same device.
! 271: * Disallow mounting of a device that is currently in use
! 272: * (except for root, which might share swap device for miniroot).
! 273: * Flush out any old buffers remaining from a previous use.
! 274: */
! 275: if ((error = vfs_mountedon(devvp)) != 0)
! 276: return (error);
! 277: if (vcount(devvp) > 1 && devvp != rootvp)
! 278: return (EBUSY);
! 279: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
! 280: error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
! 281: VOP_UNLOCK(devvp, 0, p);
! 282: if (error)
! 283: return (error);
! 284:
! 285: ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
! 286: error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
! 287: if (error)
! 288: return (error);
! 289:
! 290: bp = NULL; /* both used in error_exit */
! 291: pmp = NULL;
! 292:
! 293: /*
! 294: * Read the boot sector of the filesystem, and then check the
! 295: * boot signature. If not a dos boot sector then error out.
! 296: */
! 297: if ((error = bread(devvp, 0, 2048, NOCRED, &bp)) != 0)
! 298: goto error_exit;
! 299: bp->b_flags |= B_AGE;
! 300: bsp = (union bootsector *)bp->b_data;
! 301: b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB;
! 302: b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB;
! 303: b710 = (struct byte_bpb710 *)bsp->bs710.bsPBP;
! 304:
! 305: pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK);
! 306: bzero((caddr_t)pmp, sizeof *pmp);
! 307: pmp->pm_mountp = mp;
! 308:
! 309: /*
! 310: * Compute several useful quantities from the bpb in the
! 311: * bootsector. Copy in the dos 5 variant of the bpb then fix up
! 312: * the fields that are different between dos 5 and dos 3.3.
! 313: */
! 314: SecPerClust = b50->bpbSecPerClust;
! 315: pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
! 316: pmp->pm_ResSectors = getushort(b50->bpbResSectors);
! 317: pmp->pm_FATs = b50->bpbFATs;
! 318: pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
! 319: pmp->pm_Sectors = getushort(b50->bpbSectors);
! 320: pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
! 321: pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
! 322: pmp->pm_Heads = getushort(b50->bpbHeads);
! 323: pmp->pm_Media = b50->bpbMedia;
! 324:
! 325: /* Determine the number of DEV_BSIZE blocks in a MSDOSFS sector */
! 326: pmp->pm_BlkPerSec = pmp->pm_BytesPerSec / DEV_BSIZE;
! 327:
! 328: if (!pmp->pm_BytesPerSec || !SecPerClust || pmp->pm_SecPerTrack > 63) {
! 329: error = EFTYPE;
! 330: goto error_exit;
! 331: }
! 332:
! 333: if (pmp->pm_Sectors == 0) {
! 334: pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
! 335: pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
! 336: } else {
! 337: pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
! 338: pmp->pm_HugeSectors = pmp->pm_Sectors;
! 339: }
! 340:
! 341: if (pmp->pm_RootDirEnts == 0) {
! 342: if (pmp->pm_Sectors || pmp->pm_FATsecs ||
! 343: getushort(b710->bpbFSVers)) {
! 344: error = EINVAL;
! 345: goto error_exit;
! 346: }
! 347: pmp->pm_fatmask = FAT32_MASK;
! 348: pmp->pm_fatmult = 4;
! 349: pmp->pm_fatdiv = 1;
! 350: pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs);
! 351: if (getushort(b710->bpbExtFlags) & FATMIRROR)
! 352: pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM;
! 353: else
! 354: pmp->pm_flags |= MSDOSFS_FATMIRROR;
! 355: } else
! 356: pmp->pm_flags |= MSDOSFS_FATMIRROR;
! 357:
! 358: /*
! 359: * More sanity checks:
! 360: * MSDOSFS sectors per cluster: >0 && power of 2
! 361: * MSDOSFS sector size: >= DEV_BSIZE && power of 2
! 362: * HUGE sector count: >0
! 363: * FAT sectors: >0
! 364: */
! 365: if ((SecPerClust == 0) || (SecPerClust & (SecPerClust - 1)) ||
! 366: (pmp->pm_BytesPerSec < DEV_BSIZE) ||
! 367: (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) ||
! 368: (pmp->pm_HugeSectors == 0) || (pmp->pm_FATsecs == 0)) {
! 369: error = EINVAL;
! 370: goto error_exit;
! 371: }
! 372:
! 373: pmp->pm_HugeSectors *= pmp->pm_BlkPerSec;
! 374: pmp->pm_HiddenSects *= pmp->pm_BlkPerSec;
! 375: pmp->pm_FATsecs *= pmp->pm_BlkPerSec;
! 376: pmp->pm_fatblk = pmp->pm_ResSectors * pmp->pm_BlkPerSec;
! 377: SecPerClust *= pmp->pm_BlkPerSec;
! 378:
! 379: if (FAT32(pmp)) {
! 380: pmp->pm_rootdirblk = getulong(b710->bpbRootClust);
! 381: pmp->pm_firstcluster = pmp->pm_fatblk
! 382: + (pmp->pm_FATs * pmp->pm_FATsecs);
! 383: pmp->pm_fsinfo = getushort(b710->bpbFSInfo) * pmp->pm_BlkPerSec;
! 384: } else {
! 385: pmp->pm_rootdirblk = pmp->pm_fatblk +
! 386: (pmp->pm_FATs * pmp->pm_FATsecs);
! 387: pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)
! 388: + DEV_BSIZE - 1) / DEV_BSIZE;
! 389: pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
! 390: }
! 391:
! 392: pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
! 393: SecPerClust;
! 394: pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1;
! 395: pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE;
! 396:
! 397: if (pmp->pm_fatmask == 0) {
! 398: if (pmp->pm_maxcluster
! 399: <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) {
! 400: /*
! 401: * This will usually be a floppy disk. This size makes
! 402: * sure that one fat entry will not be split across
! 403: * multiple blocks.
! 404: */
! 405: pmp->pm_fatmask = FAT12_MASK;
! 406: pmp->pm_fatmult = 3;
! 407: pmp->pm_fatdiv = 2;
! 408: } else {
! 409: pmp->pm_fatmask = FAT16_MASK;
! 410: pmp->pm_fatmult = 2;
! 411: pmp->pm_fatdiv = 1;
! 412: }
! 413: }
! 414: if (FAT12(pmp))
! 415: pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
! 416: else
! 417: pmp->pm_fatblocksize = MAXBSIZE;
! 418:
! 419: /*
! 420: * We now have the number of sectors in each FAT, so can work
! 421: * out how many clusters can be represented in a FAT. Let's
! 422: * make sure the file system doesn't claim to have more clusters
! 423: * than this.
! 424: *
! 425: * We perform the calculation like we do to avoid integer overflow.
! 426: *
! 427: * This will give us a count of clusters. They are numbered
! 428: * from 0, so the max cluster value is one less than the value
! 429: * we end up with.
! 430: */
! 431: fat_max_clusters = pmp->pm_fatsize / pmp->pm_fatmult;
! 432: fat_max_clusters *= pmp->pm_fatdiv;
! 433: if (pmp->pm_maxcluster >= fat_max_clusters) {
! 434: #ifndef SMALL_KERNEL
! 435: printf("msdosfs: reducing max cluster to %d from %d "
! 436: "due to FAT size\n", fat_max_clusters - 1,
! 437: pmp->pm_maxcluster);
! 438: #endif
! 439: pmp->pm_maxcluster = fat_max_clusters - 1;
! 440: }
! 441:
! 442: pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE;
! 443: pmp->pm_bnshift = ffs(DEV_BSIZE) - 1;
! 444:
! 445: /*
! 446: * Compute mask and shift value for isolating cluster relative byte
! 447: * offsets and cluster numbers from a file offset.
! 448: */
! 449: pmp->pm_bpcluster = SecPerClust * DEV_BSIZE;
! 450: pmp->pm_crbomask = pmp->pm_bpcluster - 1;
! 451: pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;
! 452:
! 453: /*
! 454: * Check for valid cluster size
! 455: * must be a power of 2
! 456: */
! 457: if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) {
! 458: error = EFTYPE;
! 459: goto error_exit;
! 460: }
! 461:
! 462: /*
! 463: * Release the bootsector buffer.
! 464: */
! 465: brelse(bp);
! 466: bp = NULL;
! 467:
! 468: /*
! 469: * Check FSInfo
! 470: */
! 471: if (pmp->pm_fsinfo) {
! 472: struct fsinfo *fp;
! 473:
! 474: if ((error = bread(devvp, pmp->pm_fsinfo, fsi_size(pmp),
! 475: NOCRED, &bp)) != 0)
! 476: goto error_exit;
! 477: fp = (struct fsinfo *)bp->b_data;
! 478: if (!bcmp(fp->fsisig1, "RRaA", 4)
! 479: && !bcmp(fp->fsisig2, "rrAa", 4)
! 480: && !bcmp(fp->fsisig3, "\0\0\125\252", 4)
! 481: && !bcmp(fp->fsisig4, "\0\0\125\252", 4))
! 482: pmp->pm_nxtfree = getulong(fp->fsinxtfree);
! 483: else
! 484: pmp->pm_fsinfo = 0;
! 485: brelse(bp);
! 486: bp = NULL;
! 487: }
! 488:
! 489: /*
! 490: * Check and validate (or perhaps invalidate?) the fsinfo structure? XXX
! 491: */
! 492:
! 493: /*
! 494: * Allocate memory for the bitmap of allocated clusters, and then
! 495: * fill it in.
! 496: */
! 497: bmapsiz = (pmp->pm_maxcluster + N_INUSEBITS - 1) / N_INUSEBITS;
! 498: if (bmapsiz == 0 || SIZE_MAX / bmapsiz < sizeof(*pmp->pm_inusemap)) {
! 499: /* detect multiplicative integer overflow */
! 500: error = EINVAL;
! 501: goto error_exit;
! 502: }
! 503: pmp->pm_inusemap = malloc(bmapsiz * sizeof(*pmp->pm_inusemap),
! 504: M_MSDOSFSFAT, M_WAITOK | M_CANFAIL);
! 505: if (pmp->pm_inusemap == NULL) {
! 506: error = EINVAL;
! 507: goto error_exit;
! 508: }
! 509:
! 510: /*
! 511: * fillinusemap() needs pm_devvp.
! 512: */
! 513: pmp->pm_dev = dev;
! 514: pmp->pm_devvp = devvp;
! 515:
! 516: /*
! 517: * Have the inuse map filled in.
! 518: */
! 519: if ((error = fillinusemap(pmp)) != 0)
! 520: goto error_exit;
! 521:
! 522: /*
! 523: * If they want fat updates to be synchronous then let them suffer
! 524: * the performance degradation in exchange for the on disk copy of
! 525: * the fat being correct just about all the time. I suppose this
! 526: * would be a good thing to turn on if the kernel is still flakey.
! 527: */
! 528: if (mp->mnt_flag & MNT_SYNCHRONOUS)
! 529: pmp->pm_flags |= MSDOSFSMNT_WAITONFAT;
! 530:
! 531: /*
! 532: * Finish up.
! 533: */
! 534: if (ronly)
! 535: pmp->pm_flags |= MSDOSFSMNT_RONLY;
! 536: else
! 537: pmp->pm_fmod = 1;
! 538: mp->mnt_data = (qaddr_t)pmp;
! 539: mp->mnt_stat.f_fsid.val[0] = (long)dev;
! 540: mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
! 541: #ifdef QUOTA
! 542: /*
! 543: * If we ever do quotas for DOS filesystems this would be a place
! 544: * to fill in the info in the msdosfsmount structure. You dolt,
! 545: * quotas on dos filesystems make no sense because files have no
! 546: * owners on dos filesystems. of course there is some empty space
! 547: * in the directory entry where we could put uid's and gid's.
! 548: */
! 549: #endif
! 550: devvp->v_specmountpoint = mp;
! 551:
! 552: return (0);
! 553:
! 554: error_exit:
! 555: devvp->v_specmountpoint = NULL;
! 556: if (bp)
! 557: brelse(bp);
! 558: (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
! 559: if (pmp) {
! 560: if (pmp->pm_inusemap)
! 561: free(pmp->pm_inusemap, M_MSDOSFSFAT);
! 562: free(pmp, M_MSDOSFSMNT);
! 563: mp->mnt_data = (qaddr_t)0;
! 564: }
! 565: return (error);
! 566: }
! 567:
! 568: int
! 569: msdosfs_start(mp, flags, p)
! 570: struct mount *mp;
! 571: int flags;
! 572: struct proc *p;
! 573: {
! 574:
! 575: return (0);
! 576: }
! 577:
! 578: /*
! 579: * Unmount the filesystem described by mp.
! 580: */
! 581: int
! 582: msdosfs_unmount(mp, mntflags, p)
! 583: struct mount *mp;
! 584: int mntflags;
! 585: struct proc *p;
! 586: {
! 587: struct msdosfsmount *pmp;
! 588: int error, flags;
! 589: struct vnode *vp;
! 590:
! 591: flags = 0;
! 592: if (mntflags & MNT_FORCE)
! 593: flags |= FORCECLOSE;
! 594: #ifdef QUOTA
! 595: #endif
! 596: if ((error = vflush(mp, NULLVP, flags)) != 0)
! 597: return (error);
! 598: pmp = VFSTOMSDOSFS(mp);
! 599: pmp->pm_devvp->v_specmountpoint = NULL;
! 600: vp = pmp->pm_devvp;
! 601: #ifdef MSDOSFS_DEBUG
! 602: vprint("msdosfs_umount(): just before calling VOP_CLOSE()\n", vp);
! 603: #endif
! 604: error = VOP_CLOSE(vp,
! 605: pmp->pm_flags & MSDOSFSMNT_RONLY ? FREAD : FREAD|FWRITE, NOCRED, p);
! 606: vrele(vp);
! 607: free(pmp->pm_inusemap, M_MSDOSFSFAT);
! 608: free(pmp, M_MSDOSFSMNT);
! 609: mp->mnt_data = (qaddr_t)0;
! 610: mp->mnt_flag &= ~MNT_LOCAL;
! 611: return (error);
! 612: }
! 613:
! 614: int
! 615: msdosfs_root(mp, vpp)
! 616: struct mount *mp;
! 617: struct vnode **vpp;
! 618: {
! 619: struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
! 620: struct denode *ndep;
! 621: int error;
! 622:
! 623: if ((error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep)) != 0)
! 624: return (error);
! 625:
! 626: #ifdef MSDOSFS_DEBUG
! 627: printf("msdosfs_root(); mp %08x, pmp %08x, ndep %08x, vp %08x\n",
! 628: mp, pmp, ndep, DETOV(ndep));
! 629: #endif
! 630:
! 631: *vpp = DETOV(ndep);
! 632: return (0);
! 633: }
! 634:
! 635: int
! 636: msdosfs_statfs(mp, sbp, p)
! 637: struct mount *mp;
! 638: struct statfs *sbp;
! 639: struct proc *p;
! 640: {
! 641: struct msdosfsmount *pmp;
! 642:
! 643: pmp = VFSTOMSDOSFS(mp);
! 644: sbp->f_bsize = pmp->pm_bpcluster;
! 645: sbp->f_iosize = pmp->pm_bpcluster;
! 646: sbp->f_blocks = pmp->pm_nmbrofclusters;
! 647: sbp->f_bfree = pmp->pm_freeclustercount;
! 648: sbp->f_bavail = pmp->pm_freeclustercount;
! 649: sbp->f_files = pmp->pm_RootDirEnts; /* XXX */
! 650: sbp->f_ffree = 0; /* what to put in here? */
! 651: if (sbp != &mp->mnt_stat) {
! 652: bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
! 653: bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
! 654: bcopy(&mp->mnt_stat.mount_info.msdosfs_args,
! 655: &sbp->mount_info.msdosfs_args, sizeof(struct msdosfs_args));
! 656: }
! 657: strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN);
! 658: return (0);
! 659: }
! 660:
! 661:
! 662: struct msdosfs_sync_arg {
! 663: struct proc *p;
! 664: struct ucred *cred;
! 665: int allerror;
! 666: int waitfor;
! 667: };
! 668:
! 669: int
! 670: msdosfs_sync_vnode(struct vnode *vp, void *arg)
! 671: {
! 672: struct msdosfs_sync_arg *msa = arg;
! 673: int error;
! 674: struct denode *dep;
! 675:
! 676: dep = VTODE(vp);
! 677: if (vp->v_type == VNON ||
! 678: ((dep->de_flag & (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0
! 679: && LIST_EMPTY(&vp->v_dirtyblkhd)) ||
! 680: msa->waitfor == MNT_LAZY) {
! 681: return (0);
! 682: }
! 683:
! 684: if (vget(vp, LK_EXCLUSIVE | LK_NOWAIT, msa->p))
! 685: return (0);
! 686:
! 687: if ((error = VOP_FSYNC(vp, msa->cred, msa->waitfor, msa->p)) != 0)
! 688: msa->allerror = error;
! 689: VOP_UNLOCK(vp, 0, msa->p);
! 690: vrele(vp);
! 691:
! 692: return (0);
! 693: }
! 694:
! 695:
! 696: int
! 697: msdosfs_sync(mp, waitfor, cred, p)
! 698: struct mount *mp;
! 699: int waitfor;
! 700: struct ucred *cred;
! 701: struct proc *p;
! 702: {
! 703: struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
! 704: struct msdosfs_sync_arg msa;
! 705: int error;
! 706:
! 707: msa.allerror = 0;
! 708: msa.p = p;
! 709: msa.cred = cred;
! 710: msa.waitfor = waitfor;
! 711:
! 712: /*
! 713: * If we ever switch to not updating all of the fats all the time,
! 714: * this would be the place to update them from the first one.
! 715: */
! 716: if (pmp->pm_fmod != 0) {
! 717: if (pmp->pm_flags & MSDOSFSMNT_RONLY)
! 718: panic("msdosfs_sync: rofs mod");
! 719: else {
! 720: /* update fats here */
! 721: }
! 722: }
! 723: /*
! 724: * Write back each (modified) denode.
! 725: */
! 726: vfs_mount_foreach_vnode(mp, msdosfs_sync_vnode, &msa);
! 727:
! 728: /*
! 729: * Force stale file system control information to be flushed.
! 730: */
! 731: if (waitfor != MNT_LAZY) {
! 732: vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY, p);
! 733: if ((error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p)) != 0)
! 734: msa.allerror = error;
! 735: VOP_UNLOCK(pmp->pm_devvp, 0, p);
! 736: }
! 737:
! 738: return (msa.allerror);
! 739: }
! 740:
! 741: int
! 742: msdosfs_fhtovp(mp, fhp, vpp)
! 743: struct mount *mp;
! 744: struct fid *fhp;
! 745: struct vnode **vpp;
! 746: {
! 747: struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
! 748: struct defid *defhp = (struct defid *) fhp;
! 749: struct denode *dep;
! 750: int error;
! 751:
! 752: error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep);
! 753: if (error) {
! 754: *vpp = NULLVP;
! 755: return (error);
! 756: }
! 757: *vpp = DETOV(dep);
! 758: return (0);
! 759: }
! 760:
! 761: int
! 762: msdosfs_vptofh(vp, fhp)
! 763: struct vnode *vp;
! 764: struct fid *fhp;
! 765: {
! 766: struct denode *dep;
! 767: struct defid *defhp;
! 768:
! 769: dep = VTODE(vp);
! 770: defhp = (struct defid *)fhp;
! 771: defhp->defid_len = sizeof(struct defid);
! 772: defhp->defid_dirclust = dep->de_dirclust;
! 773: defhp->defid_dirofs = dep->de_diroffset;
! 774: /* defhp->defid_gen = dep->de_gen; */
! 775: return (0);
! 776: }
! 777:
! 778: int
! 779: msdosfs_check_export(mp, nam, exflagsp, credanonp)
! 780: register struct mount *mp;
! 781: struct mbuf *nam;
! 782: int *exflagsp;
! 783: struct ucred **credanonp;
! 784: {
! 785: register struct netcred *np;
! 786: register struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
! 787:
! 788: /*
! 789: * Get the export permission structure for this <mp, client> tuple.
! 790: */
! 791: np = vfs_export_lookup(mp, &pmp->pm_export, nam);
! 792: if (np == NULL)
! 793: return (EACCES);
! 794:
! 795: *exflagsp = np->netc_exflags;
! 796: *credanonp = &np->netc_anon;
! 797: return (0);
! 798: }
! 799:
! 800: #define msdosfs_vget ((int (*)(struct mount *, ino_t, struct vnode **)) \
! 801: eopnotsupp)
! 802:
! 803: #define msdosfs_quotactl ((int (*)(struct mount *, int, uid_t, caddr_t, \
! 804: struct proc *))eopnotsupp)
! 805:
! 806: #define msdosfs_sysctl ((int (*)(int *, u_int, void *, size_t *, void *, \
! 807: size_t, struct proc *))eopnotsupp)
! 808:
! 809: const struct vfsops msdosfs_vfsops = {
! 810: msdosfs_mount,
! 811: msdosfs_start,
! 812: msdosfs_unmount,
! 813: msdosfs_root,
! 814: msdosfs_quotactl,
! 815: msdosfs_statfs,
! 816: msdosfs_sync,
! 817: msdosfs_vget,
! 818: msdosfs_fhtovp,
! 819: msdosfs_vptofh,
! 820: msdosfs_init,
! 821: msdosfs_sysctl,
! 822: msdosfs_check_export
! 823: };
CVSweb