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/hsfs/hsfs_vfsops.c
+++ new/usr/src/uts/common/fs/hsfs/hsfs_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 "@(#)hsfs_vfsops.c 1.97 07/10/25 SMI"
26 +#pragma ident "@(#)hsfs_vfsops.c 1.98 08/05/07 SMI"
27 27
28 28 /*
29 29 * VFS operations for High Sierra filesystem
30 30 */
31 31
32 32 #include <sys/types.h>
33 33 #include <sys/isa_defs.h>
34 34 #include <sys/t_lock.h>
35 35 #include <sys/param.h>
36 36 #include <sys/systm.h>
37 37 #include <sys/sysmacros.h>
38 38 #include <sys/kmem.h>
39 39 #include <sys/signal.h>
40 40 #include <sys/user.h>
41 41 #include <sys/proc.h>
42 42 #include <sys/disp.h>
43 43 #include <sys/buf.h>
44 44 #include <sys/pathname.h>
45 45 #include <sys/vfs.h>
46 46 #include <sys/vfs_opreg.h>
47 47 #include <sys/vnode.h>
48 48 #include <sys/file.h>
49 49 #include <sys/uio.h>
50 50 #include <sys/conf.h>
51 51 #include <sys/policy.h>
52 52
53 53 #include <vm/page.h>
54 54
55 55 #include <sys/fs/snode.h>
56 56 #include <sys/fs/hsfs_spec.h>
57 57 #include <sys/fs/hsfs_isospec.h>
58 58 #include <sys/fs/hsfs_node.h>
59 59 #include <sys/fs/hsfs_impl.h>
60 60 #include <sys/fs/hsfs_susp.h>
61 61 #include <sys/fs/hsfs_rrip.h>
62 62
63 63 #include <sys/statvfs.h>
64 64 #include <sys/mount.h>
65 65 #include <sys/mntent.h>
66 66 #include <sys/swap.h>
67 67 #include <sys/errno.h>
68 68 #include <sys/debug.h>
69 69 #include "fs/fs_subr.h"
70 70 #include <sys/cmn_err.h>
71 71 #include <sys/bootconf.h>
72 72
73 73 #include <sys/sdt.h>
74 74
75 75 /*
76 76 * These are needed for the CDROMREADOFFSET Code
77 77 */
78 78 #include <sys/cdio.h>
79 79 #include <sys/sunddi.h>
80 80
81 81 #define HSFS_CLKSET
82 82
83 83 #include <sys/modctl.h>
84 84
85 85 /*
86 86 * Options for mount.
87 87 */
88 88 #define HOPT_GLOBAL MNTOPT_GLOBAL
89 89 #define HOPT_NOGLOBAL MNTOPT_NOGLOBAL
90 90 #define HOPT_MAPLCASE "maplcase"
91 91 #define HOPT_NOMAPLCASE "nomaplcase"
92 92 #define HOPT_NOTRAILDOT "notraildot"
93 93 #define HOPT_TRAILDOT "traildot"
94 94 #define HOPT_NRR "nrr"
95 95 #define HOPT_RR "rr"
96 96 #define HOPT_JOLIET "joliet"
97 97 #define HOPT_NOJOLIET "nojoliet"
98 98 #define HOPT_JOLIETLONG "jolietlong"
99 99 #define HOPT_VERS2 "vers2"
100 100 #define HOPT_NOVERS2 "novers2"
101 101 #define HOPT_RO MNTOPT_RO
102 102
103 103 static char *global_cancel[] = { HOPT_NOGLOBAL, NULL };
104 104 static char *noglobal_cancel[] = { HOPT_GLOBAL, NULL };
105 105 static char *mapl_cancel[] = { HOPT_NOMAPLCASE, NULL };
106 106 static char *nomapl_cancel[] = { HOPT_MAPLCASE, NULL };
107 107 static char *ro_cancel[] = { MNTOPT_RW, NULL };
108 108 static char *rr_cancel[] = { HOPT_NRR, NULL };
109 109 static char *nrr_cancel[] = { HOPT_RR, NULL };
110 110 static char *joliet_cancel[] = { HOPT_NOJOLIET, NULL };
111 111 static char *nojoliet_cancel[] = { HOPT_JOLIET, NULL };
112 112 static char *vers2_cancel[] = { HOPT_NOVERS2, NULL };
113 113 static char *novers2_cancel[] = { HOPT_VERS2, NULL };
114 114 static char *trail_cancel[] = { HOPT_NOTRAILDOT, NULL };
115 115 static char *notrail_cancel[] = { HOPT_TRAILDOT, NULL };
116 116
117 117 static mntopt_t hsfs_options[] = {
118 118 { HOPT_GLOBAL, global_cancel, NULL, 0, NULL },
119 119 { HOPT_NOGLOBAL, noglobal_cancel, NULL, MO_DEFAULT, NULL },
120 120 { HOPT_MAPLCASE, mapl_cancel, NULL, MO_DEFAULT, NULL },
121 121 { HOPT_NOMAPLCASE, nomapl_cancel, NULL, 0, NULL },
122 122 { HOPT_RO, ro_cancel, NULL, MO_DEFAULT, NULL },
123 123 { HOPT_RR, rr_cancel, NULL, MO_DEFAULT, NULL },
124 124 { HOPT_NRR, nrr_cancel, NULL, 0, NULL },
125 125 { HOPT_JOLIET, joliet_cancel, NULL, 0, NULL },
126 126 { HOPT_NOJOLIET, nojoliet_cancel, NULL, 0, NULL },
127 127 { HOPT_JOLIETLONG, NULL, NULL, 0, NULL },
128 128 { HOPT_VERS2, vers2_cancel, NULL, 0, NULL },
129 129 { HOPT_NOVERS2, novers2_cancel, NULL, 0, NULL },
130 130 { HOPT_TRAILDOT, trail_cancel, NULL, MO_DEFAULT, NULL },
131 131 { HOPT_NOTRAILDOT, notrail_cancel, NULL, 0, NULL },
132 132 { "sector", NULL, "0", MO_HASVALUE, NULL},
133 133 };
134 134
135 135 static mntopts_t hsfs_proto_opttbl = {
136 136 sizeof (hsfs_options) / sizeof (mntopt_t),
137 137 hsfs_options
138 138 };
139 139
140 140 /*
141 141 * Indicates whether to enable the I/O scheduling and readahead logic
142 142 * 1 - Enable, 0 - Do not Enable.
143 143 * Debugging purposes.
144 144 */
145 145 int do_schedio = 1;
146 146 static int hsfsfstype;
147 147 static int hsfsinit(int, char *);
148 148
149 149 static vfsdef_t vfw = {
150 150 VFSDEF_VERSION,
151 151 "hsfs",
152 152 hsfsinit,
153 153 VSW_HASPROTO|VSW_STATS, /* We don't suppport remounting */
154 154 &hsfs_proto_opttbl
155 155 };
156 156
157 157 static struct modlfs modlfs = {
158 158 &mod_fsops, "filesystem for HSFS", &vfw
159 159 };
160 160
161 161 static struct modlinkage modlinkage = {
162 162 MODREV_1, (void *)&modlfs, NULL
163 163 };
164 164
165 165 char _depends_on[] = "fs/specfs";
166 166
167 167 extern void hsched_init_caches(void);
168 168 extern void hsched_fini_caches(void);
169 169
170 170
171 171 int
172 172 _init(void)
173 173 {
174 174 return (mod_install(&modlinkage));
175 175 }
176 176
177 177 int
178 178 _fini(void)
179 179 {
180 180 int error;
181 181
182 182 error = mod_remove(&modlinkage);
183 183
184 184 DTRACE_PROBE1(mod_remove, int, error);
185 185
186 186 if (error)
187 187 return (error);
188 188
189 189 mutex_destroy(&hs_mounttab_lock);
190 190
191 191 /*
192 192 * Tear down the operations vectors
193 193 */
194 194 (void) vfs_freevfsops_by_type(hsfsfstype);
195 195 vn_freevnodeops(hsfs_vnodeops);
196 196
197 197 hs_fini_hsnode_cache();
198 198 hsched_fini_caches();
199 199 return (0);
200 200 }
201 201
202 202 int
203 203 _info(struct modinfo *modinfop)
204 204 {
205 205 return (mod_info(&modlinkage, modinfop));
206 206 }
207 207
208 208 #define BDEVFLAG(dev) ((devopsp[getmajor(dev)])->devo_cb_ops->cb_flag)
209 209
210 210 kmutex_t hs_mounttab_lock;
211 211 struct hsfs *hs_mounttab = NULL;
212 212
213 213 /* default mode, uid, gid */
214 214 mode_t hsfs_default_mode = 0555;
215 215 uid_t hsfs_default_uid = 0;
216 216 gid_t hsfs_default_gid = 3;
217 217
218 218 extern void hsched_init(struct hsfs *fsp, int fsid,
219 219 struct modlinkage *modlinkage);
220 220 extern void hsched_fini(struct hsfs_queue *hqueue);
221 221 extern void hsfs_init_kstats(struct hsfs *fsp, int fsid);
222 222 extern void hsfs_fini_kstats(struct hsfs *fsp);
223 223
224 224 static int hsfs_mount(struct vfs *vfsp, struct vnode *mvp,
225 225 struct mounta *uap, struct cred *cr);
226 226 static int hsfs_unmount(struct vfs *vfsp, int, struct cred *cr);
227 227 static int hsfs_root(struct vfs *vfsp, struct vnode **vpp);
228 228 static int hsfs_statvfs(struct vfs *vfsp, struct statvfs64 *sbp);
229 229 static int hsfs_vget(struct vfs *vfsp, struct vnode **vpp, struct fid *fidp);
230 230 static int hsfs_mountroot(struct vfs *, enum whymountroot);
231 231
232 232 static int hs_mountfs(struct vfs *vfsp, dev_t dev, char *path,
233 233 mode_t mode, int flags, struct cred *cr, int isroot);
234 234 static int hs_getrootvp(struct vfs *vfsp, struct hsfs *fsp, size_t pathsize);
235 235 static int hs_findhsvol(struct hsfs *fsp, struct vnode *vp,
236 236 struct hs_volume *hvp);
237 237 static int hs_parsehsvol(struct hsfs *fsp, uchar_t *volp,
238 238 struct hs_volume *hvp);
239 239 static int hs_findisovol(struct hsfs *fsp, struct vnode *vp,
240 240 struct hs_volume *hvp,
241 241 struct hs_volume *svp,
242 242 struct hs_volume *jvp);
243 243 static int hs_joliet_level(uchar_t *volp);
244 244 static int hs_parseisovol(struct hsfs *fsp, uchar_t *volp,
245 245 struct hs_volume *hvp);
246 246 static void hs_copylabel(struct hs_volume *, unsigned char *, int);
247 247 static int hs_getmdev(struct vfs *, char *fspec, int flags, dev_t *pdev,
248 248 mode_t *mode, cred_t *cr);
249 249 static int hs_findvoldesc(dev_t rdev, int desc_sec);
250 250
251 251 static int
252 252 hsfsinit(int fstype, char *name)
253 253 {
254 254 static const fs_operation_def_t hsfs_vfsops_template[] = {
255 255 VFSNAME_MOUNT, { .vfs_mount = hsfs_mount },
256 256 VFSNAME_UNMOUNT, { .vfs_unmount = hsfs_unmount },
257 257 VFSNAME_ROOT, { .vfs_root = hsfs_root },
258 258 VFSNAME_STATVFS, { .vfs_statvfs = hsfs_statvfs },
259 259 VFSNAME_VGET, { .vfs_vget = hsfs_vget },
260 260 VFSNAME_MOUNTROOT, { .vfs_mountroot = hsfs_mountroot },
261 261 NULL, NULL
262 262 };
263 263 int error;
264 264
265 265 error = vfs_setfsops(fstype, hsfs_vfsops_template, NULL);
266 266 if (error != 0) {
267 267 cmn_err(CE_WARN, "hsfsinit: bad vfs ops template");
268 268 return (error);
269 269 }
270 270
271 271 error = vn_make_ops(name, hsfs_vnodeops_template, &hsfs_vnodeops);
272 272 if (error != 0) {
273 273 (void) vfs_freevfsops_by_type(fstype);
274 274 cmn_err(CE_WARN, "hsfsinit: bad vnode ops template");
275 275 return (error);
276 276 }
277 277
278 278 hsfsfstype = fstype;
279 279 mutex_init(&hs_mounttab_lock, NULL, MUTEX_DEFAULT, NULL);
280 280 hs_init_hsnode_cache();
281 281 hsched_init_caches();
282 282 return (0);
283 283 }
284 284
285 285 /*ARGSUSED*/
286 286 static int
287 287 hsfs_mount(struct vfs *vfsp, struct vnode *mvp,
288 288 struct mounta *uap, struct cred *cr)
289 289 {
290 290 int vnode_busy;
291 291 dev_t dev;
292 292 struct pathname dpn;
293 293 int error;
294 294 mode_t mode;
295 295 int flags; /* this will hold the mount specific data */
296 296
297 297 if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
298 298 return (error);
299 299
300 300 if (mvp->v_type != VDIR)
301 301 return (ENOTDIR);
302 302
303 303 /* mount option must be read only, else mount will be rejected */
304 304 if (!(uap->flags & MS_RDONLY))
305 305 return (EROFS);
306 306
307 307 /*
308 308 * We already told the framework that we don't support remounting.
309 309 */
310 310 ASSERT(!(uap->flags & MS_REMOUNT));
311 311
312 312 mutex_enter(&mvp->v_lock);
313 313 vnode_busy = (mvp->v_count != 1) || (mvp->v_flag & VROOT);
314 314 mutex_exit(&mvp->v_lock);
315 315
316 316 if ((uap->flags & MS_OVERLAY) == 0 && vnode_busy) {
317 317 return (EBUSY);
318 318 }
319 319
320 320 /*
321 321 * Check for the options that actually affect things
322 322 * at our level.
323 323 */
324 324 flags = 0;
325 325 if (vfs_optionisset(vfsp, HOPT_NOMAPLCASE, NULL))
326 326 flags |= HSFSMNT_NOMAPLCASE;
327 327 if (vfs_optionisset(vfsp, HOPT_NOTRAILDOT, NULL))
328 328 flags |= HSFSMNT_NOTRAILDOT;
329 329 if (vfs_optionisset(vfsp, HOPT_NRR, NULL))
330 330 flags |= HSFSMNT_NORRIP;
331 331 if (vfs_optionisset(vfsp, HOPT_NOJOLIET, NULL))
332 332 flags |= HSFSMNT_NOJOLIET;
333 333 if (vfs_optionisset(vfsp, HOPT_JOLIETLONG, NULL))
334 334 flags |= HSFSMNT_JOLIETLONG;
335 335 if (vfs_optionisset(vfsp, HOPT_NOVERS2, NULL))
336 336 flags |= HSFSMNT_NOVERS2;
337 337
338 338 error = pn_get(uap->dir, (uap->flags & MS_SYSSPACE) ?
339 339 UIO_SYSSPACE : UIO_USERSPACE, &dpn);
340 340 if (error)
341 341 return (error);
342 342
343 343 error = hs_getmdev(vfsp, uap->spec, uap->flags, &dev, &mode, cr);
344 344 if (error != 0) {
345 345 pn_free(&dpn);
346 346 return (error);
347 347 }
348 348
349 349 /*
350 350 * If the device is a tape, return error
351 351 */
352 352 if ((BDEVFLAG(dev) & D_TAPE) == D_TAPE) {
353 353 pn_free(&dpn);
354 354 return (ENOTBLK);
355 355 }
356 356
357 357 /*
358 358 * Mount the filesystem.
359 359 */
360 360 error = hs_mountfs(vfsp, dev, dpn.pn_path, mode, flags, cr, 0);
361 361 pn_free(&dpn);
362 362 return (error);
363 363 }
364 364
365 365 /*ARGSUSED*/
366 366 static int
367 367 hsfs_unmount(
368 368 struct vfs *vfsp,
369 369 int flag,
370 370 struct cred *cr)
371 371 {
372 372 struct hsfs **tspp;
373 373 struct hsfs *fsp;
374 374
375 375 if (secpolicy_fs_unmount(cr, vfsp) != 0)
376 376 return (EPERM);
377 377
378 378 /*
379 379 * forced unmount is not supported by this file system
380 380 * and thus, ENOTSUP is being returned.
381 381 */
382 382 if (flag & MS_FORCE)
383 383 return (ENOTSUP);
384 384
385 385 fsp = VFS_TO_HSFS(vfsp);
386 386
387 387 if (fsp->hsfs_rootvp->v_count != 1)
388 388 return (EBUSY);
389 389
390 390 /* destroy all old pages and hsnodes for this vfs */
391 391 if (hs_synchash(vfsp))
392 392 return (EBUSY);
393 393
394 394 mutex_enter(&hs_mounttab_lock);
395 395 for (tspp = &hs_mounttab; *tspp != NULL; tspp = &(*tspp)->hsfs_next) {
396 396 if (*tspp == fsp)
397 397 break;
398 398 }
399 399 if (*tspp == NULL) {
400 400 mutex_exit(&hs_mounttab_lock);
401 401 panic("hsfs_unmount: vfs not mounted?");
402 402 /*NOTREACHED*/
403 403 }
404 404
405 405 *tspp = fsp->hsfs_next;
406 406
407 407 mutex_exit(&hs_mounttab_lock);
408 408
409 409 hsfs_fini_kstats(fsp);
410 410 (void) VOP_CLOSE(fsp->hsfs_devvp, FREAD, 1, (offset_t)0, cr, NULL);
411 411 VN_RELE(fsp->hsfs_devvp);
412 412 /* free path table space */
413 413 if (fsp->hsfs_ptbl != NULL)
414 414 kmem_free(fsp->hsfs_ptbl, (size_t)fsp->hsfs_vol.ptbl_len);
415 415 /* free path table index table */
416 416 if (fsp->hsfs_ptbl_idx != NULL)
417 417 kmem_free(fsp->hsfs_ptbl_idx, (size_t)
418 418 (fsp->hsfs_ptbl_idx_size * sizeof (struct ptable_idx)));
419 419
420 420 /* free "mounted on" pathame */
421 421 if (fsp->hsfs_fsmnt != NULL)
422 422 kmem_free(fsp->hsfs_fsmnt, strlen(fsp->hsfs_fsmnt) + 1);
423 423
424 424 hsched_fini(fsp->hqueue);
425 425 kmem_free(fsp->hqueue, sizeof (struct hsfs_queue));
426 426
427 427 mutex_destroy(&fsp->hsfs_free_lock);
428 428 rw_destroy(&fsp->hsfs_hash_lock);
429 429
430 430 kmem_free(fsp, sizeof (*fsp));
431 431 return (0);
432 432 }
433 433
434 434 /*ARGSUSED*/
435 435 static int
436 436 hsfs_root(struct vfs *vfsp, struct vnode **vpp)
437 437 {
438 438 *vpp = (VFS_TO_HSFS(vfsp))->hsfs_rootvp;
439 439 VN_HOLD(*vpp);
440 440 return (0);
441 441 }
442 442
443 443 /*ARGSUSED*/
444 444 static int
445 445 hsfs_statvfs(struct vfs *vfsp, struct statvfs64 *sbp)
446 446 {
447 447 struct hsfs *fsp;
448 448 dev32_t d32;
449 449
450 450 fsp = VFS_TO_HSFS(vfsp);
451 451 if (fsp->hsfs_magic != HSFS_MAGIC)
452 452 return (EINVAL);
453 453 bzero(sbp, sizeof (*sbp));
454 454 sbp->f_bsize = vfsp->vfs_bsize;
455 455 sbp->f_frsize = sbp->f_bsize; /* no fragment, same as block size */
456 456 sbp->f_blocks = (fsblkcnt64_t)fsp->hsfs_vol.vol_size;
457 457
458 458 sbp->f_bfree = (fsblkcnt64_t)0;
459 459 sbp->f_bavail = (fsblkcnt64_t)0;
460 460 sbp->f_files = (fsfilcnt64_t)-1;
461 461 sbp->f_ffree = (fsfilcnt64_t)0;
462 462 sbp->f_favail = (fsfilcnt64_t)0;
463 463 (void) cmpldev(&d32, vfsp->vfs_dev);
464 464 sbp->f_fsid = d32;
465 465 (void) strcpy(sbp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name);
466 466 sbp->f_flag = vf_to_stf(vfsp->vfs_flag);
467 467 sbp->f_namemax = fsp->hsfs_namemax;
468 468 (void) strcpy(sbp->f_fstr, fsp->hsfs_vol.vol_id);
469 469
470 470 return (0);
471 471 }
472 472
473 473 /*
474 474 * Previously nodeid was declared as uint32_t. This has been changed
475 475 * to conform better with the ISO9660 standard. The standard states that
476 476 * a LBN can be a 32 bit number, as the MAKE_NODEID macro shifts this
477 477 * LBN 11 places left (LBN_TO_BYTE) and then shifts the result 5 right
478 478 * (divide by 32) we are left with the potential of an overflow if
479 479 * confined to a 32 bit value.
480 480 */
481 481
482 482 static int
483 483 hsfs_vget(struct vfs *vfsp, struct vnode **vpp, struct fid *fidp)
484 484 {
485 485 struct hsfid *fid;
486 486 struct hsfs *fsp;
487 487 ino64_t nodeid;
488 488 int error;
489 489
490 490 fsp = (struct hsfs *)VFS_TO_HSFS(vfsp);
491 491 fid = (struct hsfid *)fidp;
492 492
493 493 /*
494 494 * Look for vnode on hashlist.
495 495 * If found, it's now active and the refcnt was incremented.
496 496 */
497 497
498 498 rw_enter(&fsp->hsfs_hash_lock, RW_READER);
499 499
500 500 nodeid = fid->hf_ino;
501 501
502 502 if ((*vpp = hs_findhash(nodeid, fid->hf_dir_lbn,
503 503 (uint_t)fid->hf_dir_off, vfsp)) == NULL) {
504 504 /*
505 505 * Not in cache, so we need to remake it.
506 506 * hs_remakenode() will read the directory entry
507 507 * and then check again to see if anyone else has
508 508 * put it in the cache.
509 509 */
510 510 rw_exit(&fsp->hsfs_hash_lock);
511 511 error = hs_remakenode(fid->hf_dir_lbn, (uint_t)fid->hf_dir_off,
512 512 vfsp, vpp);
513 513 return (error);
514 514 }
515 515 rw_exit(&fsp->hsfs_hash_lock);
516 516 return (0);
517 517 }
518 518
519 519
520 520 #define CHECKSUM_SIZE (64 * 1024)
521 521
522 522 /*
523 523 * Compute a CD-ROM fsid by checksumming the first 64K of data on the CD
524 524 * We use the 'fsp' argument to determine the location of the root
525 525 * directory entry, and we start reading from there.
526 526 */
527 527 static int
528 528 compute_cdrom_id(struct hsfs *fsp, vnode_t *devvp)
529 529 {
530 530 uint_t secno;
531 531 struct hs_volume *hsvp = &fsp->hsfs_vol;
532 532 struct buf *bp;
533 533 int error;
534 534 int fsid;
535 535
536 536 secno = hsvp->root_dir.ext_lbn >> hsvp->lbn_secshift;
537 537 bp = bread(devvp->v_rdev, secno * 4, CHECKSUM_SIZE);
538 538 error = geterror(bp);
539 539
540 540 /*
541 541 * An error on read or a partial read means we asked
542 542 * for a nonexistant/corrupted piece of the device
543 543 * (including past-the-end of the media). Don't
544 544 * try to use the checksumming method then.
545 545 */
546 546 if (!error && bp->b_bcount == CHECKSUM_SIZE) {
547 547 int *ibuf = (int *)bp->b_un.b_addr;
548 548 int i;
549 549
550 550 fsid = 0;
551 551
552 552 for (i = 0; i < CHECKSUM_SIZE / sizeof (int); i++)
553 553 fsid ^= ibuf[ i ];
554 554 } else {
555 555 /*
556 556 * Fallback - use creation date
557 557 */
558 558 fsid = hsvp->cre_date.tv_sec;
559 559 }
560 560
561 561 brelse(bp);
562 562
563 563 return (fsid);
564 564 }
565 565
566 566
567 567 /*ARGSUSED*/
568 568 static int
569 569 hs_mountfs(
570 570 struct vfs *vfsp,
571 571 dev_t dev,
572 572 char *path,
573 573 mode_t mode,
574 574 int mount_flags,
575 575 struct cred *cr,
576 576 int isroot)
577 577 {
578 578 struct vnode *devvp;
579 579 struct hsfs *tsp;
580 580 struct hsfs *fsp = NULL;
581 581 struct vattr vap;
582 582 struct hsnode *hp;
583 583 int error;
584 584 struct timeval tv;
585 585 int fsid;
586 586 int use_rrip;
587 587 int use_vers2;
588 588 int use_joliet;
589 589 int has_rrip = 0;
590 590 int has_vers2 = 0;
591 591 int has_joliet = 0;
592 592 int force_rrip_off;
593 593 int force_vers2_off;
594 594 int force_joliet_off;
595 595 size_t pathbufsz = strlen(path) + 1;
596 596 int redo_rootvp;
597 597
598 598 struct hs_volume *svp; /* Supplemental VD for ISO-9660:1999 */
599 599 struct hs_volume *jvp; /* Joliet VD */
600 600
601 601 /*
602 602 * The rules for which extension will be used are:
603 603 * 1. No specific mount options given:
604 604 * - use rrip if available
605 605 * - use ISO9660:1999 if available
606 606 * - use joliet if available.
607 607 * 2. rrip/ISO9660:1999/joliet explicitly disabled via mount option:
608 608 * - use next "lower" extension
609 609 * 3. joliet/ISO9660:1999/rrip explicitly requested via mount option:
610 610 * - disable rrip support even if available
611 611 * - disable IOS9660:1999 support even if available
612 612 *
613 613 * We need to adjust these flags as we discover the extensions
614 614 * present. See below. These are just the starting values.
615 615 */
616 616 use_rrip = (mount_flags & HSFSMNT_NORRIP) == 0;
617 617 use_vers2 = (mount_flags & HSFSMNT_NOVERS2) == 0;
618 618 use_joliet = (mount_flags & HSFSMNT_NOJOLIET) == 0;
619 619
620 620 /*
621 621 * Open the device
622 622 */
623 623 devvp = makespecvp(dev, VBLK);
624 624 ASSERT(devvp != 0);
625 625
626 626 /*
627 627 * Open the target device (file) for read only.
628 628 */
629 629 if (error = VOP_OPEN(&devvp, FREAD, cr, NULL)) {
630 630 VN_RELE(devvp);
631 631 return (error);
632 632 }
633 633
634 634 /*
635 635 * Refuse to go any further if this
636 636 * device is being used for swapping
637 637 */
638 638 if (IS_SWAPVP(common_specvp(devvp))) {
639 639 error = EBUSY;
640 640 goto cleanup;
641 641 }
642 642
643 643 vap.va_mask = AT_SIZE;
644 644 if ((error = VOP_GETATTR(devvp, &vap, ATTR_COMM, cr, NULL)) != 0) {
645 645 cmn_err(CE_NOTE, "Cannot get attributes of the CD-ROM driver");
646 646 goto cleanup;
647 647 }
648 648
649 649 /*
650 650 * Make sure we have a nonzero size partition.
651 651 * The current version of the SD driver will *not* fail the open
652 652 * of such a partition so we have to check for it here.
653 653 */
654 654 if (vap.va_size == 0) {
655 655 error = ENXIO;
656 656 goto cleanup;
657 657 }
658 658
659 659 /*
660 660 * Init a new hsfs structure.
661 661 */
662 662 fsp = kmem_zalloc(sizeof (*fsp), KM_SLEEP);
663 663 svp = kmem_zalloc(sizeof (*svp), KM_SLEEP);
664 664 jvp = kmem_zalloc(sizeof (*jvp), KM_SLEEP);
665 665
666 666 /* hardwire perms, uid, gid */
667 667 fsp->hsfs_vol.vol_uid = hsfs_default_uid;
668 668 fsp->hsfs_vol.vol_gid = hsfs_default_gid;
669 669 fsp->hsfs_vol.vol_prot = hsfs_default_mode;
670 670 svp->vol_uid = hsfs_default_uid;
671 671 svp->vol_gid = hsfs_default_gid;
672 672 svp->vol_prot = hsfs_default_mode;
673 673 jvp->vol_uid = hsfs_default_uid;
674 674 jvp->vol_gid = hsfs_default_gid;
675 675 jvp->vol_prot = hsfs_default_mode;
676 676
677 677 /*
678 678 * Look for a Standard File Structure Volume Descriptor,
679 679 * of which there must be at least one.
680 680 * If found, check for volume size consistency.
681 681 *
682 682 * If svp->lbn_size is != 0, we did find a ISO-9660:1999 SVD
683 683 * If jvp->lbn_size is != 0, we did find a Joliet SVD.
684 684 */
685 685 fsp->hsfs_namemax = ISO_FILE_NAMELEN;
686 686 fsp->hsfs_namelen = ISO_FILE_NAMELEN;
687 687 error = hs_findisovol(fsp, devvp, &fsp->hsfs_vol, svp, jvp);
688 688 if (error == EINVAL) /* no iso 9660 - try high sierra ... */
689 689 error = hs_findhsvol(fsp, devvp, &fsp->hsfs_vol);
690 690
691 691 if (error)
692 692 goto cleanup;
693 693
694 694 DTRACE_PROBE4(findvol,
695 695 struct hsfs *, fsp,
696 696 struct hs_volume *, &fsp->hsfs_vol,
697 697 struct hs_volume *, svp,
698 698 struct hs_volume *, jvp);
699 699
700 700 /*
701 701 * Generate a file system ID from the CD-ROM,
702 702 * and check it for uniqueness.
703 703 *
704 704 * What we are aiming for is some chance of integrity
705 705 * across disk change. That is, if a client has an fhandle,
706 706 * it will be valid as long as the same disk is mounted.
707 707 */
708 708 fsid = compute_cdrom_id(fsp, devvp);
709 709
710 710 mutex_enter(&hs_mounttab_lock);
711 711
712 712 if (fsid == 0 || fsid == -1) {
713 713 uniqtime(&tv);
714 714 fsid = tv.tv_sec;
715 715 } else /* make sure that the fsid is unique */
716 716 for (tsp = hs_mounttab; tsp != NULL; tsp = tsp->hsfs_next) {
717 717 if (fsid == tsp->hsfs_vfs->vfs_fsid.val[0]) {
718 718 uniqtime(&tv);
719 719 fsid = tv.tv_sec;
720 720 break;
721 721 }
722 722 }
723 723
724 724 fsp->hsfs_next = hs_mounttab;
725 725 hs_mounttab = fsp;
726 726
727 727 fsp->hsfs_devvp = devvp;
728 728 fsp->hsfs_vfs = vfsp;
729 729 fsp->hsfs_fsmnt = kmem_alloc(pathbufsz, KM_SLEEP);
730 730 (void) strlcpy(fsp->hsfs_fsmnt, path, pathbufsz);
731 731
732 732 mutex_init(&fsp->hsfs_free_lock, NULL, MUTEX_DEFAULT, NULL);
733 733 rw_init(&fsp->hsfs_hash_lock, NULL, RW_DEFAULT, NULL);
734 734
735 735 vfsp->vfs_data = (caddr_t)fsp;
736 736 vfsp->vfs_dev = dev;
737 737 vfsp->vfs_fstype = hsfsfstype;
738 738 vfsp->vfs_bsize = fsp->hsfs_vol.lbn_size; /* %% */
739 739 vfsp->vfs_fsid.val[0] = fsid;
740 740 vfsp->vfs_fsid.val[1] = hsfsfstype;
741 741
742 742 if (!hs_getrootvp(vfsp, fsp, pathbufsz)) {
743 743 DTRACE_PROBE1(rootvp__failed, struct hsfs *, fsp);
744 744 error = EINVAL;
745 745 goto cleanup;
746 746 }
747 747 DTRACE_PROBE1(rootvp, struct hsfs *, fsp);
748 748
749 749 /*
750 750 * Attempt to discover a RR extension.
751 751 */
752 752 if (use_rrip) {
753 753 hp = VTOH(fsp->hsfs_rootvp);
754 754 hs_check_root_dirent(fsp->hsfs_rootvp, &(hp->hs_dirent));
755 755 }
756 756
757 757 has_rrip = IS_RRIP_IMPLEMENTED(fsp);
758 758 has_vers2 = (svp->lbn_size != 0);
759 759 has_joliet = (jvp->lbn_size != 0);
760 760
761 761 DTRACE_PROBE4(voltype__suggested, struct hsfs *, fsp,
762 762 int, use_rrip, int, use_vers2, int, use_joliet);
763 763
764 764 DTRACE_PROBE4(voltype__actual, struct hsfs *, fsp,
765 765 int, has_rrip, int, has_vers2, int, has_joliet);
766 766
767 767 DTRACE_PROBE4(findvol,
768 768 struct hsfs *, fsp,
769 769 struct hs_volume *, &fsp->hsfs_vol,
770 770 struct hs_volume *, svp,
771 771 struct hs_volume *, jvp);
772 772
773 773 force_rrip_off = !use_rrip ||
774 774 (vfs_optionisset(vfsp, HOPT_JOLIET, NULL) && has_joliet) ||
775 775 (vfs_optionisset(vfsp, HOPT_VERS2, NULL) && has_vers2);
776 776
777 777 force_vers2_off = !use_vers2 ||
778 778 (vfs_optionisset(vfsp, HOPT_JOLIET, NULL) && has_joliet);
779 779
780 780 force_joliet_off = !use_joliet;
781 781
782 782 DTRACE_PROBE4(voltype__force_off, struct hsfs *, fsp,
783 783 int, force_rrip_off, int, force_vers2_off, int, force_joliet_off);
784 784
785 785 /*
786 786 * At the moment, we have references of all three possible
787 787 * extensions (RR, ISO9660:1999/v2 and Joliet) if present.
788 788 *
789 789 * The "active" volume descriptor is RRIP (or ISO9660:1988).
790 790 * We now switch to the user-requested one.
791 791 */
792 792 redo_rootvp = 0;
793 793
794 794 if (force_rrip_off || !has_rrip) {
795 795 if (has_vers2 && !force_vers2_off) {
796 796 VN_RELE(fsp->hsfs_rootvp);
797 797 bcopy(svp, &fsp->hsfs_vol, sizeof (struct hs_volume));
798 798 fsp->hsfs_vol_type = HS_VOL_TYPE_ISO_V2;
799 799 vfsp->vfs_bsize = fsp->hsfs_vol.lbn_size;
800 800 redo_rootvp = 1;
801 801 has_joliet = 0;
802 802 } else if (has_joliet && !force_joliet_off) {
803 803 VN_RELE(fsp->hsfs_rootvp);
804 804 bcopy(jvp, &fsp->hsfs_vol, sizeof (struct hs_volume));
805 805 fsp->hsfs_vol_type = HS_VOL_TYPE_JOLIET;
806 806 vfsp->vfs_bsize = fsp->hsfs_vol.lbn_size;
807 807 redo_rootvp = 1;
808 808 has_vers2 = 0;
809 809 }
810 810 }
811 811
812 812 if (redo_rootvp) {
813 813 /*
814 814 * Make sure not to use Rock Ridge.
815 815 */
816 816 UNSET_IMPL_BIT(fsp, RRIP_BIT);
817 817 UNSET_SUSP_BIT(fsp);
818 818 has_rrip = 0;
819 819
820 820 if (!hs_getrootvp(vfsp, fsp, pathbufsz)) {
821 821 DTRACE_PROBE1(rootvp__failed, struct hsfs *, fsp);
822 822 error = EINVAL;
823 823 goto cleanup;
824 824 }
825 825 DTRACE_PROBE1(rootvp, struct hsfs *, fsp);
826 826 }
827 827 if (IS_RRIP_IMPLEMENTED(fsp)) {
828 828 has_vers2 = 0;
829 829 has_joliet = 0;
830 830 }
831 831 if (force_vers2_off)
832 832 has_vers2 = 0;
833 833 if (force_joliet_off)
834 834 has_joliet = 0;
835 835 DTRACE_PROBE4(voltype__taken, struct hsfs *, fsp,
836 836 int, has_rrip, int, has_vers2, int, has_joliet);
837 837
838 838 /*
839 839 * mark root node as VROOT
840 840 */
841 841 fsp->hsfs_rootvp->v_flag |= VROOT;
842 842
843 843 /* Here we take care of some special case stuff for mountroot */
844 844 if (isroot) {
845 845 fsp->hsfs_rootvp->v_rdev = devvp->v_rdev;
846 846 rootvp = fsp->hsfs_rootvp;
847 847 }
848 848
849 849 if (IS_RRIP_IMPLEMENTED(fsp)) {
850 850 /*
851 851 * if RRIP, don't copy NOMAPLCASE or NOTRAILDOT to hsfs_flags
852 852 */
853 853 mount_flags &= ~(HSFSMNT_NOMAPLCASE | HSFSMNT_NOTRAILDOT);
854 854
855 855 fsp->hsfs_namemax = RRIP_FILE_NAMELEN;
856 856 fsp->hsfs_namelen = RRIP_FILE_NAMELEN;
857 857
858 858 ASSERT(vfs_optionisset(vfsp, HOPT_RR, NULL));
859 859 vfs_clearmntopt(vfsp, HOPT_VERS2);
860 860 vfs_clearmntopt(vfsp, HOPT_JOLIET);
861 861
862 862 } else switch (fsp->hsfs_vol_type) {
863 863
864 864 case HS_VOL_TYPE_HS:
865 865 case HS_VOL_TYPE_ISO:
866 866 default:
867 867 /*
868 868 * if iso v1, don't allow trailing spaces in iso file names
869 869 */
870 870 mount_flags |= HSFSMNT_NOTRAILSPACE;
871 871 fsp->hsfs_namemax = ISO_NAMELEN_V2_MAX;
872 872 fsp->hsfs_namelen = ISO_FILE_NAMELEN;
873 873 vfs_clearmntopt(vfsp, HOPT_RR);
874 874 vfs_clearmntopt(vfsp, HOPT_VERS2);
875 875 vfs_clearmntopt(vfsp, HOPT_JOLIET);
876 876 break;
877 877
878 878 case HS_VOL_TYPE_ISO_V2:
879 879 /*
880 880 * if iso v2, don't copy NOTRAILDOT to hsfs_flags
881 881 */
882 882 mount_flags &= ~HSFSMNT_NOTRAILDOT;
883 883 mount_flags |= HSFSMNT_NOMAPLCASE | HSFSMNT_NOVERSION;
884 884 fsp->hsfs_namemax = ISO_NAMELEN_V2_MAX;
885 885 fsp->hsfs_namelen = ISO_NAMELEN_V2;
886 886 vfs_setmntopt(vfsp, HOPT_VERS2, NULL, 0);
887 887 vfs_clearmntopt(vfsp, HOPT_RR);
888 888 vfs_clearmntopt(vfsp, HOPT_JOLIET);
889 889 break;
890 890
891 891 case HS_VOL_TYPE_JOLIET:
892 892 /*
893 893 * if Joliet, don't copy NOMAPLCASE or NOTRAILDOT to hsfs_flags
894 894 */
895 895 mount_flags &= ~(HSFSMNT_NOMAPLCASE | HSFSMNT_NOTRAILDOT);
896 896 mount_flags |= HSFSMNT_NOMAPLCASE;
897 897 if (mount_flags & HSFSMNT_JOLIETLONG)
898 898 fsp->hsfs_namemax = JOLIET_NAMELEN_MAX*3; /* UTF-8 */
899 899 else
900 900 fsp->hsfs_namemax = MAXNAMELEN-1;
901 901 fsp->hsfs_namelen = JOLIET_NAMELEN*2;
902 902 vfs_setmntopt(vfsp, HOPT_JOLIET, NULL, 0);
903 903 vfs_clearmntopt(vfsp, HOPT_RR);
904 904 vfs_clearmntopt(vfsp, HOPT_VERS2);
905 905 break;
906 906 }
907 907
908 908 /*
909 909 * Add the HSFSMNT_INODE pseudo mount flag to the current mount flags.
910 910 */
911 911 fsp->hsfs_flags = mount_flags | (fsp->hsfs_flags & HSFSMNT_INODE);
912 912
913 913 /*
914 914 * Setup I/O Scheduling structures
915 915 */
916 916 if (do_schedio) {
917 917 fsp->hqueue = kmem_alloc(sizeof (struct hsfs_queue), KM_SLEEP);
918 918 hsched_init(fsp, fsid, &modlinkage);
919 919 }
920 920
921 921 /*
922 922 * Setup kstats
923 923 */
924 924 hsfs_init_kstats(fsp, fsid);
925 925
926 926 DTRACE_PROBE1(mount__done, struct hsfs *, fsp);
927 927
928 928 /*
929 929 * set the magic word
930 930 */
931 931 fsp->hsfs_magic = HSFS_MAGIC;
932 932 mutex_exit(&hs_mounttab_lock);
933 933
934 934 kmem_free(svp, sizeof (*svp));
935 935 kmem_free(jvp, sizeof (*jvp));
936 936
937 937 return (0);
938 938
939 939 cleanup:
940 940 (void) VOP_CLOSE(devvp, FREAD, 1, (offset_t)0, cr, NULL);
941 941 VN_RELE(devvp);
942 942 if (fsp)
943 943 kmem_free(fsp, sizeof (*fsp));
944 944 if (svp)
945 945 kmem_free(svp, sizeof (*svp));
946 946 if (jvp)
947 947 kmem_free(jvp, sizeof (*jvp));
948 948 return (error);
949 949 }
950 950
951 951 /*
952 952 * Get the rootvp associated with fsp->hsfs_vol
953 953 */
954 954 static int
955 955 hs_getrootvp(
956 956 struct vfs *vfsp,
957 957 struct hsfs *fsp,
958 958 size_t pathsize)
959 959 {
960 960 struct hsnode *hp;
961 961
962 962 ASSERT(pathsize == strlen(fsp->hsfs_fsmnt) + 1);
963 963
964 964 /*
965 965 * If the root directory does not appear to be
966 966 * valid, use what it points to as "." instead.
967 967 * Some Defense Mapping Agency disks are non-conformant
968 968 * in this way.
969 969 */
970 970 if (!hsfs_valid_dir(&fsp->hsfs_vol.root_dir)) {
971 971 hs_log_bogus_disk_warning(fsp, HSFS_ERR_BAD_ROOT_DIR, 0);
972 972 if (hs_remakenode(fsp->hsfs_vol.root_dir.ext_lbn,
973 973 (uint_t)0, vfsp, &fsp->hsfs_rootvp)) {
974 974 hs_mounttab = hs_mounttab->hsfs_next;
975 975 mutex_destroy(&fsp->hsfs_free_lock);
976 976 rw_destroy(&fsp->hsfs_hash_lock);
977 977 kmem_free(fsp->hsfs_fsmnt, pathsize);
978 978 mutex_exit(&hs_mounttab_lock);
979 979 return (0);
980 980 }
981 981 } else {
982 982 fsp->hsfs_rootvp = hs_makenode(&fsp->hsfs_vol.root_dir,
983 983 fsp->hsfs_vol.root_dir.ext_lbn, 0, vfsp);
984 984 }
985 985
986 986 /* XXX - ignore the path table for now */
987 987 fsp->hsfs_ptbl = NULL;
988 988 hp = VTOH(fsp->hsfs_rootvp);
989 989 hp->hs_ptbl_idx = NULL;
990 990
991 991 return (1);
992 992 }
993 993
994 994 /*
995 995 * hs_findhsvol()
996 996 *
997 997 * Locate the Standard File Structure Volume Descriptor and
998 998 * parse it into an hs_volume structure.
999 999 *
1000 1000 * XXX - May someday want to look for Coded Character Set FSVD, too.
1001 1001 */
1002 1002 static int
1003 1003 hs_findhsvol(struct hsfs *fsp, struct vnode *vp, struct hs_volume *hvp)
1004 1004 {
1005 1005 struct buf *secbp;
1006 1006 int i;
1007 1007 int n;
1008 1008 uchar_t *volp;
1009 1009 int error;
1010 1010 uint_t secno;
1011 1011
1012 1012 secno = hs_findvoldesc(vp->v_rdev, HS_VOLDESC_SEC);
1013 1013 secbp = bread(vp->v_rdev, secno * 4, HS_SECTOR_SIZE);
1014 1014 error = geterror(secbp);
1015 1015
1016 1016 if (error != 0) {
1017 1017 cmn_err(CE_NOTE, "hs_findhsvol: bread: error=(%d)", error);
1018 1018 brelse(secbp);
1019 1019 return (error);
1020 1020 }
1021 1021
1022 1022 volp = (uchar_t *)secbp->b_un.b_addr;
1023 1023
1024 1024 /*
1025 1025 * To avoid that we read the whole medium in case that someone prepares
1026 1026 * a malicious "fs image", we read at most 32 blocks.
1027 1027 */
1028 1028 for (n = 0; n < 32 &&
1029 1029 HSV_DESC_TYPE(volp) != VD_EOV; n++) {
1030 1030 for (i = 0; i < HSV_ID_STRLEN; i++)
1031 1031 if (HSV_STD_ID(volp)[i] != HSV_ID_STRING[i])
1032 1032 goto cantfind;
1033 1033 if (HSV_STD_VER(volp) != HSV_ID_VER)
1034 1034 goto cantfind;
1035 1035 switch (HSV_DESC_TYPE(volp)) {
1036 1036 case VD_SFS:
1037 1037 /* Standard File Structure */
1038 1038 fsp->hsfs_vol_type = HS_VOL_TYPE_HS;
1039 1039 error = hs_parsehsvol(fsp, volp, hvp);
1040 1040 brelse(secbp);
1041 1041 return (error);
1042 1042
1043 1043 case VD_CCFS:
1044 1044 /* Coded Character File Structure */
1045 1045 case VD_BOOT:
1046 1046 case VD_UNSPEC:
1047 1047 case VD_EOV:
1048 1048 break;
1049 1049 }
1050 1050 brelse(secbp);
1051 1051 ++secno;
1052 1052 secbp = bread(vp->v_rdev, secno * 4, HS_SECTOR_SIZE);
1053 1053
1054 1054 error = geterror(secbp);
1055 1055
1056 1056 if (error != 0) {
1057 1057 cmn_err(CE_NOTE, "hs_findhsvol: bread: error=(%d)",
1058 1058 error);
1059 1059 brelse(secbp);
1060 1060 return (error);
1061 1061 }
1062 1062
1063 1063 volp = (uchar_t *)secbp->b_un.b_addr;
1064 1064 }
1065 1065 cantfind:
1066 1066 brelse(secbp);
1067 1067 return (EINVAL);
1068 1068 }
1069 1069
1070 1070 /*
1071 1071 * hs_parsehsvol
1072 1072 *
1073 1073 * Parse the Standard File Structure Volume Descriptor into
1074 1074 * an hs_volume structure. We can't just bcopy it into the
1075 1075 * structure because of byte-ordering problems.
1076 1076 *
1077 1077 */
1078 1078 static int
1079 1079 hs_parsehsvol(struct hsfs *fsp, uchar_t *volp, struct hs_volume *hvp)
1080 1080 {
1081 1081 hvp->vol_size = HSV_VOL_SIZE(volp);
1082 1082 hvp->lbn_size = HSV_BLK_SIZE(volp);
1083 1083 if (hvp->lbn_size == 0) {
1084 1084 cmn_err(CE_NOTE, "hs_parsehsvol: logical block size in the "
1085 1085 "SFSVD is zero");
1086 1086 return (EINVAL);
1087 1087 }
1088 1088 hvp->lbn_shift = ffs((long)hvp->lbn_size) - 1;
1089 1089 hvp->lbn_secshift =
1090 1090 ffs((long)howmany(HS_SECTOR_SIZE, (int)hvp->lbn_size)) - 1;
1091 1091 hvp->lbn_maxoffset = hvp->lbn_size - 1;
1092 1092 hs_parse_longdate(HSV_cre_date(volp), &hvp->cre_date);
1093 1093 hs_parse_longdate(HSV_mod_date(volp), &hvp->mod_date);
1094 1094 hvp->file_struct_ver = HSV_FILE_STRUCT_VER(volp);
1095 1095 hvp->ptbl_len = HSV_PTBL_SIZE(volp);
1096 1096 hvp->vol_set_size = (ushort_t)HSV_SET_SIZE(volp);
1097 1097 hvp->vol_set_seq = (ushort_t)HSV_SET_SEQ(volp);
1098 1098 #if defined(_LITTLE_ENDIAN)
1099 1099 hvp->ptbl_lbn = HSV_PTBL_MAN_LS(volp);
1100 1100 #else
1101 1101 hvp->ptbl_lbn = HSV_PTBL_MAN_MS(volp);
1102 1102 #endif
1103 1103 hs_copylabel(hvp, HSV_VOL_ID(volp), 0);
1104 1104
1105 1105 /*
1106 1106 * Make sure that lbn_size is a power of two and otherwise valid.
1107 1107 */
1108 1108 if (hvp->lbn_size & ~(1 << hvp->lbn_shift)) {
1109 1109 cmn_err(CE_NOTE,
1110 1110 "hsfs: %d-byte logical block size not supported",
1111 1111 hvp->lbn_size);
1112 1112 return (EINVAL);
1113 1113 }
1114 1114 return (hs_parsedir(fsp, HSV_ROOT_DIR(volp), &hvp->root_dir,
1115 1115 (char *)NULL, (int *)NULL, HDE_ROOT_DIR_REC_SIZE));
1116 1116 }
1117 1117
1118 1118 /*
1119 1119 * hs_findisovol()
1120 1120 *
1121 1121 * Locate the Primary Volume Descriptor
1122 1122 * parse it into an hs_volume structure.
1123 1123 *
1124 1124 * XXX - Partition not yet done
1125 1125 *
1126 1126 * Except for fsp->hsfs_vol_type, no fsp member may be modified.
1127 1127 * fsp->hsfs_vol is modified indirectly via the *hvp argument.
1128 1128 */
1129 1129 static int
1130 1130 hs_findisovol(struct hsfs *fsp, struct vnode *vp,
1131 1131 struct hs_volume *hvp,
1132 1132 struct hs_volume *svp,
1133 1133 struct hs_volume *jvp)
1134 1134 {
1135 1135 struct buf *secbp;
1136 1136 int i;
1137 1137 int n;
1138 1138 uchar_t *volp;
1139 1139 int error;
1140 1140 uint_t secno;
1141 1141 int foundpvd = 0;
1142 1142 int foundsvd = 0;
1143 1143 int foundjvd = 0;
1144 1144 int pvd_sum = 0;
1145 1145
1146 1146 secno = hs_findvoldesc(vp->v_rdev, ISO_VOLDESC_SEC);
1147 1147 secbp = bread(vp->v_rdev, secno * 4, ISO_SECTOR_SIZE);
1148 1148 error = geterror(secbp);
1149 1149
1150 1150 if (error != 0) {
1151 1151 cmn_err(CE_NOTE, "hs_findisovol: bread: error=(%d)", error);
1152 1152 brelse(secbp);
1153 1153 return (error);
1154 1154 }
1155 1155
1156 1156 volp = (uchar_t *)secbp->b_un.b_addr;
1157 1157
1158 1158 /*
1159 1159 * To avoid that we read the whole medium in case that someone prepares
1160 1160 * a malicious "fs image", we read at most 32 blocks.
1161 1161 */
1162 1162 for (n = 0; n < 32 &&
1163 1163 (enum iso_voldesc_type) ISO_DESC_TYPE(volp) != ISO_VD_EOV; n++) {
1164 1164 for (i = 0; i < ISO_ID_STRLEN; i++)
1165 1165 if (ISO_STD_ID(volp)[i] != ISO_ID_STRING[i])
1166 1166 goto cantfind;
1167 1167 switch (ISO_DESC_TYPE(volp)) {
1168 1168 case ISO_VD_PVD:
1169 1169 /* Standard File Structure */
1170 1170 if (ISO_STD_VER(volp) != ISO_ID_VER)
1171 1171 goto cantfind;
1172 1172 if (foundpvd != 1) {
1173 1173 fsp->hsfs_vol_type = HS_VOL_TYPE_ISO;
1174 1174 if (error = hs_parseisovol(fsp, volp, hvp)) {
1175 1175 brelse(secbp);
1176 1176 return (error);
1177 1177 }
1178 1178 foundpvd = 1;
1179 1179 for (i = 0; i < ISO_SECTOR_SIZE; i++)
1180 1180 pvd_sum += volp[i];
1181 1181 }
1182 1182 break;
1183 1183 case ISO_VD_SVD:
1184 1184 /* Supplementary Volume Descriptor */
1185 1185 if (ISO_STD_VER(volp) == ISO_ID_VER2 &&
1186 1186 foundsvd != 1) {
1187 1187 fsp->hsfs_vol_type = HS_VOL_TYPE_ISO;
1188 1188 if (error = hs_parseisovol(fsp, volp, svp)) {
1189 1189 brelse(secbp);
1190 1190 return (error);
1191 1191 }
1192 1192 foundsvd = 1;
1193 1193 }
1194 1194 if (hs_joliet_level(volp) >= 1 && foundjvd != 1) {
1195 1195 fsp->hsfs_vol_type = HS_VOL_TYPE_ISO;
1196 1196 if (error = hs_parseisovol(fsp, volp, jvp)) {
1197 1197 brelse(secbp);
1198 1198 return (error);
1199 1199 }
1200 1200 foundjvd = 1;
1201 1201 }
1202 1202 break;
1203 1203 case ISO_VD_BOOT:
1204 1204 break;
1205 1205 case ISO_VD_VPD:
1206 1206 /* currently cannot handle partition */
1207 1207 break;
1208 1208 case VD_EOV:
1209 1209 break;
1210 1210 }
1211 1211 brelse(secbp);
1212 1212 ++secno;
1213 1213 secbp = bread(vp->v_rdev, secno * 4, HS_SECTOR_SIZE);
1214 1214 error = geterror(secbp);
1215 1215
1216 1216 if (error != 0) {
1217 1217 cmn_err(CE_NOTE, "hs_findisovol: bread: error=(%d)",
1218 1218 error);
1219 1219 brelse(secbp);
1220 1220 return (error);
1221 1221 }
1222 1222
1223 1223 volp = (uchar_t *)secbp->b_un.b_addr;
1224 1224 }
1225 1225 for (n = 0; n < 16; n++) {
1226 1226 brelse(secbp);
1227 1227 ++secno;
1228 1228 secbp = bread(vp->v_rdev, secno * 4, HS_SECTOR_SIZE);
1229 1229 error = geterror(secbp);
1230 1230
1231 1231 if (error != 0) {
1232 1232 cmn_err(CE_NOTE, "hs_findisovol: bread: error=(%d)",
1233 1233 error);
1234 1234 brelse(secbp);
1235 1235 return (error);
1236 1236 }
1237 1237
1238 1238 /*
1239 1239 * Check for the signature from mkisofs that grants that
1240 1240 * the current filesystem allows to use the extent lbn as
1241 1241 * inode number even in pure ISO9660 mode.
1242 1242 */
1243 1243 volp = (uchar_t *)secbp->b_un.b_addr;
1244 1244 if (strncmp((char *)volp, "MKI ", 4) == 0) {
1245 1245 int sum;
1246 1246
1247 1247 sum = volp[2045];
1248 1248 sum *= 256;
1249 1249 sum += volp[2046];
1250 1250 sum *= 256;
1251 1251 sum += volp[2047];
1252 1252 if (sum == pvd_sum)
1253 1253 fsp->hsfs_flags |= HSFSMNT_INODE;
1254 1254 break;
1255 1255 }
1256 1256 }
1257 1257 if (foundpvd) {
1258 1258 brelse(secbp);
1259 1259 return (0);
1260 1260 }
1261 1261 cantfind:
1262 1262 brelse(secbp);
1263 1263 return (EINVAL);
1264 1264 }
1265 1265
1266 1266 /*
1267 1267 * Return 0 if no Joliet is found
1268 1268 * else return Joliet Level 1..3
1269 1269 */
1270 1270 static int
1271 1271 hs_joliet_level(uchar_t *volp)
1272 1272 {
1273 1273 if (ISO_std_ver(volp)[0] == ISO_ID_VER &&
1274 1274 ISO_svd_esc(volp)[0] == '%' &&
1275 1275 ISO_svd_esc(volp)[1] == '/') {
1276 1276
1277 1277 switch (ISO_svd_esc(volp)[2]) {
1278 1278
1279 1279 case '@':
1280 1280 return (1);
1281 1281 case 'C':
1282 1282 return (2);
1283 1283 case 'E':
1284 1284 return (3);
1285 1285 }
1286 1286 }
1287 1287 return (0);
1288 1288 }
1289 1289
1290 1290 /*
1291 1291 * hs_parseisovol
1292 1292 *
1293 1293 * Parse the Primary Volume Descriptor into an hs_volume structure.
1294 1294 *
1295 1295 */
1296 1296 static int
1297 1297 hs_parseisovol(struct hsfs *fsp, uchar_t *volp, struct hs_volume *hvp)
1298 1298 {
1299 1299 hvp->vol_size = ISO_VOL_SIZE(volp);
1300 1300 hvp->lbn_size = ISO_BLK_SIZE(volp);
1301 1301 if (hvp->lbn_size == 0) {
1302 1302 cmn_err(CE_NOTE, "hs_parseisovol: logical block size in the "
1303 1303 "PVD is zero");
1304 1304 return (EINVAL);
1305 1305 }
1306 1306 hvp->lbn_shift = ffs((long)hvp->lbn_size) - 1;
1307 1307 hvp->lbn_secshift =
1308 1308 ffs((long)howmany(ISO_SECTOR_SIZE, (int)hvp->lbn_size)) - 1;
1309 1309 hvp->lbn_maxoffset = hvp->lbn_size - 1;
1310 1310 hs_parse_longdate(ISO_cre_date(volp), &hvp->cre_date);
1311 1311 hs_parse_longdate(ISO_mod_date(volp), &hvp->mod_date);
1312 1312 hvp->file_struct_ver = ISO_FILE_STRUCT_VER(volp);
1313 1313 hvp->ptbl_len = ISO_PTBL_SIZE(volp);
1314 1314 hvp->vol_set_size = (ushort_t)ISO_SET_SIZE(volp);
1315 1315 hvp->vol_set_seq = (ushort_t)ISO_SET_SEQ(volp);
1316 1316 #if defined(_LITTLE_ENDIAN)
1317 1317 hvp->ptbl_lbn = ISO_PTBL_MAN_LS(volp);
1318 1318 #else
1319 1319 hvp->ptbl_lbn = ISO_PTBL_MAN_MS(volp);
1320 1320 #endif
1321 1321 hs_copylabel(hvp, ISO_VOL_ID(volp), hs_joliet_level(volp) >= 1);
1322 1322
1323 1323 /*
1324 1324 * Make sure that lbn_size is a power of two and otherwise valid.
1325 1325 */
1326 1326 if (hvp->lbn_size & ~(1 << hvp->lbn_shift)) {
1327 1327 cmn_err(CE_NOTE,
1328 1328 "hsfs: %d-byte logical block size not supported",
1329 1329 hvp->lbn_size);
1330 1330 return (EINVAL);
1331 1331 }
1332 1332 return (hs_parsedir(fsp, ISO_ROOT_DIR(volp), &hvp->root_dir,
1333 1333 (char *)NULL, (int *)NULL, IDE_ROOT_DIR_REC_SIZE));
1334 1334 }
1335 1335
|
↓ open down ↓ |
1299 lines elided |
↑ open up ↑ |
1336 1336 /*
1337 1337 * Common code for mount and umount.
1338 1338 * Check that the user's argument is a reasonable
1339 1339 * thing on which to mount, and return the device number if so.
1340 1340 */
1341 1341 static int
1342 1342 hs_getmdev(struct vfs *vfsp, char *fspec, int flags, dev_t *pdev, mode_t *mode,
1343 1343 cred_t *cr)
1344 1344 {
1345 1345 int error;
1346 - struct vnode *vp;
1346 + struct vnode *svp = NULL;
1347 + struct vnode *lvp = NULL;
1348 + struct vnode *bvp;
1347 1349 struct vattr vap;
1348 1350 dev_t dev;
1351 + enum uio_seg fromspace = (flags & MS_SYSSPACE) ?
1352 + UIO_SYSSPACE : UIO_USERSPACE;
1349 1353
1350 1354 /*
1351 - * Get the device to be mounted
1355 + * Look up the device/file to be mounted.
1352 1356 */
1353 - error = lookupname(fspec, (flags & MS_SYSSPACE) ?
1354 - UIO_SYSSPACE : UIO_USERSPACE, FOLLOW, NULLVPP, &vp);
1357 + error = lookupname(fspec, fromspace, FOLLOW, NULLVPP, &svp);
1355 1358 if (error) {
1356 - if (error == ENOENT) {
1357 - return (ENODEV); /* needs translation */
1359 + if (error == ENOENT)
1360 + error = ENODEV;
1361 + goto out;
1362 + }
1363 +
1364 + error = vfs_get_lofi(vfsp, &lvp);
1365 +
1366 + if (error > 0) {
1367 + if (error == ENOENT)
1368 + error = ENODEV;
1369 + goto out;
1370 + } else if (error == 0) {
1371 + bvp = lvp;
1372 + } else {
1373 + bvp = svp;
1374 +
1375 + if (bvp->v_type != VBLK) {
1376 + error = ENOTBLK;
1377 + goto out;
1358 1378 }
1359 - return (error);
1379 +
1380 + if ((error = secpolicy_spec_open(cr, bvp, FREAD)) != 0)
1381 + goto out;
1360 1382 }
1361 - if (vp->v_type != VBLK) {
1362 - VN_RELE(vp);
1363 - return (ENOTBLK);
1364 - }
1383 +
1365 1384 /*
1366 - * Can we read from the device?
1385 + * Can we read from the device/file ?
1367 1386 */
1368 - if ((error = VOP_ACCESS(vp, VREAD, 0, cr, NULL)) != 0 ||
1369 - (error = secpolicy_spec_open(cr, vp, FREAD)) != 0) {
1370 - VN_RELE(vp);
1371 - return (error);
1372 - }
1387 + if ((error = VOP_ACCESS(svp, VREAD, 0, cr, NULL)) != 0)
1388 + goto out;
1373 1389
1374 1390 vap.va_mask = AT_MODE; /* get protection mode */
1375 - (void) VOP_GETATTR(vp, &vap, 0, CRED(), NULL);
1391 + (void) VOP_GETATTR(bvp, &vap, 0, CRED(), NULL);
1376 1392 *mode = vap.va_mode;
1377 1393
1378 - dev = *pdev = vp->v_rdev;
1379 - VN_RELE(vp);
1394 + dev = *pdev = bvp->v_rdev;
1380 1395
1396 + error = EBUSY;
1397 +
1381 1398 /*
1382 1399 * Ensure that this device isn't already mounted,
1383 1400 * unless this is a REMOUNT request or we are told to suppress
1384 1401 * mount checks.
1385 1402 */
1386 1403 if ((flags & MS_NOCHECK) == 0) {
1387 1404 if (vfs_devmounting(dev, vfsp))
1388 - return (EBUSY);
1405 + goto out;
1389 1406 if (vfs_devismounted(dev) && !(flags & MS_REMOUNT))
1390 - return (EBUSY);
1407 + goto out;
1391 1408 }
1392 1409
1393 - if (getmajor(*pdev) >= devcnt)
1394 - return (ENXIO);
1395 - return (0);
1410 + if (getmajor(*pdev) >= devcnt) {
1411 + error = ENXIO;
1412 + goto out;
1413 + }
1414 +
1415 + error = 0;
1416 +out:
1417 + if (svp != NULL)
1418 + VN_RELE(svp);
1419 + if (lvp != NULL)
1420 + VN_RELE(lvp);
1421 + return (error);
1396 1422 }
1397 1423
1398 1424 static void
1399 1425 hs_copylabel(struct hs_volume *hvp, unsigned char *label, int isjoliet)
1400 1426 {
1401 1427 char lbuf[64]; /* hs_joliet_cp() creates 48 bytes at most */
1402 1428
1403 1429 if (isjoliet) {
1404 1430 /*
1405 1431 * hs_joliet_cp() will output 16..48 bytes.
1406 1432 * We need to clear 'lbuf' to avoid junk chars past byte 15.
1407 1433 */
1408 1434 bzero(lbuf, sizeof (lbuf));
1409 1435 (void) hs_joliet_cp((char *)label, lbuf, 32);
1410 1436 label = (unsigned char *)lbuf;
1411 1437 }
1412 1438 /* cdrom volid is at most 32 bytes */
1413 1439 bcopy(label, hvp->vol_id, 32);
1414 1440 hvp->vol_id[31] = NULL;
1415 1441 }
1416 1442
1417 1443 /*
1418 1444 * Mount root file system.
1419 1445 * "why" is ROOT_INIT on initial call, ROOT_REMOUNT if called to
1420 1446 * remount the root file system, and ROOT_UNMOUNT if called to
1421 1447 * unmount the root (e.g., as part of a system shutdown).
1422 1448 *
1423 1449 * XXX - this may be partially machine-dependent; it, along with the VFS_SWAPVP
1424 1450 * operation, goes along with auto-configuration. A mechanism should be
1425 1451 * provided by which machine-INdependent code in the kernel can say "get me the
1426 1452 * right root file system" and "get me the right initial swap area", and have
1427 1453 * that done in what may well be a machine-dependent fashion.
1428 1454 * Unfortunately, it is also file-system-type dependent (NFS gets it via
1429 1455 * bootparams calls, UFS gets it from various and sundry machine-dependent
1430 1456 * mechanisms, as SPECFS does for swap).
1431 1457 */
1432 1458 static int
1433 1459 hsfs_mountroot(struct vfs *vfsp, enum whymountroot why)
1434 1460 {
1435 1461 int error;
1436 1462 struct hsfs *fsp;
1437 1463 struct hs_volume *fvolp;
1438 1464 static int hsfsrootdone = 0;
1439 1465 dev_t rootdev;
1440 1466 mode_t mode = 0;
1441 1467
1442 1468 if (why == ROOT_INIT) {
1443 1469 if (hsfsrootdone++)
1444 1470 return (EBUSY);
1445 1471 rootdev = getrootdev();
1446 1472 if (rootdev == (dev_t)NODEV)
1447 1473 return (ENODEV);
1448 1474 vfsp->vfs_dev = rootdev;
1449 1475 vfsp->vfs_flag |= VFS_RDONLY;
1450 1476 } else if (why == ROOT_REMOUNT) {
1451 1477 cmn_err(CE_NOTE, "hsfs_mountroot: ROOT_REMOUNT");
1452 1478 return (0);
1453 1479 } else if (why == ROOT_UNMOUNT) {
1454 1480 return (0);
1455 1481 }
1456 1482 error = vfs_lock(vfsp);
1457 1483 if (error) {
1458 1484 cmn_err(CE_NOTE, "hsfs_mountroot: couldn't get vfs_lock");
1459 1485 return (error);
1460 1486 }
1461 1487
1462 1488 error = hs_mountfs(vfsp, rootdev, "/", mode, 1, CRED(), 1);
1463 1489 /*
1464 1490 * XXX - assumes root device is not indirect, because we don't set
1465 1491 * rootvp. Is rootvp used for anything? If so, make another arg
1466 1492 * to mountfs.
1467 1493 */
1468 1494 if (error) {
1469 1495 vfs_unlock(vfsp);
1470 1496 if (rootvp) {
1471 1497 VN_RELE(rootvp);
1472 1498 rootvp = (struct vnode *)0;
1473 1499 }
1474 1500 return (error);
1475 1501 }
1476 1502 if (why == ROOT_INIT)
1477 1503 vfs_add((struct vnode *)0, vfsp,
1478 1504 (vfsp->vfs_flag & VFS_RDONLY) ? MS_RDONLY : 0);
1479 1505 vfs_unlock(vfsp);
1480 1506 fsp = VFS_TO_HSFS(vfsp);
1481 1507 fvolp = &fsp->hsfs_vol;
1482 1508 #ifdef HSFS_CLKSET
1483 1509 if (fvolp->cre_date.tv_sec == 0) {
1484 1510 cmn_err(CE_NOTE, "hsfs_mountroot: cre_date.tv_sec == 0");
1485 1511 if (fvolp->mod_date.tv_sec == 0) {
1486 1512 cmn_err(CE_NOTE,
1487 1513 "hsfs_mountroot: mod_date.tv_sec == 0");
1488 1514 cmn_err(CE_NOTE, "hsfs_mountroot: clkset(-1L)");
1489 1515 clkset(-1L);
1490 1516 } else {
1491 1517 clkset(fvolp->mod_date.tv_sec);
1492 1518 }
1493 1519 } else {
1494 1520 clkset(fvolp->mod_date.tv_sec);
1495 1521 }
1496 1522 #else /* HSFS_CLKSET */
1497 1523 clkset(-1L);
1498 1524 #endif /* HSFS_CLKSET */
1499 1525 return (0);
1500 1526 }
1501 1527
1502 1528 /*
1503 1529 * hs_findvoldesc()
1504 1530 *
1505 1531 * Return the sector where the volume descriptor lives. This is
1506 1532 * a fixed value for "normal" cd-rom's, but can change for
1507 1533 * multisession cd's.
1508 1534 *
1509 1535 * desc_sec is the same for high-sierra and iso 9660 formats, why
1510 1536 * there are two different #defines used in the code for this is
1511 1537 * beyond me. These are standards, cast in concrete, right?
1512 1538 * To be general, however, this function supports passing in different
1513 1539 * values.
1514 1540 */
1515 1541 static int
1516 1542 hs_findvoldesc(dev_t rdev, int desc_sec)
1517 1543 {
1518 1544 int secno;
1519 1545 int error;
1520 1546 int rval; /* ignored */
1521 1547
1522 1548 #ifdef CDROMREADOFFSET
1523 1549 /*
1524 1550 * Issue the Read Offset ioctl directly to the
1525 1551 * device. Ignore any errors and set starting
1526 1552 * secno to the default, otherwise add the
1527 1553 * VOLDESC sector number to the offset.
1528 1554 */
1529 1555 error = cdev_ioctl(rdev, CDROMREADOFFSET, (intptr_t)&secno,
1530 1556 FNATIVE|FKIOCTL|FREAD, CRED(), &rval);
1531 1557 if (error) {
1532 1558 secno = desc_sec;
1533 1559 } else {
1534 1560 secno += desc_sec;
1535 1561 }
1536 1562 #else
1537 1563 secno = desc_sec;
1538 1564 #endif
1539 1565
1540 1566 return (secno);
1541 1567 }
|
↓ open down ↓ |
136 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX