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 (pmp->pm_maxcluster >= clusters) { 727 #ifdef MSDOSFS_DEBUG 728 printf("Warning: number of clusters (%ld) exceeds FAT " 729 "capacity (%ld)\n", pmp->pm_maxcluster - 1, clusters); 730 #endif 731 pmp->pm_maxcluster = clusters - 1; 732 } 733 734 if (FAT12(pmp)) 735 pmp->pm_fatblocksize = 3 * 512; 736 else 737 pmp->pm_fatblocksize = PAGE_SIZE; 738 pmp->pm_fatblocksize = roundup(pmp->pm_fatblocksize, 739 pmp->pm_BytesPerSec); 740 pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE; 741 pmp->pm_bnshift = ffs(DEV_BSIZE) - 1; 742 743 /* 744 * Compute mask and shift value for isolating cluster relative byte 745 * offsets and cluster numbers from a file offset. 746 */ 747 pmp->pm_bpcluster = SecPerClust * DEV_BSIZE; 748 pmp->pm_crbomask = pmp->pm_bpcluster - 1; 749 pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1; 750 751 /* 752 * Check for valid cluster size 753 * must be a power of 2 754 */ 755 if ((pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) != 0) { 756 error = EINVAL; 757 goto error_exit; 758 } 759 760 /* 761 * Release the bootsector buffer. 762 */ 763 brelse(bp); 764 bp = NULL; 765 766 /* 767 * Check the fsinfo sector if we have one. Silently fix up our 768 * in-core copy of fp->fsinxtfree if it is unknown (0xffffffff) 769 * or too large. Ignore fp->fsinfree for now, since we need to 770 * read the entire FAT anyway to fill the inuse map. 771 */ 772 if (pmp->pm_fsinfo) { 773 struct fsinfo *fp; 774 775 if ((error = bread(devvp, pmp->pm_fsinfo, pmp->pm_BytesPerSec, 776 NOCRED, &bp)) != 0) 777 goto error_exit; 778 fp = (struct fsinfo *)bp->b_data; 779 if (!bcmp(fp->fsisig1, "RRaA", 4) && 780 !bcmp(fp->fsisig2, "rrAa", 4) && 781 !bcmp(fp->fsisig3, "\0\0\125\252", 4)) { 782 pmp->pm_nxtfree = getulong(fp->fsinxtfree); 783 if (pmp->pm_nxtfree > pmp->pm_maxcluster) 784 pmp->pm_nxtfree = CLUST_FIRST; 785 } else 786 pmp->pm_fsinfo = 0; 787 brelse(bp); 788 bp = NULL; 789 } 790 791 /* 792 * Finish initializing pmp->pm_nxtfree (just in case the first few 793 * sectors aren't properly reserved in the FAT). This completes 794 * the fixup for fp->fsinxtfree, and fixes up the zero-initialized 795 * value if there is no fsinfo. We will use pmp->pm_nxtfree 796 * internally even if there is no fsinfo. 797 */ 798 if (pmp->pm_nxtfree < CLUST_FIRST) 799 pmp->pm_nxtfree = CLUST_FIRST; 800 801 /* 802 * Allocate memory for the bitmap of allocated clusters, and then 803 * fill it in. 804 */ 805 pmp->pm_inusemap = malloc(howmany(pmp->pm_maxcluster + 1, 806 N_INUSEBITS) * sizeof(*pmp->pm_inusemap), M_MSDOSFSFAT, M_WAITOK); 807 808 /* 809 * fillinusemap() needs pm_devvp. 810 */ 811 pmp->pm_devvp = devvp; 812 pmp->pm_odevvp = odevvp; 813 pmp->pm_dev = dev; 814 815 /* 816 * Have the inuse map filled in. 817 */ 818 MSDOSFS_LOCK_MP(pmp); 819 error = fillinusemap(pmp); 820 MSDOSFS_UNLOCK_MP(pmp); 821 if (error != 0) 822 goto error_exit; 823 824 /* 825 * If they want FAT updates to be synchronous then let them suffer 826 * the performance degradation in exchange for the on disk copy of 827 * the FAT being correct just about all the time. I suppose this 828 * would be a good thing to turn on if the kernel is still flakey. 829 */ 830 if (mp->mnt_flag & MNT_SYNCHRONOUS) 831 pmp->pm_flags |= MSDOSFSMNT_WAITONFAT; 832 833 /* 834 * Finish up. 835 */ 836 if (ronly) 837 pmp->pm_flags |= MSDOSFSMNT_RONLY; 838 else { 839 if ((error = markvoldirty(pmp, 1)) != 0) 840 goto error_exit; 841 pmp->pm_fmod = 1; 842 } 843 844 if (FAT32(pmp)) { 845 pmp->pm_rootdirfree = 0; 846 } else { 847 pmp->pm_rootdirfree = rootdir_free(pmp); 848 if (pmp->pm_rootdirfree < 0) 849 goto error_exit; 850 } 851 852 mp->mnt_data = pmp; 853 mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); 854 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 855 MNT_ILOCK(mp); 856 mp->mnt_flag |= MNT_LOCAL; 857 mp->mnt_kern_flag |= MNTK_USES_BCACHE | MNTK_NO_IOPF; 858 MNT_IUNLOCK(mp); 859 860 return (0); 861 862 error_exit: 863 if (bp != NULL) 864 brelse(bp); 865 if (cp != NULL) { 866 g_topology_lock(); 867 g_vfs_close(cp); 868 g_topology_unlock(); 869 } 870 if (pmp != NULL) { 871 lockdestroy(&pmp->pm_fatlock); 872 lockdestroy(&pmp->pm_checkpath_lock); 873 free(pmp->pm_inusemap, M_MSDOSFSFAT); 874 free(pmp, M_MSDOSFSMNT); 875 mp->mnt_data = NULL; 876 } 877 BO_LOCK(&odevvp->v_bufobj); 878 odevvp->v_bufobj.bo_flag &= ~BO_NOBUFS; 879 BO_UNLOCK(&odevvp->v_bufobj); 880 atomic_store_rel_ptr((uintptr_t *)&dev->si_mountpt, 0); 881 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 882 mntfs_freevp(devvp); 883 dev_rel(dev); 884 return (error); 885 } 886 887 /* 888 * Unmount the filesystem described by mp. 889 */ 890 static int 891 msdosfs_unmount(struct mount *mp, int mntflags) 892 { 893 struct msdosfsmount *pmp; 894 int error, flags; 895 bool susp; 896 897 error = flags = 0; 898 pmp = VFSTOMSDOSFS(mp); 899 susp = (pmp->pm_flags & MSDOSFSMNT_RONLY) == 0; 900 901 if (susp) { 902 error = vfs_write_suspend_umnt(mp); 903 if (error != 0) 904 return (error); 905 } 906 907 if ((mntflags & MNT_FORCE) != 0) 908 flags |= FORCECLOSE; 909 error = vflush(mp, 0, flags, curthread); 910 if (error != 0 && error != ENXIO) { 911 if (susp) 912 vfs_write_resume(mp, VR_START_WRITE); 913 return (error); 914 } 915 if (susp) { 916 error = markvoldirty(pmp, 0); 917 if (error != 0 && error != ENXIO) { 918 if (susp) 919 vfs_write_resume(mp, VR_START_WRITE); 920 (void)markvoldirty(pmp, 1); 921 return (error); 922 } 923 } 924 if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) { 925 if (pmp->pm_w2u) 926 msdosfs_iconv->close(pmp->pm_w2u); 927 if (pmp->pm_u2w) 928 msdosfs_iconv->close(pmp->pm_u2w); 929 if (pmp->pm_d2u) 930 msdosfs_iconv->close(pmp->pm_d2u); 931 if (pmp->pm_u2d) 932 msdosfs_iconv->close(pmp->pm_u2d); 933 } 934 935 #ifdef MSDOSFS_DEBUG 936 { 937 struct vnode *vp = pmp->pm_devvp; 938 struct bufobj *bo; 939 940 bo = &vp->v_bufobj; 941 BO_LOCK(bo); 942 VI_LOCK(vp); 943 vn_printf(vp, 944 "msdosfs_umount(): just before calling VOP_CLOSE()\n"); 945 printf("freef %p, freeb %p, mount %p\n", 946 TAILQ_NEXT(vp, v_vnodelist), vp->v_vnodelist.tqe_prev, 947 vp->v_mount); 948 printf("cleanblkhd %p, dirtyblkhd %p, numoutput %d, type %d\n", 949 TAILQ_FIRST(&vp->v_bufobj.bo_clean.bv_hd), 950 TAILQ_FIRST(&vp->v_bufobj.bo_dirty.bv_hd), 951 vp->v_bufobj.bo_numoutput, vp->v_type); 952 VI_UNLOCK(vp); 953 BO_UNLOCK(bo); 954 } 955 #endif 956 if (susp) 957 vfs_write_resume(mp, VR_START_WRITE); 958 959 vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY); 960 g_topology_lock(); 961 g_vfs_close(pmp->pm_cp); 962 g_topology_unlock(); 963 BO_LOCK(&pmp->pm_odevvp->v_bufobj); 964 pmp->pm_odevvp->v_bufobj.bo_flag &= ~BO_NOBUFS; 965 BO_UNLOCK(&pmp->pm_odevvp->v_bufobj); 966 atomic_store_rel_ptr((uintptr_t *)&pmp->pm_dev->si_mountpt, 0); 967 mntfs_freevp(pmp->pm_devvp); 968 vrele(pmp->pm_odevvp); 969 dev_rel(pmp->pm_dev); 970 free(pmp->pm_inusemap, M_MSDOSFSFAT); 971 lockdestroy(&pmp->pm_fatlock); 972 lockdestroy(&pmp->pm_checkpath_lock); 973 free(pmp, M_MSDOSFSMNT); 974 mp->mnt_data = NULL; 975 return (error); 976 } 977 978 static void 979 msdosfs_remount_ro(void *arg, int pending) 980 { 981 struct msdosfsmount *pmp; 982 int error; 983 984 pmp = arg; 985 986 MSDOSFS_LOCK_MP(pmp); 987 if ((pmp->pm_flags & MSDOSFS_ERR_RO) != 0) { 988 while ((pmp->pm_flags & MSDOSFS_ERR_RO) != 0) 989 msleep(&pmp->pm_flags, &pmp->pm_fatlock, PVFS, 990 "msdoserrro", hz); 991 } else if ((pmp->pm_mountp->mnt_flag & MNT_RDONLY) == 0) { 992 pmp->pm_flags |= MSDOSFS_ERR_RO; 993 MSDOSFS_UNLOCK_MP(pmp); 994 printf("%s: remounting read-only due to corruption\n", 995 pmp->pm_mountp->mnt_stat.f_mntfromname); 996 error = vfs_remount_ro(pmp->pm_mountp); 997 if (error != 0) 998 printf("%s: remounting read-only failed: error %d\n", 999 pmp->pm_mountp->mnt_stat.f_mntfromname, error); 1000 else 1001 printf("remounted %s read-only\n", 1002 pmp->pm_mountp->mnt_stat.f_mntfromname); 1003 MSDOSFS_LOCK_MP(pmp); 1004 pmp->pm_flags &= ~MSDOSFS_ERR_RO; 1005 wakeup(&pmp->pm_flags); 1006 } 1007 MSDOSFS_UNLOCK_MP(pmp); 1008 1009 vfs_unbusy(pmp->pm_mountp); 1010 } 1011 1012 void 1013 msdosfs_integrity_error(struct msdosfsmount *pmp) 1014 { 1015 int error; 1016 1017 error = vfs_busy(pmp->pm_mountp, MBF_NOWAIT); 1018 if (error == 0) 1019 taskqueue_enqueue(taskqueue_thread, &pmp->pm_rw2ro_task); 1020 else 1021 printf("%s: integrity error busying failed, error %d\n", 1022 pmp->pm_mountp->mnt_stat.f_mntfromname, error); 1023 } 1024 1025 static int 1026 msdosfs_root(struct mount *mp, int flags, struct vnode **vpp) 1027 { 1028 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 1029 struct denode *ndep; 1030 int error; 1031 1032 #ifdef MSDOSFS_DEBUG 1033 printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp); 1034 #endif 1035 error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, LK_EXCLUSIVE, &ndep); 1036 if (error) 1037 return (error); 1038 *vpp = DETOV(ndep); 1039 return (0); 1040 } 1041 1042 static int 1043 msdosfs_statfs(struct mount *mp, struct statfs *sbp) 1044 { 1045 struct msdosfsmount *pmp; 1046 1047 pmp = VFSTOMSDOSFS(mp); 1048 sbp->f_bsize = pmp->pm_bpcluster; 1049 sbp->f_iosize = pmp->pm_bpcluster; 1050 sbp->f_blocks = pmp->pm_maxcluster - CLUST_FIRST + 1; 1051 sbp->f_bfree = pmp->pm_freeclustercount; 1052 sbp->f_bavail = pmp->pm_freeclustercount; 1053 sbp->f_files = howmany(pmp->pm_rootdirsize * DEV_BSIZE, 1054 sizeof(struct direntry)); 1055 sbp->f_ffree = pmp->pm_rootdirfree; 1056 return (0); 1057 } 1058 1059 /* 1060 * If we have an FSInfo block, update it. 1061 */ 1062 static int 1063 msdosfs_fsiflush(struct msdosfsmount *pmp, int waitfor) 1064 { 1065 struct fsinfo *fp; 1066 struct buf *bp; 1067 int error; 1068 1069 MSDOSFS_LOCK_MP(pmp); 1070 if (pmp->pm_fsinfo == 0 || (pmp->pm_flags & MSDOSFS_FSIMOD) == 0) { 1071 error = 0; 1072 goto unlock; 1073 } 1074 error = bread(pmp->pm_devvp, pmp->pm_fsinfo, pmp->pm_BytesPerSec, 1075 NOCRED, &bp); 1076 if (error != 0) { 1077 goto unlock; 1078 } 1079 fp = (struct fsinfo *)bp->b_data; 1080 putulong(fp->fsinfree, pmp->pm_freeclustercount); 1081 putulong(fp->fsinxtfree, pmp->pm_nxtfree); 1082 pmp->pm_flags &= ~MSDOSFS_FSIMOD; 1083 if (waitfor == MNT_WAIT) 1084 error = bwrite(bp); 1085 else 1086 bawrite(bp); 1087 unlock: 1088 MSDOSFS_UNLOCK_MP(pmp); 1089 return (error); 1090 } 1091 1092 static int 1093 msdosfs_sync(struct mount *mp, int waitfor) 1094 { 1095 struct vnode *vp, *nvp; 1096 struct thread *td; 1097 struct denode *dep; 1098 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 1099 int error, allerror = 0; 1100 1101 td = curthread; 1102 1103 /* 1104 * If we ever switch to not updating all of the FATs all the time, 1105 * this would be the place to update them from the first one. 1106 */ 1107 if (pmp->pm_fmod != 0) { 1108 if (pmp->pm_flags & MSDOSFSMNT_RONLY) 1109 panic("msdosfs_sync: rofs mod"); 1110 else { 1111 /* update FATs here */ 1112 } 1113 } 1114 /* 1115 * Write back each (modified) denode. 1116 */ 1117 loop: 1118 MNT_VNODE_FOREACH_ALL(vp, mp, nvp) { 1119 if (vp->v_type == VNON) { 1120 VI_UNLOCK(vp); 1121 continue; 1122 } 1123 dep = VTODE(vp); 1124 if ((dep->de_flag & 1125 (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0 && 1126 (vp->v_bufobj.bo_dirty.bv_cnt == 0 || 1127 waitfor == MNT_LAZY)) { 1128 VI_UNLOCK(vp); 1129 continue; 1130 } 1131 error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK); 1132 if (error) { 1133 if (error == ENOENT) { 1134 MNT_VNODE_FOREACH_ALL_ABORT(mp, nvp); 1135 goto loop; 1136 } 1137 continue; 1138 } 1139 error = VOP_FSYNC(vp, waitfor, td); 1140 if (error) 1141 allerror = error; 1142 vput(vp); 1143 } 1144 1145 /* 1146 * Flush filesystem control info. 1147 */ 1148 if (waitfor != MNT_LAZY) { 1149 vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY); 1150 error = VOP_FSYNC(pmp->pm_devvp, waitfor, td); 1151 if (error) 1152 allerror = error; 1153 VOP_UNLOCK(pmp->pm_devvp); 1154 } 1155 1156 error = msdosfs_fsiflush(pmp, waitfor); 1157 if (error != 0) 1158 allerror = error; 1159 1160 if (allerror == 0 && waitfor == MNT_SUSPEND) { 1161 MNT_ILOCK(mp); 1162 mp->mnt_kern_flag |= MNTK_SUSPEND2 | MNTK_SUSPENDED; 1163 MNT_IUNLOCK(mp); 1164 } 1165 return (allerror); 1166 } 1167 1168 static int 1169 msdosfs_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp) 1170 { 1171 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 1172 struct defid *defhp = (struct defid *) fhp; 1173 struct denode *dep; 1174 int error; 1175 1176 error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, 1177 LK_EXCLUSIVE, &dep); 1178 if (error) { 1179 *vpp = NULLVP; 1180 return (error); 1181 } 1182 *vpp = DETOV(dep); 1183 vnode_create_vobject(*vpp, dep->de_FileSize, curthread); 1184 return (0); 1185 } 1186 1187 static struct vfsops msdosfs_vfsops = { 1188 .vfs_fhtovp = msdosfs_fhtovp, 1189 .vfs_mount = msdosfs_mount, 1190 .vfs_cmount = msdosfs_cmount, 1191 .vfs_root = msdosfs_root, 1192 .vfs_statfs = msdosfs_statfs, 1193 .vfs_sync = msdosfs_sync, 1194 .vfs_unmount = msdosfs_unmount, 1195 }; 1196 1197 VFS_SET(msdosfs_vfsops, msdosfs, 0); 1198 MODULE_VERSION(msdosfs, 1); 1199