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