This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / sys / isofs / isofs_vfsops.c
CommitLineData
15637ed4 1/*
fde1aeb2 2 * $Id: isofs_vfsops.c,v 1.4 1993/11/25 01:32:30 wollman Exp $
15637ed4 3 */
584fddaa 4
15637ed4
RG
5#include "param.h"
6#include "systm.h"
7#include "namei.h"
8#include "proc.h"
9#include "kernel.h"
10#include "vnode.h"
11#include "specdev.h"
12#include "mount.h"
13#include "buf.h"
14#include "file.h"
15#include "dkbad.h"
16#include "disklabel.h"
17#include "ioctl.h"
18#include "errno.h"
19#include "malloc.h"
20
21#include "iso.h"
22#include "isofs_node.h"
23
24extern int enodev ();
25
26struct vfsops isofs_vfsops = {
27 isofs_mount,
28 isofs_start,
29 isofs_unmount,
30 isofs_root,
31 (void *)enodev, /* quotactl */
32 isofs_statfs,
33 isofs_sync,
34 isofs_fhtovp,
35 isofs_vptofh,
36 isofs_init
37};
38
39/*
40 * Called by vfs_mountroot when ufs is going to be mounted as root.
41 *
42 * Name is updated by mount(8) after booting.
43 */
44#define ROOTNAME "root_device"
45
fde1aeb2
GW
46static int iso_mountfs(struct vnode *, struct mount *, struct proc *);
47
4c45483e 48int
15637ed4
RG
49isofs_mountroot()
50{
51 register struct mount *mp;
52 extern struct vnode *rootvp;
53 struct proc *p = curproc; /* XXX */
54 struct iso_mnt *imp;
55 register struct fs *fs;
56 u_int size;
57 int error;
58
59 mp = (struct mount *)malloc((u_long)sizeof(struct mount),
60 M_MOUNT, M_WAITOK);
61 mp->mnt_op = &isofs_vfsops;
62 mp->mnt_flag = MNT_RDONLY;
63 mp->mnt_exroot = 0;
64 mp->mnt_mounth = NULLVP;
65 error = iso_mountfs(rootvp, mp, p);
66 if (error) {
67 free((caddr_t)mp, M_MOUNT);
68 return (error);
69 }
70 if (error = vfs_lock(mp)) {
71 (void)isofs_unmount(mp, 0, p);
72 free((caddr_t)mp, M_MOUNT);
73 return (error);
74 }
75 rootfs = mp;
76 mp->mnt_next = mp;
77 mp->mnt_prev = mp;
78 mp->mnt_vnodecovered = NULLVP;
79 imp = VFSTOISOFS(mp);
80 bzero(imp->im_fsmnt, sizeof(imp->im_fsmnt));
81 imp->im_fsmnt[0] = '/';
82 bcopy((caddr_t)imp->im_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
83 MNAMELEN);
84 (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
85 &size);
86 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
87 (void) isofs_statfs(mp, &mp->mnt_stat, p);
88 vfs_unlock(mp);
89 return (0);
90}
91
92/*
93 * Flag to allow forcible unmounting.
94 */
95int iso_doforce = 1;
96
97/*
98 * VFS Operations.
99 *
100 * mount system call
101 */
4c45483e 102int
15637ed4
RG
103isofs_mount(mp, path, data, ndp, p)
104 register struct mount *mp;
105 char *path;
106 caddr_t data;
107 struct nameidata *ndp;
108 struct proc *p;
109{
110 struct vnode *devvp;
111 struct ufs_args args;
112 u_int size;
113 int error;
4c45483e 114 struct iso_mnt *imp = 0;
15637ed4
RG
115
116 if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)))
117 return (error);
118
119 if ((mp->mnt_flag & MNT_RDONLY) == 0)
120 return (EROFS);
121
122 /*
123 * Process export requests.
124 */
125 if ((args.exflags & MNT_EXPORTED) || (mp->mnt_flag & MNT_EXPORTED)) {
126 if (args.exflags & MNT_EXPORTED)
127 mp->mnt_flag |= MNT_EXPORTED;
128 else
129 mp->mnt_flag &= ~MNT_EXPORTED;
130 if (args.exflags & MNT_EXRDONLY)
131 mp->mnt_flag |= MNT_EXRDONLY;
132 else
133 mp->mnt_flag &= ~MNT_EXRDONLY;
134 mp->mnt_exroot = args.exroot;
135 }
136 /*
137 * If updating, check whether changing from read-only to
138 * read/write; if there is no device name, that's all we do.
139 */
140 if (mp->mnt_flag & MNT_UPDATE) {
141 imp = VFSTOISOFS(mp);
142 if (args.fspec == 0)
143 return (0);
144 }
145 /*
146 * Not an update, or updating the name: look up the name
147 * and verify that it refers to a sensible block device.
148 */
149 ndp->ni_nameiop = LOOKUP | FOLLOW;
150 ndp->ni_segflg = UIO_USERSPACE;
151 ndp->ni_dirp = args.fspec;
152 if (error = namei(ndp, p))
153 return (error);
154 devvp = ndp->ni_vp;
155 if (devvp->v_type != VBLK) {
156 vrele(devvp);
157 return (ENOTBLK);
158 }
159 if (major(devvp->v_rdev) >= nblkdev) {
160 vrele(devvp);
161 return (ENXIO);
162 }
163
164 if ((mp->mnt_flag & MNT_UPDATE) == 0)
165 error = iso_mountfs(devvp, mp, p);
166 else {
167 if (devvp != imp->im_devvp)
168 error = EINVAL; /* needs translation */
169 else
170 vrele(devvp);
171 }
172 if (error) {
173 vrele(devvp);
174 return (error);
175 }
176 imp = VFSTOISOFS(mp);
584fddaa
JH
177
178 /* Check the Rock Ridge Extention support */
9f888be7 179 if ( args.exflags & MNT_NORRIP ) {
584fddaa 180 imp->iso_ftype = ISO_FTYPE_9660;
9f888be7 181 mp->mnt_flag |= MNT_NORRIP;
584fddaa
JH
182 } else {
183 imp->iso_ftype = ISO_FTYPE_RRIP;
9f888be7 184 mp->mnt_flag &= ~MNT_NORRIP;
584fddaa
JH
185 }
186
15637ed4
RG
187 (void) copyinstr(path, imp->im_fsmnt, sizeof(imp->im_fsmnt)-1, &size);
188 bzero(imp->im_fsmnt + size, sizeof(imp->im_fsmnt) - size);
189 bcopy((caddr_t)imp->im_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
190 MNAMELEN);
191 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
192 &size);
193 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
194 (void) isofs_statfs(mp, &mp->mnt_stat, p);
195 return (0);
196}
197
198/*
199 * Common code for mount and mountroot
200 */
fde1aeb2 201static int
15637ed4
RG
202iso_mountfs(devvp, mp, p)
203 register struct vnode *devvp;
204 struct mount *mp;
205 struct proc *p;
206{
207 register struct iso_mnt *isomp = (struct iso_mnt *)0;
208 struct buf *bp = NULL;
209 dev_t dev = devvp->v_rdev;
210 caddr_t base, space;
211 int havepart = 0, blks;
212 int error = EINVAL, i, size;
213 int needclose = 0;
214 int ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
215 extern struct vnode *rootvp;
216 int j;
217 int iso_bsize;
218 int iso_blknum;
219 struct iso_volume_descriptor *vdp;
220 struct iso_primary_descriptor *pri;
221 struct iso_directory_record *rootp;
222 int logical_block_size;
223
224 if (!ronly)
225 return (EROFS);
226
227 /*
228 * Disallow multiple mounts of the same device.
229 * Disallow mounting of a device that is currently in use
230 * (except for root, which might share swap device for miniroot).
231 * Flush out any old buffers remaining from a previous use.
232 */
233 if (error = iso_mountedon(devvp))
234 return (error);
235 if (vcount(devvp) > 1 && devvp != rootvp)
236 return (EBUSY);
237 vinvalbuf(devvp, 1);
238 if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p))
239 return (error);
240 needclose = 1;
241
242 /* This is the "logical sector size". The standard says this
243 * should be 2048 or the physical sector size on the device,
244 * whichever is greater. For now, we'll just use a constant.
245 */
246 iso_bsize = 2048;
247
248 for (iso_blknum = 16; iso_blknum < 100; iso_blknum++) {
249 if (error = bread (devvp, iso_blknum * iso_bsize / DEV_BSIZE,
250 iso_bsize, NOCRED, &bp))
251 goto out;
252
253 vdp = (struct iso_volume_descriptor *)bp->b_un.b_addr;
254 if (bcmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) != 0) {
255 error = EINVAL;
256 goto out;
257 }
258
259 if (isonum_711 (vdp->type) == ISO_VD_END) {
260 error = EINVAL;
261 goto out;
262 }
263
264 if (isonum_711 (vdp->type) == ISO_VD_PRIMARY)
265 break;
266 brelse(bp);
267 }
268
269 if (isonum_711 (vdp->type) != ISO_VD_PRIMARY) {
270 error = EINVAL;
271 goto out;
272 }
273
274 pri = (struct iso_primary_descriptor *)vdp;
275
276 logical_block_size = isonum_723 (pri->logical_block_size);
277
278 if (logical_block_size < DEV_BSIZE
279 || logical_block_size >= MAXBSIZE
280 || (logical_block_size & (logical_block_size - 1)) != 0) {
281 error = EINVAL;
282 goto out;
283 }
284
285 rootp = (struct iso_directory_record *)pri->root_directory_record;
286
584fddaa 287 isomp = (struct iso_mnt *)malloc(sizeof *isomp,M_ISOFSMNT,M_WAITOK);
15637ed4
RG
288 isomp->logical_block_size = logical_block_size;
289 isomp->volume_space_size = isonum_733 (pri->volume_space_size);
290 bcopy (rootp, isomp->root, sizeof isomp->root);
291 isomp->root_extent = isonum_733 (rootp->extent);
292 isomp->root_size = isonum_733 (rootp->size);
293
294 isomp->im_bsize = logical_block_size;
295 isomp->im_bmask = ~(isomp->im_bsize - 1);
296 isomp->im_bshift = 0;
297 while ((1 << isomp->im_bshift) < isomp->im_bsize)
298 isomp->im_bshift++;
299
300 bp->b_flags |= B_INVAL;
301 brelse(bp);
302 bp = NULL;
303
304 isomp->im_ronly = ronly;
305 if (ronly == 0)
306 isomp->im_fmod = 1;
307
308 mp->mnt_data = (qaddr_t)isomp;
309 mp->mnt_stat.f_fsid.val[0] = (long)dev;
310 mp->mnt_stat.f_fsid.val[1] = MOUNT_ISOFS;
311 mp->mnt_flag |= MNT_LOCAL;
312 isomp->im_mountp = mp;
313 isomp->im_dev = dev;
314 isomp->im_devvp = devvp;
315
316 devvp->v_specflags |= SI_MOUNTEDON;
317
318 return (0);
319out:
320 if (bp)
321 brelse(bp);
322 if (needclose)
323 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
324 if (isomp) {
584fddaa 325 free((caddr_t)isomp, M_ISOFSMNT);
15637ed4
RG
326 mp->mnt_data = (qaddr_t)0;
327 }
328 return (error);
329}
330
331/*
332 * Make a filesystem operational.
333 * Nothing to do at the moment.
334 */
335/* ARGSUSED */
4c45483e 336int
15637ed4
RG
337isofs_start(mp, flags, p)
338 struct mount *mp;
339 int flags;
340 struct proc *p;
341{
342
343 return (0);
344}
345
346/*
347 * unmount system call
348 */
4c45483e 349int
15637ed4
RG
350isofs_unmount(mp, mntflags, p)
351 struct mount *mp;
352 int mntflags;
353 struct proc *p;
354{
355 register struct iso_mnt *isomp;
356 int i, error, ronly, flags = 0;
357
358 if (mntflags & MNT_FORCE) {
359 if (!iso_doforce || mp == rootfs)
360 return (EINVAL);
361 flags |= FORCECLOSE;
362 }
363 mntflushbuf(mp, 0);
364 if (mntinvalbuf(mp))
365 return (EBUSY);
366 isomp = VFSTOISOFS(mp);
367
368 if (error = vflush(mp, NULLVP, flags))
369 return (error);
370 ronly = !isomp->im_ronly;
371 isomp->im_devvp->v_specflags &= ~SI_MOUNTEDON;
372 error = VOP_CLOSE(isomp->im_devvp, ronly ? FREAD : FREAD|FWRITE,
373 NOCRED, p);
374 vrele(isomp->im_devvp);
584fddaa 375 free((caddr_t)isomp, M_ISOFSMNT);
15637ed4
RG
376 mp->mnt_data = (qaddr_t)0;
377 mp->mnt_flag &= ~MNT_LOCAL;
378 return (error);
379}
380
381/*
382 * Check to see if a filesystem is mounted on a block device.
383 */
4c45483e 384int
15637ed4
RG
385iso_mountedon(vp)
386 register struct vnode *vp;
387{
388 register struct vnode *vq;
389
390 if (vp->v_specflags & SI_MOUNTEDON)
391 return (EBUSY);
392 if (vp->v_flag & VALIASED) {
393 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
394 if (vq->v_rdev != vp->v_rdev ||
395 vq->v_type != vp->v_type)
396 continue;
397 if (vq->v_specflags & SI_MOUNTEDON)
398 return (EBUSY);
399 }
400 }
401 return (0);
402}
403
404/*
405 * Return root of a filesystem
406 */
4c45483e 407int
15637ed4
RG
408isofs_root(mp, vpp)
409 struct mount *mp;
410 struct vnode **vpp;
411{
412 register struct iso_node *ip;
413 struct iso_node *nip;
414 struct vnode tvp;
415 int error;
416 struct iso_mnt *imp = VFSTOISOFS (mp);
417
418 tvp.v_mount = mp;
419 ip = VTOI(&tvp);
420 ip->i_vnode = &tvp;
421 ip->i_dev = imp->im_dev;
422 ip->i_diroff = 0;
423 ip->iso_extent = imp->root_extent;
15637ed4
RG
424 error = iso_iget(ip, imp->root_extent, &nip,
425 (struct iso_directory_record *) imp->root);
426 if (error)
427 return (error);
428 *vpp = ITOV(nip);
429 return (0);
430}
431
432/*
433 * Get file system statistics.
434 */
4c45483e 435int
15637ed4
RG
436isofs_statfs(mp, sbp, p)
437 struct mount *mp;
438 register struct statfs *sbp;
439 struct proc *p;
440{
441 register struct iso_mnt *isomp;
442 register struct fs *fs;
443
444 isomp = VFSTOISOFS(mp);
445
446 sbp->f_type = MOUNT_ISOFS;
447 sbp->f_fsize = isomp->logical_block_size;
448 sbp->f_bsize = sbp->f_fsize;
449 sbp->f_blocks = isomp->volume_space_size;
450 sbp->f_bfree = 0; /* total free blocks */
451 sbp->f_bavail = 0; /* blocks free for non superuser */
452 sbp->f_files = 0; /* total files */
453 sbp->f_ffree = 0; /* free file nodes */
454 if (sbp != &mp->mnt_stat) {
455 bcopy((caddr_t)mp->mnt_stat.f_mntonname,
456 (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
457 bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
458 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
459 }
460 return (0);
461}
462
4c45483e 463int
15637ed4
RG
464isofs_sync(mp, waitfor)
465 struct mount *mp;
466 int waitfor;
467{
468 return (0);
469}
470
471/*
472 * File handle to vnode
473 *
584fddaa
JH
474 * Have to be really careful about stale file handles:
475 * - check that the inode number is in range
476 * - call iget() to get the locked inode
477 * - check for an unallocated inode (i_mode == 0)
478 * - check that the generation number matches
15637ed4
RG
479 */
480
481
482struct ifid {
483 ushort ifid_len;
484 ushort ifid_pad;
485 int ifid_lbn;
486 int ifid_offset;
487 int ifid_ino;
488};
489
4c45483e 490int
15637ed4
RG
491isofs_fhtovp(mp, fhp, vpp)
492 register struct mount *mp;
493 struct fid *fhp;
494 struct vnode **vpp;
495{
496 /* here's a guess at what we need here */
497 struct vnode tvp;
498 int error;
499 int lbn, off;
500 struct ifid *ifhp;
501 struct iso_mnt *imp;
502 struct buf *bp;
503 struct iso_directory_record *dirp;
504 struct iso_node *ip, *nip;
505 struct proc *p;
506
507 ifhp = (struct ifid *)fhp;
508 imp = VFSTOISOFS (mp);
509
510#ifdef ISOFS_DBG
511 printf("fhtovp: lbn %d, off %d, ino %d\n",
512 ifhp->ifid_lbn, ifhp->ifid_offset, ifhp->ifid_ino);
513#endif
514
515 lbn = ifhp->ifid_lbn;
516 off = ifhp->ifid_offset;
584fddaa
JH
517 ifhp->ifid_lbn += (ifhp->ifid_offset >> 11);
518 ifhp->ifid_offset &= 0x7ff;
15637ed4
RG
519
520 if (ifhp->ifid_lbn >= imp->volume_space_size)
521 return (EINVAL);
522
523 if (ifhp->ifid_offset + sizeof (struct iso_directory_record)
524 >= imp->im_bsize)
525 return (EINVAL);
526
527 if (error = bread (imp->im_devvp,
528 (ifhp->ifid_lbn * imp->im_bsize / DEV_BSIZE), imp->im_bsize,
529 NOCRED, &bp)) {
530 printf("fhtovp: bread error %d\n", error);
531 return(EINVAL);
532 }
533
534 dirp = (struct iso_directory_record *)
535 (bp->b_un.b_addr + ifhp->ifid_offset);
536
537 if (ifhp->ifid_offset + isonum_711 (dirp->length) >= imp->im_bsize) {
538 brelse (bp);
539 return (EINVAL);
540 }
541 if (isonum_733(dirp->extent) != ifhp->ifid_ino) {
542 brelse(bp);
543 return(EINVAL);
544 }
545
546 tvp.v_mount = mp;
547 ip = VTOI(&tvp);
548 ip->i_vnode = &tvp;
549 ip->i_dev = imp->im_dev;
550 ip->i_diroff = off;
551 ip->iso_extent = lbn;
552 if (error = iso_iget(ip, ifhp->ifid_ino, &nip, dirp)) {
553 *vpp = NULLVP;
554 brelse (bp);
555 return (error);
556 }
557 ip = nip;
558 *vpp = ITOV(ip);
559 brelse (bp);
560 return (0);
561}
562
563/*
564 * Vnode pointer to File handle
565 */
566/* ARGSUSED */
4c45483e 567int
15637ed4
RG
568isofs_vptofh(vp, fhp)
569 struct vnode *vp;
570 struct fid *fhp;
571{
572 register struct iso_node *ip = VTOI(vp);
573 register struct ifid *ifhp;
574 register struct iso_mnt *mp = ip->i_mnt;
575
576 ifhp = (struct ifid *)fhp;
577 ifhp->ifid_len = sizeof(struct ifid);
578
579 ifhp->ifid_lbn = ip->iso_parent_ext;
580 ifhp->ifid_offset = ip->iso_parent;
581 ifhp->ifid_ino = ip->i_number;
582
583 if(ip->i_number == mp->root_extent) {
584 ifhp->ifid_lbn = ip->i_number;
585 ifhp->ifid_offset = 0;
586 }
587
588#ifdef ISOFS_DBG
589 printf("vptofh: lbn %d, off %d, ino %d\n",
590 ifhp->ifid_lbn, ifhp->ifid_offset, ifhp->ifid_ino);
591#endif
592 return (0);
593}