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