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