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/vol.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 v%I%", 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, pcfs_mount, 230 VFSNAME_UNMOUNT, pcfs_unmount, 231 VFSNAME_ROOT, pcfs_root, 232 VFSNAME_STATVFS, pcfs_statvfs, 233 VFSNAME_SYNC, (fs_generic_func_p) pcfs_sync, 234 VFSNAME_VGET, pcfs_vget, 235 VFSNAME_FREEVFS, (fs_generic_func_p) 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 *spnp; 295 char *data = uap->dataptr; 296 int datalen = uap->datalen; 297 int dos_ldrive = 0; 298 int error; 299 int fattype; 300 int spnlen; 301 int wantbootpart = 0; 302 struct vioc_info info; 303 int rval; /* set but not used */ 304 minor_t minor; 305 int oflag, aflag; 306 307 if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0) 308 return (error); 309 310 PC_DPRINTF0(4, "pcfs_mount\n"); 311 if (mvp->v_type != VDIR) { 312 return (ENOTDIR); 313 } 314 mutex_enter(&mvp->v_lock); 315 if ((uap->flags & MS_REMOUNT) == 0 && 316 (uap->flags & MS_OVERLAY) == 0 && 317 (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { 318 mutex_exit(&mvp->v_lock); 319 return (EBUSY); 320 } 321 mutex_exit(&mvp->v_lock); 322 323 /* 324 * The caller is responsible for making sure to always 325 * pass in sizeof(struct pcfs_args) (or the old one). 326 * Doing this is the only way to know an EINVAL return 327 * from mount(2) is due to the "not a DOS filesystem" 328 * EINVAL that pc_verify/pc_getfattype could return. 329 */ 330 if ((datalen != sizeof (struct pcfs_args)) && 331 (datalen != sizeof (struct old_pcfs_args))) { 332 return (EINVAL); 333 } else { 334 struct pcfs_args tmp_tz; 335 int hidden = 0; 336 int foldcase = 0; 337 int noclamptime = 0; 338 339 tmp_tz.flags = 0; 340 if (copyin(data, &tmp_tz, datalen)) { 341 return (EFAULT); 342 } 343 if (datalen == sizeof (struct pcfs_args)) { 344 hidden = tmp_tz.flags & PCFS_MNT_HIDDEN; 345 foldcase = tmp_tz.flags & PCFS_MNT_FOLDCASE; 346 noclamptime = tmp_tz.flags & PCFS_MNT_NOCLAMPTIME; 347 } 348 349 if (hidden) 350 vfs_setmntopt(vfsp, MNTOPT_PCFS_HIDDEN, NULL, 0); 351 if (foldcase) 352 vfs_setmntopt(vfsp, MNTOPT_PCFS_FOLDCASE, NULL, 0); 353 if (noclamptime) 354 vfs_setmntopt(vfsp, MNTOPT_PCFS_NOCLAMPTIME, NULL, 0); 355 /* 356 * more than one pc filesystem can be mounted on x86 357 * so the pc_tz structure is now a critical region 358 */ 359 mutex_enter(&pcfslock); 360 if (pc_mounttab == NULL) 361 bcopy(&tmp_tz, &pc_tz, sizeof (struct pcfs_args)); 362 mutex_exit(&pcfslock); 363 } 364 /* 365 * Resolve path name of special file being mounted. 366 */ 367 if (error = pn_get(uap->spec, UIO_USERSPACE, &special)) { 368 return (error); 369 } 370 if (error = 371 lookupname(special.pn_path, UIO_SYSSPACE, FOLLOW, NULLVPP, &bvp)) { 372 /* 373 * look for suffix to special 374 * which indicates a request to mount the solaris boot 375 * partition, or a DOS logical drive on the hard disk 376 */ 377 spnlen = special.pn_pathlen; 378 379 if (spnlen > 5) { 380 spnp = special.pn_path + spnlen - 5; 381 if (*spnp++ == ':' && *spnp++ == 'b' && 382 *spnp++ == 'o' && *spnp++ == 'o' && 383 *spnp++ == 't') { 384 /* 385 * Looks as if they want to mount 386 * the Solaris boot partition 387 */ 388 wantbootpart = 1; 389 dos_ldrive = BOOT_PARTITION_DRIVE; 390 spnp = special.pn_path + spnlen - 5; 391 *spnp = '\0'; 392 error = lookupname(special.pn_path, 393 UIO_SYSSPACE, FOLLOW, NULLVPP, &bvp); 394 } 395 } 396 397 if (!wantbootpart) { 398 spnp = special.pn_path + spnlen - 1; 399 if (spnlen > 2 && *spnp >= 'c' && *spnp <= 'z') { 400 spnlen--; 401 dos_ldrive = *spnp-- - 'c' + 1; 402 } else if (spnlen > 2 && *spnp >= '0' && *spnp <= '9') { 403 spnlen--; 404 dos_ldrive = *spnp-- - '0'; 405 if (spnlen > 2 && *spnp >= '0' && 406 *spnp <= '9') { 407 spnlen--; 408 dos_ldrive += 10 * (*spnp-- - '0'); 409 } 410 } 411 if (spnlen > 1 && dos_ldrive && dos_ldrive <= 24 && 412 *spnp == ':') { 413 /* 414 * remove suffix so that we have a real 415 * device name 416 */ 417 *spnp = '\0'; 418 error = lookupname(special.pn_path, 419 UIO_SYSSPACE, FOLLOW, NULLVPP, &bvp); 420 } 421 } 422 if (error) { 423 pn_free(&special); 424 return (error); 425 } 426 } 427 pn_free(&special); 428 if (bvp->v_type != VBLK) { 429 VN_RELE(bvp); 430 return (ENOTBLK); 431 } 432 xdev = bvp->v_rdev; 433 /* 434 * Verify caller's permission to open the device special file. 435 */ 436 if ((vfsp->vfs_flag & VFS_RDONLY) != 0 || 437 ((uap->flags & MS_RDONLY) != 0)) { 438 oflag = FREAD; 439 aflag = VREAD; 440 } else { 441 oflag = FREAD | FWRITE; 442 aflag = VREAD | VWRITE; 443 } 444 if ((error = VOP_ACCESS(bvp, aflag, 0, cr)) != 0 || 445 (error = secpolicy_spec_open(cr, bvp, oflag)) != 0) { 446 VN_RELE(bvp); 447 return (error); 448 } 449 450 VN_RELE(bvp); 451 if (getmajor(xdev) >= devcnt) { 452 return (ENXIO); 453 } 454 /* 455 * Ensure that this device (or logical drive) isn't already mounted, 456 * unless this is a REMOUNT request 457 */ 458 if (dos_ldrive) { 459 mutex_enter(&pcfslock); 460 for (fsp = pc_mounttab; fsp; fsp = fsp->pcfs_nxt) 461 if (fsp->pcfs_xdev == xdev && 462 fsp->pcfs_ldrv == dos_ldrive) { 463 mutex_exit(&pcfslock); 464 if (uap->flags & MS_REMOUNT) { 465 return (0); 466 } else { 467 return (EBUSY); 468 } 469 } 470 /* 471 * Assign a unique device number for the vfs 472 * The old way (getudev() + a constantly incrementing 473 * major number) was wrong because it changes vfs_dev 474 * across mounts and reboots, which breaks nfs file handles. 475 * UFS just uses the real dev_t. We can't do that because 476 * of the way pcfs opens fdisk partitons (the :c and :d 477 * partitions are on the same dev_t). Though that _might_ 478 * actually be ok, since the file handle contains an 479 * absolute block number, it's probably better to make them 480 * different. So I think we should retain the original 481 * dev_t, but come up with a different minor number based 482 * on the logical drive that will _always_ come up the same. 483 * For now, we steal the upper 6 bits. 484 */ 485 #ifdef notdef 486 /* what should we do here? */ 487 if (((getminor(xdev) >> 12) & 0x3F) != 0) 488 printf("whoops - upper bits used!\n"); 489 #endif 490 minor = ((dos_ldrive << 12) | getminor(xdev)) & MAXMIN32; 491 pseudodev = makedevice(getmajor(xdev), minor); 492 if (vfs_devmounting(pseudodev, vfsp)) { 493 mutex_exit(&pcfslock); 494 return (EBUSY); 495 } 496 if (vfs_devismounted(pseudodev)) { 497 mutex_exit(&pcfslock); 498 if (uap->flags & MS_REMOUNT) { 499 return (0); 500 } else { 501 return (EBUSY); 502 } 503 } 504 mutex_exit(&pcfslock); 505 } else { 506 if (vfs_devmounting(xdev, vfsp)) { 507 return (EBUSY); 508 } 509 if (vfs_devismounted(xdev)) 510 if (uap->flags & MS_REMOUNT) { 511 return (0); 512 } else { 513 return (EBUSY); 514 } 515 pseudodev = xdev; 516 } 517 518 if (uap->flags & MS_RDONLY) { 519 vfsp->vfs_flag |= VFS_RDONLY; 520 vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); 521 } 522 523 /* 524 * Mount the filesystem 525 */ 526 devvp = makespecvp(xdev, VBLK); 527 if (IS_SWAPVP(devvp)) { 528 VN_RELE(devvp); 529 return (EBUSY); 530 } 531 532 /* 533 * special handling for PCMCIA memory card 534 * with pseudo floppies organization 535 */ 536 if (dos_ldrive == 0 && pcfs_pseudo_floppy(xdev)) { 537 dosstart = (daddr_t)0; 538 fattype = PCFS_PCMCIA_NO_CIS; 539 } else { 540 if (error = pc_getfattype(devvp, dos_ldrive, &dosstart, 541 &fattype)) { 542 VN_RELE(devvp); 543 return (error); 544 } 545 } 546 547 (void) VOP_PUTPAGE(devvp, (offset_t)0, (uint_t)0, B_INVAL, cr); 548 fsp = kmem_zalloc((uint_t)sizeof (struct pcfs), KM_SLEEP); 549 fsp->pcfs_vfs = vfsp; 550 fsp->pcfs_flags = fattype; 551 fsp->pcfs_devvp = devvp; 552 fsp->pcfs_xdev = xdev; 553 fsp->pcfs_ldrv = dos_ldrive; 554 fsp->pcfs_dosstart = dosstart; 555 mutex_init(&fsp->pcfs_lock, NULL, MUTEX_DEFAULT, NULL); 556 557 /* set the "nocheck" flag if volmgt is managing this volume */ 558 info.vii_pathlen = 0; 559 info.vii_devpath = 0; 560 error = cdev_ioctl(fsp->pcfs_xdev, VOLIOCINFO, (intptr_t)&info, 561 FKIOCTL|FREAD, kcred, &rval); 562 if (error == 0) { 563 fsp->pcfs_flags |= PCFS_NOCHK; 564 } 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 askedFor, int *error, 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 * Copy from disk block into memory aligned structure for fdisk usage. 937 */ 938 dosp_ptr = (struct mboot *)(*bp)->b_un.b_addr; 939 bcopy(dosp_ptr->parts, dosp, sizeof (struct ipart) * FD_NUMPART); 940 941 /* 942 * Get a summary of what is in the Master FDISK table. 943 * Normally we expect to find one partition marked as a DOS drive. 944 * This partition is the one Windows calls the primary dos partition. 945 * If the machine has any logical drives then we also expect 946 * to find a partition marked as an extended DOS partition. 947 * 948 * Sometimes we'll find multiple partitions marked as DOS drives. 949 * The Solaris fdisk program allows these partitions 950 * to be created, but Windows fdisk no longer does. We still need 951 * to support these, though, since Windows does. We also need to fix 952 * our fdisk to behave like the Windows version. 953 * 954 * It turns out that some off-the-shelf media have *only* an 955 * Extended partition, so we need to deal with that case as well. 956 * 957 * Only a single (the first) Extended or Boot Partition will 958 * be recognized. Any others will be ignored. 959 */ 960 for (i = 0; i < FD_NUMPART; i++) { 961 PC_DPRINTF1(2, "findTheDrive: found partition type %02x", 962 dosp[i].systid); 963 964 if (isDosDrive(dosp[i].systid)) { 965 if (primaryPart < 0) { 966 logicalDriveCount++; 967 primaryPart = i; 968 } else { 969 extraDrives[numExtraDrives++] = i; 970 } 971 continue; 972 } 973 if ((extendedPart < 0) && isDosExtended(dosp[i].systid)) { 974 extendedPart = i; 975 continue; 976 } 977 if ((bootPart < 0) && isBootPart(dosp[i].systid)) { 978 bootPart = i; 979 continue; 980 } 981 } 982 983 if (askedFor == BOOT_PARTITION_DRIVE) { 984 if (bootPart < 0) { 985 noLogicalDrive(askedFor); 986 *error = EINVAL; 987 return (0); 988 } 989 *sysid = dosp[bootPart].systid; 990 *startSector = ltohi(dosp[bootPart].relsect); 991 return (1); 992 } 993 994 if (askedFor == PRIMARY_DOS_DRIVE && primaryPart >= 0) { 995 *sysid = dosp[primaryPart].systid; 996 *startSector = ltohi(dosp[primaryPart].relsect); 997 return (1); 998 } 999 1000 /* 1001 * We are not looking for the C: drive (or the primary drive 1002 * was not found), so we had better have an extended partition 1003 * or extra drives in the Master FDISK table. 1004 */ 1005 if ((extendedPart < 0) && (numExtraDrives == 0)) { 1006 cmn_err(CE_NOTE, "!pcfs: no extended dos partition"); 1007 noLogicalDrive(askedFor); 1008 *error = EINVAL; 1009 return (0); 1010 } 1011 1012 if (extendedPart >= 0) { 1013 diskblk = xstartsect = ltohi(dosp[extendedPart].relsect); 1014 xnumsect = ltohi(dosp[extendedPart].numsect); 1015 do { 1016 /* 1017 * If the seek would not cause us to change 1018 * position on the drive, then we're out of 1019 * extended partitions to examine. 1020 */ 1021 if (diskblk == lastseek) 1022 break; 1023 logicalDriveCount += numDrives; 1024 /* 1025 * Seek the next extended partition, and find 1026 * logical drives within it. 1027 */ 1028 brelse(*bp); 1029 *bp = bread(dev, diskblk, PC_SAFESECSIZE); 1030 if ((*bp)->b_flags & B_ERROR) { 1031 PC_DPRINTF0(1, "pc_getfattype: read error\n"); 1032 *error = EIO; 1033 return (0); 1034 } 1035 lastseek = diskblk; 1036 dosp_ptr = (struct mboot *)(*bp)->b_un.b_addr; 1037 if (ltohs(dosp_ptr->signature) != MBB_MAGIC) { 1038 cmn_err(CE_NOTE, "!pcfs: " 1039 "extended partition signature err"); 1040 *error = EINVAL; 1041 return (0); 1042 } 1043 bcopy(dosp_ptr->parts, dosp, 1044 sizeof (struct ipart) * FD_NUMPART); 1045 /* 1046 * Count up drives, and track where the next 1047 * extended partition is in case we need it. We 1048 * are expecting only one extended partition. If 1049 * there is more than one we'll only go to the 1050 * first one we see, but warn about ignoring. 1051 */ 1052 numDrives = 0; 1053 for (i = 0; i < FD_NUMPART; i++) { 1054 if (isDosDrive(dosp[i].systid)) { 1055 extndDrives[numDrives++] = i; 1056 continue; 1057 } else if (isDosExtended(dosp[i].systid)) { 1058 if (diskblk != lastseek) { 1059 /* 1060 * Already found an extended 1061 * partition in this table. 1062 */ 1063 cmn_err(CE_NOTE, 1064 "!pcfs: ignoring unexpected" 1065 " additional extended" 1066 " partition"); 1067 continue; 1068 } 1069 diskblk = xstartsect + 1070 ltohi(dosp[i].relsect); 1071 continue; 1072 } 1073 } 1074 } while (askedFor > logicalDriveCount + numDrives); 1075 1076 if (askedFor <= logicalDriveCount + numDrives) { 1077 /* 1078 * The number of logical drives we've found thus 1079 * far is enough to get us to the one we were 1080 * searching for. 1081 */ 1082 driveIndex = logicalDriveCount + numDrives - askedFor; 1083 *sysid = dosp[extndDrives[driveIndex]].systid; 1084 *startSector = 1085 ltohi(dosp[extndDrives[driveIndex]].relsect) + 1086 lastseek; 1087 if (*startSector > (xstartsect + xnumsect)) { 1088 cmn_err(CE_NOTE, "!pcfs: extended partition " 1089 "values bad"); 1090 *error = EINVAL; 1091 return (0); 1092 } 1093 return (1); 1094 } else { 1095 /* 1096 * We ran out of extended dos partition 1097 * drives. The only hope now is to go 1098 * back to extra drives defined in the master 1099 * fdisk table. But we overwrote that table 1100 * already, so we must load it in again. 1101 */ 1102 logicalDriveCount += numDrives; 1103 brelse(*bp); 1104 *bp = bread(dev, (daddr_t)0, PC_SAFESECSIZE); 1105 if ((*bp)->b_flags & B_ERROR) { 1106 PC_DPRINTF0(1, "pc_getfattype: read error\n"); 1107 *error = EIO; 1108 return (0); 1109 } 1110 dosp_ptr = (struct mboot *)(*bp)->b_un.b_addr; 1111 bcopy(dosp_ptr->parts, dosp, 1112 sizeof (struct ipart) * FD_NUMPART); 1113 } 1114 } 1115 /* 1116 * Still haven't found the drive, is it an extra 1117 * drive defined in the main FDISK table? 1118 */ 1119 if (askedFor <= logicalDriveCount + numExtraDrives) { 1120 driveIndex = logicalDriveCount + numExtraDrives - askedFor; 1121 *sysid = dosp[extraDrives[driveIndex]].systid; 1122 *startSector = ltohi(dosp[extraDrives[driveIndex]].relsect); 1123 return (1); 1124 } 1125 /* 1126 * Still haven't found the drive, and there is 1127 * nowhere else to look. 1128 */ 1129 noLogicalDrive(askedFor); 1130 *error = EINVAL; 1131 return (0); 1132 } 1133 1134 /* 1135 * FAT12/FAT16 specific consistency checks. 1136 */ 1137 static int 1138 check_bpb_fat16(struct bootsec *bpb) 1139 { 1140 if (pcfsdebuglevel >= 5) { 1141 PC_DPRINTF1(5, "check_bpb_fat: RootEntCount = %d", 1142 ltohs(bpb->rdirents[0])); 1143 PC_DPRINTF1(5, "check_bpb_fat16: TotSec16 = %d", 1144 ltohs(bpb->numsect[0])); 1145 PC_DPRINTF1(5, "check_bpb_fat16: FATSz16 = %d", 1146 ltohs(bpb->fatsec)); 1147 PC_DPRINTF1(5, "check_bpb_fat16: TotSec32 = %d", 1148 ltohi(bpb->totalsec)); 1149 } 1150 return (ltohs(bpb->rdirents[0]) > 0 && /* RootEntCnt > 0 */ 1151 ((ltohs(bpb->numsect[0]) == 0 && /* TotSec16 == 0 */ 1152 ltohi(bpb->totalsec) > 0) || /* TotSec32 > 0 */ 1153 ltohs(bpb->numsect[0]) > 0) && /* TotSec16 > 0 */ 1154 ltohs(bpb->fatsec) > 0); /* FatSz16 > 0 */ 1155 } 1156 1157 /* 1158 * FAT32 specific consistency checks. 1159 */ 1160 static int 1161 check_bpb_fat32(struct fat32_bootsec *bpb) 1162 { 1163 if (pcfsdebuglevel >= 5) { 1164 PC_DPRINTF1(5, "check_bpb_fat32: RootEntCount = %d", 1165 ltohs(bpb->f_bs.rdirents[0])); 1166 PC_DPRINTF1(5, "check_bpb_fat32: TotSec16 = %d", 1167 ltohs(bpb->f_bs.numsect[0])); 1168 PC_DPRINTF1(5, "check_bpb_fat32: FATSz16 = %d", 1169 ltohs(bpb->f_bs.fatsec)); 1170 PC_DPRINTF1(5, "check_bpb_fat32: TotSec32 = %d", 1171 ltohi(bpb->f_bs.totalsec)); 1172 PC_DPRINTF1(5, "check_bpb_fat32: FATSz32 = %d", 1173 ltohi(bpb->f_fatlength)); 1174 } 1175 return (ltohs(bpb->f_bs.rdirents[0]) == 0 && 1176 ltohs(bpb->f_bs.numsect[0]) == 0 && 1177 ltohs(bpb->f_bs.fatsec) == 0 && 1178 ltohi(bpb->f_bs.totalsec) > 0 && 1179 ltohi(bpb->f_fatlength) > 0); 1180 } 1181 1182 /* 1183 * Calculate the number of clusters in order to determine 1184 * the type of FAT we are looking at. This is the only 1185 * recommended way of determining FAT type, though there 1186 * are other hints in the data, this is the best way. 1187 */ 1188 static ulong_t 1189 bpb_to_numclusters(uchar_t *cp) 1190 { 1191 struct fat32_bootsec *bpb; 1192 1193 ulong_t rootdirsectors; 1194 ulong_t FATsz; 1195 ulong_t TotSec; 1196 ulong_t DataSec; 1197 ulong_t CountOfClusters; 1198 char FileSysType[9]; 1199 1200 /* 1201 * Cast it to FAT32 bpb. If it turns out to be FAT12/16, its 1202 * OK, we won't try accessing the data beyond the FAT16 header 1203 * boundary. 1204 */ 1205 bpb = (struct fat32_bootsec *)cp; 1206 1207 if (pcfsdebuglevel >= 5) { 1208 if (ltohs(bpb->f_bs.rdirents[0]) != 0) { 1209 (void) memcpy(FileSysType, &cp[54], 8); 1210 FileSysType[8] = 0; 1211 PC_DPRINTF1(5, "debug_bpb: FAT12/FAT16 FileSysType = " 1212 "%s", FileSysType); 1213 } 1214 } 1215 1216 rootdirsectors = ((ltohs(bpb->f_bs.rdirents[0]) * 32) + 1217 (ltohs(bpb->f_bs.bps[0]) - 1)) / ltohs(bpb->f_bs.bps[0]); 1218 1219 if (ltohs(bpb->f_bs.fatsec) != 0) 1220 FATsz = ltohs(bpb->f_bs.fatsec); 1221 else 1222 FATsz = ltohi(bpb->f_fatlength); 1223 1224 if (ltohs(bpb->f_bs.numsect[0]) != 0) 1225 TotSec = ltohs(bpb->f_bs.numsect[0]); 1226 else 1227 TotSec = ltohi(bpb->f_bs.totalsec); 1228 1229 DataSec = TotSec - (ltohs(bpb->f_bs.res_sec[0]) + 1230 (bpb->f_bs.nfat * FATsz) + rootdirsectors); 1231 1232 CountOfClusters = DataSec / bpb->f_bs.spcl; 1233 1234 PC_DPRINTF1(5, "debug_bpb: CountOfClusters = %ld", CountOfClusters); 1235 1236 return (CountOfClusters); 1237 1238 } 1239 1240 static int 1241 fattype(ulong_t CountOfClusters) 1242 { 1243 /* 1244 * From Microsoft: 1245 * In the following example, when it says <, it does not mean <=. 1246 * Note also that the numbers are correct. The first number for 1247 * FAT12 is 4085; the second number for FAT16 is 65525. These numbers 1248 * and the '<' signs are not wrong. 1249 */ 1250 1251 /* Watch for edge cases */ 1252 if ((CountOfClusters >= 4085 && CountOfClusters <= 4095) || 1253 (CountOfClusters >= 65525 && CountOfClusters <= 65535)) { 1254 PC_DPRINTF1(5, "debug_bpb: Cannot determine FAT yet - %ld", 1255 CountOfClusters); 1256 return (-1); /* Cannot be determined yet */ 1257 } else if (CountOfClusters < 4085) { 1258 /* Volume is FAT12 */ 1259 PC_DPRINTF0(5, "debug_bpb: This must be FAT12"); 1260 return (0); 1261 } else if (CountOfClusters < 65525) { 1262 /* Volume is FAT16 */ 1263 PC_DPRINTF0(5, "debug_bpb: This must be FAT16"); 1264 return (PCFS_FAT16); 1265 } else { 1266 /* Volume is FAT32 */ 1267 PC_DPRINTF0(5, "debug_bpb: This must be FAT32"); 1268 return (PCFS_FAT32); 1269 } 1270 } 1271 1272 #define VALID_SECSIZE(s) (s == 512 || s == 1024 || s == 2048 || s == 4096) 1273 1274 #define VALID_SPCL(s) (s == 1 || s == 2 || s == 4 || s == 8 || s == 16 ||\ 1275 s == 32 || s == 64 || s == 128) 1276 1277 static int 1278 secondaryBPBChecks(uchar_t *cp) 1279 { 1280 struct bootsec *bpb = (struct bootsec *)cp; 1281 struct fat32_bootsec *f32bpb = (struct fat32_bootsec *)cp; 1282 1283 /* 1284 * Perform secondary checks to try and determine what sort 1285 * of FAT partition we have based on other, less reliable, 1286 * data in the BPB header. 1287 */ 1288 if (ltohs(bpb->fatsec) != 0) { 1289 /* 1290 * Must be FAT12 or FAT16, check the 1291 * FilSysType string (not 100% reliable). 1292 */ 1293 if (!memcmp((cp + PCFS_TYPESTRING_OFFSET16), "FAT12", 5)) { 1294 PC_DPRINTF0(5, "secondaryBPBCheck says: FAT12"); 1295 return (0); /* FAT12 */ 1296 } else if (!memcmp((cp + PCFS_TYPESTRING_OFFSET16), "FAT16", 1297 5)) { 1298 PC_DPRINTF0(5, "secondaryBPBCheck says: FAT16"); 1299 return (PCFS_FAT16); 1300 } else { 1301 /* 1302 * Try to use the BPB_Media byte 1303 * 1304 * If the media byte indicates a floppy we'll 1305 * assume FAT12, otherwise we'll assume FAT16. 1306 */ 1307 switch (bpb->mediadesriptor) { 1308 case SS8SPT: 1309 case DS8SPT: 1310 case SS9SPT: 1311 case DS9SPT: 1312 case DS18SPT: 1313 case DS9_15SPT: 1314 PC_DPRINTF0(5, 1315 "secondaryBPBCheck says: FAT12"); 1316 return (0); /* FAT12 */ 1317 case MD_FIXED: 1318 PC_DPRINTF0(5, 1319 "secondaryBPBCheck says: FAT16"); 1320 return (PCFS_FAT16); 1321 default: 1322 cmn_err(CE_NOTE, 1323 "!pcfs: unknown FAT type"); 1324 return (-1); 1325 } 1326 } 1327 } else if (ltohi(f32bpb->f_fatlength) > 0) { 1328 PC_DPRINTF0(5, "secondaryBPBCheck says: FAT32"); 1329 return (PCFS_FAT32); 1330 } else { 1331 /* We don't know */ 1332 PC_DPRINTF0(5, "secondaryBPBCheck says: unknown!!"); 1333 return (-1); 1334 } 1335 } 1336 1337 /* 1338 * Check to see if the BPB we found is correct. 1339 * 1340 * First, look for obvious, tell-tale signs of trouble: 1341 * The NumFATs value should always be 2. Sometimes it can be a '1' 1342 * on FLASH memory cards and other non-disk-based media, so we 1343 * will allow that as well. 1344 * 1345 * We also look at the Media byte, the valid range is 0xF0, or 1346 * 0xF8 thru 0xFF, anything else means this is probably not a good 1347 * BPB. 1348 * 1349 * Finally, check the BPB Magic number at the end of the 512 byte 1350 * block, it must be 0xAA55. 1351 * 1352 * If that all is good, calculate the number of clusters and 1353 * do some final verification steps. 1354 * 1355 * If all is well, return success (1) and set the fattypep 1356 * value to the correct FAT value. 1357 */ 1358 static int 1359 isBPB(uchar_t *cp, int *fattypep) 1360 { 1361 struct bootsec *bpb = (struct bootsec *)cp; 1362 1363 uint_t numclusters; /* number of clusters in file area */ 1364 ushort_t secsize = (int)ltohs(bpb->bps[0]); 1365 1366 if (pcfsdebuglevel >= 3) { 1367 if (!VALID_SECSIZE(secsize)) 1368 PC_DPRINTF1(3, "check_bpb: invalid bps value %d", 1369 secsize); 1370 1371 if (!VALID_SPCL(bpb->spcl)) 1372 PC_DPRINTF1(3, "check_bpb: invalid spcl value %d", 1373 bpb->spcl); 1374 1375 if ((secsize * bpb->spcl) >= (32 * 1024)) 1376 PC_DPRINTF3(3, "check_bpb: BPC > 32K %d x %d = %d", 1377 secsize, 1378 bpb->spcl, 1379 secsize * bpb->spcl); 1380 1381 if (bpb->nfat == 0) 1382 PC_DPRINTF1(3, "check_bpb: bad NumFATs value %d", 1383 bpb->nfat); 1384 1385 if (ltohs(bpb->res_sec[0]) == 0) 1386 PC_DPRINTF1(3, "check_bpb: bad RsvdSecCnt value %d", 1387 ltohs(bpb->res_sec[0])); 1388 1389 PC_DPRINTF1(5, "check_bpb: Media byte = %02x", 1390 bpb->mediadesriptor); 1391 1392 } 1393 if ((bpb->nfat == 0) || 1394 (bpb->mediadesriptor != 0xF0 && bpb->mediadesriptor < 0xF8) || 1395 (ltohs(cp[510]) != MBB_MAGIC) || 1396 !VALID_SECSIZE(secsize) || 1397 !VALID_SPCL(bpb->spcl) || 1398 (secsize * bpb->spcl > (64 * 1024)) || 1399 !(ltohs(bpb->res_sec[0]))) 1400 return (0); 1401 1402 /* 1403 * Basic sanity checks passed so far, now try to determine which 1404 * FAT format to use. 1405 */ 1406 numclusters = bpb_to_numclusters(cp); 1407 1408 *fattypep = fattype(numclusters); 1409 1410 /* Do some final sanity checks for each specific type of FAT */ 1411 switch (*fattypep) { 1412 case 0: /* FAT12 */ 1413 case PCFS_FAT16: 1414 if (!check_bpb_fat16((struct bootsec *)cp)) 1415 return (0); 1416 break; 1417 case PCFS_FAT32: 1418 if (!check_bpb_fat32((struct fat32_bootsec *)cp)) 1419 return (0); 1420 break; 1421 default: /* not sure yet */ 1422 *fattypep = secondaryBPBChecks(cp); 1423 if (*fattypep == -1) { 1424 /* Still nothing, give it up. */ 1425 return (0); 1426 } 1427 break; 1428 } 1429 PC_DPRINTF0(5, "isBPB: BPB passes verification tests"); 1430 return (1); 1431 } 1432 1433 1434 /* 1435 * Get the FAT type for the DOS medium. 1436 * 1437 * ------------------------- 1438 * According to Microsoft: 1439 * The FAT type one of FAT12, FAT16, or FAT32 is determined by the 1440 * count of clusters on the volume and nothing else. 1441 * ------------------------- 1442 * 1443 */ 1444 static int 1445 pc_getfattype( 1446 struct vnode *devvp, 1447 int ldrive, 1448 daddr_t *strtsectp, 1449 int *fattypep) 1450 { 1451 uchar_t *cp; /* for searching out FAT string */ 1452 buf_t *bp = NULL; /* Disk buffer pointer */ 1453 int rval = 0; 1454 uchar_t sysid = 0; /* System ID character */ 1455 dev_t dev = devvp->v_rdev; 1456 1457 *strtsectp = (daddr_t)0; 1458 1459 /* 1460 * Open the device so we can check out the BPB or FDISK table, 1461 * then read in the sector. 1462 */ 1463 PC_DPRINTF2(5, "pc_getfattype: dev=%x ldrive=%x ", (int)dev, ldrive); 1464 if (rval = VOP_OPEN(&devvp, FREAD, CRED())) { 1465 PC_DPRINTF1(1, "pc_getfattype: open error=%d\n", rval); 1466 return (rval); 1467 } 1468 1469 /* 1470 * Read block 0 from device 1471 */ 1472 bp = bread(dev, (daddr_t)0, PC_SAFESECSIZE); 1473 if (bp->b_flags & B_ERROR) { 1474 PC_DPRINTF0(1, "pc_getfattype: read error\n"); 1475 rval = EIO; 1476 goto out; 1477 } 1478 1479 cp = (uchar_t *)bp->b_un.b_addr; 1480 1481 /* 1482 * If the first block is not a valid BPB, look for the 1483 * through the FDISK table. 1484 */ 1485 if (!isBPB(cp, fattypep)) { 1486 /* find the partition table and get 512 bytes from it. */ 1487 PC_DPRINTF0(5, "pc_getfattype: using FDISK table to find BPB"); 1488 1489 if (findTheDrive(dev, ldrive, &rval, &bp, 1490 strtsectp, &sysid) == 0) 1491 goto out; 1492 1493 brelse(bp); 1494 bp = bread(dev, *strtsectp, PC_SAFESECSIZE); 1495 if (bp->b_flags & B_ERROR) { 1496 PC_DPRINTF0(1, "pc_getfattype: read error\n"); 1497 rval = EIO; 1498 goto out; 1499 } 1500 cp = (uchar_t *)bp->b_un.b_addr; 1501 1502 /* If this one is still no good, give it up. */ 1503 if (!isBPB(cp, fattypep)) { 1504 rval = EIO; 1505 goto out; 1506 } 1507 } 1508 1509 out: 1510 /* 1511 * Release the buffer used 1512 */ 1513 if (bp != NULL) 1514 brelse(bp); 1515 (void) VOP_CLOSE(devvp, FREAD, 1, (offset_t)0, CRED()); 1516 return (rval); 1517 } 1518 1519 1520 /* 1521 * Get the boot parameter block and file allocation table. 1522 * If there is an old FAT, invalidate it. 1523 */ 1524 int 1525 pc_getfat(struct pcfs *fsp) 1526 { 1527 struct vfs *vfsp = PCFSTOVFS(fsp); 1528 struct buf *tp = 0; 1529 struct buf *bp = 0; 1530 uchar_t *fatp = NULL; 1531 uchar_t *fat_changemap = NULL; 1532 struct bootsec *bootp; 1533 struct fat32_bootsec *f32b; 1534 struct vnode *devvp; 1535 int error; 1536 int fatsize; 1537 int fat_changemapsize; 1538 int flags = 0; 1539 int nfat; 1540 int secsize; 1541 int fatsec; 1542 1543 PC_DPRINTF0(5, "pc_getfat\n"); 1544 devvp = fsp->pcfs_devvp; 1545 if (fsp->pcfs_fatp) { 1546 /* 1547 * There is a FAT in core. 1548 * If there are open file pcnodes or we have modified it or 1549 * it hasn't timed out yet use the in core FAT. 1550 * Otherwise invalidate it and get a new one 1551 */ 1552 #ifdef notdef 1553 if (fsp->pcfs_frefs || 1554 (fsp->pcfs_flags & PCFS_FATMOD) || 1555 (gethrestime_sec() < fsp->pcfs_fattime)) { 1556 return (0); 1557 } else { 1558 mutex_enter(&pcfslock); 1559 pc_invalfat(fsp); 1560 mutex_exit(&pcfslock); 1561 } 1562 #endif /* notdef */ 1563 return (0); 1564 } 1565 /* 1566 * Open block device mounted on. 1567 */ 1568 error = VOP_OPEN(&devvp, 1569 (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE, 1570 CRED()); 1571 if (error) { 1572 PC_DPRINTF1(1, "pc_getfat: open error=%d\n", error); 1573 return (error); 1574 } 1575 /* 1576 * Get boot parameter block and check it for validity 1577 */ 1578 tp = bread(fsp->pcfs_xdev, fsp->pcfs_dosstart, PC_SAFESECSIZE); 1579 if (tp->b_flags & (B_ERROR | B_STALE)) { 1580 PC_DPRINTF0(1, "pc_getfat: boot block error\n"); 1581 flags = tp->b_flags & B_ERROR; 1582 error = EIO; 1583 goto out; 1584 } 1585 tp->b_flags |= B_STALE | B_AGE; 1586 bootp = (struct bootsec *)tp->b_un.b_addr; 1587 1588 1589 /* get the sector size - may be more than 512 bytes */ 1590 secsize = (int)ltohs(bootp->bps[0]); 1591 /* check for bogus sector size - fat should be at least 1 sector */ 1592 if (IS_FAT32(fsp)) { 1593 f32b = (struct fat32_bootsec *)bootp; 1594 fatsec = ltohi(f32b->f_fatlength); 1595 } else { 1596 fatsec = ltohs(bootp->fatsec); 1597 } 1598 if (secsize < 512 || fatsec < 1 || bootp->nfat < 1) { 1599 cmn_err(CE_NOTE, "!pcfs: FAT size error"); 1600 error = EINVAL; 1601 goto out; 1602 } 1603 1604 switch (bootp->mediadesriptor) { 1605 default: 1606 cmn_err(CE_NOTE, "!pcfs: media-descriptor error, 0x%x", 1607 bootp->mediadesriptor); 1608 error = EINVAL; 1609 goto out; 1610 1611 case MD_FIXED: 1612 /* 1613 * PCMCIA pseudo floppy is type MD_FIXED, 1614 * but is accessed like a floppy 1615 */ 1616 if (!(fsp->pcfs_flags & PCFS_PCMCIA_NO_CIS)) { 1617 fsp->pcfs_flags |= PCFS_NOCHK; 1618 } 1619 /* FALLTHRU */ 1620 case SS8SPT: 1621 case DS8SPT: 1622 case SS9SPT: 1623 case DS9SPT: 1624 case DS18SPT: 1625 case DS9_15SPT: 1626 fsp->pcfs_secsize = secsize; 1627 fsp->pcfs_sdshift = secsize / DEV_BSIZE - 1; 1628 fsp->pcfs_entps = secsize / sizeof (struct pcdir); 1629 fsp->pcfs_spcl = (int)bootp->spcl; 1630 fsp->pcfs_fatsec = fatsec; 1631 fsp->pcfs_spt = (int)ltohs(bootp->spt); 1632 fsp->pcfs_rdirsec = ((int)ltohs(bootp->rdirents[0]) 1633 * sizeof (struct pcdir) + (secsize - 1)) / secsize; 1634 fsp->pcfs_clsize = fsp->pcfs_spcl * secsize; 1635 fsp->pcfs_fatstart = fsp->pcfs_dosstart + 1636 (daddr_t)ltohs(bootp->res_sec[0]); 1637 fsp->pcfs_rdirstart = fsp->pcfs_fatstart + 1638 (bootp->nfat * fsp->pcfs_fatsec); 1639 fsp->pcfs_datastart = fsp->pcfs_rdirstart + fsp->pcfs_rdirsec; 1640 if (IS_FAT32(fsp)) 1641 fsp->pcfs_rdirstart = ltohi(f32b->f_rootcluster); 1642 fsp->pcfs_ncluster = (((int)(ltohs(bootp->numsect[0]) ? 1643 ltohs(bootp->numsect[0]) : ltohi(bootp->totalsec))) - 1644 fsp->pcfs_datastart + fsp->pcfs_dosstart) / fsp->pcfs_spcl; 1645 fsp->pcfs_numfat = (int)bootp->nfat; 1646 fsp->pcfs_nxfrecls = PCF_FIRSTCLUSTER; 1647 break; 1648 } 1649 1650 /* 1651 * Get FAT and check it for validity 1652 */ 1653 fatsize = fsp->pcfs_fatsec * fsp->pcfs_secsize; 1654 fatp = kmem_alloc(fatsize, KM_SLEEP); 1655 error = pc_readfat(fsp, fatp, fsp->pcfs_fatstart, fatsize); 1656 if (error) { 1657 flags = B_ERROR; 1658 goto out; 1659 } 1660 fat_changemapsize = (fatsize / fsp->pcfs_clsize) + 1; 1661 fat_changemap = kmem_zalloc(fat_changemapsize, KM_SLEEP); 1662 1663 /* 1664 * The only definite signature check is that the 1665 * media descriptor byte should match the first byte 1666 * of the FAT block. 1667 */ 1668 if (fatp[0] != bootp->mediadesriptor) { 1669 cmn_err(CE_NOTE, "!pcfs: FAT signature error"); 1670 error = EINVAL; 1671 goto out; 1672 } 1673 /* 1674 * Checking for fatsec and number of supported clusters, should 1675 * actually determine a FAT12/FAT media. 1676 */ 1677 if (fsp->pcfs_flags & PCFS_FAT16) { 1678 if ((fsp->pcfs_fatsec <= 12) && 1679 ((fatsize * 2 / 3) >= fsp->pcfs_ncluster)) { 1680 /* 1681 * We have a 12-bit FAT, rather than a 16-bit FAT. 1682 * Ignore what the fdisk table says. 1683 */ 1684 PC_DPRINTF0(2, "pc_getfattype: forcing 12-bit FAT\n"); 1685 fsp->pcfs_flags &= ~PCFS_FAT16; 1686 } 1687 } 1688 /* 1689 * Sanity check our FAT is large enough for the 1690 * clusters we think we have. 1691 */ 1692 if ((fsp->pcfs_flags & PCFS_FAT16) && 1693 ((fatsize / 2) < fsp->pcfs_ncluster)) { 1694 cmn_err(CE_NOTE, "!pcfs: FAT too small for number of clusters"); 1695 error = EINVAL; 1696 goto out; 1697 } 1698 1699 /* 1700 * Get alternate FATs and check for consistency 1701 * This is an inlined version of pc_readfat(). 1702 * Since we're only comparing FAT and alternate FAT, 1703 * there's no reason to let pc_readfat() copy data out 1704 * of the buf. Instead, compare in-situ, one cluster 1705 * at a time. 1706 */ 1707 for (nfat = 1; nfat < fsp->pcfs_numfat; nfat++) { 1708 size_t startsec; 1709 size_t off; 1710 1711 startsec = fsp->pcfs_fatstart + nfat * fsp->pcfs_fatsec; 1712 1713 for (off = 0; off < fatsize; off += fsp->pcfs_clsize) { 1714 bp = bread(fsp->pcfs_xdev, pc_dbdaddr(fsp, 1715 startsec + 1716 pc_cltodb(fsp, pc_lblkno(fsp, off))), 1717 MIN(fsp->pcfs_clsize, fatsize - off)); 1718 if (bp->b_flags & (B_ERROR | B_STALE)) { 1719 cmn_err(CE_NOTE, 1720 "!pcfs: alternate FAT #%d read error" 1721 " at byte %ld", nfat, off); 1722 flags = B_ERROR; 1723 error = EIO; 1724 goto out; 1725 } 1726 bp->b_flags |= B_STALE | B_AGE; 1727 if (bcmp(bp->b_un.b_addr, 1728 fatp + off, 1729 MIN(fsp->pcfs_clsize, fatsize - off))) { 1730 cmn_err(CE_NOTE, 1731 "!pcfs: alternate FAT #%d corrupted" 1732 " at byte %ld", nfat, off); 1733 flags = B_ERROR; 1734 } 1735 brelse(bp); 1736 bp = NULL; /* prevent double release */ 1737 } 1738 } 1739 1740 fsp->pcfs_fatsize = fatsize; 1741 fsp->pcfs_fatp = fatp; 1742 fsp->pcfs_fat_changemapsize = fat_changemapsize; 1743 fsp->pcfs_fat_changemap = fat_changemap; 1744 fsp->pcfs_fattime = gethrestime_sec() + PCFS_DISKTIMEOUT; 1745 fsp->pcfs_fatjustread = 1; 1746 1747 brelse(tp); 1748 tp = NULL; 1749 if (IS_FAT32(fsp)) { 1750 /* get fsinfo */ 1751 struct fat32_boot_fsinfo fsinfo_disk; 1752 1753 fsp->f32fsinfo_sector = ltohs(f32b->f_infosector); 1754 tp = bread(fsp->pcfs_xdev, 1755 fsp->pcfs_dosstart + pc_dbdaddr(fsp, fsp->f32fsinfo_sector), 1756 PC_SAFESECSIZE); 1757 if (tp->b_flags & (B_ERROR | B_STALE)) { 1758 cmn_err(CE_NOTE, "!pcfs: error reading fat32 fsinfo"); 1759 flags = tp->b_flags & B_ERROR; 1760 brelse(tp); 1761 tp = NULL; 1762 error = EIO; 1763 goto out; 1764 } 1765 tp->b_flags |= B_STALE | B_AGE; 1766 bcopy((void *)(tp->b_un.b_addr + FAT32_BOOT_FSINFO_OFF), 1767 &fsinfo_disk, sizeof (struct fat32_boot_fsinfo)); 1768 brelse(tp); 1769 tp = NULL; 1770 1771 /* translated fields */ 1772 fsp->fsinfo_native.fs_signature = 1773 ltohi(fsinfo_disk.fs_signature); 1774 fsp->fsinfo_native.fs_free_clusters = 1775 ltohi(fsinfo_disk.fs_free_clusters); 1776 if (fsp->fsinfo_native.fs_signature != FAT32_FS_SIGN) { 1777 cmn_err(CE_NOTE, 1778 "!pcfs: fat32 fsinfo signature mismatch."); 1779 error = EINVAL; 1780 goto out; 1781 } 1782 } 1783 1784 return (0); 1785 1786 out: 1787 cmn_err(CE_NOTE, "!pcfs: illegal disk format"); 1788 if (tp) 1789 brelse(tp); 1790 if (bp) 1791 brelse(bp); 1792 if (fatp) 1793 kmem_free(fatp, fatsize); 1794 if (fat_changemap) 1795 kmem_free(fat_changemap, fat_changemapsize); 1796 1797 if (flags) { 1798 pc_mark_irrecov(fsp); 1799 } 1800 (void) VOP_CLOSE(devvp, (vfsp->vfs_flag & VFS_RDONLY) ? 1801 FREAD : FREAD|FWRITE, 1, (offset_t)0, CRED()); 1802 return (error); 1803 } 1804 1805 int 1806 pc_syncfat(struct pcfs *fsp) 1807 { 1808 struct buf *bp; 1809 int nfat; 1810 int error; 1811 struct fat32_boot_fsinfo fsinfo_disk; 1812 1813 PC_DPRINTF0(7, "pcfs_syncfat\n"); 1814 if ((fsp->pcfs_fatp == (uchar_t *)0) || 1815 !(fsp->pcfs_flags & PCFS_FATMOD)) 1816 return (0); 1817 /* 1818 * write out all copies of FATs 1819 */ 1820 fsp->pcfs_flags &= ~PCFS_FATMOD; 1821 fsp->pcfs_fattime = gethrestime_sec() + PCFS_DISKTIMEOUT; 1822 for (nfat = 0; nfat < fsp->pcfs_numfat; nfat++) { 1823 error = pc_writefat(fsp, 1824 fsp->pcfs_fatstart + nfat*fsp->pcfs_fatsec); 1825 if (error) { 1826 pc_mark_irrecov(fsp); 1827 return (EIO); 1828 } 1829 } 1830 pc_clear_fatchanges(fsp); 1831 PC_DPRINTF0(6, "pcfs_syncfat: wrote out FAT\n"); 1832 /* write out fsinfo */ 1833 if (IS_FAT32(fsp)) { 1834 bp = bread(fsp->pcfs_xdev, 1835 fsp->pcfs_dosstart + pc_dbdaddr(fsp, fsp->f32fsinfo_sector), 1836 PC_SAFESECSIZE); 1837 if (bp->b_flags & (B_ERROR | B_STALE)) { 1838 brelse(bp); 1839 return (EIO); 1840 } 1841 bcopy((void *)(bp->b_un.b_addr + FAT32_BOOT_FSINFO_OFF), 1842 &fsinfo_disk, sizeof (struct fat32_boot_fsinfo)); 1843 /* translate fields */ 1844 fsinfo_disk.fs_free_clusters = 1845 htoli(fsp->fsinfo_native.fs_free_clusters); 1846 fsinfo_disk.fs_next_cluster = (uint32_t)FSINFO_UNKNOWN; 1847 bcopy(&fsinfo_disk, 1848 (void *)(bp->b_un.b_addr + FAT32_BOOT_FSINFO_OFF), 1849 sizeof (struct fat32_boot_fsinfo)); 1850 bwrite2(bp); 1851 error = geterror(bp); 1852 brelse(bp); 1853 if (error) { 1854 pc_mark_irrecov(fsp); 1855 return (EIO); 1856 } 1857 } 1858 return (0); 1859 } 1860 1861 void 1862 pc_invalfat(struct pcfs *fsp) 1863 { 1864 struct pcfs *xfsp; 1865 int mount_cnt = 0; 1866 1867 PC_DPRINTF0(7, "pc_invalfat\n"); 1868 if (fsp->pcfs_fatp == (uchar_t *)0) 1869 panic("pc_invalfat"); 1870 /* 1871 * Release FAT 1872 */ 1873 kmem_free(fsp->pcfs_fatp, fsp->pcfs_fatsize); 1874 fsp->pcfs_fatp = NULL; 1875 kmem_free(fsp->pcfs_fat_changemap, fsp->pcfs_fat_changemapsize); 1876 fsp->pcfs_fat_changemap = NULL; 1877 /* 1878 * Invalidate all the blocks associated with the device. 1879 * Not needed if stateless. 1880 */ 1881 for (xfsp = pc_mounttab; xfsp; xfsp = xfsp->pcfs_nxt) 1882 if (xfsp != fsp && xfsp->pcfs_xdev == fsp->pcfs_xdev) 1883 mount_cnt++; 1884 1885 if (!mount_cnt) 1886 binval(fsp->pcfs_xdev); 1887 /* 1888 * close mounted device 1889 */ 1890 (void) VOP_CLOSE(fsp->pcfs_devvp, 1891 (PCFSTOVFS(fsp)->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE, 1892 1, (offset_t)0, CRED()); 1893 } 1894 1895 void 1896 pc_badfs(struct pcfs *fsp) 1897 { 1898 cmn_err(CE_WARN, "corrupted PC file system on dev %x.%x\n", 1899 getmajor(fsp->pcfs_devvp->v_rdev), 1900 getminor(fsp->pcfs_devvp->v_rdev)); 1901 } 1902 1903 /* 1904 * The problem with supporting NFS on the PCFS filesystem is that there 1905 * is no good place to keep the generation number. The only possible 1906 * place is inside a directory entry. There are a few words that we 1907 * don't use - they store NT & OS/2 attributes, and the creation/last access 1908 * time of the file - but it seems wrong to use them. In addition, directory 1909 * entries come and go. If a directory is removed completely, its directory 1910 * blocks are freed and the generation numbers are lost. Whereas in ufs, 1911 * inode blocks are dedicated for inodes, so the generation numbers are 1912 * permanently kept on the disk. 1913 */ 1914 static int 1915 pcfs_vget(struct vfs *vfsp, struct vnode **vpp, struct fid *fidp) 1916 { 1917 struct pcnode *pcp; 1918 struct pc_fid *pcfid; 1919 struct pcfs *fsp; 1920 struct pcdir *ep; 1921 daddr_t eblkno; 1922 int eoffset; 1923 struct buf *bp; 1924 int error; 1925 pc_cluster32_t cn; 1926 1927 pcfid = (struct pc_fid *)fidp; 1928 fsp = VFSTOPCFS(vfsp); 1929 1930 error = pc_lockfs(fsp, 0, 0); 1931 if (error) { 1932 *vpp = NULL; 1933 return (error); 1934 } 1935 1936 if (pcfid->pcfid_block == 0) { 1937 pcp = pc_getnode(fsp, (daddr_t)0, 0, (struct pcdir *)0); 1938 pcp->pc_flags |= PC_EXTERNAL; 1939 *vpp = PCTOV(pcp); 1940 pc_unlockfs(fsp); 1941 return (0); 1942 } 1943 eblkno = pcfid->pcfid_block; 1944 eoffset = pcfid->pcfid_offset; 1945 if ((pc_dbtocl(fsp, 1946 eblkno - fsp->pcfs_dosstart) >= fsp->pcfs_ncluster) || 1947 (eoffset > fsp->pcfs_clsize)) { 1948 pc_unlockfs(fsp); 1949 *vpp = NULL; 1950 return (EINVAL); 1951 } 1952 1953 if (eblkno >= fsp->pcfs_datastart || (eblkno-fsp->pcfs_rdirstart) 1954 < (fsp->pcfs_rdirsec & ~(fsp->pcfs_spcl - 1))) { 1955 bp = bread(fsp->pcfs_xdev, eblkno, fsp->pcfs_clsize); 1956 } else { 1957 bp = bread(fsp->pcfs_xdev, eblkno, 1958 (int)(fsp->pcfs_datastart - eblkno) * fsp->pcfs_secsize); 1959 } 1960 if (bp->b_flags & (B_ERROR | B_STALE)) { 1961 error = geterror(bp); 1962 brelse(bp); 1963 if (error) 1964 pc_mark_irrecov(fsp); 1965 *vpp = NULL; 1966 pc_unlockfs(fsp); 1967 return (error); 1968 } 1969 ep = (struct pcdir *)(bp->b_un.b_addr + eoffset); 1970 /* 1971 * Ok, if this is a valid file handle that we gave out, 1972 * then simply ensuring that the creation time matches, 1973 * the entry has not been deleted, and it has a valid first 1974 * character should be enough. 1975 * 1976 * Unfortunately, verifying that the <blkno, offset> _still_ 1977 * refers to a directory entry is not easy, since we'd have 1978 * to search _all_ directories starting from root to find it. 1979 * That's a high price to pay just in case somebody is forging 1980 * file handles. So instead we verify that as much of the 1981 * entry is valid as we can: 1982 * 1983 * 1. The starting cluster is 0 (unallocated) or valid 1984 * 2. It is not an LFN entry 1985 * 3. It is not hidden (unless mounted as such) 1986 * 4. It is not the label 1987 */ 1988 cn = pc_getstartcluster(fsp, ep); 1989 /* 1990 * if the starting cluster is valid, but not valid according 1991 * to pc_validcl(), force it to be to simplify the following if. 1992 */ 1993 if (cn == 0) 1994 cn = PCF_FIRSTCLUSTER; 1995 if (IS_FAT32(fsp)) { 1996 if (cn >= PCF_LASTCLUSTER32) 1997 cn = PCF_FIRSTCLUSTER; 1998 } else { 1999 if (cn >= PCF_LASTCLUSTER) 2000 cn = PCF_FIRSTCLUSTER; 2001 } 2002 if ((!pc_validcl(fsp, cn)) || 2003 (PCDL_IS_LFN(ep)) || 2004 (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) || 2005 ((ep->pcd_attr & PCA_LABEL) == PCA_LABEL)) { 2006 bp->b_flags |= B_STALE | B_AGE; 2007 brelse(bp); 2008 pc_unlockfs(fsp); 2009 return (EINVAL); 2010 } 2011 if ((ep->pcd_crtime.pct_time == pcfid->pcfid_ctime) && 2012 (ep->pcd_filename[0] != PCD_ERASED) && 2013 (pc_validchar(ep->pcd_filename[0]) || 2014 (ep->pcd_filename[0] == '.' && ep->pcd_filename[1] == '.'))) { 2015 pcp = pc_getnode(fsp, eblkno, eoffset, ep); 2016 pcp->pc_flags |= PC_EXTERNAL; 2017 *vpp = PCTOV(pcp); 2018 } else { 2019 *vpp = NULL; 2020 } 2021 bp->b_flags |= B_STALE | B_AGE; 2022 brelse(bp); 2023 pc_unlockfs(fsp); 2024 return (0); 2025 } 2026 2027 /* 2028 * if device is a PCMCIA pseudo floppy, return 1 2029 * otherwise, return 0 2030 */ 2031 static int 2032 pcfs_pseudo_floppy(dev_t rdev) 2033 { 2034 int error, err; 2035 struct dk_cinfo info; 2036 ldi_handle_t lh; 2037 ldi_ident_t li; 2038 2039 err = ldi_ident_from_mod(&modlinkage, &li); 2040 if (err) { 2041 PC_DPRINTF1(1, 2042 "pcfs_pseudo_floppy: ldi_ident_from_mod err=%d\n", err); 2043 return (0); 2044 } 2045 2046 err = ldi_open_by_dev(&rdev, OTYP_CHR, FREAD, CRED(), &lh, li); 2047 ldi_ident_release(li); 2048 if (err) { 2049 PC_DPRINTF1(1, 2050 "pcfs_pseudo_floppy: ldi_open err=%d\n", err); 2051 return (0); 2052 } 2053 2054 /* return value stored in err is purposfully ignored */ 2055 error = ldi_ioctl(lh, DKIOCINFO, (intptr_t)&info, FKIOCTL, 2056 CRED(), &err); 2057 2058 err = ldi_close(lh, FREAD, CRED()); 2059 if (err != 0) { 2060 PC_DPRINTF1(1, 2061 "pcfs_pseudo_floppy: ldi_close err=%d\n", err); 2062 return (0); 2063 } 2064 2065 if ((error == 0) && (info.dki_ctype == DKC_PCMCIA_MEM) && 2066 (info.dki_flags & DKI_PCMCIA_PFD)) 2067 return (1); 2068 else 2069 return (0); 2070 } 2071 2072 /* 2073 * Unfortunately, FAT32 fat's can be pretty big (On a 1 gig jaz drive, about 2074 * a meg), so we can't bread() it all in at once. This routine reads a 2075 * fat a chunk at a time. 2076 */ 2077 static int 2078 pc_readfat(struct pcfs *fsp, uchar_t *fatp, daddr_t start, size_t fatsize) 2079 { 2080 struct buf *bp; 2081 size_t off; 2082 size_t readsize; 2083 2084 readsize = fsp->pcfs_clsize; 2085 for (off = 0; off < fatsize; off += readsize, fatp += readsize) { 2086 if (readsize > (fatsize - off)) 2087 readsize = fatsize - off; 2088 bp = bread(fsp->pcfs_xdev, 2089 pc_dbdaddr(fsp, start + 2090 pc_cltodb(fsp, pc_lblkno(fsp, off))), 2091 readsize); 2092 if (bp->b_flags & (B_ERROR | B_STALE)) { 2093 brelse(bp); 2094 return (EIO); 2095 } 2096 bp->b_flags |= B_STALE | B_AGE; 2097 bcopy(bp->b_un.b_addr, fatp, readsize); 2098 brelse(bp); 2099 } 2100 return (0); 2101 } 2102 2103 /* 2104 * We write the FAT out a _lot_, in order to make sure that it 2105 * is up-to-date. But on a FAT32 system (large drive, small clusters) 2106 * the FAT might be a couple of megabytes, and writing it all out just 2107 * because we created or deleted a small file is painful (especially 2108 * since we do it for each alternate FAT too). So instead, for FAT16 and 2109 * FAT32 we only write out the bit that has changed. We don't clear 2110 * the 'updated' fields here because the caller might be writing out 2111 * several FATs, so the caller must use pc_clear_fatchanges() after 2112 * all FATs have been updated. 2113 */ 2114 static int 2115 pc_writefat(struct pcfs *fsp, daddr_t start) 2116 { 2117 struct buf *bp; 2118 size_t off; 2119 size_t writesize; 2120 int error; 2121 uchar_t *fatp = fsp->pcfs_fatp; 2122 size_t fatsize = fsp->pcfs_fatsize; 2123 2124 writesize = fsp->pcfs_clsize; 2125 for (off = 0; off < fatsize; off += writesize, fatp += writesize) { 2126 if (writesize > (fatsize - off)) 2127 writesize = fatsize - off; 2128 if (!pc_fat_is_changed(fsp, pc_lblkno(fsp, off))) { 2129 continue; 2130 } 2131 bp = ngeteblk(writesize); 2132 bp->b_edev = fsp->pcfs_xdev; 2133 bp->b_dev = cmpdev(bp->b_edev); 2134 bp->b_blkno = pc_dbdaddr(fsp, start + 2135 pc_cltodb(fsp, pc_lblkno(fsp, off))); 2136 bcopy(fatp, bp->b_un.b_addr, writesize); 2137 bwrite2(bp); 2138 error = geterror(bp); 2139 brelse(bp); 2140 if (error) { 2141 return (error); 2142 } 2143 } 2144 return (0); 2145 } 2146 2147 /* 2148 * Mark the FAT cluster that 'cn' is stored in as modified. 2149 */ 2150 void 2151 pc_mark_fat_updated(struct pcfs *fsp, pc_cluster32_t cn) 2152 { 2153 pc_cluster32_t bn; 2154 size_t size; 2155 2156 /* which fat block is the cluster number stored in? */ 2157 if (IS_FAT32(fsp)) { 2158 size = sizeof (pc_cluster32_t); 2159 bn = pc_lblkno(fsp, cn * size); 2160 fsp->pcfs_fat_changemap[bn] = 1; 2161 } else if (IS_FAT16(fsp)) { 2162 size = sizeof (pc_cluster16_t); 2163 bn = pc_lblkno(fsp, cn * size); 2164 fsp->pcfs_fat_changemap[bn] = 1; 2165 } else { 2166 offset_t off; 2167 pc_cluster32_t nbn; 2168 2169 ASSERT(IS_FAT12(fsp)); 2170 off = cn + (cn >> 1); 2171 bn = pc_lblkno(fsp, off); 2172 fsp->pcfs_fat_changemap[bn] = 1; 2173 /* does this field wrap into the next fat cluster? */ 2174 nbn = pc_lblkno(fsp, off + 1); 2175 if (nbn != bn) { 2176 fsp->pcfs_fat_changemap[nbn] = 1; 2177 } 2178 } 2179 } 2180 2181 /* 2182 * return whether the FAT cluster 'bn' is updated and needs to 2183 * be written out. 2184 */ 2185 int 2186 pc_fat_is_changed(struct pcfs *fsp, pc_cluster32_t bn) 2187 { 2188 return (fsp->pcfs_fat_changemap[bn] == 1); 2189 } 2190 2191 /* 2192 * Implementation of VFS_FREEVFS() to support forced umounts. 2193 * This is called by the vfs framework after umount, to trigger 2194 * the release of any resources still associated with the given 2195 * vfs_t once the need to keep them has gone away. 2196 */ 2197 void 2198 pcfs_freevfs(vfs_t *vfsp) 2199 { 2200 struct pcfs *fsp = VFSTOPCFS(vfsp); 2201 2202 mutex_enter(&pcfslock); 2203 if (fsp->pcfs_fatp != (uchar_t *)0) 2204 pc_invalfat(fsp); 2205 mutex_exit(&pcfslock); 2206 2207 VN_RELE(fsp->pcfs_devvp); 2208 mutex_destroy(&fsp->pcfs_lock); 2209 kmem_free(fsp, (uint_t)sizeof (struct pcfs)); 2210 2211 /* 2212 * Allow _fini() to succeed now, if so desired. 2213 */ 2214 atomic_dec_32(&pcfs_mountcount); 2215 } 2216