ffs_vget moves to ffs_vfsops.c; add parameter declarations;
[unix-history] / usr / src / sys / ufs / ffs / ffs_vfsops.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 1989, 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 *
7 * @(#)ffs_vfsops.c 7.70 (Berkeley) %G%
8 */
9
10#include <sys/param.h>
11#include <sys/systm.h>
12#include <sys/namei.h>
13#include <sys/proc.h>
14#include <sys/kernel.h>
15#include <sys/vnode.h>
16#include <sys/specdev.h>
17#include <sys/mount.h>
18#include <sys/buf.h>
19#include <sys/file.h>
20#include <sys/disklabel.h>
21#include <sys/ioctl.h>
22#include <sys/errno.h>
23#include <sys/malloc.h>
24#include "ioctl.h"
25#include "disklabel.h"
26#include "stat.h"
27
28#include <ufs/ufs/quota.h>
29#include <ufs/ufs/ufsmount.h>
30#include <ufs/ufs/inode.h>
31#include <ufs/ufs/ufs_extern.h>
32
33#include <ufs/ffs/fs.h>
34#include <ufs/ffs/ffs_extern.h>
35
36int ffs_sbupdate __P((struct ufsmount *, int));
37
38struct vfsops ufs_vfsops = {
39 ffs_mount,
40 ufs_start,
41 ffs_unmount,
42 ffs_root,
43 ufs_quotactl,
44 ffs_statfs,
45 ffs_sync,
46 ffs_fhtovp,
47 ffs_vptofh,
48 ffs_init,
49};
50
51/*
52 * Called by main() when ufs is going to be mounted as root.
53 *
54 * Name is updated by mount(8) after booting.
55 */
56#define ROOTNAME "root_device"
57
58ffs_mountroot()
59{
60 extern struct vnode *rootvp;
61 register struct fs *fs;
62 register struct mount *mp;
63 struct proc *p = curproc; /* XXX */
64 struct ufsmount *ump;
65 u_int size;
66 int error;
67
68 mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK);
69 bzero((char *)mp, (u_long)sizeof(struct mount));
70 mp->mnt_op = &ufs_vfsops;
71 mp->mnt_flag = MNT_RDONLY;
72 if (error = ffs_mountfs(rootvp, mp, p)) {
73 free(mp, M_MOUNT);
74 return (error);
75 }
76 if (error = vfs_lock(mp)) {
77 (void)ffs_unmount(mp, 0, p);
78 free(mp, M_MOUNT);
79 return (error);
80 }
81 rootfs = mp;
82 mp->mnt_next = mp;
83 mp->mnt_prev = mp;
84 mp->mnt_vnodecovered = NULLVP;
85 ump = VFSTOUFS(mp);
86 fs = ump->um_fs;
87 bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt));
88 fs->fs_fsmnt[0] = '/';
89 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
90 MNAMELEN);
91 (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
92 &size);
93 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
94 (void)ffs_statfs(mp, &mp->mnt_stat, p);
95 vfs_unlock(mp);
96 inittodr(fs->fs_time);
97 return (0);
98}
99
100/*
101 * VFS Operations.
102 *
103 * mount system call
104 */
105int
106ffs_mount(mp, path, data, ndp, p)
107 register struct mount *mp;
108 char *path;
109 caddr_t data;
110 struct nameidata *ndp;
111 struct proc *p;
112{
113 struct vnode *devvp;
114 struct ufs_args args;
115 struct ufsmount *ump;
116 register struct fs *fs;
117 u_int size;
118 int error;
119
120 if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)))
121 return (error);
122 /*
123 * If updating, check whether changing from read-only to
124 * read/write; if there is no device name, that's all we do.
125 */
126 if (mp->mnt_flag & MNT_UPDATE) {
127 ump = VFSTOUFS(mp);
128 fs = ump->um_fs;
129 if (fs->fs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0)
130 fs->fs_ronly = 0;
131 if (args.fspec == 0) {
132 /*
133 * Process export requests.
134 */
135 if (args.exflags & MNT_EXPORTED) {
136 if (error = ufs_hang_addrlist(mp, &args))
137 return (error);
138 mp->mnt_flag |= MNT_EXPORTED;
139 }
140 if (args.exflags & MNT_DELEXPORT) {
141 ufs_free_addrlist(ump);
142 mp->mnt_flag &=
143 ~(MNT_EXPORTED | MNT_DEFEXPORTED);
144 }
145 return (0);
146 }
147 }
148 /*
149 * Not an update, or updating the name: look up the name
150 * and verify that it refers to a sensible block device.
151 */
152 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
153 if (error = namei(ndp))
154 return (error);
155 devvp = ndp->ni_vp;
156
157 if (devvp->v_type != VBLK) {
158 vrele(devvp);
159 return (ENOTBLK);
160 }
161 if (major(devvp->v_rdev) >= nblkdev) {
162 vrele(devvp);
163 return (ENXIO);
164 }
165 if ((mp->mnt_flag & MNT_UPDATE) == 0)
166 error = ffs_mountfs(devvp, mp, p);
167 else {
168 if (devvp != ump->um_devvp)
169 error = EINVAL; /* needs translation */
170 else
171 vrele(devvp);
172 }
173 if (error) {
174 vrele(devvp);
175 return (error);
176 }
177 ump = VFSTOUFS(mp);
178 fs = ump->um_fs;
179 (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
180 bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
181 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
182 MNAMELEN);
183 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
184 &size);
185 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
186 (void)ffs_statfs(mp, &mp->mnt_stat, p);
187 return (0);
188}
189
190/*
191 * Common code for mount and mountroot
192 */
193int
194ffs_mountfs(devvp, mp, p)
195 register struct vnode *devvp;
196 struct mount *mp;
197 struct proc *p;
198{
199 USES_VOP_CLOSE;
200 USES_VOP_IOCTL;
201 USES_VOP_OPEN;
202 register struct ufsmount *ump;
203 struct buf *bp;
204 register struct fs *fs;
205 dev_t dev = devvp->v_rdev;
206 struct partinfo dpart;
207 int havepart = 0, blks;
208 caddr_t base, space;
209 int havepart = 0, blks;
210 int error, i, size;
211 int ronly;
212 extern struct vnode *rootvp;
213
214 if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p))
215 return (error);
216 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
217 size = DEV_BSIZE;
218 else {
219 havepart = 1;
220 size = dpart.disklab->d_secsize;
221 }
222
223 bp = NULL;
224 ump = NULL;
225 if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp))
226 goto out;
227 fs = bp->b_un.b_fs;
228 error = EINVAL; /* XXX needs translation */
229 goto out;
230 }
231 ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
232 bzero((caddr_t)ump, sizeof *ump);
233 ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT,
234 M_WAITOK);
235 bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs,
236 (u_int)fs->fs_sbsize);
237 if (fs->fs_sbsize < SBSIZE)
238 bp->b_flags |= B_INVAL;
239 brelse(bp);
240 bp = NULL;
241 fs = ump->um_fs;
242 fs->fs_ronly = ronly;
243 if (ronly == 0)
244 fs->fs_fmod = 1;
245 if (havepart) {
246 dpart.part->p_fstype = FS_BSDFFS;
247 dpart.part->p_fsize = fs->fs_fsize;
248 dpart.part->p_frag = fs->fs_frag;
249 dpart.part->p_cpg = fs->fs_cpg;
250 }
251#ifdef SECSIZE
252 /*
253 * If we have a disk label, force per-partition
254 * filesystem information to be correct
255 * and set correct current fsbtodb shift.
256 */
257#endif SECSIZE
258 if (havepart) {
259 dpart.part->p_fstype = FS_BSDFFS;
260 dpart.part->p_fsize = fs->fs_fsize;
261 dpart.part->p_frag = fs->fs_frag;
262#ifdef SECSIZE
263#ifdef tahoe
264 /*
265 * Save the original fsbtodb shift to restore on updates.
266 * (Console doesn't understand fsbtodb changes.)
267 */
268 fs->fs_sparecon[0] = fs->fs_fsbtodb;
269#endif
270 i = fs->fs_fsize / size;
271 for (fs->fs_fsbtodb = 0; i > 1; i >>= 1)
272 fs->fs_fsbtodb++;
273#endif SECSIZE
274 fs->fs_dbsize = size;
275 }
276 blks = howmany(fs->fs_cssize, fs->fs_fsize);
277 base = space = malloc((u_long)fs->fs_cssize, M_UFSMNT,
278 M_WAITOK);
279 for (i = 0; i < blks; i += fs->fs_frag) {
280 size = fs->fs_bsize;
281 if (i + fs->fs_frag > blks)
282 size = (blks - i) * fs->fs_fsize;
283#ifdef SECSIZE
284 tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size,
285 fs->fs_dbsize);
286#else SECSIZE
287 error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
288 NOCRED, &bp);
289 if (error) {
290 free(base, M_UFSMNT);
291 goto out;
292 }
293 bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size);
294 fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
295 space += size;
296 brelse(bp);
297 bp = NULL;
298 }
299 mp->mnt_data = (qaddr_t)ump;
300 mp->mnt_stat.f_fsid.val[0] = (long)dev;
301 mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS;
302 mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
303 mp->mnt_flag |= MNT_LOCAL;
304 ump->um_mountp = mp;
305 ump->um_dev = dev;
306 ump->um_devvp = devvp;
307 for (i = 0; i < MAXQUOTAS; i++)
308 ump->um_quotas[i] = NULLVP;
309 devvp->v_specflags |= SI_MOUNTEDON;
310
311 /* Sanity checks for old file systems. XXX */
312 fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect); /* XXX */
313 fs->fs_interleave = MAX(fs->fs_interleave, 1); /* XXX */
314 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */
315 fs->fs_nrpos = 8; /* XXX */
316 if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */
317 quad_t sizepb = fs->fs_bsize; /* XXX */
318 /* XXX */
319 fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */
320 for (i = 0; i < NIADDR; i++) { /* XXX */
321 sizepb *= NINDIR(fs); /* XXX */
322 fs->fs_maxfilesize += sizepb; /* XXX */
323 } /* XXX */
324 fs->fs_qbmask = ~fs->fs_bmask; /* XXX */
325 fs->fs_qfmask = ~fs->fs_fmask; /* XXX */
326 } /* XXX */
327
328 return (0);
329out:
330 if (bp)
331 brelse(bp);
332 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
333 if (ump) {
334 free(ump->um_fs, M_UFSMNT);
335 free(ump, M_UFSMNT);
336 mp->mnt_data = (qaddr_t)0;
337 }
338 return (error);
339}
340
341/*
342 * unmount system call
343 */
344int
345ffs_unmount(mp, mntflags, p)
346 struct mount *mp;
347 int mntflags;
348 struct proc *p;
349{
350 USES_VOP_CLOSE;
351 extern int doforce;
352 register struct ufsmount *ump;
353 register struct fs *fs;
354 int i, error, flags, ronly;
355
356 flags = 0;
357 if (mntflags & MNT_FORCE) {
358 if (!doforce || mp == rootfs)
359 return (EINVAL);
360 flags |= FORCECLOSE;
361 }
362 ump = VFSTOUFS(mp);
363 return (error);
364#ifdef QUOTA
365 if (mp->mnt_flag & MNT_QUOTA) {
366 if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags))
367 return (error);
368 for (i = 0; i < MAXQUOTAS; i++) {
369 if (ump->um_quotas[i] == NULLVP)
370 continue;
371 quotaoff(p, mp, i);
372 }
373 /*
374 * Here we fall through to vflush again to ensure
375 * that we have gotten rid of all the system vnodes.
376 */
377 }
378#endif
379 if (error = vflush(mp, NULLVP, flags))
380 return (error);
381 fs = ump->um_fs;
382 ronly = !fs->fs_ronly;
383 * Get file system statistics.
384 */
385int
386ffs_statfs(mp, sbp, p)
387 struct mount *mp;
388 register struct statfs *sbp;
389 struct proc *p;
390{
391 register struct ufsmount *ump;
392 register struct fs *fs;
393
394 ump = VFSTOUFS(mp);
395 fs = ump->um_fs;
396 if (fs->fs_magic != FS_MAGIC)
397 panic("ffs_statfs");
398 sbp->f_type = MOUNT_UFS;
399 sbp->f_bsize = fs->fs_fsize;
400 sbp->f_iosize = fs->fs_bsize;
401 sbp->f_blocks = fs->fs_dsize;
402 sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
403 fs->fs_cstotal.cs_nffree;
404 sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) -
405 (fs->fs_dsize - sbp->f_bfree);
406 sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO;
407 sbp->f_ffree = fs->fs_cstotal.cs_nifree;
408 if (sbp != &mp->mnt_stat) {
409 bcopy((caddr_t)mp->mnt_stat.f_mntonname,
410 (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
411 bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
412 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
413 }
414 return (0);
415}
416
417/*
418 * Go through the disk queues to initiate sandbagged IO;
419 * go through the inodes to write those that have been modified;
420 * initiate the writing of the super block if it has been modified.
421 *
422 * Note: we are always called with the filesystem marked `MPBUSY'.
423 */
424int
425ffs_sync(mp, waitfor, cred, p)
426 struct mount *mp;
427 int waitfor;
428 struct ucred *cred;
429 struct proc *p;
430{
431 USES_VOP_ISLOCKED;
432 USES_VOP_FSYNC;
433 extern int syncprt;
434 register struct vnode *vp;
435 register struct inode *ip;
436 register struct ufsmount *ump = VFSTOUFS(mp);
437 register struct fs *fs;
438 int error, allerror = 0;
439
440 if (syncprt)
441 ufs_bufstats();
442 fs = ump->um_fs;
443 /*
444 * Write back modified superblock.
445 * Consistency check that the superblock
446 * is still in the buffer cache.
447 */
448 if (fs->fs_fmod != 0) {
449 if (fs->fs_ronly != 0) { /* XXX */
450 printf("fs = %s\n", fs->fs_fsmnt);
451 panic("update: rofs mod");
452 }
453 fs->fs_fmod = 0;
454 fs->fs_time = time.tv_sec;
455 allerror = ffs_sbupdate(ump, waitfor);
456 }
457 /*
458 * Write back each (modified) inode.
459 */
460loop:
461 for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
462 /*
463 * If the vnode that we are about to sync is no longer
464 * associated with this mount point, start over.
465 */
466 if (vp->v_mount != mp)
467 goto loop;
468 if (VOP_ISLOCKED(vp))
469 continue;
470 ip = VTOI(vp);
471 if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0 &&
472 vp->v_dirtyblkhd == NULL)
473 continue;
474 if (vget(vp))
475 goto loop;
476 if (error = VOP_FSYNC(vp, cred, waitfor, p))
477 allerror = error;
478 vput(vp);
479 }
480 /*
481 * Force stale file system control information to be flushed.
482 */
483 if (error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p))
484 allerror = error;
485#ifdef QUOTA
486 qsync(mp);
487#endif
488 return (allerror);
489}
490
491/*
492 * File handle to vnode
493 *
494 * Have to be really careful about stale file handles:
495 * - check that the inode number is valid
496 * - call ffs_vget() to get the locked inode
497 * - check for an unallocated inode (i_mode == 0)
498 */
499int
500ffs_fhtovp(mp, fhp, vpp)
501 register struct mount *mp;
502 struct fid *fhp;
503 struct vnode **vpp;
504{
505 USES_VOP_VGET;
506 register struct inode *ip;
507 register struct ufid *ufhp;
508 struct fs *fs;
509 struct vnode *nvp;
510 int error;
511
512 ufhp = (struct ufid *)fhp;
513 fs = VFSTOUFS(mp)->um_fs;
514 if (ufhp->ufid_ino < ROOTINO ||
515 ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg)
516 return (EINVAL);
517 if (error = FFS_VGET(mp, ufhp->ufid_ino, &nvp)) {
518 *vpp = NULLVP;
519 return (error);
520 }
521 ip = VTOI(nvp);
522 if (ip->i_mode == 0 || ip->i_gen != ufhp->ufid_gen) {
523 ufs_iput(ip);
524 *vpp = NULLVP;
525 return (EINVAL);
526 }
527 *vpp = nvp;
528 return (0);
529}
530
531/*
532 * Vnode pointer to File handle
533 */
534/* ARGSUSED */
535ffs_vptofh(vp, fhp)
536 struct vnode *vp;
537 struct fid *fhp;
538{
539 register struct inode *ip;
540 register struct ufid *ufhp;
541
542 ip = VTOI(vp);
543 ufhp = (struct ufid *)fhp;
544 ufhp->ufid_len = sizeof(struct ufid);
545 ufhp->ufid_ino = ip->i_number;
546 ufhp->ufid_gen = ip->i_gen;
547 return (0);
548}
549
550/*
551 * Write a superblock and associated information back to disk.
552 */
553int
554ffs_sbupdate(mp, waitfor)
555 struct ufsmount *mp;
556 int waitfor;
557{
558 register struct fs *fs = mp->um_fs;
559 register struct buf *bp;
560 int blks;
561 caddr_t space;
562 int i, size, error = 0;
563
564#ifdef SECSIZE
565 bp = getblk(mp->m_dev, (daddr_t)fsbtodb(fs, SBOFF / fs->fs_fsize),
566 (int)fs->fs_sbsize, fs->fs_dbsize);
567#else SECSIZE
568 bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize);
569#endif SECSIZE
570 bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
571 /* Restore compatibility to old file systems. XXX */
572 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */
573 bp->b_un.b_fs->fs_nrpos = -1; /* XXX */
574#ifdef SECSIZE
575#ifdef tahoe
576 /* restore standard fsbtodb shift */
577 bp->b_un.b_fs->fs_fsbtodb = fs->fs_sparecon[0];
578 bp->b_un.b_fs->fs_sparecon[0] = 0;
579#endif
580#endif SECSIZE
581 if (waitfor == MNT_WAIT)
582 error = bwrite(bp);
583 else
584 bawrite(bp);
585 blks = howmany(fs->fs_cssize, fs->fs_fsize);
586 space = (caddr_t)fs->fs_csp[0];
587 for (i = 0; i < blks; i += fs->fs_frag) {
588 size = fs->fs_bsize;
589 if (i + fs->fs_frag > blks)
590 size = (blks - i) * fs->fs_fsize;
591#ifdef SECSIZE
592 bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size,
593 fs->fs_dbsize);
594#else SECSIZE
595 bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), size);
596#endif SECSIZE
597 bcopy(space, bp->b_un.b_addr, (u_int)size);
598 space += size;
599 if (waitfor == MNT_WAIT)
600 error = bwrite(bp);
601 else
602 bawrite(bp);
603 }
604 return (error);
605}