1 /* $FreeBSD$ */ 2 /* $NetBSD: msdosfs_vfsops.c,v 1.51 1997/11/17 15:36:58 ws 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/conf.h> 54 #include <sys/namei.h> 55 #include <sys/proc.h> 56 #include <sys/kernel.h> 57 #include <sys/vnode.h> 58 #include <sys/mount.h> 59 #include <sys/buf.h> 60 #include <sys/fcntl.h> 61 #include <sys/malloc.h> 62 #include <sys/stat.h> /* defines ALLPERMS */ 63 64 #include <msdosfs/bpb.h> 65 #include <msdosfs/bootsect.h> 66 #include <msdosfs/direntry.h> 67 #include <msdosfs/denode.h> 68 #include <msdosfs/msdosfsmount.h> 69 #include <msdosfs/fat.h> 70 71 #define MSDOSFS_DFLTBSIZE 4096 72 73 #if 1 /*def PC98*/ 74 /* 75 * XXX - The boot signature formatted by NEC PC-98 DOS looks like a 76 * garbage or a random value :-{ 77 * If you want to use that broken-signatured media, define the 78 * following symbol even though PC/AT. 79 * (ex. mount PC-98 DOS formatted FD on PC/AT) 80 */ 81 #define MSDOSFS_NOCHECKSIG 82 #endif 83 84 MALLOC_DEFINE(M_MSDOSFSMNT, "MSDOSFS mount", "MSDOSFS mount structure"); 85 static MALLOC_DEFINE(M_MSDOSFSFAT, "MSDOSFS FAT", "MSDOSFS file allocation table"); 86 87 static int update_mp __P((struct mount *mp, struct msdosfs_args *argp)); 88 static int mountmsdosfs __P((struct vnode *devvp, struct mount *mp, 89 struct proc *p, struct msdosfs_args *argp)); 90 static int msdosfs_fhtovp __P((struct mount *, struct fid *, 91 struct vnode **)); 92 static int msdosfs_checkexp __P((struct mount *, struct sockaddr *, 93 int *, struct ucred **)); 94 static int msdosfs_mount __P((struct mount *, char *, caddr_t, 95 struct nameidata *, struct proc *)); 96 static int msdosfs_root __P((struct mount *, struct vnode **)); 97 static int msdosfs_statfs __P((struct mount *, struct statfs *, 98 struct proc *)); 99 static int msdosfs_sync __P((struct mount *, int, struct ucred *, 100 struct proc *)); 101 static int msdosfs_unmount __P((struct mount *, int, struct proc *)); 102 static int msdosfs_vptofh __P((struct vnode *, struct fid *)); 103 104 static int 105 update_mp(mp, argp) 106 struct mount *mp; 107 struct msdosfs_args *argp; 108 { 109 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 110 int error; 111 112 pmp->pm_gid = argp->gid; 113 pmp->pm_uid = argp->uid; 114 pmp->pm_mask = argp->mask & ALLPERMS; 115 pmp->pm_flags |= argp->flags & MSDOSFSMNT_MNTOPT; 116 if (pmp->pm_flags & MSDOSFSMNT_U2WTABLE) { 117 bcopy(argp->u2w, pmp->pm_u2w, sizeof(pmp->pm_u2w)); 118 bcopy(argp->d2u, pmp->pm_d2u, sizeof(pmp->pm_d2u)); 119 bcopy(argp->u2d, pmp->pm_u2d, sizeof(pmp->pm_u2d)); 120 } 121 if (pmp->pm_flags & MSDOSFSMNT_ULTABLE) { 122 bcopy(argp->ul, pmp->pm_ul, sizeof(pmp->pm_ul)); 123 bcopy(argp->lu, pmp->pm_lu, sizeof(pmp->pm_lu)); 124 } 125 126 #ifndef __FreeBSD__ 127 /* 128 * GEMDOS knows nothing (yet) about win95 129 */ 130 if (pmp->pm_flags & MSDOSFSMNT_GEMDOSFS) 131 pmp->pm_flags |= MSDOSFSMNT_NOWIN95; 132 #endif 133 134 if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 135 pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 136 else if (!(pmp->pm_flags & 137 (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) { 138 struct vnode *rootvp; 139 140 /* 141 * Try to divine whether to support Win'95 long filenames 142 */ 143 if (FAT32(pmp)) 144 pmp->pm_flags |= MSDOSFSMNT_LONGNAME; 145 else { 146 if ((error = msdosfs_root(mp, &rootvp)) != 0) 147 return error; 148 pmp->pm_flags |= findwin95(VTODE(rootvp)) 149 ? MSDOSFSMNT_LONGNAME 150 : MSDOSFSMNT_SHORTNAME; 151 vput(rootvp); 152 } 153 } 154 return 0; 155 } 156 157 #ifndef __FreeBSD__ 158 int 159 msdosfs_mountroot() 160 { 161 register struct mount *mp; 162 struct proc *p = curproc; /* XXX */ 163 size_t size; 164 int error; 165 struct msdosfs_args args; 166 167 if (root_device->dv_class != DV_DISK) 168 return (ENODEV); 169 170 /* 171 * Get vnodes for swapdev and rootdev. 172 */ 173 if (bdevvp(rootdev, &rootvp)) 174 panic("msdosfs_mountroot: can't setup rootvp"); 175 176 mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); 177 bzero((char *)mp, (u_long)sizeof(struct mount)); 178 mp->mnt_op = &msdosfs_vfsops; 179 mp->mnt_flag = 0; 180 LIST_INIT(&mp->mnt_vnodelist); 181 182 args.flags = 0; 183 args.uid = 0; 184 args.gid = 0; 185 args.mask = 0777; 186 187 if ((error = mountmsdosfs(rootvp, mp, p, &args)) != 0) { 188 free(mp, M_MOUNT); 189 return (error); 190 } 191 192 if ((error = update_mp(mp, &args)) != 0) { 193 (void)msdosfs_unmount(mp, 0, p); 194 free(mp, M_MOUNT); 195 return (error); 196 } 197 198 if ((error = vfs_lock(mp)) != 0) { 199 (void)msdosfs_unmount(mp, 0, p); 200 free(mp, M_MOUNT); 201 return (error); 202 } 203 204 TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); 205 mp->mnt_vnodecovered = NULLVP; 206 (void) copystr("/", mp->mnt_stat.f_mntonname, MNAMELEN - 1, 207 &size); 208 bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 209 (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 210 &size); 211 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 212 (void)msdosfs_statfs(mp, &mp->mnt_stat, p); 213 vfs_unlock(mp); 214 return (0); 215 } 216 #endif 217 218 /* 219 * mp - path - addr in user space of mount point (ie /usr or whatever) 220 * data - addr in user space of mount params including the name of the block 221 * special file to treat as a filesystem. 222 */ 223 static int 224 msdosfs_mount(mp, path, data, ndp, p) 225 struct mount *mp; 226 char *path; 227 caddr_t data; 228 struct nameidata *ndp; 229 struct proc *p; 230 { 231 struct vnode *devvp; /* vnode for blk device to mount */ 232 struct msdosfs_args args; /* will hold data from mount request */ 233 /* msdosfs specific mount control block */ 234 struct msdosfsmount *pmp = NULL; 235 size_t size; 236 int error, flags; 237 mode_t accessmode; 238 239 error = copyin(data, (caddr_t)&args, sizeof(struct msdosfs_args)); 240 if (error) 241 return (error); 242 if (args.magic != MSDOSFS_ARGSMAGIC) 243 args.flags = 0; 244 /* 245 * If updating, check whether changing from read-only to 246 * read/write; if there is no device name, that's all we do. 247 */ 248 if (mp->mnt_flag & MNT_UPDATE) { 249 pmp = VFSTOMSDOSFS(mp); 250 error = 0; 251 if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_flag & MNT_RDONLY)) { 252 flags = WRITECLOSE; 253 if (mp->mnt_flag & MNT_FORCE) 254 flags |= FORCECLOSE; 255 error = vflush(mp, NULLVP, flags); 256 } 257 if (!error && (mp->mnt_flag & MNT_RELOAD)) 258 /* not yet implemented */ 259 error = EOPNOTSUPP; 260 if (error) 261 return (error); 262 if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_kern_flag & MNTK_WANTRDWR)) { 263 /* 264 * If upgrade to read-write by non-root, then verify 265 * that user has necessary permissions on the device. 266 */ 267 if (p->p_ucred->cr_uid != 0) { 268 devvp = pmp->pm_devvp; 269 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 270 error = VOP_ACCESS(devvp, VREAD | VWRITE, 271 p->p_ucred, p); 272 if (error) { 273 VOP_UNLOCK(devvp, 0, p); 274 return (error); 275 } 276 VOP_UNLOCK(devvp, 0, p); 277 } 278 pmp->pm_flags &= ~MSDOSFSMNT_RONLY; 279 } 280 if (args.fspec == 0) { 281 #ifdef __notyet__ /* doesn't work correctly with current mountd XXX */ 282 if (args.flags & MSDOSFSMNT_MNTOPT) { 283 pmp->pm_flags &= ~MSDOSFSMNT_MNTOPT; 284 pmp->pm_flags |= args.flags & MSDOSFSMNT_MNTOPT; 285 if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 286 pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 287 } 288 #endif 289 /* 290 * Process export requests. 291 */ 292 return (vfs_export(mp, &pmp->pm_export, &args.export)); 293 } 294 } 295 /* 296 * Not an update, or updating the name: look up the name 297 * and verify that it refers to a sensible block device. 298 */ 299 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 300 error = namei(ndp); 301 if (error) 302 return (error); 303 devvp = ndp->ni_vp; 304 NDFREE(ndp, NDF_ONLY_PNBUF); 305 306 if (!vn_isdisk(devvp, &error)) { 307 vrele(devvp); 308 return (error); 309 } 310 /* 311 * If mount by non-root, then verify that user has necessary 312 * permissions on the device. 313 */ 314 if (p->p_ucred->cr_uid != 0) { 315 accessmode = VREAD; 316 if ((mp->mnt_flag & MNT_RDONLY) == 0) 317 accessmode |= VWRITE; 318 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 319 error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p); 320 if (error) { 321 vput(devvp); 322 return (error); 323 } 324 VOP_UNLOCK(devvp, 0, p); 325 } 326 if ((mp->mnt_flag & MNT_UPDATE) == 0) { 327 error = mountmsdosfs(devvp, mp, p, &args); 328 #ifdef MSDOSFS_DEBUG /* only needed for the printf below */ 329 pmp = VFSTOMSDOSFS(mp); 330 #endif 331 } else { 332 if (devvp != pmp->pm_devvp) 333 error = EINVAL; /* XXX needs translation */ 334 else 335 vrele(devvp); 336 } 337 if (error) { 338 vrele(devvp); 339 return (error); 340 } 341 342 error = update_mp(mp, &args); 343 if (error) { 344 msdosfs_unmount(mp, MNT_FORCE, p); 345 return error; 346 } 347 348 (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); 349 bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 350 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 351 &size); 352 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 353 (void) msdosfs_statfs(mp, &mp->mnt_stat, p); 354 #ifdef MSDOSFS_DEBUG 355 printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); 356 #endif 357 return (0); 358 } 359 360 static int 361 mountmsdosfs(devvp, mp, p, argp) 362 struct vnode *devvp; 363 struct mount *mp; 364 struct proc *p; 365 struct msdosfs_args *argp; 366 { 367 struct msdosfsmount *pmp; 368 struct buf *bp; 369 dev_t dev = devvp->v_rdev; 370 #ifndef __FreeBSD__ 371 struct partinfo dpart; 372 int bsize = 0, dtype = 0, tmp; 373 #endif 374 union bootsector *bsp; 375 struct byte_bpb33 *b33; 376 struct byte_bpb50 *b50; 377 struct byte_bpb710 *b710; 378 u_int8_t SecPerClust; 379 u_long clusters; 380 int ronly, error; 381 382 /* 383 * Disallow multiple mounts of the same device. 384 * Disallow mounting of a device that is currently in use 385 * (except for root, which might share swap device for miniroot). 386 * Flush out any old buffers remaining from a previous use. 387 */ 388 error = vfs_mountedon(devvp); 389 if (error) 390 return (error); 391 if (vcount(devvp) > 1 && devvp != rootvp) 392 return (EBUSY); 393 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 394 error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0); 395 VOP_UNLOCK(devvp, 0, p); 396 if (error) 397 return (error); 398 399 ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 400 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 401 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p); 402 VOP_UNLOCK(devvp, 0, p); 403 if (error) 404 return (error); 405 406 bp = NULL; /* both used in error_exit */ 407 pmp = NULL; 408 409 #ifndef __FreeBSD__ 410 if (argp->flags & MSDOSFSMNT_GEMDOSFS) { 411 /* 412 * We need the disklabel to calculate the size of a FAT entry 413 * later on. Also make sure the partition contains a filesystem 414 * of type FS_MSDOS. This doesn't work for floppies, so we have 415 * to check for them too. 416 * 417 * At least some parts of the msdos fs driver seem to assume 418 * that the size of a disk block will always be 512 bytes. 419 * Let's check it... 420 */ 421 error = VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, 422 FREAD, NOCRED, p); 423 if (error) 424 goto error_exit; 425 tmp = dpart.part->p_fstype; 426 dtype = dpart.disklab->d_type; 427 bsize = dpart.disklab->d_secsize; 428 if (bsize != 512 || (dtype!=DTYPE_FLOPPY && tmp!=FS_MSDOS)) { 429 error = EINVAL; 430 goto error_exit; 431 } 432 } 433 #endif 434 435 /* 436 * Read the boot sector of the filesystem, and then check the 437 * boot signature. If not a dos boot sector then error out. 438 * 439 * NOTE: 2048 is a maximum sector size in current... 440 */ 441 error = bread(devvp, 0, 2048, NOCRED, &bp); 442 if (error) 443 goto error_exit; 444 bp->b_flags |= B_AGE; 445 bsp = (union bootsector *)bp->b_data; 446 b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB; 447 b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB; 448 b710 = (struct byte_bpb710 *)bsp->bs710.bsPBP; 449 450 #ifndef __FreeBSD__ 451 if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) { 452 #endif 453 #ifndef MSDOSFS_NOCHECKSIG 454 if (bsp->bs50.bsBootSectSig0 != BOOTSIG0 455 || bsp->bs50.bsBootSectSig1 != BOOTSIG1) { 456 error = EINVAL; 457 goto error_exit; 458 } 459 #endif 460 #ifndef __FreeBSD__ 461 } 462 #endif 463 464 pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK); 465 bzero((caddr_t)pmp, sizeof *pmp); 466 pmp->pm_mountp = mp; 467 468 /* 469 * Compute several useful quantities from the bpb in the 470 * bootsector. Copy in the dos 5 variant of the bpb then fix up 471 * the fields that are different between dos 5 and dos 3.3. 472 */ 473 SecPerClust = b50->bpbSecPerClust; 474 pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 475 pmp->pm_ResSectors = getushort(b50->bpbResSectors); 476 pmp->pm_FATs = b50->bpbFATs; 477 pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 478 pmp->pm_Sectors = getushort(b50->bpbSectors); 479 pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 480 pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 481 pmp->pm_Heads = getushort(b50->bpbHeads); 482 pmp->pm_Media = b50->bpbMedia; 483 484 /* calculate the ratio of sector size to DEV_BSIZE */ 485 pmp->pm_BlkPerSec = pmp->pm_BytesPerSec / DEV_BSIZE; 486 487 #ifndef __FreeBSD__ 488 if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) { 489 #endif 490 /* XXX - We should probably check more values here */ 491 if (!pmp->pm_BytesPerSec || !SecPerClust 492 || !pmp->pm_Heads || pmp->pm_Heads > 255 493 #ifdef PC98 494 || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) { 495 #else 496 || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) { 497 #endif 498 error = EINVAL; 499 goto error_exit; 500 } 501 #ifndef __FreeBSD__ 502 } 503 #endif 504 505 if (pmp->pm_Sectors == 0) { 506 pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 507 pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 508 } else { 509 pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 510 pmp->pm_HugeSectors = pmp->pm_Sectors; 511 } 512 if (pmp->pm_HugeSectors > 0xffffffff / 513 (pmp->pm_BytesPerSec / sizeof(struct direntry)) + 1) { 514 /* 515 * We cannot deal currently with this size of disk 516 * due to fileid limitations (see msdosfs_getattr and 517 * msdosfs_readdir) 518 */ 519 error = EINVAL; 520 printf("mountmsdosfs(): disk too big, sorry\n"); 521 goto error_exit; 522 } 523 524 if (pmp->pm_RootDirEnts == 0) { 525 if (bsp->bs710.bsBootSectSig2 != BOOTSIG2 526 || bsp->bs710.bsBootSectSig3 != BOOTSIG3 527 || pmp->pm_Sectors 528 || pmp->pm_FATsecs 529 || getushort(b710->bpbFSVers)) { 530 error = EINVAL; 531 printf("mountmsdosfs(): bad FAT32 filesystem\n"); 532 goto error_exit; 533 } 534 pmp->pm_fatmask = FAT32_MASK; 535 pmp->pm_fatmult = 4; 536 pmp->pm_fatdiv = 1; 537 pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs); 538 if (getushort(b710->bpbExtFlags) & FATMIRROR) 539 pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM; 540 else 541 pmp->pm_flags |= MSDOSFS_FATMIRROR; 542 } else 543 pmp->pm_flags |= MSDOSFS_FATMIRROR; 544 545 /* 546 * Check a few values (could do some more): 547 * - logical sector size: power of 2, >= block size 548 * - sectors per cluster: power of 2, >= 1 549 * - number of sectors: >= 1, <= size of partition 550 */ 551 if ( (SecPerClust == 0) 552 || (SecPerClust & (SecPerClust - 1)) 553 || (pmp->pm_BytesPerSec < DEV_BSIZE) 554 || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) 555 || (pmp->pm_HugeSectors == 0) 556 ) { 557 error = EINVAL; 558 goto error_exit; 559 } 560 561 pmp->pm_HugeSectors *= pmp->pm_BlkPerSec; 562 pmp->pm_HiddenSects *= pmp->pm_BlkPerSec; /* XXX not used? */ 563 pmp->pm_FATsecs *= pmp->pm_BlkPerSec; 564 SecPerClust *= pmp->pm_BlkPerSec; 565 566 pmp->pm_fatblk = pmp->pm_ResSectors * pmp->pm_BlkPerSec; 567 568 if (FAT32(pmp)) { 569 pmp->pm_rootdirblk = getulong(b710->bpbRootClust); 570 pmp->pm_firstcluster = pmp->pm_fatblk 571 + (pmp->pm_FATs * pmp->pm_FATsecs); 572 pmp->pm_fsinfo = getushort(b710->bpbFSInfo) * pmp->pm_BlkPerSec; 573 } else { 574 pmp->pm_rootdirblk = pmp->pm_fatblk + 575 (pmp->pm_FATs * pmp->pm_FATsecs); 576 pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry) 577 + DEV_BSIZE - 1) 578 / DEV_BSIZE; /* in blocks */ 579 pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 580 } 581 582 pmp->pm_maxcluster = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 583 SecPerClust + 1; 584 pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE; /* XXX not used? */ 585 586 #ifndef __FreeBSD__ 587 if (argp->flags & MSDOSFSMNT_GEMDOSFS) { 588 if ((pmp->pm_maxcluster <= (0xff0 - 2)) 589 && ((dtype == DTYPE_FLOPPY) || ((dtype == DTYPE_VNODE) 590 && ((pmp->pm_Heads == 1) || (pmp->pm_Heads == 2)))) 591 ) { 592 pmp->pm_fatmask = FAT12_MASK; 593 pmp->pm_fatmult = 3; 594 pmp->pm_fatdiv = 2; 595 } else { 596 pmp->pm_fatmask = FAT16_MASK; 597 pmp->pm_fatmult = 2; 598 pmp->pm_fatdiv = 1; 599 } 600 } else 601 #endif 602 if (pmp->pm_fatmask == 0) { 603 if (pmp->pm_maxcluster 604 <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) { 605 /* 606 * This will usually be a floppy disk. This size makes 607 * sure that one fat entry will not be split across 608 * multiple blocks. 609 */ 610 pmp->pm_fatmask = FAT12_MASK; 611 pmp->pm_fatmult = 3; 612 pmp->pm_fatdiv = 2; 613 } else { 614 pmp->pm_fatmask = FAT16_MASK; 615 pmp->pm_fatmult = 2; 616 pmp->pm_fatdiv = 1; 617 } 618 } 619 620 clusters = (pmp->pm_fatsize / pmp->pm_fatmult) * pmp->pm_fatdiv; 621 if (pmp->pm_maxcluster >= clusters) { 622 printf("Warning: number of clusters (%ld) exceeds FAT " 623 "capacity (%ld)\n", pmp->pm_maxcluster + 1, clusters); 624 pmp->pm_maxcluster = clusters - 1; 625 } 626 627 628 if (FAT12(pmp)) 629 pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; 630 else 631 pmp->pm_fatblocksize = MSDOSFS_DFLTBSIZE; 632 633 pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE; 634 pmp->pm_bnshift = ffs(DEV_BSIZE) - 1; 635 636 /* 637 * Compute mask and shift value for isolating cluster relative byte 638 * offsets and cluster numbers from a file offset. 639 */ 640 pmp->pm_bpcluster = SecPerClust * DEV_BSIZE; 641 pmp->pm_crbomask = pmp->pm_bpcluster - 1; 642 pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1; 643 644 /* 645 * Check for valid cluster size 646 * must be a power of 2 647 */ 648 if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) { 649 error = EINVAL; 650 goto error_exit; 651 } 652 653 /* 654 * Release the bootsector buffer. 655 */ 656 brelse(bp); 657 bp = NULL; 658 659 /* 660 * Check FSInfo. 661 */ 662 if (pmp->pm_fsinfo) { 663 struct fsinfo *fp; 664 665 if ((error = bread(devvp, pmp->pm_fsinfo, fsi_size(pmp), 666 NOCRED, &bp)) != 0) 667 goto error_exit; 668 fp = (struct fsinfo *)bp->b_data; 669 if (!bcmp(fp->fsisig1, "RRaA", 4) 670 && !bcmp(fp->fsisig2, "rrAa", 4) 671 && !bcmp(fp->fsisig3, "\0\0\125\252", 4) 672 && !bcmp(fp->fsisig4, "\0\0\125\252", 4)) 673 pmp->pm_nxtfree = getulong(fp->fsinxtfree); 674 else 675 pmp->pm_fsinfo = 0; 676 brelse(bp); 677 bp = NULL; 678 } 679 680 /* 681 * Check and validate (or perhaps invalidate?) the fsinfo structure? XXX 682 */ 683 684 /* 685 * Allocate memory for the bitmap of allocated clusters, and then 686 * fill it in. 687 */ 688 pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS - 1) 689 / N_INUSEBITS) 690 * sizeof(*pmp->pm_inusemap), 691 M_MSDOSFSFAT, M_WAITOK); 692 693 /* 694 * fillinusemap() needs pm_devvp. 695 */ 696 pmp->pm_dev = dev; 697 pmp->pm_devvp = devvp; 698 699 /* 700 * Have the inuse map filled in. 701 */ 702 if ((error = fillinusemap(pmp)) != 0) 703 goto error_exit; 704 705 /* 706 * If they want fat updates to be synchronous then let them suffer 707 * the performance degradation in exchange for the on disk copy of 708 * the fat being correct just about all the time. I suppose this 709 * would be a good thing to turn on if the kernel is still flakey. 710 */ 711 if (mp->mnt_flag & MNT_SYNCHRONOUS) 712 pmp->pm_flags |= MSDOSFSMNT_WAITONFAT; 713 714 /* 715 * Finish up. 716 */ 717 if (ronly) 718 pmp->pm_flags |= MSDOSFSMNT_RONLY; 719 else 720 pmp->pm_fmod = 1; 721 mp->mnt_data = (qaddr_t) pmp; 722 mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); 723 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 724 mp->mnt_flag |= MNT_LOCAL; 725 devvp->v_specmountpoint = mp; 726 727 return 0; 728 729 error_exit: 730 if (bp) 731 brelse(bp); 732 (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE, NOCRED, p); 733 if (pmp) { 734 if (pmp->pm_inusemap) 735 free(pmp->pm_inusemap, M_MSDOSFSFAT); 736 free(pmp, M_MSDOSFSMNT); 737 mp->mnt_data = (qaddr_t)0; 738 } 739 return (error); 740 } 741 742 /* 743 * Unmount the filesystem described by mp. 744 */ 745 static int 746 msdosfs_unmount(mp, mntflags, p) 747 struct mount *mp; 748 int mntflags; 749 struct proc *p; 750 { 751 struct msdosfsmount *pmp; 752 int error, flags; 753 754 flags = 0; 755 if (mntflags & MNT_FORCE) 756 flags |= FORCECLOSE; 757 error = vflush(mp, NULLVP, flags); 758 if (error) 759 return error; 760 pmp = VFSTOMSDOSFS(mp); 761 pmp->pm_devvp->v_specmountpoint = NULL; 762 #ifdef MSDOSFS_DEBUG 763 { 764 struct vnode *vp = pmp->pm_devvp; 765 766 printf("msdosfs_umount(): just before calling VOP_CLOSE()\n"); 767 printf("flag %08lx, usecount %d, writecount %d, holdcnt %ld\n", 768 vp->v_flag, vp->v_usecount, vp->v_writecount, vp->v_holdcnt); 769 printf("id %lu, mount %p, op %p\n", 770 vp->v_id, vp->v_mount, vp->v_op); 771 printf("freef %p, freeb %p, mount %p\n", 772 vp->v_freelist.tqe_next, vp->v_freelist.tqe_prev, 773 vp->v_mount); 774 printf("cleanblkhd %p, dirtyblkhd %p, numoutput %ld, type %d\n", 775 TAILQ_FIRST(&vp->v_cleanblkhd), 776 TAILQ_FIRST(&vp->v_dirtyblkhd), 777 vp->v_numoutput, vp->v_type); 778 printf("union %p, tag %d, data[0] %08x, data[1] %08x\n", 779 vp->v_socket, vp->v_tag, 780 ((u_int *)vp->v_data)[0], 781 ((u_int *)vp->v_data)[1]); 782 } 783 #endif 784 error = VOP_CLOSE(pmp->pm_devvp, 785 (pmp->pm_flags&MSDOSFSMNT_RONLY) ? FREAD : FREAD | FWRITE, 786 NOCRED, p); 787 vrele(pmp->pm_devvp); 788 free(pmp->pm_inusemap, M_MSDOSFSFAT); 789 free(pmp, M_MSDOSFSMNT); 790 mp->mnt_data = (qaddr_t)0; 791 mp->mnt_flag &= ~MNT_LOCAL; 792 return (error); 793 } 794 795 static int 796 msdosfs_root(mp, vpp) 797 struct mount *mp; 798 struct vnode **vpp; 799 { 800 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 801 struct denode *ndep; 802 int error; 803 804 #ifdef MSDOSFS_DEBUG 805 printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp); 806 #endif 807 error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep); 808 if (error) 809 return (error); 810 *vpp = DETOV(ndep); 811 return (0); 812 } 813 814 static int 815 msdosfs_statfs(mp, sbp, p) 816 struct mount *mp; 817 struct statfs *sbp; 818 struct proc *p; 819 { 820 struct msdosfsmount *pmp; 821 822 pmp = VFSTOMSDOSFS(mp); 823 sbp->f_bsize = pmp->pm_bpcluster; 824 sbp->f_iosize = pmp->pm_bpcluster; 825 sbp->f_blocks = pmp->pm_maxcluster + 1; 826 sbp->f_bfree = pmp->pm_freeclustercount; 827 sbp->f_bavail = pmp->pm_freeclustercount; 828 sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ 829 sbp->f_ffree = 0; /* what to put in here? */ 830 if (sbp != &mp->mnt_stat) { 831 sbp->f_type = mp->mnt_vfc->vfc_typenum; 832 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 833 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 834 } 835 strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN); 836 return (0); 837 } 838 839 static int 840 msdosfs_sync(mp, waitfor, cred, p) 841 struct mount *mp; 842 int waitfor; 843 struct ucred *cred; 844 struct proc *p; 845 { 846 struct vnode *vp, *nvp; 847 struct denode *dep; 848 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 849 int error, allerror = 0; 850 851 /* 852 * If we ever switch to not updating all of the fats all the time, 853 * this would be the place to update them from the first one. 854 */ 855 if (pmp->pm_fmod != 0) { 856 if (pmp->pm_flags & MSDOSFSMNT_RONLY) 857 panic("msdosfs_sync: rofs mod"); 858 else { 859 /* update fats here */ 860 } 861 } 862 /* 863 * Write back each (modified) denode. 864 */ 865 simple_lock(&mntvnode_slock); 866 loop: 867 for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { 868 /* 869 * If the vnode that we are about to sync is no longer 870 * associated with this mount point, start over. 871 */ 872 if (vp->v_mount != mp) 873 goto loop; 874 875 simple_lock(&vp->v_interlock); 876 nvp = vp->v_mntvnodes.le_next; 877 dep = VTODE(vp); 878 if (vp->v_type == VNON || 879 ((dep->de_flag & 880 (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0 && 881 (TAILQ_EMPTY(&vp->v_dirtyblkhd) || waitfor == MNT_LAZY))) { 882 simple_unlock(&vp->v_interlock); 883 continue; 884 } 885 simple_unlock(&mntvnode_slock); 886 error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); 887 if (error) { 888 simple_lock(&mntvnode_slock); 889 if (error == ENOENT) 890 goto loop; 891 continue; 892 } 893 error = VOP_FSYNC(vp, cred, waitfor, p); 894 if (error) 895 allerror = error; 896 VOP_UNLOCK(vp, 0, p); 897 vrele(vp); 898 simple_lock(&mntvnode_slock); 899 } 900 simple_unlock(&mntvnode_slock); 901 902 /* 903 * Flush filesystem control info. 904 */ 905 if (waitfor != MNT_LAZY) { 906 vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY, p); 907 error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p); 908 if (error) 909 allerror = error; 910 VOP_UNLOCK(pmp->pm_devvp, 0, p); 911 } 912 return (allerror); 913 } 914 915 static int 916 msdosfs_fhtovp(mp, fhp, vpp) 917 struct mount *mp; 918 struct fid *fhp; 919 struct vnode **vpp; 920 { 921 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 922 struct defid *defhp = (struct defid *) fhp; 923 struct denode *dep; 924 int error; 925 926 error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep); 927 if (error) { 928 *vpp = NULLVP; 929 return (error); 930 } 931 *vpp = DETOV(dep); 932 return (0); 933 } 934 935 static int 936 msdosfs_checkexp(mp, nam, exflagsp, credanonp) 937 struct mount *mp; 938 struct sockaddr *nam; 939 int *exflagsp; 940 struct ucred **credanonp; 941 { 942 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 943 struct netcred *np; 944 945 np = vfs_export_lookup(mp, &pmp->pm_export, nam); 946 if (np == NULL) 947 return (EACCES); 948 *exflagsp = np->netc_exflags; 949 *credanonp = &np->netc_anon; 950 return (0); 951 } 952 953 static int 954 msdosfs_vptofh(vp, fhp) 955 struct vnode *vp; 956 struct fid *fhp; 957 { 958 struct denode *dep; 959 struct defid *defhp; 960 961 dep = VTODE(vp); 962 defhp = (struct defid *)fhp; 963 defhp->defid_len = sizeof(struct defid); 964 defhp->defid_dirclust = dep->de_dirclust; 965 defhp->defid_dirofs = dep->de_diroffset; 966 /* defhp->defid_gen = dep->de_gen; */ 967 return (0); 968 } 969 970 static struct vfsops msdosfs_vfsops = { 971 msdosfs_mount, 972 vfs_stdstart, 973 msdosfs_unmount, 974 msdosfs_root, 975 vfs_stdquotactl, 976 msdosfs_statfs, 977 msdosfs_sync, 978 vfs_stdvget, 979 msdosfs_fhtovp, 980 msdosfs_checkexp, 981 msdosfs_vptofh, 982 msdosfs_init, 983 vfs_stduninit, 984 vfs_stdextattrctl, 985 }; 986 987 VFS_SET(msdosfs_vfsops, msdos, 0); 988