1 /* $FreeBSD$ */ 2 /* $NetBSD: msdosfs_vfsops.c,v 1.51 1997/11/17 15:36:58 ws Exp $ */ 3 4 /*- 5 * SPDX-License-Identifier: BSD-4-Clause 6 * 7 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. 8 * Copyright (C) 1994, 1995, 1997 TooLs GmbH. 9 * All rights reserved. 10 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by TooLs GmbH. 23 * 4. The name of TooLs GmbH may not be used to endorse or promote products 24 * derived from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 29 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 31 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 32 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 33 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 */ 37 /*- 38 * Written by Paul Popelka (paulp@uts.amdahl.com) 39 * 40 * You can do anything you want with this software, just don't say you wrote 41 * it, and don't remove this notice. 42 * 43 * This software is provided "as is". 44 * 45 * The author supplies this software to be publicly redistributed on the 46 * understanding that the author is not responsible for the correct 47 * functioning of this software in any circumstances and is not liable for 48 * any damages caused by this software. 49 * 50 * October 1992 51 */ 52 53 #include <sys/param.h> 54 #include <sys/systm.h> 55 #include <sys/conf.h> 56 #include <sys/proc.h> 57 #include <sys/nlookup.h> 58 #include <sys/kernel.h> 59 #include <sys/vnode.h> 60 #include <sys/iconv.h> 61 #include <sys/mount.h> 62 #include <sys/buf.h> 63 #include <sys/fcntl.h> 64 #include <sys/malloc.h> 65 #include <sys/stat.h> /* defines ALLPERMS */ 66 #include <vm/vm_zone.h> 67 68 #include <sys/buf2.h> 69 70 #include "bpb.h" 71 #include "bootsect.h" 72 #include "direntry.h" 73 #include "denode.h" 74 #include "msdosfsmount.h" 75 #include "fat.h" 76 77 extern struct vop_ops msdosfs_vnode_vops; 78 struct iconv_functions *msdos_iconv; 79 80 #define MSDOSFS_DFLTBSIZE 4096 81 #define ENCODING_UNICODE "UTF-16BE" 82 #if 1 /*def PC98*/ 83 /* 84 * XXX - The boot signature formatted by NEC PC-98 DOS looks like a 85 * garbage or a random value :-{ 86 * If you want to use that broken-signatured media, define the 87 * following symbol even though PC/AT. 88 * (ex. mount PC-98 DOS formatted FD on PC/AT) 89 */ 90 #define MSDOSFS_NOCHECKSIG 91 #endif 92 93 MALLOC_DEFINE(M_MSDOSFSMNT, "MSDOSFS mount", "MSDOSFS mount structure"); 94 static MALLOC_DEFINE(M_MSDOSFSFAT, "MSDOSFS FAT", "MSDOSFS file allocation table"); 95 96 static int mountmsdosfs(struct vnode *devvp, struct mount *mp, 97 struct msdosfs_args *argp); 98 static int msdosfs_root(struct mount *, struct vnode **); 99 static int msdosfs_statfs(struct mount *, struct statfs *, struct ucred *); 100 static int msdosfs_unmount(struct mount *, int); 101 102 static int 103 update_mp(struct mount *mp, struct msdosfs_args *argp) 104 { 105 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 106 int error; 107 char cs_local[ICONV_CSNMAXLEN]; 108 char cs_dos[ICONV_CSNMAXLEN]; 109 110 pmp->pm_gid = argp->gid; 111 pmp->pm_uid = argp->uid; 112 pmp->pm_mask = argp->mask & ALLPERMS; 113 pmp->pm_dirmask = argp->dirmask & ALLPERMS; 114 pmp->pm_flags |= argp->flags & MSDOSFSMNT_MNTOPT; 115 116 if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdos_iconv) { 117 bcopy(argp->cs_local, cs_local, sizeof(cs_local)); 118 bcopy(argp->cs_dos, cs_dos, sizeof(cs_dos)); 119 kprintf("local: %s dos: %s\n",argp->cs_local, argp->cs_dos); 120 error = msdos_iconv->open(cs_local, ENCODING_UNICODE, 121 &pmp->pm_w2u); 122 if(error) 123 return error; 124 error = msdos_iconv->open(ENCODING_UNICODE, cs_local, 125 &pmp->pm_u2w); 126 if(error) 127 return error; 128 error = msdos_iconv->open(cs_dos, cs_local, &pmp->pm_u2d); 129 if(error) 130 return error; 131 error = msdos_iconv->open(cs_local, cs_dos, &pmp->pm_d2u); 132 if(error) 133 return error; 134 } 135 136 if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) { 137 pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 138 } else if (!(pmp->pm_flags & 139 (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) { 140 /* 141 * Try to divine whether to support Win'95 long filenames 142 */ 143 if (FAT32(pmp)) { 144 pmp->pm_flags |= MSDOSFSMNT_LONGNAME; 145 } else { 146 struct vnode *rootvp; 147 if ((error = msdosfs_root(mp, &rootvp)) != 0) 148 return error; 149 pmp->pm_flags |= findwin95(VTODE(rootvp)) 150 ? MSDOSFSMNT_LONGNAME : MSDOSFSMNT_SHORTNAME; 151 vput(rootvp); 152 } 153 } 154 return 0; 155 } 156 157 /* 158 * mp - path - addr in user space of mount point (ie /usr or whatever) 159 * data - addr in user space of mount params including the name of the block 160 * special file to treat as a filesystem. 161 */ 162 static int 163 msdosfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred) 164 { 165 struct vnode *devvp; /* vnode for blk device to mount */ 166 struct msdosfs_args args; /* will hold data from mount request */ 167 /* msdosfs specific mount control block */ 168 struct msdosfsmount *pmp = NULL; 169 size_t size; 170 int error, flags; 171 mode_t accessmode; 172 struct nlookupdata nd; 173 174 error = copyin(data, (caddr_t)&args, sizeof(struct msdosfs_args)); 175 if (error) 176 return (error); 177 if (args.magic != MSDOSFS_ARGSMAGIC) 178 args.flags = 0; 179 /* 180 * If updating, check whether changing from read-only to 181 * read/write; if there is no device name, that's all we do. 182 */ 183 if (mp->mnt_flag & MNT_UPDATE) { 184 pmp = VFSTOMSDOSFS(mp); 185 error = 0; 186 if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && 187 (mp->mnt_flag & MNT_RDONLY)) { 188 flags = WRITECLOSE; 189 if (mp->mnt_flag & MNT_FORCE) 190 flags |= FORCECLOSE; 191 error = vflush(mp, 0, flags); 192 if (error == 0) { 193 devvp = pmp->pm_devvp; 194 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 195 VOP_OPEN(devvp, FREAD, FSCRED, NULL); 196 VOP_CLOSE(devvp, FREAD|FWRITE, NULL); 197 vn_unlock(devvp); 198 pmp->pm_flags |= MSDOSFSMNT_RONLY; 199 } 200 } 201 if (!error && (mp->mnt_flag & MNT_RELOAD)) 202 error = EOPNOTSUPP; /* not yet implemented */ 203 if (error) 204 return (error); 205 if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && 206 (mp->mnt_kern_flag & MNTK_WANTRDWR)) { 207 /* 208 * If upgrade to read-write by non-root, then verify 209 * that user has necessary permissions on the device. 210 */ 211 devvp = pmp->pm_devvp; 212 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 213 if (cred->cr_uid != 0) { 214 error = VOP_EACCESS(devvp, VREAD | VWRITE, 215 cred); 216 if (error) { 217 vn_unlock(devvp); 218 return (error); 219 } 220 } 221 VOP_OPEN(devvp, FREAD|FWRITE, FSCRED, NULL); 222 VOP_CLOSE(devvp, FREAD, NULL); 223 vn_unlock(devvp); 224 pmp->pm_flags &= ~MSDOSFSMNT_RONLY; 225 } 226 if (args.fspec == NULL) { 227 #ifdef __notyet__ /* doesn't work correctly with current mountd XXX */ 228 if (args.flags & MSDOSFSMNT_MNTOPT) { 229 pmp->pm_flags &= ~MSDOSFSMNT_MNTOPT; 230 pmp->pm_flags |= args.flags & MSDOSFSMNT_MNTOPT; 231 if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 232 pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 233 } 234 #endif 235 /* 236 * Process export requests. 237 */ 238 return (vfs_export(mp, &pmp->pm_export, &args.export)); 239 } 240 } 241 /* 242 * Not an update, or updating the name: look up the name 243 * and verify that it refers to a sensible disk device. 244 */ 245 devvp = NULL; 246 error = nlookup_init(&nd, args.fspec, UIO_USERSPACE, NLC_FOLLOW); 247 if (error == 0) 248 error = nlookup(&nd); 249 if (error == 0) 250 error = cache_vref(&nd.nl_nch, nd.nl_cred, &devvp); 251 nlookup_done(&nd); 252 if (error) 253 return (error); 254 255 if (!vn_isdisk(devvp, &error)) { 256 vrele(devvp); 257 return (error); 258 } 259 /* 260 * If mount by non-root, then verify that user has necessary 261 * permissions on the device. 262 */ 263 if (cred->cr_uid != 0) { 264 accessmode = VREAD; 265 if ((mp->mnt_flag & MNT_RDONLY) == 0) 266 accessmode |= VWRITE; 267 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 268 error = VOP_EACCESS(devvp, accessmode, cred); 269 if (error) { 270 vput(devvp); 271 return (error); 272 } 273 vn_unlock(devvp); 274 } 275 if ((mp->mnt_flag & MNT_UPDATE) == 0) { 276 error = mountmsdosfs(devvp, mp, &args); 277 #ifdef MSDOSFS_DEBUG /* only needed for the kprintf below */ 278 pmp = VFSTOMSDOSFS(mp); 279 #endif 280 } else { 281 if (devvp != pmp->pm_devvp) 282 error = EINVAL; /* XXX needs translation */ 283 else 284 vrele(devvp); 285 } 286 if (error) { 287 vrele(devvp); 288 return (error); 289 } 290 291 error = update_mp(mp, &args); 292 if (error) { 293 msdosfs_unmount(mp, MNT_FORCE); 294 return error; 295 } 296 297 copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); 298 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 299 msdosfs_statfs(mp, &mp->mnt_stat, cred); 300 #ifdef MSDOSFS_DEBUG 301 kprintf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", 302 mp, pmp, pmp->pm_inusemap); 303 #endif 304 return (0); 305 } 306 307 static int 308 mountmsdosfs(struct vnode *devvp, struct mount *mp, struct msdosfs_args *argp) 309 { 310 struct msdosfsmount *pmp; 311 struct buf *bp; 312 cdev_t dev; 313 union bootsector *bsp; 314 struct byte_bpb33 *b33; 315 struct byte_bpb50 *b50; 316 struct byte_bpb710 *b710; 317 uint8_t SecPerClust; 318 u_long clusters; 319 int ronly, error; 320 321 /* 322 * Disallow multiple mounts of the same device. 323 * Disallow mounting of a device that is currently in use 324 * Flush out any old buffers remaining from a previous use. 325 */ 326 error = vfs_mountedon(devvp); 327 if (error) 328 return (error); 329 if (vcount(devvp) > 0) 330 return (EBUSY); 331 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 332 error = vinvalbuf(devvp, V_SAVE, 0, 0); 333 vn_unlock(devvp); 334 if (error) 335 return (error); 336 337 ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 338 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 339 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, NULL); 340 vn_unlock(devvp); 341 if (error) 342 return (error); 343 dev = devvp->v_rdev; 344 bp = NULL; /* both used in error_exit */ 345 pmp = NULL; 346 347 /* 348 * Read the boot sector of the filesystem, and then check the 349 * boot signature. If not a dos boot sector then error out. 350 * 351 * NOTE: 2048 is a maximum sector size in current... 352 */ 353 error = bread(devvp, 0, 2048, &bp); 354 if (error) 355 goto error_exit; 356 bp->b_flags |= B_AGE; 357 bsp = (union bootsector *)bp->b_data; 358 b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB; 359 b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB; 360 b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB; 361 362 #ifndef MSDOSFS_NOCHECKSIG 363 if (bsp->bs50.bsBootSectSig0 != BOOTSIG0 364 || bsp->bs50.bsBootSectSig1 != BOOTSIG1) { 365 error = EINVAL; 366 goto error_exit; 367 } 368 #endif 369 370 pmp = kmalloc(sizeof(*pmp), M_MSDOSFSMNT, M_WAITOK | M_ZERO); 371 pmp->pm_mountp = mp; 372 373 /* 374 * Compute several useful quantities from the bpb in the 375 * bootsector. Copy in the dos 5 variant of the bpb then fix up 376 * the fields that are different between dos 5 and dos 3.3. 377 */ 378 SecPerClust = b50->bpbSecPerClust; 379 pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 380 if (pmp->pm_BytesPerSec < DEV_BSIZE) { 381 error = EINVAL; 382 goto error_exit; 383 } 384 pmp->pm_ResSectors = getushort(b50->bpbResSectors); 385 pmp->pm_FATs = b50->bpbFATs; 386 pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 387 pmp->pm_Sectors = getushort(b50->bpbSectors); 388 pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 389 pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 390 pmp->pm_Heads = getushort(b50->bpbHeads); 391 pmp->pm_Media = b50->bpbMedia; 392 393 /* calculate the ratio of sector size to DEV_BSIZE */ 394 pmp->pm_BlkPerSec = pmp->pm_BytesPerSec / DEV_BSIZE; 395 396 /* 397 * We don't check pm_Heads nor pm_SecPerTrack, because 398 * these may not be set for EFI file systems. We don't 399 * use these anyway, so we're unaffected if they are 400 * invalid. 401 */ 402 if (!pmp->pm_BytesPerSec || !SecPerClust) { 403 error = EINVAL; 404 goto error_exit; 405 } 406 407 if (pmp->pm_Sectors == 0) { 408 pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 409 pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 410 } else { 411 pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 412 pmp->pm_HugeSectors = pmp->pm_Sectors; 413 } 414 415 if (pmp->pm_RootDirEnts == 0) { 416 if (pmp->pm_Sectors 417 || pmp->pm_FATsecs 418 || getushort(b710->bpbFSVers)) { 419 error = EINVAL; 420 kprintf("mountmsdosfs(): bad FAT32 filesystem\n"); 421 goto error_exit; 422 } 423 pmp->pm_fatmask = FAT32_MASK; 424 pmp->pm_fatmult = 4; 425 pmp->pm_fatdiv = 1; 426 pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs); 427 if (getushort(b710->bpbExtFlags) & FATMIRROR) 428 pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM; 429 else 430 pmp->pm_flags |= MSDOSFS_FATMIRROR; 431 } else 432 pmp->pm_flags |= MSDOSFS_FATMIRROR; 433 434 /* 435 * Check a few values (could do some more): 436 * - logical sector size: power of 2, >= block size 437 * - sectors per cluster: power of 2, >= 1 438 * - number of sectors: >= 1, <= size of partition 439 * - number of FAT sectors: >= 1 440 */ 441 if ( (SecPerClust == 0) 442 || (SecPerClust & (SecPerClust - 1)) 443 || (pmp->pm_BytesPerSec < DEV_BSIZE) 444 || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) 445 || (pmp->pm_HugeSectors == 0) 446 || (pmp->pm_FATsecs == 0) 447 || (SecPerClust * pmp->pm_BlkPerSec > MAXBSIZE / DEV_BSIZE)) { 448 error = EINVAL; 449 goto error_exit; 450 } 451 452 pmp->pm_HugeSectors *= pmp->pm_BlkPerSec; 453 pmp->pm_HiddenSects *= pmp->pm_BlkPerSec; /* XXX not used? */ 454 pmp->pm_FATsecs *= pmp->pm_BlkPerSec; 455 SecPerClust *= pmp->pm_BlkPerSec; 456 457 pmp->pm_fatblk = pmp->pm_ResSectors * pmp->pm_BlkPerSec; 458 459 if (FAT32(pmp)) { 460 pmp->pm_rootdirblk = getulong(b710->bpbRootClust); 461 pmp->pm_firstcluster = pmp->pm_fatblk 462 + (pmp->pm_FATs * pmp->pm_FATsecs); 463 pmp->pm_fsinfo = getushort(b710->bpbFSInfo) * pmp->pm_BlkPerSec; 464 } else { 465 pmp->pm_rootdirblk = pmp->pm_fatblk + 466 (pmp->pm_FATs * pmp->pm_FATsecs); 467 pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * 468 sizeof(struct direntry) + DEV_BSIZE - 1) 469 / DEV_BSIZE; /* in blocks */ 470 pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 471 } 472 473 pmp->pm_maxcluster = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 474 SecPerClust + 1; 475 476 if (pmp->pm_fatmask == 0) { 477 if (pmp->pm_maxcluster 478 <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) { 479 /* 480 * This will usually be a floppy disk. This size makes 481 * sure that one FAT entry will not be split across 482 * multiple blocks. 483 */ 484 pmp->pm_fatmask = FAT12_MASK; 485 pmp->pm_fatmult = 3; 486 pmp->pm_fatdiv = 2; 487 } else { 488 pmp->pm_fatmask = FAT16_MASK; 489 pmp->pm_fatmult = 2; 490 pmp->pm_fatdiv = 1; 491 } 492 } 493 494 clusters = ((pmp->pm_FATsecs * DEV_BSIZE) / pmp->pm_fatmult) * 495 pmp->pm_fatdiv; 496 if (pmp->pm_maxcluster >= clusters) { 497 kprintf("Warning: number of clusters (%ld) exceeds FAT " 498 "capacity (%ld)\n", pmp->pm_maxcluster + 1, clusters); 499 pmp->pm_maxcluster = clusters - 1; 500 } 501 502 if (FAT12(pmp)) 503 pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; 504 else 505 pmp->pm_fatblocksize = MSDOSFS_DFLTBSIZE; 506 507 pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE; 508 pmp->pm_bnshift = DEV_BSHIFT; 509 510 /* 511 * Compute mask and shift value for isolating cluster relative byte 512 * offsets and cluster numbers from a file offset. 513 */ 514 pmp->pm_bpcluster = SecPerClust * DEV_BSIZE; 515 pmp->pm_crbomask = pmp->pm_bpcluster - 1; 516 pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1; 517 518 /* 519 * Check for valid cluster size 520 * must be a power of 2 521 */ 522 if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) { 523 error = EINVAL; 524 goto error_exit; 525 } 526 527 /* 528 * Release the bootsector buffer. 529 */ 530 bp->b_flags |= B_RELBUF; 531 brelse(bp); 532 bp = NULL; 533 534 /* 535 * Check FSInfo. 536 */ 537 if (pmp->pm_fsinfo) { 538 struct fsinfo *fp; 539 540 if ((error = bread(devvp, de_bntodoff(pmp, pmp->pm_fsinfo), 541 fsi_size(pmp), &bp)) != 0) 542 goto error_exit; 543 fp = (struct fsinfo *)bp->b_data; 544 if (!bcmp(fp->fsisig1, "RRaA", 4) && 545 !bcmp(fp->fsisig2, "rrAa", 4) && 546 !bcmp(fp->fsisig3, "\0\0\125\252", 4) && 547 !bcmp(fp->fsisig4, "\0\0\125\252", 4)) { 548 pmp->pm_nxtfree = getulong(fp->fsinxtfree); 549 if (pmp->pm_nxtfree == (u_long)-1) 550 pmp->pm_nxtfree = CLUST_FIRST; 551 if (pmp->pm_nxtfree == (u_int)-1) { 552 kprintf("msdosfs_mount(): " 553 "ignoring illegal nxtfree 0x%016jx\n", 554 (uintmax_t)pmp->pm_nxtfree); 555 pmp->pm_nxtfree = CLUST_FIRST; 556 } 557 } else 558 pmp->pm_fsinfo = 0; 559 bp->b_flags |= B_RELBUF; 560 brelse(bp); 561 bp = NULL; 562 } 563 564 /* 565 * Check and validate (or perhaps invalidate?) the fsinfo structure? 566 */ 567 if (pmp->pm_fsinfo && pmp->pm_nxtfree > pmp->pm_maxcluster) { 568 kprintf("Next free cluster in FSInfo (%lu) exceeds " 569 "maxcluster (%lu)\n", 570 pmp->pm_nxtfree, pmp->pm_maxcluster); 571 error = EINVAL; 572 goto error_exit; 573 } 574 575 /* 576 * Allocate memory for the bitmap of allocated clusters, and then 577 * fill it in. 578 */ 579 pmp->pm_inusemap = kmalloc(((pmp->pm_maxcluster + N_INUSEBITS - 1) 580 / N_INUSEBITS) * sizeof(*pmp->pm_inusemap), 581 M_MSDOSFSFAT, M_WAITOK); 582 583 /* 584 * fillinusemap() needs pm_devvp. 585 */ 586 pmp->pm_devvp = devvp; 587 pmp->pm_dev = dev; 588 589 /* 590 * Have the inuse map filled in. 591 */ 592 if ((error = fillinusemap(pmp)) != 0) 593 goto error_exit; 594 595 /* 596 * If they want FAT updates to be synchronous then let them suffer 597 * the performance degradation in exchange for the on disk copy of 598 * the FAT being correct just about all the time. I suppose this 599 * would be a good thing to turn on if the kernel is still flakey. 600 */ 601 if (mp->mnt_flag & MNT_SYNCHRONOUS) 602 pmp->pm_flags |= MSDOSFSMNT_WAITONFAT; 603 604 /* 605 * Finish up. 606 */ 607 if (ronly) 608 pmp->pm_flags |= MSDOSFSMNT_RONLY; 609 else 610 pmp->pm_fmod = 1; 611 mp->mnt_data = (qaddr_t) pmp; 612 mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); 613 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 614 mp->mnt_flag |= MNT_LOCAL; 615 vfs_add_vnodeops(mp, &msdosfs_vnode_vops, &mp->mnt_vn_norm_ops); 616 dev->si_mountpoint = mp; 617 618 return (0); 619 620 error_exit: 621 if (bp) { 622 bp->b_flags |= B_RELBUF; 623 brelse(bp); 624 } 625 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 626 VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE, NULL); 627 vn_unlock(devvp); 628 if (pmp) { 629 if (pmp->pm_inusemap) 630 kfree(pmp->pm_inusemap, M_MSDOSFSFAT); 631 kfree(pmp, M_MSDOSFSMNT); 632 mp->mnt_data = (qaddr_t)0; 633 } 634 return (error); 635 } 636 637 /* 638 * Unmount the filesystem described by mp. 639 */ 640 static int 641 msdosfs_unmount(struct mount *mp, int mntflags) 642 { 643 struct msdosfsmount *pmp; 644 int error, flags; 645 #ifdef MSDOSFS_DEBUG 646 struct vnode *vp; 647 #endif 648 flags = 0; 649 if (mntflags & MNT_FORCE) 650 flags |= FORCECLOSE; 651 error = vflush(mp, 0, flags); 652 if (error) 653 return error; 654 655 pmp = VFSTOMSDOSFS(mp); 656 pmp->pm_devvp->v_rdev->si_mountpoint = NULL; 657 658 if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdos_iconv) { 659 if(pmp->pm_w2u) 660 msdos_iconv->close(pmp->pm_w2u); 661 if(pmp->pm_u2w) 662 msdos_iconv->close(pmp->pm_u2w); 663 if(pmp->pm_d2u) 664 msdos_iconv->close(pmp->pm_d2u); 665 if(pmp->pm_u2d) 666 msdos_iconv->close(pmp->pm_u2d); 667 } 668 669 #ifdef MSDOSFS_DEBUG 670 vp = pmp->pm_devvp; 671 kprintf("msdosfs_umount(): just before calling VOP_CLOSE()\n"); 672 kprintf("flag %08x, refcnt 0x%08x, writecount %d, auxrefs 0x%08x\n", 673 vp->v_flag, vp->v_refcnt, vp->v_writecount, vp->v_auxrefs); 674 kprintf("mount %p, op %p\n", vp->v_mount, vp->v_ops); 675 kprintf("mount %p\n", vp->v_mount); 676 kprintf("cleanblkhd %p, dirtyblkhd %p, numoutput %d, type %d\n", 677 RB_ROOT(&vp->v_rbclean_tree), RB_ROOT(&vp->v_rbdirty_tree), 678 bio_track_active(&vp->v_track_write), vp->v_type); 679 kprintf("union %p, tag %d, data[0] %08x, data[1] %08x\n", 680 vp->v_socket, vp->v_tag, ((u_int *)vp->v_data)[0], 681 ((u_int *)vp->v_data)[1]); 682 #endif 683 684 vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY); 685 error = VOP_CLOSE(pmp->pm_devvp, 686 pmp->pm_flags & MSDOSFSMNT_RONLY ? FREAD : FREAD | FWRITE, 687 NULL); 688 vn_unlock(pmp->pm_devvp); 689 vrele(pmp->pm_devvp); 690 kfree(pmp->pm_inusemap, M_MSDOSFSFAT); 691 kfree(pmp, M_MSDOSFSMNT); 692 mp->mnt_data = (qaddr_t)0; 693 mp->mnt_flag &= ~MNT_LOCAL; 694 return (error); 695 } 696 697 static int 698 msdosfs_root(struct mount *mp, struct vnode **vpp) 699 { 700 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 701 struct denode *ndep; 702 int error; 703 704 mprintf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp); 705 error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep); 706 if (error) 707 return (error); 708 *vpp = DETOV(ndep); 709 return (0); 710 } 711 712 static int 713 msdosfs_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred) 714 { 715 struct msdosfsmount *pmp; 716 717 pmp = VFSTOMSDOSFS(mp); 718 sbp->f_bsize = pmp->pm_bpcluster; 719 sbp->f_iosize = pmp->pm_bpcluster; 720 sbp->f_blocks = pmp->pm_maxcluster + 1; 721 sbp->f_bfree = pmp->pm_freeclustercount; 722 sbp->f_bavail = pmp->pm_freeclustercount; 723 sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ 724 sbp->f_ffree = 0; /* what to put in here? */ 725 if (sbp != &mp->mnt_stat) { 726 sbp->f_type = mp->mnt_vfc->vfc_typenum; 727 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 728 } 729 strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN); 730 return (0); 731 } 732 733 struct scaninfo { 734 int rescan; 735 int allerror; 736 int waitfor; 737 }; 738 739 static int msdosfs_sync_scan(struct mount *mp, struct vnode *vp, void *data); 740 741 static int 742 msdosfs_sync(struct mount *mp, int waitfor) 743 { 744 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 745 struct scaninfo scaninfo; 746 int error; 747 748 /* 749 * If we ever switch to not updating all of the FATs all the time, 750 * this would be the place to update them from the first one. 751 */ 752 if (pmp->pm_fmod != 0) { 753 if (pmp->pm_flags & MSDOSFSMNT_RONLY) { 754 panic("msdosfs_sync: rofs mod"); 755 } else { 756 /* update FATs here */ 757 } 758 } 759 /* 760 * Write back each (modified) denode. 761 */ 762 scaninfo.allerror = 0; 763 scaninfo.rescan = 1; 764 while (scaninfo.rescan) { 765 scaninfo.rescan = 0; 766 vmntvnodescan(mp, VMSC_GETVP|VMSC_NOWAIT, NULL, 767 msdosfs_sync_scan, &scaninfo); 768 } 769 770 /* 771 * Flush filesystem control info. 772 */ 773 if ((waitfor & MNT_LAZY) == 0) { 774 vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY); 775 if ((error = VOP_FSYNC(pmp->pm_devvp, waitfor, 0)) != 0) 776 scaninfo.allerror = error; 777 vn_unlock(pmp->pm_devvp); 778 } 779 return (scaninfo.allerror); 780 } 781 782 static int 783 msdosfs_sync_scan(struct mount *mp, struct vnode *vp, void *data) 784 { 785 struct scaninfo *info = data; 786 struct denode *dep; 787 int error; 788 789 dep = VTODE(vp); 790 if (vp->v_type == VNON || vp->v_type == VBAD || 791 ((dep->de_flag & 792 (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0 && 793 (RB_EMPTY(&vp->v_rbdirty_tree) || (info->waitfor & MNT_LAZY)))) { 794 return(0); 795 } 796 if ((error = VOP_FSYNC(vp, info->waitfor, 0)) != 0) 797 info->allerror = error; 798 return(0); 799 } 800 801 static int 802 msdosfs_fhtovp(struct mount *mp, struct vnode *rootvp, 803 struct fid *fhp, struct vnode **vpp) 804 { 805 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 806 struct defid *defhp = (struct defid *) fhp; 807 struct denode *dep; 808 int error; 809 810 error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep); 811 if (error) { 812 *vpp = NULLVP; 813 return (error); 814 } 815 *vpp = DETOV(dep); 816 return (0); 817 } 818 819 static int 820 msdosfs_checkexp(struct mount *mp, struct sockaddr *nam, int *exflagsp, 821 struct ucred **credanonp) 822 { 823 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 824 struct netcred *np; 825 826 np = vfs_export_lookup(mp, &pmp->pm_export, nam); 827 if (np == NULL) 828 return (EACCES); 829 *exflagsp = np->netc_exflags; 830 *credanonp = &np->netc_anon; 831 return (0); 832 } 833 834 static int 835 msdosfs_vptofh(struct vnode *vp, struct fid *fhp) 836 { 837 struct denode *dep; 838 struct defid *defhp; 839 840 dep = VTODE(vp); 841 defhp = (struct defid *)fhp; 842 defhp->defid_len = sizeof(struct defid); 843 defhp->defid_dirclust = dep->de_dirclust; 844 defhp->defid_dirofs = dep->de_diroffset; 845 /* defhp->defid_gen = dep->de_gen; */ 846 return (0); 847 } 848 849 static struct vfsops msdosfs_vfsops = { 850 .vfs_mount = msdosfs_mount, 851 .vfs_unmount = msdosfs_unmount, 852 .vfs_root = msdosfs_root, 853 .vfs_statfs = msdosfs_statfs, 854 .vfs_sync = msdosfs_sync, 855 .vfs_fhtovp = msdosfs_fhtovp, 856 .vfs_checkexp = msdosfs_checkexp, 857 .vfs_vptofh = msdosfs_vptofh, 858 .vfs_init = msdosfs_init, 859 .vfs_uninit = msdosfs_uninit 860 }; 861 862 VFS_SET(msdosfs_vfsops, msdos, 0); 863 MODULE_VERSION(msdos, 1); 864