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