proc->thread stage 4: rework the VFS and DEVICE subsystems to take thread
[dragonfly.git] / sys / vfs / isofs / cd9660 / cd9660_vfsops.c
CommitLineData
984263bc
MD
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 * $FreeBSD: src/sys/isofs/cd9660/cd9660_vfsops.c,v 1.74.2.7 2002/04/08 09:39:29 bde Exp $
dadab5e9 40 * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_vfsops.c,v 1.4 2003/06/25 03:55:56 dillon Exp $
984263bc
MD
41 */
42
43#include <sys/param.h>
44#include <sys/systm.h>
984263bc 45#include <sys/proc.h>
dadab5e9 46#include <sys/namei.h>
984263bc
MD
47#include <sys/kernel.h>
48#include <sys/vnode.h>
49#include <sys/mount.h>
50#include <sys/buf.h>
51#include <sys/cdio.h>
52#include <sys/conf.h>
53#include <sys/fcntl.h>
54#include <sys/malloc.h>
55#include <sys/stat.h>
56#include <sys/syslog.h>
57
58#include <vm/vm_zone.h>
59
60#include <isofs/cd9660/iso.h>
61#include <isofs/cd9660/iso_rrip.h>
62#include <isofs/cd9660/cd9660_node.h>
63#include <isofs/cd9660/cd9660_mount.h>
64
65MALLOC_DEFINE(M_ISOFSMNT, "ISOFS mount", "ISOFS mount structure");
66MALLOC_DEFINE(M_ISOFSNODE, "ISOFS node", "ISOFS vnode private part");
67
68static int cd9660_mount __P((struct mount *,
dadab5e9
MD
69 char *, caddr_t, struct nameidata *, struct thread *));
70static int cd9660_unmount __P((struct mount *, int, struct thread *));
984263bc 71static int cd9660_root __P((struct mount *, struct vnode **));
dadab5e9 72static int cd9660_statfs __P((struct mount *, struct statfs *, struct thread *));
984263bc
MD
73static int cd9660_vget __P((struct mount *, ino_t, struct vnode **));
74static int cd9660_fhtovp __P((struct mount *, struct fid *, struct vnode **));
75static int cd9660_checkexp __P((struct mount *, struct sockaddr *,
76 int *, struct ucred **));
77static int cd9660_vptofh __P((struct vnode *, struct fid *));
78
79static struct vfsops cd9660_vfsops = {
80 cd9660_mount,
81 vfs_stdstart,
82 cd9660_unmount,
83 cd9660_root,
84 vfs_stdquotactl,
85 cd9660_statfs,
86 vfs_stdsync,
87 cd9660_vget,
88 cd9660_fhtovp,
89 cd9660_checkexp,
90 cd9660_vptofh,
91 cd9660_init,
92 cd9660_uninit,
93 vfs_stdextattrctl,
94};
95VFS_SET(cd9660_vfsops, cd9660, VFCF_READONLY);
96MODULE_VERSION(cd9660, 1);
97
98
99/*
100 * Called by vfs_mountroot when iso is going to be mounted as root.
101 */
102
dadab5e9 103static int iso_get_ssector __P((dev_t dev, struct thread *td));
984263bc 104static int iso_mountfs __P((struct vnode *devvp, struct mount *mp,
dadab5e9 105 struct thread *td, struct iso_args *argp));
984263bc
MD
106
107/*
108 * Try to find the start of the last data track on this CD-ROM. This
109 * is used to mount the last session of a multi-session CD. Bail out
110 * and return 0 if we fail, this is always a safe bet.
111 */
112static int
dadab5e9 113iso_get_ssector(dev_t dev, struct thread *td)
984263bc
MD
114{
115 struct ioc_toc_header h;
116 struct ioc_read_toc_single_entry t;
117 int i;
118 struct cdevsw *bd;
119 d_ioctl_t *ioctlp;
120
121 bd = devsw(dev);
122 ioctlp = bd->d_ioctl;
123 if (ioctlp == NULL)
124 return 0;
125
dadab5e9 126 if (ioctlp(dev, CDIOREADTOCHEADER, (caddr_t)&h, FREAD, td) != 0)
984263bc
MD
127 return 0;
128
129 for (i = h.ending_track; i >= 0; i--) {
130 t.address_format = CD_LBA_FORMAT;
131 t.track = i;
dadab5e9 132 if (ioctlp(dev, CDIOREADTOCENTRY, (caddr_t)&t, FREAD, td) != 0)
984263bc
MD
133 return 0;
134 if ((t.entry.control & 4) != 0)
135 /* found a data track */
136 break;
137 }
138
139 if (i < 0)
140 return 0;
141
142 return ntohl(t.entry.addr.lba);
143}
144
dadab5e9 145static int iso_mountroot __P((struct mount *mp, struct thread *td));
984263bc
MD
146
147static int
dadab5e9 148iso_mountroot(struct mount *mp, struct thread *td)
984263bc
MD
149{
150 struct iso_args args;
151 int error;
152
153 if ((error = bdevvp(rootdev, &rootvp))) {
154 printf("iso_mountroot: can't find rootvp\n");
155 return (error);
156 }
157 args.flags = ISOFSMNT_ROOT;
158
dadab5e9
MD
159 vn_lock(rootvp, LK_EXCLUSIVE | LK_RETRY, td);
160 error = VOP_OPEN(rootvp, FREAD, FSCRED, td);
161 VOP_UNLOCK(rootvp, 0, td);
984263bc
MD
162 if (error)
163 return (error);
164
dadab5e9 165 args.ssector = iso_get_ssector(rootdev, td);
984263bc 166
dadab5e9 167 (void)VOP_CLOSE(rootvp, FREAD, NOCRED, td);
984263bc
MD
168
169 if (bootverbose)
170 printf("iso_mountroot(): using session at block %d\n",
171 args.ssector);
dadab5e9 172 if ((error = iso_mountfs(rootvp, mp, td, &args)) != 0)
984263bc
MD
173 return (error);
174
dadab5e9 175 (void)cd9660_statfs(mp, &mp->mnt_stat, td);
984263bc
MD
176 return (0);
177}
178
179/*
180 * VFS Operations.
181 *
182 * mount system call
183 */
184static int
dadab5e9 185cd9660_mount(mp, path, data, ndp, td)
984263bc
MD
186 register struct mount *mp;
187 char *path;
188 caddr_t data;
189 struct nameidata *ndp;
dadab5e9 190 struct thread *td;
984263bc
MD
191{
192 struct vnode *devvp;
193 struct iso_args args;
194 size_t size;
195 int error;
196 mode_t accessmode;
197 struct iso_mnt *imp = 0;
198
199 if ((mp->mnt_flag & MNT_ROOTFS) != 0) {
dadab5e9 200 return (iso_mountroot(mp, td));
984263bc
MD
201 }
202 if ((error = copyin(data, (caddr_t)&args, sizeof (struct iso_args))))
203 return (error);
204
205 if ((mp->mnt_flag & MNT_RDONLY) == 0)
206 return (EROFS);
207
dadab5e9
MD
208 KKASSERT(td->td_proc);
209
984263bc
MD
210 /*
211 * If updating, check whether changing from read-only to
212 * read/write; if there is no device name, that's all we do.
213 */
214 if (mp->mnt_flag & MNT_UPDATE) {
215 imp = VFSTOISOFS(mp);
216 if (args.fspec == 0)
217 return (vfs_export(mp, &imp->im_export, &args.export));
218 }
219 /*
220 * Not an update, or updating the name: look up the name
221 * and verify that it refers to a sensible block device.
222 */
dadab5e9 223 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, td);
984263bc
MD
224 if ((error = namei(ndp)))
225 return (error);
226 NDFREE(ndp, NDF_ONLY_PNBUF);
227 devvp = ndp->ni_vp;
228
229 if (!vn_isdisk(devvp, &error)) {
230 vrele(devvp);
231 return (error);
232 }
233
234 /*
235 * Verify that user has necessary permissions on the device,
236 * or has superuser abilities
237 */
238 accessmode = VREAD;
dadab5e9
MD
239 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
240 error = VOP_ACCESS(devvp, accessmode, td->td_proc->p_ucred, td);
984263bc 241 if (error)
dadab5e9 242 error = suser(td);
984263bc
MD
243 if (error) {
244 vput(devvp);
245 return (error);
246 }
dadab5e9 247 VOP_UNLOCK(devvp, 0, td);
984263bc
MD
248
249 if ((mp->mnt_flag & MNT_UPDATE) == 0) {
dadab5e9 250 error = iso_mountfs(devvp, mp, td, &args);
984263bc
MD
251 } else {
252 if (devvp != imp->im_devvp)
253 error = EINVAL; /* needs translation */
254 else
255 vrele(devvp);
256 }
257 if (error) {
258 vrele(devvp);
259 return error;
260 }
261 imp = VFSTOISOFS(mp);
262 (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
263 bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
264 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
265 &size);
266 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
dadab5e9 267 (void) cd9660_statfs(mp, &mp->mnt_stat, td);
984263bc
MD
268 return 0;
269}
270
271/*
272 * Common code for mount and mountroot
273 */
274static int
dadab5e9
MD
275iso_mountfs(
276 struct vnode *devvp,
277 struct mount *mp,
278 struct thread *td,
279 struct iso_args *argp
280) {
984263bc
MD
281 register struct iso_mnt *isomp = (struct iso_mnt *)0;
282 struct buf *bp = NULL;
283 struct buf *pribp = NULL, *supbp = NULL;
284 dev_t dev = devvp->v_rdev;
285 int error = EINVAL;
286 int needclose = 0;
287 int high_sierra = 0;
288 int iso_bsize;
289 int iso_blknum;
290 int joliet_level;
291 struct iso_volume_descriptor *vdp = 0;
292 struct iso_primary_descriptor *pri = NULL;
293 struct iso_sierra_primary_descriptor *pri_sierra = NULL;
294 struct iso_supplementary_descriptor *sup = NULL;
295 struct iso_directory_record *rootp;
296 int logical_block_size;
297
298 if (!(mp->mnt_flag & MNT_RDONLY))
299 return EROFS;
300
dadab5e9 301 KKASSERT(td->td_proc);
984263bc
MD
302 /*
303 * Disallow multiple mounts of the same device.
304 * Disallow mounting of a device that is currently in use
305 * (except for root, which might share swap device for miniroot).
306 * Flush out any old buffers remaining from a previous use.
307 */
308 if ((error = vfs_mountedon(devvp)))
309 return error;
310 if (vcount(devvp) > 1 && devvp != rootvp)
311 return EBUSY;
dadab5e9 312 if ((error = vinvalbuf(devvp, V_SAVE, td->td_proc->p_ucred, td, 0, 0)))
984263bc
MD
313 return (error);
314
dadab5e9
MD
315 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
316 error = VOP_OPEN(devvp, FREAD, FSCRED, td);
317 VOP_UNLOCK(devvp, 0, td);
984263bc
MD
318 if (error)
319 return error;
320 if (devvp->v_rdev->si_iosize_max != 0)
321 mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max;
322 if (mp->mnt_iosize_max > MAXPHYS)
323 mp->mnt_iosize_max = MAXPHYS;
324
325 needclose = 1;
326
327 /* This is the "logical sector size". The standard says this
328 * should be 2048 or the physical sector size on the device,
329 * whichever is greater. For now, we'll just use a constant.
330 */
331 iso_bsize = ISO_DEFAULT_BLOCK_SIZE;
332
333 joliet_level = 0;
334 for (iso_blknum = 16 + argp->ssector;
335 iso_blknum < 100 + argp->ssector;
336 iso_blknum++) {
337 if ((error = bread(devvp, iso_blknum * btodb(iso_bsize),
338 iso_bsize, NOCRED, &bp)) != 0)
339 goto out;
340
341 vdp = (struct iso_volume_descriptor *)bp->b_data;
342 if (bcmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) != 0) {
343 if (bcmp (vdp->id_sierra, ISO_SIERRA_ID,
344 sizeof vdp->id) != 0) {
345 error = EINVAL;
346 goto out;
347 } else
348 high_sierra = 1;
349 }
350 switch (isonum_711 (high_sierra? vdp->type_sierra: vdp->type)){
351 case ISO_VD_PRIMARY:
352 if (pribp == NULL) {
353 pribp = bp;
354 bp = NULL;
355 pri = (struct iso_primary_descriptor *)vdp;
356 pri_sierra =
357 (struct iso_sierra_primary_descriptor *)vdp;
358 }
359 break;
360
361 case ISO_VD_SUPPLEMENTARY:
362 if (supbp == NULL) {
363 supbp = bp;
364 bp = NULL;
365 sup = (struct iso_supplementary_descriptor *)vdp;
366
367 if (!(argp->flags & ISOFSMNT_NOJOLIET)) {
368 if (bcmp(sup->escape, "%/@", 3) == 0)
369 joliet_level = 1;
370 if (bcmp(sup->escape, "%/C", 3) == 0)
371 joliet_level = 2;
372 if (bcmp(sup->escape, "%/E", 3) == 0)
373 joliet_level = 3;
374
375 if ((isonum_711 (sup->flags) & 1) &&
376 (argp->flags & ISOFSMNT_BROKENJOLIET) == 0)
377 joliet_level = 0;
378 }
379 }
380 break;
381
382 case ISO_VD_END:
383 goto vd_end;
384
385 default:
386 break;
387 }
388 if (bp) {
389 brelse(bp);
390 bp = NULL;
391 }
392 }
393 vd_end:
394 if (bp) {
395 brelse(bp);
396 bp = NULL;
397 }
398
399 if (pri == NULL) {
400 error = EINVAL;
401 goto out;
402 }
403
404 logical_block_size =
405 isonum_723 (high_sierra?
406 pri_sierra->logical_block_size:
407 pri->logical_block_size);
408
409 if (logical_block_size < DEV_BSIZE || logical_block_size > MAXBSIZE
410 || (logical_block_size & (logical_block_size - 1)) != 0) {
411 error = EINVAL;
412 goto out;
413 }
414
415 rootp = (struct iso_directory_record *)
416 (high_sierra?
417 pri_sierra->root_directory_record:
418 pri->root_directory_record);
419
420 isomp = malloc(sizeof *isomp, M_ISOFSMNT, M_WAITOK);
421 bzero((caddr_t)isomp, sizeof *isomp);
422 isomp->logical_block_size = logical_block_size;
423 isomp->volume_space_size =
424 isonum_733 (high_sierra?
425 pri_sierra->volume_space_size:
426 pri->volume_space_size);
427 isomp->joliet_level = 0;
428 /*
429 * Since an ISO9660 multi-session CD can also access previous
430 * sessions, we have to include them into the space consider-
431 * ations. This doesn't yield a very accurate number since
432 * parts of the old sessions might be inaccessible now, but we
433 * can't do much better. This is also important for the NFS
434 * filehandle validation.
435 */
436 isomp->volume_space_size += argp->ssector;
437 bcopy (rootp, isomp->root, sizeof isomp->root);
438 isomp->root_extent = isonum_733 (rootp->extent);
439 isomp->root_size = isonum_733 (rootp->size);
440
441 isomp->im_bmask = logical_block_size - 1;
442 isomp->im_bshift = ffs(logical_block_size) - 1;
443
444 pribp->b_flags |= B_AGE;
445 brelse(pribp);
446 pribp = NULL;
447
448 mp->mnt_data = (qaddr_t)isomp;
449 mp->mnt_stat.f_fsid.val[0] = dev2udev(dev);
450 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
451 mp->mnt_maxsymlinklen = 0;
452 mp->mnt_flag |= MNT_LOCAL;
453 isomp->im_mountp = mp;
454 isomp->im_dev = dev;
455 isomp->im_devvp = devvp;
456
457 devvp->v_specmountpoint = mp;
458
459 /* Check the Rock Ridge Extention support */
460 if (!(argp->flags & ISOFSMNT_NORRIP)) {
461 if ((error = bread(isomp->im_devvp,
462 (isomp->root_extent + isonum_711(rootp->ext_attr_length)) <<
463 (isomp->im_bshift - DEV_BSHIFT),
464 isomp->logical_block_size, NOCRED, &bp)) != 0)
465 goto out;
466
467 rootp = (struct iso_directory_record *)bp->b_data;
468
469 if ((isomp->rr_skip = cd9660_rrip_offset(rootp,isomp)) < 0) {
470 argp->flags |= ISOFSMNT_NORRIP;
471 } else {
472 argp->flags &= ~ISOFSMNT_GENS;
473 }
474
475 /*
476 * The contents are valid,
477 * but they will get reread as part of another vnode, so...
478 */
479 bp->b_flags |= B_AGE;
480 brelse(bp);
481 bp = NULL;
482 }
483 isomp->im_flags = argp->flags & (ISOFSMNT_NORRIP | ISOFSMNT_GENS |
484 ISOFSMNT_EXTATT | ISOFSMNT_NOJOLIET);
485
486 if (high_sierra) {
487 /* this effectively ignores all the mount flags */
488 log(LOG_INFO, "cd9660: High Sierra Format\n");
489 isomp->iso_ftype = ISO_FTYPE_HIGH_SIERRA;
490 } else
491 switch (isomp->im_flags&(ISOFSMNT_NORRIP|ISOFSMNT_GENS)) {
492 default:
493 isomp->iso_ftype = ISO_FTYPE_DEFAULT;
494 break;
495 case ISOFSMNT_GENS|ISOFSMNT_NORRIP:
496 isomp->iso_ftype = ISO_FTYPE_9660;
497 break;
498 case 0:
499 log(LOG_INFO, "cd9660: RockRidge Extension\n");
500 isomp->iso_ftype = ISO_FTYPE_RRIP;
501 break;
502 }
503
504 /* Decide whether to use the Joliet descriptor */
505
506 if (isomp->iso_ftype != ISO_FTYPE_RRIP && joliet_level) {
507 log(LOG_INFO, "cd9660: Joliet Extension (Level %d)\n", joliet_level);
508 rootp = (struct iso_directory_record *)
509 sup->root_directory_record;
510 bcopy (rootp, isomp->root, sizeof isomp->root);
511 isomp->root_extent = isonum_733 (rootp->extent);
512 isomp->root_size = isonum_733 (rootp->size);
513 isomp->joliet_level = joliet_level;
514 supbp->b_flags |= B_AGE;
515 }
516
517 if (supbp) {
518 brelse(supbp);
519 supbp = NULL;
520 }
521
522 return 0;
523out:
524 devvp->v_specmountpoint = NULL;
525 if (bp)
526 brelse(bp);
527 if (pribp)
528 brelse(pribp);
529 if (supbp)
530 brelse(supbp);
531 if (needclose)
dadab5e9 532 (void)VOP_CLOSE(devvp, FREAD, NOCRED, td);
984263bc
MD
533 if (isomp) {
534 free((caddr_t)isomp, M_ISOFSMNT);
535 mp->mnt_data = (qaddr_t)0;
536 }
537 return error;
538}
539
540/*
541 * unmount system call
542 */
543static int
dadab5e9 544cd9660_unmount(struct mount *mp, int mntflags, struct thread *td)
984263bc
MD
545{
546 register struct iso_mnt *isomp;
547 int error, flags = 0;
548
549 if (mntflags & MNT_FORCE)
550 flags |= FORCECLOSE;
551#if 0
552 mntflushbuf(mp, 0);
553 if (mntinvalbuf(mp))
554 return EBUSY;
555#endif
556 if ((error = vflush(mp, 0, flags)))
557 return (error);
558
559 isomp = VFSTOISOFS(mp);
560
561 isomp->im_devvp->v_specmountpoint = NULL;
dadab5e9 562 error = VOP_CLOSE(isomp->im_devvp, FREAD, NOCRED, td);
984263bc
MD
563 vrele(isomp->im_devvp);
564 free((caddr_t)isomp, M_ISOFSMNT);
565 mp->mnt_data = (qaddr_t)0;
566 mp->mnt_flag &= ~MNT_LOCAL;
567 return (error);
568}
569
570/*
571 * Return root of a filesystem
572 */
573static int
574cd9660_root(mp, vpp)
575 struct mount *mp;
576 struct vnode **vpp;
577{
578 struct iso_mnt *imp = VFSTOISOFS(mp);
579 struct iso_directory_record *dp =
580 (struct iso_directory_record *)imp->root;
581 ino_t ino = isodirino(dp, imp);
582
583 /*
584 * With RRIP we must use the `.' entry of the root directory.
585 * Simply tell vget, that it's a relocated directory.
586 */
587 return (cd9660_vget_internal(mp, ino, vpp,
588 imp->iso_ftype == ISO_FTYPE_RRIP, dp));
589}
590
591/*
592 * Get file system statistics.
593 */
594int
dadab5e9 595cd9660_statfs(struct mount *mp, register struct statfs *sbp, struct thread *td)
984263bc 596{
dadab5e9 597 struct iso_mnt *isomp;
984263bc
MD
598
599 isomp = VFSTOISOFS(mp);
600
601 sbp->f_bsize = isomp->logical_block_size;
602 sbp->f_iosize = sbp->f_bsize; /* XXX */
603 sbp->f_blocks = isomp->volume_space_size;
604 sbp->f_bfree = 0; /* total free blocks */
605 sbp->f_bavail = 0; /* blocks free for non superuser */
606 sbp->f_files = 0; /* total files */
607 sbp->f_ffree = 0; /* free file nodes */
608 if (sbp != &mp->mnt_stat) {
609 sbp->f_type = mp->mnt_vfc->vfc_typenum;
610 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
611 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
612 }
613 return 0;
614}
615
616/*
617 * File handle to vnode
618 *
619 * Have to be really careful about stale file handles:
620 * - check that the inode number is in range
621 * - call iget() to get the locked inode
622 * - check for an unallocated inode (i_mode == 0)
623 * - check that the generation number matches
624 */
625
626struct ifid {
627 ushort ifid_len;
628 ushort ifid_pad;
629 int ifid_ino;
630 long ifid_start;
631};
632
633/* ARGSUSED */
634int
635cd9660_fhtovp(mp, fhp, vpp)
636 register struct mount *mp;
637 struct fid *fhp;
638 struct vnode **vpp;
639{
640 struct ifid *ifhp = (struct ifid *)fhp;
641 register struct iso_node *ip;
642 struct vnode *nvp;
643 int error;
644
645#ifdef ISOFS_DBG
646 printf("fhtovp: ino %d, start %ld\n",
647 ifhp->ifid_ino, ifhp->ifid_start);
648#endif
649
650 if ((error = VFS_VGET(mp, ifhp->ifid_ino, &nvp)) != 0) {
651 *vpp = NULLVP;
652 return (error);
653 }
654 ip = VTOI(nvp);
655 if (ip->inode.iso_mode == 0) {
656 vput(nvp);
657 *vpp = NULLVP;
658 return (ESTALE);
659 }
660 *vpp = nvp;
661 return (0);
662}
663
664int
665cd9660_checkexp(mp, nam, exflagsp, credanonp)
666 struct mount *mp;
667 struct sockaddr *nam;
668 int *exflagsp;
669 struct ucred **credanonp;
670{
671 register struct netcred *np;
672 register struct iso_mnt *imp;
673
674 imp = VFSTOISOFS(mp);
675
676 /*
677 * Get the export permission structure for this <mp, client> tuple.
678 */
679 np = vfs_export_lookup(mp, &imp->im_export, nam);
680 if (np == NULL)
681 return (EACCES);
682
683 *exflagsp = np->netc_exflags;
684 *credanonp = &np->netc_anon;
685 return (0);
686}
687
688int
689cd9660_vget(mp, ino, vpp)
690 struct mount *mp;
691 ino_t ino;
692 struct vnode **vpp;
693{
694
695 /*
696 * XXXX
697 * It would be nice if we didn't always set the `relocated' flag
698 * and force the extra read, but I don't want to think about fixing
699 * that right now.
700 */
701 return (cd9660_vget_internal(mp, ino, vpp,
702#if 0
703 VFSTOISOFS(mp)->iso_ftype == ISO_FTYPE_RRIP,
704#else
705 0,
706#endif
707 (struct iso_directory_record *)0));
708}
709
710int
711cd9660_vget_internal(mp, ino, vpp, relocated, isodir)
712 struct mount *mp;
713 ino_t ino;
714 struct vnode **vpp;
715 int relocated;
716 struct iso_directory_record *isodir;
717{
718 struct iso_mnt *imp;
719 struct iso_node *ip;
720 struct buf *bp;
721 struct vnode *vp;
722 dev_t dev;
723 int error;
724
725 imp = VFSTOISOFS(mp);
726 dev = imp->im_dev;
727 if ((*vpp = cd9660_ihashget(dev, ino)) != NULLVP)
728 return (0);
729
730 /* Allocate a new vnode/iso_node. */
731 if ((error = getnewvnode(VT_ISOFS, mp, cd9660_vnodeop_p, &vp)) != 0) {
732 *vpp = NULLVP;
733 return (error);
734 }
735 MALLOC(ip, struct iso_node *, sizeof(struct iso_node), M_ISOFSNODE,
736 M_WAITOK);
737 bzero((caddr_t)ip, sizeof(struct iso_node));
738 lockinit(&ip->i_lock, PINOD, "isonode", 0, 0);
739 vp->v_data = ip;
740 ip->i_vnode = vp;
741 ip->i_dev = dev;
742 ip->i_number = ino;
743
744 /*
745 * Put it onto its hash chain and lock it so that other requests for
746 * this inode will block if they arrive while we are sleeping waiting
747 * for old data structures to be purged or for the contents of the
748 * disk portion of this inode to be read.
749 */
750 cd9660_ihashins(ip);
751
752 if (isodir == 0) {
753 int lbn, off;
754
755 lbn = lblkno(imp, ino);
756 if (lbn >= imp->volume_space_size) {
757 vput(vp);
758 printf("fhtovp: lbn exceed volume space %d\n", lbn);
759 return (ESTALE);
760 }
761
762 off = blkoff(imp, ino);
763 if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) {
764 vput(vp);
765 printf("fhtovp: crosses block boundary %d\n",
766 off + ISO_DIRECTORY_RECORD_SIZE);
767 return (ESTALE);
768 }
769
770 error = bread(imp->im_devvp,
771 lbn << (imp->im_bshift - DEV_BSHIFT),
772 imp->logical_block_size, NOCRED, &bp);
773 if (error) {
774 vput(vp);
775 brelse(bp);
776 printf("fhtovp: bread error %d\n",error);
777 return (error);
778 }
779 isodir = (struct iso_directory_record *)(bp->b_data + off);
780
781 if (off + isonum_711(isodir->length) >
782 imp->logical_block_size) {
783 vput(vp);
784 if (bp != 0)
785 brelse(bp);
786 printf("fhtovp: directory crosses block boundary %d[off=%d/len=%d]\n",
787 off +isonum_711(isodir->length), off,
788 isonum_711(isodir->length));
789 return (ESTALE);
790 }
791
792#if 0
793 if (isonum_733(isodir->extent) +
794 isonum_711(isodir->ext_attr_length) != ifhp->ifid_start) {
795 if (bp != 0)
796 brelse(bp);
797 printf("fhtovp: file start miss %d vs %d\n",
798 isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length),
799 ifhp->ifid_start);
800 return (ESTALE);
801 }
802#endif
803 } else
804 bp = 0;
805
806 ip->i_mnt = imp;
807 ip->i_devvp = imp->im_devvp;
808 VREF(ip->i_devvp);
809
810 if (relocated) {
811 /*
812 * On relocated directories we must
813 * read the `.' entry out of a dir.
814 */
815 ip->iso_start = ino >> imp->im_bshift;
816 if (bp != 0)
817 brelse(bp);
818 if ((error = cd9660_blkatoff(vp, (off_t)0, NULL, &bp)) != 0) {
819 vput(vp);
820 return (error);
821 }
822 isodir = (struct iso_directory_record *)bp->b_data;
823 }
824
825 ip->iso_extent = isonum_733(isodir->extent);
826 ip->i_size = isonum_733(isodir->size);
827 ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent;
828
829 /*
830 * Setup time stamp, attribute
831 */
832 vp->v_type = VNON;
833 switch (imp->iso_ftype) {
834 default: /* ISO_FTYPE_9660 */
835 {
836 struct buf *bp2;
837 int off;
838 if ((imp->im_flags & ISOFSMNT_EXTATT)
839 && (off = isonum_711(isodir->ext_attr_length)))
840 cd9660_blkatoff(vp, (off_t)-(off << imp->im_bshift), NULL,
841 &bp2);
842 else
843 bp2 = NULL;
844 cd9660_defattr(isodir, ip, bp2, ISO_FTYPE_9660);
845 cd9660_deftstamp(isodir, ip, bp2, ISO_FTYPE_9660);
846 if (bp2)
847 brelse(bp2);
848 break;
849 }
850 case ISO_FTYPE_RRIP:
851 cd9660_rrip_analyze(isodir, ip, imp);
852 break;
853 }
854
855 if (bp != 0)
856 brelse(bp);
857
858 /*
859 * Initialize the associated vnode
860 */
861 switch (vp->v_type = IFTOVT(ip->inode.iso_mode)) {
862 case VFIFO:
863 vp->v_op = cd9660_fifoop_p;
864 break;
865 case VCHR:
866 case VBLK:
867 vp->v_op = cd9660_specop_p;
868 addaliasu(vp, ip->inode.iso_rdev);
869 break;
870 default:
871 break;
872 }
873
874 if (ip->iso_extent == imp->root_extent)
875 vp->v_flag |= VROOT;
876
877 /*
878 * XXX need generation number?
879 */
880
881 *vpp = vp;
882 return (0);
883}
884
885/*
886 * Vnode pointer to File handle
887 */
888/* ARGSUSED */
889int
890cd9660_vptofh(vp, fhp)
891 struct vnode *vp;
892 struct fid *fhp;
893{
894 register struct iso_node *ip = VTOI(vp);
895 register struct ifid *ifhp;
896
897 ifhp = (struct ifid *)fhp;
898 ifhp->ifid_len = sizeof(struct ifid);
899
900 ifhp->ifid_ino = ip->i_number;
901 ifhp->ifid_start = ip->iso_start;
902
903#ifdef ISOFS_DBG
904 printf("vptofh: ino %d, start %ld\n",
905 ifhp->ifid_ino,ifhp->ifid_start);
906#endif
907 return 0;
908}