xref: /freebsd/sys/fs/cd9660/cd9660_vfsops.c (revision 4a0f765fbf09711e612e86fce8bb09ec43f482d9)
1 /*-
2  * Copyright (c) 1994
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley
6  * by Pace Willisson (pace@blitz.com).  The Rock Ridge Extension
7  * Support code is derived from software contributed to Berkeley
8  * by Atsushi Murai (amurai@spec.co.jp).
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *	@(#)cd9660_vfsops.c	8.18 (Berkeley) 5/22/95
39  * $Id$
40  */
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/namei.h>
45 #include <sys/proc.h>
46 #include <sys/kernel.h>
47 #include <sys/vnode.h>
48 #include <miscfs/specfs/specdev.h>
49 #include <sys/mount.h>
50 #include <sys/buf.h>
51 #include <sys/file.h>
52 #include <sys/ioctl.h>
53 #include <sys/errno.h>
54 #include <sys/malloc.h>
55 #include <sys/stat.h>
56 
57 #include <isofs/cd9660/iso.h>
58 #include <isofs/cd9660/iso_rrip.h>
59 #include <isofs/cd9660/cd9660_node.h>
60 #include <isofs/cd9660/cd9660_mount.h>
61 
62 
63 static int cd9660_mount __P((struct mount *,
64 	    char *, caddr_t, struct nameidata *, struct proc *));
65 static int cd9660_start __P((struct mount *, int, struct proc *));
66 static int cd9660_unmount __P((struct mount *, int, struct proc *));
67 static int cd9660_root __P((struct mount *, struct vnode **));
68 static int cd9660_quotactl __P((struct mount *, int, uid_t, caddr_t,
69 	    struct proc *));
70 static int cd9660_statfs __P((struct mount *, struct statfs *, struct proc *));
71 static int cd9660_sync __P((struct mount *, int, struct ucred *,
72 	    struct proc *));
73 static int cd9660_vget __P((struct mount *, ino_t, struct vnode **));
74 static int cd9660_fhtovp __P((struct mount *, struct fid *, struct mbuf *,
75 	    struct vnode **, int *, struct ucred **));
76 static int cd9660_vptofh __P((struct vnode *, struct fid *));
77 
78 static struct vfsops cd9660_vfsops = {
79 	cd9660_mount,
80 	cd9660_start,
81 	cd9660_unmount,
82 	cd9660_root,
83 	cd9660_quotactl,
84 	cd9660_statfs,
85 	cd9660_sync,
86 	cd9660_vget,
87 	cd9660_fhtovp,
88 	cd9660_vptofh,
89 	cd9660_init
90 };
91 VFS_SET(cd9660_vfsops, cd9660, MOUNT_CD9660, VFCF_READONLY);
92 
93 
94 /*
95  * Called by vfs_mountroot when iso is going to be mounted as root.
96  */
97 
98 static int iso_mountfs __P((struct vnode *devvp, struct mount *mp,
99 			    struct proc *p, struct iso_args *argp));
100 
101 int
102 cd9660_mountroot()
103 {
104 	struct mount *mp;
105 	struct proc *p = curproc;	/* XXX */
106 	struct iso_args args;
107 	int error;
108 
109 	/*
110 	 * Get vnode for rootdev.
111 	 */
112 	if ((error = bdevvp(swapdev, &swapdev_vp)) ||
113 	    (error = bdevvp(rootdev, &rootvp))) {
114 		printf("cd9660_mountroot: can't setup bdevvp's");
115 		return (error);
116 	}
117 
118 	if (error = vfs_rootmountalloc("cd9660", "root_device", &mp))
119 		return (error);
120 	args.flags = ISOFSMNT_ROOT;
121 	if (error = iso_mountfs(rootvp, mp, p, &args)) {
122 		mp->mnt_vfc->vfc_refcount--;
123 		vfs_unbusy(mp, p);
124 		free(mp, M_MOUNT);
125 		return (error);
126 	}
127 	simple_lock(&mountlist_slock);
128 	CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
129 	simple_unlock(&mountlist_slock);
130 	(void)cd9660_statfs(mp, &mp->mnt_stat, p);
131 	vfs_unbusy(mp, p);
132 	return (0);
133 }
134 
135 /*
136  * VFS Operations.
137  *
138  * mount system call
139  */
140 static int
141 cd9660_mount(mp, path, data, ndp, p)
142 	register struct mount *mp;
143 	char *path;
144 	caddr_t data;
145 	struct nameidata *ndp;
146 	struct proc *p;
147 {
148 	struct vnode *devvp;
149 	struct iso_args args;
150 	u_int size;
151 	int error;
152 	struct iso_mnt *imp = 0;
153 
154 	if ((error = copyin(data, (caddr_t)&args, sizeof (struct iso_args))))
155 		return (error);
156 
157 	if ((mp->mnt_flag & MNT_RDONLY) == 0)
158 		return (EROFS);
159 
160 	/*
161 	 * If updating, check whether changing from read-only to
162 	 * read/write; if there is no device name, that's all we do.
163 	 */
164 	if (mp->mnt_flag & MNT_UPDATE) {
165 		imp = VFSTOISOFS(mp);
166 		if (args.fspec == 0)
167 			return (vfs_export(mp, &imp->im_export, &args.export));
168 	}
169 	/*
170 	 * Not an update, or updating the name: look up the name
171 	 * and verify that it refers to a sensible block device.
172 	 */
173 	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
174 	if ((error = namei(ndp)))
175 		return (error);
176 	devvp = ndp->ni_vp;
177 
178 	if (devvp->v_type != VBLK) {
179 		vrele(devvp);
180 		return ENOTBLK;
181 	}
182 	if (major(devvp->v_rdev) >= nblkdev) {
183 		vrele(devvp);
184 		return ENXIO;
185 	}
186 	if ((mp->mnt_flag & MNT_UPDATE) == 0)
187 		error = iso_mountfs(devvp, mp, p, &args);
188 	else {
189 		if (devvp != imp->im_devvp)
190 			error = EINVAL;	/* needs translation */
191 		else
192 			vrele(devvp);
193 	}
194 	if (error) {
195 		vrele(devvp);
196 		return error;
197 	}
198 	imp = VFSTOISOFS(mp);
199 	(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
200 	bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
201 	(void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
202 	    &size);
203 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
204 	(void) cd9660_statfs(mp, &mp->mnt_stat, p);
205 	return 0;
206 }
207 
208 /*
209  * Common code for mount and mountroot
210  */
211 static int
212 iso_mountfs(devvp, mp, p, argp)
213 	register struct vnode *devvp;
214 	struct mount *mp;
215 	struct proc *p;
216 	struct iso_args *argp;
217 {
218 	register struct iso_mnt *isomp = (struct iso_mnt *)0;
219 	struct buf *bp = NULL;
220 	dev_t dev = devvp->v_rdev;
221 	int error = EINVAL;
222 	int needclose = 0;
223 	int high_sierra = 0;
224 	int ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
225 	int iso_bsize;
226 	int iso_blknum;
227 	struct iso_volume_descriptor *vdp;
228 	struct iso_primary_descriptor *pri;
229 	struct iso_sierra_primary_descriptor *pri_sierra;
230 	struct iso_directory_record *rootp;
231 	int logical_block_size;
232 
233 	if (!ronly)
234 		return EROFS;
235 
236 	/*
237 	 * Disallow multiple mounts of the same device.
238 	 * Disallow mounting of a device that is currently in use
239 	 * (except for root, which might share swap device for miniroot).
240 	 * Flush out any old buffers remaining from a previous use.
241 	 */
242 	if ((error = vfs_mountedon(devvp)))
243 		return error;
244 	if (vcount(devvp) > 1 && devvp != rootvp)
245 		return EBUSY;
246 	if ((error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0)))
247 		return (error);
248 
249 	if ((error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p)))
250 		return error;
251 	needclose = 1;
252 
253 	/* This is the "logical sector size".  The standard says this
254 	 * should be 2048 or the physical sector size on the device,
255 	 * whichever is greater.  For now, we'll just use a constant.
256 	 */
257 	iso_bsize = ISO_DEFAULT_BLOCK_SIZE;
258 
259 	for (iso_blknum = 16; iso_blknum < 100; iso_blknum++) {
260 		if (error = bread(devvp, iso_blknum * btodb(iso_bsize),
261 				  iso_bsize, NOCRED, &bp))
262 			goto out;
263 
264 		vdp = (struct iso_volume_descriptor *)bp->b_data;
265 		if (bcmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) != 0) {
266 			if (bcmp (vdp->id_sierra, ISO_SIERRA_ID,
267 				  sizeof vdp->id) != 0) {
268 				error = EINVAL;
269 				goto out;
270 			} else
271 				high_sierra = 1;
272 		}
273 
274 		if (isonum_711 (high_sierra? vdp->type_sierra: vdp->type) == ISO_VD_END) {
275 			error = EINVAL;
276 			goto out;
277 		}
278 
279 		if (isonum_711 (high_sierra? vdp->type_sierra: vdp->type) == ISO_VD_PRIMARY)
280 			break;
281 		brelse(bp);
282 	}
283 
284 	if (isonum_711 (high_sierra? vdp->type_sierra: vdp->type) != ISO_VD_PRIMARY) {
285 		error = EINVAL;
286 		goto out;
287 	}
288 
289 	pri = (struct iso_primary_descriptor *)vdp;
290 	pri_sierra = (struct iso_sierra_primary_descriptor *)vdp;
291 
292 	logical_block_size =
293 		isonum_723 (high_sierra?
294 			    pri_sierra->logical_block_size:
295 			    pri->logical_block_size);
296 
297 	if (logical_block_size < DEV_BSIZE || logical_block_size > MAXBSIZE
298 	    || (logical_block_size & (logical_block_size - 1)) != 0) {
299 		error = EINVAL;
300 		goto out;
301 	}
302 
303 	rootp = (struct iso_directory_record *)
304 		(high_sierra?
305 		 pri_sierra->root_directory_record:
306 		 pri->root_directory_record);
307 
308 	isomp = malloc(sizeof *isomp, M_ISOFSMNT, M_WAITOK);
309 	bzero((caddr_t)isomp, sizeof *isomp);
310 	isomp->logical_block_size = logical_block_size;
311 	isomp->volume_space_size =
312 		isonum_733 (high_sierra?
313 			    pri_sierra->volume_space_size:
314 			    pri->volume_space_size);
315 	bcopy (rootp, isomp->root, sizeof isomp->root);
316 	isomp->root_extent = isonum_733 (rootp->extent);
317 	isomp->root_size = isonum_733 (rootp->size);
318 
319 	isomp->im_bmask = logical_block_size - 1;
320 	isomp->im_bshift = 0;
321 	while ((1 << isomp->im_bshift) < isomp->logical_block_size)
322 		isomp->im_bshift++;
323 
324 	bp->b_flags |= B_AGE;
325 	brelse(bp);
326 	bp = NULL;
327 
328 	mp->mnt_data = (qaddr_t)isomp;
329 	mp->mnt_stat.f_fsid.val[0] = (long)dev;
330 	mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
331 	mp->mnt_maxsymlinklen = 0;
332 	mp->mnt_flag |= MNT_LOCAL;
333 	isomp->im_mountp = mp;
334 	isomp->im_dev = dev;
335 	isomp->im_devvp = devvp;
336 
337 	devvp->v_specflags |= SI_MOUNTEDON;
338 
339 	/* Check the Rock Ridge Extention support */
340 	if (!(argp->flags & ISOFSMNT_NORRIP)) {
341 		if (error = bread(isomp->im_devvp,
342 				  (isomp->root_extent + isonum_711(rootp->ext_attr_length)) <<
343 				  (isomp->im_bshift - DEV_BSHIFT),
344 				  isomp->logical_block_size, NOCRED, &bp))
345 		    goto out;
346 
347 		rootp = (struct iso_directory_record *)bp->b_data;
348 
349 		if ((isomp->rr_skip = cd9660_rrip_offset(rootp,isomp)) < 0) {
350 		    argp->flags	 |= ISOFSMNT_NORRIP;
351 		} else {
352 		    argp->flags	 &= ~ISOFSMNT_GENS;
353 		}
354 
355 		/*
356 		 * The contents are valid,
357 		 * but they will get reread as part of another vnode, so...
358 		 */
359 		bp->b_flags |= B_AGE;
360 		brelse(bp);
361 		bp = NULL;
362 	}
363 	isomp->im_flags = argp->flags&(ISOFSMNT_NORRIP|ISOFSMNT_GENS|ISOFSMNT_EXTATT);
364 
365 	if(high_sierra)
366 		/* this effectively ignores all the mount flags */
367 		isomp->iso_ftype = ISO_FTYPE_HIGH_SIERRA;
368 	else
369 		switch (isomp->im_flags&(ISOFSMNT_NORRIP|ISOFSMNT_GENS)) {
370 		  default:
371 			  isomp->iso_ftype = ISO_FTYPE_DEFAULT;
372 			  break;
373 		  case ISOFSMNT_GENS|ISOFSMNT_NORRIP:
374 			  isomp->iso_ftype = ISO_FTYPE_9660;
375 			  break;
376 		  case 0:
377 			  isomp->iso_ftype = ISO_FTYPE_RRIP;
378 			  break;
379 		}
380 
381 	return 0;
382 out:
383 	if (bp)
384 		brelse(bp);
385 	if (needclose)
386 		(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
387 	if (isomp) {
388 		free((caddr_t)isomp, M_ISOFSMNT);
389 		mp->mnt_data = (qaddr_t)0;
390 	}
391 	return error;
392 }
393 
394 /*
395  * Make a filesystem operational.
396  * Nothing to do at the moment.
397  */
398 /* ARGSUSED */
399 static int
400 cd9660_start(mp, flags, p)
401 	struct mount *mp;
402 	int flags;
403 	struct proc *p;
404 {
405 	return 0;
406 }
407 
408 /*
409  * unmount system call
410  */
411 static int
412 cd9660_unmount(mp, mntflags, p)
413 	struct mount *mp;
414 	int mntflags;
415 	struct proc *p;
416 {
417 	register struct iso_mnt *isomp;
418 	int error, flags = 0;
419 
420 	if (mntflags & MNT_FORCE)
421 		flags |= FORCECLOSE;
422 #if 0
423 	mntflushbuf(mp, 0);
424 	if (mntinvalbuf(mp))
425 		return EBUSY;
426 #endif
427 	if ((error = vflush(mp, NULLVP, flags)))
428 		return (error);
429 
430 	isomp = VFSTOISOFS(mp);
431 
432 #ifdef	ISODEVMAP
433 	if (isomp->iso_ftype == ISO_FTYPE_RRIP)
434 		iso_dunmap(isomp->im_dev);
435 #endif
436 
437 	isomp->im_devvp->v_specflags &= ~SI_MOUNTEDON;
438 	error = VOP_CLOSE(isomp->im_devvp, FREAD, NOCRED, p);
439 	vrele(isomp->im_devvp);
440 	free((caddr_t)isomp, M_ISOFSMNT);
441 	mp->mnt_data = (qaddr_t)0;
442 	mp->mnt_flag &= ~MNT_LOCAL;
443 	return (error);
444 }
445 
446 /*
447  * Return root of a filesystem
448  */
449 static int
450 cd9660_root(mp, vpp)
451 	struct mount *mp;
452 	struct vnode **vpp;
453 {
454 	struct iso_mnt *imp = VFSTOISOFS(mp);
455 	struct iso_directory_record *dp =
456 	    (struct iso_directory_record *)imp->root;
457 	ino_t ino = isodirino(dp, imp);
458 
459 	/*
460 	 * With RRIP we must use the `.' entry of the root directory.
461 	 * Simply tell vget, that it's a relocated directory.
462 	 */
463 	return (cd9660_vget_internal(mp, ino, vpp,
464 	    imp->iso_ftype == ISO_FTYPE_RRIP, dp));
465 }
466 
467 /*
468  * Do operations associated with quotas, not supported
469  */
470 /* ARGSUSED */
471 static int
472 cd9660_quotactl(mp, cmd, uid, arg, p)
473 	struct mount *mp;
474 	int cmd;
475 	uid_t uid;
476 	caddr_t arg;
477 	struct proc *p;
478 {
479 
480 	return (EOPNOTSUPP);
481 }
482 
483 /*
484  * Get file system statistics.
485  */
486 int
487 cd9660_statfs(mp, sbp, p)
488 	struct mount *mp;
489 	register struct statfs *sbp;
490 	struct proc *p;
491 {
492 	register struct iso_mnt *isomp;
493 
494 	isomp = VFSTOISOFS(mp);
495 
496 	sbp->f_type = MOUNT_CD9660;
497 	sbp->f_bsize = isomp->logical_block_size;
498 	sbp->f_iosize = sbp->f_bsize;	/* XXX */
499 	sbp->f_blocks = isomp->volume_space_size;
500 	sbp->f_bfree = 0; /* total free blocks */
501 	sbp->f_bavail = 0; /* blocks free for non superuser */
502 	sbp->f_files =	0; /* total files */
503 	sbp->f_ffree = 0; /* free file nodes */
504 	if (sbp != &mp->mnt_stat) {
505 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
506 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
507 	}
508 	/* Use the first spare for flags: */
509 	sbp->f_spare[0] = isomp->im_flags;
510 	return 0;
511 }
512 
513 /* ARGSUSED */
514 static int
515 cd9660_sync(mp, waitfor, cred, p)
516 	struct mount *mp;
517 	int waitfor;
518 	struct ucred *cred;
519 	struct proc *p;
520 {
521 	return (0);
522 }
523 
524 /*
525  * File handle to vnode
526  *
527  * Have to be really careful about stale file handles:
528  * - check that the inode number is in range
529  * - call iget() to get the locked inode
530  * - check for an unallocated inode (i_mode == 0)
531  * - check that the generation number matches
532  */
533 
534 struct ifid {
535 	ushort	ifid_len;
536 	ushort	ifid_pad;
537 	int	ifid_ino;
538 	long	ifid_start;
539 };
540 
541 /* ARGSUSED */
542 int
543 cd9660_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
544 	register struct mount *mp;
545 	struct fid *fhp;
546 	struct mbuf *nam;
547 	struct vnode **vpp;
548 	int *exflagsp;
549 	struct ucred **credanonp;
550 {
551 	struct ifid *ifhp = (struct ifid *)fhp;
552 	register struct iso_node *ip;
553 	register struct netcred *np;
554 	register struct iso_mnt *imp = VFSTOISOFS(mp);
555 	struct vnode *nvp;
556 	int error;
557 
558 #ifdef	ISOFS_DBG
559 	printf("fhtovp: ino %d, start %ld\n",
560 	       ifhp->ifid_ino, ifhp->ifid_start);
561 #endif
562 
563 	/*
564 	 * Get the export permission structure for this <mp, client> tuple.
565 	 */
566 	np = vfs_export_lookup(mp, &imp->im_export, nam);
567 	if (np == NULL)
568 		return (EACCES);
569 
570 	if (error = VFS_VGET(mp, ifhp->ifid_ino, &nvp)) {
571 		*vpp = NULLVP;
572 		return (error);
573 	}
574 	ip = VTOI(nvp);
575 	if (ip->inode.iso_mode == 0) {
576 		vput(nvp);
577 		*vpp = NULLVP;
578 		return (ESTALE);
579 	}
580 	*vpp = nvp;
581 	*exflagsp = np->netc_exflags;
582 	*credanonp = &np->netc_anon;
583 	return (0);
584 }
585 
586 int
587 cd9660_vget(mp, ino, vpp)
588 	struct mount *mp;
589 	ino_t ino;
590 	struct vnode **vpp;
591 {
592 
593 	/*
594 	 * XXXX
595 	 * It would be nice if we didn't always set the `relocated' flag
596 	 * and force the extra read, but I don't want to think about fixing
597 	 * that right now.
598 	 */
599 	return (cd9660_vget_internal(mp, ino, vpp,
600 #if 0
601 	    VFSTOISOFS(mp)->iso_ftype == ISO_FTYPE_RRIP,
602 #else
603 	    0,
604 #endif
605 	    (struct iso_directory_record *)0));
606 }
607 
608 int
609 cd9660_vget_internal(mp, ino, vpp, relocated, isodir)
610 	struct mount *mp;
611 	ino_t ino;
612 	struct vnode **vpp;
613 	int relocated;
614 	struct iso_directory_record *isodir;
615 {
616 	struct iso_mnt *imp;
617 	struct iso_node *ip;
618 	struct buf *bp;
619 	struct vnode *vp, *nvp;
620 	dev_t dev;
621 	int error;
622 
623 	imp = VFSTOISOFS(mp);
624 	dev = imp->im_dev;
625 	if ((*vpp = cd9660_ihashget(dev, ino)) != NULLVP)
626 		return (0);
627 
628 	/* Allocate a new vnode/iso_node. */
629 	if (error = getnewvnode(VT_ISOFS, mp, cd9660_vnodeop_p, &vp)) {
630 		*vpp = NULLVP;
631 		return (error);
632 	}
633 	MALLOC(ip, struct iso_node *, sizeof(struct iso_node), M_ISOFSNODE,
634 	    M_WAITOK);
635 	bzero((caddr_t)ip, sizeof(struct iso_node));
636 	lockinit(&ip->i_lock, PINOD, "isonode", 0, 0);
637 	vp->v_data = ip;
638 	ip->i_vnode = vp;
639 	ip->i_dev = dev;
640 	ip->i_number = ino;
641 
642 	/*
643 	 * Put it onto its hash chain and lock it so that other requests for
644 	 * this inode will block if they arrive while we are sleeping waiting
645 	 * for old data structures to be purged or for the contents of the
646 	 * disk portion of this inode to be read.
647 	 */
648 	cd9660_ihashins(ip);
649 
650 	if (isodir == 0) {
651 		int lbn, off;
652 
653 		lbn = lblkno(imp, ino);
654 		if (lbn >= imp->volume_space_size) {
655 			vput(vp);
656 			printf("fhtovp: lbn exceed volume space %d\n", lbn);
657 			return (ESTALE);
658 		}
659 
660 		off = blkoff(imp, ino);
661 		if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) {
662 			vput(vp);
663 			printf("fhtovp: crosses block boundary %d\n",
664 			       off + ISO_DIRECTORY_RECORD_SIZE);
665 			return (ESTALE);
666 		}
667 
668 		error = bread(imp->im_devvp,
669 			      lbn << (imp->im_bshift - DEV_BSHIFT),
670 			      imp->logical_block_size, NOCRED, &bp);
671 		if (error) {
672 			vput(vp);
673 			brelse(bp);
674 			printf("fhtovp: bread error %d\n",error);
675 			return (error);
676 		}
677 		isodir = (struct iso_directory_record *)(bp->b_data + off);
678 
679 		if (off + isonum_711(isodir->length) >
680 		    imp->logical_block_size) {
681 			vput(vp);
682 			if (bp != 0)
683 				brelse(bp);
684 			printf("fhtovp: directory crosses block boundary %d[off=%d/len=%d]\n",
685 			       off +isonum_711(isodir->length), off,
686 			       isonum_711(isodir->length));
687 			return (ESTALE);
688 		}
689 
690 #if 0
691 		if (isonum_733(isodir->extent) +
692 		    isonum_711(isodir->ext_attr_length) != ifhp->ifid_start) {
693 			if (bp != 0)
694 				brelse(bp);
695 			printf("fhtovp: file start miss %d vs %d\n",
696 			       isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length),
697 			       ifhp->ifid_start);
698 			return (ESTALE);
699 		}
700 #endif
701 	} else
702 		bp = 0;
703 
704 	ip->i_mnt = imp;
705 	ip->i_devvp = imp->im_devvp;
706 	VREF(ip->i_devvp);
707 
708 	if (relocated) {
709 		/*
710 		 * On relocated directories we must
711 		 * read the `.' entry out of a dir.
712 		 */
713 		ip->iso_start = ino >> imp->im_bshift;
714 		if (bp != 0)
715 			brelse(bp);
716 		if (error = VOP_BLKATOFF(vp, (off_t)0, NULL, &bp)) {
717 			vput(vp);
718 			return (error);
719 		}
720 		isodir = (struct iso_directory_record *)bp->b_data;
721 	}
722 
723 	ip->iso_extent = isonum_733(isodir->extent);
724 	ip->i_size = isonum_733(isodir->size);
725 	ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent;
726 
727 	/*
728 	 * Setup time stamp, attribute
729 	 */
730 	vp->v_type = VNON;
731 	switch (imp->iso_ftype) {
732 	default:	/* ISO_FTYPE_9660 */
733 	    {
734 		struct buf *bp2;
735 		int off;
736 		if ((imp->im_flags & ISOFSMNT_EXTATT)
737 		    && (off = isonum_711(isodir->ext_attr_length)))
738 			VOP_BLKATOFF(vp, (off_t)-(off << imp->im_bshift), NULL,
739 				     &bp2);
740 		else
741 			bp2 = NULL;
742 		cd9660_defattr(isodir, ip, bp2, ISO_FTYPE_9660);
743 		cd9660_deftstamp(isodir, ip, bp2, ISO_FTYPE_9660);
744 		if (bp2)
745 			brelse(bp2);
746 		break;
747 	    }
748 	case ISO_FTYPE_RRIP:
749 		cd9660_rrip_analyze(isodir, ip, imp);
750 		break;
751 	}
752 
753 	if (bp != 0)
754 		brelse(bp);
755 
756 	/*
757 	 * Initialize the associated vnode
758 	 */
759 	switch (vp->v_type = IFTOVT(ip->inode.iso_mode)) {
760 	case VFIFO:
761 		vp->v_op = cd9660_fifoop_p;
762 		break;
763 	case VCHR:
764 	case VBLK:
765 		/*
766 		 * if device, look at device number table for translation
767 		 */
768 #ifdef	ISODEVMAP
769 		if (dp = iso_dmap(dev, ino, 0))
770 			ip->inode.iso_rdev = dp->d_dev;
771 #endif
772 		vp->v_op = cd9660_specop_p;
773 		if (nvp = checkalias(vp, ip->inode.iso_rdev, mp)) {
774 			/*
775 			 * Discard unneeded vnode, but save its iso_node.
776 			 * Note that the lock is carried over in the iso_node
777 			 * to the replacement vnode.
778 			 */
779 			nvp->v_data = vp->v_data;
780 			vp->v_data = NULL;
781 			vp->v_op = spec_vnodeop_p;
782 			vrele(vp);
783 			vgone(vp);
784 			/*
785 			 * Reinitialize aliased inode.
786 			 */
787 			vp = nvp;
788 			ip->i_vnode = vp;
789 		}
790 		break;
791 	}
792 
793 	if (ip->iso_extent == imp->root_extent)
794 		vp->v_flag |= VROOT;
795 
796 	/*
797 	 * XXX need generation number?
798 	 */
799 
800 	*vpp = vp;
801 	return (0);
802 }
803 
804 /*
805  * Vnode pointer to File handle
806  */
807 /* ARGSUSED */
808 int
809 cd9660_vptofh(vp, fhp)
810 	struct vnode *vp;
811 	struct fid *fhp;
812 {
813 	register struct iso_node *ip = VTOI(vp);
814 	register struct ifid *ifhp;
815 
816 	ifhp = (struct ifid *)fhp;
817 	ifhp->ifid_len = sizeof(struct ifid);
818 
819 	ifhp->ifid_ino = ip->i_number;
820 	ifhp->ifid_start = ip->iso_start;
821 
822 #ifdef	ISOFS_DBG
823 	printf("vptofh: ino %d, start %ld\n",
824 	       ifhp->ifid_ino,ifhp->ifid_start);
825 #endif
826 	return 0;
827 }
828