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