UFS/FFS split for LFS version 1; inode can no longer directly access
[unix-history] / usr / src / sys / ufs / ffs / ufs_vfsops.c
CommitLineData
da7c5cc6 1/*
190244fb 2 * Copyright (c) 1989, 1991 The Regents of the University of California.
7188ac27 3 * All rights reserved.
da7c5cc6 4 *
b702c21d 5 * %sccs.include.redist.c%
7188ac27 6 *
190244fb 7 * @(#)ufs_vfsops.c 7.56 (Berkeley) %G%
da7c5cc6 8 */
71e4e98b 9
94368568
JB
10#include "param.h"
11#include "systm.h"
c6f5111d 12#include "namei.h"
8dc876c1 13#include "proc.h"
7188ac27 14#include "kernel.h"
7188ac27 15#include "vnode.h"
0f93ba7b 16#include "specdev.h"
94368568 17#include "mount.h"
7188ac27 18#include "buf.h"
94368568 19#include "file.h"
ec67a3ce 20#include "disklabel.h"
7188ac27
KM
21#include "ioctl.h"
22#include "errno.h"
4def0c5e 23#include "malloc.h"
609e7cfa
MK
24#include "ioctl.h"
25#include "disklabel.h"
26#include "stat.h"
71e4e98b 27
c6f5111d
MK
28#include "quota.h"
29#include "fs.h"
30#include "ufsmount.h"
31#include "inode.h"
32
7188ac27
KM
33struct vfsops ufs_vfsops = {
34 ufs_mount,
5bf9d21f 35 ufs_start,
7188ac27
KM
36 ufs_unmount,
37 ufs_root,
8dc876c1 38 ufs_quotactl,
7188ac27
KM
39 ufs_statfs,
40 ufs_sync,
41 ufs_fhtovp,
de0d8667
KM
42 ufs_vptofh,
43 ufs_init
7188ac27
KM
44};
45
d85a9d1b
KM
46/*
47 * Flag to allow forcible unmounting.
48 */
49int doforce = 1;
50
7188ac27 51/*
d48157d5 52 * Called by vfs_mountroot when ufs is going to be mounted as root.
7188ac27 53 *
d48157d5 54 * Name is updated by mount(8) after booting.
7188ac27 55 */
8a4911ca 56#define ROOTNAME "root_device"
7188ac27
KM
57
58ufs_mountroot()
71e4e98b 59{
7188ac27
KM
60 register struct mount *mp;
61 extern struct vnode *rootvp;
0eb6f54a 62 struct proc *p = curproc; /* XXX */
7188ac27 63 struct ufsmount *ump;
71e4e98b 64 register struct fs *fs;
7188ac27
KM
65 u_int size;
66 int error;
71e4e98b 67
7188ac27
KM
68 mp = (struct mount *)malloc((u_long)sizeof(struct mount),
69 M_MOUNT, M_WAITOK);
82161bc8
KM
70 mp->mnt_op = &ufs_vfsops;
71 mp->mnt_flag = MNT_RDONLY;
72 mp->mnt_exroot = 0;
73 mp->mnt_mounth = NULLVP;
0eb6f54a 74 error = mountfs(rootvp, mp, p);
7188ac27
KM
75 if (error) {
76 free((caddr_t)mp, M_MOUNT);
77 return (error);
71e4e98b 78 }
d48157d5 79 if (error = vfs_lock(mp)) {
0eb6f54a 80 (void)ufs_unmount(mp, 0, p);
7188ac27
KM
81 free((caddr_t)mp, M_MOUNT);
82 return (error);
6d07f4cd 83 }
d48157d5 84 rootfs = mp;
82161bc8
KM
85 mp->mnt_next = mp;
86 mp->mnt_prev = mp;
87 mp->mnt_vnodecovered = NULLVP;
7188ac27
KM
88 ump = VFSTOUFS(mp);
89 fs = ump->um_fs;
d45de50d 90 bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt));
7188ac27 91 fs->fs_fsmnt[0] = '/';
82161bc8
KM
92 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
93 MNAMELEN);
94 (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
95 &size);
96 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
0eb6f54a 97 (void) ufs_statfs(mp, &mp->mnt_stat, p);
7188ac27
KM
98 vfs_unlock(mp);
99 inittodr(fs->fs_time);
100 return (0);
101}
102
103/*
104 * VFS Operations.
105 *
106 * mount system call
107 */
0eb6f54a 108ufs_mount(mp, path, data, ndp, p)
d45de50d 109 register struct mount *mp;
7188ac27
KM
110 char *path;
111 caddr_t data;
112 struct nameidata *ndp;
0eb6f54a 113 struct proc *p;
7188ac27
KM
114{
115 struct vnode *devvp;
116 struct ufs_args args;
117 struct ufsmount *ump;
118 register struct fs *fs;
119 u_int size;
120 int error;
121
122 if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)))
123 return (error);
3b931949
KM
124 /*
125 * Process export requests.
126 */
82161bc8
KM
127 if ((args.exflags & MNT_EXPORTED) || (mp->mnt_flag & MNT_EXPORTED)) {
128 if (args.exflags & MNT_EXPORTED)
129 mp->mnt_flag |= MNT_EXPORTED;
3b931949 130 else
82161bc8
KM
131 mp->mnt_flag &= ~MNT_EXPORTED;
132 if (args.exflags & MNT_EXRDONLY)
133 mp->mnt_flag |= MNT_EXRDONLY;
3b931949 134 else
82161bc8
KM
135 mp->mnt_flag &= ~MNT_EXRDONLY;
136 mp->mnt_exroot = args.exroot;
3b931949 137 }
190244fb
MK
138 /*
139 * If updating, check whether changing from read-only to
140 * read/write; if there is no device name, that's all we do.
141 */
142 if (mp->mnt_flag & MNT_UPDATE) {
d48157d5
KM
143 ump = VFSTOUFS(mp);
144 fs = ump->um_fs;
82161bc8 145 if (fs->fs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0)
d48157d5 146 fs->fs_ronly = 0;
3b931949
KM
147 if (args.fspec == 0)
148 return (0);
190244fb
MK
149 }
150 /*
151 * Not an update, or updating the name: look up the name
152 * and verify that it refers to a sensible block device.
153 */
154 ndp->ni_nameiop = LOOKUP | FOLLOW;
155 ndp->ni_segflg = UIO_USERSPACE;
156 ndp->ni_dirp = args.fspec;
157 if (error = namei(ndp, p))
158 return (error);
159 devvp = ndp->ni_vp;
160 if (devvp->v_type != VBLK) {
161 vrele(devvp);
162 return (ENOTBLK);
163 }
164 if (major(devvp->v_rdev) >= nblkdev) {
165 vrele(devvp);
166 return (ENXIO);
167 }
168 if ((mp->mnt_flag & MNT_UPDATE) == 0)
169 error = mountfs(devvp, mp, p);
170 else {
d48157d5
KM
171 if (devvp != ump->um_devvp)
172 error = EINVAL; /* needs translation */
2a7dbb09
KM
173 else
174 vrele(devvp);
d48157d5 175 }
7188ac27
KM
176 if (error) {
177 vrele(devvp);
178 return (error);
27d00e76 179 }
7188ac27
KM
180 ump = VFSTOUFS(mp);
181 fs = ump->um_fs;
182 (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
183 bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
82161bc8
KM
184 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
185 MNAMELEN);
186 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
187 &size);
188 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
0eb6f54a 189 (void) ufs_statfs(mp, &mp->mnt_stat, p);
7188ac27 190 return (0);
71e4e98b
SL
191}
192
7188ac27
KM
193/*
194 * Common code for mount and mountroot
195 */
0eb6f54a 196mountfs(devvp, mp, p)
1182ae61 197 register struct vnode *devvp;
7188ac27 198 struct mount *mp;
0eb6f54a 199 struct proc *p;
71e4e98b 200{
8dc876c1 201 register struct ufsmount *ump = (struct ufsmount *)0;
7188ac27 202 struct buf *bp = NULL;
71e4e98b 203 register struct fs *fs;
7188ac27 204 dev_t dev = devvp->v_rdev;
ec67a3ce
MK
205 struct partinfo dpart;
206 int havepart = 0, blks;
27d00e76 207 caddr_t base, space;
7188ac27
KM
208 int havepart = 0, blks;
209 int error, i, size;
6d07f4cd 210 int needclose = 0;
82161bc8 211 int ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
1c26e003 212 extern struct vnode *rootvp;
71e4e98b 213
0eb6f54a 214 if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p))
7188ac27 215 return (error);
6d07f4cd 216 needclose = 1;
0eb6f54a 217 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
609e7cfa 218 size = DEV_BSIZE;
0eb6f54a 219 else {
ec67a3ce
MK
220 havepart = 1;
221 size = dpart.disklab->d_secsize;
7188ac27 222 }
8dc876c1 223 if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp))
71e4e98b 224 goto out;
e018935f 225 fs = bp->b_un.b_fs;
8dc876c1 226 error = EINVAL; /* XXX needs translation */
1c281610
MK
227 goto out;
228 }
8dc876c1 229 ump = (struct ufsmount *)malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
7188ac27 230 ump->um_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK,
5adcb337 231 M_WAITOK);
7188ac27 232 bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs,
71e4e98b 233 (u_int)fs->fs_sbsize);
5d96a9ad
KM
234 if (fs->fs_sbsize < SBSIZE)
235 bp->b_flags |= B_INVAL;
e018935f
MK
236 brelse(bp);
237 bp = NULL;
7188ac27
KM
238 fs = ump->um_fs;
239 fs->fs_ronly = ronly;
71e4e98b
SL
240 if (ronly == 0)
241 fs->fs_fmod = 1;
609e7cfa
MK
242 if (havepart) {
243 dpart.part->p_fstype = FS_BSDFFS;
244 dpart.part->p_fsize = fs->fs_fsize;
245 dpart.part->p_frag = fs->fs_frag;
42ff4c2e 246 dpart.part->p_cpg = fs->fs_cpg;
609e7cfa 247 }
ec67a3ce
MK
248#ifdef SECSIZE
249 /*
250 * If we have a disk label, force per-partition
251 * filesystem information to be correct
252 * and set correct current fsbtodb shift.
253 */
254#endif SECSIZE
255 if (havepart) {
256 dpart.part->p_fstype = FS_BSDFFS;
257 dpart.part->p_fsize = fs->fs_fsize;
258 dpart.part->p_frag = fs->fs_frag;
259#ifdef SECSIZE
260#ifdef tahoe
261 /*
262 * Save the original fsbtodb shift to restore on updates.
263 * (Console doesn't understand fsbtodb changes.)
264 */
265 fs->fs_sparecon[0] = fs->fs_fsbtodb;
266#endif
267 i = fs->fs_fsize / size;
268 for (fs->fs_fsbtodb = 0; i > 1; i >>= 1)
269 fs->fs_fsbtodb++;
270#endif SECSIZE
271 fs->fs_dbsize = size;
272 }
71e4e98b 273 blks = howmany(fs->fs_cssize, fs->fs_fsize);
5adcb337
KM
274 base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK,
275 M_WAITOK);
71e4e98b
SL
276 for (i = 0; i < blks; i += fs->fs_frag) {
277 size = fs->fs_bsize;
278 if (i + fs->fs_frag > blks)
279 size = (blks - i) * fs->fs_fsize;
ec67a3ce
MK
280#ifdef SECSIZE
281 tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size,
282 fs->fs_dbsize);
283#else SECSIZE
a937f856
KM
284 error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
285 NOCRED, &bp);
7188ac27 286 if (error) {
5adcb337 287 free((caddr_t)base, M_SUPERBLK);
71e4e98b
SL
288 goto out;
289 }
e018935f 290 bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size);
60f9c9e3 291 fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
71e4e98b 292 space += size;
e018935f
MK
293 brelse(bp);
294 bp = NULL;
71e4e98b 295 }
82161bc8
KM
296 mp->mnt_data = (qaddr_t)ump;
297 mp->mnt_stat.f_fsid.val[0] = (long)dev;
298 mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS;
299 mp->mnt_flag |= MNT_LOCAL;
7188ac27
KM
300 ump->um_mountp = mp;
301 ump->um_dev = dev;
302 ump->um_devvp = devvp;
8dc876c1
KM
303 for (i = 0; i < MAXQUOTAS; i++)
304 ump->um_quotas[i] = NULLVP;
0f93ba7b 305 devvp->v_specflags |= SI_MOUNTEDON;
7188ac27 306
94354803
KM
307 /* Sanity checks for old file systems. XXX */
308 fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect); /* XXX */
309 fs->fs_interleave = MAX(fs->fs_interleave, 1); /* XXX */
2af59000
KM
310 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */
311 fs->fs_nrpos = 8; /* XXX */
609e7cfa 312
7188ac27 313 return (0);
71e4e98b 314out:
c86c9b6e
KM
315 if (bp)
316 brelse(bp);
609e7cfa 317 if (needclose)
0eb6f54a 318 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
8dc876c1 319 if (ump) {
7188ac27 320 free((caddr_t)ump->um_fs, M_SUPERBLK);
8dc876c1 321 free((caddr_t)ump, M_UFSMNT);
82161bc8 322 mp->mnt_data = (qaddr_t)0;
27d00e76 323 }
7188ac27 324 return (error);
71e4e98b
SL
325}
326
5bf9d21f
KM
327/*
328 * Make a filesystem operational.
329 * Nothing to do at the moment.
330 */
31593ba7 331/* ARGSUSED */
0eb6f54a 332ufs_start(mp, flags, p)
5bf9d21f
KM
333 struct mount *mp;
334 int flags;
0eb6f54a 335 struct proc *p;
5bf9d21f
KM
336{
337
338 return (0);
339}
71e4e98b 340
7188ac27
KM
341/*
342 * unmount system call
343 */
0eb6f54a 344ufs_unmount(mp, mntflags, p)
7188ac27 345 struct mount *mp;
8dc876c1 346 int mntflags;
0eb6f54a 347 struct proc *p;
71e4e98b 348{
7188ac27 349 register struct ufsmount *ump;
71e4e98b 350 register struct fs *fs;
8dc876c1 351 int i, error, ronly, flags = 0;
71e4e98b 352
87be6db2 353 if (mntflags & MNT_FORCE) {
d85a9d1b 354 if (!doforce || mp == rootfs)
87be6db2 355 return (EINVAL);
8dc876c1 356 flags |= FORCECLOSE;
87be6db2 357 }
5d96a9ad
KM
358 mntflushbuf(mp, 0);
359 if (mntinvalbuf(mp))
360 return (EBUSY);
7188ac27 361 ump = VFSTOUFS(mp);
ec67a3ce 362 return (error);
71e4e98b 363#ifdef QUOTA
82161bc8 364 if (mp->mnt_flag & MNT_QUOTA) {
8dc876c1 365 if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags))
6d943995 366 return (error);
8dc876c1
KM
367 for (i = 0; i < MAXQUOTAS; i++) {
368 if (ump->um_quotas[i] == NULLVP)
369 continue;
70a360ba 370 quotaoff(p, mp, i);
8dc876c1 371 }
6d943995 372 /*
8dc876c1
KM
373 * Here we fall through to vflush again to ensure
374 * that we have gotten rid of all the system vnodes.
6d943995 375 */
8dc876c1 376 }
71e4e98b 377#endif
8dc876c1 378 if (error = vflush(mp, NULLVP, flags))
6d943995 379 return (error);
7188ac27
KM
380 fs = ump->um_fs;
381 ronly = !fs->fs_ronly;
ec67a3ce
MK
382 error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE);
383 irele(ip);
384 return (error);
71e4e98b
SL
385}
386
7188ac27
KM
387/*
388 * Return root of a filesystem
389 */
390ufs_root(mp, vpp)
391 struct mount *mp;
392 struct vnode **vpp;
393{
31593ba7
KM
394 register struct inode *ip;
395 struct inode *nip;
396 struct vnode tvp;
7188ac27
KM
397 int error;
398
31593ba7
KM
399 tvp.v_mount = mp;
400 ip = VTOI(&tvp);
401 ip->i_vnode = &tvp;
402 ip->i_dev = VFSTOUFS(mp)->um_dev;
403 error = iget(ip, (ino_t)ROOTINO, &nip);
7188ac27
KM
404 if (error)
405 return (error);
31593ba7 406 *vpp = ITOV(nip);
7188ac27
KM
407 return (0);
408}
409
8dc876c1
KM
410/*
411 * Do operations associated with quotas
412 */
0eb6f54a 413ufs_quotactl(mp, cmds, uid, arg, p)
8dc876c1
KM
414 struct mount *mp;
415 int cmds;
416 uid_t uid;
417 caddr_t arg;
0eb6f54a 418 struct proc *p;
8dc876c1 419{
8dc876c1
KM
420 struct ufsmount *ump = VFSTOUFS(mp);
421 int cmd, type, error;
422
423#ifndef QUOTA
424 return (EOPNOTSUPP);
425#else
426 if (uid == -1)
c6f5111d 427 uid = p->p_cred->p_ruid;
8dc876c1
KM
428 cmd = cmds >> SUBCMDSHIFT;
429
430 switch (cmd) {
431 case Q_GETQUOTA:
432 case Q_SYNC:
c6f5111d 433 if (uid == p->p_cred->p_ruid)
8dc876c1
KM
434 break;
435 /* fall through */
436 default:
c6f5111d 437 if (error = suser(p->p_ucred, &p->p_acflag))
8dc876c1
KM
438 return (error);
439 }
440
441 type = cmd & SUBCMDMASK;
442 if ((u_int)type >= MAXQUOTAS)
443 return (EINVAL);
444
445 switch (cmd) {
446
447 case Q_QUOTAON:
c6f5111d 448 return (quotaon(p, mp, type, arg));
8dc876c1
KM
449
450 case Q_QUOTAOFF:
451 if (vfs_busy(mp))
452 return (0);
70a360ba 453 error = quotaoff(p, mp, type);
8dc876c1
KM
454 vfs_unbusy(mp);
455 return (error);
456
457 case Q_SETQUOTA:
458 return (setquota(mp, uid, type, arg));
459
460 case Q_SETUSE:
461 return (setuse(mp, uid, type, arg));
462
463 case Q_GETQUOTA:
464 return (getquota(mp, uid, type, arg));
465
466 case Q_SYNC:
467 if (vfs_busy(mp))
468 return (0);
469 error = qsync(mp);
470 vfs_unbusy(mp);
471 return (error);
472
473 default:
474 return (EINVAL);
475 }
476 /* NOTREACHED */
477#endif
478}
479
7188ac27
KM
480/*
481 * Get file system statistics.
482 */
0eb6f54a 483ufs_statfs(mp, sbp, p)
7188ac27
KM
484 struct mount *mp;
485 register struct statfs *sbp;
0eb6f54a 486 struct proc *p;
7188ac27
KM
487{
488 register struct ufsmount *ump;
489 register struct fs *fs;
490
491 ump = VFSTOUFS(mp);
492 fs = ump->um_fs;
493 if (fs->fs_magic != FS_MAGIC)
494 panic("ufs_statfs");
495 sbp->f_type = MOUNT_UFS;
7188ac27
KM
496 sbp->f_fsize = fs->fs_fsize;
497 sbp->f_bsize = fs->fs_bsize;
498 sbp->f_blocks = fs->fs_dsize;
499 sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
500 fs->fs_cstotal.cs_nffree;
501 sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) -
502 (fs->fs_dsize - sbp->f_bfree);
5c41c19e 503 sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO;
7188ac27 504 sbp->f_ffree = fs->fs_cstotal.cs_nifree;
82161bc8
KM
505 if (sbp != &mp->mnt_stat) {
506 bcopy((caddr_t)mp->mnt_stat.f_mntonname,
d45de50d 507 (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
82161bc8 508 bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
d45de50d
KM
509 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
510 }
7188ac27
KM
511 return (0);
512}
513
514int syncprt = 0;
515
516/*
517 * Go through the disk queues to initiate sandbagged IO;
518 * go through the inodes to write those that have been modified;
519 * initiate the writing of the super block if it has been modified.
8dc876c1
KM
520 *
521 * Note: we are always called with the filesystem marked `MPBUSY'.
7188ac27
KM
522 */
523ufs_sync(mp, waitfor)
71e4e98b 524 struct mount *mp;
7188ac27 525 int waitfor;
71e4e98b 526{
31593ba7 527 register struct vnode *vp;
7188ac27
KM
528 register struct inode *ip;
529 register struct ufsmount *ump = VFSTOUFS(mp);
530 register struct fs *fs;
812b91f3 531 int error, allerror = 0;
7188ac27
KM
532
533 if (syncprt)
534 bufstats();
7188ac27 535 fs = ump->um_fs;
7188ac27
KM
536 /*
537 * Write back modified superblock.
538 * Consistency check that the superblock
539 * is still in the buffer cache.
540 */
541 if (fs->fs_fmod != 0) {
542 if (fs->fs_ronly != 0) { /* XXX */
543 printf("fs = %s\n", fs->fs_fsmnt);
544 panic("update: rofs mod");
545 }
546 fs->fs_fmod = 0;
547 fs->fs_time = time.tv_sec;
881f1b87 548 allerror = sbupdate(ump, waitfor);
7188ac27
KM
549 }
550 /*
551 * Write back each (modified) inode.
552 */
25b5cf58 553loop:
a242f429
KM
554 for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
555 /*
556 * If the vnode that we are about to sync is no longer
557 * associated with this mount point, start over.
558 */
559 if (vp->v_mount != mp)
560 goto loop;
d85a9d1b
KM
561 if (VOP_ISLOCKED(vp))
562 continue;
31593ba7 563 ip = VTOI(vp);
25b5cf58
KM
564 if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0 &&
565 vp->v_dirtyblkhd == NULL)
7188ac27 566 continue;
25b5cf58
KM
567 if (vget(vp))
568 goto loop;
569 if (vp->v_dirtyblkhd)
570 vflushbuf(vp, 0);
571 if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) &&
572 (error = iupdat(ip, &time, &time, 0)))
812b91f3
KM
573 allerror = error;
574 vput(vp);
7188ac27 575 }
7188ac27 576 /*
5d96a9ad 577 * Force stale file system control information to be flushed.
7188ac27 578 */
5d96a9ad 579 vflushbuf(ump->um_devvp, waitfor == MNT_WAIT ? B_SYNC : 0);
8dc876c1
KM
580#ifdef QUOTA
581 qsync(mp);
582#endif
812b91f3 583 return (allerror);
7188ac27
KM
584}
585
586/*
587 * Write a superblock and associated information back to disk.
588 */
589sbupdate(mp, waitfor)
590 struct ufsmount *mp;
591 int waitfor;
592{
593 register struct fs *fs = mp->um_fs;
71e4e98b
SL
594 register struct buf *bp;
595 int blks;
596 caddr_t space;
7188ac27 597 int i, size, error = 0;
71e4e98b 598
ec67a3ce
MK
599#ifdef SECSIZE
600 bp = getblk(mp->m_dev, (daddr_t)fsbtodb(fs, SBOFF / fs->fs_fsize),
601 (int)fs->fs_sbsize, fs->fs_dbsize);
602#else SECSIZE
7188ac27 603 bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize);
ec67a3ce 604#endif SECSIZE
71e4e98b 605 bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
2af59000
KM
606 /* Restore compatibility to old file systems. XXX */
607 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */
608 bp->b_un.b_fs->fs_nrpos = -1; /* XXX */
ec67a3ce
MK
609#ifdef SECSIZE
610#ifdef tahoe
611 /* restore standard fsbtodb shift */
612 bp->b_un.b_fs->fs_fsbtodb = fs->fs_sparecon[0];
613 bp->b_un.b_fs->fs_sparecon[0] = 0;
614#endif
615#endif SECSIZE
7188ac27
KM
616 if (waitfor == MNT_WAIT)
617 error = bwrite(bp);
618 else
619 bawrite(bp);
71e4e98b
SL
620 blks = howmany(fs->fs_cssize, fs->fs_fsize);
621 space = (caddr_t)fs->fs_csp[0];
622 for (i = 0; i < blks; i += fs->fs_frag) {
623 size = fs->fs_bsize;
624 if (i + fs->fs_frag > blks)
625 size = (blks - i) * fs->fs_fsize;
ec67a3ce
MK
626#ifdef SECSIZE
627 bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size,
628 fs->fs_dbsize);
629#else SECSIZE
7188ac27 630 bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), size);
ec67a3ce 631#endif SECSIZE
71e4e98b
SL
632 bcopy(space, bp->b_un.b_addr, (u_int)size);
633 space += size;
7188ac27
KM
634 if (waitfor == MNT_WAIT)
635 error = bwrite(bp);
636 else
637 bawrite(bp);
71e4e98b 638 }
7188ac27 639 return (error);
71e4e98b
SL
640}
641
642/*
7188ac27
KM
643 * Print out statistics on the current allocation of the buffer pool.
644 * Can be enabled to print out on every ``sync'' by setting "syncprt"
645 * above.
646 */
647bufstats()
648{
649 int s, i, j, count;
650 register struct buf *bp, *dp;
651 int counts[MAXBSIZE/CLBYTES+1];
652 static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" };
653
654 for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) {
655 count = 0;
656 for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
657 counts[j] = 0;
658 s = splbio();
659 for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) {
660 counts[dp->b_bufsize/CLBYTES]++;
661 count++;
662 }
663 splx(s);
664 printf("%s: total-%d", bname[i], count);
665 for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
666 if (counts[j] != 0)
667 printf(", %d-%d", j * CLBYTES, counts[j]);
668 printf("\n");
669 }
670}
671
672/*
673 * File handle to vnode
113c35f2
KM
674 *
675 * Have to be really careful about stale file handles:
676 * - check that the inode number is in range
677 * - call iget() to get the locked inode
678 * - check for an unallocated inode (i_mode == 0)
679 * - check that the generation number matches
7188ac27
KM
680 */
681ufs_fhtovp(mp, fhp, vpp)
113c35f2 682 register struct mount *mp;
7188ac27
KM
683 struct fid *fhp;
684 struct vnode **vpp;
685{
686 register struct ufid *ufhp;
113c35f2 687 register struct fs *fs;
31593ba7
KM
688 register struct inode *ip;
689 struct inode *nip;
690 struct vnode tvp;
7188ac27
KM
691 int error;
692
693 ufhp = (struct ufid *)fhp;
113c35f2
KM
694 fs = VFSTOUFS(mp)->um_fs;
695 if (ufhp->ufid_ino < ROOTINO ||
696 ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) {
82161bc8 697 *vpp = NULLVP;
113c35f2
KM
698 return (EINVAL);
699 }
31593ba7
KM
700 tvp.v_mount = mp;
701 ip = VTOI(&tvp);
702 ip->i_vnode = &tvp;
703 ip->i_dev = VFSTOUFS(mp)->um_dev;
704 if (error = iget(ip, ufhp->ufid_ino, &nip)) {
82161bc8 705 *vpp = NULLVP;
7188ac27
KM
706 return (error);
707 }
31593ba7 708 ip = nip;
113c35f2
KM
709 if (ip->i_mode == 0) {
710 iput(ip);
82161bc8 711 *vpp = NULLVP;
113c35f2
KM
712 return (EINVAL);
713 }
7188ac27
KM
714 if (ip->i_gen != ufhp->ufid_gen) {
715 iput(ip);
82161bc8 716 *vpp = NULLVP;
7188ac27
KM
717 return (EINVAL);
718 }
719 *vpp = ITOV(ip);
720 return (0);
721}
722
723/*
29e77c27 724 * Vnode pointer to File handle
7188ac27
KM
725 */
726/* ARGSUSED */
758e3529
KM
727ufs_vptofh(vp, fhp)
728 struct vnode *vp;
7188ac27 729 struct fid *fhp;
7188ac27 730{
758e3529
KM
731 register struct inode *ip = VTOI(vp);
732 register struct ufid *ufhp;
7188ac27 733
758e3529
KM
734 ufhp = (struct ufid *)fhp;
735 ufhp->ufid_len = sizeof(struct ufid);
736 ufhp->ufid_ino = ip->i_number;
737 ufhp->ufid_gen = ip->i_gen;
738 return (0);
7188ac27 739}