xref: /freebsd/sys/ufs/ffs/ffs_vfsops.c (revision a316b26e50bbed7cf655fbba726ab87d8ab7599d)
1 /*
2  * Copyright (c) 1989, 1991, 1993, 1994
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  *	@(#)ffs_vfsops.c	8.8 (Berkeley) 4/18/94
34  * $Id: ffs_vfsops.c,v 1.11 1994/10/28 12:42:03 jkh Exp $
35  */
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/namei.h>
40 #include <sys/proc.h>
41 #include <sys/kernel.h>
42 #include <sys/vnode.h>
43 #include <sys/socket.h>
44 #include <sys/mount.h>
45 #include <sys/buf.h>
46 #include <sys/mbuf.h>
47 #include <sys/file.h>
48 #include <sys/disklabel.h>
49 #include <sys/ioctl.h>
50 #include <sys/errno.h>
51 #include <sys/malloc.h>
52 
53 #include <miscfs/specfs/specdev.h>
54 
55 #include <ufs/ufs/quota.h>
56 #include <ufs/ufs/ufsmount.h>
57 #include <ufs/ufs/inode.h>
58 #include <ufs/ufs/ufs_extern.h>
59 
60 #include <ufs/ffs/fs.h>
61 #include <ufs/ffs/ffs_extern.h>
62 
63 #include <machine/clock.h> 	/* What is inittodr() doing in a fs anyway ? */
64 
65 int	ffs_sbupdate __P((struct ufsmount *, int));
66 int	ffs_flushfiles __P((struct mount *, int, struct proc *));
67 int	ffs_reload __P((struct mount *,struct ucred *,struct proc *));
68 int	ffs_oldfscompat __P((struct fs *));
69 
70 struct vfsops ufs_vfsops = {
71 	ffs_mount,
72 	ufs_start,
73 	ffs_unmount,
74 	ufs_root,
75 	ufs_quotactl,
76 	ffs_statfs,
77 	ffs_sync,
78 	ffs_vget,
79 	ffs_fhtovp,
80 	ffs_vptofh,
81 	ffs_init,
82 };
83 
84 VFS_SET(ufs_vfsops, ufs, MOUNT_UFS, 0);
85 
86 extern u_long nextgennumber;
87 
88 /*
89  * Called by main() when ufs is going to be mounted as root.
90  *
91  * Name is updated by mount(8) after booting.
92  */
93 #define ROOTNAME	"root_device"
94 
95 int
96 ffs_mountroot()
97 {
98 	register struct fs *fs;
99 	register struct mount *mp;
100 	struct proc *p = curproc;	/* XXX */
101 	struct ufsmount *ump;
102 	u_int size;
103 	int error;
104 
105 	/*
106 	 * Get vnodes for swapdev and rootdev.
107 	 */
108 	if (bdevvp(swapdev, &swapdev_vp) || bdevvp(rootdev, &rootvp))
109 		panic("ffs_mountroot: can't setup bdevvp's");
110 
111 	mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK);
112 	bzero((char *)mp, (u_long)sizeof(struct mount));
113 	mp->mnt_op = &ufs_vfsops;
114 	mp->mnt_flag = MNT_RDONLY;
115 	error = ffs_mountfs(rootvp, mp, p);
116 	if (error) {
117 		free(mp, M_MOUNT);
118 		return (error);
119 	}
120 	error = vfs_lock(mp);
121 	if (error) {
122 		(void)ffs_unmount(mp, 0, p);
123 		free(mp, M_MOUNT);
124 		return (error);
125 	}
126 	TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
127 	mp->mnt_flag |= MNT_ROOTFS;
128 	mp->mnt_vnodecovered = NULLVP;
129 	ump = VFSTOUFS(mp);
130 	fs = ump->um_fs;
131 	bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt));
132 	fs->fs_fsmnt[0] = '/';
133 	bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
134 	    MNAMELEN);
135 	(void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
136 	    &size);
137 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
138 	(void)ffs_statfs(mp, &mp->mnt_stat, p);
139 	vfs_unlock(mp);
140 	inittodr(fs->fs_time);
141 	return (0);
142 }
143 
144 /*
145  * VFS Operations.
146  *
147  * mount system call
148  */
149 int
150 ffs_mount(mp, path, data, ndp, p)
151 	register struct mount *mp;
152 	char *path;
153 	caddr_t data;
154 	struct nameidata *ndp;
155 	struct proc *p;
156 {
157 	struct vnode *devvp;
158 	struct ufs_args args;
159 	struct ufsmount *ump = 0;
160 	register struct fs *fs;
161 	u_int size;
162 	int error, flags;
163 
164 	error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args));
165 	if (error)
166 		return (error);
167 	/*
168 	 * If updating, check whether changing from read-only to
169 	 * read/write; if there is no device name, that's all we do.
170 	 */
171 	if (mp->mnt_flag & MNT_UPDATE) {
172 		ump = VFSTOUFS(mp);
173 		fs = ump->um_fs;
174 		error = 0;
175 		if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
176 			flags = WRITECLOSE;
177 			if (mp->mnt_flag & MNT_FORCE)
178 				flags |= FORCECLOSE;
179 			if (vfs_busy(mp))
180 				return (EBUSY);
181 			error = ffs_flushfiles(mp, flags, p);
182 			vfs_unbusy(mp);
183 		}
184 		if (!error && (mp->mnt_flag & MNT_RELOAD))
185 			error = ffs_reload(mp, ndp->ni_cnd.cn_cred, p);
186 		if (error)
187 			return (error);
188 		if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR))
189 			fs->fs_ronly = 0;
190 		if (fs->fs_ronly == 0) {
191 			fs->fs_clean = 0;
192 			ffs_sbupdate(ump, MNT_WAIT);
193 		}
194 		if (args.fspec == 0) {
195 			/*
196 			 * Process export requests.
197 			 */
198 			return (vfs_export(mp, &ump->um_export, &args.export));
199 		}
200 	}
201 	/*
202 	 * Not an update, or updating the name: look up the name
203 	 * and verify that it refers to a sensible block device.
204 	 */
205 	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
206 	error = namei(ndp);
207 	if (error)
208 		return (error);
209 	devvp = ndp->ni_vp;
210 
211 	if (devvp->v_type != VBLK) {
212 		vrele(devvp);
213 		return (ENOTBLK);
214 	}
215 	if (major(devvp->v_rdev) >= nblkdev) {
216 		vrele(devvp);
217 		return (ENXIO);
218 	}
219 	if ((mp->mnt_flag & MNT_UPDATE) == 0)
220 		error = ffs_mountfs(devvp, mp, p);
221 	else {
222 		if (devvp != ump->um_devvp)
223 			error = EINVAL;	/* needs translation */
224 		else
225 			vrele(devvp);
226 	}
227 	if (error) {
228 		vrele(devvp);
229 		return (error);
230 	}
231 	ump = VFSTOUFS(mp);
232 	fs = ump->um_fs;
233 	(void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
234 	bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
235 	bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
236 	    MNAMELEN);
237 	(void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
238 	    &size);
239 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
240 	(void)ffs_statfs(mp, &mp->mnt_stat, p);
241 	return (0);
242 }
243 
244 /*
245  * Reload all incore data for a filesystem (used after running fsck on
246  * the root filesystem and finding things to fix). The filesystem must
247  * be mounted read-only.
248  *
249  * Things to do to update the mount:
250  *	1) invalidate all cached meta-data.
251  *	2) re-read superblock from disk.
252  *	3) re-read summary information from disk.
253  *	4) invalidate all inactive vnodes.
254  *	5) invalidate all cached file data.
255  *	6) re-read inode data for all active vnodes.
256  */
257 int
258 ffs_reload(mountp, cred, p)
259 	register struct mount *mountp;
260 	struct ucred *cred;
261 	struct proc *p;
262 {
263 	register struct vnode *vp, *nvp, *devvp;
264 	struct inode *ip;
265 	struct csum *space;
266 	struct buf *bp;
267 	struct fs *fs;
268 	int i, blks, size, error;
269 
270 	if ((mountp->mnt_flag & MNT_RDONLY) == 0)
271 		return (EINVAL);
272 	/*
273 	 * Step 1: invalidate all cached meta-data.
274 	 */
275 	devvp = VFSTOUFS(mountp)->um_devvp;
276 	if (vinvalbuf(devvp, 0, cred, p, 0, 0))
277 		panic("ffs_reload: dirty1");
278 	/*
279 	 * Step 2: re-read superblock from disk.
280 	 */
281 	error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp);
282 	if (error)
283 		return (error);
284 	fs = (struct fs *)bp->b_data;
285 	if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
286 	    fs->fs_bsize < sizeof(struct fs)) {
287 		brelse(bp);
288 		return (EIO);		/* XXX needs translation */
289 	}
290 	fs = VFSTOUFS(mountp)->um_fs;
291 	bcopy(&fs->fs_csp[0], &((struct fs *)bp->b_data)->fs_csp[0],
292 	    sizeof(fs->fs_csp));
293 	bcopy(bp->b_data, fs, (u_int)fs->fs_sbsize);
294 	if (fs->fs_sbsize < SBSIZE)
295 		bp->b_flags |= B_INVAL;
296 	brelse(bp);
297 	ffs_oldfscompat(fs);
298 	/*
299 	 * Step 3: re-read summary information from disk.
300 	 */
301 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
302 	space = fs->fs_csp[0];
303 	for (i = 0; i < blks; i += fs->fs_frag) {
304 		size = fs->fs_bsize;
305 		if (i + fs->fs_frag > blks)
306 			size = (blks - i) * fs->fs_fsize;
307 		error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
308 		    NOCRED, &bp);
309 		if (error)
310 			return (error);
311 		bcopy(bp->b_data, fs->fs_csp[fragstoblks(fs, i)], (u_int)size);
312 		brelse(bp);
313 	}
314 loop:
315 	for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
316 		nvp = vp->v_mntvnodes.le_next;
317 		/*
318 		 * Step 4: invalidate all inactive vnodes.
319 		 */
320 		if (vp->v_usecount == 0) {
321 			vgone(vp);
322 			continue;
323 		}
324 		/*
325 		 * Step 5: invalidate all cached file data.
326 		 */
327 		if (vget(vp, 1))
328 			goto loop;
329 		if (vinvalbuf(vp, 0, cred, p, 0, 0))
330 			panic("ffs_reload: dirty2");
331 		/*
332 		 * Step 6: re-read inode data for all active vnodes.
333 		 */
334 		ip = VTOI(vp);
335 		error =
336 		    bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
337 		    (int)fs->fs_bsize, NOCRED, &bp);
338 		if (error) {
339 			vput(vp);
340 			return (error);
341 		}
342 		ip->i_din = *((struct dinode *)bp->b_data +
343 		    ino_to_fsbo(fs, ip->i_number));
344 		brelse(bp);
345 		vput(vp);
346 		if (vp->v_mount != mountp)
347 			goto loop;
348 	}
349 	return (0);
350 }
351 
352 /*
353  * Common code for mount and mountroot
354  */
355 int
356 ffs_mountfs(devvp, mp, p)
357 	register struct vnode *devvp;
358 	struct mount *mp;
359 	struct proc *p;
360 {
361 	register struct ufsmount *ump;
362 	struct buf *bp;
363 	register struct fs *fs;
364 	dev_t dev = devvp->v_rdev;
365 	struct partinfo dpart;
366 	caddr_t base, space;
367 	int havepart = 0, blks;
368 	int error, i, size;
369 	int ronly;
370 
371 	/*
372 	 * Disallow multiple mounts of the same device.
373 	 * Disallow mounting of a device that is currently in use
374 	 * (except for root, which might share swap device for miniroot).
375 	 * Flush out any old buffers remaining from a previous use.
376 	 */
377 	error = vfs_mountedon(devvp);
378 	if (error)
379 		return (error);
380 	if (vcount(devvp) > 1 && devvp != rootvp)
381 		return (EBUSY);
382 	error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
383 	if (error)
384 		return (error);
385 
386 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
387 	error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
388 	if (error)
389 		return (error);
390 	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
391 		size = DEV_BSIZE;
392 	else {
393 		havepart = 1;
394 		size = dpart.disklab->d_secsize;
395 	}
396 
397 	bp = NULL;
398 	ump = NULL;
399 	error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp);
400 	if (error)
401 		goto out;
402 	fs = (struct fs *)bp->b_data;
403 	if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
404 	    fs->fs_bsize < sizeof(struct fs)) {
405 		error = EINVAL;		/* XXX needs translation */
406 		goto out;
407 	}
408 	ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
409 	bzero((caddr_t)ump, sizeof *ump);
410 	ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT,
411 	    M_WAITOK);
412 	bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize);
413 	if (fs->fs_sbsize < SBSIZE)
414 		bp->b_flags |= B_INVAL;
415 	brelse(bp);
416 	bp = NULL;
417 	fs = ump->um_fs;
418 	fs->fs_ronly = ronly;
419 	if (!fs->fs_clean) {
420 		printf("WARNING: %s was not properly dismounted\n",fs->fs_fsmnt);
421 	}
422 	if (ronly == 0) {
423 		fs->fs_fmod = 1;
424 		fs->fs_clean = 0;
425 	}
426 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
427 	base = space = malloc((u_long)fs->fs_cssize, M_UFSMNT,
428 	    M_WAITOK);
429 	for (i = 0; i < blks; i += fs->fs_frag) {
430 		size = fs->fs_bsize;
431 		if (i + fs->fs_frag > blks)
432 			size = (blks - i) * fs->fs_fsize;
433 		error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
434 			NOCRED, &bp);
435 		if (error) {
436 			free(base, M_UFSMNT);
437 			goto out;
438 		}
439 		bcopy(bp->b_data, space, (u_int)size);
440 		fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
441 		space += size;
442 		brelse(bp);
443 		bp = NULL;
444 	}
445 	mp->mnt_data = (qaddr_t)ump;
446 	mp->mnt_stat.f_fsid.val[0] = (long)dev;
447 	mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS;
448 	mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
449 	mp->mnt_flag |= MNT_LOCAL;
450 	ump->um_mountp = mp;
451 	ump->um_dev = dev;
452 	ump->um_devvp = devvp;
453 	ump->um_nindir = fs->fs_nindir;
454 	ump->um_bptrtodb = fs->fs_fsbtodb;
455 	ump->um_seqinc = fs->fs_frag;
456 	for (i = 0; i < MAXQUOTAS; i++)
457 		ump->um_quotas[i] = NULLVP;
458 	devvp->v_specflags |= SI_MOUNTEDON;
459 	ffs_oldfscompat(fs);
460 	if (ronly == 0)
461 		ffs_sbupdate(ump, MNT_WAIT);
462 	return (0);
463 out:
464 	if (bp)
465 		brelse(bp);
466 	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
467 	if (ump) {
468 		free(ump->um_fs, M_UFSMNT);
469 		free(ump, M_UFSMNT);
470 		mp->mnt_data = (qaddr_t)0;
471 	}
472 	return (error);
473 }
474 
475 /*
476  * Sanity checks for old file systems.
477  *
478  * XXX - goes away some day.
479  */
480 int
481 ffs_oldfscompat(fs)
482 	struct fs *fs;
483 {
484 	int i;
485 
486 	fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect);	/* XXX */
487 	fs->fs_interleave = max(fs->fs_interleave, 1);		/* XXX */
488 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
489 		fs->fs_nrpos = 8;				/* XXX */
490 	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
491 		quad_t sizepb = fs->fs_bsize;			/* XXX */
492 								/* XXX */
493 #if 0
494 		fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1;	/* XXX */
495 		for (i = 0; i < NIADDR; i++) {			/* XXX */
496 			sizepb *= NINDIR(fs);			/* XXX */
497 			fs->fs_maxfilesize += sizepb;		/* XXX */
498 		}						/* XXX */
499 #endif
500 		fs->fs_maxfilesize = (u_quad_t) 1 << 39;
501 		fs->fs_qbmask = ~fs->fs_bmask;			/* XXX */
502 		fs->fs_qfmask = ~fs->fs_fmask;			/* XXX */
503 	}							/* XXX */
504 	return (0);
505 }
506 
507 /*
508  * unmount system call
509  */
510 int
511 ffs_unmount(mp, mntflags, p)
512 	struct mount *mp;
513 	int mntflags;
514 	struct proc *p;
515 {
516 	register struct ufsmount *ump;
517 	register struct fs *fs;
518 	int error, flags, ronly;
519 
520 	flags = 0;
521 	if (mntflags & MNT_FORCE) {
522 		flags |= FORCECLOSE;
523 	}
524 	error = ffs_flushfiles(mp, flags, p);
525 	if (error)
526 		return (error);
527 	ump = VFSTOUFS(mp);
528 	fs = ump->um_fs;
529 	ronly = fs->fs_ronly;
530 	if (!ronly) {
531 		fs->fs_clean = 1;
532 		ffs_sbupdate(ump, MNT_WAIT);
533 	}
534 	ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
535 	error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE,
536 		NOCRED, p);
537 	vrele(ump->um_devvp);
538 	free(fs->fs_csp[0], M_UFSMNT);
539 	free(fs, M_UFSMNT);
540 	free(ump, M_UFSMNT);
541 	mp->mnt_data = (qaddr_t)0;
542 	mp->mnt_flag &= ~MNT_LOCAL;
543 	return (error);
544 }
545 
546 /*
547  * Flush out all the files in a filesystem.
548  */
549 int
550 ffs_flushfiles(mp, flags, p)
551 	register struct mount *mp;
552 	int flags;
553 	struct proc *p;
554 {
555 	extern int doforce;
556 	register struct ufsmount *ump;
557 	int error;
558 
559 	if (!doforce)
560 		flags &= ~FORCECLOSE;
561 	ump = VFSTOUFS(mp);
562 #ifdef QUOTA
563 	if (mp->mnt_flag & MNT_QUOTA) {
564 		int i;
565 		error = vflush(mp, NULLVP, SKIPSYSTEM|flags);
566 		if (error)
567 			return (error);
568 		for (i = 0; i < MAXQUOTAS; i++) {
569 			if (ump->um_quotas[i] == NULLVP)
570 				continue;
571 			quotaoff(p, mp, i);
572 		}
573 		/*
574 		 * Here we fall through to vflush again to ensure
575 		 * that we have gotten rid of all the system vnodes.
576 		 */
577 	}
578 #endif
579 	error = vflush(mp, NULLVP, flags);
580 	return (error);
581 }
582 
583 /*
584  * Get file system statistics.
585  */
586 int
587 ffs_statfs(mp, sbp, p)
588 	struct mount *mp;
589 	register struct statfs *sbp;
590 	struct proc *p;
591 {
592 	register struct ufsmount *ump;
593 	register struct fs *fs;
594 
595 	ump = VFSTOUFS(mp);
596 	fs = ump->um_fs;
597 	if (fs->fs_magic != FS_MAGIC)
598 		panic("ffs_statfs");
599 	sbp->f_type = MOUNT_UFS;
600 	sbp->f_bsize = fs->fs_fsize;
601 	sbp->f_iosize = fs->fs_bsize;
602 	sbp->f_blocks = fs->fs_dsize;
603 	sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
604 		fs->fs_cstotal.cs_nffree;
605 	sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) -
606 		(fs->fs_dsize - sbp->f_bfree);
607 	sbp->f_files =  fs->fs_ncg * fs->fs_ipg - ROOTINO;
608 	sbp->f_ffree = fs->fs_cstotal.cs_nifree;
609 	if (sbp != &mp->mnt_stat) {
610 		bcopy((caddr_t)mp->mnt_stat.f_mntonname,
611 			(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
612 		bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
613 			(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
614 	}
615 	return (0);
616 }
617 
618 /*
619  * Go through the disk queues to initiate sandbagged IO;
620  * go through the inodes to write those that have been modified;
621  * initiate the writing of the super block if it has been modified.
622  *
623  * Note: we are always called with the filesystem marked `MPBUSY'.
624  */
625 int
626 ffs_sync(mp, waitfor, cred, p)
627 	struct mount *mp;
628 	int waitfor;
629 	struct ucred *cred;
630 	struct proc *p;
631 {
632 	register struct vnode *vp;
633 	register struct inode *ip;
634 	register struct ufsmount *ump = VFSTOUFS(mp);
635 	register struct fs *fs;
636 	int error, allerror = 0;
637 
638 	fs = ump->um_fs;
639 	/*
640 	 * Write back modified superblock.
641 	 * Consistency check that the superblock
642 	 * is still in the buffer cache.
643 	 */
644 	if (fs->fs_fmod != 0) {
645 		if (fs->fs_ronly != 0) {		/* XXX */
646 			printf("fs = %s\n", fs->fs_fsmnt);
647 			panic("update: rofs mod");
648 		}
649 		fs->fs_fmod = 0;
650 		fs->fs_time = time.tv_sec;
651 		allerror = ffs_sbupdate(ump, waitfor);
652 	}
653 	/*
654 	 * Write back each (modified) inode.
655 	 */
656 loop:
657 	for (vp = mp->mnt_vnodelist.lh_first;
658 	     vp != NULL;
659 	     vp = vp->v_mntvnodes.le_next) {
660 		/*
661 		 * If the vnode that we are about to sync is no longer
662 		 * associated with this mount point, start over.
663 		 */
664 		if (vp->v_mount != mp)
665 			goto loop;
666 		if (VOP_ISLOCKED(vp))
667 			continue;
668 		ip = VTOI(vp);
669 		if ((ip->i_flag &
670 		    (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
671 		    vp->v_dirtyblkhd.lh_first == NULL)
672 			continue;
673 		if (vget(vp, 1))
674 			goto loop;
675 		error = VOP_FSYNC(vp, cred, waitfor, p);
676 		if (error)
677 			allerror = error;
678 		vput(vp);
679 	}
680 	/*
681 	 * Force stale file system control information to be flushed.
682 	 */
683 	error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p);
684 	if (error)
685 		allerror = error;
686 #ifdef QUOTA
687 	qsync(mp);
688 #endif
689 	return (allerror);
690 }
691 
692 /*
693  * Look up a FFS dinode number to find its incore vnode, otherwise read it
694  * in from disk.  If it is in core, wait for the lock bit to clear, then
695  * return the inode locked.  Detection and handling of mount points must be
696  * done by the calling routine.
697  */
698 int
699 ffs_vget(mp, ino, vpp)
700 	struct mount *mp;
701 	ino_t ino;
702 	struct vnode **vpp;
703 {
704 	register struct fs *fs;
705 	register struct inode *ip;
706 	struct ufsmount *ump;
707 	struct buf *bp;
708 	struct vnode *vp;
709 	dev_t dev;
710 	int type, error;
711 
712 	ump = VFSTOUFS(mp);
713 	dev = ump->um_dev;
714 	if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
715 		return (0);
716 
717 	/* Allocate a new vnode/inode. */
718 	error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp);
719 	if (error) {
720 		*vpp = NULL;
721 		return (error);
722 	}
723 	type = ump->um_devvp->v_tag == VT_MFS ? M_MFSNODE : M_FFSNODE; /* XXX */
724 	MALLOC(ip, struct inode *, sizeof(struct inode), type, M_WAITOK);
725 	bzero((caddr_t)ip, sizeof(struct inode));
726 	vp->v_data = ip;
727 	ip->i_vnode = vp;
728 	ip->i_fs = fs = ump->um_fs;
729 	ip->i_dev = dev;
730 	ip->i_number = ino;
731 #ifdef QUOTA
732 	{
733 	int i;
734 	for (i = 0; i < MAXQUOTAS; i++)
735 		ip->i_dquot[i] = NODQUOT;
736 	}
737 #endif
738 	/*
739 	 * Put it onto its hash chain and lock it so that other requests for
740 	 * this inode will block if they arrive while we are sleeping waiting
741 	 * for old data structures to be purged or for the contents of the
742 	 * disk portion of this inode to be read.
743 	 */
744 	ufs_ihashins(ip);
745 
746 	/* Read in the disk contents for the inode, copy into the inode. */
747 	error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
748 	    (int)fs->fs_bsize, NOCRED, &bp);
749 	if (error) {
750 		/*
751 		 * The inode does not contain anything useful, so it would
752 		 * be misleading to leave it on its hash chain. With mode
753 		 * still zero, it will be unlinked and returned to the free
754 		 * list by vput().
755 		 */
756 		vput(vp);
757 		brelse(bp);
758 		*vpp = NULL;
759 		return (error);
760 	}
761 	ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ino));
762 	brelse(bp);
763 
764 	/*
765 	 * Initialize the vnode from the inode, check for aliases.
766 	 * Note that the underlying vnode may have changed.
767 	 */
768 	error = ufs_vinit(mp, ffs_specop_p, FFS_FIFOOPS, &vp);
769 	if (error) {
770 		vput(vp);
771 		*vpp = NULL;
772 		return (error);
773 	}
774 	/*
775 	 * Finish inode initialization now that aliasing has been resolved.
776 	 */
777 	ip->i_devvp = ump->um_devvp;
778 	VREF(ip->i_devvp);
779 	/*
780 	 * Set up a generation number for this inode if it does not
781 	 * already have one. This should only happen on old filesystems.
782 	 */
783 	if (ip->i_gen == 0) {
784 		if (++nextgennumber < (u_long)time.tv_sec)
785 			nextgennumber = time.tv_sec;
786 		ip->i_gen = nextgennumber;
787 		if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
788 			ip->i_flag |= IN_MODIFIED;
789 	}
790 	/*
791 	 * Ensure that uid and gid are correct. This is a temporary
792 	 * fix until fsck has been changed to do the update.
793 	 */
794 	if (fs->fs_inodefmt < FS_44INODEFMT) {		/* XXX */
795 		ip->i_uid = ip->i_din.di_ouid;		/* XXX */
796 		ip->i_gid = ip->i_din.di_ogid;		/* XXX */
797 	}						/* XXX */
798 
799 	*vpp = vp;
800 	return (0);
801 }
802 
803 /*
804  * File handle to vnode
805  *
806  * Have to be really careful about stale file handles:
807  * - check that the inode number is valid
808  * - call ffs_vget() to get the locked inode
809  * - check for an unallocated inode (i_mode == 0)
810  * - check that the given client host has export rights and return
811  *   those rights via. exflagsp and credanonp
812  */
813 int
814 ffs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
815 	register struct mount *mp;
816 	struct fid *fhp;
817 	struct mbuf *nam;
818 	struct vnode **vpp;
819 	int *exflagsp;
820 	struct ucred **credanonp;
821 {
822 	register struct ufid *ufhp;
823 	struct fs *fs;
824 
825 	ufhp = (struct ufid *)fhp;
826 	fs = VFSTOUFS(mp)->um_fs;
827 	if (ufhp->ufid_ino < ROOTINO ||
828 	    ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg)
829 		return (ESTALE);
830 	return (ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp));
831 }
832 
833 /*
834  * Vnode pointer to File handle
835  */
836 /* ARGSUSED */
837 int
838 ffs_vptofh(vp, fhp)
839 	struct vnode *vp;
840 	struct fid *fhp;
841 {
842 	register struct inode *ip;
843 	register struct ufid *ufhp;
844 
845 	ip = VTOI(vp);
846 	ufhp = (struct ufid *)fhp;
847 	ufhp->ufid_len = sizeof(struct ufid);
848 	ufhp->ufid_ino = ip->i_number;
849 	ufhp->ufid_gen = ip->i_gen;
850 	return (0);
851 }
852 
853 /*
854  * Write a superblock and associated information back to disk.
855  */
856 int
857 ffs_sbupdate(mp, waitfor)
858 	struct ufsmount *mp;
859 	int waitfor;
860 {
861 	register struct fs *fs = mp->um_fs;
862 	register struct buf *bp;
863 	int blks;
864 	caddr_t space;
865 	int i, size, error = 0;
866 
867 	bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0);
868 	bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize);
869 	/* Restore compatibility to old file systems.		   XXX */
870 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
871 		((struct fs *)bp->b_data)->fs_nrpos = -1;	/* XXX */
872 	if (waitfor == MNT_WAIT)
873 		error = bwrite(bp);
874 	else
875 		bawrite(bp);
876 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
877 	space = (caddr_t)fs->fs_csp[0];
878 	for (i = 0; i < blks; i += fs->fs_frag) {
879 		size = fs->fs_bsize;
880 		if (i + fs->fs_frag > blks)
881 			size = (blks - i) * fs->fs_fsize;
882 		bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i),
883 		    size, 0, 0);
884 		bcopy(space, bp->b_data, (u_int)size);
885 		space += size;
886 		if (waitfor == MNT_WAIT)
887 			error = bwrite(bp);
888 		else
889 			bawrite(bp);
890 	}
891 	return (error);
892 }
893