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/buf.h> 54 #include <sys/conf.h> 55 #include <sys/fcntl.h> 56 #include <sys/iconv.h> 57 #include <sys/kernel.h> 58 #include <sys/lock.h> 59 #include <sys/malloc.h> 60 #include <sys/mount.h> 61 #include <sys/mutex.h> 62 #include <sys/namei.h> 63 #include <sys/priv.h> 64 #include <sys/proc.h> 65 #include <sys/stat.h> 66 #include <sys/vnode.h> 67 68 #include <geom/geom.h> 69 #include <geom/geom_vfs.h> 70 71 #include <fs/msdosfs/bootsect.h> 72 #include <fs/msdosfs/bpb.h> 73 #include <fs/msdosfs/direntry.h> 74 #include <fs/msdosfs/denode.h> 75 #include <fs/msdosfs/fat.h> 76 #include <fs/msdosfs/msdosfsmount.h> 77 78 #ifdef MSDOSFS_DEBUG 79 #include <sys/rwlock.h> 80 #endif 81 82 static const char msdosfs_lock_msg[] = "fatlk"; 83 84 /* Mount options that we support. */ 85 static const char *msdosfs_opts[] = { 86 "async", "noatime", "noclusterr", "noclusterw", 87 "export", "force", "from", "sync", 88 "cs_dos", "cs_local", "cs_win", "dirmask", 89 "gid", "kiconv", "longname", 90 "longnames", "mask", "shortname", "shortnames", 91 "uid", "win95", "nowin95", 92 NULL 93 }; 94 95 #if 1 /*def PC98*/ 96 /* 97 * XXX - The boot signature formatted by NEC PC-98 DOS looks like a 98 * garbage or a random value :-{ 99 * If you want to use that broken-signatured media, define the 100 * following symbol even though PC/AT. 101 * (ex. mount PC-98 DOS formatted FD on PC/AT) 102 */ 103 #define MSDOSFS_NOCHECKSIG 104 #endif 105 106 MALLOC_DEFINE(M_MSDOSFSMNT, "msdosfs_mount", "MSDOSFS mount structure"); 107 static MALLOC_DEFINE(M_MSDOSFSFAT, "msdosfs_fat", "MSDOSFS file allocation table"); 108 109 struct iconv_functions *msdosfs_iconv; 110 111 static int update_mp(struct mount *mp, struct thread *td); 112 static int mountmsdosfs(struct vnode *devvp, struct mount *mp); 113 static vfs_fhtovp_t msdosfs_fhtovp; 114 static vfs_mount_t msdosfs_mount; 115 static vfs_root_t msdosfs_root; 116 static vfs_statfs_t msdosfs_statfs; 117 static vfs_sync_t msdosfs_sync; 118 static vfs_unmount_t msdosfs_unmount; 119 120 /* Maximum length of a character set name (arbitrary). */ 121 #define MAXCSLEN 64 122 123 static int 124 update_mp(struct mount *mp, struct thread *td) 125 { 126 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 127 void *dos, *win, *local; 128 int error, v; 129 130 if (!vfs_getopt(mp->mnt_optnew, "kiconv", NULL, NULL)) { 131 if (msdosfs_iconv != NULL) { 132 error = vfs_getopt(mp->mnt_optnew, 133 "cs_win", &win, NULL); 134 if (!error) 135 error = vfs_getopt(mp->mnt_optnew, 136 "cs_local", &local, NULL); 137 if (!error) 138 error = vfs_getopt(mp->mnt_optnew, 139 "cs_dos", &dos, NULL); 140 if (!error) { 141 msdosfs_iconv->open(win, local, &pmp->pm_u2w); 142 msdosfs_iconv->open(local, win, &pmp->pm_w2u); 143 msdosfs_iconv->open(dos, local, &pmp->pm_u2d); 144 msdosfs_iconv->open(local, dos, &pmp->pm_d2u); 145 } 146 if (error != 0) 147 return (error); 148 } else { 149 pmp->pm_w2u = NULL; 150 pmp->pm_u2w = NULL; 151 pmp->pm_d2u = NULL; 152 pmp->pm_u2d = NULL; 153 } 154 } 155 156 if (vfs_scanopt(mp->mnt_optnew, "gid", "%d", &v) == 1) 157 pmp->pm_gid = v; 158 if (vfs_scanopt(mp->mnt_optnew, "uid", "%d", &v) == 1) 159 pmp->pm_uid = v; 160 if (vfs_scanopt(mp->mnt_optnew, "mask", "%d", &v) == 1) 161 pmp->pm_mask = v & ALLPERMS; 162 if (vfs_scanopt(mp->mnt_optnew, "dirmask", "%d", &v) == 1) 163 pmp->pm_dirmask = v & ALLPERMS; 164 vfs_flagopt(mp->mnt_optnew, "shortname", 165 &pmp->pm_flags, MSDOSFSMNT_SHORTNAME); 166 vfs_flagopt(mp->mnt_optnew, "shortnames", 167 &pmp->pm_flags, MSDOSFSMNT_SHORTNAME); 168 vfs_flagopt(mp->mnt_optnew, "longname", 169 &pmp->pm_flags, MSDOSFSMNT_LONGNAME); 170 vfs_flagopt(mp->mnt_optnew, "longnames", 171 &pmp->pm_flags, MSDOSFSMNT_LONGNAME); 172 vfs_flagopt(mp->mnt_optnew, "kiconv", 173 &pmp->pm_flags, MSDOSFSMNT_KICONV); 174 175 if (vfs_getopt(mp->mnt_optnew, "nowin95", NULL, NULL) == 0) 176 pmp->pm_flags |= MSDOSFSMNT_NOWIN95; 177 else 178 pmp->pm_flags &= ~MSDOSFSMNT_NOWIN95; 179 180 if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 181 pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 182 else 183 pmp->pm_flags |= MSDOSFSMNT_LONGNAME; 184 return 0; 185 } 186 187 static int 188 msdosfs_cmount(struct mntarg *ma, void *data, uint64_t flags) 189 { 190 struct msdosfs_args args; 191 struct export_args exp; 192 int error; 193 194 if (data == NULL) 195 return (EINVAL); 196 error = copyin(data, &args, sizeof args); 197 if (error) 198 return (error); 199 vfs_oexport_conv(&args.export, &exp); 200 201 ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN); 202 ma = mount_arg(ma, "export", &exp, sizeof(exp)); 203 ma = mount_argf(ma, "uid", "%d", args.uid); 204 ma = mount_argf(ma, "gid", "%d", args.gid); 205 ma = mount_argf(ma, "mask", "%d", args.mask); 206 ma = mount_argf(ma, "dirmask", "%d", args.dirmask); 207 208 ma = mount_argb(ma, args.flags & MSDOSFSMNT_SHORTNAME, "noshortname"); 209 ma = mount_argb(ma, args.flags & MSDOSFSMNT_LONGNAME, "nolongname"); 210 ma = mount_argb(ma, !(args.flags & MSDOSFSMNT_NOWIN95), "nowin95"); 211 ma = mount_argb(ma, args.flags & MSDOSFSMNT_KICONV, "nokiconv"); 212 213 ma = mount_argsu(ma, "cs_win", args.cs_win, MAXCSLEN); 214 ma = mount_argsu(ma, "cs_dos", args.cs_dos, MAXCSLEN); 215 ma = mount_argsu(ma, "cs_local", args.cs_local, MAXCSLEN); 216 217 error = kernel_mount(ma, flags); 218 219 return (error); 220 } 221 222 /* 223 * mp - path - addr in user space of mount point (ie /usr or whatever) 224 * data - addr in user space of mount params including the name of the block 225 * special file to treat as a filesystem. 226 */ 227 static int 228 msdosfs_mount(struct mount *mp) 229 { 230 struct vnode *devvp; /* vnode for blk device to mount */ 231 struct thread *td; 232 /* msdosfs specific mount control block */ 233 struct msdosfsmount *pmp = NULL; 234 struct nameidata ndp; 235 int error, flags; 236 accmode_t accmode; 237 char *from; 238 239 td = curthread; 240 if (vfs_filteropt(mp->mnt_optnew, msdosfs_opts)) 241 return (EINVAL); 242 243 /* 244 * If updating, check whether changing from read-only to 245 * read/write; if there is no device name, that's all we do. 246 */ 247 if (mp->mnt_flag & MNT_UPDATE) { 248 pmp = VFSTOMSDOSFS(mp); 249 if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && 250 vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) { 251 error = VFS_SYNC(mp, MNT_WAIT); 252 if (error) 253 return (error); 254 flags = WRITECLOSE; 255 if (mp->mnt_flag & MNT_FORCE) 256 flags |= FORCECLOSE; 257 error = vflush(mp, 0, flags, td); 258 if (error) 259 return (error); 260 261 /* 262 * Now the volume is clean. Mark it so while the 263 * device is still rw. 264 */ 265 error = markvoldirty(pmp, 0); 266 if (error) { 267 (void)markvoldirty(pmp, 1); 268 return (error); 269 } 270 271 /* Downgrade the device from rw to ro. */ 272 g_topology_lock(); 273 error = g_access(pmp->pm_cp, 0, -1, 0); 274 g_topology_unlock(); 275 if (error) { 276 (void)markvoldirty(pmp, 1); 277 return (error); 278 } 279 280 /* 281 * Backing out after an error was painful in the 282 * above. Now we are committed to succeeding. 283 */ 284 pmp->pm_fmod = 0; 285 pmp->pm_flags |= MSDOSFSMNT_RONLY; 286 MNT_ILOCK(mp); 287 mp->mnt_flag |= MNT_RDONLY; 288 MNT_IUNLOCK(mp); 289 } else if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && 290 !vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) { 291 /* 292 * If upgrade to read-write by non-root, then verify 293 * that user has necessary permissions on the device. 294 */ 295 devvp = pmp->pm_devvp; 296 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 297 error = VOP_ACCESS(devvp, VREAD | VWRITE, 298 td->td_ucred, td); 299 if (error) 300 error = priv_check(td, PRIV_VFS_MOUNT_PERM); 301 if (error) { 302 VOP_UNLOCK(devvp, 0); 303 return (error); 304 } 305 VOP_UNLOCK(devvp, 0); 306 g_topology_lock(); 307 error = g_access(pmp->pm_cp, 0, 1, 0); 308 g_topology_unlock(); 309 if (error) 310 return (error); 311 312 pmp->pm_fmod = 1; 313 pmp->pm_flags &= ~MSDOSFSMNT_RONLY; 314 MNT_ILOCK(mp); 315 mp->mnt_flag &= ~MNT_RDONLY; 316 MNT_IUNLOCK(mp); 317 318 /* Now that the volume is modifiable, mark it dirty. */ 319 error = markvoldirty(pmp, 1); 320 if (error) 321 return (error); 322 } 323 } 324 /* 325 * Not an update, or updating the name: look up the name 326 * and verify that it refers to a sensible disk device. 327 */ 328 if (vfs_getopt(mp->mnt_optnew, "from", (void **)&from, NULL)) 329 return (EINVAL); 330 NDINIT(&ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, from, td); 331 error = namei(&ndp); 332 if (error) 333 return (error); 334 devvp = ndp.ni_vp; 335 NDFREE(&ndp, NDF_ONLY_PNBUF); 336 337 if (!vn_isdisk(devvp, &error)) { 338 vput(devvp); 339 return (error); 340 } 341 /* 342 * If mount by non-root, then verify that user has necessary 343 * permissions on the device. 344 */ 345 accmode = VREAD; 346 if ((mp->mnt_flag & MNT_RDONLY) == 0) 347 accmode |= VWRITE; 348 error = VOP_ACCESS(devvp, accmode, td->td_ucred, td); 349 if (error) 350 error = priv_check(td, PRIV_VFS_MOUNT_PERM); 351 if (error) { 352 vput(devvp); 353 return (error); 354 } 355 if ((mp->mnt_flag & MNT_UPDATE) == 0) { 356 error = mountmsdosfs(devvp, mp); 357 #ifdef MSDOSFS_DEBUG /* only needed for the printf below */ 358 pmp = VFSTOMSDOSFS(mp); 359 #endif 360 } else { 361 vput(devvp); 362 if (devvp != pmp->pm_devvp) 363 return (EINVAL); /* XXX needs translation */ 364 } 365 if (error) { 366 vrele(devvp); 367 return (error); 368 } 369 370 error = update_mp(mp, td); 371 if (error) { 372 if ((mp->mnt_flag & MNT_UPDATE) == 0) 373 msdosfs_unmount(mp, MNT_FORCE); 374 return error; 375 } 376 377 vfs_mountedfrom(mp, from); 378 #ifdef MSDOSFS_DEBUG 379 printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); 380 #endif 381 return (0); 382 } 383 384 static int 385 mountmsdosfs(struct vnode *devvp, struct mount *mp) 386 { 387 struct msdosfsmount *pmp; 388 struct buf *bp; 389 struct cdev *dev; 390 union bootsector *bsp; 391 struct byte_bpb33 *b33; 392 struct byte_bpb50 *b50; 393 struct byte_bpb710 *b710; 394 uint8_t SecPerClust; 395 u_long clusters; 396 int ronly, error; 397 struct g_consumer *cp; 398 struct bufobj *bo; 399 400 bp = NULL; /* This and pmp both used in error_exit. */ 401 pmp = NULL; 402 ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 403 404 dev = devvp->v_rdev; 405 if (atomic_cmpset_acq_ptr((uintptr_t *)&dev->si_mountpt, 0, 406 (uintptr_t)mp) == 0) { 407 VOP_UNLOCK(devvp, 0); 408 return (EBUSY); 409 } 410 g_topology_lock(); 411 error = g_vfs_open(devvp, &cp, "msdosfs", ronly ? 0 : 1); 412 g_topology_unlock(); 413 if (error != 0) { 414 atomic_store_rel_ptr((uintptr_t *)&dev->si_mountpt, 0); 415 VOP_UNLOCK(devvp, 0); 416 return (error); 417 } 418 dev_ref(dev); 419 VOP_UNLOCK(devvp, 0); 420 421 bo = &devvp->v_bufobj; 422 423 /* 424 * Read the boot sector of the filesystem, and then check the 425 * boot signature. If not a dos boot sector then error out. 426 * 427 * NOTE: 8192 is a magic size that works for ffs. 428 */ 429 error = bread(devvp, 0, 8192, NOCRED, &bp); 430 if (error) 431 goto error_exit; 432 bp->b_flags |= B_AGE; 433 bsp = (union bootsector *)bp->b_data; 434 b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB; 435 b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB; 436 b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB; 437 438 #ifndef MSDOSFS_NOCHECKSIG 439 if (bsp->bs50.bsBootSectSig0 != BOOTSIG0 440 || bsp->bs50.bsBootSectSig1 != BOOTSIG1) { 441 error = EINVAL; 442 goto error_exit; 443 } 444 #endif 445 446 pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK | M_ZERO); 447 pmp->pm_mountp = mp; 448 pmp->pm_cp = cp; 449 pmp->pm_bo = bo; 450 451 lockinit(&pmp->pm_fatlock, 0, msdosfs_lock_msg, 0, 0); 452 453 /* 454 * Initialize ownerships and permissions, since nothing else will 455 * initialize them iff we are mounting root. 456 */ 457 pmp->pm_uid = UID_ROOT; 458 pmp->pm_gid = GID_WHEEL; 459 pmp->pm_mask = pmp->pm_dirmask = S_IXUSR | S_IXGRP | S_IXOTH | 460 S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR; 461 462 /* 463 * Compute several useful quantities from the bpb in the 464 * bootsector. Copy in the dos 5 variant of the bpb then fix up 465 * the fields that are different between dos 5 and dos 3.3. 466 */ 467 SecPerClust = b50->bpbSecPerClust; 468 pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 469 if (pmp->pm_BytesPerSec < DEV_BSIZE) { 470 error = EINVAL; 471 goto error_exit; 472 } 473 pmp->pm_ResSectors = getushort(b50->bpbResSectors); 474 pmp->pm_FATs = b50->bpbFATs; 475 pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 476 pmp->pm_Sectors = getushort(b50->bpbSectors); 477 pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 478 pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 479 pmp->pm_Heads = getushort(b50->bpbHeads); 480 pmp->pm_Media = b50->bpbMedia; 481 482 /* calculate the ratio of sector size to DEV_BSIZE */ 483 pmp->pm_BlkPerSec = pmp->pm_BytesPerSec / DEV_BSIZE; 484 485 /* 486 * We don't check pm_Heads nor pm_SecPerTrack, because 487 * these may not be set for EFI file systems. We don't 488 * use these anyway, so we're unaffected if they are 489 * invalid. 490 */ 491 if (!pmp->pm_BytesPerSec || !SecPerClust) { 492 error = EINVAL; 493 goto error_exit; 494 } 495 496 if (pmp->pm_Sectors == 0) { 497 pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 498 pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 499 } else { 500 pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 501 pmp->pm_HugeSectors = pmp->pm_Sectors; 502 } 503 504 if (pmp->pm_RootDirEnts == 0) { 505 if (pmp->pm_FATsecs 506 || getushort(b710->bpbFSVers)) { 507 error = EINVAL; 508 #ifdef MSDOSFS_DEBUG 509 printf("mountmsdosfs(): bad FAT32 filesystem\n"); 510 #endif 511 goto error_exit; 512 } 513 pmp->pm_fatmask = FAT32_MASK; 514 pmp->pm_fatmult = 4; 515 pmp->pm_fatdiv = 1; 516 pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs); 517 if (getushort(b710->bpbExtFlags) & FATMIRROR) 518 pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM; 519 else 520 pmp->pm_flags |= MSDOSFS_FATMIRROR; 521 } else 522 pmp->pm_flags |= MSDOSFS_FATMIRROR; 523 524 /* 525 * Check a few values (could do some more): 526 * - logical sector size: power of 2, >= block size 527 * - sectors per cluster: power of 2, >= 1 528 * - number of sectors: >= 1, <= size of partition 529 * - number of FAT sectors: >= 1 530 */ 531 if ( (SecPerClust == 0) 532 || (SecPerClust & (SecPerClust - 1)) 533 || (pmp->pm_BytesPerSec < DEV_BSIZE) 534 || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) 535 || (pmp->pm_HugeSectors == 0) 536 || (pmp->pm_FATsecs == 0) 537 || (SecPerClust * pmp->pm_BlkPerSec > MAXBSIZE / DEV_BSIZE) 538 ) { 539 error = EINVAL; 540 goto error_exit; 541 } 542 543 pmp->pm_HugeSectors *= pmp->pm_BlkPerSec; 544 pmp->pm_HiddenSects *= pmp->pm_BlkPerSec; /* XXX not used? */ 545 pmp->pm_FATsecs *= pmp->pm_BlkPerSec; 546 SecPerClust *= pmp->pm_BlkPerSec; 547 548 pmp->pm_fatblk = pmp->pm_ResSectors * pmp->pm_BlkPerSec; 549 550 if (FAT32(pmp)) { 551 pmp->pm_rootdirblk = getulong(b710->bpbRootClust); 552 pmp->pm_firstcluster = pmp->pm_fatblk 553 + (pmp->pm_FATs * pmp->pm_FATsecs); 554 pmp->pm_fsinfo = getushort(b710->bpbFSInfo) * pmp->pm_BlkPerSec; 555 } else { 556 pmp->pm_rootdirblk = pmp->pm_fatblk + 557 (pmp->pm_FATs * pmp->pm_FATsecs); 558 pmp->pm_rootdirsize = howmany(pmp->pm_RootDirEnts * 559 sizeof(struct direntry), DEV_BSIZE); /* in blocks */ 560 pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 561 } 562 563 pmp->pm_maxcluster = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 564 SecPerClust + 1; 565 pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE; /* XXX not used? */ 566 567 if (pmp->pm_fatmask == 0) { 568 if (pmp->pm_maxcluster 569 <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) { 570 /* 571 * This will usually be a floppy disk. This size makes 572 * sure that one FAT entry will not be split across 573 * multiple blocks. 574 */ 575 pmp->pm_fatmask = FAT12_MASK; 576 pmp->pm_fatmult = 3; 577 pmp->pm_fatdiv = 2; 578 } else { 579 pmp->pm_fatmask = FAT16_MASK; 580 pmp->pm_fatmult = 2; 581 pmp->pm_fatdiv = 1; 582 } 583 } 584 585 clusters = (pmp->pm_fatsize / pmp->pm_fatmult) * pmp->pm_fatdiv; 586 if (pmp->pm_maxcluster >= clusters) { 587 #ifdef MSDOSFS_DEBUG 588 printf("Warning: number of clusters (%ld) exceeds FAT " 589 "capacity (%ld)\n", pmp->pm_maxcluster + 1, clusters); 590 #endif 591 pmp->pm_maxcluster = clusters - 1; 592 } 593 594 if (FAT12(pmp)) 595 pmp->pm_fatblocksize = 3 * 512; 596 else 597 pmp->pm_fatblocksize = PAGE_SIZE; 598 pmp->pm_fatblocksize = roundup(pmp->pm_fatblocksize, 599 pmp->pm_BytesPerSec); 600 pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE; 601 pmp->pm_bnshift = ffs(DEV_BSIZE) - 1; 602 603 /* 604 * Compute mask and shift value for isolating cluster relative byte 605 * offsets and cluster numbers from a file offset. 606 */ 607 pmp->pm_bpcluster = SecPerClust * DEV_BSIZE; 608 pmp->pm_crbomask = pmp->pm_bpcluster - 1; 609 pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1; 610 611 /* 612 * Check for valid cluster size 613 * must be a power of 2 614 */ 615 if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) { 616 error = EINVAL; 617 goto error_exit; 618 } 619 620 /* 621 * Release the bootsector buffer. 622 */ 623 brelse(bp); 624 bp = NULL; 625 626 /* 627 * Check the fsinfo sector if we have one. Silently fix up our 628 * in-core copy of fp->fsinxtfree if it is unknown (0xffffffff) 629 * or too large. Ignore fp->fsinfree for now, since we need to 630 * read the entire FAT anyway to fill the inuse map. 631 */ 632 if (pmp->pm_fsinfo) { 633 struct fsinfo *fp; 634 635 if ((error = bread(devvp, pmp->pm_fsinfo, pmp->pm_BytesPerSec, 636 NOCRED, &bp)) != 0) 637 goto error_exit; 638 fp = (struct fsinfo *)bp->b_data; 639 if (!bcmp(fp->fsisig1, "RRaA", 4) 640 && !bcmp(fp->fsisig2, "rrAa", 4) 641 && !bcmp(fp->fsisig3, "\0\0\125\252", 4)) { 642 pmp->pm_nxtfree = getulong(fp->fsinxtfree); 643 if (pmp->pm_nxtfree > pmp->pm_maxcluster) 644 pmp->pm_nxtfree = CLUST_FIRST; 645 } else 646 pmp->pm_fsinfo = 0; 647 brelse(bp); 648 bp = NULL; 649 } 650 651 /* 652 * Finish initializing pmp->pm_nxtfree (just in case the first few 653 * sectors aren't properly reserved in the FAT). This completes 654 * the fixup for fp->fsinxtfree, and fixes up the zero-initialized 655 * value if there is no fsinfo. We will use pmp->pm_nxtfree 656 * internally even if there is no fsinfo. 657 */ 658 if (pmp->pm_nxtfree < CLUST_FIRST) 659 pmp->pm_nxtfree = CLUST_FIRST; 660 661 /* 662 * Allocate memory for the bitmap of allocated clusters, and then 663 * fill it in. 664 */ 665 pmp->pm_inusemap = malloc(howmany(pmp->pm_maxcluster + 1, N_INUSEBITS) 666 * sizeof(*pmp->pm_inusemap), 667 M_MSDOSFSFAT, M_WAITOK); 668 669 /* 670 * fillinusemap() needs pm_devvp. 671 */ 672 pmp->pm_devvp = devvp; 673 pmp->pm_dev = dev; 674 675 /* 676 * Have the inuse map filled in. 677 */ 678 MSDOSFS_LOCK_MP(pmp); 679 error = fillinusemap(pmp); 680 MSDOSFS_UNLOCK_MP(pmp); 681 if (error != 0) 682 goto error_exit; 683 684 /* 685 * If they want FAT updates to be synchronous then let them suffer 686 * the performance degradation in exchange for the on disk copy of 687 * the FAT being correct just about all the time. I suppose this 688 * would be a good thing to turn on if the kernel is still flakey. 689 */ 690 if (mp->mnt_flag & MNT_SYNCHRONOUS) 691 pmp->pm_flags |= MSDOSFSMNT_WAITONFAT; 692 693 /* 694 * Finish up. 695 */ 696 if (ronly) 697 pmp->pm_flags |= MSDOSFSMNT_RONLY; 698 else { 699 if ((error = markvoldirty(pmp, 1)) != 0) { 700 (void)markvoldirty(pmp, 0); 701 goto error_exit; 702 } 703 pmp->pm_fmod = 1; 704 } 705 mp->mnt_data = pmp; 706 mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); 707 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 708 MNT_ILOCK(mp); 709 mp->mnt_flag |= MNT_LOCAL; 710 mp->mnt_kern_flag |= MNTK_USES_BCACHE | MNTK_NO_IOPF; 711 MNT_IUNLOCK(mp); 712 713 return (0); 714 715 error_exit: 716 if (bp) 717 brelse(bp); 718 if (cp != NULL) { 719 g_topology_lock(); 720 g_vfs_close(cp); 721 g_topology_unlock(); 722 } 723 if (pmp) { 724 lockdestroy(&pmp->pm_fatlock); 725 free(pmp->pm_inusemap, M_MSDOSFSFAT); 726 free(pmp, M_MSDOSFSMNT); 727 mp->mnt_data = NULL; 728 } 729 atomic_store_rel_ptr((uintptr_t *)&dev->si_mountpt, 0); 730 dev_rel(dev); 731 return (error); 732 } 733 734 /* 735 * Unmount the filesystem described by mp. 736 */ 737 static int 738 msdosfs_unmount(struct mount *mp, int mntflags) 739 { 740 struct msdosfsmount *pmp; 741 int error, flags; 742 743 error = flags = 0; 744 pmp = VFSTOMSDOSFS(mp); 745 if ((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0) 746 error = msdosfs_sync(mp, MNT_WAIT); 747 if ((mntflags & MNT_FORCE) != 0) 748 flags |= FORCECLOSE; 749 else if (error != 0) 750 return (error); 751 error = vflush(mp, 0, flags, curthread); 752 if (error != 0 && error != ENXIO) 753 return (error); 754 if ((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0) { 755 error = markvoldirty(pmp, 0); 756 if (error && error != ENXIO) { 757 (void)markvoldirty(pmp, 1); 758 return (error); 759 } 760 } 761 if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) { 762 if (pmp->pm_w2u) 763 msdosfs_iconv->close(pmp->pm_w2u); 764 if (pmp->pm_u2w) 765 msdosfs_iconv->close(pmp->pm_u2w); 766 if (pmp->pm_d2u) 767 msdosfs_iconv->close(pmp->pm_d2u); 768 if (pmp->pm_u2d) 769 msdosfs_iconv->close(pmp->pm_u2d); 770 } 771 772 #ifdef MSDOSFS_DEBUG 773 { 774 struct vnode *vp = pmp->pm_devvp; 775 struct bufobj *bo; 776 777 bo = &vp->v_bufobj; 778 BO_LOCK(bo); 779 VI_LOCK(vp); 780 vn_printf(vp, 781 "msdosfs_umount(): just before calling VOP_CLOSE()\n"); 782 printf("freef %p, freeb %p, mount %p\n", 783 TAILQ_NEXT(vp, v_actfreelist), vp->v_actfreelist.tqe_prev, 784 vp->v_mount); 785 printf("cleanblkhd %p, dirtyblkhd %p, numoutput %ld, type %d\n", 786 TAILQ_FIRST(&vp->v_bufobj.bo_clean.bv_hd), 787 TAILQ_FIRST(&vp->v_bufobj.bo_dirty.bv_hd), 788 vp->v_bufobj.bo_numoutput, vp->v_type); 789 VI_UNLOCK(vp); 790 BO_UNLOCK(bo); 791 } 792 #endif 793 g_topology_lock(); 794 g_vfs_close(pmp->pm_cp); 795 g_topology_unlock(); 796 atomic_store_rel_ptr((uintptr_t *)&pmp->pm_dev->si_mountpt, 0); 797 vrele(pmp->pm_devvp); 798 dev_rel(pmp->pm_dev); 799 free(pmp->pm_inusemap, M_MSDOSFSFAT); 800 lockdestroy(&pmp->pm_fatlock); 801 free(pmp, M_MSDOSFSMNT); 802 mp->mnt_data = NULL; 803 MNT_ILOCK(mp); 804 mp->mnt_flag &= ~MNT_LOCAL; 805 MNT_IUNLOCK(mp); 806 return (error); 807 } 808 809 static int 810 msdosfs_root(struct mount *mp, int flags, struct vnode **vpp) 811 { 812 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 813 struct denode *ndep; 814 int error; 815 816 #ifdef MSDOSFS_DEBUG 817 printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp); 818 #endif 819 error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep); 820 if (error) 821 return (error); 822 *vpp = DETOV(ndep); 823 return (0); 824 } 825 826 static int 827 msdosfs_statfs(struct mount *mp, struct statfs *sbp) 828 { 829 struct msdosfsmount *pmp; 830 831 pmp = VFSTOMSDOSFS(mp); 832 sbp->f_bsize = pmp->pm_bpcluster; 833 sbp->f_iosize = pmp->pm_bpcluster; 834 sbp->f_blocks = pmp->pm_maxcluster + 1; 835 sbp->f_bfree = pmp->pm_freeclustercount; 836 sbp->f_bavail = pmp->pm_freeclustercount; 837 sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ 838 sbp->f_ffree = 0; /* what to put in here? */ 839 return (0); 840 } 841 842 /* 843 * If we have an FSInfo block, update it. 844 */ 845 static int 846 msdosfs_fsiflush(struct msdosfsmount *pmp, int waitfor) 847 { 848 struct fsinfo *fp; 849 struct buf *bp; 850 int error; 851 852 MSDOSFS_LOCK_MP(pmp); 853 if (pmp->pm_fsinfo == 0 || (pmp->pm_flags & MSDOSFS_FSIMOD) == 0) { 854 error = 0; 855 goto unlock; 856 } 857 error = bread(pmp->pm_devvp, pmp->pm_fsinfo, pmp->pm_BytesPerSec, 858 NOCRED, &bp); 859 if (error != 0) { 860 brelse(bp); 861 goto unlock; 862 } 863 fp = (struct fsinfo *)bp->b_data; 864 putulong(fp->fsinfree, pmp->pm_freeclustercount); 865 putulong(fp->fsinxtfree, pmp->pm_nxtfree); 866 pmp->pm_flags &= ~MSDOSFS_FSIMOD; 867 if (waitfor == MNT_WAIT) 868 error = bwrite(bp); 869 else 870 bawrite(bp); 871 unlock: 872 MSDOSFS_UNLOCK_MP(pmp); 873 return (error); 874 } 875 876 static int 877 msdosfs_sync(struct mount *mp, int waitfor) 878 { 879 struct vnode *vp, *nvp; 880 struct thread *td; 881 struct denode *dep; 882 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 883 int error, allerror = 0; 884 885 td = curthread; 886 887 /* 888 * If we ever switch to not updating all of the FATs all the time, 889 * this would be the place to update them from the first one. 890 */ 891 if (pmp->pm_fmod != 0) { 892 if (pmp->pm_flags & MSDOSFSMNT_RONLY) 893 panic("msdosfs_sync: rofs mod"); 894 else { 895 /* update FATs here */ 896 } 897 } 898 /* 899 * Write back each (modified) denode. 900 */ 901 loop: 902 MNT_VNODE_FOREACH_ALL(vp, mp, nvp) { 903 if (vp->v_type == VNON) { 904 VI_UNLOCK(vp); 905 continue; 906 } 907 dep = VTODE(vp); 908 if ((dep->de_flag & 909 (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0 && 910 (vp->v_bufobj.bo_dirty.bv_cnt == 0 || 911 waitfor == MNT_LAZY)) { 912 VI_UNLOCK(vp); 913 continue; 914 } 915 error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, td); 916 if (error) { 917 if (error == ENOENT) 918 goto loop; 919 continue; 920 } 921 error = VOP_FSYNC(vp, waitfor, td); 922 if (error) 923 allerror = error; 924 VOP_UNLOCK(vp, 0); 925 vrele(vp); 926 } 927 928 /* 929 * Flush filesystem control info. 930 */ 931 if (waitfor != MNT_LAZY) { 932 vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY); 933 error = VOP_FSYNC(pmp->pm_devvp, waitfor, td); 934 if (error) 935 allerror = error; 936 VOP_UNLOCK(pmp->pm_devvp, 0); 937 } 938 939 error = msdosfs_fsiflush(pmp, waitfor); 940 if (error != 0) 941 allerror = error; 942 return (allerror); 943 } 944 945 static int 946 msdosfs_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp) 947 { 948 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 949 struct defid *defhp = (struct defid *) fhp; 950 struct denode *dep; 951 int error; 952 953 error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep); 954 if (error) { 955 *vpp = NULLVP; 956 return (error); 957 } 958 *vpp = DETOV(dep); 959 vnode_create_vobject(*vpp, dep->de_FileSize, curthread); 960 return (0); 961 } 962 963 static struct vfsops msdosfs_vfsops = { 964 .vfs_fhtovp = msdosfs_fhtovp, 965 .vfs_mount = msdosfs_mount, 966 .vfs_cmount = msdosfs_cmount, 967 .vfs_root = msdosfs_root, 968 .vfs_statfs = msdosfs_statfs, 969 .vfs_sync = msdosfs_sync, 970 .vfs_unmount = msdosfs_unmount, 971 }; 972 973 VFS_SET(msdosfs_vfsops, msdosfs, 0); 974 MODULE_VERSION(msdosfs, 1); 975