1 /* $NetBSD: msdosfs_vfsops.c,v 1.51 1997/11/17 15:36:58 ws Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-4-Clause 5 * 6 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. 7 * Copyright (C) 1994, 1995, 1997 TooLs GmbH. 8 * All rights reserved. 9 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by TooLs GmbH. 22 * 4. The name of TooLs GmbH may not be used to endorse or promote products 23 * derived from this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 30 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 31 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 32 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 33 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 34 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 */ 36 /*- 37 * Written by Paul Popelka (paulp@uts.amdahl.com) 38 * 39 * You can do anything you want with this software, just don't say you wrote 40 * it, and don't remove this notice. 41 * 42 * This software is provided "as is". 43 * 44 * The author supplies this software to be publicly redistributed on the 45 * understanding that the author is not responsible for the correct 46 * functioning of this software in any circumstances and is not liable for 47 * any damages caused by this software. 48 * 49 * October 1992 50 */ 51 52 #include <sys/param.h> 53 #include <sys/systm.h> 54 #include <sys/buf.h> 55 #include <sys/bufobj.h> 56 #include <sys/conf.h> 57 #include <sys/fcntl.h> 58 #include <sys/iconv.h> 59 #include <sys/kernel.h> 60 #include <sys/lock.h> 61 #include <sys/malloc.h> 62 #include <sys/mount.h> 63 #include <sys/mutex.h> 64 #include <sys/namei.h> 65 #include <sys/priv.h> 66 #include <sys/proc.h> 67 #include <sys/rwlock.h> 68 #include <sys/stat.h> 69 #include <sys/taskqueue.h> 70 #include <sys/vnode.h> 71 72 #include <geom/geom.h> 73 #include <geom/geom_vfs.h> 74 75 #include <fs/msdosfs/bootsect.h> 76 #include <fs/msdosfs/bpb.h> 77 #include <fs/msdosfs/direntry.h> 78 #include <fs/msdosfs/denode.h> 79 #include <fs/msdosfs/fat.h> 80 #include <fs/msdosfs/msdosfsmount.h> 81 82 #ifdef MSDOSFS_DEBUG 83 #include <sys/rwlock.h> 84 #endif 85 86 static const char msdosfs_lock_msg[] = "fatlk"; 87 88 /* Mount options that we support. */ 89 static const char *msdosfs_opts[] = { 90 "async", "noatime", "noclusterr", "noclusterw", 91 "export", "force", "from", "sync", 92 "cs_dos", "cs_local", "cs_win", "dirmask", 93 "gid", "kiconv", "longname", 94 "longnames", "mask", "shortname", "shortnames", 95 "uid", "win95", "nowin95", 96 NULL 97 }; 98 99 #if 1 /*def PC98*/ 100 /* 101 * XXX - The boot signature formatted by NEC PC-98 DOS looks like a 102 * garbage or a random value :-{ 103 * If you want to use that broken-signatured media, define the 104 * following symbol even though PC/AT. 105 * (ex. mount PC-98 DOS formatted FD on PC/AT) 106 */ 107 #define MSDOSFS_NOCHECKSIG 108 #endif 109 110 MALLOC_DEFINE(M_MSDOSFSMNT, "msdosfs_mount", "MSDOSFS mount structure"); 111 static MALLOC_DEFINE(M_MSDOSFSFAT, "msdosfs_fat", "MSDOSFS file allocation table"); 112 113 struct iconv_functions *msdosfs_iconv; 114 115 static int update_mp(struct mount *mp, struct thread *td); 116 static int mountmsdosfs(struct vnode *devvp, struct mount *mp); 117 static void msdosfs_remount_ro(void *arg, int pending); 118 static vfs_fhtovp_t msdosfs_fhtovp; 119 static vfs_mount_t msdosfs_mount; 120 static vfs_root_t msdosfs_root; 121 static vfs_statfs_t msdosfs_statfs; 122 static vfs_sync_t msdosfs_sync; 123 static vfs_unmount_t msdosfs_unmount; 124 125 /* Maximum length of a character set name (arbitrary). */ 126 #define MAXCSLEN 64 127 128 static int 129 update_mp(struct mount *mp, struct thread *td) 130 { 131 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 132 void *dos, *win, *local; 133 int error, v; 134 135 if (!vfs_getopt(mp->mnt_optnew, "kiconv", NULL, NULL)) { 136 if (msdosfs_iconv != NULL) { 137 error = vfs_getopt(mp->mnt_optnew, 138 "cs_win", &win, NULL); 139 if (!error) 140 error = vfs_getopt(mp->mnt_optnew, 141 "cs_local", &local, NULL); 142 if (!error) 143 error = vfs_getopt(mp->mnt_optnew, 144 "cs_dos", &dos, NULL); 145 if (!error) { 146 msdosfs_iconv->open(win, local, &pmp->pm_u2w); 147 msdosfs_iconv->open(local, win, &pmp->pm_w2u); 148 msdosfs_iconv->open(dos, local, &pmp->pm_u2d); 149 msdosfs_iconv->open(local, dos, &pmp->pm_d2u); 150 } 151 if (error != 0) 152 return (error); 153 } else { 154 pmp->pm_w2u = NULL; 155 pmp->pm_u2w = NULL; 156 pmp->pm_d2u = NULL; 157 pmp->pm_u2d = NULL; 158 } 159 } 160 161 if (vfs_scanopt(mp->mnt_optnew, "gid", "%d", &v) == 1) 162 pmp->pm_gid = v; 163 if (vfs_scanopt(mp->mnt_optnew, "uid", "%d", &v) == 1) 164 pmp->pm_uid = v; 165 if (vfs_scanopt(mp->mnt_optnew, "mask", "%d", &v) == 1) 166 pmp->pm_mask = v & ALLPERMS; 167 if (vfs_scanopt(mp->mnt_optnew, "dirmask", "%d", &v) == 1) 168 pmp->pm_dirmask = v & ALLPERMS; 169 vfs_flagopt(mp->mnt_optnew, "shortname", 170 &pmp->pm_flags, MSDOSFSMNT_SHORTNAME); 171 vfs_flagopt(mp->mnt_optnew, "shortnames", 172 &pmp->pm_flags, MSDOSFSMNT_SHORTNAME); 173 vfs_flagopt(mp->mnt_optnew, "longname", 174 &pmp->pm_flags, MSDOSFSMNT_LONGNAME); 175 vfs_flagopt(mp->mnt_optnew, "longnames", 176 &pmp->pm_flags, MSDOSFSMNT_LONGNAME); 177 vfs_flagopt(mp->mnt_optnew, "kiconv", 178 &pmp->pm_flags, MSDOSFSMNT_KICONV); 179 180 if (vfs_getopt(mp->mnt_optnew, "nowin95", NULL, NULL) == 0) 181 pmp->pm_flags |= MSDOSFSMNT_NOWIN95; 182 else 183 pmp->pm_flags &= ~MSDOSFSMNT_NOWIN95; 184 185 if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 186 pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 187 else 188 pmp->pm_flags |= MSDOSFSMNT_LONGNAME; 189 return 0; 190 } 191 192 static int 193 msdosfs_cmount(struct mntarg *ma, void *data, uint64_t flags) 194 { 195 struct msdosfs_args args; 196 int error; 197 198 if (data == NULL) 199 return (EINVAL); 200 error = copyin(data, &args, sizeof args); 201 if (error) 202 return (error); 203 204 ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN); 205 ma = mount_arg(ma, "export", &args.export, sizeof(args.export)); 206 ma = mount_argf(ma, "uid", "%d", args.uid); 207 ma = mount_argf(ma, "gid", "%d", args.gid); 208 ma = mount_argf(ma, "mask", "%d", args.mask); 209 ma = mount_argf(ma, "dirmask", "%d", args.dirmask); 210 211 ma = mount_argb(ma, args.flags & MSDOSFSMNT_SHORTNAME, "noshortname"); 212 ma = mount_argb(ma, args.flags & MSDOSFSMNT_LONGNAME, "nolongname"); 213 ma = mount_argb(ma, !(args.flags & MSDOSFSMNT_NOWIN95), "nowin95"); 214 ma = mount_argb(ma, args.flags & MSDOSFSMNT_KICONV, "nokiconv"); 215 216 ma = mount_argsu(ma, "cs_win", args.cs_win, MAXCSLEN); 217 ma = mount_argsu(ma, "cs_dos", args.cs_dos, MAXCSLEN); 218 ma = mount_argsu(ma, "cs_local", args.cs_local, MAXCSLEN); 219 220 error = kernel_mount(ma, flags); 221 222 return (error); 223 } 224 225 /* 226 * mp - path - addr in user space of mount point (ie /usr or whatever) 227 * data - addr in user space of mount params including the name of the block 228 * special file to treat as a filesystem. 229 */ 230 static int 231 msdosfs_mount(struct mount *mp) 232 { 233 struct vnode *devvp, *odevvp; /* vnode for blk device to mount */ 234 struct thread *td; 235 /* msdosfs specific mount control block */ 236 struct msdosfsmount *pmp = NULL; 237 struct nameidata ndp; 238 int error, flags; 239 accmode_t accmode; 240 char *from; 241 242 td = curthread; 243 if (vfs_filteropt(mp->mnt_optnew, msdosfs_opts)) 244 return (EINVAL); 245 246 /* 247 * If updating, check whether changing from read-only to 248 * read/write; if there is no device name, that's all we do. 249 */ 250 if (mp->mnt_flag & MNT_UPDATE) { 251 pmp = VFSTOMSDOSFS(mp); 252 if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && 253 vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) { 254 if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0) 255 return (error); 256 error = vfs_write_suspend_umnt(mp); 257 if (error != 0) 258 return (error); 259 260 flags = WRITECLOSE; 261 if (mp->mnt_flag & MNT_FORCE) 262 flags |= FORCECLOSE; 263 error = vflush(mp, 0, flags, td); 264 if (error != 0) { 265 vfs_write_resume(mp, 0); 266 return (error); 267 } 268 269 /* 270 * Now the volume is clean. Mark it so while the 271 * device is still rw. 272 */ 273 error = markvoldirty(pmp, 0); 274 if (error != 0) { 275 vfs_write_resume(mp, 0); 276 (void)markvoldirty(pmp, 1); 277 return (error); 278 } 279 280 /* Downgrade the device from rw to ro. */ 281 g_topology_lock(); 282 error = g_access(pmp->pm_cp, 0, -1, 0); 283 g_topology_unlock(); 284 if (error) { 285 vfs_write_resume(mp, 0); 286 (void)markvoldirty(pmp, 1); 287 return (error); 288 } 289 290 /* 291 * Backing out after an error was painful in the 292 * above. Now we are committed to succeeding. 293 */ 294 pmp->pm_fmod = 0; 295 pmp->pm_flags |= MSDOSFSMNT_RONLY; 296 MNT_ILOCK(mp); 297 mp->mnt_flag |= MNT_RDONLY; 298 MNT_IUNLOCK(mp); 299 vfs_write_resume(mp, 0); 300 } else if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && 301 !vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) { 302 /* 303 * If upgrade to read-write by non-root, then verify 304 * that user has necessary permissions on the device. 305 */ 306 odevvp = pmp->pm_odevvp; 307 vn_lock(odevvp, LK_EXCLUSIVE | LK_RETRY); 308 error = VOP_ACCESS(odevvp, VREAD | VWRITE, 309 td->td_ucred, td); 310 if (error) 311 error = priv_check(td, PRIV_VFS_MOUNT_PERM); 312 if (error) { 313 VOP_UNLOCK(odevvp); 314 return (error); 315 } 316 VOP_UNLOCK(odevvp); 317 g_topology_lock(); 318 error = g_access(pmp->pm_cp, 0, 1, 0); 319 g_topology_unlock(); 320 if (error) 321 return (error); 322 323 /* Now that the volume is modifiable, mark it dirty. */ 324 error = markvoldirty_upgrade(pmp, true, true); 325 if (error) { 326 /* 327 * If dirtying the superblock failed, drop GEOM 328 * 'w' refs (we're still RO). 329 */ 330 g_topology_lock(); 331 (void)g_access(pmp->pm_cp, 0, -1, 0); 332 g_topology_unlock(); 333 334 return (error); 335 } 336 337 pmp->pm_fmod = 1; 338 pmp->pm_flags &= ~MSDOSFSMNT_RONLY; 339 MNT_ILOCK(mp); 340 mp->mnt_flag &= ~MNT_RDONLY; 341 MNT_IUNLOCK(mp); 342 } 343 344 /* 345 * Avoid namei() below. The "from" option is not set. 346 * Update of the devvp is pointless for this case. 347 */ 348 if ((pmp->pm_flags & MSDOSFS_ERR_RO) != 0) 349 return (0); 350 } 351 /* 352 * Not an update, or updating the name: look up the name 353 * and verify that it refers to a sensible disk device. 354 */ 355 if (vfs_getopt(mp->mnt_optnew, "from", (void **)&from, NULL)) 356 return (EINVAL); 357 NDINIT(&ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, from); 358 error = namei(&ndp); 359 if (error) 360 return (error); 361 devvp = ndp.ni_vp; 362 NDFREE_PNBUF(&ndp); 363 364 if (!vn_isdisk_error(devvp, &error)) { 365 vput(devvp); 366 return (error); 367 } 368 /* 369 * If mount by non-root, then verify that user has necessary 370 * permissions on the device. 371 */ 372 accmode = VREAD; 373 if ((mp->mnt_flag & MNT_RDONLY) == 0) 374 accmode |= VWRITE; 375 error = VOP_ACCESS(devvp, accmode, td->td_ucred, td); 376 if (error) 377 error = priv_check(td, PRIV_VFS_MOUNT_PERM); 378 if (error) { 379 vput(devvp); 380 return (error); 381 } 382 if ((mp->mnt_flag & MNT_UPDATE) == 0) { 383 error = mountmsdosfs(devvp, mp); 384 #ifdef MSDOSFS_DEBUG /* only needed for the printf below */ 385 pmp = VFSTOMSDOSFS(mp); 386 #endif 387 } else { 388 vput(devvp); 389 if (devvp != pmp->pm_odevvp) 390 return (EINVAL); /* XXX needs translation */ 391 } 392 if (error) { 393 vrele(devvp); 394 return (error); 395 } 396 397 error = update_mp(mp, td); 398 if (error) { 399 if ((mp->mnt_flag & MNT_UPDATE) == 0) 400 msdosfs_unmount(mp, MNT_FORCE); 401 return error; 402 } 403 404 vfs_mountedfrom(mp, from); 405 #ifdef MSDOSFS_DEBUG 406 printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); 407 #endif 408 return (0); 409 } 410 411 /* 412 * The FAT12 and FAT16 file systems use a limited size root directory that 413 * can be created with 1 to 65535 entries for files, directories, or a disk 414 * label (but DOS or Windows creates at most 512 root directory entries). 415 * This function calculates the number of free root directory entries by 416 * counting the non-deleted entries (not starting with 0xE5) and by adding 417 * the amount of never used entries (with the position indicated by an 418 * entry that starts with 0x00). 419 */ 420 static int 421 rootdir_free(struct msdosfsmount* pmp) 422 { 423 struct buf *bp; 424 struct direntry *dep; 425 u_long readsize; 426 int dirclu; 427 int diridx; 428 int dirmax; 429 int dirleft; 430 int ffree; 431 432 dirclu = pmp->pm_rootdirblk; 433 434 /* 435 * The msdosfs code ignores pm_RootDirEnts and uses pm_rootdirsize 436 * (measured in DEV_BSIZE) to prevent excess root dir allocations. 437 */ 438 dirleft = howmany(pmp->pm_rootdirsize * DEV_BSIZE, 439 sizeof(struct direntry)); 440 441 /* Read in chunks of default maximum root directory size */ 442 readsize = 512 * sizeof(struct direntry); 443 444 #ifdef MSDOSFS_DEBUG 445 printf("rootdir_free: blkpersec=%lu fatblksize=%lu dirsize=%lu " 446 "firstclu=%lu dirclu=%d entries=%d rootdirsize=%lu " 447 "bytespersector=%hu bytepercluster=%lu\n", 448 pmp->pm_BlkPerSec, pmp->pm_fatblocksize, readsize, 449 pmp->pm_firstcluster, dirclu, dirleft, pmp->pm_rootdirsize, 450 pmp->pm_BytesPerSec, pmp->pm_bpcluster); 451 #endif 452 ffree = dirleft; 453 while (dirleft > 0 && ffree > 0) { 454 if (readsize > dirleft * sizeof(struct direntry)) 455 readsize = dirleft * sizeof(struct direntry); 456 #ifdef MSDOSFS_DEBUG 457 printf("rootdir_free: dirclu=%d dirleft=%d readsize=%lu\n", 458 dirclu, dirleft, readsize); 459 #endif 460 if (bread(pmp->pm_devvp, dirclu, readsize, NOCRED, &bp) != 0) { 461 printf("rootdir_free: read error\n"); 462 if (bp != NULL) 463 brelse(bp); 464 return (-1); 465 } 466 dirmax = readsize / sizeof(struct direntry); 467 for (diridx = 0; diridx < dirmax && dirleft > 0; 468 diridx++, dirleft--) { 469 dep = (struct direntry*)bp->b_data + diridx; 470 #ifdef MSDOSFS_DEBUG 471 if (dep->deName[0] == SLOT_DELETED) 472 printf("rootdir_free: idx=%d <deleted>\n", 473 diridx); 474 else if (dep->deName[0] == SLOT_EMPTY) 475 printf("rootdir_free: idx=%d <end marker>\n", 476 diridx); 477 else if (dep->deAttributes == ATTR_WIN95) 478 printf("rootdir_free: idx=%d <LFN part %d>\n", 479 diridx, (dep->deName[0] & 0x1f) + 1); 480 else if (dep->deAttributes & ATTR_VOLUME) 481 printf("rootdir_free: idx=%d label='%11.11s'\n", 482 diridx, dep->deName); 483 else if (dep->deAttributes & ATTR_DIRECTORY) 484 printf("rootdir_free: idx=%d dir='%11.11s'\n", 485 diridx, dep->deName); 486 else 487 printf("rootdir_free: idx=%d file='%11.11s'\n", 488 diridx, dep->deName); 489 #endif 490 if (dep->deName[0] == SLOT_EMPTY) 491 dirleft = 0; 492 else if (dep->deName[0] != SLOT_DELETED) 493 ffree--; 494 } 495 brelse(bp); 496 bp = NULL; 497 dirclu += readsize / DEV_BSIZE; 498 } 499 return (ffree); 500 } 501 502 static int 503 mountmsdosfs(struct vnode *odevvp, struct mount *mp) 504 { 505 struct msdosfsmount *pmp; 506 struct buf *bp; 507 struct cdev *dev; 508 struct vnode *devvp; 509 union bootsector *bsp; 510 struct byte_bpb33 *b33; 511 struct byte_bpb50 *b50; 512 struct byte_bpb710 *b710; 513 uint8_t SecPerClust; 514 u_long clusters; 515 int ronly, error; 516 struct g_consumer *cp; 517 struct bufobj *bo; 518 519 bp = NULL; /* This and pmp both used in error_exit. */ 520 pmp = NULL; 521 ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 522 523 devvp = mntfs_allocvp(mp, odevvp); 524 dev = devvp->v_rdev; 525 if (atomic_cmpset_acq_ptr((uintptr_t *)&dev->si_mountpt, 0, 526 (uintptr_t)mp) == 0) { 527 mntfs_freevp(devvp); 528 return (EBUSY); 529 } 530 g_topology_lock(); 531 error = g_vfs_open(devvp, &cp, "msdosfs", ronly ? 0 : 1); 532 g_topology_unlock(); 533 if (error != 0) { 534 atomic_store_rel_ptr((uintptr_t *)&dev->si_mountpt, 0); 535 mntfs_freevp(devvp); 536 return (error); 537 } 538 dev_ref(dev); 539 bo = &devvp->v_bufobj; 540 BO_LOCK(&odevvp->v_bufobj); 541 odevvp->v_bufobj.bo_flag |= BO_NOBUFS; 542 BO_UNLOCK(&odevvp->v_bufobj); 543 VOP_UNLOCK(devvp); 544 if (dev->si_iosize_max != 0) 545 mp->mnt_iosize_max = dev->si_iosize_max; 546 if (mp->mnt_iosize_max > maxphys) 547 mp->mnt_iosize_max = maxphys; 548 549 /* 550 * Read the boot sector of the filesystem, and then check the 551 * boot signature. If not a dos boot sector then error out. 552 * 553 * NOTE: 8192 is a magic size that works for ffs. 554 */ 555 error = bread(devvp, 0, 8192, NOCRED, &bp); 556 if (error) 557 goto error_exit; 558 bp->b_flags |= B_AGE; 559 bsp = (union bootsector *)bp->b_data; 560 b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB; 561 b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB; 562 b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB; 563 564 #ifndef MSDOSFS_NOCHECKSIG 565 if (bsp->bs50.bsBootSectSig0 != BOOTSIG0 || 566 bsp->bs50.bsBootSectSig1 != BOOTSIG1) { 567 error = EINVAL; 568 goto error_exit; 569 } 570 #endif 571 572 pmp = malloc(sizeof(*pmp), M_MSDOSFSMNT, M_WAITOK | M_ZERO); 573 pmp->pm_mountp = mp; 574 pmp->pm_cp = cp; 575 pmp->pm_bo = bo; 576 577 lockinit(&pmp->pm_fatlock, 0, msdosfs_lock_msg, 0, 0); 578 lockinit(&pmp->pm_checkpath_lock, 0, "msdoscp", 0, 0); 579 580 TASK_INIT(&pmp->pm_rw2ro_task, 0, msdosfs_remount_ro, pmp); 581 582 /* 583 * Initialize ownerships and permissions, since nothing else will 584 * initialize them iff we are mounting root. 585 */ 586 pmp->pm_uid = UID_ROOT; 587 pmp->pm_gid = GID_WHEEL; 588 pmp->pm_mask = pmp->pm_dirmask = S_IXUSR | S_IXGRP | S_IXOTH | 589 S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR; 590 591 /* 592 * Compute several useful quantities from the bpb in the 593 * bootsector. Copy in the dos 5 variant of the bpb then fix up 594 * the fields that are different between dos 5 and dos 3.3. 595 */ 596 SecPerClust = b50->bpbSecPerClust; 597 pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 598 if (pmp->pm_BytesPerSec < DEV_BSIZE) { 599 error = EINVAL; 600 goto error_exit; 601 } 602 pmp->pm_ResSectors = getushort(b50->bpbResSectors); 603 pmp->pm_FATs = b50->bpbFATs; 604 pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 605 pmp->pm_Sectors = getushort(b50->bpbSectors); 606 pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 607 pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 608 pmp->pm_Heads = getushort(b50->bpbHeads); 609 pmp->pm_Media = b50->bpbMedia; 610 611 /* calculate the ratio of sector size to DEV_BSIZE */ 612 pmp->pm_BlkPerSec = pmp->pm_BytesPerSec / DEV_BSIZE; 613 614 /* 615 * We don't check pm_Heads nor pm_SecPerTrack, because 616 * these may not be set for EFI file systems. We don't 617 * use these anyway, so we're unaffected if they are 618 * invalid. 619 */ 620 if (pmp->pm_BytesPerSec == 0 || SecPerClust == 0) { 621 error = EINVAL; 622 goto error_exit; 623 } 624 625 if (pmp->pm_Sectors == 0) { 626 pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 627 pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 628 } else { 629 pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 630 pmp->pm_HugeSectors = pmp->pm_Sectors; 631 } 632 633 if (pmp->pm_RootDirEnts == 0) { 634 if (pmp->pm_FATsecs != 0 || getushort(b710->bpbFSVers) != 0) { 635 error = EINVAL; 636 #ifdef MSDOSFS_DEBUG 637 printf("mountmsdosfs(): bad FAT32 filesystem\n"); 638 #endif 639 goto error_exit; 640 } 641 pmp->pm_fatmask = FAT32_MASK; 642 pmp->pm_fatmult = 4; 643 pmp->pm_fatdiv = 1; 644 pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs); 645 if ((getushort(b710->bpbExtFlags) & FATMIRROR) != 0) 646 pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM; 647 else 648 pmp->pm_flags |= MSDOSFS_FATMIRROR; 649 } else 650 pmp->pm_flags |= MSDOSFS_FATMIRROR; 651 652 /* 653 * Check a few values (could do some more): 654 * - logical sector size: power of 2, >= block size 655 * - sectors per cluster: power of 2, >= 1 656 * - number of sectors: >= 1, <= size of partition 657 * - number of FAT sectors: >= 1 658 */ 659 if (SecPerClust == 0 || (SecPerClust & (SecPerClust - 1)) != 0 || 660 pmp->pm_BytesPerSec < DEV_BSIZE || 661 (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) != 0 || 662 pmp->pm_HugeSectors == 0 || pmp->pm_FATsecs == 0 || 663 SecPerClust * pmp->pm_BlkPerSec > MAXBSIZE / DEV_BSIZE) { 664 error = EINVAL; 665 goto error_exit; 666 } 667 668 if ((off_t)pmp->pm_HugeSectors * pmp->pm_BytesPerSec < 669 pmp->pm_HugeSectors /* overflow */ || 670 (off_t)pmp->pm_HugeSectors * pmp->pm_BytesPerSec > 671 cp->provider->mediasize /* past end of vol */) { 672 error = EINVAL; 673 goto error_exit; 674 } 675 676 pmp->pm_HugeSectors *= pmp->pm_BlkPerSec; 677 pmp->pm_HiddenSects *= pmp->pm_BlkPerSec; /* XXX not used? */ 678 pmp->pm_FATsecs *= pmp->pm_BlkPerSec; 679 SecPerClust *= pmp->pm_BlkPerSec; 680 681 pmp->pm_fatblk = pmp->pm_ResSectors * pmp->pm_BlkPerSec; 682 683 if (FAT32(pmp)) { 684 pmp->pm_rootdirblk = getulong(b710->bpbRootClust); 685 pmp->pm_firstcluster = pmp->pm_fatblk + 686 pmp->pm_FATs * pmp->pm_FATsecs; 687 pmp->pm_fsinfo = getushort(b710->bpbFSInfo) * pmp->pm_BlkPerSec; 688 } else { 689 pmp->pm_rootdirblk = pmp->pm_fatblk + 690 pmp->pm_FATs * pmp->pm_FATsecs; 691 pmp->pm_rootdirsize = howmany(pmp->pm_RootDirEnts * 692 sizeof(struct direntry), DEV_BSIZE); /* in blocks */ 693 pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 694 } 695 696 if (pmp->pm_HugeSectors <= pmp->pm_firstcluster) { 697 error = EINVAL; 698 goto error_exit; 699 } 700 pmp->pm_maxcluster = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 701 SecPerClust + 1; 702 pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE; 703 704 if (pmp->pm_fatmask == 0) { 705 /* 706 * The last 10 (or 16?) clusters are reserved and must not 707 * be allocated for data. 708 */ 709 if (pmp->pm_maxcluster < (CLUST_RSRVD & FAT12_MASK)) { 710 /* 711 * This will usually be a floppy disk. This size makes 712 * sure that one FAT entry will not be split across 713 * multiple blocks. 714 */ 715 pmp->pm_fatmask = FAT12_MASK; 716 pmp->pm_fatmult = 3; 717 pmp->pm_fatdiv = 2; 718 } else { 719 pmp->pm_fatmask = FAT16_MASK; 720 pmp->pm_fatmult = 2; 721 pmp->pm_fatdiv = 1; 722 } 723 } 724 725 clusters = (pmp->pm_fatsize / pmp->pm_fatmult) * pmp->pm_fatdiv; 726 if (clusters >= (CLUST_RSRVD & pmp->pm_fatmask)) 727 clusters = CLUST_RSRVD & pmp->pm_fatmask; 728 if (pmp->pm_maxcluster >= clusters) { 729 #ifdef MSDOSFS_DEBUG 730 printf("Warning: number of clusters (%ld) exceeds FAT " 731 "capacity (%ld)\n", pmp->pm_maxcluster - 1, clusters); 732 #endif 733 pmp->pm_maxcluster = clusters - 1; 734 } 735 736 if (FAT12(pmp)) 737 pmp->pm_fatblocksize = 3 * 512; 738 else 739 pmp->pm_fatblocksize = PAGE_SIZE; 740 pmp->pm_fatblocksize = roundup(pmp->pm_fatblocksize, 741 pmp->pm_BytesPerSec); 742 pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE; 743 pmp->pm_bnshift = ffs(DEV_BSIZE) - 1; 744 745 /* 746 * Compute mask and shift value for isolating cluster relative byte 747 * offsets and cluster numbers from a file offset. 748 */ 749 pmp->pm_bpcluster = SecPerClust * DEV_BSIZE; 750 pmp->pm_crbomask = pmp->pm_bpcluster - 1; 751 pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1; 752 753 /* 754 * Check for valid cluster size 755 * must be a power of 2 756 */ 757 if ((pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) != 0) { 758 error = EINVAL; 759 goto error_exit; 760 } 761 762 /* 763 * Release the bootsector buffer. 764 */ 765 brelse(bp); 766 bp = NULL; 767 768 /* 769 * Check the fsinfo sector if we have one. Silently fix up our 770 * in-core copy of fp->fsinxtfree if it is unknown (0xffffffff) 771 * or too large. Ignore fp->fsinfree for now, since we need to 772 * read the entire FAT anyway to fill the inuse map. 773 */ 774 if (pmp->pm_fsinfo) { 775 struct fsinfo *fp; 776 777 if ((error = bread(devvp, pmp->pm_fsinfo, pmp->pm_BytesPerSec, 778 NOCRED, &bp)) != 0) 779 goto error_exit; 780 fp = (struct fsinfo *)bp->b_data; 781 if (!bcmp(fp->fsisig1, "RRaA", 4) && 782 !bcmp(fp->fsisig2, "rrAa", 4) && 783 !bcmp(fp->fsisig3, "\0\0\125\252", 4)) { 784 pmp->pm_nxtfree = getulong(fp->fsinxtfree); 785 if (pmp->pm_nxtfree > pmp->pm_maxcluster) 786 pmp->pm_nxtfree = CLUST_FIRST; 787 } else 788 pmp->pm_fsinfo = 0; 789 brelse(bp); 790 bp = NULL; 791 } 792 793 /* 794 * Finish initializing pmp->pm_nxtfree (just in case the first few 795 * sectors aren't properly reserved in the FAT). This completes 796 * the fixup for fp->fsinxtfree, and fixes up the zero-initialized 797 * value if there is no fsinfo. We will use pmp->pm_nxtfree 798 * internally even if there is no fsinfo. 799 */ 800 if (pmp->pm_nxtfree < CLUST_FIRST) 801 pmp->pm_nxtfree = CLUST_FIRST; 802 803 /* 804 * Allocate memory for the bitmap of allocated clusters, and then 805 * fill it in. 806 */ 807 pmp->pm_inusemap = malloc(howmany(pmp->pm_maxcluster + 1, 808 N_INUSEBITS) * sizeof(*pmp->pm_inusemap), M_MSDOSFSFAT, M_WAITOK); 809 810 /* 811 * fillinusemap() needs pm_devvp. 812 */ 813 pmp->pm_devvp = devvp; 814 pmp->pm_odevvp = odevvp; 815 pmp->pm_dev = dev; 816 817 /* 818 * Have the inuse map filled in. 819 */ 820 MSDOSFS_LOCK_MP(pmp); 821 error = fillinusemap(pmp); 822 MSDOSFS_UNLOCK_MP(pmp); 823 if (error != 0) 824 goto error_exit; 825 826 /* 827 * If they want FAT updates to be synchronous then let them suffer 828 * the performance degradation in exchange for the on disk copy of 829 * the FAT being correct just about all the time. I suppose this 830 * would be a good thing to turn on if the kernel is still flakey. 831 */ 832 if (mp->mnt_flag & MNT_SYNCHRONOUS) 833 pmp->pm_flags |= MSDOSFSMNT_WAITONFAT; 834 835 /* 836 * Finish up. 837 */ 838 if (ronly) 839 pmp->pm_flags |= MSDOSFSMNT_RONLY; 840 else { 841 if ((error = markvoldirty(pmp, 1)) != 0) 842 goto error_exit; 843 pmp->pm_fmod = 1; 844 } 845 846 if (FAT32(pmp)) { 847 pmp->pm_rootdirfree = 0; 848 } else { 849 pmp->pm_rootdirfree = rootdir_free(pmp); 850 if (pmp->pm_rootdirfree < 0) 851 goto error_exit; 852 } 853 854 mp->mnt_data = pmp; 855 mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); 856 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 857 MNT_ILOCK(mp); 858 mp->mnt_flag |= MNT_LOCAL; 859 mp->mnt_kern_flag |= MNTK_USES_BCACHE | MNTK_NO_IOPF; 860 MNT_IUNLOCK(mp); 861 862 return (0); 863 864 error_exit: 865 if (bp != NULL) 866 brelse(bp); 867 if (cp != NULL) { 868 g_topology_lock(); 869 g_vfs_close(cp); 870 g_topology_unlock(); 871 } 872 if (pmp != NULL) { 873 lockdestroy(&pmp->pm_fatlock); 874 lockdestroy(&pmp->pm_checkpath_lock); 875 free(pmp->pm_inusemap, M_MSDOSFSFAT); 876 free(pmp, M_MSDOSFSMNT); 877 mp->mnt_data = NULL; 878 } 879 BO_LOCK(&odevvp->v_bufobj); 880 odevvp->v_bufobj.bo_flag &= ~BO_NOBUFS; 881 BO_UNLOCK(&odevvp->v_bufobj); 882 atomic_store_rel_ptr((uintptr_t *)&dev->si_mountpt, 0); 883 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 884 mntfs_freevp(devvp); 885 dev_rel(dev); 886 return (error); 887 } 888 889 /* 890 * Unmount the filesystem described by mp. 891 */ 892 static int 893 msdosfs_unmount(struct mount *mp, int mntflags) 894 { 895 struct msdosfsmount *pmp; 896 int error, flags; 897 bool susp; 898 899 error = flags = 0; 900 pmp = VFSTOMSDOSFS(mp); 901 susp = (pmp->pm_flags & MSDOSFSMNT_RONLY) == 0; 902 903 if (susp) { 904 error = vfs_write_suspend_umnt(mp); 905 if (error != 0) 906 return (error); 907 } 908 909 if ((mntflags & MNT_FORCE) != 0) 910 flags |= FORCECLOSE; 911 error = vflush(mp, 0, flags, curthread); 912 if (error != 0 && error != ENXIO) { 913 if (susp) 914 vfs_write_resume(mp, VR_START_WRITE); 915 return (error); 916 } 917 if (susp) { 918 error = markvoldirty(pmp, 0); 919 if (error != 0 && error != ENXIO) { 920 if (susp) 921 vfs_write_resume(mp, VR_START_WRITE); 922 (void)markvoldirty(pmp, 1); 923 return (error); 924 } 925 } 926 if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) { 927 if (pmp->pm_w2u) 928 msdosfs_iconv->close(pmp->pm_w2u); 929 if (pmp->pm_u2w) 930 msdosfs_iconv->close(pmp->pm_u2w); 931 if (pmp->pm_d2u) 932 msdosfs_iconv->close(pmp->pm_d2u); 933 if (pmp->pm_u2d) 934 msdosfs_iconv->close(pmp->pm_u2d); 935 } 936 937 #ifdef MSDOSFS_DEBUG 938 { 939 struct vnode *vp = pmp->pm_devvp; 940 struct bufobj *bo; 941 942 bo = &vp->v_bufobj; 943 BO_LOCK(bo); 944 VI_LOCK(vp); 945 vn_printf(vp, 946 "msdosfs_umount(): just before calling VOP_CLOSE()\n"); 947 printf("freef %p, freeb %p, mount %p\n", 948 TAILQ_NEXT(vp, v_vnodelist), vp->v_vnodelist.tqe_prev, 949 vp->v_mount); 950 printf("cleanblkhd %p, dirtyblkhd %p, numoutput %d, type %d\n", 951 TAILQ_FIRST(&vp->v_bufobj.bo_clean.bv_hd), 952 TAILQ_FIRST(&vp->v_bufobj.bo_dirty.bv_hd), 953 vp->v_bufobj.bo_numoutput, vp->v_type); 954 VI_UNLOCK(vp); 955 BO_UNLOCK(bo); 956 } 957 #endif 958 if (susp) 959 vfs_write_resume(mp, VR_START_WRITE); 960 961 vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY); 962 g_topology_lock(); 963 g_vfs_close(pmp->pm_cp); 964 g_topology_unlock(); 965 BO_LOCK(&pmp->pm_odevvp->v_bufobj); 966 pmp->pm_odevvp->v_bufobj.bo_flag &= ~BO_NOBUFS; 967 BO_UNLOCK(&pmp->pm_odevvp->v_bufobj); 968 atomic_store_rel_ptr((uintptr_t *)&pmp->pm_dev->si_mountpt, 0); 969 mntfs_freevp(pmp->pm_devvp); 970 vrele(pmp->pm_odevvp); 971 dev_rel(pmp->pm_dev); 972 free(pmp->pm_inusemap, M_MSDOSFSFAT); 973 lockdestroy(&pmp->pm_fatlock); 974 lockdestroy(&pmp->pm_checkpath_lock); 975 free(pmp, M_MSDOSFSMNT); 976 mp->mnt_data = NULL; 977 return (error); 978 } 979 980 static void 981 msdosfs_remount_ro(void *arg, int pending) 982 { 983 struct msdosfsmount *pmp; 984 int error; 985 986 pmp = arg; 987 988 MSDOSFS_LOCK_MP(pmp); 989 if ((pmp->pm_flags & MSDOSFS_ERR_RO) != 0) { 990 while ((pmp->pm_flags & MSDOSFS_ERR_RO) != 0) 991 msleep(&pmp->pm_flags, &pmp->pm_fatlock, PVFS, 992 "msdoserrro", hz); 993 } else if ((pmp->pm_mountp->mnt_flag & MNT_RDONLY) == 0) { 994 pmp->pm_flags |= MSDOSFS_ERR_RO; 995 MSDOSFS_UNLOCK_MP(pmp); 996 printf("%s: remounting read-only due to corruption\n", 997 pmp->pm_mountp->mnt_stat.f_mntfromname); 998 error = vfs_remount_ro(pmp->pm_mountp); 999 if (error != 0) 1000 printf("%s: remounting read-only failed: error %d\n", 1001 pmp->pm_mountp->mnt_stat.f_mntfromname, error); 1002 else 1003 printf("remounted %s read-only\n", 1004 pmp->pm_mountp->mnt_stat.f_mntfromname); 1005 MSDOSFS_LOCK_MP(pmp); 1006 pmp->pm_flags &= ~MSDOSFS_ERR_RO; 1007 wakeup(&pmp->pm_flags); 1008 } 1009 MSDOSFS_UNLOCK_MP(pmp); 1010 1011 while (--pending >= 0) 1012 vfs_unbusy(pmp->pm_mountp); 1013 } 1014 1015 void 1016 msdosfs_integrity_error(struct msdosfsmount *pmp) 1017 { 1018 int error; 1019 1020 error = vfs_busy(pmp->pm_mountp, MBF_NOWAIT); 1021 if (error == 0) { 1022 error = taskqueue_enqueue(taskqueue_thread, 1023 &pmp->pm_rw2ro_task); 1024 if (error != 0) { 1025 printf("%s: integrity error scheduling failed, " 1026 "error %d\n", 1027 pmp->pm_mountp->mnt_stat.f_mntfromname, error); 1028 vfs_unbusy(pmp->pm_mountp); 1029 } 1030 } else { 1031 printf("%s: integrity error busying failed, error %d\n", 1032 pmp->pm_mountp->mnt_stat.f_mntfromname, error); 1033 } 1034 } 1035 1036 static int 1037 msdosfs_root(struct mount *mp, int flags, struct vnode **vpp) 1038 { 1039 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 1040 struct denode *ndep; 1041 int error; 1042 1043 #ifdef MSDOSFS_DEBUG 1044 printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp); 1045 #endif 1046 error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, LK_EXCLUSIVE, &ndep); 1047 if (error) 1048 return (error); 1049 *vpp = DETOV(ndep); 1050 return (0); 1051 } 1052 1053 static int 1054 msdosfs_statfs(struct mount *mp, struct statfs *sbp) 1055 { 1056 struct msdosfsmount *pmp; 1057 1058 pmp = VFSTOMSDOSFS(mp); 1059 sbp->f_bsize = pmp->pm_bpcluster; 1060 sbp->f_iosize = pmp->pm_bpcluster; 1061 sbp->f_blocks = pmp->pm_maxcluster - CLUST_FIRST + 1; 1062 sbp->f_bfree = pmp->pm_freeclustercount; 1063 sbp->f_bavail = pmp->pm_freeclustercount; 1064 sbp->f_files = howmany(pmp->pm_rootdirsize * DEV_BSIZE, 1065 sizeof(struct direntry)); 1066 sbp->f_ffree = pmp->pm_rootdirfree; 1067 return (0); 1068 } 1069 1070 /* 1071 * If we have an FSInfo block, update it. 1072 */ 1073 static int 1074 msdosfs_fsiflush(struct msdosfsmount *pmp, int waitfor) 1075 { 1076 struct fsinfo *fp; 1077 struct buf *bp; 1078 int error; 1079 1080 MSDOSFS_LOCK_MP(pmp); 1081 if (pmp->pm_fsinfo == 0 || (pmp->pm_flags & MSDOSFS_FSIMOD) == 0) { 1082 error = 0; 1083 goto unlock; 1084 } 1085 error = bread(pmp->pm_devvp, pmp->pm_fsinfo, pmp->pm_BytesPerSec, 1086 NOCRED, &bp); 1087 if (error != 0) { 1088 goto unlock; 1089 } 1090 fp = (struct fsinfo *)bp->b_data; 1091 putulong(fp->fsinfree, pmp->pm_freeclustercount); 1092 putulong(fp->fsinxtfree, pmp->pm_nxtfree); 1093 pmp->pm_flags &= ~MSDOSFS_FSIMOD; 1094 if (waitfor == MNT_WAIT) 1095 error = bwrite(bp); 1096 else 1097 bawrite(bp); 1098 unlock: 1099 MSDOSFS_UNLOCK_MP(pmp); 1100 return (error); 1101 } 1102 1103 static int 1104 msdosfs_sync(struct mount *mp, int waitfor) 1105 { 1106 struct vnode *vp, *nvp; 1107 struct thread *td; 1108 struct denode *dep; 1109 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 1110 int error, allerror = 0; 1111 1112 td = curthread; 1113 1114 /* 1115 * If we ever switch to not updating all of the FATs all the time, 1116 * this would be the place to update them from the first one. 1117 */ 1118 if (pmp->pm_fmod != 0) { 1119 if (pmp->pm_flags & MSDOSFSMNT_RONLY) 1120 panic("msdosfs_sync: rofs mod"); 1121 else { 1122 /* update FATs here */ 1123 } 1124 } 1125 /* 1126 * Write back each (modified) denode. 1127 */ 1128 loop: 1129 MNT_VNODE_FOREACH_ALL(vp, mp, nvp) { 1130 if (vp->v_type == VNON) { 1131 VI_UNLOCK(vp); 1132 continue; 1133 } 1134 dep = VTODE(vp); 1135 if ((dep->de_flag & 1136 (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0 && 1137 (vp->v_bufobj.bo_dirty.bv_cnt == 0 || 1138 waitfor == MNT_LAZY)) { 1139 VI_UNLOCK(vp); 1140 continue; 1141 } 1142 error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK); 1143 if (error) { 1144 if (error == ENOENT) { 1145 MNT_VNODE_FOREACH_ALL_ABORT(mp, nvp); 1146 goto loop; 1147 } 1148 continue; 1149 } 1150 error = VOP_FSYNC(vp, waitfor, td); 1151 if (error) 1152 allerror = error; 1153 vput(vp); 1154 } 1155 1156 /* 1157 * Flush filesystem control info. 1158 */ 1159 if (waitfor != MNT_LAZY) { 1160 vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY); 1161 error = VOP_FSYNC(pmp->pm_devvp, waitfor, td); 1162 if (error) 1163 allerror = error; 1164 VOP_UNLOCK(pmp->pm_devvp); 1165 } 1166 1167 error = msdosfs_fsiflush(pmp, waitfor); 1168 if (error != 0) 1169 allerror = error; 1170 1171 if (allerror == 0 && waitfor == MNT_SUSPEND) { 1172 MNT_ILOCK(mp); 1173 mp->mnt_kern_flag |= MNTK_SUSPEND2 | MNTK_SUSPENDED; 1174 MNT_IUNLOCK(mp); 1175 } 1176 return (allerror); 1177 } 1178 1179 static int 1180 msdosfs_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp) 1181 { 1182 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 1183 struct defid *defhp = (struct defid *) fhp; 1184 struct denode *dep; 1185 int error; 1186 1187 error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, 1188 LK_EXCLUSIVE, &dep); 1189 if (error) { 1190 *vpp = NULLVP; 1191 return (error); 1192 } 1193 *vpp = DETOV(dep); 1194 vnode_create_vobject(*vpp, dep->de_FileSize, curthread); 1195 return (0); 1196 } 1197 1198 static struct vfsops msdosfs_vfsops = { 1199 .vfs_fhtovp = msdosfs_fhtovp, 1200 .vfs_mount = msdosfs_mount, 1201 .vfs_cmount = msdosfs_cmount, 1202 .vfs_root = msdosfs_root, 1203 .vfs_statfs = msdosfs_statfs, 1204 .vfs_sync = msdosfs_sync, 1205 .vfs_unmount = msdosfs_unmount, 1206 }; 1207 1208 VFS_SET(msdosfs_vfsops, msdosfs, 0); 1209 MODULE_VERSION(msdosfs, 1); 1210