1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/param.h> 29 #include <sys/systm.h> 30 #include <sys/kmem.h> 31 #include <sys/user.h> 32 #include <sys/proc.h> 33 #include <sys/cred.h> 34 #include <sys/disp.h> 35 #include <sys/buf.h> 36 #include <sys/vfs.h> 37 #include <sys/vnode.h> 38 #include <sys/fdio.h> 39 #include <sys/file.h> 40 #include <sys/uio.h> 41 #include <sys/conf.h> 42 #undef NFSCLIENT 43 #include <sys/statvfs.h> 44 #include <sys/mount.h> 45 #include <sys/pathname.h> 46 #include <sys/cmn_err.h> 47 #include <sys/debug.h> 48 #include <sys/sysmacros.h> 49 #include <sys/conf.h> 50 #include <sys/mkdev.h> 51 #include <sys/swap.h> 52 #include <sys/sunddi.h> 53 #include <sys/sunldi.h> 54 #include <sys/dktp/fdisk.h> 55 #include <sys/fs/pc_label.h> 56 #include <sys/fs/pc_fs.h> 57 #include <sys/fs/pc_dir.h> 58 #include <sys/fs/pc_node.h> 59 #include <fs/fs_subr.h> 60 #include <sys/modctl.h> 61 #include <sys/dkio.h> 62 #include <sys/open.h> 63 #include <sys/mntent.h> 64 #include <sys/policy.h> 65 #include <sys/atomic.h> 66 67 /* 68 * The majority of PC media use a 512 sector size, but 69 * occasionally you will run across a 1k sector size. 70 * For media with a 1k sector size, fd_strategy() requires 71 * the I/O size to be a 1k multiple; so when the sector size 72 * is not yet known, always read 1k. 73 */ 74 #define PC_SAFESECSIZE (PC_SECSIZE * 2) 75 76 static int pcfs_pseudo_floppy(dev_t); 77 78 static int pcfsinit(int, char *); 79 static int pcfs_mount(struct vfs *, struct vnode *, struct mounta *, 80 struct cred *); 81 static int pcfs_unmount(struct vfs *, int, struct cred *); 82 static int pcfs_root(struct vfs *, struct vnode **); 83 static int pcfs_statvfs(struct vfs *, struct statvfs64 *); 84 static int pc_syncfsnodes(struct pcfs *); 85 static int pcfs_sync(struct vfs *, short, struct cred *); 86 static int pcfs_vget(struct vfs *vfsp, struct vnode **vpp, struct fid *fidp); 87 static void pcfs_freevfs(vfs_t *vfsp); 88 89 static int pc_getfattype(struct vnode *, int, daddr_t *, int *); 90 static int pc_readfat(struct pcfs *fsp, uchar_t *fatp, daddr_t start, 91 size_t fatsize); 92 static int pc_writefat(struct pcfs *fsp, daddr_t start); 93 94 /* 95 * pcfs mount options table 96 */ 97 98 static char *nohidden_cancel[] = { MNTOPT_PCFS_HIDDEN, NULL }; 99 static char *hidden_cancel[] = { MNTOPT_PCFS_NOHIDDEN, NULL }; 100 static char *nofoldcase_cancel[] = { MNTOPT_PCFS_FOLDCASE, NULL }; 101 static char *foldcase_cancel[] = { MNTOPT_PCFS_NOFOLDCASE, NULL }; 102 static char *clamptime_cancel[] = { MNTOPT_PCFS_NOCLAMPTIME, NULL }; 103 static char *noclamptime_cancel[] = { MNTOPT_PCFS_CLAMPTIME, NULL }; 104 105 static mntopt_t mntopts[] = { 106 /* 107 * option name cancel option default arg flags opt data 108 */ 109 { MNTOPT_PCFS_NOHIDDEN, nohidden_cancel, NULL, 0, NULL }, 110 { MNTOPT_PCFS_HIDDEN, hidden_cancel, NULL, MO_DEFAULT, NULL }, 111 { MNTOPT_PCFS_NOFOLDCASE, nofoldcase_cancel, NULL, MO_DEFAULT, NULL }, 112 { MNTOPT_PCFS_FOLDCASE, foldcase_cancel, NULL, 0, NULL }, 113 { MNTOPT_PCFS_CLAMPTIME, clamptime_cancel, NULL, MO_DEFAULT, NULL }, 114 { MNTOPT_PCFS_NOCLAMPTIME, noclamptime_cancel, NULL, NULL, NULL } 115 }; 116 117 static mntopts_t pcfs_mntopts = { 118 sizeof (mntopts) / sizeof (mntopt_t), 119 mntopts 120 }; 121 122 int pcfsdebuglevel = 0; 123 124 /* 125 * pcfslock: protects the list of mounted pc filesystems "pc_mounttab. 126 * pcfs_lock: (inside per filesystem structure "pcfs") 127 * per filesystem lock. Most of the vfsops and vnodeops are 128 * protected by this lock. 129 * pcnodes_lock: protects the pcnode hash table "pcdhead", "pcfhead". 130 * 131 * Lock hierarchy: pcfslock > pcfs_lock > pcnodes_lock 132 * 133 * pcfs_mountcount: used to prevent module unloads while there is still 134 * pcfs state from a former mount hanging around. With 135 * forced umount support, the filesystem module must not 136 * be allowed to go away before the last VFS_FREEVFS() 137 * call has been made. 138 * Since this is just an atomic counter, there's no need 139 * for locking. 140 */ 141 kmutex_t pcfslock; 142 krwlock_t pcnodes_lock; 143 uint32_t pcfs_mountcount; 144 145 static int pcfstype; 146 147 static vfsdef_t vfw = { 148 VFSDEF_VERSION, 149 "pcfs", 150 pcfsinit, 151 VSW_HASPROTO|VSW_CANREMOUNT|VSW_STATS, 152 &pcfs_mntopts 153 }; 154 155 extern struct mod_ops mod_fsops; 156 157 static struct modlfs modlfs = { 158 &mod_fsops, 159 "PC filesystem v1.100", 160 &vfw 161 }; 162 163 static struct modlinkage modlinkage = { 164 MODREV_1, 165 &modlfs, 166 NULL 167 }; 168 169 int 170 _init(void) 171 { 172 int error; 173 174 #if !defined(lint) 175 /* make sure the on-disk structures are sane */ 176 ASSERT(sizeof (struct pcdir) == 32); 177 ASSERT(sizeof (struct pcdir_lfn) == 32); 178 #endif 179 mutex_init(&pcfslock, NULL, MUTEX_DEFAULT, NULL); 180 rw_init(&pcnodes_lock, NULL, RW_DEFAULT, NULL); 181 error = mod_install(&modlinkage); 182 if (error) { 183 mutex_destroy(&pcfslock); 184 rw_destroy(&pcnodes_lock); 185 } 186 return (error); 187 } 188 189 int 190 _fini(void) 191 { 192 int error; 193 194 /* 195 * If a forcedly unmounted instance is still hanging around, 196 * we cannot allow the module to be unloaded because that would 197 * cause panics once the VFS framework decides it's time to call 198 * into VFS_FREEVFS(). 199 */ 200 if (pcfs_mountcount) 201 return (EBUSY); 202 203 error = mod_remove(&modlinkage); 204 if (error) 205 return (error); 206 mutex_destroy(&pcfslock); 207 rw_destroy(&pcnodes_lock); 208 /* 209 * Tear down the operations vectors 210 */ 211 (void) vfs_freevfsops_by_type(pcfstype); 212 vn_freevnodeops(pcfs_fvnodeops); 213 vn_freevnodeops(pcfs_dvnodeops); 214 return (0); 215 } 216 217 int 218 _info(struct modinfo *modinfop) 219 { 220 return (mod_info(&modlinkage, modinfop)); 221 } 222 223 /* ARGSUSED1 */ 224 static int 225 pcfsinit(int fstype, char *name) 226 { 227 static const fs_operation_def_t pcfs_vfsops_template[] = { 228 VFSNAME_MOUNT, pcfs_mount, 229 VFSNAME_UNMOUNT, pcfs_unmount, 230 VFSNAME_ROOT, pcfs_root, 231 VFSNAME_STATVFS, pcfs_statvfs, 232 VFSNAME_SYNC, (fs_generic_func_p) pcfs_sync, 233 VFSNAME_VGET, pcfs_vget, 234 VFSNAME_FREEVFS, (fs_generic_func_p) pcfs_freevfs, 235 NULL, NULL 236 }; 237 int error; 238 239 error = vfs_setfsops(fstype, pcfs_vfsops_template, NULL); 240 if (error != 0) { 241 cmn_err(CE_WARN, "pcfsinit: bad vfs ops template"); 242 return (error); 243 } 244 245 error = vn_make_ops("pcfs", pcfs_fvnodeops_template, &pcfs_fvnodeops); 246 if (error != 0) { 247 (void) vfs_freevfsops_by_type(fstype); 248 cmn_err(CE_WARN, "pcfsinit: bad file vnode ops template"); 249 return (error); 250 } 251 252 error = vn_make_ops("pcfsd", pcfs_dvnodeops_template, &pcfs_dvnodeops); 253 if (error != 0) { 254 (void) vfs_freevfsops_by_type(fstype); 255 vn_freevnodeops(pcfs_fvnodeops); 256 cmn_err(CE_WARN, "pcfsinit: bad dir vnode ops template"); 257 return (error); 258 } 259 260 pcfstype = fstype; 261 (void) pc_init(); 262 pcfs_mountcount = 0; 263 return (0); 264 } 265 266 static struct pcfs *pc_mounttab = NULL; 267 268 extern struct pcfs_args pc_tz; 269 270 /* 271 * Define some special logical drives we use internal to this file. 272 */ 273 #define BOOT_PARTITION_DRIVE 99 274 #define PRIMARY_DOS_DRIVE 1 275 276 /* 277 * pc_mount system call 278 */ 279 static int 280 pcfs_mount( 281 struct vfs *vfsp, 282 struct vnode *mvp, 283 struct mounta *uap, 284 struct cred *cr) 285 { 286 struct pcfs *fsp; 287 struct vnode *bvp; 288 struct vnode *devvp; 289 struct pathname special; 290 daddr_t dosstart; 291 dev_t pseudodev; 292 dev_t xdev; 293 char *c; 294 char *data = uap->dataptr; 295 int datalen = uap->datalen; 296 int dos_ldrive = 0; 297 int error; 298 int fattype; 299 minor_t minor; 300 int oflag, aflag; 301 302 if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0) 303 return (error); 304 305 PC_DPRINTF0(4, "pcfs_mount\n"); 306 if (mvp->v_type != VDIR) { 307 return (ENOTDIR); 308 } 309 mutex_enter(&mvp->v_lock); 310 if ((uap->flags & MS_REMOUNT) == 0 && 311 (uap->flags & MS_OVERLAY) == 0 && 312 (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { 313 mutex_exit(&mvp->v_lock); 314 return (EBUSY); 315 } 316 mutex_exit(&mvp->v_lock); 317 318 /* 319 * The caller is responsible for making sure to always 320 * pass in sizeof(struct pcfs_args) (or the old one). 321 * Doing this is the only way to know an EINVAL return 322 * from mount(2) is due to the "not a DOS filesystem" 323 * EINVAL that pc_verify/pc_getfattype could return. 324 */ 325 if ((datalen != sizeof (struct pcfs_args)) && 326 (datalen != sizeof (struct old_pcfs_args))) { 327 return (EINVAL); 328 } else { 329 struct pcfs_args tmp_tz; 330 int hidden = 0; 331 int foldcase = 0; 332 int noclamptime = 0; 333 334 tmp_tz.flags = 0; 335 if (copyin(data, &tmp_tz, datalen)) { 336 return (EFAULT); 337 } 338 if (datalen == sizeof (struct pcfs_args)) { 339 hidden = tmp_tz.flags & PCFS_MNT_HIDDEN; 340 foldcase = tmp_tz.flags & PCFS_MNT_FOLDCASE; 341 noclamptime = tmp_tz.flags & PCFS_MNT_NOCLAMPTIME; 342 } 343 344 if (hidden) 345 vfs_setmntopt(vfsp, MNTOPT_PCFS_HIDDEN, NULL, 0); 346 if (foldcase) 347 vfs_setmntopt(vfsp, MNTOPT_PCFS_FOLDCASE, NULL, 0); 348 if (noclamptime) 349 vfs_setmntopt(vfsp, MNTOPT_PCFS_NOCLAMPTIME, NULL, 0); 350 /* 351 * more than one pc filesystem can be mounted on x86 352 * so the pc_tz structure is now a critical region 353 */ 354 mutex_enter(&pcfslock); 355 if (pc_mounttab == NULL) 356 bcopy(&tmp_tz, &pc_tz, sizeof (struct pcfs_args)); 357 mutex_exit(&pcfslock); 358 } 359 /* 360 * Resolve path name of special file being mounted. 361 */ 362 if (error = pn_get(uap->spec, UIO_USERSPACE, &special)) { 363 return (error); 364 } 365 if (error = 366 lookupname(special.pn_path, UIO_SYSSPACE, FOLLOW, NULLVPP, &bvp)) { 367 /* 368 * Split the pathname string at the last ':' separator. 369 * If there's no ':' in the device name, or the ':' is the 370 * last character in the string, the name is invalid and 371 * the error from the previous lookup will be returned. 372 */ 373 c = strrchr(special.pn_path, ':'); 374 if (c == NULL || strlen(c) == 0) 375 goto devlookup_done; 376 377 *c++ = '\0'; 378 379 /* 380 * PCFS partition name suffixes can be: 381 * - "boot" to indicate the X86BOOT partition 382 * - a drive letter [c-z] for the "DOS logical drive" 383 * - a drive number 1..24 for the "DOS logical drive" 384 */ 385 if (strcasecmp(c, "boot") == 0) { 386 /* 387 * The Solaris boot partition is requested. 388 */ 389 dos_ldrive = BOOT_PARTITION_DRIVE; 390 } else if (strspn(c, "0123456789") == strlen(c)) { 391 /* 392 * All digits - parse the partition number. 393 */ 394 long drvnum = 0; 395 396 if ((error = ddi_strtol(c, NULL, 10, &drvnum)) == 0) { 397 /* 398 * A number alright - in the allowed range ? 399 */ 400 if (drvnum > 24 || drvnum == 0) 401 error = EINVAL; 402 } 403 if (error) 404 goto devlookup_done; 405 dos_ldrive = (int)drvnum; 406 } else if (strlen(c) == 1) { 407 /* 408 * A single trailing character - is it [c-zC-Z] ? 409 */ 410 *c = tolower(*c); 411 if (*c < 'c' || *c > 'z') { 412 error = EINVAL; 413 goto devlookup_done; 414 } 415 dos_ldrive = 1 + *c - 'c'; 416 } else { 417 /* 418 * Can't parse this - pass through previous error. 419 */ 420 goto devlookup_done; 421 } 422 423 ASSERT(dos_ldrive > 0); 424 425 error = lookupname(special.pn_path, UIO_SYSSPACE, FOLLOW, 426 NULLVPP, &bvp); 427 } 428 devlookup_done: 429 pn_free(&special); 430 if (error) 431 return (error); 432 433 if (bvp->v_type != VBLK) { 434 VN_RELE(bvp); 435 return (ENOTBLK); 436 } 437 xdev = bvp->v_rdev; 438 /* 439 * Verify caller's permission to open the device special file. 440 */ 441 if ((vfsp->vfs_flag & VFS_RDONLY) != 0 || 442 ((uap->flags & MS_RDONLY) != 0)) { 443 oflag = FREAD; 444 aflag = VREAD; 445 } else { 446 oflag = FREAD | FWRITE; 447 aflag = VREAD | VWRITE; 448 } 449 if ((error = VOP_ACCESS(bvp, aflag, 0, cr)) != 0 || 450 (error = secpolicy_spec_open(cr, bvp, oflag)) != 0) { 451 VN_RELE(bvp); 452 return (error); 453 } 454 455 VN_RELE(bvp); 456 if (getmajor(xdev) >= devcnt) { 457 return (ENXIO); 458 } 459 /* 460 * Ensure that this logical drive isn't already mounted, unless 461 * this is a REMOUNT request. 462 * Note: The framework will perform this check if the "...:c" 463 * PCFS-style "logical drive" syntax has not been used and an 464 * actually existing physical device is backing this filesystem. 465 */ 466 if (dos_ldrive) { 467 mutex_enter(&pcfslock); 468 for (fsp = pc_mounttab; fsp; fsp = fsp->pcfs_nxt) 469 if (fsp->pcfs_xdev == xdev && 470 fsp->pcfs_ldrv == dos_ldrive) { 471 mutex_exit(&pcfslock); 472 if (uap->flags & MS_REMOUNT) { 473 return (0); 474 } else { 475 return (EBUSY); 476 } 477 } 478 /* 479 * Assign a unique device number for the vfs 480 * The old way (getudev() + a constantly incrementing 481 * major number) was wrong because it changes vfs_dev 482 * across mounts and reboots, which breaks nfs file handles. 483 * UFS just uses the real dev_t. We can't do that because 484 * of the way pcfs opens fdisk partitons (the :c and :d 485 * partitions are on the same dev_t). Though that _might_ 486 * actually be ok, since the file handle contains an 487 * absolute block number, it's probably better to make them 488 * different. So I think we should retain the original 489 * dev_t, but come up with a different minor number based 490 * on the logical drive that will _always_ come up the same. 491 * For now, we steal the upper 6 bits. 492 */ 493 #ifdef notdef 494 /* what should we do here? */ 495 if (((getminor(xdev) >> 12) & 0x3F) != 0) 496 printf("whoops - upper bits used!\n"); 497 #endif 498 minor = ((dos_ldrive << 12) | getminor(xdev)) & MAXMIN32; 499 pseudodev = makedevice(getmajor(xdev), minor); 500 if (vfs_devmounting(pseudodev, vfsp)) { 501 mutex_exit(&pcfslock); 502 return (EBUSY); 503 } 504 if (vfs_devismounted(pseudodev)) { 505 mutex_exit(&pcfslock); 506 if (uap->flags & MS_REMOUNT) { 507 return (0); 508 } else { 509 return (EBUSY); 510 } 511 } 512 mutex_exit(&pcfslock); 513 } else { 514 if (vfs_devmounting(xdev, vfsp)) { 515 return (EBUSY); 516 } 517 if (vfs_devismounted(xdev)) 518 if (uap->flags & MS_REMOUNT) { 519 return (0); 520 } else { 521 return (EBUSY); 522 } 523 pseudodev = xdev; 524 } 525 526 if (uap->flags & MS_RDONLY) { 527 vfsp->vfs_flag |= VFS_RDONLY; 528 vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); 529 } 530 531 /* 532 * Mount the filesystem 533 */ 534 devvp = makespecvp(xdev, VBLK); 535 if (IS_SWAPVP(devvp)) { 536 VN_RELE(devvp); 537 return (EBUSY); 538 } 539 540 /* 541 * special handling for PCMCIA memory card 542 * with pseudo floppies organization 543 */ 544 if (dos_ldrive == 0 && pcfs_pseudo_floppy(xdev)) { 545 dosstart = (daddr_t)0; 546 fattype = PCFS_PCMCIA_NO_CIS; 547 } else { 548 if (error = pc_getfattype(devvp, dos_ldrive, &dosstart, 549 &fattype)) { 550 VN_RELE(devvp); 551 return (error); 552 } 553 } 554 555 (void) VOP_PUTPAGE(devvp, (offset_t)0, (uint_t)0, B_INVAL, cr); 556 fsp = kmem_zalloc((uint_t)sizeof (struct pcfs), KM_SLEEP); 557 fsp->pcfs_vfs = vfsp; 558 fsp->pcfs_flags = fattype; 559 fsp->pcfs_devvp = devvp; 560 fsp->pcfs_xdev = xdev; 561 fsp->pcfs_ldrv = dos_ldrive; 562 fsp->pcfs_dosstart = dosstart; 563 mutex_init(&fsp->pcfs_lock, NULL, MUTEX_DEFAULT, NULL); 564 565 if (vfs_optionisset(vfsp, MNTOPT_PCFS_HIDDEN, NULL)) 566 fsp->pcfs_flags |= PCFS_HIDDEN; 567 if (vfs_optionisset(vfsp, MNTOPT_PCFS_FOLDCASE, NULL)) 568 fsp->pcfs_flags |= PCFS_FOLDCASE; 569 if (vfs_optionisset(vfsp, MNTOPT_PCFS_NOCLAMPTIME, NULL)) 570 fsp->pcfs_flags |= PCFS_NOCLAMPTIME; 571 vfsp->vfs_dev = pseudodev; 572 vfsp->vfs_fstype = pcfstype; 573 vfs_make_fsid(&vfsp->vfs_fsid, pseudodev, pcfstype); 574 vfsp->vfs_data = (caddr_t)fsp; 575 vfsp->vfs_bcount = 0; 576 577 error = pc_verify(fsp); 578 if (error) { 579 VN_RELE(devvp); 580 mutex_destroy(&fsp->pcfs_lock); 581 kmem_free(fsp, (uint_t)sizeof (struct pcfs)); 582 return (error); 583 } 584 vfsp->vfs_bsize = fsp->pcfs_clsize; 585 586 mutex_enter(&pcfslock); 587 fsp->pcfs_nxt = pc_mounttab; 588 pc_mounttab = fsp; 589 mutex_exit(&pcfslock); 590 atomic_inc_32(&pcfs_mountcount); 591 return (0); 592 } 593 594 /* 595 * vfs operations 596 */ 597 598 /* ARGSUSED */ 599 static int 600 pcfs_unmount( 601 struct vfs *vfsp, 602 int flag, 603 struct cred *cr) 604 { 605 struct pcfs *fsp, *fsp1; 606 607 if (secpolicy_fs_unmount(cr, vfsp) != 0) 608 return (EPERM); 609 610 PC_DPRINTF0(4, "pcfs_unmount\n"); 611 fsp = VFSTOPCFS(vfsp); 612 613 /* 614 * We don't have to lock fsp because the VVFSLOCK in vfs layer will 615 * prevent lookuppn from crossing the mount point. 616 * If this is not a forced umount request and there's ongoing I/O, 617 * don't allow the mount to proceed. 618 */ 619 if (flag & MS_FORCE) 620 vfsp->vfs_flag |= VFS_UNMOUNTED; 621 else if (fsp->pcfs_nrefs) 622 return (EBUSY); 623 624 mutex_enter(&pcfslock); 625 626 /* 627 * If this is a forced umount request or if the fs instance has 628 * been marked as beyond recovery, allow the umount to proceed 629 * regardless of state. pc_diskchanged() forcibly releases all 630 * inactive vnodes/pcnodes. 631 */ 632 if (flag & MS_FORCE || fsp->pcfs_flags & PCFS_IRRECOV) { 633 rw_enter(&pcnodes_lock, RW_WRITER); 634 pc_diskchanged(fsp); 635 rw_exit(&pcnodes_lock); 636 } 637 638 /* now there should be no pcp node on pcfhead or pcdhead. */ 639 640 if (fsp == pc_mounttab) { 641 pc_mounttab = fsp->pcfs_nxt; 642 } else { 643 for (fsp1 = pc_mounttab; fsp1 != NULL; fsp1 = fsp1->pcfs_nxt) 644 if (fsp1->pcfs_nxt == fsp) 645 fsp1->pcfs_nxt = fsp->pcfs_nxt; 646 } 647 648 mutex_exit(&pcfslock); 649 650 /* 651 * Since we support VFS_FREEVFS(), there's no need to 652 * free the fsp right now. The framework will tell us 653 * when the right time to do so has arrived by calling 654 * into pcfs_freevfs. 655 */ 656 return (0); 657 } 658 659 /* 660 * find root of pcfs 661 */ 662 static int 663 pcfs_root( 664 struct vfs *vfsp, 665 struct vnode **vpp) 666 { 667 struct pcfs *fsp; 668 struct pcnode *pcp; 669 int error; 670 671 fsp = VFSTOPCFS(vfsp); 672 if (error = pc_lockfs(fsp, 0, 0)) 673 return (error); 674 675 pcp = pc_getnode(fsp, (daddr_t)0, 0, (struct pcdir *)0); 676 PC_DPRINTF2(9, "pcfs_root(0x%p) pcp= 0x%p\n", 677 (void *)vfsp, (void *)pcp); 678 pc_unlockfs(fsp); 679 *vpp = PCTOV(pcp); 680 pcp->pc_flags |= PC_EXTERNAL; 681 return (0); 682 } 683 684 /* 685 * Get file system statistics. 686 */ 687 static int 688 pcfs_statvfs( 689 struct vfs *vfsp, 690 struct statvfs64 *sp) 691 { 692 struct pcfs *fsp; 693 int error; 694 dev32_t d32; 695 696 fsp = VFSTOPCFS(vfsp); 697 error = pc_getfat(fsp); 698 if (error) 699 return (error); 700 bzero(sp, sizeof (*sp)); 701 sp->f_bsize = sp->f_frsize = fsp->pcfs_clsize; 702 sp->f_blocks = (fsblkcnt64_t)fsp->pcfs_ncluster; 703 sp->f_bavail = sp->f_bfree = (fsblkcnt64_t)pc_freeclusters(fsp); 704 sp->f_files = (fsfilcnt64_t)-1; 705 sp->f_ffree = (fsfilcnt64_t)-1; 706 sp->f_favail = (fsfilcnt64_t)-1; 707 #ifdef notdef 708 (void) cmpldev(&d32, fsp->pcfs_devvp->v_rdev); 709 #endif /* notdef */ 710 (void) cmpldev(&d32, vfsp->vfs_dev); 711 sp->f_fsid = d32; 712 (void) strcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name); 713 sp->f_flag = vf_to_stf(vfsp->vfs_flag); 714 sp->f_namemax = PCFNAMESIZE; 715 return (0); 716 } 717 718 static int 719 pc_syncfsnodes(struct pcfs *fsp) 720 { 721 struct pchead *hp; 722 struct pcnode *pcp; 723 int error; 724 725 PC_DPRINTF0(7, "pcfs_syncfsnodes\n"); 726 if (error = pc_lockfs(fsp, 0, 0)) 727 return (error); 728 729 if (!(error = pc_syncfat(fsp))) { 730 hp = pcfhead; 731 while (hp < & pcfhead [ NPCHASH ]) { 732 rw_enter(&pcnodes_lock, RW_READER); 733 pcp = hp->pch_forw; 734 while (pcp != (struct pcnode *)hp) { 735 if (VFSTOPCFS(PCTOV(pcp) -> v_vfsp) == fsp) 736 if (error = pc_nodesync(pcp)) 737 break; 738 pcp = pcp -> pc_forw; 739 } 740 rw_exit(&pcnodes_lock); 741 if (error) 742 break; 743 hp++; 744 } 745 } 746 pc_unlockfs(fsp); 747 return (error); 748 } 749 750 /* 751 * Flush any pending I/O. 752 */ 753 /*ARGSUSED*/ 754 static int 755 pcfs_sync( 756 struct vfs *vfsp, 757 short flag, 758 struct cred *cr) 759 { 760 struct pcfs *fsp; 761 int error = 0; 762 763 /* this prevents the filesystem from being umounted. */ 764 mutex_enter(&pcfslock); 765 if (vfsp != NULL) { 766 fsp = VFSTOPCFS(vfsp); 767 if (!(fsp->pcfs_flags & PCFS_IRRECOV)) { 768 error = pc_syncfsnodes(fsp); 769 } else { 770 rw_enter(&pcnodes_lock, RW_WRITER); 771 pc_diskchanged(fsp); 772 rw_exit(&pcnodes_lock); 773 error = EIO; 774 } 775 } else { 776 fsp = pc_mounttab; 777 while (fsp != NULL) { 778 if (fsp->pcfs_flags & PCFS_IRRECOV) { 779 rw_enter(&pcnodes_lock, RW_WRITER); 780 pc_diskchanged(fsp); 781 rw_exit(&pcnodes_lock); 782 error = EIO; 783 break; 784 } 785 error = pc_syncfsnodes(fsp); 786 if (error) break; 787 fsp = fsp->pcfs_nxt; 788 } 789 } 790 mutex_exit(&pcfslock); 791 return (error); 792 } 793 794 int 795 pc_lockfs(struct pcfs *fsp, int diskchanged, int releasing) 796 { 797 int err; 798 799 if ((fsp->pcfs_flags & PCFS_IRRECOV) && !releasing) 800 return (EIO); 801 802 if ((fsp->pcfs_flags & PCFS_LOCKED) && (fsp->pcfs_owner == curthread)) { 803 fsp->pcfs_count++; 804 } else { 805 mutex_enter(&fsp->pcfs_lock); 806 if (fsp->pcfs_flags & PCFS_LOCKED) 807 panic("pc_lockfs"); 808 /* 809 * We check the IRRECOV bit again just in case somebody 810 * snuck past the initial check but then got held up before 811 * they could grab the lock. (And in the meantime someone 812 * had grabbed the lock and set the bit) 813 */ 814 if (!diskchanged && !(fsp->pcfs_flags & PCFS_IRRECOV)) { 815 if ((err = pc_getfat(fsp))) { 816 mutex_exit(&fsp->pcfs_lock); 817 return (err); 818 } 819 } 820 fsp->pcfs_flags |= PCFS_LOCKED; 821 fsp->pcfs_owner = curthread; 822 fsp->pcfs_count++; 823 } 824 return (0); 825 } 826 827 void 828 pc_unlockfs(struct pcfs *fsp) 829 { 830 831 if ((fsp->pcfs_flags & PCFS_LOCKED) == 0) 832 panic("pc_unlockfs"); 833 if (--fsp->pcfs_count < 0) 834 panic("pc_unlockfs: count"); 835 if (fsp->pcfs_count == 0) { 836 fsp->pcfs_flags &= ~PCFS_LOCKED; 837 fsp->pcfs_owner = 0; 838 mutex_exit(&fsp->pcfs_lock); 839 } 840 } 841 842 /* 843 * isDosDrive() 844 * Boolean function. Give it the systid field for an fdisk partition 845 * and it decides if that's a systid that describes a DOS drive. We 846 * use systid values defined in sys/dktp/fdisk.h. 847 */ 848 static int 849 isDosDrive(uchar_t checkMe) 850 { 851 return ((checkMe == DOSOS12) || (checkMe == DOSOS16) || 852 (checkMe == DOSHUGE) || (checkMe == FDISK_WINDOWS) || 853 (checkMe == FDISK_EXT_WIN) || (checkMe == FDISK_FAT95) || 854 (checkMe == DIAGPART)); 855 } 856 857 /* 858 * isDosExtended() 859 * Boolean function. Give it the systid field for an fdisk partition 860 * and it decides if that's a systid that describes an extended DOS 861 * partition. 862 */ 863 static int 864 isDosExtended(uchar_t checkMe) 865 { 866 return ((checkMe == EXTDOS) || (checkMe == FDISK_EXTLBA)); 867 } 868 869 /* 870 * isBootPart() 871 * Boolean function. Give it the systid field for an fdisk partition 872 * and it decides if that's a systid that describes a Solaris boot 873 * partition. 874 */ 875 static int 876 isBootPart(uchar_t checkMe) 877 { 878 return (checkMe == X86BOOT); 879 } 880 881 /* 882 * noLogicalDrive() 883 * Display error message about not being able to find a logical 884 * drive. 885 */ 886 static void 887 noLogicalDrive(int requested) 888 { 889 if (requested == BOOT_PARTITION_DRIVE) { 890 cmn_err(CE_NOTE, "!pcfs: no boot partition"); 891 } else { 892 cmn_err(CE_NOTE, "!pcfs: no such logical drive"); 893 } 894 } 895 896 /* 897 * findTheDrive() 898 * Discover offset of the requested logical drive, and return 899 * that offset (startSector), the systid of that drive (sysid), 900 * and a buffer pointer (bp), with the buffer contents being 901 * the first sector of the logical drive (i.e., the sector that 902 * contains the BPB for that drive). 903 */ 904 static int 905 findTheDrive(dev_t dev, int ldrive, buf_t **bp, 906 daddr_t *startSector, uchar_t *sysid) 907 { 908 struct ipart dosp[FD_NUMPART]; /* incore fdisk partition structure */ 909 struct mboot *dosp_ptr; /* boot structure pointer */ 910 daddr_t lastseek = 0; /* Disk block we sought previously */ 911 daddr_t diskblk = 0; /* Disk block to get */ 912 daddr_t xstartsect; /* base of Extended DOS partition */ 913 int logicalDriveCount = 0; /* Count of logical drives seen */ 914 int extendedPart = -1; /* index of extended dos partition */ 915 int primaryPart = -1; /* index of primary dos partition */ 916 int bootPart = -1; /* index of a Solaris boot partition */ 917 int xnumsect = -1; /* length of extended DOS partition */ 918 int driveIndex; /* computed FDISK table index */ 919 int i; 920 /* 921 * Count of drives in the current extended partition's 922 * FDISK table, and indexes of the drives themselves. 923 */ 924 int extndDrives[FD_NUMPART]; 925 int numDrives = 0; 926 927 /* 928 * Count of drives (beyond primary) in master boot record's 929 * FDISK table, and indexes of the drives themselves. 930 */ 931 int extraDrives[FD_NUMPART]; 932 int numExtraDrives = 0; 933 934 /* 935 * "ldrive == 0" should never happen, as this is a request to 936 * mount the physical device (and ignore partitioning). The code 937 * in pcfs_mount() should have made sure that a logical drive number 938 * is at least 1, meaning we're looking for drive "C:". It is not 939 * safe (and a bug in the callers of this function) to request logical 940 * drive number 0; we could ASSERT() but a graceful EIO is a more 941 * polite way. 942 */ 943 if (ldrive == 0) { 944 cmn_err(CE_NOTE, "!pcfs: request for logical partition zero"); 945 noLogicalDrive(ldrive); 946 return (EIO); 947 } 948 949 /* 950 * Copy from disk block into memory aligned structure for fdisk usage. 951 */ 952 dosp_ptr = (struct mboot *)(*bp)->b_un.b_addr; 953 bcopy(dosp_ptr->parts, dosp, sizeof (struct ipart) * FD_NUMPART); 954 955 if (ltohs(dosp_ptr->signature) != MBB_MAGIC) { 956 cmn_err(CE_NOTE, "!pcfs: MBR partition table signature err"); 957 return (EINVAL); 958 } 959 960 /* 961 * Get a summary of what is in the Master FDISK table. 962 * Normally we expect to find one partition marked as a DOS drive. 963 * This partition is the one Windows calls the primary dos partition. 964 * If the machine has any logical drives then we also expect 965 * to find a partition marked as an extended DOS partition. 966 * 967 * Sometimes we'll find multiple partitions marked as DOS drives. 968 * The Solaris fdisk program allows these partitions 969 * to be created, but Windows fdisk no longer does. We still need 970 * to support these, though, since Windows does. We also need to fix 971 * our fdisk to behave like the Windows version. 972 * 973 * It turns out that some off-the-shelf media have *only* an 974 * Extended partition, so we need to deal with that case as well. 975 * 976 * Only a single (the first) Extended or Boot Partition will 977 * be recognized. Any others will be ignored. 978 */ 979 for (i = 0; i < FD_NUMPART; i++) { 980 PC_DPRINTF1(2, "findTheDrive: found partition type %02x", 981 dosp[i].systid); 982 983 if (isDosDrive(dosp[i].systid)) { 984 if (primaryPart < 0) { 985 logicalDriveCount++; 986 primaryPart = i; 987 } else { 988 extraDrives[numExtraDrives++] = i; 989 } 990 continue; 991 } 992 if ((extendedPart < 0) && isDosExtended(dosp[i].systid)) { 993 extendedPart = i; 994 continue; 995 } 996 if ((bootPart < 0) && isBootPart(dosp[i].systid)) { 997 bootPart = i; 998 continue; 999 } 1000 } 1001 1002 if (ldrive == BOOT_PARTITION_DRIVE) { 1003 if (bootPart < 0) { 1004 noLogicalDrive(ldrive); 1005 return (EINVAL); 1006 } 1007 *sysid = dosp[bootPart].systid; 1008 *startSector = ltohi(dosp[bootPart].relsect); 1009 return (0); 1010 } 1011 1012 if (ldrive == PRIMARY_DOS_DRIVE && primaryPart >= 0) { 1013 *sysid = dosp[primaryPart].systid; 1014 *startSector = ltohi(dosp[primaryPart].relsect); 1015 return (0); 1016 } 1017 1018 /* 1019 * We are not looking for the C: drive (or the primary drive 1020 * was not found), so we had better have an extended partition 1021 * or extra drives in the Master FDISK table. 1022 */ 1023 if ((extendedPart < 0) && (numExtraDrives == 0)) { 1024 cmn_err(CE_NOTE, "!pcfs: no extended dos partition"); 1025 noLogicalDrive(ldrive); 1026 return (EINVAL); 1027 } 1028 1029 if (extendedPart >= 0) { 1030 diskblk = xstartsect = ltohi(dosp[extendedPart].relsect); 1031 xnumsect = ltohi(dosp[extendedPart].numsect); 1032 do { 1033 /* 1034 * If the seek would not cause us to change 1035 * position on the drive, then we're out of 1036 * extended partitions to examine. 1037 */ 1038 if (diskblk == lastseek) 1039 break; 1040 logicalDriveCount += numDrives; 1041 /* 1042 * Seek the next extended partition, and find 1043 * logical drives within it. 1044 */ 1045 brelse(*bp); 1046 *bp = bread(dev, diskblk, PC_SAFESECSIZE); 1047 if ((*bp)->b_flags & B_ERROR) { 1048 PC_DPRINTF0(1, "pc_getfattype: read error\n"); 1049 return (EIO); 1050 } 1051 lastseek = diskblk; 1052 dosp_ptr = (struct mboot *)(*bp)->b_un.b_addr; 1053 if (ltohs(dosp_ptr->signature) != MBB_MAGIC) { 1054 cmn_err(CE_NOTE, "!pcfs: " 1055 "extended partition signature err"); 1056 return (EINVAL); 1057 } 1058 bcopy(dosp_ptr->parts, dosp, 1059 sizeof (struct ipart) * FD_NUMPART); 1060 /* 1061 * Count up drives, and track where the next 1062 * extended partition is in case we need it. We 1063 * are expecting only one extended partition. If 1064 * there is more than one we'll only go to the 1065 * first one we see, but warn about ignoring. 1066 */ 1067 numDrives = 0; 1068 for (i = 0; i < FD_NUMPART; i++) { 1069 if (isDosDrive(dosp[i].systid)) { 1070 extndDrives[numDrives++] = i; 1071 } else if (isDosExtended(dosp[i].systid)) { 1072 if (diskblk != lastseek) { 1073 /* 1074 * Already found an extended 1075 * partition in this table. 1076 */ 1077 cmn_err(CE_NOTE, 1078 "!pcfs: ignoring unexpected" 1079 " additional extended" 1080 " partition"); 1081 } else { 1082 diskblk = xstartsect + 1083 ltohi(dosp[i].relsect); 1084 } 1085 } 1086 } 1087 } while (ldrive > logicalDriveCount + numDrives); 1088 1089 if (ldrive <= logicalDriveCount + numDrives) { 1090 /* 1091 * The number of logical drives we've found thus 1092 * far is enough to get us to the one we were 1093 * searching for. 1094 */ 1095 driveIndex = logicalDriveCount + numDrives - ldrive; 1096 *sysid = dosp[extndDrives[driveIndex]].systid; 1097 *startSector = 1098 ltohi(dosp[extndDrives[driveIndex]].relsect) + 1099 lastseek; 1100 if (*startSector > (xstartsect + xnumsect)) { 1101 cmn_err(CE_NOTE, "!pcfs: extended partition " 1102 "values bad"); 1103 return (EINVAL); 1104 } 1105 return (0); 1106 } else { 1107 /* 1108 * We ran out of extended dos partition 1109 * drives. The only hope now is to go 1110 * back to extra drives defined in the master 1111 * fdisk table. But we overwrote that table 1112 * already, so we must load it in again. 1113 */ 1114 logicalDriveCount += numDrives; 1115 brelse(*bp); 1116 *bp = bread(dev, (daddr_t)0, PC_SAFESECSIZE); 1117 if ((*bp)->b_flags & B_ERROR) { 1118 PC_DPRINTF0(1, "pc_getfattype: read error\n"); 1119 return (EIO); 1120 } 1121 dosp_ptr = (struct mboot *)(*bp)->b_un.b_addr; 1122 bcopy(dosp_ptr->parts, dosp, 1123 sizeof (struct ipart) * FD_NUMPART); 1124 } 1125 } 1126 /* 1127 * Still haven't found the drive, is it an extra 1128 * drive defined in the main FDISK table? 1129 */ 1130 if (ldrive <= logicalDriveCount + numExtraDrives) { 1131 driveIndex = logicalDriveCount + numExtraDrives - ldrive; 1132 ASSERT(driveIndex < MIN(numExtraDrives, FD_NUMPART)); 1133 *sysid = dosp[extraDrives[driveIndex]].systid; 1134 *startSector = ltohi(dosp[extraDrives[driveIndex]].relsect); 1135 return (0); 1136 } 1137 /* 1138 * Still haven't found the drive, and there is 1139 * nowhere else to look. 1140 */ 1141 noLogicalDrive(ldrive); 1142 return (EINVAL); 1143 } 1144 1145 /* 1146 * FAT12/FAT16 specific consistency checks. 1147 */ 1148 static int 1149 check_bpb_fat16(struct bootsec *bpb) 1150 { 1151 if (pcfsdebuglevel >= 5) { 1152 PC_DPRINTF1(5, "check_bpb_fat: RootEntCount = %d", 1153 ltohs(bpb->rdirents[0])); 1154 PC_DPRINTF1(5, "check_bpb_fat16: TotSec16 = %d", 1155 ltohs(bpb->numsect[0])); 1156 PC_DPRINTF1(5, "check_bpb_fat16: FATSz16 = %d", 1157 ltohs(bpb->fatsec)); 1158 PC_DPRINTF1(5, "check_bpb_fat16: TotSec32 = %d", 1159 ltohi(bpb->totalsec)); 1160 } 1161 return (ltohs(bpb->rdirents[0]) > 0 && /* RootEntCnt > 0 */ 1162 ((ltohs(bpb->numsect[0]) == 0 && /* TotSec16 == 0 */ 1163 ltohi(bpb->totalsec) > 0) || /* TotSec32 > 0 */ 1164 ltohs(bpb->numsect[0]) > 0) && /* TotSec16 > 0 */ 1165 ltohs(bpb->fatsec) > 0); /* FatSz16 > 0 */ 1166 } 1167 1168 /* 1169 * FAT32 specific consistency checks. 1170 */ 1171 static int 1172 check_bpb_fat32(struct fat32_bootsec *bpb) 1173 { 1174 if (pcfsdebuglevel >= 5) { 1175 PC_DPRINTF1(5, "check_bpb_fat32: RootEntCount = %d", 1176 ltohs(bpb->f_bs.rdirents[0])); 1177 PC_DPRINTF1(5, "check_bpb_fat32: TotSec16 = %d", 1178 ltohs(bpb->f_bs.numsect[0])); 1179 PC_DPRINTF1(5, "check_bpb_fat32: FATSz16 = %d", 1180 ltohs(bpb->f_bs.fatsec)); 1181 PC_DPRINTF1(5, "check_bpb_fat32: TotSec32 = %d", 1182 ltohi(bpb->f_bs.totalsec)); 1183 PC_DPRINTF1(5, "check_bpb_fat32: FATSz32 = %d", 1184 ltohi(bpb->f_fatlength)); 1185 } 1186 return (ltohs(bpb->f_bs.rdirents[0]) == 0 && 1187 ltohs(bpb->f_bs.numsect[0]) == 0 && 1188 ltohs(bpb->f_bs.fatsec) == 0 && 1189 ltohi(bpb->f_bs.totalsec) > 0 && 1190 ltohi(bpb->f_fatlength) > 0); 1191 } 1192 1193 /* 1194 * Calculate the number of clusters in order to determine 1195 * the type of FAT we are looking at. This is the only 1196 * recommended way of determining FAT type, though there 1197 * are other hints in the data, this is the best way. 1198 */ 1199 static ulong_t 1200 bpb_to_numclusters(uchar_t *cp) 1201 { 1202 struct fat32_bootsec *bpb; 1203 1204 ulong_t rootdirsectors; 1205 ulong_t FATsz; 1206 ulong_t TotSec; 1207 ulong_t DataSec; 1208 ulong_t CountOfClusters; 1209 char FileSysType[9]; 1210 1211 /* 1212 * Cast it to FAT32 bpb. If it turns out to be FAT12/16, its 1213 * OK, we won't try accessing the data beyond the FAT16 header 1214 * boundary. 1215 */ 1216 bpb = (struct fat32_bootsec *)cp; 1217 1218 if (pcfsdebuglevel >= 5) { 1219 if (ltohs(bpb->f_bs.rdirents[0]) != 0) { 1220 (void) memcpy(FileSysType, &cp[54], 8); 1221 FileSysType[8] = 0; 1222 PC_DPRINTF1(5, "debug_bpb: FAT12/FAT16 FileSysType = " 1223 "%s", FileSysType); 1224 } 1225 } 1226 1227 rootdirsectors = ((ltohs(bpb->f_bs.rdirents[0]) * 32) + 1228 (ltohs(bpb->f_bs.bps[0]) - 1)) / ltohs(bpb->f_bs.bps[0]); 1229 1230 if (ltohs(bpb->f_bs.fatsec) != 0) 1231 FATsz = ltohs(bpb->f_bs.fatsec); 1232 else 1233 FATsz = ltohi(bpb->f_fatlength); 1234 1235 if (ltohs(bpb->f_bs.numsect[0]) != 0) 1236 TotSec = ltohs(bpb->f_bs.numsect[0]); 1237 else 1238 TotSec = ltohi(bpb->f_bs.totalsec); 1239 1240 DataSec = TotSec - (ltohs(bpb->f_bs.res_sec[0]) + 1241 (bpb->f_bs.nfat * FATsz) + rootdirsectors); 1242 1243 CountOfClusters = DataSec / bpb->f_bs.spcl; 1244 1245 PC_DPRINTF1(5, "debug_bpb: CountOfClusters = %ld", CountOfClusters); 1246 1247 return (CountOfClusters); 1248 1249 } 1250 1251 static int 1252 fattype(ulong_t CountOfClusters) 1253 { 1254 /* 1255 * From Microsoft: 1256 * In the following example, when it says <, it does not mean <=. 1257 * Note also that the numbers are correct. The first number for 1258 * FAT12 is 4085; the second number for FAT16 is 65525. These numbers 1259 * and the '<' signs are not wrong. 1260 */ 1261 1262 /* Watch for edge cases */ 1263 if ((CountOfClusters >= 4085 && CountOfClusters <= 4095) || 1264 (CountOfClusters >= 65525 && CountOfClusters <= 65535)) { 1265 PC_DPRINTF1(5, "debug_bpb: Cannot determine FAT yet - %ld", 1266 CountOfClusters); 1267 return (-1); /* Cannot be determined yet */ 1268 } else if (CountOfClusters < 4085) { 1269 /* Volume is FAT12 */ 1270 PC_DPRINTF0(5, "debug_bpb: This must be FAT12"); 1271 return (0); 1272 } else if (CountOfClusters < 65525) { 1273 /* Volume is FAT16 */ 1274 PC_DPRINTF0(5, "debug_bpb: This must be FAT16"); 1275 return (PCFS_FAT16); 1276 } else { 1277 /* Volume is FAT32 */ 1278 PC_DPRINTF0(5, "debug_bpb: This must be FAT32"); 1279 return (PCFS_FAT32); 1280 } 1281 } 1282 1283 #define VALID_SECSIZE(s) (s == 512 || s == 1024 || s == 2048 || s == 4096) 1284 1285 #define VALID_SPCL(s) (s == 1 || s == 2 || s == 4 || s == 8 || s == 16 ||\ 1286 s == 32 || s == 64 || s == 128) 1287 1288 static int 1289 secondaryBPBChecks(uchar_t *cp) 1290 { 1291 struct bootsec *bpb = (struct bootsec *)cp; 1292 struct fat32_bootsec *f32bpb = (struct fat32_bootsec *)cp; 1293 1294 /* 1295 * Perform secondary checks to try and determine what sort 1296 * of FAT partition we have based on other, less reliable, 1297 * data in the BPB header. 1298 */ 1299 if (ltohs(bpb->fatsec) != 0) { 1300 /* 1301 * Must be FAT12 or FAT16, check the 1302 * FilSysType string (not 100% reliable). 1303 */ 1304 if (!memcmp((cp + PCFS_TYPESTRING_OFFSET16), "FAT12", 5)) { 1305 PC_DPRINTF0(5, "secondaryBPBCheck says: FAT12"); 1306 return (0); /* FAT12 */ 1307 } else if (!memcmp((cp + PCFS_TYPESTRING_OFFSET16), "FAT16", 1308 5)) { 1309 PC_DPRINTF0(5, "secondaryBPBCheck says: FAT16"); 1310 return (PCFS_FAT16); 1311 } else { 1312 /* 1313 * Try to use the BPB_Media byte 1314 * 1315 * If the media byte indicates a floppy we'll 1316 * assume FAT12, otherwise we'll assume FAT16. 1317 */ 1318 switch (bpb->mediadesriptor) { 1319 case SS8SPT: 1320 case DS8SPT: 1321 case SS9SPT: 1322 case DS9SPT: 1323 case DS18SPT: 1324 case DS9_15SPT: 1325 PC_DPRINTF0(5, 1326 "secondaryBPBCheck says: FAT12"); 1327 return (0); /* FAT12 */ 1328 case MD_FIXED: 1329 PC_DPRINTF0(5, 1330 "secondaryBPBCheck says: FAT16"); 1331 return (PCFS_FAT16); 1332 default: 1333 cmn_err(CE_NOTE, 1334 "!pcfs: unknown FAT type"); 1335 return (-1); 1336 } 1337 } 1338 } else if (ltohi(f32bpb->f_fatlength) > 0) { 1339 PC_DPRINTF0(5, "secondaryBPBCheck says: FAT32"); 1340 return (PCFS_FAT32); 1341 } else { 1342 /* We don't know */ 1343 PC_DPRINTF0(5, "secondaryBPBCheck says: unknown!!"); 1344 return (-1); 1345 } 1346 } 1347 1348 /* 1349 * Check to see if the BPB we found is correct. 1350 * 1351 * First, look for obvious, tell-tale signs of trouble: 1352 * The NumFATs value should always be 2. Sometimes it can be a '1' 1353 * on FLASH memory cards and other non-disk-based media, so we 1354 * will allow that as well. 1355 * 1356 * We also look at the Media byte, the valid range is 0xF0, or 1357 * 0xF8 thru 0xFF, anything else means this is probably not a good 1358 * BPB. 1359 * 1360 * Finally, check the BPB Magic number at the end of the 512 byte 1361 * block, it must be 0xAA55. 1362 * 1363 * If that all is good, calculate the number of clusters and 1364 * do some final verification steps. 1365 * 1366 * If all is well, return success (1) and set the fattypep value to the 1367 * correct FAT value if the caller provided a pointer to store it in. 1368 */ 1369 static int 1370 isBPB(uchar_t *cp, int *fattypep) 1371 { 1372 struct bootsec *bpb = (struct bootsec *)cp; 1373 int type; 1374 1375 uint_t numclusters; /* number of clusters in file area */ 1376 ushort_t secsize = (int)ltohs(bpb->bps[0]); 1377 1378 if (pcfsdebuglevel >= 3) { 1379 if (!VALID_SECSIZE(secsize)) 1380 PC_DPRINTF1(3, "check_bpb: invalid bps value %d", 1381 secsize); 1382 1383 if (!VALID_SPCL(bpb->spcl)) 1384 PC_DPRINTF1(3, "check_bpb: invalid spcl value %d", 1385 bpb->spcl); 1386 1387 if ((secsize * bpb->spcl) >= (32 * 1024)) 1388 PC_DPRINTF3(3, "check_bpb: BPC > 32K %d x %d = %d", 1389 secsize, 1390 bpb->spcl, 1391 secsize * bpb->spcl); 1392 1393 if (bpb->nfat == 0) 1394 PC_DPRINTF1(3, "check_bpb: bad NumFATs value %d", 1395 bpb->nfat); 1396 1397 if (ltohs(bpb->res_sec[0]) == 0) 1398 PC_DPRINTF1(3, "check_bpb: bad RsvdSecCnt value %d", 1399 ltohs(bpb->res_sec[0])); 1400 1401 PC_DPRINTF1(5, "check_bpb: Media byte = %02x", 1402 bpb->mediadesriptor); 1403 1404 } 1405 if ((bpb->nfat == 0) || 1406 (bpb->mediadesriptor != 0xF0 && bpb->mediadesriptor < 0xF8) || 1407 (ltohs(cp[510]) != MBB_MAGIC) || 1408 !VALID_SECSIZE(secsize) || 1409 !VALID_SPCL(bpb->spcl) || 1410 (secsize * bpb->spcl > (64 * 1024)) || 1411 !(ltohs(bpb->res_sec[0]))) 1412 return (0); 1413 1414 /* 1415 * Basic sanity checks passed so far, now try to determine which 1416 * FAT format to use. 1417 */ 1418 numclusters = bpb_to_numclusters(cp); 1419 1420 type = fattype(numclusters); 1421 1422 /* Do some final sanity checks for each specific type of FAT */ 1423 switch (type) { 1424 case 0: /* FAT12 */ 1425 case PCFS_FAT16: 1426 if (!check_bpb_fat16((struct bootsec *)cp)) 1427 return (0); 1428 break; 1429 case PCFS_FAT32: 1430 if (!check_bpb_fat32((struct fat32_bootsec *)cp)) 1431 return (0); 1432 break; 1433 default: /* not sure yet */ 1434 type = secondaryBPBChecks(cp); 1435 if (type == -1) { 1436 /* Still nothing, give it up. */ 1437 return (0); 1438 } 1439 break; 1440 } 1441 1442 if (fattypep) 1443 *fattypep = type; 1444 1445 PC_DPRINTF0(5, "isBPB: BPB passes verification tests"); 1446 return (1); 1447 } 1448 1449 1450 /* 1451 * Get the FAT type for the DOS medium. 1452 * 1453 * ------------------------- 1454 * According to Microsoft: 1455 * The FAT type one of FAT12, FAT16, or FAT32 is determined by the 1456 * count of clusters on the volume and nothing else. 1457 * ------------------------- 1458 * 1459 */ 1460 static int 1461 pc_getfattype( 1462 struct vnode *devvp, 1463 int ldrive, 1464 daddr_t *strtsectp, 1465 int *fattypep) 1466 { 1467 buf_t *bp = NULL; /* Disk buffer pointer */ 1468 int err = 0; 1469 uchar_t sysid = 0; /* System ID character */ 1470 dev_t dev = devvp->v_rdev; 1471 1472 1473 /* 1474 * Open the device so we can check out the BPB or FDISK table, 1475 * then read in the sector. 1476 */ 1477 PC_DPRINTF2(5, "pc_getfattype: dev=%x ldrive=%x ", (int)dev, ldrive); 1478 if (err = VOP_OPEN(&devvp, FREAD, CRED())) { 1479 PC_DPRINTF1(1, "pc_getfattype: open error=%d\n", err); 1480 return (err); 1481 } 1482 1483 /* 1484 * Unpartitioned media (floppies and some removeable devices) 1485 * don't have a partition table, the FAT BPB is at disk block 0. 1486 * Start out by reading block 0. 1487 */ 1488 *strtsectp = (daddr_t)0; 1489 bp = bread(dev, *strtsectp, PC_SAFESECSIZE); 1490 1491 if (bp->b_flags & B_ERROR) { 1492 PC_DPRINTF2(1, "pc_getfattype: read error on " 1493 "device %d, disk LBA %d\n", (int)dev, (int)*strtsectp); 1494 err = EIO; 1495 goto out; 1496 } 1497 1498 /* 1499 * If a logical drive number is requested, parse the partition table 1500 * and attempt to locate it. Otherwise, proceed immediately to the 1501 * BPB check. findTheDrive(), if successful, returns the disk block 1502 * number where the requested partition starts in "strtsecp". 1503 */ 1504 if (ldrive != 0) { 1505 PC_DPRINTF0(5, "pc_getfattype: using FDISK table to find BPB"); 1506 1507 if (err = findTheDrive(dev, ldrive, &bp, strtsectp, &sysid)) 1508 goto out; 1509 1510 brelse(bp); 1511 bp = bread(dev, *strtsectp, PC_SAFESECSIZE); 1512 if (bp->b_flags & B_ERROR) { 1513 PC_DPRINTF2(1, "pc_getfattype: read error on " 1514 "device %d, disk LBA %d\n", 1515 (int)dev, (int)*strtsectp); 1516 err = EIO; 1517 goto out; 1518 } 1519 } 1520 1521 if (!isBPB((uchar_t *)bp->b_un.b_addr, fattypep)) { 1522 PC_DPRINTF2(1, "pc_getfattype: No FAT BPB on device %d, " 1523 "disk LBA %d\n", (int)dev, (int)*strtsectp); 1524 err = EIO; 1525 goto out; 1526 } 1527 1528 out: 1529 /* 1530 * Release the buffer used 1531 */ 1532 if (bp != NULL) 1533 brelse(bp); 1534 (void) VOP_CLOSE(devvp, FREAD, 1, (offset_t)0, CRED()); 1535 return (err); 1536 } 1537 1538 1539 /* 1540 * Get the boot parameter block and file allocation table. 1541 * If there is an old FAT, invalidate it. 1542 */ 1543 int 1544 pc_getfat(struct pcfs *fsp) 1545 { 1546 struct vfs *vfsp = PCFSTOVFS(fsp); 1547 struct buf *tp = 0; 1548 struct buf *bp = 0; 1549 uchar_t *fatp = NULL; 1550 uchar_t *fat_changemap = NULL; 1551 struct bootsec *bootp; 1552 struct fat32_bootsec *f32b; 1553 struct vnode *devvp; 1554 int error; 1555 int fatsize; 1556 int fat_changemapsize; 1557 int flags = 0; 1558 int nfat; 1559 int secsize; 1560 int fatsec; 1561 1562 PC_DPRINTF0(5, "pc_getfat\n"); 1563 devvp = fsp->pcfs_devvp; 1564 if (fsp->pcfs_fatp) { 1565 /* 1566 * There is a FAT in core. 1567 * If there are open file pcnodes or we have modified it or 1568 * it hasn't timed out yet use the in core FAT. 1569 * Otherwise invalidate it and get a new one 1570 */ 1571 #ifdef notdef 1572 if (fsp->pcfs_frefs || 1573 (fsp->pcfs_flags & PCFS_FATMOD) || 1574 (gethrestime_sec() < fsp->pcfs_fattime)) { 1575 return (0); 1576 } else { 1577 mutex_enter(&pcfslock); 1578 pc_invalfat(fsp); 1579 mutex_exit(&pcfslock); 1580 } 1581 #endif /* notdef */ 1582 return (0); 1583 } 1584 /* 1585 * Open block device mounted on. 1586 */ 1587 error = VOP_OPEN(&devvp, 1588 (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE, 1589 CRED()); 1590 if (error) { 1591 PC_DPRINTF1(1, "pc_getfat: open error=%d\n", error); 1592 return (error); 1593 } 1594 /* 1595 * Get boot parameter block and check it for validity 1596 */ 1597 tp = bread(fsp->pcfs_xdev, fsp->pcfs_dosstart, PC_SAFESECSIZE); 1598 if ((tp->b_flags & (B_ERROR | B_STALE)) || 1599 !isBPB((uchar_t *)tp->b_un.b_addr, NULL)) { 1600 PC_DPRINTF2(1, "pc_getfat: boot block error on device %d, " 1601 "disk LBA %d\n", 1602 (int)fsp->pcfs_xdev, (int)fsp->pcfs_dosstart); 1603 flags = tp->b_flags & B_ERROR; 1604 error = EIO; 1605 goto out; 1606 } 1607 tp->b_flags |= B_STALE | B_AGE; 1608 bootp = (struct bootsec *)tp->b_un.b_addr; 1609 1610 1611 /* get the sector size - may be more than 512 bytes */ 1612 secsize = (int)ltohs(bootp->bps[0]); 1613 /* check for bogus sector size - fat should be at least 1 sector */ 1614 if (IS_FAT32(fsp)) { 1615 f32b = (struct fat32_bootsec *)bootp; 1616 fatsec = ltohi(f32b->f_fatlength); 1617 } else { 1618 fatsec = ltohs(bootp->fatsec); 1619 } 1620 if (secsize < 512 || fatsec < 1 || bootp->nfat < 1) { 1621 cmn_err(CE_NOTE, "!pcfs: FAT size error"); 1622 error = EINVAL; 1623 goto out; 1624 } 1625 1626 switch (bootp->mediadesriptor) { 1627 default: 1628 cmn_err(CE_NOTE, "!pcfs: media-descriptor error, 0x%x", 1629 bootp->mediadesriptor); 1630 error = EINVAL; 1631 goto out; 1632 1633 case MD_FIXED: 1634 /* 1635 * PCMCIA pseudo floppy is type MD_FIXED, 1636 * but is accessed like a floppy 1637 */ 1638 if (!(fsp->pcfs_flags & PCFS_PCMCIA_NO_CIS)) { 1639 fsp->pcfs_flags |= PCFS_NOCHK; 1640 } 1641 /* FALLTHRU */ 1642 case SS8SPT: 1643 case DS8SPT: 1644 case SS9SPT: 1645 case DS9SPT: 1646 case DS18SPT: 1647 case DS9_15SPT: 1648 fsp->pcfs_secsize = secsize; 1649 fsp->pcfs_sdshift = secsize / DEV_BSIZE - 1; 1650 fsp->pcfs_entps = secsize / sizeof (struct pcdir); 1651 fsp->pcfs_spcl = (int)bootp->spcl; 1652 fsp->pcfs_fatsec = fatsec; 1653 fsp->pcfs_spt = (int)ltohs(bootp->spt); 1654 fsp->pcfs_rdirsec = ((int)ltohs(bootp->rdirents[0]) 1655 * sizeof (struct pcdir) + (secsize - 1)) / secsize; 1656 fsp->pcfs_clsize = fsp->pcfs_spcl * secsize; 1657 fsp->pcfs_fatstart = fsp->pcfs_dosstart + 1658 (daddr_t)ltohs(bootp->res_sec[0]); 1659 fsp->pcfs_rdirstart = fsp->pcfs_fatstart + 1660 (bootp->nfat * fsp->pcfs_fatsec); 1661 fsp->pcfs_datastart = fsp->pcfs_rdirstart + fsp->pcfs_rdirsec; 1662 if (IS_FAT32(fsp)) 1663 fsp->pcfs_rdirstart = ltohi(f32b->f_rootcluster); 1664 fsp->pcfs_ncluster = (((int)(ltohs(bootp->numsect[0]) ? 1665 ltohs(bootp->numsect[0]) : ltohi(bootp->totalsec))) - 1666 fsp->pcfs_datastart + fsp->pcfs_dosstart) / fsp->pcfs_spcl; 1667 fsp->pcfs_numfat = (int)bootp->nfat; 1668 fsp->pcfs_nxfrecls = PCF_FIRSTCLUSTER; 1669 break; 1670 } 1671 1672 /* 1673 * Get FAT and check it for validity 1674 */ 1675 fatsize = fsp->pcfs_fatsec * fsp->pcfs_secsize; 1676 fatp = kmem_alloc(fatsize, KM_SLEEP); 1677 error = pc_readfat(fsp, fatp, fsp->pcfs_fatstart, fatsize); 1678 if (error) { 1679 flags = B_ERROR; 1680 goto out; 1681 } 1682 fat_changemapsize = (fatsize / fsp->pcfs_clsize) + 1; 1683 fat_changemap = kmem_zalloc(fat_changemapsize, KM_SLEEP); 1684 1685 /* 1686 * The only definite signature check is that the 1687 * media descriptor byte should match the first byte 1688 * of the FAT block. 1689 */ 1690 if (fatp[0] != bootp->mediadesriptor) { 1691 cmn_err(CE_NOTE, "!pcfs: FAT signature error"); 1692 error = EINVAL; 1693 goto out; 1694 } 1695 /* 1696 * Checking for fatsec and number of supported clusters, should 1697 * actually determine a FAT12/FAT media. 1698 */ 1699 if (fsp->pcfs_flags & PCFS_FAT16) { 1700 if ((fsp->pcfs_fatsec <= 12) && 1701 ((fatsize * 2 / 3) >= fsp->pcfs_ncluster)) { 1702 /* 1703 * We have a 12-bit FAT, rather than a 16-bit FAT. 1704 * Ignore what the fdisk table says. 1705 */ 1706 PC_DPRINTF0(2, "pc_getfattype: forcing 12-bit FAT\n"); 1707 fsp->pcfs_flags &= ~PCFS_FAT16; 1708 } 1709 } 1710 /* 1711 * Sanity check our FAT is large enough for the 1712 * clusters we think we have. 1713 */ 1714 if ((fsp->pcfs_flags & PCFS_FAT16) && 1715 ((fatsize / 2) < fsp->pcfs_ncluster)) { 1716 cmn_err(CE_NOTE, "!pcfs: FAT too small for number of clusters"); 1717 error = EINVAL; 1718 goto out; 1719 } 1720 1721 /* 1722 * Get alternate FATs and check for consistency 1723 * This is an inlined version of pc_readfat(). 1724 * Since we're only comparing FAT and alternate FAT, 1725 * there's no reason to let pc_readfat() copy data out 1726 * of the buf. Instead, compare in-situ, one cluster 1727 * at a time. 1728 */ 1729 for (nfat = 1; nfat < fsp->pcfs_numfat; nfat++) { 1730 size_t startsec; 1731 size_t off; 1732 1733 startsec = fsp->pcfs_fatstart + nfat * fsp->pcfs_fatsec; 1734 1735 for (off = 0; off < fatsize; off += fsp->pcfs_clsize) { 1736 bp = bread(fsp->pcfs_xdev, pc_dbdaddr(fsp, 1737 startsec + 1738 pc_cltodb(fsp, pc_lblkno(fsp, off))), 1739 MIN(fsp->pcfs_clsize, fatsize - off)); 1740 if (bp->b_flags & (B_ERROR | B_STALE)) { 1741 cmn_err(CE_NOTE, 1742 "!pcfs: alternate FAT #%d read error" 1743 " at byte %ld", nfat, off); 1744 flags = B_ERROR; 1745 error = EIO; 1746 goto out; 1747 } 1748 bp->b_flags |= B_STALE | B_AGE; 1749 if (bcmp(bp->b_un.b_addr, 1750 fatp + off, 1751 MIN(fsp->pcfs_clsize, fatsize - off))) { 1752 cmn_err(CE_NOTE, 1753 "!pcfs: alternate FAT #%d corrupted" 1754 " at byte %ld", nfat, off); 1755 flags = B_ERROR; 1756 } 1757 brelse(bp); 1758 bp = NULL; /* prevent double release */ 1759 } 1760 } 1761 1762 fsp->pcfs_fatsize = fatsize; 1763 fsp->pcfs_fatp = fatp; 1764 fsp->pcfs_fat_changemapsize = fat_changemapsize; 1765 fsp->pcfs_fat_changemap = fat_changemap; 1766 fsp->pcfs_fattime = gethrestime_sec() + PCFS_DISKTIMEOUT; 1767 fsp->pcfs_fatjustread = 1; 1768 1769 brelse(tp); 1770 tp = NULL; 1771 if (IS_FAT32(fsp)) { 1772 /* get fsinfo */ 1773 struct fat32_boot_fsinfo fsinfo_disk; 1774 1775 fsp->f32fsinfo_sector = ltohs(f32b->f_infosector); 1776 tp = bread(fsp->pcfs_xdev, 1777 fsp->pcfs_dosstart + pc_dbdaddr(fsp, fsp->f32fsinfo_sector), 1778 PC_SAFESECSIZE); 1779 if (tp->b_flags & (B_ERROR | B_STALE)) { 1780 cmn_err(CE_NOTE, "!pcfs: error reading fat32 fsinfo"); 1781 flags = tp->b_flags & B_ERROR; 1782 brelse(tp); 1783 tp = NULL; 1784 error = EIO; 1785 goto out; 1786 } 1787 tp->b_flags |= B_STALE | B_AGE; 1788 bcopy((void *)(tp->b_un.b_addr + FAT32_BOOT_FSINFO_OFF), 1789 &fsinfo_disk, sizeof (struct fat32_boot_fsinfo)); 1790 brelse(tp); 1791 tp = NULL; 1792 1793 /* translated fields */ 1794 fsp->fsinfo_native.fs_signature = 1795 ltohi(fsinfo_disk.fs_signature); 1796 fsp->fsinfo_native.fs_free_clusters = 1797 ltohi(fsinfo_disk.fs_free_clusters); 1798 if (fsp->fsinfo_native.fs_signature != FAT32_FS_SIGN) { 1799 cmn_err(CE_NOTE, 1800 "!pcfs: fat32 fsinfo signature mismatch."); 1801 error = EINVAL; 1802 goto out; 1803 } 1804 } 1805 1806 return (0); 1807 1808 out: 1809 cmn_err(CE_NOTE, "!pcfs: illegal disk format"); 1810 if (tp) 1811 brelse(tp); 1812 if (bp) 1813 brelse(bp); 1814 if (fatp) 1815 kmem_free(fatp, fatsize); 1816 if (fat_changemap) 1817 kmem_free(fat_changemap, fat_changemapsize); 1818 1819 if (flags) { 1820 pc_mark_irrecov(fsp); 1821 } 1822 (void) VOP_CLOSE(devvp, (vfsp->vfs_flag & VFS_RDONLY) ? 1823 FREAD : FREAD|FWRITE, 1, (offset_t)0, CRED()); 1824 return (error); 1825 } 1826 1827 int 1828 pc_syncfat(struct pcfs *fsp) 1829 { 1830 struct buf *bp; 1831 int nfat; 1832 int error; 1833 struct fat32_boot_fsinfo fsinfo_disk; 1834 1835 PC_DPRINTF0(7, "pcfs_syncfat\n"); 1836 if ((fsp->pcfs_fatp == (uchar_t *)0) || 1837 !(fsp->pcfs_flags & PCFS_FATMOD)) 1838 return (0); 1839 /* 1840 * write out all copies of FATs 1841 */ 1842 fsp->pcfs_flags &= ~PCFS_FATMOD; 1843 fsp->pcfs_fattime = gethrestime_sec() + PCFS_DISKTIMEOUT; 1844 for (nfat = 0; nfat < fsp->pcfs_numfat; nfat++) { 1845 error = pc_writefat(fsp, 1846 fsp->pcfs_fatstart + nfat*fsp->pcfs_fatsec); 1847 if (error) { 1848 pc_mark_irrecov(fsp); 1849 return (EIO); 1850 } 1851 } 1852 pc_clear_fatchanges(fsp); 1853 PC_DPRINTF0(6, "pcfs_syncfat: wrote out FAT\n"); 1854 /* write out fsinfo */ 1855 if (IS_FAT32(fsp)) { 1856 bp = bread(fsp->pcfs_xdev, 1857 fsp->pcfs_dosstart + pc_dbdaddr(fsp, fsp->f32fsinfo_sector), 1858 PC_SAFESECSIZE); 1859 if (bp->b_flags & (B_ERROR | B_STALE)) { 1860 brelse(bp); 1861 return (EIO); 1862 } 1863 bcopy((void *)(bp->b_un.b_addr + FAT32_BOOT_FSINFO_OFF), 1864 &fsinfo_disk, sizeof (struct fat32_boot_fsinfo)); 1865 /* translate fields */ 1866 fsinfo_disk.fs_free_clusters = 1867 htoli(fsp->fsinfo_native.fs_free_clusters); 1868 fsinfo_disk.fs_next_cluster = (uint32_t)FSINFO_UNKNOWN; 1869 bcopy(&fsinfo_disk, 1870 (void *)(bp->b_un.b_addr + FAT32_BOOT_FSINFO_OFF), 1871 sizeof (struct fat32_boot_fsinfo)); 1872 bwrite2(bp); 1873 error = geterror(bp); 1874 brelse(bp); 1875 if (error) { 1876 pc_mark_irrecov(fsp); 1877 return (EIO); 1878 } 1879 } 1880 return (0); 1881 } 1882 1883 void 1884 pc_invalfat(struct pcfs *fsp) 1885 { 1886 struct pcfs *xfsp; 1887 int mount_cnt = 0; 1888 1889 PC_DPRINTF0(7, "pc_invalfat\n"); 1890 if (fsp->pcfs_fatp == (uchar_t *)0) 1891 panic("pc_invalfat"); 1892 /* 1893 * Release FAT 1894 */ 1895 kmem_free(fsp->pcfs_fatp, fsp->pcfs_fatsize); 1896 fsp->pcfs_fatp = NULL; 1897 kmem_free(fsp->pcfs_fat_changemap, fsp->pcfs_fat_changemapsize); 1898 fsp->pcfs_fat_changemap = NULL; 1899 /* 1900 * Invalidate all the blocks associated with the device. 1901 * Not needed if stateless. 1902 */ 1903 for (xfsp = pc_mounttab; xfsp; xfsp = xfsp->pcfs_nxt) 1904 if (xfsp != fsp && xfsp->pcfs_xdev == fsp->pcfs_xdev) 1905 mount_cnt++; 1906 1907 if (!mount_cnt) 1908 binval(fsp->pcfs_xdev); 1909 /* 1910 * close mounted device 1911 */ 1912 (void) VOP_CLOSE(fsp->pcfs_devvp, 1913 (PCFSTOVFS(fsp)->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE, 1914 1, (offset_t)0, CRED()); 1915 } 1916 1917 void 1918 pc_badfs(struct pcfs *fsp) 1919 { 1920 cmn_err(CE_WARN, "corrupted PC file system on dev %x.%x\n", 1921 getmajor(fsp->pcfs_devvp->v_rdev), 1922 getminor(fsp->pcfs_devvp->v_rdev)); 1923 } 1924 1925 /* 1926 * The problem with supporting NFS on the PCFS filesystem is that there 1927 * is no good place to keep the generation number. The only possible 1928 * place is inside a directory entry. There are a few words that we 1929 * don't use - they store NT & OS/2 attributes, and the creation/last access 1930 * time of the file - but it seems wrong to use them. In addition, directory 1931 * entries come and go. If a directory is removed completely, its directory 1932 * blocks are freed and the generation numbers are lost. Whereas in ufs, 1933 * inode blocks are dedicated for inodes, so the generation numbers are 1934 * permanently kept on the disk. 1935 */ 1936 static int 1937 pcfs_vget(struct vfs *vfsp, struct vnode **vpp, struct fid *fidp) 1938 { 1939 struct pcnode *pcp; 1940 struct pc_fid *pcfid; 1941 struct pcfs *fsp; 1942 struct pcdir *ep; 1943 daddr_t eblkno; 1944 int eoffset; 1945 struct buf *bp; 1946 int error; 1947 pc_cluster32_t cn; 1948 1949 pcfid = (struct pc_fid *)fidp; 1950 fsp = VFSTOPCFS(vfsp); 1951 1952 error = pc_lockfs(fsp, 0, 0); 1953 if (error) { 1954 *vpp = NULL; 1955 return (error); 1956 } 1957 1958 if (pcfid->pcfid_block == 0) { 1959 pcp = pc_getnode(fsp, (daddr_t)0, 0, (struct pcdir *)0); 1960 pcp->pc_flags |= PC_EXTERNAL; 1961 *vpp = PCTOV(pcp); 1962 pc_unlockfs(fsp); 1963 return (0); 1964 } 1965 eblkno = pcfid->pcfid_block; 1966 eoffset = pcfid->pcfid_offset; 1967 if ((pc_dbtocl(fsp, 1968 eblkno - fsp->pcfs_dosstart) >= fsp->pcfs_ncluster) || 1969 (eoffset > fsp->pcfs_clsize)) { 1970 pc_unlockfs(fsp); 1971 *vpp = NULL; 1972 return (EINVAL); 1973 } 1974 1975 if (eblkno >= fsp->pcfs_datastart || (eblkno-fsp->pcfs_rdirstart) 1976 < (fsp->pcfs_rdirsec & ~(fsp->pcfs_spcl - 1))) { 1977 bp = bread(fsp->pcfs_xdev, eblkno, fsp->pcfs_clsize); 1978 } else { 1979 bp = bread(fsp->pcfs_xdev, eblkno, 1980 (int)(fsp->pcfs_datastart - eblkno) * fsp->pcfs_secsize); 1981 } 1982 if (bp->b_flags & (B_ERROR | B_STALE)) { 1983 error = geterror(bp); 1984 brelse(bp); 1985 if (error) 1986 pc_mark_irrecov(fsp); 1987 *vpp = NULL; 1988 pc_unlockfs(fsp); 1989 return (error); 1990 } 1991 ep = (struct pcdir *)(bp->b_un.b_addr + eoffset); 1992 /* 1993 * Ok, if this is a valid file handle that we gave out, 1994 * then simply ensuring that the creation time matches, 1995 * the entry has not been deleted, and it has a valid first 1996 * character should be enough. 1997 * 1998 * Unfortunately, verifying that the <blkno, offset> _still_ 1999 * refers to a directory entry is not easy, since we'd have 2000 * to search _all_ directories starting from root to find it. 2001 * That's a high price to pay just in case somebody is forging 2002 * file handles. So instead we verify that as much of the 2003 * entry is valid as we can: 2004 * 2005 * 1. The starting cluster is 0 (unallocated) or valid 2006 * 2. It is not an LFN entry 2007 * 3. It is not hidden (unless mounted as such) 2008 * 4. It is not the label 2009 */ 2010 cn = pc_getstartcluster(fsp, ep); 2011 /* 2012 * if the starting cluster is valid, but not valid according 2013 * to pc_validcl(), force it to be to simplify the following if. 2014 */ 2015 if (cn == 0) 2016 cn = PCF_FIRSTCLUSTER; 2017 if (IS_FAT32(fsp)) { 2018 if (cn >= PCF_LASTCLUSTER32) 2019 cn = PCF_FIRSTCLUSTER; 2020 } else { 2021 if (cn >= PCF_LASTCLUSTER) 2022 cn = PCF_FIRSTCLUSTER; 2023 } 2024 if ((!pc_validcl(fsp, cn)) || 2025 (PCDL_IS_LFN(ep)) || 2026 (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) || 2027 ((ep->pcd_attr & PCA_LABEL) == PCA_LABEL)) { 2028 bp->b_flags |= B_STALE | B_AGE; 2029 brelse(bp); 2030 pc_unlockfs(fsp); 2031 return (EINVAL); 2032 } 2033 if ((ep->pcd_crtime.pct_time == pcfid->pcfid_ctime) && 2034 (ep->pcd_filename[0] != PCD_ERASED) && 2035 (pc_validchar(ep->pcd_filename[0]) || 2036 (ep->pcd_filename[0] == '.' && ep->pcd_filename[1] == '.'))) { 2037 pcp = pc_getnode(fsp, eblkno, eoffset, ep); 2038 pcp->pc_flags |= PC_EXTERNAL; 2039 *vpp = PCTOV(pcp); 2040 } else { 2041 *vpp = NULL; 2042 } 2043 bp->b_flags |= B_STALE | B_AGE; 2044 brelse(bp); 2045 pc_unlockfs(fsp); 2046 return (0); 2047 } 2048 2049 /* 2050 * if device is a PCMCIA pseudo floppy, return 1 2051 * otherwise, return 0 2052 */ 2053 static int 2054 pcfs_pseudo_floppy(dev_t rdev) 2055 { 2056 int error, err; 2057 struct dk_cinfo info; 2058 ldi_handle_t lh; 2059 ldi_ident_t li; 2060 2061 err = ldi_ident_from_mod(&modlinkage, &li); 2062 if (err) { 2063 PC_DPRINTF1(1, 2064 "pcfs_pseudo_floppy: ldi_ident_from_mod err=%d\n", err); 2065 return (0); 2066 } 2067 2068 err = ldi_open_by_dev(&rdev, OTYP_CHR, FREAD, CRED(), &lh, li); 2069 ldi_ident_release(li); 2070 if (err) { 2071 PC_DPRINTF1(1, 2072 "pcfs_pseudo_floppy: ldi_open err=%d\n", err); 2073 return (0); 2074 } 2075 2076 /* return value stored in err is purposfully ignored */ 2077 error = ldi_ioctl(lh, DKIOCINFO, (intptr_t)&info, FKIOCTL, 2078 CRED(), &err); 2079 2080 err = ldi_close(lh, FREAD, CRED()); 2081 if (err != 0) { 2082 PC_DPRINTF1(1, 2083 "pcfs_pseudo_floppy: ldi_close err=%d\n", err); 2084 return (0); 2085 } 2086 2087 if ((error == 0) && (info.dki_ctype == DKC_PCMCIA_MEM) && 2088 (info.dki_flags & DKI_PCMCIA_PFD)) 2089 return (1); 2090 else 2091 return (0); 2092 } 2093 2094 /* 2095 * Unfortunately, FAT32 fat's can be pretty big (On a 1 gig jaz drive, about 2096 * a meg), so we can't bread() it all in at once. This routine reads a 2097 * fat a chunk at a time. 2098 */ 2099 static int 2100 pc_readfat(struct pcfs *fsp, uchar_t *fatp, daddr_t start, size_t fatsize) 2101 { 2102 struct buf *bp; 2103 size_t off; 2104 size_t readsize; 2105 2106 readsize = fsp->pcfs_clsize; 2107 for (off = 0; off < fatsize; off += readsize, fatp += readsize) { 2108 if (readsize > (fatsize - off)) 2109 readsize = fatsize - off; 2110 bp = bread(fsp->pcfs_xdev, 2111 pc_dbdaddr(fsp, start + 2112 pc_cltodb(fsp, pc_lblkno(fsp, off))), 2113 readsize); 2114 if (bp->b_flags & (B_ERROR | B_STALE)) { 2115 brelse(bp); 2116 return (EIO); 2117 } 2118 bp->b_flags |= B_STALE | B_AGE; 2119 bcopy(bp->b_un.b_addr, fatp, readsize); 2120 brelse(bp); 2121 } 2122 return (0); 2123 } 2124 2125 /* 2126 * We write the FAT out a _lot_, in order to make sure that it 2127 * is up-to-date. But on a FAT32 system (large drive, small clusters) 2128 * the FAT might be a couple of megabytes, and writing it all out just 2129 * because we created or deleted a small file is painful (especially 2130 * since we do it for each alternate FAT too). So instead, for FAT16 and 2131 * FAT32 we only write out the bit that has changed. We don't clear 2132 * the 'updated' fields here because the caller might be writing out 2133 * several FATs, so the caller must use pc_clear_fatchanges() after 2134 * all FATs have been updated. 2135 */ 2136 static int 2137 pc_writefat(struct pcfs *fsp, daddr_t start) 2138 { 2139 struct buf *bp; 2140 size_t off; 2141 size_t writesize; 2142 int error; 2143 uchar_t *fatp = fsp->pcfs_fatp; 2144 size_t fatsize = fsp->pcfs_fatsize; 2145 2146 writesize = fsp->pcfs_clsize; 2147 for (off = 0; off < fatsize; off += writesize, fatp += writesize) { 2148 if (writesize > (fatsize - off)) 2149 writesize = fatsize - off; 2150 if (!pc_fat_is_changed(fsp, pc_lblkno(fsp, off))) { 2151 continue; 2152 } 2153 bp = ngeteblk(writesize); 2154 bp->b_edev = fsp->pcfs_xdev; 2155 bp->b_dev = cmpdev(bp->b_edev); 2156 bp->b_blkno = pc_dbdaddr(fsp, start + 2157 pc_cltodb(fsp, pc_lblkno(fsp, off))); 2158 bcopy(fatp, bp->b_un.b_addr, writesize); 2159 bwrite2(bp); 2160 error = geterror(bp); 2161 brelse(bp); 2162 if (error) { 2163 return (error); 2164 } 2165 } 2166 return (0); 2167 } 2168 2169 /* 2170 * Mark the FAT cluster that 'cn' is stored in as modified. 2171 */ 2172 void 2173 pc_mark_fat_updated(struct pcfs *fsp, pc_cluster32_t cn) 2174 { 2175 pc_cluster32_t bn; 2176 size_t size; 2177 2178 /* which fat block is the cluster number stored in? */ 2179 if (IS_FAT32(fsp)) { 2180 size = sizeof (pc_cluster32_t); 2181 bn = pc_lblkno(fsp, cn * size); 2182 fsp->pcfs_fat_changemap[bn] = 1; 2183 } else if (IS_FAT16(fsp)) { 2184 size = sizeof (pc_cluster16_t); 2185 bn = pc_lblkno(fsp, cn * size); 2186 fsp->pcfs_fat_changemap[bn] = 1; 2187 } else { 2188 offset_t off; 2189 pc_cluster32_t nbn; 2190 2191 ASSERT(IS_FAT12(fsp)); 2192 off = cn + (cn >> 1); 2193 bn = pc_lblkno(fsp, off); 2194 fsp->pcfs_fat_changemap[bn] = 1; 2195 /* does this field wrap into the next fat cluster? */ 2196 nbn = pc_lblkno(fsp, off + 1); 2197 if (nbn != bn) { 2198 fsp->pcfs_fat_changemap[nbn] = 1; 2199 } 2200 } 2201 } 2202 2203 /* 2204 * return whether the FAT cluster 'bn' is updated and needs to 2205 * be written out. 2206 */ 2207 int 2208 pc_fat_is_changed(struct pcfs *fsp, pc_cluster32_t bn) 2209 { 2210 return (fsp->pcfs_fat_changemap[bn] == 1); 2211 } 2212 2213 /* 2214 * Implementation of VFS_FREEVFS() to support forced umounts. 2215 * This is called by the vfs framework after umount, to trigger 2216 * the release of any resources still associated with the given 2217 * vfs_t once the need to keep them has gone away. 2218 */ 2219 void 2220 pcfs_freevfs(vfs_t *vfsp) 2221 { 2222 struct pcfs *fsp = VFSTOPCFS(vfsp); 2223 2224 mutex_enter(&pcfslock); 2225 if (fsp->pcfs_fatp != (uchar_t *)0) 2226 pc_invalfat(fsp); 2227 mutex_exit(&pcfslock); 2228 2229 VN_RELE(fsp->pcfs_devvp); 2230 mutex_destroy(&fsp->pcfs_lock); 2231 kmem_free(fsp, (uint_t)sizeof (struct pcfs)); 2232 2233 /* 2234 * Allow _fini() to succeed now, if so desired. 2235 */ 2236 atomic_dec_32(&pcfs_mountcount); 2237 } 2238