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