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