xref: /freebsd/sys/ufs/ffs/ffs_vfsops.c (revision b40ce4165d5eb3a5de1515245055350ae3dbab8e)
1df8bae1dSRodney W. Grimes /*
2df8bae1dSRodney W. Grimes  * Copyright (c) 1989, 1991, 1993, 1994
3df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
4df8bae1dSRodney W. Grimes  *
5df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
6df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
7df8bae1dSRodney W. Grimes  * are met:
8df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
9df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
10df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
11df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
12df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
13df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
14df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
15df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
16df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
17df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
18df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
19df8bae1dSRodney W. Grimes  *    without specific prior written permission.
20df8bae1dSRodney W. Grimes  *
21df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
32df8bae1dSRodney W. Grimes  *
33996c772fSJohn Dyson  *	@(#)ffs_vfsops.c	8.31 (Berkeley) 5/20/95
34c3aac50fSPeter Wemm  * $FreeBSD$
35df8bae1dSRodney W. Grimes  */
36df8bae1dSRodney W. Grimes 
3701733a9bSGarrett Wollman #include "opt_quota.h"
38516081f2SRobert Watson #include "opt_ufs.h"
3901733a9bSGarrett Wollman 
40df8bae1dSRodney W. Grimes #include <sys/param.h>
41df8bae1dSRodney W. Grimes #include <sys/systm.h>
42df8bae1dSRodney W. Grimes #include <sys/namei.h>
43df8bae1dSRodney W. Grimes #include <sys/proc.h>
44df8bae1dSRodney W. Grimes #include <sys/kernel.h>
45df8bae1dSRodney W. Grimes #include <sys/vnode.h>
46df8bae1dSRodney W. Grimes #include <sys/mount.h>
479626b608SPoul-Henning Kamp #include <sys/bio.h>
48df8bae1dSRodney W. Grimes #include <sys/buf.h>
4981bca6ddSKATO Takenori #include <sys/conf.h>
503ac4d1efSBruce Evans #include <sys/fcntl.h>
51df8bae1dSRodney W. Grimes #include <sys/disklabel.h>
52df8bae1dSRodney W. Grimes #include <sys/malloc.h>
531b367556SJason Evans #include <sys/mutex.h>
54a18b1f1dSJason Evans 
55a64ed089SRobert Watson #include <ufs/ufs/extattr.h>
56df8bae1dSRodney W. Grimes #include <ufs/ufs/quota.h>
57df8bae1dSRodney W. Grimes #include <ufs/ufs/ufsmount.h>
58df8bae1dSRodney W. Grimes #include <ufs/ufs/inode.h>
59df8bae1dSRodney W. Grimes #include <ufs/ufs/ufs_extern.h>
60df8bae1dSRodney W. Grimes 
61df8bae1dSRodney W. Grimes #include <ufs/ffs/fs.h>
62df8bae1dSRodney W. Grimes #include <ufs/ffs/ffs_extern.h>
63df8bae1dSRodney W. Grimes 
64f6b04d2bSDavid Greenman #include <vm/vm.h>
65f6b04d2bSDavid Greenman #include <vm/vm_page.h>
66f6b04d2bSDavid Greenman 
67a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_FFSNODE, "FFS node", "FFS vnode private part");
6855166637SPoul-Henning Kamp 
69b8dce649SPoul-Henning Kamp static int	ffs_sbupdate __P((struct ufsmount *, int));
70b40ce416SJulian Elischer int	ffs_reload __P((struct mount *,struct ucred *,struct thread *));
71b8dce649SPoul-Henning Kamp static int	ffs_oldfscompat __P((struct fs *));
72996c772fSJohn Dyson static int	ffs_init __P((struct vfsconf *));
73df8bae1dSRodney W. Grimes 
74303b270bSEivind Eklund static struct vfsops ufs_vfsops = {
75df8bae1dSRodney W. Grimes 	ffs_mount,
76df8bae1dSRodney W. Grimes 	ufs_start,
77df8bae1dSRodney W. Grimes 	ffs_unmount,
78df8bae1dSRodney W. Grimes 	ufs_root,
79df8bae1dSRodney W. Grimes 	ufs_quotactl,
80df8bae1dSRodney W. Grimes 	ffs_statfs,
81df8bae1dSRodney W. Grimes 	ffs_sync,
82df8bae1dSRodney W. Grimes 	ffs_vget,
83df8bae1dSRodney W. Grimes 	ffs_fhtovp,
84a13234bbSPoul-Henning Kamp 	vfs_stdcheckexp,
85df8bae1dSRodney W. Grimes 	ffs_vptofh,
86df8bae1dSRodney W. Grimes 	ffs_init,
8791f37dcbSRobert Watson 	vfs_stduninit,
88516081f2SRobert Watson #ifdef UFS_EXTATTR
89a64ed089SRobert Watson 	ufs_extattrctl,
90a64ed089SRobert Watson #else
9191f37dcbSRobert Watson 	vfs_stdextattrctl,
92a64ed089SRobert Watson #endif
93df8bae1dSRodney W. Grimes };
94df8bae1dSRodney W. Grimes 
958994ca3cSBruce Evans VFS_SET(ufs_vfsops, ufs, 0);
96c901836cSGarrett Wollman 
97df8bae1dSRodney W. Grimes /*
982b14f991SJulian Elischer  * ffs_mount
99df8bae1dSRodney W. Grimes  *
1002b14f991SJulian Elischer  * Called when mounting local physical media
101df8bae1dSRodney W. Grimes  *
1022b14f991SJulian Elischer  * PARAMETERS:
1032b14f991SJulian Elischer  *		mountroot
1042b14f991SJulian Elischer  *			mp	mount point structure
1052b14f991SJulian Elischer  *			path	NULL (flag for root mount!!!)
1062b14f991SJulian Elischer  *			data	<unused>
1072b14f991SJulian Elischer  *			ndp	<unused>
1082b14f991SJulian Elischer  *			p	process (user credentials check [statfs])
1092b14f991SJulian Elischer  *
1102b14f991SJulian Elischer  *		mount
1112b14f991SJulian Elischer  *			mp	mount point structure
1122b14f991SJulian Elischer  *			path	path to mount point
1132b14f991SJulian Elischer  *			data	pointer to argument struct in user space
1142b14f991SJulian Elischer  *			ndp	mount point namei() return (used for
1152b14f991SJulian Elischer  *				credentials on reload), reused to look
1162b14f991SJulian Elischer  *				up block device.
1172b14f991SJulian Elischer  *			p	process (user credentials check)
1182b14f991SJulian Elischer  *
1192b14f991SJulian Elischer  * RETURNS:	0	Success
1202b14f991SJulian Elischer  *		!0	error number (errno.h)
1212b14f991SJulian Elischer  *
1222b14f991SJulian Elischer  * LOCK STATE:
1232b14f991SJulian Elischer  *
1242b14f991SJulian Elischer  *		ENTRY
1252b14f991SJulian Elischer  *			mount point is locked
1262b14f991SJulian Elischer  *		EXIT
1272b14f991SJulian Elischer  *			mount point is locked
1282b14f991SJulian Elischer  *
1292b14f991SJulian Elischer  * NOTES:
1302b14f991SJulian Elischer  *		A NULL path can be used for a flag since the mount
1312b14f991SJulian Elischer  *		system call will fail with EFAULT in copyinstr in
1322b14f991SJulian Elischer  *		namei() if it is a genuine NULL from the user.
133df8bae1dSRodney W. Grimes  */
1340b0c10b4SAdrian Chadd int
135b40ce416SJulian Elischer ffs_mount(mp, path, data, ndp, td)
136996c772fSJohn Dyson         struct mount		*mp;	/* mount struct pointer*/
1372b14f991SJulian Elischer         char			*path;	/* path to mount point*/
1382b14f991SJulian Elischer         caddr_t			data;	/* arguments to FS specific mount*/
1392b14f991SJulian Elischer         struct nameidata	*ndp;	/* mount point credentials*/
140b40ce416SJulian Elischer         struct thread		*td;	/* process requesting mount*/
141df8bae1dSRodney W. Grimes {
1428435e0aeSDoug Rabson 	size_t		size;
143df8bae1dSRodney W. Grimes 	struct vnode	*devvp;
144df8bae1dSRodney W. Grimes 	struct ufs_args args;
14526f9a767SRodney W. Grimes 	struct ufsmount *ump = 0;
146df8bae1dSRodney W. Grimes 	register struct fs *fs;
147f2a2857bSKirk McKusick 	int error, flags;
148c9b99213SBruce Evans 	mode_t accessmode;
149df8bae1dSRodney W. Grimes 
1502b14f991SJulian Elischer 	/*
151f2a2857bSKirk McKusick 	 * Use NULL path to indicate we are mounting the root file system.
1522b14f991SJulian Elischer 	 */
1532b14f991SJulian Elischer 	if (path == NULL) {
154f2a2857bSKirk McKusick 		if ((error = bdevvp(rootdev, &rootvp))) {
1556d147828SMike Smith 			printf("ffs_mountroot: can't find rootvp\n");
156f2a2857bSKirk McKusick 			return (error);
157996c772fSJohn Dyson 		}
1582b14f991SJulian Elischer 
159b40ce416SJulian Elischer 		if ((error = ffs_mountfs(rootvp, mp, td, M_FFSNODE)) != 0)
160f2a2857bSKirk McKusick 			return (error);
1612b14f991SJulian Elischer 
162b40ce416SJulian Elischer 		(void)VFS_STATFS(mp, &mp->mnt_stat, td);
163f2a2857bSKirk McKusick 		return (0);
1642b14f991SJulian Elischer 	}
1652b14f991SJulian Elischer 
1662b14f991SJulian Elischer 	/*
1672b14f991SJulian Elischer 	 * Mounting non-root file system or updating a file system
1682b14f991SJulian Elischer 	 */
169f2a2857bSKirk McKusick 	if ((error = copyin(data, (caddr_t)&args, sizeof(struct ufs_args)))!= 0)
170f2a2857bSKirk McKusick 		return (error);
1712b14f991SJulian Elischer 
172df8bae1dSRodney W. Grimes 	/*
173df8bae1dSRodney W. Grimes 	 * If updating, check whether changing from read-only to
174df8bae1dSRodney W. Grimes 	 * read/write; if there is no device name, that's all we do.
175df8bae1dSRodney W. Grimes 	 */
176df8bae1dSRodney W. Grimes 	if (mp->mnt_flag & MNT_UPDATE) {
177df8bae1dSRodney W. Grimes 		ump = VFSTOUFS(mp);
178df8bae1dSRodney W. Grimes 		fs = ump->um_fs;
17926cf9c3bSPeter Wemm 		devvp = ump->um_devvp;
180f2a2857bSKirk McKusick 		if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
181f2a2857bSKirk McKusick 			if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0)
182f2a2857bSKirk McKusick 				return (error);
183df8bae1dSRodney W. Grimes 			flags = WRITECLOSE;
184df8bae1dSRodney W. Grimes 			if (mp->mnt_flag & MNT_FORCE)
185df8bae1dSRodney W. Grimes 				flags |= FORCECLOSE;
186b1897c19SJulian Elischer 			if (mp->mnt_flag & MNT_SOFTDEP) {
187b40ce416SJulian Elischer 				error = softdep_flushfiles(mp, flags, td);
188b1897c19SJulian Elischer 			} else {
189b40ce416SJulian Elischer 				error = ffs_flushfiles(mp, flags, td);
190df8bae1dSRodney W. Grimes 			}
191f2a2857bSKirk McKusick 			if (error) {
192f2a2857bSKirk McKusick 				vn_finished_write(mp);
193f2a2857bSKirk McKusick 				return (error);
194b1897c19SJulian Elischer 			}
1959ccb939eSKirk McKusick 			if (fs->fs_pendingblocks != 0 ||
1969ccb939eSKirk McKusick 			    fs->fs_pendinginodes != 0) {
1979ccb939eSKirk McKusick 				printf("%s: update error: blocks %d files %d\n",
1989ccb939eSKirk McKusick 				    fs->fs_fsmnt, fs->fs_pendingblocks,
1999ccb939eSKirk McKusick 				    fs->fs_pendinginodes);
2009ccb939eSKirk McKusick 				fs->fs_pendingblocks = 0;
2019ccb939eSKirk McKusick 				fs->fs_pendinginodes = 0;
2029ccb939eSKirk McKusick 			}
203f2a2857bSKirk McKusick 			fs->fs_ronly = 1;
2041a6a6610SKirk McKusick 			if ((fs->fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) == 0)
205f2a2857bSKirk McKusick 				fs->fs_clean = 1;
206f2a2857bSKirk McKusick 			if ((error = ffs_sbupdate(ump, MNT_WAIT)) != 0) {
207f2a2857bSKirk McKusick 				fs->fs_ronly = 0;
208f2a2857bSKirk McKusick 				fs->fs_clean = 0;
209f2a2857bSKirk McKusick 				vn_finished_write(mp);
210f2a2857bSKirk McKusick 				return (error);
2112b14f991SJulian Elischer 			}
212f2a2857bSKirk McKusick 			vn_finished_write(mp);
213f2a2857bSKirk McKusick 		}
214f2a2857bSKirk McKusick 		if ((mp->mnt_flag & MNT_RELOAD) &&
215b40ce416SJulian Elischer 		    (error = ffs_reload(mp, ndp->ni_cnd.cn_cred, td)) != 0)
216f2a2857bSKirk McKusick 			return (error);
217f2a2857bSKirk McKusick 		if (fs->fs_ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) {
218c9b99213SBruce Evans 			/*
219c9b99213SBruce Evans 			 * If upgrade to read-write by non-root, then verify
220c9b99213SBruce Evans 			 * that user has necessary permissions on the device.
221c9b99213SBruce Evans 			 */
222b40ce416SJulian Elischer 			if (td->td_proc->p_ucred->cr_uid != 0) {
223b40ce416SJulian Elischer 				vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
2248aef1712SMatthew Dillon 				if ((error = VOP_ACCESS(devvp, VREAD | VWRITE,
225b40ce416SJulian Elischer 				    td->td_proc->p_ucred, td)) != 0) {
226b40ce416SJulian Elischer 					VOP_UNLOCK(devvp, 0, td);
227c9b99213SBruce Evans 					return (error);
228c9b99213SBruce Evans 				}
229b40ce416SJulian Elischer 				VOP_UNLOCK(devvp, 0, td);
230c9b99213SBruce Evans 			}
2317e58bfacSBruce Evans 			fs->fs_flags &= ~FS_UNCLEAN;
2320922cce6SBruce Evans 			if (fs->fs_clean == 0) {
2337e58bfacSBruce Evans 				fs->fs_flags |= FS_UNCLEAN;
234812b1d41SKirk McKusick 				if ((mp->mnt_flag & MNT_FORCE) ||
2351a6a6610SKirk McKusick 				    ((fs->fs_flags & FS_NEEDSFSCK) == 0 &&
2361a6a6610SKirk McKusick 				     (fs->fs_flags & FS_DOSOFTDEP))) {
237f2a2857bSKirk McKusick 					printf("WARNING: %s was not %s\n",
238f2a2857bSKirk McKusick 					   fs->fs_fsmnt, "properly dismounted");
2390922cce6SBruce Evans 				} else {
2400922cce6SBruce Evans 					printf(
2410922cce6SBruce Evans "WARNING: R/W mount of %s denied.  Filesystem is not clean - run fsck\n",
2420922cce6SBruce Evans 					    fs->fs_fsmnt);
243f2a2857bSKirk McKusick 					return (EPERM);
2440922cce6SBruce Evans 				}
2450922cce6SBruce Evans 			}
246f2a2857bSKirk McKusick 			if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0)
247f2a2857bSKirk McKusick 				return (error);
248f2a2857bSKirk McKusick 			fs->fs_ronly = 0;
249f2a2857bSKirk McKusick 			fs->fs_clean = 0;
250f2a2857bSKirk McKusick 			if ((error = ffs_sbupdate(ump, MNT_WAIT)) != 0) {
251f2a2857bSKirk McKusick 				vn_finished_write(mp);
252f2a2857bSKirk McKusick 				return (error);
253f2a2857bSKirk McKusick 			}
25426cf9c3bSPeter Wemm 			/* check to see if we need to start softdep */
255f2a2857bSKirk McKusick 			if ((fs->fs_flags & FS_DOSOFTDEP) &&
256b40ce416SJulian Elischer 			    (error = softdep_mount(devvp, mp, fs, td->td_proc->p_ucred))){
257f2a2857bSKirk McKusick 				vn_finished_write(mp);
258f2a2857bSKirk McKusick 				return (error);
25926cf9c3bSPeter Wemm 			}
260f2a2857bSKirk McKusick 			if (fs->fs_snapinum[0] != 0)
261f2a2857bSKirk McKusick 				ffs_snapshot_mount(mp);
262f2a2857bSKirk McKusick 			vn_finished_write(mp);
2631469eec8SDavid Greenman 		}
264c11d2981SJulian Elischer 		/*
265c11d2981SJulian Elischer 		 * Soft updates is incompatible with "async",
266c11d2981SJulian Elischer 		 * so if we are doing softupdates stop the user
267c11d2981SJulian Elischer 		 * from setting the async flag in an update.
268c11d2981SJulian Elischer 		 * Softdep_mount() clears it in an initial mount
269c11d2981SJulian Elischer 		 * or ro->rw remount.
270c11d2981SJulian Elischer 		 */
271f2a2857bSKirk McKusick 		if (mp->mnt_flag & MNT_SOFTDEP)
272c11d2981SJulian Elischer 			mp->mnt_flag &= ~MNT_ASYNC;
273df8bae1dSRodney W. Grimes 		/*
274f2a2857bSKirk McKusick 		 * If not updating name, process export requests.
275df8bae1dSRodney W. Grimes 		 */
276f2a2857bSKirk McKusick 		if (args.fspec == 0)
277a13234bbSPoul-Henning Kamp 			return (vfs_export(mp, &args.export));
278f2a2857bSKirk McKusick 		/*
279f2a2857bSKirk McKusick 		 * If this is a snapshot request, take the snapshot.
280f2a2857bSKirk McKusick 		 */
281f2a2857bSKirk McKusick 		if (mp->mnt_flag & MNT_SNAPSHOT)
282f2a2857bSKirk McKusick 			return (ffs_snapshot(mp, args.fspec));
283df8bae1dSRodney W. Grimes 	}
2842b14f991SJulian Elischer 
285df8bae1dSRodney W. Grimes 	/*
286df8bae1dSRodney W. Grimes 	 * Not an update, or updating the name: look up the name
287df8bae1dSRodney W. Grimes 	 * and verify that it refers to a sensible block device.
288df8bae1dSRodney W. Grimes 	 */
289b40ce416SJulian Elischer 	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, td);
290f2a2857bSKirk McKusick 	if ((error = namei(ndp)) != 0)
291f2a2857bSKirk McKusick 		return (error);
292762e6b85SEivind Eklund 	NDFREE(ndp, NDF_ONLY_PNBUF);
293df8bae1dSRodney W. Grimes 	devvp = ndp->ni_vp;
294f2a2857bSKirk McKusick 	if (!vn_isdisk(devvp, &error)) {
295f2a2857bSKirk McKusick 		vrele(devvp);
296f2a2857bSKirk McKusick 		return (error);
297f2a2857bSKirk McKusick 	}
298c9b99213SBruce Evans 
299c9b99213SBruce Evans 	/*
300c9b99213SBruce Evans 	 * If mount by non-root, then verify that user has necessary
301c9b99213SBruce Evans 	 * permissions on the device.
302c9b99213SBruce Evans 	 */
303b40ce416SJulian Elischer 	if (td->td_proc->p_ucred->cr_uid != 0) {
304c9b99213SBruce Evans 		accessmode = VREAD;
305c9b99213SBruce Evans 		if ((mp->mnt_flag & MNT_RDONLY) == 0)
306c9b99213SBruce Evans 			accessmode |= VWRITE;
307b40ce416SJulian Elischer 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
308b40ce416SJulian Elischer 		if ((error = VOP_ACCESS(devvp, accessmode, td->td_proc->p_ucred, td))!= 0){
309c9b99213SBruce Evans 			vput(devvp);
310c9b99213SBruce Evans 			return (error);
311c9b99213SBruce Evans 		}
312b40ce416SJulian Elischer 		VOP_UNLOCK(devvp, 0, td);
313c9b99213SBruce Evans 	}
314c9b99213SBruce Evans 
3152b14f991SJulian Elischer 	if (mp->mnt_flag & MNT_UPDATE) {
3162b14f991SJulian Elischer 		/*
317f2a2857bSKirk McKusick 		 * Update only
318f2a2857bSKirk McKusick 		 *
3193e425b96SJulian Elischer 		 * If it's not the same vnode, or at least the same device
3203e425b96SJulian Elischer 		 * then it's not correct.
3212b14f991SJulian Elischer 		 */
3222b14f991SJulian Elischer 
323f2a2857bSKirk McKusick 		if (devvp != ump->um_devvp &&
324f2a2857bSKirk McKusick 		    devvp->v_rdev != ump->um_devvp->v_rdev)
325f2a2857bSKirk McKusick 			error = EINVAL;	/* needs translation */
3263e425b96SJulian Elischer 		vrele(devvp);
327f2a2857bSKirk McKusick 		if (error)
328f2a2857bSKirk McKusick 			return (error);
3292b14f991SJulian Elischer 	} else {
3302b14f991SJulian Elischer 		/*
331f2a2857bSKirk McKusick 		 * New mount
3322b14f991SJulian Elischer 		 *
333f2a2857bSKirk McKusick 		 * We need the name for the mount point (also used for
334f2a2857bSKirk McKusick 		 * "last mounted on") copied in. If an error occurs,
335f2a2857bSKirk McKusick 		 * the mount point is discarded by the upper level code.
336f3a90da9SAdrian Chadd 		 * Note that vfs_mount() populates f_mntonname for us.
337f2a2857bSKirk McKusick 		 */
338b40ce416SJulian Elischer 		if ((error = ffs_mountfs(devvp, mp, td, M_FFSNODE)) != 0) {
339f2a2857bSKirk McKusick 			vrele(devvp);
340f2a2857bSKirk McKusick 			return (error);
341f2a2857bSKirk McKusick 		}
342f2a2857bSKirk McKusick 	}
343f2a2857bSKirk McKusick 	/*
344f2a2857bSKirk McKusick 	 * Save "mounted from" device name info for mount point (NULL pad).
345f2a2857bSKirk McKusick 	 */
346f2a2857bSKirk McKusick 	copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
347f2a2857bSKirk McKusick 	bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
348f2a2857bSKirk McKusick 	/*
349f2a2857bSKirk McKusick 	 * Initialize filesystem stat information in mount struct.
3502b14f991SJulian Elischer 	 */
351b40ce416SJulian Elischer 	(void)VFS_STATFS(mp, &mp->mnt_stat, td);
352f2a2857bSKirk McKusick 	return (0);
3532b14f991SJulian Elischer }
3542b14f991SJulian Elischer 
355df8bae1dSRodney W. Grimes /*
356df8bae1dSRodney W. Grimes  * Reload all incore data for a filesystem (used after running fsck on
357df8bae1dSRodney W. Grimes  * the root filesystem and finding things to fix). The filesystem must
358df8bae1dSRodney W. Grimes  * be mounted read-only.
359df8bae1dSRodney W. Grimes  *
360df8bae1dSRodney W. Grimes  * Things to do to update the mount:
361df8bae1dSRodney W. Grimes  *	1) invalidate all cached meta-data.
362df8bae1dSRodney W. Grimes  *	2) re-read superblock from disk.
363df8bae1dSRodney W. Grimes  *	3) re-read summary information from disk.
364df8bae1dSRodney W. Grimes  *	4) invalidate all inactive vnodes.
365df8bae1dSRodney W. Grimes  *	5) invalidate all cached file data.
366df8bae1dSRodney W. Grimes  *	6) re-read inode data for all active vnodes.
367df8bae1dSRodney W. Grimes  */
3680b0c10b4SAdrian Chadd int
369b40ce416SJulian Elischer ffs_reload(mp, cred, td)
3702b14f991SJulian Elischer 	register struct mount *mp;
371df8bae1dSRodney W. Grimes 	struct ucred *cred;
372b40ce416SJulian Elischer 	struct thread *td;
373df8bae1dSRodney W. Grimes {
374df8bae1dSRodney W. Grimes 	register struct vnode *vp, *nvp, *devvp;
375df8bae1dSRodney W. Grimes 	struct inode *ip;
376f55ff3f3SIan Dowse 	void *space;
377df8bae1dSRodney W. Grimes 	struct buf *bp;
378996c772fSJohn Dyson 	struct fs *fs, *newfs;
379996c772fSJohn Dyson 	struct partinfo dpart;
38095e5e988SJohn Dyson 	dev_t dev;
381df8bae1dSRodney W. Grimes 	int i, blks, size, error;
382996c772fSJohn Dyson 	int32_t *lp;
383df8bae1dSRodney W. Grimes 
3842b14f991SJulian Elischer 	if ((mp->mnt_flag & MNT_RDONLY) == 0)
385df8bae1dSRodney W. Grimes 		return (EINVAL);
386df8bae1dSRodney W. Grimes 	/*
387df8bae1dSRodney W. Grimes 	 * Step 1: invalidate all cached meta-data.
388df8bae1dSRodney W. Grimes 	 */
3892b14f991SJulian Elischer 	devvp = VFSTOUFS(mp)->um_devvp;
390b40ce416SJulian Elischer 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
391b40ce416SJulian Elischer 	error = vinvalbuf(devvp, 0, cred, td, 0, 0);
392b40ce416SJulian Elischer 	VOP_UNLOCK(devvp, 0, td);
393b1897c19SJulian Elischer 	if (error)
394df8bae1dSRodney W. Grimes 		panic("ffs_reload: dirty1");
39595e5e988SJohn Dyson 
39695e5e988SJohn Dyson 	dev = devvp->v_rdev;
397b5ee1640SBruce Evans 
39895e5e988SJohn Dyson 	/*
39995e5e988SJohn Dyson 	 * Only VMIO the backing device if the backing device is a real
400c7a3e237SPoul-Henning Kamp 	 * block device.
40195e5e988SJohn Dyson 	 */
402c7a3e237SPoul-Henning Kamp 	if (vn_isdisk(devvp, NULL)) {
403b40ce416SJulian Elischer 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
404b40ce416SJulian Elischer 		vfs_object_create(devvp, td, td->td_proc->p_ucred);
4059ed346baSBosko Milekic 		mtx_lock(&devvp->v_interlock);
406b40ce416SJulian Elischer 		VOP_UNLOCK(devvp, LK_INTERLOCK, td);
40795e5e988SJohn Dyson 	}
40895e5e988SJohn Dyson 
409df8bae1dSRodney W. Grimes 	/*
410df8bae1dSRodney W. Grimes 	 * Step 2: re-read superblock from disk.
411df8bae1dSRodney W. Grimes 	 */
412b40ce416SJulian Elischer 	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, td) != 0)
413996c772fSJohn Dyson 		size = DEV_BSIZE;
414996c772fSJohn Dyson 	else
415996c772fSJohn Dyson 		size = dpart.disklab->d_secsize;
4168aef1712SMatthew Dillon 	if ((error = bread(devvp, (ufs_daddr_t)(SBOFF/size), SBSIZE, NOCRED,&bp)) != 0)
417df8bae1dSRodney W. Grimes 		return (error);
418996c772fSJohn Dyson 	newfs = (struct fs *)bp->b_data;
419996c772fSJohn Dyson 	if (newfs->fs_magic != FS_MAGIC || newfs->fs_bsize > MAXBSIZE ||
420996c772fSJohn Dyson 		newfs->fs_bsize < sizeof(struct fs)) {
421df8bae1dSRodney W. Grimes 			brelse(bp);
422df8bae1dSRodney W. Grimes 			return (EIO);		/* XXX needs translation */
423df8bae1dSRodney W. Grimes 	}
4242b14f991SJulian Elischer 	fs = VFSTOUFS(mp)->um_fs;
425996c772fSJohn Dyson 	/*
426996c772fSJohn Dyson 	 * Copy pointer fields back into superblock before copying in	XXX
427996c772fSJohn Dyson 	 * new superblock. These should really be in the ufsmount.	XXX
428996c772fSJohn Dyson 	 * Note that important parameters (eg fs_ncg) are unchanged.
429996c772fSJohn Dyson 	 */
430f55ff3f3SIan Dowse 	newfs->fs_csp = fs->fs_csp;
431996c772fSJohn Dyson 	newfs->fs_maxcluster = fs->fs_maxcluster;
4325d69bac4SIan Dowse 	newfs->fs_contigdirs = fs->fs_contigdirs;
433996c772fSJohn Dyson 	bcopy(newfs, fs, (u_int)fs->fs_sbsize);
434df8bae1dSRodney W. Grimes 	if (fs->fs_sbsize < SBSIZE)
435f2a2857bSKirk McKusick 		bp->b_flags |= B_INVAL | B_NOCACHE;
436df8bae1dSRodney W. Grimes 	brelse(bp);
437996c772fSJohn Dyson 	mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
438df8bae1dSRodney W. Grimes 	ffs_oldfscompat(fs);
4395d69bac4SIan Dowse 	/* An old fsck may have zeroed these fields, so recheck them. */
4405d69bac4SIan Dowse 	if (fs->fs_avgfilesize <= 0)		/* XXX */
4415d69bac4SIan Dowse 		fs->fs_avgfilesize = AVFILESIZ;	/* XXX */
4425d69bac4SIan Dowse 	if (fs->fs_avgfpdir <= 0)		/* XXX */
4435d69bac4SIan Dowse 		fs->fs_avgfpdir = AFPDIR;	/* XXX */
4449ccb939eSKirk McKusick 	if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
4459ccb939eSKirk McKusick 		printf("%s: reload pending error: blocks %d files %d\n",
4469ccb939eSKirk McKusick 		    fs->fs_fsmnt, fs->fs_pendingblocks, fs->fs_pendinginodes);
4479ccb939eSKirk McKusick 		fs->fs_pendingblocks = 0;
4489ccb939eSKirk McKusick 		fs->fs_pendinginodes = 0;
4499ccb939eSKirk McKusick 	}
450996c772fSJohn Dyson 
451df8bae1dSRodney W. Grimes 	/*
452df8bae1dSRodney W. Grimes 	 * Step 3: re-read summary information from disk.
453df8bae1dSRodney W. Grimes 	 */
454df8bae1dSRodney W. Grimes 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
455f55ff3f3SIan Dowse 	space = fs->fs_csp;
456df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
457df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
458df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
459df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
460c9671602SPoul-Henning Kamp 		error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
461c9671602SPoul-Henning Kamp 		    NOCRED, &bp);
462c9671602SPoul-Henning Kamp 		if (error)
463df8bae1dSRodney W. Grimes 			return (error);
464f55ff3f3SIan Dowse 		bcopy(bp->b_data, space, (u_int)size);
465f55ff3f3SIan Dowse 		space = (char *)space + size;
466df8bae1dSRodney W. Grimes 		brelse(bp);
467df8bae1dSRodney W. Grimes 	}
468996c772fSJohn Dyson 	/*
469996c772fSJohn Dyson 	 * We no longer know anything about clusters per cylinder group.
470996c772fSJohn Dyson 	 */
471996c772fSJohn Dyson 	if (fs->fs_contigsumsize > 0) {
472996c772fSJohn Dyson 		lp = fs->fs_maxcluster;
473996c772fSJohn Dyson 		for (i = 0; i < fs->fs_ncg; i++)
474996c772fSJohn Dyson 			*lp++ = fs->fs_contigsumsize;
475996c772fSJohn Dyson 	}
476996c772fSJohn Dyson 
477df8bae1dSRodney W. Grimes loop:
4789ed346baSBosko Milekic 	mtx_lock(&mntvnode_mtx);
479fc2ffbe6SPoul-Henning Kamp 	for (vp = LIST_FIRST(&mp->mnt_vnodelist); vp != NULL; vp = nvp) {
480996c772fSJohn Dyson 		if (vp->v_mount != mp) {
4819ed346baSBosko Milekic 			mtx_unlock(&mntvnode_mtx);
482996c772fSJohn Dyson 			goto loop;
483996c772fSJohn Dyson 		}
484fc2ffbe6SPoul-Henning Kamp 		nvp = LIST_NEXT(vp, v_mntvnodes);
485ed87274dSJohn Baldwin 		mtx_unlock(&mntvnode_mtx);
486df8bae1dSRodney W. Grimes 		/*
487df8bae1dSRodney W. Grimes 		 * Step 4: invalidate all inactive vnodes.
488df8bae1dSRodney W. Grimes 		 */
489b40ce416SJulian Elischer 		if (vrecycle(vp, NULL, td))
490996c772fSJohn Dyson 			goto loop;
491df8bae1dSRodney W. Grimes 		/*
492df8bae1dSRodney W. Grimes 		 * Step 5: invalidate all cached file data.
493df8bae1dSRodney W. Grimes 		 */
49449d2d9f4SJohn Baldwin 		mtx_lock(&vp->v_interlock);
495b40ce416SJulian Elischer 		if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) {
496df8bae1dSRodney W. Grimes 			goto loop;
497996c772fSJohn Dyson 		}
498b40ce416SJulian Elischer 		if (vinvalbuf(vp, 0, cred, td, 0, 0))
499df8bae1dSRodney W. Grimes 			panic("ffs_reload: dirty2");
500df8bae1dSRodney W. Grimes 		/*
501df8bae1dSRodney W. Grimes 		 * Step 6: re-read inode data for all active vnodes.
502df8bae1dSRodney W. Grimes 		 */
503df8bae1dSRodney W. Grimes 		ip = VTOI(vp);
504c9671602SPoul-Henning Kamp 		error =
505df8bae1dSRodney W. Grimes 		    bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
506c9671602SPoul-Henning Kamp 		    (int)fs->fs_bsize, NOCRED, &bp);
507c9671602SPoul-Henning Kamp 		if (error) {
508df8bae1dSRodney W. Grimes 			vput(vp);
509df8bae1dSRodney W. Grimes 			return (error);
510df8bae1dSRodney W. Grimes 		}
511df8bae1dSRodney W. Grimes 		ip->i_din = *((struct dinode *)bp->b_data +
512df8bae1dSRodney W. Grimes 		    ino_to_fsbo(fs, ip->i_number));
513b1897c19SJulian Elischer 		ip->i_effnlink = ip->i_nlink;
514df8bae1dSRodney W. Grimes 		brelse(bp);
515df8bae1dSRodney W. Grimes 		vput(vp);
5169ed346baSBosko Milekic 		mtx_lock(&mntvnode_mtx);
517df8bae1dSRodney W. Grimes 	}
5189ed346baSBosko Milekic 	mtx_unlock(&mntvnode_mtx);
519df8bae1dSRodney W. Grimes 	return (0);
520df8bae1dSRodney W. Grimes }
521df8bae1dSRodney W. Grimes 
5225819ab3fSKirk McKusick #include <sys/sysctl.h>
5235819ab3fSKirk McKusick int bigcgs = 0;
5245819ab3fSKirk McKusick SYSCTL_INT(_debug, OID_AUTO, bigcgs, CTLFLAG_RW, &bigcgs, 0, "");
5255819ab3fSKirk McKusick 
526df8bae1dSRodney W. Grimes /*
527df8bae1dSRodney W. Grimes  * Common code for mount and mountroot
528df8bae1dSRodney W. Grimes  */
529df8bae1dSRodney W. Grimes int
530b40ce416SJulian Elischer ffs_mountfs(devvp, mp, td, malloctype)
531df8bae1dSRodney W. Grimes 	register struct vnode *devvp;
532df8bae1dSRodney W. Grimes 	struct mount *mp;
533b40ce416SJulian Elischer 	struct thread *td;
5340be6b890SPoul-Henning Kamp 	struct malloc_type *malloctype;
535df8bae1dSRodney W. Grimes {
536df8bae1dSRodney W. Grimes 	register struct ufsmount *ump;
537df8bae1dSRodney W. Grimes 	struct buf *bp;
538df8bae1dSRodney W. Grimes 	register struct fs *fs;
539996c772fSJohn Dyson 	dev_t dev;
540df8bae1dSRodney W. Grimes 	struct partinfo dpart;
541f55ff3f3SIan Dowse 	void *space;
542f5ef029eSPoul-Henning Kamp 	int error, i, blks, size, ronly;
543996c772fSJohn Dyson 	int32_t *lp;
544996c772fSJohn Dyson 	struct ucred *cred;
545996c772fSJohn Dyson 	u_int64_t maxfilesize;					/* XXX */
5468435e0aeSDoug Rabson 	size_t strsize;
5476476c0d2SJohn Dyson 	int ncount;
548df8bae1dSRodney W. Grimes 
549996c772fSJohn Dyson 	dev = devvp->v_rdev;
550b40ce416SJulian Elischer 	cred = td ? td->td_proc->p_ucred : NOCRED;
551df8bae1dSRodney W. Grimes 	/*
552df8bae1dSRodney W. Grimes 	 * Disallow multiple mounts of the same device.
553df8bae1dSRodney W. Grimes 	 * Disallow mounting of a device that is currently in use
554df8bae1dSRodney W. Grimes 	 * (except for root, which might share swap device for miniroot).
555df8bae1dSRodney W. Grimes 	 * Flush out any old buffers remaining from a previous use.
556df8bae1dSRodney W. Grimes 	 */
557c9671602SPoul-Henning Kamp 	error = vfs_mountedon(devvp);
558c9671602SPoul-Henning Kamp 	if (error)
559df8bae1dSRodney W. Grimes 		return (error);
5606476c0d2SJohn Dyson 	ncount = vcount(devvp);
5618f9110f6SJohn Dyson 
5626476c0d2SJohn Dyson 	if (ncount > 1 && devvp != rootvp)
563df8bae1dSRodney W. Grimes 		return (EBUSY);
564b40ce416SJulian Elischer 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
565b40ce416SJulian Elischer 	error = vinvalbuf(devvp, V_SAVE, cred, td, 0, 0);
566b40ce416SJulian Elischer 	VOP_UNLOCK(devvp, 0, td);
567b1897c19SJulian Elischer 	if (error)
568df8bae1dSRodney W. Grimes 		return (error);
569df8bae1dSRodney W. Grimes 
57095e5e988SJohn Dyson 	/*
57195e5e988SJohn Dyson 	 * Only VMIO the backing device if the backing device is a real
572c7a3e237SPoul-Henning Kamp 	 * block device.
57395e5e988SJohn Dyson 	 * Note that it is optional that the backing device be VMIOed.  This
57495e5e988SJohn Dyson 	 * increases the opportunity for metadata caching.
57595e5e988SJohn Dyson 	 */
576c7a3e237SPoul-Henning Kamp 	if (vn_isdisk(devvp, NULL)) {
577b40ce416SJulian Elischer 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
578b40ce416SJulian Elischer 		vfs_object_create(devvp, td, cred);
5799ed346baSBosko Milekic 		mtx_lock(&devvp->v_interlock);
580b40ce416SJulian Elischer 		VOP_UNLOCK(devvp, LK_INTERLOCK, td);
58195e5e988SJohn Dyson 	}
58295e5e988SJohn Dyson 
583df8bae1dSRodney W. Grimes 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
584b40ce416SJulian Elischer 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
585b40ce416SJulian Elischer 	error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, td);
586b40ce416SJulian Elischer 	VOP_UNLOCK(devvp, 0, td);
587c9671602SPoul-Henning Kamp 	if (error)
588df8bae1dSRodney W. Grimes 		return (error);
5891b5464efSPoul-Henning Kamp 	if (devvp->v_rdev->si_iosize_max > mp->mnt_iosize_max)
5901b5464efSPoul-Henning Kamp 		mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max;
5911b5464efSPoul-Henning Kamp 	if (mp->mnt_iosize_max > MAXPHYS)
5921b5464efSPoul-Henning Kamp 		mp->mnt_iosize_max = MAXPHYS;
59395e5e988SJohn Dyson 
594b40ce416SJulian Elischer 	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, td) != 0)
595df8bae1dSRodney W. Grimes 		size = DEV_BSIZE;
596996c772fSJohn Dyson 	else
597df8bae1dSRodney W. Grimes 		size = dpart.disklab->d_secsize;
598df8bae1dSRodney W. Grimes 
599df8bae1dSRodney W. Grimes 	bp = NULL;
600df8bae1dSRodney W. Grimes 	ump = NULL;
6018aef1712SMatthew Dillon 	if ((error = bread(devvp, SBLOCK, SBSIZE, cred, &bp)) != 0)
602df8bae1dSRodney W. Grimes 		goto out;
603df8bae1dSRodney W. Grimes 	fs = (struct fs *)bp->b_data;
604df8bae1dSRodney W. Grimes 	if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
605df8bae1dSRodney W. Grimes 	    fs->fs_bsize < sizeof(struct fs)) {
606df8bae1dSRodney W. Grimes 		error = EINVAL;		/* XXX needs translation */
607df8bae1dSRodney W. Grimes 		goto out;
608df8bae1dSRodney W. Grimes 	}
6093f6f17eeSJulian Elischer 	fs->fs_fmod = 0;
6100922cce6SBruce Evans 	fs->fs_flags &= ~FS_UNCLEAN;
6110922cce6SBruce Evans 	if (fs->fs_clean == 0) {
6120922cce6SBruce Evans 		fs->fs_flags |= FS_UNCLEAN;
613812b1d41SKirk McKusick 		if (ronly || (mp->mnt_flag & MNT_FORCE) ||
6141a6a6610SKirk McKusick 		    ((fs->fs_flags & FS_NEEDSFSCK) == 0 &&
6151a6a6610SKirk McKusick 		     (fs->fs_flags & FS_DOSOFTDEP))) {
6160922cce6SBruce Evans 			printf(
6170922cce6SBruce Evans "WARNING: %s was not properly dismounted\n",
6180922cce6SBruce Evans 			    fs->fs_fsmnt);
6191469eec8SDavid Greenman 		} else {
6200922cce6SBruce Evans 			printf(
6210922cce6SBruce Evans "WARNING: R/W mount of %s denied.  Filesystem is not clean - run fsck\n",
6220922cce6SBruce Evans 			    fs->fs_fsmnt);
6231469eec8SDavid Greenman 			error = EPERM;
6241469eec8SDavid Greenman 			goto out;
6251469eec8SDavid Greenman 		}
6269ccb939eSKirk McKusick 		if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
6279ccb939eSKirk McKusick 			printf("%s: lost blocks %d files %d\n", fs->fs_fsmnt,
6289ccb939eSKirk McKusick 			    fs->fs_pendingblocks, fs->fs_pendinginodes);
6299ccb939eSKirk McKusick 			fs->fs_pendingblocks = 0;
6309ccb939eSKirk McKusick 			fs->fs_pendinginodes = 0;
6319ccb939eSKirk McKusick 		}
6329ccb939eSKirk McKusick 	}
6339ccb939eSKirk McKusick 	if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
6349ccb939eSKirk McKusick 		printf("%s: mount pending error: blocks %d files %d\n",
6359ccb939eSKirk McKusick 		    fs->fs_fsmnt, fs->fs_pendingblocks, fs->fs_pendinginodes);
6369ccb939eSKirk McKusick 		fs->fs_pendingblocks = 0;
6379ccb939eSKirk McKusick 		fs->fs_pendinginodes = 0;
6381469eec8SDavid Greenman 	}
639996c772fSJohn Dyson 	/* XXX updating 4.2 FFS superblocks trashes rotational layout tables */
640996c772fSJohn Dyson 	if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) {
641996c772fSJohn Dyson 		error = EROFS;          /* needs translation */
642996c772fSJohn Dyson 		goto out;
643996c772fSJohn Dyson 	}
6447cc0979fSDavid Malone 	ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK | M_ZERO);
6450be6b890SPoul-Henning Kamp 	ump->um_malloctype = malloctype;
6465bd5c8b9SBruce Evans 	ump->um_i_effnlink_valid = 1;
647df8bae1dSRodney W. Grimes 	ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT,
648df8bae1dSRodney W. Grimes 	    M_WAITOK);
649cec0f20cSPoul-Henning Kamp 	ump->um_blkatoff = ffs_blkatoff;
650cec0f20cSPoul-Henning Kamp 	ump->um_truncate = ffs_truncate;
651987f5696SPoul-Henning Kamp 	ump->um_update = ffs_update;
652cec0f20cSPoul-Henning Kamp 	ump->um_valloc = ffs_valloc;
653cec0f20cSPoul-Henning Kamp 	ump->um_vfree = ffs_vfree;
654855aa097SPoul-Henning Kamp 	ump->um_balloc = ffs_balloc;
655df8bae1dSRodney W. Grimes 	bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize);
656df8bae1dSRodney W. Grimes 	if (fs->fs_sbsize < SBSIZE)
657f2a2857bSKirk McKusick 		bp->b_flags |= B_INVAL | B_NOCACHE;
658df8bae1dSRodney W. Grimes 	brelse(bp);
659df8bae1dSRodney W. Grimes 	bp = NULL;
660df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
661df8bae1dSRodney W. Grimes 	fs->fs_ronly = ronly;
662996c772fSJohn Dyson 	size = fs->fs_cssize;
663996c772fSJohn Dyson 	blks = howmany(size, fs->fs_fsize);
664996c772fSJohn Dyson 	if (fs->fs_contigsumsize > 0)
665996c772fSJohn Dyson 		size += fs->fs_ncg * sizeof(int32_t);
666a61ab64aSKirk McKusick 	size += fs->fs_ncg * sizeof(u_int8_t);
667f55ff3f3SIan Dowse 	space = malloc((u_long)size, M_UFSMNT, M_WAITOK);
668f55ff3f3SIan Dowse 	fs->fs_csp = space;
669df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
670df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
671df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
672df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
6738aef1712SMatthew Dillon 		if ((error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
6748aef1712SMatthew Dillon 		    cred, &bp)) != 0) {
675f55ff3f3SIan Dowse 			free(fs->fs_csp, M_UFSMNT);
676df8bae1dSRodney W. Grimes 			goto out;
677df8bae1dSRodney W. Grimes 		}
678df8bae1dSRodney W. Grimes 		bcopy(bp->b_data, space, (u_int)size);
679f55ff3f3SIan Dowse 		space = (char *)space + size;
680df8bae1dSRodney W. Grimes 		brelse(bp);
681df8bae1dSRodney W. Grimes 		bp = NULL;
682df8bae1dSRodney W. Grimes 	}
683996c772fSJohn Dyson 	if (fs->fs_contigsumsize > 0) {
684f55ff3f3SIan Dowse 		fs->fs_maxcluster = lp = space;
685996c772fSJohn Dyson 		for (i = 0; i < fs->fs_ncg; i++)
686996c772fSJohn Dyson 			*lp++ = fs->fs_contigsumsize;
6874691e9eaSIan Dowse 		space = lp;
688996c772fSJohn Dyson 	}
689a61ab64aSKirk McKusick 	size = fs->fs_ncg * sizeof(u_int8_t);
690a61ab64aSKirk McKusick 	fs->fs_contigdirs = (u_int8_t *)space;
691a61ab64aSKirk McKusick 	bzero(fs->fs_contigdirs, size);
692a61ab64aSKirk McKusick 	/* Compatibility for old filesystems 	   XXX */
693a61ab64aSKirk McKusick 	if (fs->fs_avgfilesize <= 0)		/* XXX */
694a61ab64aSKirk McKusick 		fs->fs_avgfilesize = AVFILESIZ;	/* XXX */
695a61ab64aSKirk McKusick 	if (fs->fs_avgfpdir <= 0)		/* XXX */
696a61ab64aSKirk McKusick 		fs->fs_avgfpdir = AFPDIR;	/* XXX */
697df8bae1dSRodney W. Grimes 	mp->mnt_data = (qaddr_t)ump;
69868de329eSPoul-Henning Kamp 	mp->mnt_stat.f_fsid.val[0] = fs->fs_id[0];
6998f89943eSGuido van Rooij 	mp->mnt_stat.f_fsid.val[1] = fs->fs_id[1];
70068de329eSPoul-Henning Kamp 	if (fs->fs_id[0] == 0 || fs->fs_id[1] == 0 ||
70168de329eSPoul-Henning Kamp 	    vfs_getvfs(&mp->mnt_stat.f_fsid))
70268de329eSPoul-Henning Kamp 		vfs_getnewfsid(mp);
703df8bae1dSRodney W. Grimes 	mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
704cc9d8990SPeter Wemm 	mp->mnt_flag |= MNT_LOCAL;
705df8bae1dSRodney W. Grimes 	ump->um_mountp = mp;
706df8bae1dSRodney W. Grimes 	ump->um_dev = dev;
707df8bae1dSRodney W. Grimes 	ump->um_devvp = devvp;
708df8bae1dSRodney W. Grimes 	ump->um_nindir = fs->fs_nindir;
709df8bae1dSRodney W. Grimes 	ump->um_bptrtodb = fs->fs_fsbtodb;
710df8bae1dSRodney W. Grimes 	ump->um_seqinc = fs->fs_frag;
711df8bae1dSRodney W. Grimes 	for (i = 0; i < MAXQUOTAS; i++)
712df8bae1dSRodney W. Grimes 		ump->um_quotas[i] = NULLVP;
713516081f2SRobert Watson #ifdef UFS_EXTATTR
714a64ed089SRobert Watson 	ufs_extattr_uepm_init(&ump->um_extattr);
715a64ed089SRobert Watson #endif
7167eb9fca5SEivind Eklund 	devvp->v_rdev->si_mountpoint = mp;
717df8bae1dSRodney W. Grimes 	ffs_oldfscompat(fs);
7182b14f991SJulian Elischer 
7192b14f991SJulian Elischer 	/*
7202b14f991SJulian Elischer 	 * Set FS local "last mounted on" information (NULL pad)
7212b14f991SJulian Elischer 	 */
7222b14f991SJulian Elischer 	copystr(	mp->mnt_stat.f_mntonname,	/* mount point*/
7232b14f991SJulian Elischer 			fs->fs_fsmnt,			/* copy area*/
7242b14f991SJulian Elischer 			sizeof(fs->fs_fsmnt) - 1,	/* max size*/
7252b14f991SJulian Elischer 			&strsize);			/* real size*/
7262b14f991SJulian Elischer 	bzero( fs->fs_fsmnt + strsize, sizeof(fs->fs_fsmnt) - strsize);
7272b14f991SJulian Elischer 
7282b14f991SJulian Elischer 	if( mp->mnt_flag & MNT_ROOTFS) {
7292b14f991SJulian Elischer 		/*
7302b14f991SJulian Elischer 		 * Root mount; update timestamp in mount structure.
7312b14f991SJulian Elischer 		 * this will be used by the common root mount code
7322b14f991SJulian Elischer 		 * to update the system clock.
7332b14f991SJulian Elischer 		 */
7342b14f991SJulian Elischer 		mp->mnt_time = fs->fs_time;
7352b14f991SJulian Elischer 	}
736996c772fSJohn Dyson 
737996c772fSJohn Dyson 	ump->um_savedmaxfilesize = fs->fs_maxfilesize;		/* XXX */
738996c772fSJohn Dyson 	maxfilesize = (u_int64_t)0x40000000 * fs->fs_bsize - 1;	/* XXX */
739996c772fSJohn Dyson 	if (fs->fs_maxfilesize > maxfilesize)			/* XXX */
740996c772fSJohn Dyson 		fs->fs_maxfilesize = maxfilesize;		/* XXX */
7415819ab3fSKirk McKusick 	if (bigcgs) {
7425819ab3fSKirk McKusick 		if (fs->fs_sparecon[0] <= 0)
7435819ab3fSKirk McKusick 			fs->fs_sparecon[0] = fs->fs_cgsize;
7445819ab3fSKirk McKusick 		fs->fs_cgsize = fs->fs_bsize;
7455819ab3fSKirk McKusick 	}
746996c772fSJohn Dyson 	if (ronly == 0) {
747b1897c19SJulian Elischer 		if ((fs->fs_flags & FS_DOSOFTDEP) &&
748b1897c19SJulian Elischer 		    (error = softdep_mount(devvp, mp, fs, cred)) != 0) {
749f55ff3f3SIan Dowse 			free(fs->fs_csp, M_UFSMNT);
750b1897c19SJulian Elischer 			goto out;
751b1897c19SJulian Elischer 		}
752f2a2857bSKirk McKusick 		if (fs->fs_snapinum[0] != 0)
753f2a2857bSKirk McKusick 			ffs_snapshot_mount(mp);
754cf60e8e4SKirk McKusick 		fs->fs_fmod = 1;
755996c772fSJohn Dyson 		fs->fs_clean = 0;
756996c772fSJohn Dyson 		(void) ffs_sbupdate(ump, MNT_WAIT);
757996c772fSJohn Dyson 	}
758516081f2SRobert Watson #ifdef UFS_EXTATTR
759516081f2SRobert Watson #ifdef UFS_EXTATTR_AUTOSTART
7609de54ba5SRobert Watson 	/*
7619de54ba5SRobert Watson 	 *
762f5161237SRobert Watson 	 * Auto-starting does the following:
7639de54ba5SRobert Watson 	 *	- check for /.attribute in the fs, and extattr_start if so
7649de54ba5SRobert Watson 	 *	- for each file in .attribute, enable that file with
7659de54ba5SRobert Watson 	 * 	  an attribute of the same name.
7669de54ba5SRobert Watson 	 * Not clear how to report errors -- probably eat them.
7679de54ba5SRobert Watson 	 * This would all happen while the file system was busy/not
7689de54ba5SRobert Watson 	 * available, so would effectively be "atomic".
7699de54ba5SRobert Watson 	 */
770b40ce416SJulian Elischer 	(void) ufs_extattr_autostart(mp, td);
771516081f2SRobert Watson #endif /* !UFS_EXTATTR_AUTOSTART */
772516081f2SRobert Watson #endif /* !UFS_EXTATTR */
773df8bae1dSRodney W. Grimes 	return (0);
774df8bae1dSRodney W. Grimes out:
7757eb9fca5SEivind Eklund 	devvp->v_rdev->si_mountpoint = NULL;
776df8bae1dSRodney W. Grimes 	if (bp)
777df8bae1dSRodney W. Grimes 		brelse(bp);
778b40ce416SJulian Elischer 	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, td);
779df8bae1dSRodney W. Grimes 	if (ump) {
780df8bae1dSRodney W. Grimes 		free(ump->um_fs, M_UFSMNT);
781df8bae1dSRodney W. Grimes 		free(ump, M_UFSMNT);
782df8bae1dSRodney W. Grimes 		mp->mnt_data = (qaddr_t)0;
783df8bae1dSRodney W. Grimes 	}
784df8bae1dSRodney W. Grimes 	return (error);
785df8bae1dSRodney W. Grimes }
786df8bae1dSRodney W. Grimes 
787df8bae1dSRodney W. Grimes /*
788df8bae1dSRodney W. Grimes  * Sanity checks for old file systems.
789df8bae1dSRodney W. Grimes  *
790df8bae1dSRodney W. Grimes  * XXX - goes away some day.
791df8bae1dSRodney W. Grimes  */
792b8dce649SPoul-Henning Kamp static int
793df8bae1dSRodney W. Grimes ffs_oldfscompat(fs)
794df8bae1dSRodney W. Grimes 	struct fs *fs;
795df8bae1dSRodney W. Grimes {
796df8bae1dSRodney W. Grimes 
797df8bae1dSRodney W. Grimes 	fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect);	/* XXX */
798df8bae1dSRodney W. Grimes 	fs->fs_interleave = max(fs->fs_interleave, 1);		/* XXX */
799df8bae1dSRodney W. Grimes 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
800df8bae1dSRodney W. Grimes 		fs->fs_nrpos = 8;				/* XXX */
801df8bae1dSRodney W. Grimes 	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
802c03020b2SPoul-Henning Kamp #if 0
803c03020b2SPoul-Henning Kamp 		int i;						/* XXX */
804996c772fSJohn Dyson 		u_int64_t sizepb = fs->fs_bsize;		/* XXX */
805996c772fSJohn Dyson 								/* XXX */
806df8bae1dSRodney W. Grimes 		fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1;	/* XXX */
807df8bae1dSRodney W. Grimes 		for (i = 0; i < NIADDR; i++) {			/* XXX */
808df8bae1dSRodney W. Grimes 			sizepb *= NINDIR(fs);			/* XXX */
809df8bae1dSRodney W. Grimes 			fs->fs_maxfilesize += sizepb;		/* XXX */
810df8bae1dSRodney W. Grimes 		}						/* XXX */
811901ba606SDavid Greenman #endif
812a316d390SJohn Dyson 		fs->fs_maxfilesize = (u_quad_t) 1LL << 39;
813df8bae1dSRodney W. Grimes 		fs->fs_qbmask = ~fs->fs_bmask;			/* XXX */
814df8bae1dSRodney W. Grimes 		fs->fs_qfmask = ~fs->fs_fmask;			/* XXX */
815df8bae1dSRodney W. Grimes 	}							/* XXX */
816df8bae1dSRodney W. Grimes 	return (0);
817df8bae1dSRodney W. Grimes }
818df8bae1dSRodney W. Grimes 
819df8bae1dSRodney W. Grimes /*
820df8bae1dSRodney W. Grimes  * unmount system call
821df8bae1dSRodney W. Grimes  */
822df8bae1dSRodney W. Grimes int
823b40ce416SJulian Elischer ffs_unmount(mp, mntflags, td)
824df8bae1dSRodney W. Grimes 	struct mount *mp;
825df8bae1dSRodney W. Grimes 	int mntflags;
826b40ce416SJulian Elischer 	struct thread *td;
827df8bae1dSRodney W. Grimes {
828ff435dcbSRobert Watson 	register struct ufsmount *ump = VFSTOUFS(mp);
829df8bae1dSRodney W. Grimes 	register struct fs *fs;
830996c772fSJohn Dyson 	int error, flags;
831df8bae1dSRodney W. Grimes 
832df8bae1dSRodney W. Grimes 	flags = 0;
833df8bae1dSRodney W. Grimes 	if (mntflags & MNT_FORCE) {
834df8bae1dSRodney W. Grimes 		flags |= FORCECLOSE;
835df8bae1dSRodney W. Grimes 	}
836516081f2SRobert Watson #ifdef UFS_EXTATTR
837b40ce416SJulian Elischer 	if ((error = ufs_extattr_stop(mp, td))) {
838b2b0497aSRobert Watson 		if (error != EOPNOTSUPP)
839b2b0497aSRobert Watson 			printf("ffs_unmount: ufs_extattr_stop returned %d\n",
840b2b0497aSRobert Watson 			    error);
8417df97b61SRobert Watson 	} else {
8429de54ba5SRobert Watson 		ufs_extattr_uepm_destroy(&ump->um_extattr);
8437df97b61SRobert Watson 	}
844a64ed089SRobert Watson #endif
845b1897c19SJulian Elischer 	if (mp->mnt_flag & MNT_SOFTDEP) {
846b40ce416SJulian Elischer 		if ((error = softdep_flushfiles(mp, flags, td)) != 0)
847df8bae1dSRodney W. Grimes 			return (error);
848b1897c19SJulian Elischer 	} else {
849b40ce416SJulian Elischer 		if ((error = ffs_flushfiles(mp, flags, td)) != 0)
850b1897c19SJulian Elischer 			return (error);
851b1897c19SJulian Elischer 	}
852df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
8535819ab3fSKirk McKusick 	if (bigcgs) {
8545819ab3fSKirk McKusick 		fs->fs_cgsize = fs->fs_sparecon[0];
8555819ab3fSKirk McKusick 		fs->fs_sparecon[0] = 0;
8565819ab3fSKirk McKusick 	}
8579ccb939eSKirk McKusick 	if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
8589ccb939eSKirk McKusick 		printf("%s: unmount pending error: blocks %d files %d\n",
8599ccb939eSKirk McKusick 		    fs->fs_fsmnt, fs->fs_pendingblocks, fs->fs_pendinginodes);
8609ccb939eSKirk McKusick 		fs->fs_pendingblocks = 0;
8619ccb939eSKirk McKusick 		fs->fs_pendinginodes = 0;
8629ccb939eSKirk McKusick 	}
863996c772fSJohn Dyson 	if (fs->fs_ronly == 0) {
8641a6a6610SKirk McKusick 		fs->fs_clean = fs->fs_flags & (FS_UNCLEAN|FS_NEEDSFSCK) ? 0 : 1;
865996c772fSJohn Dyson 		error = ffs_sbupdate(ump, MNT_WAIT);
866996c772fSJohn Dyson 		if (error) {
867996c772fSJohn Dyson 			fs->fs_clean = 0;
868996c772fSJohn Dyson 			return (error);
869996c772fSJohn Dyson 		}
870e0e9c421SDavid Greenman 	}
8717eb9fca5SEivind Eklund 	ump->um_devvp->v_rdev->si_mountpoint = NULL;
8726476c0d2SJohn Dyson 
873b40ce416SJulian Elischer 	vinvalbuf(ump->um_devvp, V_SAVE, NOCRED, td, 0, 0);
874996c772fSJohn Dyson 	error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE,
875b40ce416SJulian Elischer 		NOCRED, td);
8766476c0d2SJohn Dyson 
8776476c0d2SJohn Dyson 	vrele(ump->um_devvp);
8786476c0d2SJohn Dyson 
879f55ff3f3SIan Dowse 	free(fs->fs_csp, M_UFSMNT);
880df8bae1dSRodney W. Grimes 	free(fs, M_UFSMNT);
881df8bae1dSRodney W. Grimes 	free(ump, M_UFSMNT);
882df8bae1dSRodney W. Grimes 	mp->mnt_data = (qaddr_t)0;
883cc9d8990SPeter Wemm 	mp->mnt_flag &= ~MNT_LOCAL;
884df8bae1dSRodney W. Grimes 	return (error);
885df8bae1dSRodney W. Grimes }
886df8bae1dSRodney W. Grimes 
887df8bae1dSRodney W. Grimes /*
888df8bae1dSRodney W. Grimes  * Flush out all the files in a filesystem.
889df8bae1dSRodney W. Grimes  */
89026f9a767SRodney W. Grimes int
891b40ce416SJulian Elischer ffs_flushfiles(mp, flags, td)
892df8bae1dSRodney W. Grimes 	register struct mount *mp;
893df8bae1dSRodney W. Grimes 	int flags;
894b40ce416SJulian Elischer 	struct thread *td;
895df8bae1dSRodney W. Grimes {
896df8bae1dSRodney W. Grimes 	register struct ufsmount *ump;
897c9671602SPoul-Henning Kamp 	int error;
898df8bae1dSRodney W. Grimes 
899df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
900df8bae1dSRodney W. Grimes #ifdef QUOTA
901df8bae1dSRodney W. Grimes 	if (mp->mnt_flag & MNT_QUOTA) {
902c1d9efcbSPoul-Henning Kamp 		int i;
9030864ef1eSIan Dowse 		error = vflush(mp, 0, SKIPSYSTEM|flags);
904c1d9efcbSPoul-Henning Kamp 		if (error)
905df8bae1dSRodney W. Grimes 			return (error);
906df8bae1dSRodney W. Grimes 		for (i = 0; i < MAXQUOTAS; i++) {
907df8bae1dSRodney W. Grimes 			if (ump->um_quotas[i] == NULLVP)
908df8bae1dSRodney W. Grimes 				continue;
909b40ce416SJulian Elischer 			quotaoff(td, mp, i);
910df8bae1dSRodney W. Grimes 		}
911df8bae1dSRodney W. Grimes 		/*
912df8bae1dSRodney W. Grimes 		 * Here we fall through to vflush again to ensure
913df8bae1dSRodney W. Grimes 		 * that we have gotten rid of all the system vnodes.
914df8bae1dSRodney W. Grimes 		 */
915df8bae1dSRodney W. Grimes 	}
916df8bae1dSRodney W. Grimes #endif
917f2a2857bSKirk McKusick 	if (ump->um_devvp->v_flag & VCOPYONWRITE) {
9180864ef1eSIan Dowse 		if ((error = vflush(mp, 0, SKIPSYSTEM | flags)) != 0)
919f2a2857bSKirk McKusick 			return (error);
920f2a2857bSKirk McKusick 		ffs_snapshot_unmount(mp);
921f2a2857bSKirk McKusick 		/*
922f2a2857bSKirk McKusick 		 * Here we fall through to vflush again to ensure
923f2a2857bSKirk McKusick 		 * that we have gotten rid of all the system vnodes.
924f2a2857bSKirk McKusick 		 */
925f2a2857bSKirk McKusick 	}
926b1897c19SJulian Elischer         /*
927b1897c19SJulian Elischer 	 * Flush all the files.
928b1897c19SJulian Elischer 	 */
9290864ef1eSIan Dowse 	if ((error = vflush(mp, 0, flags)) != 0)
930b1897c19SJulian Elischer 		return (error);
931b1897c19SJulian Elischer 	/*
932b1897c19SJulian Elischer 	 * Flush filesystem metadata.
933b1897c19SJulian Elischer 	 */
934b40ce416SJulian Elischer 	vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, td);
935b40ce416SJulian Elischer 	error = VOP_FSYNC(ump->um_devvp, td->td_proc->p_ucred, MNT_WAIT, td);
936b40ce416SJulian Elischer 	VOP_UNLOCK(ump->um_devvp, 0, td);
937df8bae1dSRodney W. Grimes 	return (error);
938df8bae1dSRodney W. Grimes }
939df8bae1dSRodney W. Grimes 
940df8bae1dSRodney W. Grimes /*
941df8bae1dSRodney W. Grimes  * Get file system statistics.
942df8bae1dSRodney W. Grimes  */
943df8bae1dSRodney W. Grimes int
944b40ce416SJulian Elischer ffs_statfs(mp, sbp, td)
945df8bae1dSRodney W. Grimes 	struct mount *mp;
946df8bae1dSRodney W. Grimes 	register struct statfs *sbp;
947b40ce416SJulian Elischer 	struct thread *td;
948df8bae1dSRodney W. Grimes {
949df8bae1dSRodney W. Grimes 	register struct ufsmount *ump;
950df8bae1dSRodney W. Grimes 	register struct fs *fs;
951df8bae1dSRodney W. Grimes 
952df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
953df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
954df8bae1dSRodney W. Grimes 	if (fs->fs_magic != FS_MAGIC)
955df8bae1dSRodney W. Grimes 		panic("ffs_statfs");
956df8bae1dSRodney W. Grimes 	sbp->f_bsize = fs->fs_fsize;
957df8bae1dSRodney W. Grimes 	sbp->f_iosize = fs->fs_bsize;
958df8bae1dSRodney W. Grimes 	sbp->f_blocks = fs->fs_dsize;
959df8bae1dSRodney W. Grimes 	sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
9609ccb939eSKirk McKusick 	    fs->fs_cstotal.cs_nffree + dbtofsb(fs, fs->fs_pendingblocks);
9619ccb939eSKirk McKusick 	sbp->f_bavail = freespace(fs, fs->fs_minfree) +
9629ccb939eSKirk McKusick 	    dbtofsb(fs, fs->fs_pendingblocks);
963df8bae1dSRodney W. Grimes 	sbp->f_files =  fs->fs_ncg * fs->fs_ipg - ROOTINO;
9649ccb939eSKirk McKusick 	sbp->f_ffree = fs->fs_cstotal.cs_nifree + fs->fs_pendinginodes;
965df8bae1dSRodney W. Grimes 	if (sbp != &mp->mnt_stat) {
966996c772fSJohn Dyson 		sbp->f_type = mp->mnt_vfc->vfc_typenum;
967df8bae1dSRodney W. Grimes 		bcopy((caddr_t)mp->mnt_stat.f_mntonname,
968df8bae1dSRodney W. Grimes 			(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
969df8bae1dSRodney W. Grimes 		bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
970df8bae1dSRodney W. Grimes 			(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
971df8bae1dSRodney W. Grimes 	}
972df8bae1dSRodney W. Grimes 	return (0);
973df8bae1dSRodney W. Grimes }
974df8bae1dSRodney W. Grimes 
975df8bae1dSRodney W. Grimes /*
976df8bae1dSRodney W. Grimes  * Go through the disk queues to initiate sandbagged IO;
977df8bae1dSRodney W. Grimes  * go through the inodes to write those that have been modified;
978df8bae1dSRodney W. Grimes  * initiate the writing of the super block if it has been modified.
979df8bae1dSRodney W. Grimes  *
980df8bae1dSRodney W. Grimes  * Note: we are always called with the filesystem marked `MPBUSY'.
981df8bae1dSRodney W. Grimes  */
982df8bae1dSRodney W. Grimes int
983b40ce416SJulian Elischer ffs_sync(mp, waitfor, cred, td)
984df8bae1dSRodney W. Grimes 	struct mount *mp;
985df8bae1dSRodney W. Grimes 	int waitfor;
986df8bae1dSRodney W. Grimes 	struct ucred *cred;
987b40ce416SJulian Elischer 	struct thread *td;
988df8bae1dSRodney W. Grimes {
989112f7372SKirk McKusick 	struct vnode *nvp, *vp, *devvp;
990996c772fSJohn Dyson 	struct inode *ip;
991996c772fSJohn Dyson 	struct ufsmount *ump = VFSTOUFS(mp);
992996c772fSJohn Dyson 	struct fs *fs;
9939b971133SKirk McKusick 	int error, count, wait, lockreq, allerror = 0;
994df8bae1dSRodney W. Grimes 
995df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
996996c772fSJohn Dyson 	if (fs->fs_fmod != 0 && fs->fs_ronly != 0) {		/* XXX */
997df8bae1dSRodney W. Grimes 		printf("fs = %s\n", fs->fs_fsmnt);
9985ace3b26SMike Pritchard 		panic("ffs_sync: rofs mod");
999df8bae1dSRodney W. Grimes 	}
1000df8bae1dSRodney W. Grimes 	/*
1001df8bae1dSRodney W. Grimes 	 * Write back each (modified) inode.
1002df8bae1dSRodney W. Grimes 	 */
10039b971133SKirk McKusick 	wait = 0;
10049b971133SKirk McKusick 	lockreq = LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK;
10059b971133SKirk McKusick 	if (waitfor == MNT_WAIT) {
10069b971133SKirk McKusick 		wait = 1;
10079b971133SKirk McKusick 		lockreq = LK_EXCLUSIVE | LK_INTERLOCK;
10089b971133SKirk McKusick 	}
10099ed346baSBosko Milekic 	mtx_lock(&mntvnode_mtx);
1010df8bae1dSRodney W. Grimes loop:
1011fc2ffbe6SPoul-Henning Kamp 	for (vp = LIST_FIRST(&mp->mnt_vnodelist); vp != NULL; vp = nvp) {
1012df8bae1dSRodney W. Grimes 		/*
1013df8bae1dSRodney W. Grimes 		 * If the vnode that we are about to sync is no longer
1014df8bae1dSRodney W. Grimes 		 * associated with this mount point, start over.
1015df8bae1dSRodney W. Grimes 		 */
1016df8bae1dSRodney W. Grimes 		if (vp->v_mount != mp)
1017df8bae1dSRodney W. Grimes 			goto loop;
1018fc2ffbe6SPoul-Henning Kamp 		nvp = LIST_NEXT(vp, v_mntvnodes);
101949d2d9f4SJohn Baldwin 
102049d2d9f4SJohn Baldwin 		mtx_unlock(&mntvnode_mtx);
102149d2d9f4SJohn Baldwin 		mtx_lock(&vp->v_interlock);
1022df8bae1dSRodney W. Grimes 		ip = VTOI(vp);
1023cf60e8e4SKirk McKusick 		if (vp->v_type == VNON || ((ip->i_flag &
1024cf60e8e4SKirk McKusick 		     (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
1025cf60e8e4SKirk McKusick 		     TAILQ_EMPTY(&vp->v_dirtyblkhd))) {
10269ed346baSBosko Milekic 			mtx_unlock(&vp->v_interlock);
102749d2d9f4SJohn Baldwin 			mtx_lock(&mntvnode_mtx);
1028df8bae1dSRodney W. Grimes 			continue;
1029996c772fSJohn Dyson 		}
103081c6e3e5SDavid Greenman 		if (vp->v_type != VCHR) {
1031b40ce416SJulian Elischer 			if ((error = vget(vp, lockreq, td)) != 0) {
10329ed346baSBosko Milekic 				mtx_lock(&mntvnode_mtx);
1033996c772fSJohn Dyson 				if (error == ENOENT)
1034df8bae1dSRodney W. Grimes 					goto loop;
1035996c772fSJohn Dyson 				continue;
1036996c772fSJohn Dyson 			}
1037b40ce416SJulian Elischer 			if ((error = VOP_FSYNC(vp, cred, waitfor, td)) != 0)
1038df8bae1dSRodney W. Grimes 				allerror = error;
1039b40ce416SJulian Elischer 			VOP_UNLOCK(vp, 0, td);
10408694d8e9SOllivier Robert 			vrele(vp);
104181c6e3e5SDavid Greenman 		} else {
10429ed346baSBosko Milekic 			mtx_unlock(&vp->v_interlock);
10439b971133SKirk McKusick 			UFS_UPDATE(vp, wait);
104481c6e3e5SDavid Greenman 		}
104549d2d9f4SJohn Baldwin 		mtx_lock(&mntvnode_mtx);
1046df8bae1dSRodney W. Grimes 	}
10479ed346baSBosko Milekic 	mtx_unlock(&mntvnode_mtx);
1048df8bae1dSRodney W. Grimes 	/*
1049df8bae1dSRodney W. Grimes 	 * Force stale file system control information to be flushed.
1050df8bae1dSRodney W. Grimes 	 */
10519b971133SKirk McKusick 	if (waitfor == MNT_WAIT) {
1052b40ce416SJulian Elischer 		if ((error = softdep_flushworklist(ump->um_mountp, &count, td)))
10539b971133SKirk McKusick 			allerror = error;
10549b971133SKirk McKusick 		/* Flushed work items may create new vnodes to clean */
10559b971133SKirk McKusick 		if (count) {
10569ed346baSBosko Milekic 			mtx_lock(&mntvnode_mtx);
10579b971133SKirk McKusick 			goto loop;
10589b971133SKirk McKusick 		}
10599b971133SKirk McKusick 	}
1060589c7af9SKirk McKusick #ifdef QUOTA
1061589c7af9SKirk McKusick 	qsync(mp);
1062589c7af9SKirk McKusick #endif
1063112f7372SKirk McKusick 	devvp = ump->um_devvp;
1064112f7372SKirk McKusick 	mtx_lock(&devvp->v_interlock);
1065112f7372SKirk McKusick 	if (waitfor != MNT_LAZY &&
1066112f7372SKirk McKusick 	    (devvp->v_numoutput > 0 || TAILQ_FIRST(&devvp->v_dirtyblkhd))) {
1067112f7372SKirk McKusick 		mtx_unlock(&devvp->v_interlock);
1068b40ce416SJulian Elischer 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
1069b40ce416SJulian Elischer 		if ((error = VOP_FSYNC(devvp, cred, waitfor, td)) != 0)
1070df8bae1dSRodney W. Grimes 			allerror = error;
1071b40ce416SJulian Elischer 		VOP_UNLOCK(devvp, 0, td);
1072112f7372SKirk McKusick 		if (waitfor == MNT_WAIT) {
1073112f7372SKirk McKusick 			mtx_lock(&mntvnode_mtx);
1074112f7372SKirk McKusick 			goto loop;
1075b1897c19SJulian Elischer 		}
1076112f7372SKirk McKusick 	} else
1077112f7372SKirk McKusick 		mtx_unlock(&devvp->v_interlock);
1078996c772fSJohn Dyson 	/*
1079996c772fSJohn Dyson 	 * Write back modified superblock.
1080996c772fSJohn Dyson 	 */
1081b1897c19SJulian Elischer 	if (fs->fs_fmod != 0 && (error = ffs_sbupdate(ump, waitfor)) != 0)
1082996c772fSJohn Dyson 		allerror = error;
1083df8bae1dSRodney W. Grimes 	return (allerror);
1084df8bae1dSRodney W. Grimes }
1085df8bae1dSRodney W. Grimes 
1086df8bae1dSRodney W. Grimes /*
1087df8bae1dSRodney W. Grimes  * Look up a FFS dinode number to find its incore vnode, otherwise read it
1088df8bae1dSRodney W. Grimes  * in from disk.  If it is in core, wait for the lock bit to clear, then
1089df8bae1dSRodney W. Grimes  * return the inode locked.  Detection and handling of mount points must be
1090df8bae1dSRodney W. Grimes  * done by the calling routine.
1091df8bae1dSRodney W. Grimes  */
1092b8dce649SPoul-Henning Kamp static int ffs_inode_hash_lock;
1093937c4dfaSSeigo Tanimura /*
1094937c4dfaSSeigo Tanimura  * ffs_inode_hash_lock is a variable to manage mutual exclusion
1095937c4dfaSSeigo Tanimura  * of vnode allocation and intertion to the hash, especially to
1096937c4dfaSSeigo Tanimura  * avoid holding more than one vnodes for the same inode in the
1097937c4dfaSSeigo Tanimura  * hash table. ffs_inode_hash_lock must hence be tested-and-set
1098937c4dfaSSeigo Tanimura  * or cleared atomically, accomplished by ffs_inode_hash_mtx.
1099937c4dfaSSeigo Tanimura  *
1100937c4dfaSSeigo Tanimura  * As vnode allocation may block during MALLOC() and zone
1101937c4dfaSSeigo Tanimura  * allocation, we should also do msleep() to give away the CPU
1102937c4dfaSSeigo Tanimura  * if anyone else is allocating a vnode. lockmgr is not suitable
1103937c4dfaSSeigo Tanimura  * here because someone else may insert to the hash table the
1104937c4dfaSSeigo Tanimura  * vnode we are trying to allocate during our sleep, in which
1105937c4dfaSSeigo Tanimura  * case the hash table needs to be examined once again after
1106937c4dfaSSeigo Tanimura  * waking up.
1107937c4dfaSSeigo Tanimura  */
1108937c4dfaSSeigo Tanimura static struct mtx ffs_inode_hash_mtx;
11092094ddb6SDavid Greenman 
1110df8bae1dSRodney W. Grimes int
1111df8bae1dSRodney W. Grimes ffs_vget(mp, ino, vpp)
1112df8bae1dSRodney W. Grimes 	struct mount *mp;
1113df8bae1dSRodney W. Grimes 	ino_t ino;
1114df8bae1dSRodney W. Grimes 	struct vnode **vpp;
1115df8bae1dSRodney W. Grimes {
1116996c772fSJohn Dyson 	struct fs *fs;
1117996c772fSJohn Dyson 	struct inode *ip;
1118df8bae1dSRodney W. Grimes 	struct ufsmount *ump;
1119df8bae1dSRodney W. Grimes 	struct buf *bp;
1120df8bae1dSRodney W. Grimes 	struct vnode *vp;
1121df8bae1dSRodney W. Grimes 	dev_t dev;
1122937c4dfaSSeigo Tanimura 	int error, want_wakeup;
1123df8bae1dSRodney W. Grimes 
1124df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
1125df8bae1dSRodney W. Grimes 	dev = ump->um_dev;
11268997d94fSDavid Greenman restart:
11278f9110f6SJohn Dyson 	if ((*vpp = ufs_ihashget(dev, ino)) != NULL) {
1128df8bae1dSRodney W. Grimes 		return (0);
11298f9110f6SJohn Dyson 	}
1130df8bae1dSRodney W. Grimes 
11312094ddb6SDavid Greenman 	/*
11328997d94fSDavid Greenman 	 * Lock out the creation of new entries in the FFS hash table in
11338997d94fSDavid Greenman 	 * case getnewvnode() or MALLOC() blocks, otherwise a duplicate
11342094ddb6SDavid Greenman 	 * may occur!
11352094ddb6SDavid Greenman 	 */
11369ed346baSBosko Milekic 	mtx_lock(&ffs_inode_hash_mtx);
11372094ddb6SDavid Greenman 	if (ffs_inode_hash_lock) {
11382094ddb6SDavid Greenman 		while (ffs_inode_hash_lock) {
11392094ddb6SDavid Greenman 			ffs_inode_hash_lock = -1;
1140937c4dfaSSeigo Tanimura 			msleep(&ffs_inode_hash_lock, &ffs_inode_hash_mtx, PVM, "ffsvgt", 0);
11412094ddb6SDavid Greenman 		}
11429ed346baSBosko Milekic 		mtx_unlock(&ffs_inode_hash_mtx);
11438997d94fSDavid Greenman 		goto restart;
11442094ddb6SDavid Greenman 	}
11452094ddb6SDavid Greenman 	ffs_inode_hash_lock = 1;
11469ed346baSBosko Milekic 	mtx_unlock(&ffs_inode_hash_mtx);
11472094ddb6SDavid Greenman 
11482f9bae59SDavid Greenman 	/*
11492f9bae59SDavid Greenman 	 * If this MALLOC() is performed after the getnewvnode()
11502f9bae59SDavid Greenman 	 * it might block, leaving a vnode with a NULL v_data to be
11512f9bae59SDavid Greenman 	 * found by ffs_sync() if a sync happens to fire right then,
11522f9bae59SDavid Greenman 	 * which will cause a panic because ffs_sync() blindly
11532f9bae59SDavid Greenman 	 * dereferences vp->v_data (as well it should).
11542f9bae59SDavid Greenman 	 */
11550be6b890SPoul-Henning Kamp 	MALLOC(ip, struct inode *, sizeof(struct inode),
11560be6b890SPoul-Henning Kamp 	    ump->um_malloctype, M_WAITOK);
11572f9bae59SDavid Greenman 
1158df8bae1dSRodney W. Grimes 	/* Allocate a new vnode/inode. */
1159c9671602SPoul-Henning Kamp 	error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp);
1160c9671602SPoul-Henning Kamp 	if (error) {
1161937c4dfaSSeigo Tanimura 		/*
1162937c4dfaSSeigo Tanimura 		 * Do not wake up processes while holding the mutex,
1163937c4dfaSSeigo Tanimura 		 * otherwise the processes waken up immediately hit
1164937c4dfaSSeigo Tanimura 		 * themselves into the mutex.
1165937c4dfaSSeigo Tanimura 		 */
11669ed346baSBosko Milekic 		mtx_lock(&ffs_inode_hash_mtx);
1167937c4dfaSSeigo Tanimura 		want_wakeup = ffs_inode_hash_lock < 0;
11682094ddb6SDavid Greenman 		ffs_inode_hash_lock = 0;
11699ed346baSBosko Milekic 		mtx_unlock(&ffs_inode_hash_mtx);
1170937c4dfaSSeigo Tanimura 		if (want_wakeup)
1171937c4dfaSSeigo Tanimura 			wakeup(&ffs_inode_hash_lock);
1172df8bae1dSRodney W. Grimes 		*vpp = NULL;
11730be6b890SPoul-Henning Kamp 		FREE(ip, ump->um_malloctype);
1174df8bae1dSRodney W. Grimes 		return (error);
1175df8bae1dSRodney W. Grimes 	}
1176df8bae1dSRodney W. Grimes 	bzero((caddr_t)ip, sizeof(struct inode));
117767e87166SBoris Popov 	/*
117867e87166SBoris Popov 	 * FFS supports lock sharing in the stack of vnodes
117967e87166SBoris Popov 	 */
118067e87166SBoris Popov 	vp->v_vnlock = &vp->v_lock;
118167e87166SBoris Popov 	lockinit(vp->v_vnlock, PINOD, "inode", 0, LK_CANRECURSE);
1182df8bae1dSRodney W. Grimes 	vp->v_data = ip;
1183df8bae1dSRodney W. Grimes 	ip->i_vnode = vp;
1184df8bae1dSRodney W. Grimes 	ip->i_fs = fs = ump->um_fs;
1185df8bae1dSRodney W. Grimes 	ip->i_dev = dev;
1186df8bae1dSRodney W. Grimes 	ip->i_number = ino;
1187df8bae1dSRodney W. Grimes #ifdef QUOTA
1188c1d9efcbSPoul-Henning Kamp 	{
1189c1d9efcbSPoul-Henning Kamp 		int i;
1190df8bae1dSRodney W. Grimes 		for (i = 0; i < MAXQUOTAS; i++)
1191df8bae1dSRodney W. Grimes 			ip->i_dquot[i] = NODQUOT;
1192c1d9efcbSPoul-Henning Kamp 	}
1193df8bae1dSRodney W. Grimes #endif
1194df8bae1dSRodney W. Grimes 	/*
1195df8bae1dSRodney W. Grimes 	 * Put it onto its hash chain and lock it so that other requests for
1196df8bae1dSRodney W. Grimes 	 * this inode will block if they arrive while we are sleeping waiting
1197df8bae1dSRodney W. Grimes 	 * for old data structures to be purged or for the contents of the
1198df8bae1dSRodney W. Grimes 	 * disk portion of this inode to be read.
1199df8bae1dSRodney W. Grimes 	 */
1200df8bae1dSRodney W. Grimes 	ufs_ihashins(ip);
1201df8bae1dSRodney W. Grimes 
1202937c4dfaSSeigo Tanimura 	/*
1203937c4dfaSSeigo Tanimura 	 * Do not wake up processes while holding the mutex,
1204937c4dfaSSeigo Tanimura 	 * otherwise the processes waken up immediately hit
1205937c4dfaSSeigo Tanimura 	 * themselves into the mutex.
1206937c4dfaSSeigo Tanimura 	 */
12079ed346baSBosko Milekic 	mtx_lock(&ffs_inode_hash_mtx);
1208937c4dfaSSeigo Tanimura 	want_wakeup = ffs_inode_hash_lock < 0;
12092094ddb6SDavid Greenman 	ffs_inode_hash_lock = 0;
12109ed346baSBosko Milekic 	mtx_unlock(&ffs_inode_hash_mtx);
1211937c4dfaSSeigo Tanimura 	if (want_wakeup)
1212937c4dfaSSeigo Tanimura 		wakeup(&ffs_inode_hash_lock);
12132094ddb6SDavid Greenman 
1214df8bae1dSRodney W. Grimes 	/* Read in the disk contents for the inode, copy into the inode. */
1215c9671602SPoul-Henning Kamp 	error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
1216c9671602SPoul-Henning Kamp 	    (int)fs->fs_bsize, NOCRED, &bp);
1217c9671602SPoul-Henning Kamp 	if (error) {
1218df8bae1dSRodney W. Grimes 		/*
1219df8bae1dSRodney W. Grimes 		 * The inode does not contain anything useful, so it would
1220df8bae1dSRodney W. Grimes 		 * be misleading to leave it on its hash chain. With mode
1221df8bae1dSRodney W. Grimes 		 * still zero, it will be unlinked and returned to the free
1222df8bae1dSRodney W. Grimes 		 * list by vput().
1223df8bae1dSRodney W. Grimes 		 */
1224df8bae1dSRodney W. Grimes 		brelse(bp);
1225bd7e5f99SJohn Dyson 		vput(vp);
1226df8bae1dSRodney W. Grimes 		*vpp = NULL;
1227df8bae1dSRodney W. Grimes 		return (error);
1228df8bae1dSRodney W. Grimes 	}
1229df8bae1dSRodney W. Grimes 	ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ino));
1230b1897c19SJulian Elischer 	if (DOINGSOFTDEP(vp))
1231b1897c19SJulian Elischer 		softdep_load_inodeblock(ip);
1232b1897c19SJulian Elischer 	else
1233b1897c19SJulian Elischer 		ip->i_effnlink = ip->i_nlink;
1234bd7e5f99SJohn Dyson 	bqrelse(bp);
1235df8bae1dSRodney W. Grimes 
1236df8bae1dSRodney W. Grimes 	/*
1237df8bae1dSRodney W. Grimes 	 * Initialize the vnode from the inode, check for aliases.
1238df8bae1dSRodney W. Grimes 	 * Note that the underlying vnode may have changed.
1239df8bae1dSRodney W. Grimes 	 */
1240e6302eabSBruce Evans 	error = ufs_vinit(mp, ffs_specop_p, ffs_fifoop_p, &vp);
1241c9671602SPoul-Henning Kamp 	if (error) {
1242df8bae1dSRodney W. Grimes 		vput(vp);
1243df8bae1dSRodney W. Grimes 		*vpp = NULL;
1244df8bae1dSRodney W. Grimes 		return (error);
1245df8bae1dSRodney W. Grimes 	}
1246df8bae1dSRodney W. Grimes 	/*
1247df8bae1dSRodney W. Grimes 	 * Finish inode initialization now that aliasing has been resolved.
1248df8bae1dSRodney W. Grimes 	 */
1249df8bae1dSRodney W. Grimes 	ip->i_devvp = ump->um_devvp;
1250df8bae1dSRodney W. Grimes 	VREF(ip->i_devvp);
1251df8bae1dSRodney W. Grimes 	/*
1252df8bae1dSRodney W. Grimes 	 * Set up a generation number for this inode if it does not
1253df8bae1dSRodney W. Grimes 	 * already have one. This should only happen on old filesystems.
1254df8bae1dSRodney W. Grimes 	 */
1255df8bae1dSRodney W. Grimes 	if (ip->i_gen == 0) {
12568f89943eSGuido van Rooij 		ip->i_gen = random() / 2 + 1;
1257df8bae1dSRodney W. Grimes 		if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
1258df8bae1dSRodney W. Grimes 			ip->i_flag |= IN_MODIFIED;
1259df8bae1dSRodney W. Grimes 	}
1260df8bae1dSRodney W. Grimes 	/*
1261df8bae1dSRodney W. Grimes 	 * Ensure that uid and gid are correct. This is a temporary
1262df8bae1dSRodney W. Grimes 	 * fix until fsck has been changed to do the update.
1263df8bae1dSRodney W. Grimes 	 */
1264df8bae1dSRodney W. Grimes 	if (fs->fs_inodefmt < FS_44INODEFMT) {		/* XXX */
1265df8bae1dSRodney W. Grimes 		ip->i_uid = ip->i_din.di_ouid;		/* XXX */
1266df8bae1dSRodney W. Grimes 		ip->i_gid = ip->i_din.di_ogid;		/* XXX */
1267df8bae1dSRodney W. Grimes 	}						/* XXX */
1268df8bae1dSRodney W. Grimes 
1269df8bae1dSRodney W. Grimes 	*vpp = vp;
1270df8bae1dSRodney W. Grimes 	return (0);
1271df8bae1dSRodney W. Grimes }
1272df8bae1dSRodney W. Grimes 
1273df8bae1dSRodney W. Grimes /*
1274df8bae1dSRodney W. Grimes  * File handle to vnode
1275df8bae1dSRodney W. Grimes  *
1276df8bae1dSRodney W. Grimes  * Have to be really careful about stale file handles:
1277df8bae1dSRodney W. Grimes  * - check that the inode number is valid
1278df8bae1dSRodney W. Grimes  * - call ffs_vget() to get the locked inode
1279df8bae1dSRodney W. Grimes  * - check for an unallocated inode (i_mode == 0)
1280df8bae1dSRodney W. Grimes  * - check that the given client host has export rights and return
1281df8bae1dSRodney W. Grimes  *   those rights via. exflagsp and credanonp
1282df8bae1dSRodney W. Grimes  */
1283df8bae1dSRodney W. Grimes int
1284c24fda81SAlfred Perlstein ffs_fhtovp(mp, fhp, vpp)
1285df8bae1dSRodney W. Grimes 	register struct mount *mp;
1286df8bae1dSRodney W. Grimes 	struct fid *fhp;
1287df8bae1dSRodney W. Grimes 	struct vnode **vpp;
1288df8bae1dSRodney W. Grimes {
1289df8bae1dSRodney W. Grimes 	register struct ufid *ufhp;
1290df8bae1dSRodney W. Grimes 	struct fs *fs;
1291df8bae1dSRodney W. Grimes 
1292df8bae1dSRodney W. Grimes 	ufhp = (struct ufid *)fhp;
1293df8bae1dSRodney W. Grimes 	fs = VFSTOUFS(mp)->um_fs;
1294df8bae1dSRodney W. Grimes 	if (ufhp->ufid_ino < ROOTINO ||
1295df8bae1dSRodney W. Grimes 	    ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg)
1296df8bae1dSRodney W. Grimes 		return (ESTALE);
1297c24fda81SAlfred Perlstein 	return (ufs_fhtovp(mp, ufhp, vpp));
1298df8bae1dSRodney W. Grimes }
1299df8bae1dSRodney W. Grimes 
1300df8bae1dSRodney W. Grimes /*
1301df8bae1dSRodney W. Grimes  * Vnode pointer to File handle
1302df8bae1dSRodney W. Grimes  */
1303df8bae1dSRodney W. Grimes /* ARGSUSED */
130426f9a767SRodney W. Grimes int
1305df8bae1dSRodney W. Grimes ffs_vptofh(vp, fhp)
1306df8bae1dSRodney W. Grimes 	struct vnode *vp;
1307df8bae1dSRodney W. Grimes 	struct fid *fhp;
1308df8bae1dSRodney W. Grimes {
1309df8bae1dSRodney W. Grimes 	register struct inode *ip;
1310df8bae1dSRodney W. Grimes 	register struct ufid *ufhp;
1311df8bae1dSRodney W. Grimes 
1312df8bae1dSRodney W. Grimes 	ip = VTOI(vp);
1313df8bae1dSRodney W. Grimes 	ufhp = (struct ufid *)fhp;
1314df8bae1dSRodney W. Grimes 	ufhp->ufid_len = sizeof(struct ufid);
1315df8bae1dSRodney W. Grimes 	ufhp->ufid_ino = ip->i_number;
1316df8bae1dSRodney W. Grimes 	ufhp->ufid_gen = ip->i_gen;
1317df8bae1dSRodney W. Grimes 	return (0);
1318df8bae1dSRodney W. Grimes }
1319df8bae1dSRodney W. Grimes 
1320df8bae1dSRodney W. Grimes /*
1321996c772fSJohn Dyson  * Initialize the filesystem; just use ufs_init.
1322996c772fSJohn Dyson  */
1323996c772fSJohn Dyson static int
1324996c772fSJohn Dyson ffs_init(vfsp)
1325996c772fSJohn Dyson 	struct vfsconf *vfsp;
1326996c772fSJohn Dyson {
1327996c772fSJohn Dyson 
1328b1897c19SJulian Elischer 	softdep_initialize();
1329937c4dfaSSeigo Tanimura 	mtx_init(&ffs_inode_hash_mtx, "ifsvgt", MTX_DEF);
1330996c772fSJohn Dyson 	return (ufs_init(vfsp));
1331996c772fSJohn Dyson }
1332996c772fSJohn Dyson 
1333996c772fSJohn Dyson /*
1334df8bae1dSRodney W. Grimes  * Write a superblock and associated information back to disk.
1335df8bae1dSRodney W. Grimes  */
1336b8dce649SPoul-Henning Kamp static int
1337df8bae1dSRodney W. Grimes ffs_sbupdate(mp, waitfor)
1338df8bae1dSRodney W. Grimes 	struct ufsmount *mp;
1339df8bae1dSRodney W. Grimes 	int waitfor;
1340df8bae1dSRodney W. Grimes {
1341996c772fSJohn Dyson 	register struct fs *dfs, *fs = mp->um_fs;
1342df8bae1dSRodney W. Grimes 	register struct buf *bp;
1343df8bae1dSRodney W. Grimes 	int blks;
1344f55ff3f3SIan Dowse 	void *space;
1345996c772fSJohn Dyson 	int i, size, error, allerror = 0;
1346df8bae1dSRodney W. Grimes 
1347996c772fSJohn Dyson 	/*
1348996c772fSJohn Dyson 	 * First write back the summary information.
1349996c772fSJohn Dyson 	 */
1350df8bae1dSRodney W. Grimes 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
1351f55ff3f3SIan Dowse 	space = fs->fs_csp;
1352df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
1353df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
1354df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
1355df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
1356df8bae1dSRodney W. Grimes 		bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i),
1357df8bae1dSRodney W. Grimes 		    size, 0, 0);
1358df8bae1dSRodney W. Grimes 		bcopy(space, bp->b_data, (u_int)size);
1359f55ff3f3SIan Dowse 		space = (char *)space + size;
1360996c772fSJohn Dyson 		if (waitfor != MNT_WAIT)
1361df8bae1dSRodney W. Grimes 			bawrite(bp);
13628aef1712SMatthew Dillon 		else if ((error = bwrite(bp)) != 0)
1363996c772fSJohn Dyson 			allerror = error;
1364df8bae1dSRodney W. Grimes 	}
1365996c772fSJohn Dyson 	/*
1366996c772fSJohn Dyson 	 * Now write back the superblock itself. If any errors occurred
1367996c772fSJohn Dyson 	 * up to this point, then fail so that the superblock avoids
1368996c772fSJohn Dyson 	 * being written out as clean.
1369996c772fSJohn Dyson 	 */
1370996c772fSJohn Dyson 	if (allerror)
1371996c772fSJohn Dyson 		return (allerror);
1372996c772fSJohn Dyson 	bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0);
1373b1897c19SJulian Elischer 	fs->fs_fmod = 0;
1374227ee8a1SPoul-Henning Kamp 	fs->fs_time = time_second;
1375996c772fSJohn Dyson 	bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize);
1376996c772fSJohn Dyson 	/* Restore compatibility to old file systems.		   XXX */
1377996c772fSJohn Dyson 	dfs = (struct fs *)bp->b_data;				/* XXX */
1378996c772fSJohn Dyson 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
1379996c772fSJohn Dyson 		dfs->fs_nrpos = -1;				/* XXX */
1380996c772fSJohn Dyson 	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
1381996c772fSJohn Dyson 		int32_t *lp, tmp;				/* XXX */
1382996c772fSJohn Dyson 								/* XXX */
1383996c772fSJohn Dyson 		lp = (int32_t *)&dfs->fs_qbmask;		/* XXX */
1384996c772fSJohn Dyson 		tmp = lp[4];					/* XXX */
1385996c772fSJohn Dyson 		for (i = 4; i > 0; i--)				/* XXX */
1386996c772fSJohn Dyson 			lp[i] = lp[i-1];			/* XXX */
1387996c772fSJohn Dyson 		lp[0] = tmp;					/* XXX */
1388996c772fSJohn Dyson 	}							/* XXX */
1389996c772fSJohn Dyson 	dfs->fs_maxfilesize = mp->um_savedmaxfilesize;		/* XXX */
1390996c772fSJohn Dyson 	if (waitfor != MNT_WAIT)
1391996c772fSJohn Dyson 		bawrite(bp);
13928aef1712SMatthew Dillon 	else if ((error = bwrite(bp)) != 0)
1393996c772fSJohn Dyson 		allerror = error;
1394996c772fSJohn Dyson 	return (allerror);
1395df8bae1dSRodney W. Grimes }
1396