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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/param.h> 28 #include <sys/systm.h> 29 #include <sys/kmem.h> 30 #include <sys/user.h> 31 #include <sys/proc.h> 32 #include <sys/cred.h> 33 #include <sys/disp.h> 34 #include <sys/buf.h> 35 #include <sys/vfs.h> 36 #include <sys/vfs_opreg.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 #include <sys/statvfs.h> 43 #include <sys/mount.h> 44 #include <sys/pathname.h> 45 #include <sys/cmn_err.h> 46 #include <sys/debug.h> 47 #include <sys/sysmacros.h> 48 #include <sys/conf.h> 49 #include <sys/mkdev.h> 50 #include <sys/swap.h> 51 #include <sys/sunddi.h> 52 #include <sys/sunldi.h> 53 #include <sys/dktp/fdisk.h> 54 #include <sys/fs/pc_label.h> 55 #include <sys/fs/pc_fs.h> 56 #include <sys/fs/pc_dir.h> 57 #include <sys/fs/pc_node.h> 58 #include <fs/fs_subr.h> 59 #include <sys/modctl.h> 60 #include <sys/dkio.h> 61 #include <sys/open.h> 62 #include <sys/mntent.h> 63 #include <sys/policy.h> 64 #include <sys/atomic.h> 65 #include <sys/sdt.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_readfat(struct pcfs *fsp, uchar_t *fatp); 90 static int pc_writefat(struct pcfs *fsp, daddr_t start); 91 92 static int pc_getfattype(struct pcfs *fsp); 93 static void pcfs_parse_mntopts(struct pcfs *fsp); 94 95 96 /* 97 * pcfs mount options table 98 */ 99 100 static char *nohidden_cancel[] = { MNTOPT_PCFS_HIDDEN, NULL }; 101 static char *hidden_cancel[] = { MNTOPT_PCFS_NOHIDDEN, NULL }; 102 static char *nofoldcase_cancel[] = { MNTOPT_PCFS_FOLDCASE, NULL }; 103 static char *foldcase_cancel[] = { MNTOPT_PCFS_NOFOLDCASE, NULL }; 104 static char *clamptime_cancel[] = { MNTOPT_PCFS_NOCLAMPTIME, NULL }; 105 static char *noclamptime_cancel[] = { MNTOPT_PCFS_CLAMPTIME, NULL }; 106 static char *atime_cancel[] = { MNTOPT_NOATIME, NULL }; 107 static char *noatime_cancel[] = { MNTOPT_ATIME, NULL }; 108 109 static mntopt_t mntopts[] = { 110 /* 111 * option name cancel option default arg flags opt data 112 */ 113 { MNTOPT_PCFS_NOHIDDEN, nohidden_cancel, NULL, 0, NULL }, 114 { MNTOPT_PCFS_HIDDEN, hidden_cancel, NULL, MO_DEFAULT, NULL }, 115 { MNTOPT_PCFS_NOFOLDCASE, nofoldcase_cancel, NULL, MO_DEFAULT, NULL }, 116 { MNTOPT_PCFS_FOLDCASE, foldcase_cancel, NULL, 0, NULL }, 117 { MNTOPT_PCFS_CLAMPTIME, clamptime_cancel, NULL, MO_DEFAULT, NULL }, 118 { MNTOPT_PCFS_NOCLAMPTIME, noclamptime_cancel, NULL, NULL, NULL }, 119 { MNTOPT_NOATIME, noatime_cancel, NULL, NULL, NULL }, 120 { MNTOPT_ATIME, atime_cancel, NULL, NULL, NULL }, 121 { MNTOPT_PCFS_TIMEZONE, NULL, "+0", MO_DEFAULT | MO_HASVALUE, NULL }, 122 { MNTOPT_PCFS_SECSIZE, NULL, NULL, MO_HASVALUE, NULL } 123 }; 124 125 static mntopts_t pcfs_mntopts = { 126 sizeof (mntopts) / sizeof (mntopt_t), 127 mntopts 128 }; 129 130 int pcfsdebuglevel = 0; 131 132 /* 133 * pcfslock: protects the list of mounted pc filesystems "pc_mounttab. 134 * pcfs_lock: (inside per filesystem structure "pcfs") 135 * per filesystem lock. Most of the vfsops and vnodeops are 136 * protected by this lock. 137 * pcnodes_lock: protects the pcnode hash table "pcdhead", "pcfhead". 138 * 139 * Lock hierarchy: pcfslock > pcfs_lock > pcnodes_lock 140 * 141 * pcfs_mountcount: used to prevent module unloads while there is still 142 * pcfs state from a former mount hanging around. With 143 * forced umount support, the filesystem module must not 144 * be allowed to go away before the last VFS_FREEVFS() 145 * call has been made. 146 * Since this is just an atomic counter, there's no need 147 * for locking. 148 */ 149 kmutex_t pcfslock; 150 krwlock_t pcnodes_lock; 151 uint32_t pcfs_mountcount; 152 153 static int pcfstype; 154 155 static vfsdef_t vfw = { 156 VFSDEF_VERSION, 157 "pcfs", 158 pcfsinit, 159 VSW_HASPROTO|VSW_CANREMOUNT|VSW_STATS|VSW_CANLOFI, 160 &pcfs_mntopts 161 }; 162 163 extern struct mod_ops mod_fsops; 164 165 static struct modlfs modlfs = { 166 &mod_fsops, 167 "PC filesystem", 168 &vfw 169 }; 170 171 static struct modlinkage modlinkage = { 172 MODREV_1, 173 &modlfs, 174 NULL 175 }; 176 177 int 178 _init(void) 179 { 180 int error; 181 182 #if !defined(lint) 183 /* make sure the on-disk structures are sane */ 184 ASSERT(sizeof (struct pcdir) == 32); 185 ASSERT(sizeof (struct pcdir_lfn) == 32); 186 #endif 187 mutex_init(&pcfslock, NULL, MUTEX_DEFAULT, NULL); 188 rw_init(&pcnodes_lock, NULL, RW_DEFAULT, NULL); 189 error = mod_install(&modlinkage); 190 if (error) { 191 mutex_destroy(&pcfslock); 192 rw_destroy(&pcnodes_lock); 193 } 194 return (error); 195 } 196 197 int 198 _fini(void) 199 { 200 int error; 201 202 /* 203 * If a forcedly unmounted instance is still hanging around, 204 * we cannot allow the module to be unloaded because that would 205 * cause panics once the VFS framework decides it's time to call 206 * into VFS_FREEVFS(). 207 */ 208 if (pcfs_mountcount) 209 return (EBUSY); 210 211 error = mod_remove(&modlinkage); 212 if (error) 213 return (error); 214 mutex_destroy(&pcfslock); 215 rw_destroy(&pcnodes_lock); 216 /* 217 * Tear down the operations vectors 218 */ 219 (void) vfs_freevfsops_by_type(pcfstype); 220 vn_freevnodeops(pcfs_fvnodeops); 221 vn_freevnodeops(pcfs_dvnodeops); 222 return (0); 223 } 224 225 int 226 _info(struct modinfo *modinfop) 227 { 228 return (mod_info(&modlinkage, modinfop)); 229 } 230 231 /* ARGSUSED1 */ 232 static int 233 pcfsinit(int fstype, char *name) 234 { 235 static const fs_operation_def_t pcfs_vfsops_template[] = { 236 VFSNAME_MOUNT, { .vfs_mount = pcfs_mount }, 237 VFSNAME_UNMOUNT, { .vfs_unmount = pcfs_unmount }, 238 VFSNAME_ROOT, { .vfs_root = pcfs_root }, 239 VFSNAME_STATVFS, { .vfs_statvfs = pcfs_statvfs }, 240 VFSNAME_SYNC, { .vfs_sync = pcfs_sync }, 241 VFSNAME_VGET, { .vfs_vget = pcfs_vget }, 242 VFSNAME_FREEVFS, { .vfs_freevfs = pcfs_freevfs }, 243 NULL, NULL 244 }; 245 int error; 246 247 error = vfs_setfsops(fstype, pcfs_vfsops_template, NULL); 248 if (error != 0) { 249 cmn_err(CE_WARN, "pcfsinit: bad vfs ops template"); 250 return (error); 251 } 252 253 error = vn_make_ops("pcfs", pcfs_fvnodeops_template, &pcfs_fvnodeops); 254 if (error != 0) { 255 (void) vfs_freevfsops_by_type(fstype); 256 cmn_err(CE_WARN, "pcfsinit: bad file vnode ops template"); 257 return (error); 258 } 259 260 error = vn_make_ops("pcfsd", pcfs_dvnodeops_template, &pcfs_dvnodeops); 261 if (error != 0) { 262 (void) vfs_freevfsops_by_type(fstype); 263 vn_freevnodeops(pcfs_fvnodeops); 264 cmn_err(CE_WARN, "pcfsinit: bad dir vnode ops template"); 265 return (error); 266 } 267 268 pcfstype = fstype; 269 (void) pc_init(); 270 pcfs_mountcount = 0; 271 return (0); 272 } 273 274 static struct pcfs *pc_mounttab = NULL; 275 276 extern struct pcfs_args pc_tz; 277 278 /* 279 * Define some special logical drives we use internal to this file. 280 */ 281 #define BOOT_PARTITION_DRIVE 99 282 #define PRIMARY_DOS_DRIVE 1 283 #define UNPARTITIONED_DRIVE 0 284 285 static int 286 pcfs_device_identify( 287 struct vfs *vfsp, 288 struct mounta *uap, 289 struct cred *cr, 290 int *dos_ldrive, 291 dev_t *xdev) 292 { 293 struct pathname special; 294 char *c; 295 struct vnode *svp = NULL; 296 struct vnode *lvp = NULL; 297 int oflag, aflag; 298 int error; 299 300 /* 301 * Resolve path name of special file being mounted. 302 */ 303 if (error = pn_get(uap->spec, UIO_USERSPACE, &special)) { 304 return (error); 305 } 306 307 *dos_ldrive = -1; 308 309 if (error = 310 lookupname(special.pn_path, UIO_SYSSPACE, FOLLOW, NULLVPP, &svp)) { 311 /* 312 * If there's no device node, the name specified most likely 313 * maps to a PCFS-style "partition specifier" to select a 314 * harddisk primary/logical partition. Disable floppy-specific 315 * checks in such cases unless an explicit :A or :B is 316 * requested. 317 */ 318 319 /* 320 * Split the pathname string at the last ':' separator. 321 * If there's no ':' in the device name, or the ':' is the 322 * last character in the string, the name is invalid and 323 * the error from the previous lookup will be returned. 324 */ 325 c = strrchr(special.pn_path, ':'); 326 if (c == NULL || strlen(c) == 0) 327 goto devlookup_done; 328 329 *c++ = '\0'; 330 331 /* 332 * PCFS partition name suffixes can be: 333 * - "boot" to indicate the X86BOOT partition 334 * - a drive letter [c-z] for the "DOS logical drive" 335 * - a drive number 1..24 for the "DOS logical drive" 336 * - a "floppy name letter", 'a' or 'b' (just strip this) 337 */ 338 if (strcasecmp(c, "boot") == 0) { 339 /* 340 * The Solaris boot partition is requested. 341 */ 342 *dos_ldrive = BOOT_PARTITION_DRIVE; 343 } else if (strspn(c, "0123456789") == strlen(c)) { 344 /* 345 * All digits - parse the partition number. 346 */ 347 long drvnum = 0; 348 349 if ((error = ddi_strtol(c, NULL, 10, &drvnum)) == 0) { 350 /* 351 * A number alright - in the allowed range ? 352 */ 353 if (drvnum > 24 || drvnum == 0) 354 error = ENXIO; 355 } 356 if (error) 357 goto devlookup_done; 358 *dos_ldrive = (int)drvnum; 359 } else if (strlen(c) == 1) { 360 /* 361 * A single trailing character was specified. 362 * - [c-zC-Z] means a harddisk partition, and 363 * we retrieve the partition number. 364 * - [abAB] means a floppy drive, so we swallow 365 * the "drive specifier" and test later 366 * whether the physical device is a floppy or 367 * PCMCIA pseudofloppy (sram card). 368 */ 369 *c = tolower(*c); 370 if (*c == 'a' || *c == 'b') { 371 *dos_ldrive = UNPARTITIONED_DRIVE; 372 } else if (*c < 'c' || *c > 'z') { 373 error = ENXIO; 374 goto devlookup_done; 375 } else { 376 *dos_ldrive = 1 + *c - 'c'; 377 } 378 } else { 379 /* 380 * Can't parse this - pass through previous error. 381 */ 382 goto devlookup_done; 383 } 384 385 386 error = lookupname(special.pn_path, UIO_SYSSPACE, FOLLOW, 387 NULLVPP, &svp); 388 } else { 389 *dos_ldrive = UNPARTITIONED_DRIVE; 390 } 391 devlookup_done: 392 pn_free(&special); 393 if (error) 394 return (error); 395 396 ASSERT(*dos_ldrive >= UNPARTITIONED_DRIVE); 397 398 /* 399 * Verify caller's permission to open the device special file. 400 */ 401 if ((vfsp->vfs_flag & VFS_RDONLY) != 0 || 402 ((uap->flags & MS_RDONLY) != 0)) { 403 oflag = FREAD; 404 aflag = VREAD; 405 } else { 406 oflag = FREAD | FWRITE; 407 aflag = VREAD | VWRITE; 408 } 409 410 error = vfs_get_lofi(vfsp, &lvp); 411 412 if (error > 0) { 413 if (error == ENOENT) 414 error = ENODEV; 415 goto out; 416 } else if (error == 0) { 417 *xdev = lvp->v_rdev; 418 } else { 419 *xdev = svp->v_rdev; 420 421 if (svp->v_type != VBLK) { 422 error = ENOTBLK; 423 goto out; 424 } 425 426 if ((error = secpolicy_spec_open(cr, svp, oflag)) != 0) 427 goto out; 428 } 429 430 if (getmajor(*xdev) >= devcnt) { 431 error = ENXIO; 432 goto out; 433 } 434 435 if ((error = VOP_ACCESS(svp, aflag, 0, cr, NULL)) != 0) 436 goto out; 437 438 out: 439 if (svp != NULL) 440 VN_RELE(svp); 441 if (lvp != NULL) 442 VN_RELE(lvp); 443 return (error); 444 } 445 446 static int 447 pcfs_device_ismounted( 448 struct vfs *vfsp, 449 int dos_ldrive, 450 dev_t xdev, 451 int *remounting, 452 dev_t *pseudodev) 453 { 454 struct pcfs *fsp; 455 int remount = *remounting; 456 457 /* 458 * Ensure that this logical drive isn't already mounted, unless 459 * this is a REMOUNT request. 460 * Note: The framework will perform this check if the "...:c" 461 * PCFS-style "logical drive" syntax has not been used and an 462 * actually existing physical device is backing this filesystem. 463 * Once all block device drivers support PC-style partitioning, 464 * this codeblock can be dropped. 465 */ 466 *pseudodev = xdev; 467 468 if (dos_ldrive) { 469 mutex_enter(&pcfslock); 470 for (fsp = pc_mounttab; fsp; fsp = fsp->pcfs_nxt) 471 if (fsp->pcfs_xdev == xdev && 472 fsp->pcfs_ldrive == dos_ldrive) { 473 mutex_exit(&pcfslock); 474 if (remount) { 475 return (0); 476 } else { 477 return (EBUSY); 478 } 479 } 480 /* 481 * Assign a unique device number for the vfs 482 * The old way (getudev() + a constantly incrementing 483 * major number) was wrong because it changes vfs_dev 484 * across mounts and reboots, which breaks nfs file handles. 485 * UFS just uses the real dev_t. We can't do that because 486 * of the way pcfs opens fdisk partitons (the :c and :d 487 * partitions are on the same dev_t). Though that _might_ 488 * actually be ok, since the file handle contains an 489 * absolute block number, it's probably better to make them 490 * different. So I think we should retain the original 491 * dev_t, but come up with a different minor number based 492 * on the logical drive that will _always_ come up the same. 493 * For now, we steal the upper 6 bits. 494 */ 495 #ifdef notdef 496 /* what should we do here? */ 497 if (((getminor(xdev) >> 12) & 0x3F) != 0) 498 printf("whoops - upper bits used!\n"); 499 #endif 500 *pseudodev = makedevice(getmajor(xdev), 501 ((dos_ldrive << 12) | getminor(xdev)) & MAXMIN32); 502 if (vfs_devmounting(*pseudodev, vfsp)) { 503 mutex_exit(&pcfslock); 504 return (EBUSY); 505 } 506 if (vfs_devismounted(*pseudodev)) { 507 mutex_exit(&pcfslock); 508 if (remount) { 509 return (0); 510 } else { 511 return (EBUSY); 512 } 513 } 514 mutex_exit(&pcfslock); 515 } else { 516 *pseudodev = xdev; 517 if (vfs_devmounting(*pseudodev, vfsp)) { 518 return (EBUSY); 519 } 520 if (vfs_devismounted(*pseudodev)) 521 if (remount) { 522 return (0); 523 } else { 524 return (EBUSY); 525 } 526 } 527 528 /* 529 * This is not a remount. Even if MS_REMOUNT was requested, 530 * the caller needs to proceed as it would on an ordinary 531 * mount. 532 */ 533 *remounting = 0; 534 535 ASSERT(*pseudodev); 536 return (0); 537 } 538 539 /* 540 * Get the PCFS-specific mount options from the VFS framework. 541 * For "timezone" and "secsize", we need to parse the number 542 * ourselves and ensure its validity. 543 * Note: "secsize" is deliberately undocumented at this time, 544 * it's a workaround for devices (particularly: lofi image files) 545 * that don't support the DKIOCGMEDIAINFO ioctl for autodetection. 546 */ 547 static void 548 pcfs_parse_mntopts(struct pcfs *fsp) 549 { 550 char *c; 551 char *endptr; 552 long l; 553 struct vfs *vfsp = fsp->pcfs_vfs; 554 555 ASSERT(fsp->pcfs_secondswest == 0); 556 ASSERT(fsp->pcfs_secsize == 0); 557 558 if (vfs_optionisset(vfsp, MNTOPT_PCFS_HIDDEN, NULL)) 559 fsp->pcfs_flags |= PCFS_HIDDEN; 560 if (vfs_optionisset(vfsp, MNTOPT_PCFS_FOLDCASE, NULL)) 561 fsp->pcfs_flags |= PCFS_FOLDCASE; 562 if (vfs_optionisset(vfsp, MNTOPT_PCFS_NOCLAMPTIME, NULL)) 563 fsp->pcfs_flags |= PCFS_NOCLAMPTIME; 564 if (vfs_optionisset(vfsp, MNTOPT_NOATIME, NULL)) 565 fsp->pcfs_flags |= PCFS_NOATIME; 566 567 if (vfs_optionisset(vfsp, MNTOPT_PCFS_TIMEZONE, &c)) { 568 if (ddi_strtol(c, &endptr, 10, &l) == 0 && 569 endptr == c + strlen(c)) { 570 /* 571 * A number alright - in the allowed range ? 572 */ 573 if (l <= -12*3600 || l >= 12*3600) { 574 cmn_err(CE_WARN, "!pcfs: invalid use of " 575 "'timezone' mount option - %ld " 576 "is out of range. Assuming 0.", l); 577 l = 0; 578 } 579 } else { 580 cmn_err(CE_WARN, "!pcfs: invalid use of " 581 "'timezone' mount option - argument %s " 582 "is not a valid number. Assuming 0.", c); 583 l = 0; 584 } 585 fsp->pcfs_secondswest = l; 586 } 587 588 /* 589 * The "secsize=..." mount option is a workaround for the lack of 590 * lofi(7d) support for DKIOCGMEDIAINFO. If PCFS wants to parse the 591 * partition table of a disk image and it has been partitioned with 592 * sector sizes other than 512 bytes, we'd fail on loopback'ed disk 593 * images. 594 * That should really be fixed in lofi ... this is a workaround. 595 */ 596 if (vfs_optionisset(vfsp, MNTOPT_PCFS_SECSIZE, &c)) { 597 if (ddi_strtol(c, &endptr, 10, &l) == 0 && 598 endptr == c + strlen(c)) { 599 /* 600 * A number alright - a valid sector size as well ? 601 */ 602 if (!VALID_SECSIZE(l)) { 603 cmn_err(CE_WARN, "!pcfs: invalid use of " 604 "'secsize' mount option - %ld is " 605 "unsupported. Autodetecting.", l); 606 l = 0; 607 } 608 } else { 609 cmn_err(CE_WARN, "!pcfs: invalid use of " 610 "'secsize' mount option - argument %s " 611 "is not a valid number. Autodetecting.", c); 612 l = 0; 613 } 614 fsp->pcfs_secsize = l; 615 fsp->pcfs_sdshift = ddi_ffs(l / DEV_BSIZE) - 1; 616 } 617 } 618 619 /* 620 * vfs operations 621 */ 622 623 /* 624 * pcfs_mount - backend for VFS_MOUNT() on PCFS. 625 */ 626 static int 627 pcfs_mount( 628 struct vfs *vfsp, 629 struct vnode *mvp, 630 struct mounta *uap, 631 struct cred *cr) 632 { 633 struct pcfs *fsp; 634 struct vnode *devvp; 635 dev_t pseudodev; 636 dev_t xdev; 637 int dos_ldrive = 0; 638 int error; 639 int remounting; 640 641 if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0) 642 return (error); 643 644 if (mvp->v_type != VDIR) 645 return (ENOTDIR); 646 647 mutex_enter(&mvp->v_lock); 648 if ((uap->flags & MS_REMOUNT) == 0 && 649 (uap->flags & MS_OVERLAY) == 0 && 650 (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { 651 mutex_exit(&mvp->v_lock); 652 return (EBUSY); 653 } 654 mutex_exit(&mvp->v_lock); 655 656 /* 657 * PCFS doesn't do mount arguments anymore - everything's a mount 658 * option these days. In order not to break existing callers, we 659 * don't reject it yet, just warn that the data (if any) is ignored. 660 */ 661 if (uap->datalen != 0) 662 cmn_err(CE_WARN, "!pcfs: deprecated use of mount(2) with " 663 "mount argument structures instead of mount options. " 664 "Ignoring mount(2) 'dataptr' argument."); 665 666 /* 667 * This is needed early, to make sure the access / open calls 668 * are done using the correct mode. Processing this mount option 669 * only when calling pcfs_parse_mntopts() would lead us to attempt 670 * a read/write access to a possibly writeprotected device, and 671 * a readonly mount attempt might fail because of that. 672 */ 673 if (uap->flags & MS_RDONLY) { 674 vfsp->vfs_flag |= VFS_RDONLY; 675 vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); 676 } 677 678 /* 679 * For most filesystems, this is just a lookupname() on the 680 * mount pathname string. PCFS historically has to do its own 681 * partition table parsing because not all Solaris architectures 682 * support all styles of partitioning that PC media can have, and 683 * hence PCFS understands "device names" that don't map to actual 684 * physical device nodes. Parsing the "PCFS syntax" for device 685 * names is done in pcfs_device_identify() - see there. 686 * 687 * Once all block device drivers that can host FAT filesystems have 688 * been enhanced to create device nodes for all PC-style partitions, 689 * this code can go away. 690 */ 691 if (error = pcfs_device_identify(vfsp, uap, cr, &dos_ldrive, &xdev)) 692 return (error); 693 694 /* 695 * As with looking up the actual device to mount, PCFS cannot rely 696 * on just the checks done by vfs_ismounted() whether a given device 697 * is mounted already. The additional check against the "PCFS syntax" 698 * is done in pcfs_device_ismounted(). 699 */ 700 remounting = (uap->flags & MS_REMOUNT); 701 702 if (error = pcfs_device_ismounted(vfsp, dos_ldrive, xdev, &remounting, 703 &pseudodev)) 704 return (error); 705 706 if (remounting) 707 return (0); 708 709 /* 710 * Mount the filesystem. 711 * An instance structure is required before the attempt to locate 712 * and parse the FAT BPB. This is because mount options may change 713 * the behaviour of the filesystem type matching code. Precreate 714 * it and fill it in to a degree that allows parsing the mount 715 * options. 716 */ 717 devvp = makespecvp(xdev, VBLK); 718 if (IS_SWAPVP(devvp)) { 719 VN_RELE(devvp); 720 return (EBUSY); 721 } 722 error = VOP_OPEN(&devvp, 723 (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD | FWRITE, cr, NULL); 724 if (error) { 725 VN_RELE(devvp); 726 return (error); 727 } 728 729 fsp = kmem_zalloc(sizeof (*fsp), KM_SLEEP); 730 fsp->pcfs_vfs = vfsp; 731 fsp->pcfs_xdev = xdev; 732 fsp->pcfs_devvp = devvp; 733 fsp->pcfs_ldrive = dos_ldrive; 734 mutex_init(&fsp->pcfs_lock, NULL, MUTEX_DEFAULT, NULL); 735 736 pcfs_parse_mntopts(fsp); 737 738 /* 739 * This is the actual "mount" - the PCFS superblock check. 740 * 741 * Find the requested logical drive and the FAT BPB therein. 742 * Check device type and flag the instance if media is removeable. 743 * 744 * Initializes most members of the filesystem instance structure. 745 * Returns EINVAL if no valid BPB can be found. Other errors may 746 * occur after I/O failures, or when invalid / unparseable partition 747 * tables are encountered. 748 */ 749 if (error = pc_getfattype(fsp)) 750 goto errout; 751 752 /* 753 * Now that the BPB has been parsed, this structural information 754 * is available and known to be valid. Initialize the VFS. 755 */ 756 vfsp->vfs_data = fsp; 757 vfsp->vfs_dev = pseudodev; 758 vfsp->vfs_fstype = pcfstype; 759 vfs_make_fsid(&vfsp->vfs_fsid, pseudodev, pcfstype); 760 vfsp->vfs_bcount = 0; 761 vfsp->vfs_bsize = fsp->pcfs_clsize; 762 763 /* 764 * Validate that we can access the FAT and that it is, to the 765 * degree we can verify here, self-consistent. 766 */ 767 if (error = pc_verify(fsp)) 768 goto errout; 769 770 /* 771 * Record the time of the mount, to return as an "approximate" 772 * timestamp for the FAT root directory. Since FAT roots don't 773 * have timestamps, this is less confusing to the user than 774 * claiming "zero" / Jan/01/1970. 775 */ 776 gethrestime(&fsp->pcfs_mounttime); 777 778 /* 779 * Fix up the mount options. Because "noatime" is made default on 780 * removeable media only, a fixed disk will have neither "atime" 781 * nor "noatime" set. We set the options explicitly depending on 782 * the PCFS_NOATIME flag, to inform the user of what applies. 783 * Mount option cancellation will take care that the mutually 784 * exclusive 'other' is cleared. 785 */ 786 vfs_setmntopt(vfsp, 787 fsp->pcfs_flags & PCFS_NOATIME ? MNTOPT_NOATIME : MNTOPT_ATIME, 788 NULL, 0); 789 790 /* 791 * All clear - insert the FS instance into PCFS' list. 792 */ 793 mutex_enter(&pcfslock); 794 fsp->pcfs_nxt = pc_mounttab; 795 pc_mounttab = fsp; 796 mutex_exit(&pcfslock); 797 atomic_inc_32(&pcfs_mountcount); 798 return (0); 799 800 errout: 801 (void) VOP_CLOSE(devvp, 802 vfsp->vfs_flag & VFS_RDONLY ? FREAD : FREAD | FWRITE, 803 1, (offset_t)0, cr, NULL); 804 VN_RELE(devvp); 805 mutex_destroy(&fsp->pcfs_lock); 806 kmem_free(fsp, sizeof (*fsp)); 807 return (error); 808 809 } 810 811 static int 812 pcfs_unmount( 813 struct vfs *vfsp, 814 int flag, 815 struct cred *cr) 816 { 817 struct pcfs *fsp, *fsp1; 818 819 if (secpolicy_fs_unmount(cr, vfsp) != 0) 820 return (EPERM); 821 822 fsp = VFSTOPCFS(vfsp); 823 824 /* 825 * We don't have to lock fsp because the VVFSLOCK in vfs layer will 826 * prevent lookuppn from crossing the mount point. 827 * If this is not a forced umount request and there's ongoing I/O, 828 * don't allow the mount to proceed. 829 */ 830 if (flag & MS_FORCE) 831 vfsp->vfs_flag |= VFS_UNMOUNTED; 832 else if (fsp->pcfs_nrefs) 833 return (EBUSY); 834 835 mutex_enter(&pcfslock); 836 837 /* 838 * If this is a forced umount request or if the fs instance has 839 * been marked as beyond recovery, allow the umount to proceed 840 * regardless of state. pc_diskchanged() forcibly releases all 841 * inactive vnodes/pcnodes. 842 */ 843 if (flag & MS_FORCE || fsp->pcfs_flags & PCFS_IRRECOV) { 844 rw_enter(&pcnodes_lock, RW_WRITER); 845 pc_diskchanged(fsp); 846 rw_exit(&pcnodes_lock); 847 } 848 849 /* now there should be no pcp node on pcfhead or pcdhead. */ 850 851 if (fsp == pc_mounttab) { 852 pc_mounttab = fsp->pcfs_nxt; 853 } else { 854 for (fsp1 = pc_mounttab; fsp1 != NULL; fsp1 = fsp1->pcfs_nxt) 855 if (fsp1->pcfs_nxt == fsp) 856 fsp1->pcfs_nxt = fsp->pcfs_nxt; 857 } 858 859 mutex_exit(&pcfslock); 860 861 /* 862 * Since we support VFS_FREEVFS(), there's no need to 863 * free the fsp right now. The framework will tell us 864 * when the right time to do so has arrived by calling 865 * into pcfs_freevfs. 866 */ 867 return (0); 868 } 869 870 /* 871 * find root of pcfs 872 */ 873 static int 874 pcfs_root( 875 struct vfs *vfsp, 876 struct vnode **vpp) 877 { 878 struct pcfs *fsp; 879 struct pcnode *pcp; 880 int error; 881 882 fsp = VFSTOPCFS(vfsp); 883 if (error = pc_lockfs(fsp, 0, 0)) 884 return (error); 885 886 pcp = pc_getnode(fsp, (daddr_t)0, 0, (struct pcdir *)0); 887 pc_unlockfs(fsp); 888 *vpp = PCTOV(pcp); 889 pcp->pc_flags |= PC_EXTERNAL; 890 return (0); 891 } 892 893 /* 894 * Get file system statistics. 895 */ 896 static int 897 pcfs_statvfs( 898 struct vfs *vfsp, 899 struct statvfs64 *sp) 900 { 901 struct pcfs *fsp; 902 int error; 903 dev32_t d32; 904 905 fsp = VFSTOPCFS(vfsp); 906 error = pc_getfat(fsp); 907 if (error) 908 return (error); 909 bzero(sp, sizeof (*sp)); 910 sp->f_bsize = sp->f_frsize = fsp->pcfs_clsize; 911 sp->f_blocks = (fsblkcnt64_t)fsp->pcfs_ncluster; 912 sp->f_bavail = sp->f_bfree = (fsblkcnt64_t)pc_freeclusters(fsp); 913 sp->f_files = (fsfilcnt64_t)-1; 914 sp->f_ffree = (fsfilcnt64_t)-1; 915 sp->f_favail = (fsfilcnt64_t)-1; 916 #ifdef notdef 917 (void) cmpldev(&d32, fsp->pcfs_devvp->v_rdev); 918 #endif /* notdef */ 919 (void) cmpldev(&d32, vfsp->vfs_dev); 920 sp->f_fsid = d32; 921 (void) strcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name); 922 sp->f_flag = vf_to_stf(vfsp->vfs_flag); 923 sp->f_namemax = PCMAXNAMLEN; 924 return (0); 925 } 926 927 static int 928 pc_syncfsnodes(struct pcfs *fsp) 929 { 930 struct pchead *hp; 931 struct pcnode *pcp; 932 int error; 933 934 if (error = pc_lockfs(fsp, 0, 0)) 935 return (error); 936 937 if (!(error = pc_syncfat(fsp))) { 938 hp = pcfhead; 939 while (hp < & pcfhead [ NPCHASH ]) { 940 rw_enter(&pcnodes_lock, RW_READER); 941 pcp = hp->pch_forw; 942 while (pcp != (struct pcnode *)hp) { 943 if (VFSTOPCFS(PCTOV(pcp) -> v_vfsp) == fsp) 944 if (error = pc_nodesync(pcp)) 945 break; 946 pcp = pcp -> pc_forw; 947 } 948 rw_exit(&pcnodes_lock); 949 if (error) 950 break; 951 hp++; 952 } 953 } 954 pc_unlockfs(fsp); 955 return (error); 956 } 957 958 /* 959 * Flush any pending I/O. 960 */ 961 /*ARGSUSED*/ 962 static int 963 pcfs_sync( 964 struct vfs *vfsp, 965 short flag, 966 struct cred *cr) 967 { 968 struct pcfs *fsp; 969 int error = 0; 970 971 /* this prevents the filesystem from being umounted. */ 972 mutex_enter(&pcfslock); 973 if (vfsp != NULL) { 974 fsp = VFSTOPCFS(vfsp); 975 if (!(fsp->pcfs_flags & PCFS_IRRECOV)) { 976 error = pc_syncfsnodes(fsp); 977 } else { 978 rw_enter(&pcnodes_lock, RW_WRITER); 979 pc_diskchanged(fsp); 980 rw_exit(&pcnodes_lock); 981 error = EIO; 982 } 983 } else { 984 fsp = pc_mounttab; 985 while (fsp != NULL) { 986 if (fsp->pcfs_flags & PCFS_IRRECOV) { 987 rw_enter(&pcnodes_lock, RW_WRITER); 988 pc_diskchanged(fsp); 989 rw_exit(&pcnodes_lock); 990 error = EIO; 991 break; 992 } 993 error = pc_syncfsnodes(fsp); 994 if (error) break; 995 fsp = fsp->pcfs_nxt; 996 } 997 } 998 mutex_exit(&pcfslock); 999 return (error); 1000 } 1001 1002 int 1003 pc_lockfs(struct pcfs *fsp, int diskchanged, int releasing) 1004 { 1005 int err; 1006 1007 if ((fsp->pcfs_flags & PCFS_IRRECOV) && !releasing) 1008 return (EIO); 1009 1010 if ((fsp->pcfs_flags & PCFS_LOCKED) && (fsp->pcfs_owner == curthread)) { 1011 fsp->pcfs_count++; 1012 } else { 1013 mutex_enter(&fsp->pcfs_lock); 1014 if (fsp->pcfs_flags & PCFS_LOCKED) 1015 panic("pc_lockfs"); 1016 /* 1017 * We check the IRRECOV bit again just in case somebody 1018 * snuck past the initial check but then got held up before 1019 * they could grab the lock. (And in the meantime someone 1020 * had grabbed the lock and set the bit) 1021 */ 1022 if (!diskchanged && !(fsp->pcfs_flags & PCFS_IRRECOV)) { 1023 if ((err = pc_getfat(fsp))) { 1024 mutex_exit(&fsp->pcfs_lock); 1025 return (err); 1026 } 1027 } 1028 fsp->pcfs_flags |= PCFS_LOCKED; 1029 fsp->pcfs_owner = curthread; 1030 fsp->pcfs_count++; 1031 } 1032 return (0); 1033 } 1034 1035 void 1036 pc_unlockfs(struct pcfs *fsp) 1037 { 1038 1039 if ((fsp->pcfs_flags & PCFS_LOCKED) == 0) 1040 panic("pc_unlockfs"); 1041 if (--fsp->pcfs_count < 0) 1042 panic("pc_unlockfs: count"); 1043 if (fsp->pcfs_count == 0) { 1044 fsp->pcfs_flags &= ~PCFS_LOCKED; 1045 fsp->pcfs_owner = 0; 1046 mutex_exit(&fsp->pcfs_lock); 1047 } 1048 } 1049 1050 int 1051 pc_syncfat(struct pcfs *fsp) 1052 { 1053 struct buf *bp; 1054 int nfat; 1055 int error = 0; 1056 struct fat_od_fsi *fsinfo_disk; 1057 1058 if ((fsp->pcfs_fatp == (uchar_t *)0) || 1059 !(fsp->pcfs_flags & PCFS_FATMOD)) 1060 return (0); 1061 /* 1062 * write out all copies of FATs 1063 */ 1064 fsp->pcfs_flags &= ~PCFS_FATMOD; 1065 fsp->pcfs_fattime = gethrestime_sec() + PCFS_DISKTIMEOUT; 1066 for (nfat = 0; nfat < fsp->pcfs_numfat; nfat++) { 1067 error = pc_writefat(fsp, pc_dbdaddr(fsp, 1068 fsp->pcfs_fatstart + nfat * fsp->pcfs_fatsec)); 1069 if (error) { 1070 pc_mark_irrecov(fsp); 1071 return (EIO); 1072 } 1073 } 1074 pc_clear_fatchanges(fsp); 1075 1076 /* 1077 * Write out fsinfo sector. 1078 */ 1079 if (IS_FAT32(fsp)) { 1080 bp = bread(fsp->pcfs_xdev, 1081 pc_dbdaddr(fsp, fsp->pcfs_fsistart), fsp->pcfs_secsize); 1082 if (bp->b_flags & (B_ERROR | B_STALE)) { 1083 error = geterror(bp); 1084 } 1085 fsinfo_disk = (fat_od_fsi_t *)(bp->b_un.b_addr); 1086 if (!error && FSISIG_OK(fsinfo_disk)) { 1087 fsinfo_disk->fsi_incore.fs_free_clusters = 1088 LE_32(fsp->pcfs_fsinfo.fs_free_clusters); 1089 fsinfo_disk->fsi_incore.fs_next_free = 1090 LE_32(FSINFO_UNKNOWN); 1091 bwrite2(bp); 1092 error = geterror(bp); 1093 } 1094 brelse(bp); 1095 if (error) { 1096 pc_mark_irrecov(fsp); 1097 return (EIO); 1098 } 1099 } 1100 return (0); 1101 } 1102 1103 void 1104 pc_invalfat(struct pcfs *fsp) 1105 { 1106 struct pcfs *xfsp; 1107 int mount_cnt = 0; 1108 1109 if (fsp->pcfs_fatp == (uchar_t *)0) 1110 panic("pc_invalfat"); 1111 /* 1112 * Release FAT 1113 */ 1114 kmem_free(fsp->pcfs_fatp, fsp->pcfs_fatsec * fsp->pcfs_secsize); 1115 fsp->pcfs_fatp = NULL; 1116 kmem_free(fsp->pcfs_fat_changemap, fsp->pcfs_fat_changemapsize); 1117 fsp->pcfs_fat_changemap = NULL; 1118 /* 1119 * Invalidate all the blocks associated with the device. 1120 * Not needed if stateless. 1121 */ 1122 for (xfsp = pc_mounttab; xfsp; xfsp = xfsp->pcfs_nxt) 1123 if (xfsp != fsp && xfsp->pcfs_xdev == fsp->pcfs_xdev) 1124 mount_cnt++; 1125 1126 if (!mount_cnt) 1127 binval(fsp->pcfs_xdev); 1128 /* 1129 * close mounted device 1130 */ 1131 (void) VOP_CLOSE(fsp->pcfs_devvp, 1132 (PCFSTOVFS(fsp)->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE, 1133 1, (offset_t)0, CRED(), NULL); 1134 } 1135 1136 void 1137 pc_badfs(struct pcfs *fsp) 1138 { 1139 cmn_err(CE_WARN, "corrupted PC file system on dev (%x.%x):%d\n", 1140 getmajor(fsp->pcfs_devvp->v_rdev), 1141 getminor(fsp->pcfs_devvp->v_rdev), fsp->pcfs_ldrive); 1142 } 1143 1144 /* 1145 * The problem with supporting NFS on the PCFS filesystem is that there 1146 * is no good place to keep the generation number. The only possible 1147 * place is inside a directory entry. There are a few words that we 1148 * don't use - they store NT & OS/2 attributes, and the creation/last access 1149 * time of the file - but it seems wrong to use them. In addition, directory 1150 * entries come and go. If a directory is removed completely, its directory 1151 * blocks are freed and the generation numbers are lost. Whereas in ufs, 1152 * inode blocks are dedicated for inodes, so the generation numbers are 1153 * permanently kept on the disk. 1154 */ 1155 static int 1156 pcfs_vget(struct vfs *vfsp, struct vnode **vpp, struct fid *fidp) 1157 { 1158 struct pcnode *pcp; 1159 struct pc_fid *pcfid; 1160 struct pcfs *fsp; 1161 struct pcdir *ep; 1162 daddr_t eblkno; 1163 int eoffset; 1164 struct buf *bp; 1165 int error; 1166 pc_cluster32_t cn; 1167 1168 pcfid = (struct pc_fid *)fidp; 1169 fsp = VFSTOPCFS(vfsp); 1170 1171 error = pc_lockfs(fsp, 0, 0); 1172 if (error) { 1173 *vpp = NULL; 1174 return (error); 1175 } 1176 1177 if (pcfid->pcfid_block == 0) { 1178 pcp = pc_getnode(fsp, (daddr_t)0, 0, (struct pcdir *)0); 1179 pcp->pc_flags |= PC_EXTERNAL; 1180 *vpp = PCTOV(pcp); 1181 pc_unlockfs(fsp); 1182 return (0); 1183 } 1184 eblkno = pcfid->pcfid_block; 1185 eoffset = pcfid->pcfid_offset; 1186 1187 if ((pc_dbtocl(fsp, 1188 eblkno - fsp->pcfs_dosstart) >= fsp->pcfs_ncluster) || 1189 (eoffset > fsp->pcfs_clsize)) { 1190 pc_unlockfs(fsp); 1191 *vpp = NULL; 1192 return (EINVAL); 1193 } 1194 1195 if (eblkno >= fsp->pcfs_datastart || (eblkno - fsp->pcfs_rdirstart) 1196 < (fsp->pcfs_rdirsec & ~(fsp->pcfs_spcl - 1))) { 1197 bp = bread(fsp->pcfs_xdev, pc_dbdaddr(fsp, eblkno), 1198 fsp->pcfs_clsize); 1199 } else { 1200 /* 1201 * This is an access "backwards" into the FAT12/FAT16 1202 * root directory. A better code structure would 1203 * significantly improve maintainability here ... 1204 */ 1205 bp = bread(fsp->pcfs_xdev, pc_dbdaddr(fsp, eblkno), 1206 (int)(fsp->pcfs_datastart - eblkno) * fsp->pcfs_secsize); 1207 } 1208 if (bp->b_flags & (B_ERROR | B_STALE)) { 1209 error = geterror(bp); 1210 brelse(bp); 1211 if (error) 1212 pc_mark_irrecov(fsp); 1213 *vpp = NULL; 1214 pc_unlockfs(fsp); 1215 return (error); 1216 } 1217 ep = (struct pcdir *)(bp->b_un.b_addr + eoffset); 1218 /* 1219 * Ok, if this is a valid file handle that we gave out, 1220 * then simply ensuring that the creation time matches, 1221 * the entry has not been deleted, and it has a valid first 1222 * character should be enough. 1223 * 1224 * Unfortunately, verifying that the <blkno, offset> _still_ 1225 * refers to a directory entry is not easy, since we'd have 1226 * to search _all_ directories starting from root to find it. 1227 * That's a high price to pay just in case somebody is forging 1228 * file handles. So instead we verify that as much of the 1229 * entry is valid as we can: 1230 * 1231 * 1. The starting cluster is 0 (unallocated) or valid 1232 * 2. It is not an LFN entry 1233 * 3. It is not hidden (unless mounted as such) 1234 * 4. It is not the label 1235 */ 1236 cn = pc_getstartcluster(fsp, ep); 1237 /* 1238 * if the starting cluster is valid, but not valid according 1239 * to pc_validcl(), force it to be to simplify the following if. 1240 */ 1241 if (cn == 0) 1242 cn = PCF_FIRSTCLUSTER; 1243 if (IS_FAT32(fsp)) { 1244 if (cn >= PCF_LASTCLUSTER32) 1245 cn = PCF_FIRSTCLUSTER; 1246 } else { 1247 if (cn >= PCF_LASTCLUSTER) 1248 cn = PCF_FIRSTCLUSTER; 1249 } 1250 if ((!pc_validcl(fsp, cn)) || 1251 (PCDL_IS_LFN(ep)) || 1252 (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) || 1253 ((ep->pcd_attr & PCA_LABEL) == PCA_LABEL)) { 1254 bp->b_flags |= B_STALE | B_AGE; 1255 brelse(bp); 1256 pc_unlockfs(fsp); 1257 return (EINVAL); 1258 } 1259 if ((ep->pcd_crtime.pct_time == pcfid->pcfid_ctime) && 1260 (ep->pcd_filename[0] != PCD_ERASED) && 1261 (pc_validchar(ep->pcd_filename[0]) || 1262 (ep->pcd_filename[0] == '.' && ep->pcd_filename[1] == '.'))) { 1263 pcp = pc_getnode(fsp, eblkno, eoffset, ep); 1264 pcp->pc_flags |= PC_EXTERNAL; 1265 *vpp = PCTOV(pcp); 1266 } else { 1267 *vpp = NULL; 1268 } 1269 bp->b_flags |= B_STALE | B_AGE; 1270 brelse(bp); 1271 pc_unlockfs(fsp); 1272 return (0); 1273 } 1274 1275 /* 1276 * Unfortunately, FAT32 fat's can be pretty big (On a 1 gig jaz drive, about 1277 * a meg), so we can't bread() it all in at once. This routine reads a 1278 * fat a chunk at a time. 1279 */ 1280 static int 1281 pc_readfat(struct pcfs *fsp, uchar_t *fatp) 1282 { 1283 struct buf *bp; 1284 size_t off; 1285 size_t readsize; 1286 daddr_t diskblk; 1287 size_t fatsize = fsp->pcfs_fatsec * fsp->pcfs_secsize; 1288 daddr_t start = fsp->pcfs_fatstart; 1289 1290 readsize = fsp->pcfs_clsize; 1291 for (off = 0; off < fatsize; off += readsize, fatp += readsize) { 1292 if (readsize > (fatsize - off)) 1293 readsize = fatsize - off; 1294 diskblk = pc_dbdaddr(fsp, start + 1295 pc_cltodb(fsp, pc_lblkno(fsp, off))); 1296 bp = bread(fsp->pcfs_xdev, diskblk, readsize); 1297 if (bp->b_flags & (B_ERROR | B_STALE)) { 1298 brelse(bp); 1299 return (EIO); 1300 } 1301 bp->b_flags |= B_STALE | B_AGE; 1302 bcopy(bp->b_un.b_addr, fatp, readsize); 1303 brelse(bp); 1304 } 1305 return (0); 1306 } 1307 1308 /* 1309 * We write the FAT out a _lot_, in order to make sure that it 1310 * is up-to-date. But on a FAT32 system (large drive, small clusters) 1311 * the FAT might be a couple of megabytes, and writing it all out just 1312 * because we created or deleted a small file is painful (especially 1313 * since we do it for each alternate FAT too). So instead, for FAT16 and 1314 * FAT32 we only write out the bit that has changed. We don't clear 1315 * the 'updated' fields here because the caller might be writing out 1316 * several FATs, so the caller must use pc_clear_fatchanges() after 1317 * all FATs have been updated. 1318 * This function doesn't take "start" from fsp->pcfs_dosstart because 1319 * callers can use it to write either the primary or any of the alternate 1320 * FAT tables. 1321 */ 1322 static int 1323 pc_writefat(struct pcfs *fsp, daddr_t start) 1324 { 1325 struct buf *bp; 1326 size_t off; 1327 size_t writesize; 1328 int error; 1329 uchar_t *fatp = fsp->pcfs_fatp; 1330 size_t fatsize = fsp->pcfs_fatsec * fsp->pcfs_secsize; 1331 1332 writesize = fsp->pcfs_clsize; 1333 for (off = 0; off < fatsize; off += writesize, fatp += writesize) { 1334 if (writesize > (fatsize - off)) 1335 writesize = fatsize - off; 1336 if (!pc_fat_is_changed(fsp, pc_lblkno(fsp, off))) { 1337 continue; 1338 } 1339 bp = ngeteblk(writesize); 1340 bp->b_edev = fsp->pcfs_xdev; 1341 bp->b_dev = cmpdev(bp->b_edev); 1342 bp->b_blkno = pc_dbdaddr(fsp, start + 1343 pc_cltodb(fsp, pc_lblkno(fsp, off))); 1344 bcopy(fatp, bp->b_un.b_addr, writesize); 1345 bwrite2(bp); 1346 error = geterror(bp); 1347 brelse(bp); 1348 if (error) { 1349 return (error); 1350 } 1351 } 1352 return (0); 1353 } 1354 1355 /* 1356 * Mark the FAT cluster that 'cn' is stored in as modified. 1357 */ 1358 void 1359 pc_mark_fat_updated(struct pcfs *fsp, pc_cluster32_t cn) 1360 { 1361 pc_cluster32_t bn; 1362 size_t size; 1363 1364 /* which fat block is the cluster number stored in? */ 1365 if (IS_FAT32(fsp)) { 1366 size = sizeof (pc_cluster32_t); 1367 bn = pc_lblkno(fsp, cn * size); 1368 fsp->pcfs_fat_changemap[bn] = 1; 1369 } else if (IS_FAT16(fsp)) { 1370 size = sizeof (pc_cluster16_t); 1371 bn = pc_lblkno(fsp, cn * size); 1372 fsp->pcfs_fat_changemap[bn] = 1; 1373 } else { 1374 offset_t off; 1375 pc_cluster32_t nbn; 1376 1377 ASSERT(IS_FAT12(fsp)); 1378 off = cn + (cn >> 1); 1379 bn = pc_lblkno(fsp, off); 1380 fsp->pcfs_fat_changemap[bn] = 1; 1381 /* does this field wrap into the next fat cluster? */ 1382 nbn = pc_lblkno(fsp, off + 1); 1383 if (nbn != bn) { 1384 fsp->pcfs_fat_changemap[nbn] = 1; 1385 } 1386 } 1387 } 1388 1389 /* 1390 * return whether the FAT cluster 'bn' is updated and needs to 1391 * be written out. 1392 */ 1393 int 1394 pc_fat_is_changed(struct pcfs *fsp, pc_cluster32_t bn) 1395 { 1396 return (fsp->pcfs_fat_changemap[bn] == 1); 1397 } 1398 1399 /* 1400 * Implementation of VFS_FREEVFS() to support forced umounts. 1401 * This is called by the vfs framework after umount, to trigger 1402 * the release of any resources still associated with the given 1403 * vfs_t once the need to keep them has gone away. 1404 */ 1405 void 1406 pcfs_freevfs(vfs_t *vfsp) 1407 { 1408 struct pcfs *fsp = VFSTOPCFS(vfsp); 1409 1410 mutex_enter(&pcfslock); 1411 /* 1412 * Purging the FAT closes the device - can't do any more 1413 * I/O after this. 1414 */ 1415 if (fsp->pcfs_fatp != (uchar_t *)0) 1416 pc_invalfat(fsp); 1417 mutex_exit(&pcfslock); 1418 1419 VN_RELE(fsp->pcfs_devvp); 1420 mutex_destroy(&fsp->pcfs_lock); 1421 kmem_free(fsp, sizeof (*fsp)); 1422 1423 /* 1424 * Allow _fini() to succeed now, if so desired. 1425 */ 1426 atomic_dec_32(&pcfs_mountcount); 1427 } 1428 1429 1430 /* 1431 * PC-style partition parsing and FAT BPB identification/validation code. 1432 * The partition parsers here assume: 1433 * - a FAT filesystem will be in a partition that has one of a set of 1434 * recognized partition IDs 1435 * - the user wants the 'numbering' (C:, D:, ...) that one would get 1436 * on MSDOS 6.x. 1437 * That means any non-FAT partition type (NTFS, HPFS, or any Linux fs) 1438 * will not factor in the enumeration. 1439 * These days, such assumptions should be revisited. FAT is no longer the 1440 * only game in 'PC town'. 1441 */ 1442 /* 1443 * isDosDrive() 1444 * Boolean function. Give it the systid field for an fdisk partition 1445 * and it decides if that's a systid that describes a DOS drive. We 1446 * use systid values defined in sys/dktp/fdisk.h. 1447 */ 1448 static int 1449 isDosDrive(uchar_t checkMe) 1450 { 1451 return ((checkMe == DOSOS12) || (checkMe == DOSOS16) || 1452 (checkMe == DOSHUGE) || (checkMe == FDISK_WINDOWS) || 1453 (checkMe == FDISK_EXT_WIN) || (checkMe == FDISK_FAT95) || 1454 (checkMe == DIAGPART)); 1455 } 1456 1457 1458 /* 1459 * isDosExtended() 1460 * Boolean function. Give it the systid field for an fdisk partition 1461 * and it decides if that's a systid that describes an extended DOS 1462 * partition. 1463 */ 1464 static int 1465 isDosExtended(uchar_t checkMe) 1466 { 1467 return ((checkMe == EXTDOS) || (checkMe == FDISK_EXTLBA)); 1468 } 1469 1470 1471 /* 1472 * isBootPart() 1473 * Boolean function. Give it the systid field for an fdisk partition 1474 * and it decides if that's a systid that describes a Solaris boot 1475 * partition. 1476 */ 1477 static int 1478 isBootPart(uchar_t checkMe) 1479 { 1480 return (checkMe == X86BOOT); 1481 } 1482 1483 1484 /* 1485 * noLogicalDrive() 1486 * Display error message about not being able to find a logical 1487 * drive. 1488 */ 1489 static void 1490 noLogicalDrive(int ldrive) 1491 { 1492 if (ldrive == BOOT_PARTITION_DRIVE) { 1493 cmn_err(CE_NOTE, "!pcfs: no boot partition"); 1494 } else { 1495 cmn_err(CE_NOTE, "!pcfs: %d: no such logical drive", ldrive); 1496 } 1497 } 1498 1499 1500 /* 1501 * findTheDrive() 1502 * Discover offset of the requested logical drive, and return 1503 * that offset (startSector), the systid of that drive (sysid), 1504 * and a buffer pointer (bp), with the buffer contents being 1505 * the first sector of the logical drive (i.e., the sector that 1506 * contains the BPB for that drive). 1507 * 1508 * Note: this code is not capable of addressing >2TB disks, as it uses 1509 * daddr_t not diskaddr_t, some of the calculations would overflow 1510 */ 1511 #define COPY_PTBL(mbr, ptblp) \ 1512 bcopy(&(((struct mboot *)(mbr))->parts), (ptblp), \ 1513 FD_NUMPART * sizeof (struct ipart)) 1514 1515 static int 1516 findTheDrive(struct pcfs *fsp, buf_t **bp) 1517 { 1518 int ldrive = fsp->pcfs_ldrive; 1519 dev_t dev = fsp->pcfs_devvp->v_rdev; 1520 1521 struct ipart dosp[FD_NUMPART]; /* incore fdisk partition structure */ 1522 daddr_t lastseek = 0; /* Disk block we sought previously */ 1523 daddr_t diskblk = 0; /* Disk block to get */ 1524 daddr_t xstartsect; /* base of Extended DOS partition */ 1525 int logicalDriveCount = 0; /* Count of logical drives seen */ 1526 int extendedPart = -1; /* index of extended dos partition */ 1527 int primaryPart = -1; /* index of primary dos partition */ 1528 int bootPart = -1; /* index of a Solaris boot partition */ 1529 uint32_t xnumsect = 0; /* length of extended DOS partition */ 1530 int driveIndex; /* computed FDISK table index */ 1531 daddr_t startsec; 1532 len_t mediasize; 1533 int i; 1534 /* 1535 * Count of drives in the current extended partition's 1536 * FDISK table, and indexes of the drives themselves. 1537 */ 1538 int extndDrives[FD_NUMPART]; 1539 int numDrives = 0; 1540 1541 /* 1542 * Count of drives (beyond primary) in master boot record's 1543 * FDISK table, and indexes of the drives themselves. 1544 */ 1545 int extraDrives[FD_NUMPART]; 1546 int numExtraDrives = 0; 1547 1548 /* 1549 * "ldrive == 0" should never happen, as this is a request to 1550 * mount the physical device (and ignore partitioning). The code 1551 * in pcfs_mount() should have made sure that a logical drive number 1552 * is at least 1, meaning we're looking for drive "C:". It is not 1553 * safe (and a bug in the callers of this function) to request logical 1554 * drive number 0; we could ASSERT() but a graceful EIO is a more 1555 * polite way. 1556 */ 1557 if (ldrive == 0) { 1558 cmn_err(CE_NOTE, "!pcfs: request for logical partition zero"); 1559 noLogicalDrive(ldrive); 1560 return (EIO); 1561 } 1562 1563 /* 1564 * Copy from disk block into memory aligned structure for fdisk usage. 1565 */ 1566 COPY_PTBL((*bp)->b_un.b_addr, dosp); 1567 1568 /* 1569 * This check is ok because a FAT BPB and a master boot record (MBB) 1570 * have the same signature, in the same position within the block. 1571 */ 1572 if (bpb_get_BPBSig((*bp)->b_un.b_addr) != MBB_MAGIC) { 1573 cmn_err(CE_NOTE, "!pcfs: MBR partition table signature err, " 1574 "device (%x.%x):%d\n", 1575 getmajor(dev), getminor(dev), ldrive); 1576 return (EINVAL); 1577 } 1578 1579 /* 1580 * Get a summary of what is in the Master FDISK table. 1581 * Normally we expect to find one partition marked as a DOS drive. 1582 * This partition is the one Windows calls the primary dos partition. 1583 * If the machine has any logical drives then we also expect 1584 * to find a partition marked as an extended DOS partition. 1585 * 1586 * Sometimes we'll find multiple partitions marked as DOS drives. 1587 * The Solaris fdisk program allows these partitions 1588 * to be created, but Windows fdisk no longer does. We still need 1589 * to support these, though, since Windows does. We also need to fix 1590 * our fdisk to behave like the Windows version. 1591 * 1592 * It turns out that some off-the-shelf media have *only* an 1593 * Extended partition, so we need to deal with that case as well. 1594 * 1595 * Only a single (the first) Extended or Boot Partition will 1596 * be recognized. Any others will be ignored. 1597 */ 1598 for (i = 0; i < FD_NUMPART; i++) { 1599 DTRACE_PROBE4(primarypart, struct pcfs *, fsp, 1600 uint_t, (uint_t)dosp[i].systid, 1601 uint_t, LE_32(dosp[i].relsect), 1602 uint_t, LE_32(dosp[i].numsect)); 1603 1604 if (isDosDrive(dosp[i].systid)) { 1605 if (primaryPart < 0) { 1606 logicalDriveCount++; 1607 primaryPart = i; 1608 } else { 1609 extraDrives[numExtraDrives++] = i; 1610 } 1611 continue; 1612 } 1613 if ((extendedPart < 0) && isDosExtended(dosp[i].systid)) { 1614 extendedPart = i; 1615 continue; 1616 } 1617 if ((bootPart < 0) && isBootPart(dosp[i].systid)) { 1618 bootPart = i; 1619 continue; 1620 } 1621 } 1622 1623 if (ldrive == BOOT_PARTITION_DRIVE) { 1624 if (bootPart < 0) { 1625 noLogicalDrive(ldrive); 1626 return (EINVAL); 1627 } 1628 startsec = LE_32(dosp[bootPart].relsect); 1629 mediasize = LE_32(dosp[bootPart].numsect); 1630 goto found; 1631 } 1632 1633 if (ldrive == PRIMARY_DOS_DRIVE && primaryPart >= 0) { 1634 startsec = LE_32(dosp[primaryPart].relsect); 1635 mediasize = LE_32(dosp[primaryPart].numsect); 1636 goto found; 1637 } 1638 1639 /* 1640 * We are not looking for the C: drive (or the primary drive 1641 * was not found), so we had better have an extended partition 1642 * or extra drives in the Master FDISK table. 1643 */ 1644 if ((extendedPart < 0) && (numExtraDrives == 0)) { 1645 cmn_err(CE_NOTE, "!pcfs: no extended dos partition"); 1646 noLogicalDrive(ldrive); 1647 return (EINVAL); 1648 } 1649 1650 if (extendedPart >= 0) { 1651 diskblk = xstartsect = LE_32(dosp[extendedPart].relsect); 1652 xnumsect = LE_32(dosp[extendedPart].numsect); 1653 do { 1654 /* 1655 * If the seek would not cause us to change 1656 * position on the drive, then we're out of 1657 * extended partitions to examine. 1658 */ 1659 if (diskblk == lastseek) 1660 break; 1661 logicalDriveCount += numDrives; 1662 /* 1663 * Seek the next extended partition, and find 1664 * logical drives within it. 1665 */ 1666 brelse(*bp); 1667 /* 1668 * bread() block numbers are multiples of DEV_BSIZE 1669 * but the device sector size (the unit of partitioning) 1670 * might be larger than that; pcfs_get_device_info() 1671 * has calculated the multiplicator for us. 1672 */ 1673 *bp = bread(dev, 1674 pc_dbdaddr(fsp, diskblk), fsp->pcfs_secsize); 1675 if ((*bp)->b_flags & B_ERROR) { 1676 return (EIO); 1677 } 1678 1679 lastseek = diskblk; 1680 COPY_PTBL((*bp)->b_un.b_addr, dosp); 1681 if (bpb_get_BPBSig((*bp)->b_un.b_addr) != MBB_MAGIC) { 1682 cmn_err(CE_NOTE, "!pcfs: " 1683 "extended partition table signature err, " 1684 "device (%x.%x):%d, LBA %u", 1685 getmajor(dev), getminor(dev), ldrive, 1686 (uint_t)pc_dbdaddr(fsp, diskblk)); 1687 return (EINVAL); 1688 } 1689 /* 1690 * Count up drives, and track where the next 1691 * extended partition is in case we need it. We 1692 * are expecting only one extended partition. If 1693 * there is more than one we'll only go to the 1694 * first one we see, but warn about ignoring. 1695 */ 1696 numDrives = 0; 1697 for (i = 0; i < FD_NUMPART; i++) { 1698 DTRACE_PROBE4(extendedpart, 1699 struct pcfs *, fsp, 1700 uint_t, (uint_t)dosp[i].systid, 1701 uint_t, LE_32(dosp[i].relsect), 1702 uint_t, LE_32(dosp[i].numsect)); 1703 if (isDosDrive(dosp[i].systid)) { 1704 extndDrives[numDrives++] = i; 1705 } else if (isDosExtended(dosp[i].systid)) { 1706 if (diskblk != lastseek) { 1707 /* 1708 * Already found an extended 1709 * partition in this table. 1710 */ 1711 cmn_err(CE_NOTE, 1712 "!pcfs: ignoring unexpected" 1713 " additional extended" 1714 " partition"); 1715 } else { 1716 diskblk = xstartsect + 1717 LE_32(dosp[i].relsect); 1718 } 1719 } 1720 } 1721 } while (ldrive > logicalDriveCount + numDrives); 1722 1723 ASSERT(numDrives <= FD_NUMPART); 1724 1725 if (ldrive <= logicalDriveCount + numDrives) { 1726 /* 1727 * The number of logical drives we've found thus 1728 * far is enough to get us to the one we were 1729 * searching for. 1730 */ 1731 driveIndex = logicalDriveCount + numDrives - ldrive; 1732 mediasize = 1733 LE_32(dosp[extndDrives[driveIndex]].numsect); 1734 startsec = 1735 LE_32(dosp[extndDrives[driveIndex]].relsect) + 1736 lastseek; 1737 if (startsec > (xstartsect + xnumsect)) { 1738 cmn_err(CE_NOTE, "!pcfs: extended partition " 1739 "values bad"); 1740 return (EINVAL); 1741 } 1742 goto found; 1743 } else { 1744 /* 1745 * We ran out of extended dos partition 1746 * drives. The only hope now is to go 1747 * back to extra drives defined in the master 1748 * fdisk table. But we overwrote that table 1749 * already, so we must load it in again. 1750 */ 1751 logicalDriveCount += numDrives; 1752 brelse(*bp); 1753 ASSERT(fsp->pcfs_dosstart == 0); 1754 *bp = bread(dev, pc_dbdaddr(fsp, fsp->pcfs_dosstart), 1755 fsp->pcfs_secsize); 1756 if ((*bp)->b_flags & B_ERROR) { 1757 return (EIO); 1758 } 1759 COPY_PTBL((*bp)->b_un.b_addr, dosp); 1760 } 1761 } 1762 /* 1763 * Still haven't found the drive, is it an extra 1764 * drive defined in the main FDISK table? 1765 */ 1766 if (ldrive <= logicalDriveCount + numExtraDrives) { 1767 driveIndex = logicalDriveCount + numExtraDrives - ldrive; 1768 ASSERT(driveIndex < MIN(numExtraDrives, FD_NUMPART)); 1769 mediasize = LE_32(dosp[extraDrives[driveIndex]].numsect); 1770 startsec = LE_32(dosp[extraDrives[driveIndex]].relsect); 1771 goto found; 1772 } 1773 /* 1774 * Still haven't found the drive, and there is 1775 * nowhere else to look. 1776 */ 1777 noLogicalDrive(ldrive); 1778 return (EINVAL); 1779 1780 found: 1781 /* 1782 * We need this value in units of sectorsize, because PCFS' internal 1783 * offset calculations go haywire for > 512Byte sectors unless all 1784 * pcfs_.*start values are in units of sectors. 1785 * So, assign before the capacity check (that's done in DEV_BSIZE) 1786 */ 1787 fsp->pcfs_dosstart = startsec; 1788 1789 /* 1790 * convert from device sectors to proper units: 1791 * - starting sector: DEV_BSIZE (as argument to bread()) 1792 * - media size: Bytes 1793 */ 1794 startsec = pc_dbdaddr(fsp, startsec); 1795 mediasize *= fsp->pcfs_secsize; 1796 1797 /* 1798 * some additional validation / warnings in case the partition table 1799 * and the actual media capacity are not in accordance ... 1800 */ 1801 if (fsp->pcfs_mediasize != 0) { 1802 diskaddr_t startoff = 1803 (diskaddr_t)startsec * (diskaddr_t)DEV_BSIZE; 1804 1805 if (startoff >= fsp->pcfs_mediasize || 1806 startoff + mediasize > fsp->pcfs_mediasize) { 1807 cmn_err(CE_WARN, 1808 "!pcfs: partition size (LBA start %u, %lld bytes, " 1809 "device (%x.%x):%d) smaller than " 1810 "mediasize (%lld bytes).\n" 1811 "filesystem may be truncated, access errors " 1812 "may result.\n", 1813 (uint_t)startsec, (long long)mediasize, 1814 getmajor(fsp->pcfs_xdev), getminor(fsp->pcfs_xdev), 1815 fsp->pcfs_ldrive, (long long)fsp->pcfs_mediasize); 1816 } 1817 } else { 1818 fsp->pcfs_mediasize = mediasize; 1819 } 1820 1821 return (0); 1822 } 1823 1824 1825 static fattype_t 1826 secondaryBPBChecks(struct pcfs *fsp, uchar_t *bpb, size_t secsize) 1827 { 1828 uint32_t ncl = fsp->pcfs_ncluster; 1829 1830 if (ncl <= 4096) { 1831 if (bpb_get_FatSz16(bpb) == 0) 1832 return (FAT_UNKNOWN); 1833 1834 if (bpb_get_FatSz16(bpb) * secsize < ncl * 2 && 1835 bpb_get_FatSz16(bpb) * secsize >= (3 * ncl / 2)) 1836 return (FAT12); 1837 if (bcmp(bpb_FilSysType16(bpb), "FAT12", 5) == 0) 1838 return (FAT12); 1839 if (bcmp(bpb_FilSysType16(bpb), "FAT16", 5) == 0) 1840 return (FAT16); 1841 1842 switch (bpb_get_Media(bpb)) { 1843 case SS8SPT: 1844 case DS8SPT: 1845 case SS9SPT: 1846 case DS9SPT: 1847 case DS18SPT: 1848 case DS9_15SPT: 1849 /* 1850 * Is this reliable - all floppies are FAT12 ? 1851 */ 1852 return (FAT12); 1853 case MD_FIXED: 1854 /* 1855 * Is this reliable - disks are always FAT16 ? 1856 */ 1857 return (FAT16); 1858 default: 1859 break; 1860 } 1861 } else if (ncl <= 65536) { 1862 if (bpb_get_FatSz16(bpb) == 0 && bpb_get_FatSz32(bpb) > 0) 1863 return (FAT32); 1864 if (VALID_BOOTSIG(bpb_get_BootSig32(bpb))) 1865 return (FAT32); 1866 if (VALID_FSTYPSTR32(bpb_FilSysType32(bpb))) 1867 return (FAT32); 1868 1869 if (VALID_BOOTSIG(bpb_get_BootSig16(bpb))) 1870 return (FAT16); 1871 if (bpb_get_FatSz16(bpb) * secsize < ncl * 4) 1872 return (FAT16); 1873 } 1874 1875 /* 1876 * We don't know 1877 */ 1878 return (FAT_UNKNOWN); 1879 } 1880 1881 /* 1882 * Check to see if the BPB we found is correct. 1883 * 1884 * This looks far more complicated that it needs to be for pure structural 1885 * validation. The reason for this is that parseBPB() is also used for 1886 * debugging purposes (mdb dcmd) and we therefore want a bitmap of which 1887 * BPB fields (do not) have 'known good' values, even if we (do not) reject 1888 * the BPB when attempting to mount the filesystem. 1889 * 1890 * Real-world usage of FAT shows there are a lot of corner-case situations 1891 * and, following the specification strictly, invalid filesystems out there. 1892 * Known are situations such as: 1893 * - FAT12/FAT16 filesystems with garbage in either totsec16/32 1894 * instead of the zero in one of the fields mandated by the spec 1895 * - filesystems that claim to be larger than the partition they're in 1896 * - filesystems without valid media descriptor 1897 * - FAT32 filesystems with RootEntCnt != 0 1898 * - FAT32 filesystems with less than 65526 clusters 1899 * - FAT32 filesystems without valid FSI sector 1900 * - FAT32 filesystems with FAT size in fatsec16 instead of fatsec32 1901 * 1902 * Such filesystems are accessible by PCFS - if it'd know to start with that 1903 * the filesystem should be treated as a specific FAT type. Before S10, it 1904 * relied on the PC/fdisk partition type for the purpose and almost completely 1905 * ignored the BPB; now it ignores the partition type for anything else but 1906 * logical drive enumeration, which can result in rejection of (invalid) 1907 * FAT32 - if the partition ID says FAT32, but the filesystem, for example 1908 * has less than 65526 clusters. 1909 * 1910 * Without a "force this fs as FAT{12,16,32}" tunable or mount option, it's 1911 * not possible to allow all such mostly-compliant filesystems in unless one 1912 * accepts false positives (definitely invalid filesystems that cause problems 1913 * later). This at least allows to pinpoint why the mount failed. 1914 * 1915 * Due to the use of FAT on removeable media, all relaxations of the rules 1916 * here need to be carefully evaluated wrt. to potential effects on PCFS 1917 * resilience. A faulty/"mis-crafted" filesystem must not cause a panic, so 1918 * beware. 1919 */ 1920 static int 1921 parseBPB(struct pcfs *fsp, uchar_t *bpb, int *valid) 1922 { 1923 fattype_t type; 1924 1925 uint32_t ncl; /* number of clusters in file area */ 1926 uint32_t rec; 1927 uint32_t reserved; 1928 uint32_t fsisec, bkbootsec; 1929 blkcnt_t totsec, totsec16, totsec32, datasec; 1930 size_t fatsec, fatsec16, fatsec32, rdirsec; 1931 size_t secsize; 1932 len_t mediasize; 1933 uint64_t validflags = 0; 1934 1935 if (VALID_BPBSIG(bpb_get_BPBSig(bpb))) 1936 validflags |= BPB_BPBSIG_OK; 1937 1938 rec = bpb_get_RootEntCnt(bpb); 1939 reserved = bpb_get_RsvdSecCnt(bpb); 1940 fsisec = bpb_get_FSInfo32(bpb); 1941 bkbootsec = bpb_get_BkBootSec32(bpb); 1942 totsec16 = (blkcnt_t)bpb_get_TotSec16(bpb); 1943 totsec32 = (blkcnt_t)bpb_get_TotSec32(bpb); 1944 fatsec16 = bpb_get_FatSz16(bpb); 1945 fatsec32 = bpb_get_FatSz32(bpb); 1946 1947 totsec = totsec16 ? totsec16 : totsec32; 1948 fatsec = fatsec16 ? fatsec16 : fatsec32; 1949 1950 secsize = bpb_get_BytesPerSec(bpb); 1951 if (!VALID_SECSIZE(secsize)) 1952 secsize = fsp->pcfs_secsize; 1953 if (secsize != fsp->pcfs_secsize) { 1954 PC_DPRINTF3(3, "!pcfs: parseBPB, device (%x.%x):%d:\n", 1955 getmajor(fsp->pcfs_xdev), 1956 getminor(fsp->pcfs_xdev), fsp->pcfs_ldrive); 1957 PC_DPRINTF2(3, "!BPB secsize %d != " 1958 "autodetected media block size %d\n", 1959 (int)secsize, (int)fsp->pcfs_secsize); 1960 if (fsp->pcfs_ldrive) { 1961 /* 1962 * We've already attempted to parse the partition 1963 * table. If the block size used for that don't match 1964 * the PCFS sector size, we're hosed one way or the 1965 * other. Just try what happens. 1966 */ 1967 secsize = fsp->pcfs_secsize; 1968 PC_DPRINTF1(3, 1969 "!pcfs: Using autodetected secsize %d\n", 1970 (int)secsize); 1971 } else { 1972 /* 1973 * This allows mounting lofi images of PCFS partitions 1974 * with sectorsize != DEV_BSIZE. We can't parse the 1975 * partition table on whole-disk images unless the 1976 * (undocumented) "secsize=..." mount option is used, 1977 * but at least this allows us to mount if we have 1978 * an image of a partition. 1979 */ 1980 PC_DPRINTF1(3, 1981 "!pcfs: Using BPB secsize %d\n", (int)secsize); 1982 } 1983 } 1984 1985 if (fsp->pcfs_mediasize == 0) { 1986 mediasize = (len_t)totsec * (len_t)secsize; 1987 /* 1988 * This is not an error because not all devices support the 1989 * dkio(7i) mediasize queries, and/or not all devices are 1990 * partitioned. If we have not been able to figure out the 1991 * size of the underlaying medium, we have to trust the BPB. 1992 */ 1993 PC_DPRINTF4(3, "!pcfs: parseBPB: mediasize autodetect failed " 1994 "on device (%x.%x):%d, trusting BPB totsec (%lld Bytes)\n", 1995 getmajor(fsp->pcfs_xdev), getminor(fsp->pcfs_xdev), 1996 fsp->pcfs_ldrive, (long long)fsp->pcfs_mediasize); 1997 } else if ((len_t)totsec * (len_t)secsize > fsp->pcfs_mediasize) { 1998 cmn_err(CE_WARN, 1999 "!pcfs: autodetected mediasize (%lld Bytes) smaller than " 2000 "FAT BPB mediasize (%lld Bytes).\n" 2001 "truncated filesystem on device (%x.%x):%d, access errors " 2002 "possible.\n", 2003 (long long)fsp->pcfs_mediasize, 2004 (long long)(totsec * (blkcnt_t)secsize), 2005 getmajor(fsp->pcfs_xdev), getminor(fsp->pcfs_xdev), 2006 fsp->pcfs_ldrive); 2007 mediasize = fsp->pcfs_mediasize; 2008 } else { 2009 /* 2010 * This is actually ok. A FAT needs not occupy the maximum 2011 * space available in its partition, it can be shorter. 2012 */ 2013 mediasize = (len_t)totsec * (len_t)secsize; 2014 } 2015 2016 /* 2017 * Since we let just about anything pass through this function, 2018 * fence against divide-by-zero here. 2019 */ 2020 if (secsize) 2021 rdirsec = roundup(rec * 32, secsize) / secsize; 2022 else 2023 rdirsec = 0; 2024 2025 /* 2026 * This assignment is necessary before pc_dbdaddr() can first be 2027 * used. Must initialize the value here. 2028 */ 2029 fsp->pcfs_secsize = secsize; 2030 fsp->pcfs_sdshift = ddi_ffs(secsize / DEV_BSIZE) - 1; 2031 2032 fsp->pcfs_mediasize = mediasize; 2033 2034 fsp->pcfs_spcl = bpb_get_SecPerClus(bpb); 2035 fsp->pcfs_numfat = bpb_get_NumFATs(bpb); 2036 fsp->pcfs_mediadesc = bpb_get_Media(bpb); 2037 fsp->pcfs_clsize = secsize * fsp->pcfs_spcl; 2038 fsp->pcfs_rdirsec = rdirsec; 2039 2040 /* 2041 * Remember: All PCFS offset calculations in sectors. Before I/O 2042 * is done, convert to DEV_BSIZE units via pc_dbdaddr(). This is 2043 * necessary so that media with > 512Byte sector sizes work correctly. 2044 */ 2045 fsp->pcfs_fatstart = fsp->pcfs_dosstart + reserved; 2046 fsp->pcfs_rdirstart = fsp->pcfs_fatstart + fsp->pcfs_numfat * fatsec; 2047 fsp->pcfs_datastart = fsp->pcfs_rdirstart + rdirsec; 2048 datasec = totsec - 2049 (blkcnt_t)fatsec * fsp->pcfs_numfat - 2050 (blkcnt_t)rdirsec - 2051 (blkcnt_t)reserved; 2052 2053 DTRACE_PROBE4(fatgeometry, 2054 blkcnt_t, totsec, size_t, fatsec, 2055 size_t, rdirsec, blkcnt_t, datasec); 2056 2057 /* 2058 * 'totsec' is taken directly from the BPB and guaranteed to fit 2059 * into a 32bit unsigned integer. The calculation of 'datasec', 2060 * on the other hand, could underflow for incorrect values in 2061 * rdirsec/reserved/fatsec. Check for that. 2062 * We also check that the BPB conforms to the FAT specification's 2063 * requirement that either of the 16/32bit total sector counts 2064 * must be zero. 2065 */ 2066 if (totsec != 0 && 2067 (totsec16 == totsec32 || totsec16 == 0 || totsec32 == 0) && 2068 datasec < totsec && datasec <= UINT32_MAX) 2069 validflags |= BPB_TOTSEC_OK; 2070 2071 if ((len_t)totsec * (len_t)secsize <= mediasize) 2072 validflags |= BPB_MEDIASZ_OK; 2073 2074 if (VALID_SECSIZE(secsize)) 2075 validflags |= BPB_SECSIZE_OK; 2076 if (VALID_SPCL(fsp->pcfs_spcl)) 2077 validflags |= BPB_SECPERCLUS_OK; 2078 if (VALID_CLSIZE(fsp->pcfs_clsize)) 2079 validflags |= BPB_CLSIZE_OK; 2080 if (VALID_NUMFATS(fsp->pcfs_numfat)) 2081 validflags |= BPB_NUMFAT_OK; 2082 if (VALID_RSVDSEC(reserved) && reserved < totsec) 2083 validflags |= BPB_RSVDSECCNT_OK; 2084 if (VALID_MEDIA(fsp->pcfs_mediadesc)) 2085 validflags |= BPB_MEDIADESC_OK; 2086 if (VALID_BOOTSIG(bpb_get_BootSig16(bpb))) 2087 validflags |= BPB_BOOTSIG16_OK; 2088 if (VALID_BOOTSIG(bpb_get_BootSig32(bpb))) 2089 validflags |= BPB_BOOTSIG32_OK; 2090 if (VALID_FSTYPSTR16(bpb_FilSysType16(bpb))) 2091 validflags |= BPB_FSTYPSTR16_OK; 2092 if (VALID_FSTYPSTR32(bpb_FilSysType32(bpb))) 2093 validflags |= BPB_FSTYPSTR32_OK; 2094 if (VALID_OEMNAME(bpb_OEMName(bpb))) 2095 validflags |= BPB_OEMNAME_OK; 2096 if (bkbootsec > 0 && bkbootsec <= reserved && fsisec != bkbootsec) 2097 validflags |= BPB_BKBOOTSEC_OK; 2098 if (fsisec > 0 && fsisec <= reserved) 2099 validflags |= BPB_FSISEC_OK; 2100 if (VALID_JMPBOOT(bpb_jmpBoot(bpb))) 2101 validflags |= BPB_JMPBOOT_OK; 2102 if (VALID_FSVER32(bpb_get_FSVer32(bpb))) 2103 validflags |= BPB_FSVER_OK; 2104 if (VALID_VOLLAB(bpb_VolLab16(bpb))) 2105 validflags |= BPB_VOLLAB16_OK; 2106 if (VALID_VOLLAB(bpb_VolLab32(bpb))) 2107 validflags |= BPB_VOLLAB32_OK; 2108 if (VALID_EXTFLAGS(bpb_get_ExtFlags32(bpb))) 2109 validflags |= BPB_EXTFLAGS_OK; 2110 2111 /* 2112 * Try to determine which FAT format to use. 2113 * 2114 * Calculate the number of clusters in order to determine 2115 * the type of FAT we are looking at. This is the only 2116 * recommended way of determining FAT type, though there 2117 * are other hints in the data, this is the best way. 2118 * 2119 * Since we let just about "anything" pass through this function 2120 * without early exits, fence against divide-by-zero here. 2121 * 2122 * datasec was already validated against UINT32_MAX so we know 2123 * the result will not overflow the 32bit calculation. 2124 */ 2125 if (fsp->pcfs_spcl) 2126 ncl = (uint32_t)datasec / fsp->pcfs_spcl; 2127 else 2128 ncl = 0; 2129 2130 fsp->pcfs_ncluster = ncl; 2131 2132 /* 2133 * From the Microsoft FAT specification: 2134 * In the following example, when it says <, it does not mean <=. 2135 * Note also that the numbers are correct. The first number for 2136 * FAT12 is 4085; the second number for FAT16 is 65525. These numbers 2137 * and the '<' signs are not wrong. 2138 * 2139 * We "specialdetect" the corner cases, and use at least one "extra" 2140 * criterion to decide whether it's FAT16 or FAT32 if the cluster 2141 * count is dangerously close to the boundaries. 2142 */ 2143 2144 if (ncl <= PCF_FIRSTCLUSTER) { 2145 type = FAT_UNKNOWN; 2146 } else if (ncl < 4085) { 2147 type = FAT12; 2148 } else if (ncl <= 4096) { 2149 type = FAT_QUESTIONABLE; 2150 } else if (ncl < 65525) { 2151 type = FAT16; 2152 } else if (ncl <= 65536) { 2153 type = FAT_QUESTIONABLE; 2154 } else if (ncl < PCF_LASTCLUSTER32) { 2155 type = FAT32; 2156 } else { 2157 type = FAT_UNKNOWN; 2158 } 2159 2160 DTRACE_PROBE4(parseBPB__initial, 2161 struct pcfs *, fsp, unsigned char *, bpb, 2162 int, validflags, fattype_t, type); 2163 2164 recheck: 2165 fsp->pcfs_fatsec = fatsec; 2166 2167 /* Do some final sanity checks for each specific type of FAT */ 2168 switch (type) { 2169 case FAT12: 2170 if (rec != 0) 2171 validflags |= BPB_ROOTENTCNT_OK; 2172 if ((blkcnt_t)bpb_get_TotSec16(bpb) == totsec || 2173 bpb_get_TotSec16(bpb) == 0) 2174 validflags |= BPB_TOTSEC16_OK; 2175 if ((blkcnt_t)bpb_get_TotSec32(bpb) == totsec || 2176 bpb_get_TotSec32(bpb) == 0) 2177 validflags |= BPB_TOTSEC32_OK; 2178 if (bpb_get_FatSz16(bpb) == fatsec) 2179 validflags |= BPB_FATSZ16_OK; 2180 if (fatsec * secsize >= ncl * 3 / 2) 2181 validflags |= BPB_FATSZ_OK; 2182 if (ncl < 4085) 2183 validflags |= BPB_NCLUSTERS_OK; 2184 2185 fsp->pcfs_lastclmark = (PCF_LASTCLUSTER & 0xfff); 2186 fsp->pcfs_rootblksize = 2187 fsp->pcfs_rdirsec * secsize; 2188 fsp->pcfs_fsistart = 0; 2189 2190 if ((validflags & FAT12_VALIDMSK) != FAT12_VALIDMSK) 2191 type = FAT_UNKNOWN; 2192 break; 2193 case FAT16: 2194 if (rec != 0) 2195 validflags |= BPB_ROOTENTCNT_OK; 2196 if ((blkcnt_t)bpb_get_TotSec16(bpb) == totsec || 2197 bpb_get_TotSec16(bpb) == 0) 2198 validflags |= BPB_TOTSEC16_OK; 2199 if ((blkcnt_t)bpb_get_TotSec32(bpb) == totsec || 2200 bpb_get_TotSec32(bpb) == 0) 2201 validflags |= BPB_TOTSEC32_OK; 2202 if (bpb_get_FatSz16(bpb) == fatsec) 2203 validflags |= BPB_FATSZ16_OK; 2204 if (fatsec * secsize >= ncl * 2) 2205 validflags |= BPB_FATSZ_OK; 2206 if (ncl >= 4085 && ncl < 65525) 2207 validflags |= BPB_NCLUSTERS_OK; 2208 2209 fsp->pcfs_lastclmark = PCF_LASTCLUSTER; 2210 fsp->pcfs_rootblksize = 2211 fsp->pcfs_rdirsec * secsize; 2212 fsp->pcfs_fsistart = 0; 2213 2214 if ((validflags & FAT16_VALIDMSK) != FAT16_VALIDMSK) 2215 type = FAT_UNKNOWN; 2216 break; 2217 case FAT32: 2218 if (rec == 0) 2219 validflags |= BPB_ROOTENTCNT_OK; 2220 if (bpb_get_TotSec16(bpb) == 0) 2221 validflags |= BPB_TOTSEC16_OK; 2222 if ((blkcnt_t)bpb_get_TotSec32(bpb) == totsec) 2223 validflags |= BPB_TOTSEC32_OK; 2224 if (bpb_get_FatSz16(bpb) == 0) 2225 validflags |= BPB_FATSZ16_OK; 2226 if (bpb_get_FatSz32(bpb) == fatsec) 2227 validflags |= BPB_FATSZ32_OK; 2228 if (fatsec * secsize >= ncl * 4) 2229 validflags |= BPB_FATSZ_OK; 2230 if (ncl >= 65525 && ncl < PCF_LASTCLUSTER32) 2231 validflags |= BPB_NCLUSTERS_OK; 2232 2233 fsp->pcfs_lastclmark = PCF_LASTCLUSTER32; 2234 fsp->pcfs_rootblksize = fsp->pcfs_clsize; 2235 fsp->pcfs_fsistart = fsp->pcfs_dosstart + fsisec; 2236 if (validflags & BPB_FSISEC_OK) 2237 fsp->pcfs_flags |= PCFS_FSINFO_OK; 2238 fsp->pcfs_rootclnum = bpb_get_RootClus32(bpb); 2239 if (pc_validcl(fsp, fsp->pcfs_rootclnum)) 2240 validflags |= BPB_ROOTCLUSTER_OK; 2241 2242 /* 2243 * Current PCFS code only works if 'pcfs_rdirstart' 2244 * contains the root cluster number on FAT32. 2245 * That's a mis-use and would better be changed. 2246 */ 2247 fsp->pcfs_rdirstart = (daddr_t)fsp->pcfs_rootclnum; 2248 2249 if ((validflags & FAT32_VALIDMSK) != FAT32_VALIDMSK) 2250 type = FAT_UNKNOWN; 2251 break; 2252 case FAT_QUESTIONABLE: 2253 type = secondaryBPBChecks(fsp, bpb, secsize); 2254 goto recheck; 2255 default: 2256 ASSERT(type == FAT_UNKNOWN); 2257 break; 2258 } 2259 2260 ASSERT(type != FAT_QUESTIONABLE); 2261 2262 fsp->pcfs_fattype = type; 2263 2264 if (valid) 2265 *valid = validflags; 2266 2267 DTRACE_PROBE4(parseBPB__final, 2268 struct pcfs *, fsp, unsigned char *, bpb, 2269 int, validflags, fattype_t, type); 2270 2271 if (type != FAT_UNKNOWN) { 2272 ASSERT((secsize & (DEV_BSIZE - 1)) == 0); 2273 ASSERT(ISP2(secsize / DEV_BSIZE)); 2274 return (1); 2275 } 2276 2277 return (0); 2278 } 2279 2280 2281 /* 2282 * Detect the device's native block size (sector size). 2283 * 2284 * Test whether the device is: 2285 * - a floppy device from a known controller type via DKIOCINFO 2286 * - a real floppy using the fd(7d) driver and capable of fdio(7I) ioctls 2287 * - a PCMCIA sram memory card (pseudofloppy) using pcram(7d) 2288 * - a USB floppy drive (identified by drive geometry) 2289 * 2290 * Detecting a floppy will make PCFS metadata updates on such media synchronous, 2291 * to minimize risks due to slow I/O and user hotplugging / device ejection. 2292 * 2293 * This might be a bit wasteful on kernel stack space; if anyone's 2294 * bothered by this, kmem_alloc/kmem_free the ioctl arguments... 2295 */ 2296 static void 2297 pcfs_device_getinfo(struct pcfs *fsp) 2298 { 2299 dev_t rdev = fsp->pcfs_xdev; 2300 int error; 2301 union { 2302 struct dk_minfo mi; 2303 struct dk_cinfo ci; 2304 struct dk_geom gi; 2305 struct fd_char fc; 2306 } arg; /* save stackspace ... */ 2307 intptr_t argp = (intptr_t)&arg; 2308 ldi_handle_t lh; 2309 ldi_ident_t li; 2310 int isfloppy, isremoveable, ishotpluggable; 2311 cred_t *cr = CRED(); 2312 2313 if (ldi_ident_from_dev(rdev, &li)) 2314 goto out; 2315 2316 error = ldi_open_by_dev(&rdev, OTYP_CHR, FREAD, cr, &lh, li); 2317 ldi_ident_release(li); 2318 if (error) 2319 goto out; 2320 2321 /* 2322 * Not sure if this could possibly happen. It'd be a bit like 2323 * VOP_OPEN() changing the passed-in vnode ptr. We're just not 2324 * expecting it, needs some thought if triggered ... 2325 */ 2326 ASSERT(fsp->pcfs_xdev == rdev); 2327 2328 /* 2329 * Check for removeable/hotpluggable media. 2330 */ 2331 if (ldi_ioctl(lh, DKIOCREMOVABLE, 2332 (intptr_t)&isremoveable, FKIOCTL, cr, NULL)) { 2333 isremoveable = 0; 2334 } 2335 if (ldi_ioctl(lh, DKIOCHOTPLUGGABLE, 2336 (intptr_t)&ishotpluggable, FKIOCTL, cr, NULL)) { 2337 ishotpluggable = 0; 2338 } 2339 2340 /* 2341 * Make sure we don't use "half-initialized" values if the ioctls fail. 2342 */ 2343 if (ldi_ioctl(lh, DKIOCGMEDIAINFO, argp, FKIOCTL, cr, NULL)) { 2344 bzero(&arg, sizeof (arg)); 2345 fsp->pcfs_mediasize = 0; 2346 } else { 2347 fsp->pcfs_mediasize = 2348 (len_t)arg.mi.dki_lbsize * 2349 (len_t)arg.mi.dki_capacity; 2350 } 2351 2352 if (VALID_SECSIZE(arg.mi.dki_lbsize)) { 2353 if (fsp->pcfs_secsize == 0) { 2354 fsp->pcfs_secsize = arg.mi.dki_lbsize; 2355 fsp->pcfs_sdshift = 2356 ddi_ffs(arg.mi.dki_lbsize / DEV_BSIZE) - 1; 2357 } else { 2358 PC_DPRINTF4(1, "!pcfs: autodetected media block size " 2359 "%d, device (%x.%x), different from user-provided " 2360 "%d. User override - ignoring autodetect result.\n", 2361 arg.mi.dki_lbsize, 2362 getmajor(fsp->pcfs_xdev), getminor(fsp->pcfs_xdev), 2363 fsp->pcfs_secsize); 2364 } 2365 } else if (arg.mi.dki_lbsize) { 2366 PC_DPRINTF3(1, "!pcfs: autodetected media block size " 2367 "%d, device (%x.%x), invalid (not 512, 1024, 2048, 4096). " 2368 "Ignoring autodetect result.\n", 2369 arg.mi.dki_lbsize, 2370 getmajor(fsp->pcfs_xdev), getminor(fsp->pcfs_xdev)); 2371 } 2372 2373 /* 2374 * We treat the following media types as a floppy by default. 2375 */ 2376 isfloppy = 2377 (arg.mi.dki_media_type == DK_FLOPPY || 2378 arg.mi.dki_media_type == DK_ZIP || 2379 arg.mi.dki_media_type == DK_JAZ); 2380 2381 /* 2382 * if this device understands fdio(7I) requests it's 2383 * obviously a floppy drive. 2384 */ 2385 if (!isfloppy && 2386 !ldi_ioctl(lh, FDIOGCHAR, argp, FKIOCTL, cr, NULL)) 2387 isfloppy = 1; 2388 2389 /* 2390 * some devices (PCMCIA pseudofloppies) we like to treat 2391 * as floppies, but they don't understand fdio(7I) requests. 2392 */ 2393 if (!isfloppy && 2394 !ldi_ioctl(lh, DKIOCINFO, argp, FKIOCTL, cr, NULL) && 2395 (arg.ci.dki_ctype == DKC_WDC2880 || 2396 arg.ci.dki_ctype == DKC_NCRFLOPPY || 2397 arg.ci.dki_ctype == DKC_SMSFLOPPY || 2398 arg.ci.dki_ctype == DKC_INTEL82077 || 2399 (arg.ci.dki_ctype == DKC_PCMCIA_MEM && 2400 arg.ci.dki_flags & DKI_PCMCIA_PFD))) 2401 isfloppy = 1; 2402 2403 /* 2404 * This is the "final fallback" test - media with 2405 * 2 heads and 80 cylinders are assumed to be floppies. 2406 * This is normally true for USB floppy drives ... 2407 */ 2408 if (!isfloppy && 2409 !ldi_ioctl(lh, DKIOCGGEOM, argp, FKIOCTL, cr, NULL) && 2410 (arg.gi.dkg_ncyl == 80 && arg.gi.dkg_nhead == 2)) 2411 isfloppy = 1; 2412 2413 /* 2414 * This is similar to the "old" PCFS code that sets this flag 2415 * just based on the media descriptor being 0xf8 (MD_FIXED). 2416 * Should be re-worked. We really need some specialcasing for 2417 * removeable media. 2418 */ 2419 if (!isfloppy) { 2420 fsp->pcfs_flags |= PCFS_NOCHK; 2421 } 2422 2423 /* 2424 * We automatically disable access time updates if the medium is 2425 * removeable and/or hotpluggable, and the admin did not explicitly 2426 * request access time updates (via the "atime" mount option). 2427 * The majority of flash-based media should fit this category. 2428 * Minimizing write access extends the lifetime of your memory stick ! 2429 */ 2430 if (!vfs_optionisset(fsp->pcfs_vfs, MNTOPT_ATIME, NULL) && 2431 (isremoveable || ishotpluggable | isfloppy)) { 2432 fsp->pcfs_flags |= PCFS_NOATIME; 2433 } 2434 2435 (void) ldi_close(lh, FREAD, cr); 2436 out: 2437 if (fsp->pcfs_secsize == 0) { 2438 PC_DPRINTF3(1, "!pcfs: media block size autodetection " 2439 "device (%x.%x) failed, no user-provided fallback. " 2440 "Using %d bytes.\n", 2441 getmajor(fsp->pcfs_xdev), getminor(fsp->pcfs_xdev), 2442 DEV_BSIZE); 2443 fsp->pcfs_secsize = DEV_BSIZE; 2444 fsp->pcfs_sdshift = 0; 2445 } 2446 ASSERT(fsp->pcfs_secsize % DEV_BSIZE == 0); 2447 ASSERT(VALID_SECSIZE(fsp->pcfs_secsize)); 2448 } 2449 2450 /* 2451 * Get the FAT type for the DOS medium. 2452 * 2453 * ------------------------- 2454 * According to Microsoft: 2455 * The FAT type one of FAT12, FAT16, or FAT32 is determined by the 2456 * count of clusters on the volume and nothing else. 2457 * ------------------------- 2458 * 2459 */ 2460 static int 2461 pc_getfattype(struct pcfs *fsp) 2462 { 2463 int error = 0; 2464 buf_t *bp = NULL; 2465 struct vnode *devvp = fsp->pcfs_devvp; 2466 dev_t dev = devvp->v_rdev; 2467 2468 /* 2469 * Detect the native block size of the medium, and attempt to 2470 * detect whether the medium is removeable. 2471 * We do treat removeable media (floppies, PCMCIA memory cards, 2472 * USB and FireWire disks) differently wrt. to the frequency 2473 * and synchronicity of FAT updates. 2474 * We need to know the media block size in order to be able to 2475 * parse the partition table. 2476 */ 2477 pcfs_device_getinfo(fsp); 2478 2479 /* 2480 * Unpartitioned media (floppies and some removeable devices) 2481 * don't have a partition table, the FAT BPB is at disk block 0. 2482 * Start out by reading block 0. 2483 */ 2484 fsp->pcfs_dosstart = 0; 2485 bp = bread(dev, pc_dbdaddr(fsp, fsp->pcfs_dosstart), fsp->pcfs_secsize); 2486 2487 if (error = geterror(bp)) 2488 goto out; 2489 2490 /* 2491 * If a logical drive number is requested, parse the partition table 2492 * and attempt to locate it. Otherwise, proceed immediately to the 2493 * BPB check. findTheDrive(), if successful, returns the disk block 2494 * number where the requested partition starts in "startsec". 2495 */ 2496 if (fsp->pcfs_ldrive != 0) { 2497 PC_DPRINTF3(5, "!pcfs: pc_getfattype: using FDISK table on " 2498 "device (%x,%x):%d to find BPB\n", 2499 getmajor(dev), getminor(dev), fsp->pcfs_ldrive); 2500 2501 if (error = findTheDrive(fsp, &bp)) 2502 goto out; 2503 2504 ASSERT(fsp->pcfs_dosstart != 0); 2505 2506 brelse(bp); 2507 bp = bread(dev, pc_dbdaddr(fsp, fsp->pcfs_dosstart), 2508 fsp->pcfs_secsize); 2509 if (error = geterror(bp)) 2510 goto out; 2511 } 2512 2513 /* 2514 * Validate the BPB and fill in the instance structure. 2515 */ 2516 if (!parseBPB(fsp, (uchar_t *)bp->b_un.b_addr, NULL)) { 2517 PC_DPRINTF4(1, "!pcfs: pc_getfattype: No FAT BPB on " 2518 "device (%x.%x):%d, disk LBA %u\n", 2519 getmajor(dev), getminor(dev), fsp->pcfs_ldrive, 2520 (uint_t)pc_dbdaddr(fsp, fsp->pcfs_dosstart)); 2521 error = EINVAL; 2522 goto out; 2523 } 2524 2525 ASSERT(fsp->pcfs_fattype != FAT_UNKNOWN); 2526 2527 out: 2528 /* 2529 * Release the buffer used 2530 */ 2531 if (bp != NULL) 2532 brelse(bp); 2533 return (error); 2534 } 2535 2536 2537 /* 2538 * Get the file allocation table. 2539 * If there is an old FAT, invalidate it. 2540 */ 2541 int 2542 pc_getfat(struct pcfs *fsp) 2543 { 2544 struct buf *bp = NULL; 2545 uchar_t *fatp = NULL; 2546 uchar_t *fat_changemap = NULL; 2547 int error; 2548 int fat_changemapsize; 2549 int flags = 0; 2550 int nfat; 2551 int altfat_mustmatch = 0; 2552 int fatsize = fsp->pcfs_fatsec * fsp->pcfs_secsize; 2553 2554 if (fsp->pcfs_fatp) { 2555 /* 2556 * There is a FAT in core. 2557 * If there are open file pcnodes or we have modified it or 2558 * it hasn't timed out yet use the in core FAT. 2559 * Otherwise invalidate it and get a new one 2560 */ 2561 #ifdef notdef 2562 if (fsp->pcfs_frefs || 2563 (fsp->pcfs_flags & PCFS_FATMOD) || 2564 (gethrestime_sec() < fsp->pcfs_fattime)) { 2565 return (0); 2566 } else { 2567 mutex_enter(&pcfslock); 2568 pc_invalfat(fsp); 2569 mutex_exit(&pcfslock); 2570 } 2571 #endif /* notdef */ 2572 return (0); 2573 } 2574 2575 /* 2576 * Get FAT and check it for validity 2577 */ 2578 fatp = kmem_alloc(fatsize, KM_SLEEP); 2579 error = pc_readfat(fsp, fatp); 2580 if (error) { 2581 flags = B_ERROR; 2582 goto out; 2583 } 2584 fat_changemapsize = (fatsize / fsp->pcfs_clsize) + 1; 2585 fat_changemap = kmem_zalloc(fat_changemapsize, KM_SLEEP); 2586 fsp->pcfs_fatp = fatp; 2587 fsp->pcfs_fat_changemapsize = fat_changemapsize; 2588 fsp->pcfs_fat_changemap = fat_changemap; 2589 2590 /* 2591 * The only definite signature check is that the 2592 * media descriptor byte should match the first byte 2593 * of the FAT block. 2594 */ 2595 if (fatp[0] != fsp->pcfs_mediadesc) { 2596 cmn_err(CE_NOTE, "!pcfs: FAT signature mismatch, " 2597 "media descriptor %x, FAT[0] lowbyte %x\n", 2598 (uint32_t)fsp->pcfs_mediadesc, (uint32_t)fatp[0]); 2599 cmn_err(CE_NOTE, "!pcfs: Enforcing alternate FAT validation\n"); 2600 altfat_mustmatch = 1; 2601 } 2602 2603 /* 2604 * Get alternate FATs and check for consistency 2605 * This is an inlined version of pc_readfat(). 2606 * Since we're only comparing FAT and alternate FAT, 2607 * there's no reason to let pc_readfat() copy data out 2608 * of the buf. Instead, compare in-situ, one cluster 2609 * at a time. 2610 */ 2611 for (nfat = 1; nfat < fsp->pcfs_numfat; nfat++) { 2612 size_t startsec; 2613 size_t off; 2614 2615 startsec = pc_dbdaddr(fsp, 2616 fsp->pcfs_fatstart + nfat * fsp->pcfs_fatsec); 2617 2618 for (off = 0; off < fatsize; off += fsp->pcfs_clsize) { 2619 daddr_t fatblk = startsec + pc_dbdaddr(fsp, 2620 pc_cltodb(fsp, pc_lblkno(fsp, off))); 2621 2622 bp = bread(fsp->pcfs_xdev, fatblk, 2623 MIN(fsp->pcfs_clsize, fatsize - off)); 2624 if (bp->b_flags & (B_ERROR | B_STALE)) { 2625 cmn_err(CE_NOTE, 2626 "!pcfs: alternate FAT #%d (start LBA %p)" 2627 " read error at offset %ld on device" 2628 " (%x.%x):%d", 2629 nfat, (void *)(uintptr_t)startsec, off, 2630 getmajor(fsp->pcfs_xdev), 2631 getminor(fsp->pcfs_xdev), 2632 fsp->pcfs_ldrive); 2633 flags = B_ERROR; 2634 error = EIO; 2635 goto out; 2636 } 2637 bp->b_flags |= B_STALE | B_AGE; 2638 if (bcmp(bp->b_un.b_addr, fatp + off, 2639 MIN(fsp->pcfs_clsize, fatsize - off))) { 2640 cmn_err(CE_NOTE, 2641 "!pcfs: alternate FAT #%d (start LBA %p)" 2642 " corrupted at offset %ld on device" 2643 " (%x.%x):%d", 2644 nfat, (void *)(uintptr_t)startsec, off, 2645 getmajor(fsp->pcfs_xdev), 2646 getminor(fsp->pcfs_xdev), 2647 fsp->pcfs_ldrive); 2648 if (altfat_mustmatch) { 2649 flags = B_ERROR; 2650 error = EIO; 2651 goto out; 2652 } 2653 } 2654 brelse(bp); 2655 bp = NULL; /* prevent double release */ 2656 } 2657 } 2658 2659 fsp->pcfs_fattime = gethrestime_sec() + PCFS_DISKTIMEOUT; 2660 fsp->pcfs_fatjustread = 1; 2661 2662 /* 2663 * Retrieve FAT32 fsinfo sector. 2664 * A failure to read this is not fatal to accessing the volume. 2665 * It simply means operations that count or search free blocks 2666 * will have to do a full FAT walk, vs. a possibly quicker lookup 2667 * of the summary information. 2668 * Hence, we log a message but return success overall after this point. 2669 */ 2670 if (IS_FAT32(fsp) && (fsp->pcfs_flags & PCFS_FSINFO_OK)) { 2671 struct fat_od_fsi *fsinfo_disk; 2672 2673 bp = bread(fsp->pcfs_xdev, 2674 pc_dbdaddr(fsp, fsp->pcfs_fsistart), fsp->pcfs_secsize); 2675 fsinfo_disk = (struct fat_od_fsi *)bp->b_un.b_addr; 2676 if (bp->b_flags & (B_ERROR | B_STALE) || 2677 !FSISIG_OK(fsinfo_disk)) { 2678 cmn_err(CE_NOTE, 2679 "!pcfs: error reading fat32 fsinfo from " 2680 "device (%x.%x):%d, block %lld", 2681 getmajor(fsp->pcfs_xdev), getminor(fsp->pcfs_xdev), 2682 fsp->pcfs_ldrive, 2683 (long long)pc_dbdaddr(fsp, fsp->pcfs_fsistart)); 2684 fsp->pcfs_flags &= ~PCFS_FSINFO_OK; 2685 fsp->pcfs_fsinfo.fs_free_clusters = FSINFO_UNKNOWN; 2686 fsp->pcfs_fsinfo.fs_next_free = FSINFO_UNKNOWN; 2687 } else { 2688 bp->b_flags |= B_STALE | B_AGE; 2689 fsinfo_disk = (fat_od_fsi_t *)(bp->b_un.b_addr); 2690 fsp->pcfs_fsinfo.fs_free_clusters = 2691 LE_32(fsinfo_disk->fsi_incore.fs_free_clusters); 2692 fsp->pcfs_fsinfo.fs_next_free = 2693 LE_32(fsinfo_disk->fsi_incore.fs_next_free); 2694 } 2695 brelse(bp); 2696 bp = NULL; 2697 } 2698 2699 if (pc_validcl(fsp, (pc_cluster32_t)fsp->pcfs_fsinfo.fs_next_free)) 2700 fsp->pcfs_nxfrecls = fsp->pcfs_fsinfo.fs_next_free; 2701 else 2702 fsp->pcfs_nxfrecls = PCF_FIRSTCLUSTER; 2703 2704 return (0); 2705 2706 out: 2707 cmn_err(CE_NOTE, "!pcfs: illegal disk format"); 2708 if (bp) 2709 brelse(bp); 2710 if (fatp) 2711 kmem_free(fatp, fatsize); 2712 if (fat_changemap) 2713 kmem_free(fat_changemap, fat_changemapsize); 2714 2715 if (flags) { 2716 pc_mark_irrecov(fsp); 2717 } 2718 return (error); 2719 } 2720