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