xref: /freebsd/sys/ufs/ffs/ffs_vfsops.c (revision f55ff3f3efac63d2f4e5125ccdb454cc52f3eff1)
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 
37a64ed089SRobert Watson #include "opt_ffs.h"
3801733a9bSGarrett Wollman #include "opt_quota.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>
53df8bae1dSRodney W. Grimes 
54a18b1f1dSJason Evans #include <machine/mutex.h>
55a18b1f1dSJason Evans 
56a64ed089SRobert Watson #include <ufs/ufs/extattr.h>
57df8bae1dSRodney W. Grimes #include <ufs/ufs/quota.h>
58df8bae1dSRodney W. Grimes #include <ufs/ufs/ufsmount.h>
59df8bae1dSRodney W. Grimes #include <ufs/ufs/inode.h>
60df8bae1dSRodney W. Grimes #include <ufs/ufs/ufs_extern.h>
61df8bae1dSRodney W. Grimes 
62df8bae1dSRodney W. Grimes #include <ufs/ffs/fs.h>
63df8bae1dSRodney W. Grimes #include <ufs/ffs/ffs_extern.h>
64df8bae1dSRodney W. Grimes 
65f6b04d2bSDavid Greenman #include <vm/vm.h>
66f6b04d2bSDavid Greenman #include <vm/vm_page.h>
67f6b04d2bSDavid Greenman 
68a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_FFSNODE, "FFS node", "FFS vnode private part");
6955166637SPoul-Henning Kamp 
70b8dce649SPoul-Henning Kamp static int	ffs_sbupdate __P((struct ufsmount *, int));
710b0c10b4SAdrian Chadd int	ffs_reload __P((struct mount *,struct ucred *,struct proc *));
72b8dce649SPoul-Henning Kamp static int	ffs_oldfscompat __P((struct fs *));
73996c772fSJohn Dyson static int	ffs_init __P((struct vfsconf *));
74df8bae1dSRodney W. Grimes 
75303b270bSEivind Eklund static struct vfsops ufs_vfsops = {
76df8bae1dSRodney W. Grimes 	ffs_mount,
77df8bae1dSRodney W. Grimes 	ufs_start,
78df8bae1dSRodney W. Grimes 	ffs_unmount,
79df8bae1dSRodney W. Grimes 	ufs_root,
80df8bae1dSRodney W. Grimes 	ufs_quotactl,
81df8bae1dSRodney W. Grimes 	ffs_statfs,
82df8bae1dSRodney W. Grimes 	ffs_sync,
83df8bae1dSRodney W. Grimes 	ffs_vget,
84df8bae1dSRodney W. Grimes 	ffs_fhtovp,
85c24fda81SAlfred Perlstein 	ufs_check_export,
86df8bae1dSRodney W. Grimes 	ffs_vptofh,
87df8bae1dSRodney W. Grimes 	ffs_init,
8891f37dcbSRobert Watson 	vfs_stduninit,
89a64ed089SRobert Watson #ifdef FFS_EXTATTR
90a64ed089SRobert Watson 	ufs_extattrctl,
91a64ed089SRobert Watson #else
9291f37dcbSRobert Watson 	vfs_stdextattrctl,
93a64ed089SRobert Watson #endif
94df8bae1dSRodney W. Grimes };
95df8bae1dSRodney W. Grimes 
968994ca3cSBruce Evans VFS_SET(ufs_vfsops, ufs, 0);
97c901836cSGarrett Wollman 
98df8bae1dSRodney W. Grimes /*
992b14f991SJulian Elischer  * ffs_mount
100df8bae1dSRodney W. Grimes  *
1012b14f991SJulian Elischer  * Called when mounting local physical media
102df8bae1dSRodney W. Grimes  *
1032b14f991SJulian Elischer  * PARAMETERS:
1042b14f991SJulian Elischer  *		mountroot
1052b14f991SJulian Elischer  *			mp	mount point structure
1062b14f991SJulian Elischer  *			path	NULL (flag for root mount!!!)
1072b14f991SJulian Elischer  *			data	<unused>
1082b14f991SJulian Elischer  *			ndp	<unused>
1092b14f991SJulian Elischer  *			p	process (user credentials check [statfs])
1102b14f991SJulian Elischer  *
1112b14f991SJulian Elischer  *		mount
1122b14f991SJulian Elischer  *			mp	mount point structure
1132b14f991SJulian Elischer  *			path	path to mount point
1142b14f991SJulian Elischer  *			data	pointer to argument struct in user space
1152b14f991SJulian Elischer  *			ndp	mount point namei() return (used for
1162b14f991SJulian Elischer  *				credentials on reload), reused to look
1172b14f991SJulian Elischer  *				up block device.
1182b14f991SJulian Elischer  *			p	process (user credentials check)
1192b14f991SJulian Elischer  *
1202b14f991SJulian Elischer  * RETURNS:	0	Success
1212b14f991SJulian Elischer  *		!0	error number (errno.h)
1222b14f991SJulian Elischer  *
1232b14f991SJulian Elischer  * LOCK STATE:
1242b14f991SJulian Elischer  *
1252b14f991SJulian Elischer  *		ENTRY
1262b14f991SJulian Elischer  *			mount point is locked
1272b14f991SJulian Elischer  *		EXIT
1282b14f991SJulian Elischer  *			mount point is locked
1292b14f991SJulian Elischer  *
1302b14f991SJulian Elischer  * NOTES:
1312b14f991SJulian Elischer  *		A NULL path can be used for a flag since the mount
1322b14f991SJulian Elischer  *		system call will fail with EFAULT in copyinstr in
1332b14f991SJulian Elischer  *		namei() if it is a genuine NULL from the user.
134df8bae1dSRodney W. Grimes  */
1350b0c10b4SAdrian Chadd int
136df8bae1dSRodney W. Grimes ffs_mount(mp, path, data, ndp, p)
137996c772fSJohn Dyson         struct mount		*mp;	/* mount struct pointer*/
1382b14f991SJulian Elischer         char			*path;	/* path to mount point*/
1392b14f991SJulian Elischer         caddr_t			data;	/* arguments to FS specific mount*/
1402b14f991SJulian Elischer         struct nameidata	*ndp;	/* mount point credentials*/
1412b14f991SJulian Elischer         struct proc		*p;	/* process requesting mount*/
142df8bae1dSRodney W. Grimes {
1438435e0aeSDoug Rabson 	size_t		size;
144df8bae1dSRodney W. Grimes 	struct vnode	*devvp;
145df8bae1dSRodney W. Grimes 	struct ufs_args args;
14626f9a767SRodney W. Grimes 	struct ufsmount *ump = 0;
147df8bae1dSRodney W. Grimes 	register struct fs *fs;
148f2a2857bSKirk McKusick 	int error, flags;
149c9b99213SBruce Evans 	mode_t accessmode;
150df8bae1dSRodney W. Grimes 
1512b14f991SJulian Elischer 	/*
152f2a2857bSKirk McKusick 	 * Use NULL path to indicate we are mounting the root file system.
1532b14f991SJulian Elischer 	 */
1542b14f991SJulian Elischer 	if (path == NULL) {
155f2a2857bSKirk McKusick 		if ((error = bdevvp(rootdev, &rootvp))) {
1566d147828SMike Smith 			printf("ffs_mountroot: can't find rootvp\n");
157f2a2857bSKirk McKusick 			return (error);
158996c772fSJohn Dyson 		}
1592b14f991SJulian Elischer 
160f2a2857bSKirk McKusick 		if ((error = ffs_mountfs(rootvp, mp, p, M_FFSNODE)) != 0)
161f2a2857bSKirk McKusick 			return (error);
1622b14f991SJulian Elischer 
163f2a2857bSKirk McKusick 		(void)VFS_STATFS(mp, &mp->mnt_stat, p);
164f2a2857bSKirk McKusick 		return (0);
1652b14f991SJulian Elischer 	}
1662b14f991SJulian Elischer 
1672b14f991SJulian Elischer 	/*
1682b14f991SJulian Elischer 	 * Mounting non-root file system or updating a file system
1692b14f991SJulian Elischer 	 */
170f2a2857bSKirk McKusick 	if ((error = copyin(data, (caddr_t)&args, sizeof(struct ufs_args)))!= 0)
171f2a2857bSKirk McKusick 		return (error);
1722b14f991SJulian Elischer 
173df8bae1dSRodney W. Grimes 	/*
174df8bae1dSRodney W. Grimes 	 * If updating, check whether changing from read-only to
175df8bae1dSRodney W. Grimes 	 * read/write; if there is no device name, that's all we do.
176df8bae1dSRodney W. Grimes 	 */
177df8bae1dSRodney W. Grimes 	if (mp->mnt_flag & MNT_UPDATE) {
178df8bae1dSRodney W. Grimes 		ump = VFSTOUFS(mp);
179df8bae1dSRodney W. Grimes 		fs = ump->um_fs;
18026cf9c3bSPeter Wemm 		devvp = ump->um_devvp;
181f2a2857bSKirk McKusick 		if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
182f2a2857bSKirk McKusick 			if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0)
183f2a2857bSKirk McKusick 				return (error);
184df8bae1dSRodney W. Grimes 			flags = WRITECLOSE;
185df8bae1dSRodney W. Grimes 			if (mp->mnt_flag & MNT_FORCE)
186df8bae1dSRodney W. Grimes 				flags |= FORCECLOSE;
187b1897c19SJulian Elischer 			if (mp->mnt_flag & MNT_SOFTDEP) {
188f2a2857bSKirk McKusick 				error = softdep_flushfiles(mp, flags, p);
189b1897c19SJulian Elischer 			} else {
190f2a2857bSKirk McKusick 				error = ffs_flushfiles(mp, flags, p);
191df8bae1dSRodney W. Grimes 			}
192f2a2857bSKirk McKusick 			if (error) {
193f2a2857bSKirk McKusick 				vn_finished_write(mp);
194f2a2857bSKirk McKusick 				return (error);
195b1897c19SJulian Elischer 			}
196f2a2857bSKirk McKusick 			fs->fs_ronly = 1;
197f2a2857bSKirk McKusick 			if ((fs->fs_flags & FS_UNCLEAN) == 0)
198f2a2857bSKirk McKusick 				fs->fs_clean = 1;
199f2a2857bSKirk McKusick 			if ((error = ffs_sbupdate(ump, MNT_WAIT)) != 0) {
200f2a2857bSKirk McKusick 				fs->fs_ronly = 0;
201f2a2857bSKirk McKusick 				fs->fs_clean = 0;
202f2a2857bSKirk McKusick 				vn_finished_write(mp);
203f2a2857bSKirk McKusick 				return (error);
2042b14f991SJulian Elischer 			}
205f2a2857bSKirk McKusick 			vn_finished_write(mp);
206f2a2857bSKirk McKusick 		}
207f2a2857bSKirk McKusick 		if ((mp->mnt_flag & MNT_RELOAD) &&
208f2a2857bSKirk McKusick 		    (error = ffs_reload(mp, ndp->ni_cnd.cn_cred, p)) != 0)
209f2a2857bSKirk McKusick 			return (error);
210f2a2857bSKirk McKusick 		if (fs->fs_ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) {
211c9b99213SBruce Evans 			/*
212c9b99213SBruce Evans 			 * If upgrade to read-write by non-root, then verify
213c9b99213SBruce Evans 			 * that user has necessary permissions on the device.
214c9b99213SBruce Evans 			 */
215c9b99213SBruce Evans 			if (p->p_ucred->cr_uid != 0) {
216c9b99213SBruce Evans 				vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
2178aef1712SMatthew Dillon 				if ((error = VOP_ACCESS(devvp, VREAD | VWRITE,
2188aef1712SMatthew Dillon 				    p->p_ucred, p)) != 0) {
219c9b99213SBruce Evans 					VOP_UNLOCK(devvp, 0, p);
220c9b99213SBruce Evans 					return (error);
221c9b99213SBruce Evans 				}
222c9b99213SBruce Evans 				VOP_UNLOCK(devvp, 0, p);
223c9b99213SBruce Evans 			}
2247e58bfacSBruce Evans 			fs->fs_flags &= ~FS_UNCLEAN;
2250922cce6SBruce Evans 			if (fs->fs_clean == 0) {
2267e58bfacSBruce Evans 				fs->fs_flags |= FS_UNCLEAN;
2270922cce6SBruce Evans 				if (mp->mnt_flag & MNT_FORCE) {
228f2a2857bSKirk McKusick 					printf("WARNING: %s was not %s\n",
229f2a2857bSKirk McKusick 					   fs->fs_fsmnt, "properly dismounted");
2300922cce6SBruce Evans 				} else {
2310922cce6SBruce Evans 					printf(
2320922cce6SBruce Evans "WARNING: R/W mount of %s denied.  Filesystem is not clean - run fsck\n",
2330922cce6SBruce Evans 					    fs->fs_fsmnt);
234f2a2857bSKirk McKusick 					return (EPERM);
2350922cce6SBruce Evans 				}
2360922cce6SBruce Evans 			}
237f2a2857bSKirk McKusick 			if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0)
238f2a2857bSKirk McKusick 				return (error);
239f2a2857bSKirk McKusick 			fs->fs_ronly = 0;
240f2a2857bSKirk McKusick 			fs->fs_clean = 0;
241f2a2857bSKirk McKusick 			if ((error = ffs_sbupdate(ump, MNT_WAIT)) != 0) {
242f2a2857bSKirk McKusick 				vn_finished_write(mp);
243f2a2857bSKirk McKusick 				return (error);
244f2a2857bSKirk McKusick 			}
24526cf9c3bSPeter Wemm 			/* check to see if we need to start softdep */
246f2a2857bSKirk McKusick 			if ((fs->fs_flags & FS_DOSOFTDEP) &&
247f2a2857bSKirk McKusick 			    (error = softdep_mount(devvp, mp, fs, p->p_ucred))){
248f2a2857bSKirk McKusick 				vn_finished_write(mp);
249f2a2857bSKirk McKusick 				return (error);
25026cf9c3bSPeter Wemm 			}
251f2a2857bSKirk McKusick 			if (fs->fs_snapinum[0] != 0)
252f2a2857bSKirk McKusick 				ffs_snapshot_mount(mp);
253f2a2857bSKirk McKusick 			vn_finished_write(mp);
2541469eec8SDavid Greenman 		}
255c11d2981SJulian Elischer 		/*
256c11d2981SJulian Elischer 		 * Soft updates is incompatible with "async",
257c11d2981SJulian Elischer 		 * so if we are doing softupdates stop the user
258c11d2981SJulian Elischer 		 * from setting the async flag in an update.
259c11d2981SJulian Elischer 		 * Softdep_mount() clears it in an initial mount
260c11d2981SJulian Elischer 		 * or ro->rw remount.
261c11d2981SJulian Elischer 		 */
262f2a2857bSKirk McKusick 		if (mp->mnt_flag & MNT_SOFTDEP)
263c11d2981SJulian Elischer 			mp->mnt_flag &= ~MNT_ASYNC;
264df8bae1dSRodney W. Grimes 		/*
265f2a2857bSKirk McKusick 		 * If not updating name, process export requests.
266df8bae1dSRodney W. Grimes 		 */
267f2a2857bSKirk McKusick 		if (args.fspec == 0)
268f2a2857bSKirk McKusick 			return (vfs_export(mp, &ump->um_export, &args.export));
269f2a2857bSKirk McKusick 		/*
270f2a2857bSKirk McKusick 		 * If this is a snapshot request, take the snapshot.
271f2a2857bSKirk McKusick 		 */
272f2a2857bSKirk McKusick 		if (mp->mnt_flag & MNT_SNAPSHOT)
273f2a2857bSKirk McKusick 			return (ffs_snapshot(mp, args.fspec));
274df8bae1dSRodney W. Grimes 	}
2752b14f991SJulian Elischer 
276df8bae1dSRodney W. Grimes 	/*
277df8bae1dSRodney W. Grimes 	 * Not an update, or updating the name: look up the name
278df8bae1dSRodney W. Grimes 	 * and verify that it refers to a sensible block device.
279df8bae1dSRodney W. Grimes 	 */
280df8bae1dSRodney W. Grimes 	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
281f2a2857bSKirk McKusick 	if ((error = namei(ndp)) != 0)
282f2a2857bSKirk McKusick 		return (error);
283762e6b85SEivind Eklund 	NDFREE(ndp, NDF_ONLY_PNBUF);
284df8bae1dSRodney W. Grimes 	devvp = ndp->ni_vp;
285f2a2857bSKirk McKusick 	if (!vn_isdisk(devvp, &error)) {
286f2a2857bSKirk McKusick 		vrele(devvp);
287f2a2857bSKirk McKusick 		return (error);
288f2a2857bSKirk McKusick 	}
289c9b99213SBruce Evans 
290c9b99213SBruce Evans 	/*
291c9b99213SBruce Evans 	 * If mount by non-root, then verify that user has necessary
292c9b99213SBruce Evans 	 * permissions on the device.
293c9b99213SBruce Evans 	 */
294c9b99213SBruce Evans 	if (p->p_ucred->cr_uid != 0) {
295c9b99213SBruce Evans 		accessmode = VREAD;
296c9b99213SBruce Evans 		if ((mp->mnt_flag & MNT_RDONLY) == 0)
297c9b99213SBruce Evans 			accessmode |= VWRITE;
298c9b99213SBruce Evans 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
2998aef1712SMatthew Dillon 		if ((error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p))!= 0){
300c9b99213SBruce Evans 			vput(devvp);
301c9b99213SBruce Evans 			return (error);
302c9b99213SBruce Evans 		}
303c9b99213SBruce Evans 		VOP_UNLOCK(devvp, 0, p);
304c9b99213SBruce Evans 	}
305c9b99213SBruce Evans 
3062b14f991SJulian Elischer 	if (mp->mnt_flag & MNT_UPDATE) {
3072b14f991SJulian Elischer 		/*
308f2a2857bSKirk McKusick 		 * Update only
309f2a2857bSKirk McKusick 		 *
3103e425b96SJulian Elischer 		 * If it's not the same vnode, or at least the same device
3113e425b96SJulian Elischer 		 * then it's not correct.
3122b14f991SJulian Elischer 		 */
3132b14f991SJulian Elischer 
314f2a2857bSKirk McKusick 		if (devvp != ump->um_devvp &&
315f2a2857bSKirk McKusick 		    devvp->v_rdev != ump->um_devvp->v_rdev)
316f2a2857bSKirk McKusick 			error = EINVAL;	/* needs translation */
3173e425b96SJulian Elischer 		vrele(devvp);
318f2a2857bSKirk McKusick 		if (error)
319f2a2857bSKirk McKusick 			return (error);
3202b14f991SJulian Elischer 	} else {
3212b14f991SJulian Elischer 		/*
322f2a2857bSKirk McKusick 		 * New mount
3232b14f991SJulian Elischer 		 *
324f2a2857bSKirk McKusick 		 * We need the name for the mount point (also used for
325f2a2857bSKirk McKusick 		 * "last mounted on") copied in. If an error occurs,
326f2a2857bSKirk McKusick 		 * the mount point is discarded by the upper level code.
327f2a2857bSKirk McKusick 		 */
328f2a2857bSKirk McKusick 		copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
329f2a2857bSKirk McKusick 		bzero( mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
330f2a2857bSKirk McKusick 		if ((error = ffs_mountfs(devvp, mp, p, M_FFSNODE)) != 0) {
331f2a2857bSKirk McKusick 			vrele(devvp);
332f2a2857bSKirk McKusick 			return (error);
333f2a2857bSKirk McKusick 		}
334f2a2857bSKirk McKusick 	}
335f2a2857bSKirk McKusick 	/*
336f2a2857bSKirk McKusick 	 * Save "mounted from" device name info for mount point (NULL pad).
337f2a2857bSKirk McKusick 	 */
338f2a2857bSKirk McKusick 	copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
339f2a2857bSKirk McKusick 	bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
340f2a2857bSKirk McKusick 	/*
341f2a2857bSKirk McKusick 	 * Initialize filesystem stat information in mount struct.
3422b14f991SJulian Elischer 	 */
3432b14f991SJulian Elischer 	(void)VFS_STATFS(mp, &mp->mnt_stat, p);
344f2a2857bSKirk McKusick 	return (0);
3452b14f991SJulian Elischer }
3462b14f991SJulian Elischer 
347df8bae1dSRodney W. Grimes /*
348df8bae1dSRodney W. Grimes  * Reload all incore data for a filesystem (used after running fsck on
349df8bae1dSRodney W. Grimes  * the root filesystem and finding things to fix). The filesystem must
350df8bae1dSRodney W. Grimes  * be mounted read-only.
351df8bae1dSRodney W. Grimes  *
352df8bae1dSRodney W. Grimes  * Things to do to update the mount:
353df8bae1dSRodney W. Grimes  *	1) invalidate all cached meta-data.
354df8bae1dSRodney W. Grimes  *	2) re-read superblock from disk.
355df8bae1dSRodney W. Grimes  *	3) re-read summary information from disk.
356df8bae1dSRodney W. Grimes  *	4) invalidate all inactive vnodes.
357df8bae1dSRodney W. Grimes  *	5) invalidate all cached file data.
358df8bae1dSRodney W. Grimes  *	6) re-read inode data for all active vnodes.
359df8bae1dSRodney W. Grimes  */
3600b0c10b4SAdrian Chadd int
3612b14f991SJulian Elischer ffs_reload(mp, cred, p)
3622b14f991SJulian Elischer 	register struct mount *mp;
363df8bae1dSRodney W. Grimes 	struct ucred *cred;
364df8bae1dSRodney W. Grimes 	struct proc *p;
365df8bae1dSRodney W. Grimes {
366df8bae1dSRodney W. Grimes 	register struct vnode *vp, *nvp, *devvp;
367df8bae1dSRodney W. Grimes 	struct inode *ip;
368f55ff3f3SIan Dowse 	void *space;
369df8bae1dSRodney W. Grimes 	struct buf *bp;
370996c772fSJohn Dyson 	struct fs *fs, *newfs;
371996c772fSJohn Dyson 	struct partinfo dpart;
37295e5e988SJohn Dyson 	dev_t dev;
373df8bae1dSRodney W. Grimes 	int i, blks, size, error;
374996c772fSJohn Dyson 	int32_t *lp;
375df8bae1dSRodney W. Grimes 
3762b14f991SJulian Elischer 	if ((mp->mnt_flag & MNT_RDONLY) == 0)
377df8bae1dSRodney W. Grimes 		return (EINVAL);
378df8bae1dSRodney W. Grimes 	/*
379df8bae1dSRodney W. Grimes 	 * Step 1: invalidate all cached meta-data.
380df8bae1dSRodney W. Grimes 	 */
3812b14f991SJulian Elischer 	devvp = VFSTOUFS(mp)->um_devvp;
382b1897c19SJulian Elischer 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
383b1897c19SJulian Elischer 	error = vinvalbuf(devvp, 0, cred, p, 0, 0);
384b1897c19SJulian Elischer 	VOP_UNLOCK(devvp, 0, p);
385b1897c19SJulian Elischer 	if (error)
386df8bae1dSRodney W. Grimes 		panic("ffs_reload: dirty1");
38795e5e988SJohn Dyson 
38895e5e988SJohn Dyson 	dev = devvp->v_rdev;
389b5ee1640SBruce Evans 
39095e5e988SJohn Dyson 	/*
39195e5e988SJohn Dyson 	 * Only VMIO the backing device if the backing device is a real
392b5ee1640SBruce Evans 	 * block device.  See ffs_mountmfs() for more details.
39395e5e988SJohn Dyson 	 */
394ba4ad1fcSPoul-Henning Kamp 	if (devvp->v_tag != VT_MFS && vn_isdisk(devvp, NULL)) {
395a777e820SEivind Eklund 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
396fb116777SEivind Eklund 		vfs_object_create(devvp, p, p->p_ucred);
397a18b1f1dSJason Evans 		mtx_enter(&devvp->v_interlock, MTX_DEF);
398a777e820SEivind Eklund 		VOP_UNLOCK(devvp, LK_INTERLOCK, p);
39995e5e988SJohn Dyson 	}
40095e5e988SJohn Dyson 
401df8bae1dSRodney W. Grimes 	/*
402df8bae1dSRodney W. Grimes 	 * Step 2: re-read superblock from disk.
403df8bae1dSRodney W. Grimes 	 */
404996c772fSJohn Dyson 	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
405996c772fSJohn Dyson 		size = DEV_BSIZE;
406996c772fSJohn Dyson 	else
407996c772fSJohn Dyson 		size = dpart.disklab->d_secsize;
4088aef1712SMatthew Dillon 	if ((error = bread(devvp, (ufs_daddr_t)(SBOFF/size), SBSIZE, NOCRED,&bp)) != 0)
409df8bae1dSRodney W. Grimes 		return (error);
410996c772fSJohn Dyson 	newfs = (struct fs *)bp->b_data;
411996c772fSJohn Dyson 	if (newfs->fs_magic != FS_MAGIC || newfs->fs_bsize > MAXBSIZE ||
412996c772fSJohn Dyson 		newfs->fs_bsize < sizeof(struct fs)) {
413df8bae1dSRodney W. Grimes 			brelse(bp);
414df8bae1dSRodney W. Grimes 			return (EIO);		/* XXX needs translation */
415df8bae1dSRodney W. Grimes 	}
4162b14f991SJulian Elischer 	fs = VFSTOUFS(mp)->um_fs;
417996c772fSJohn Dyson 	/*
418996c772fSJohn Dyson 	 * Copy pointer fields back into superblock before copying in	XXX
419996c772fSJohn Dyson 	 * new superblock. These should really be in the ufsmount.	XXX
420996c772fSJohn Dyson 	 * Note that important parameters (eg fs_ncg) are unchanged.
421996c772fSJohn Dyson 	 */
422f55ff3f3SIan Dowse 	newfs->fs_csp = fs->fs_csp;
423996c772fSJohn Dyson 	newfs->fs_maxcluster = fs->fs_maxcluster;
424996c772fSJohn Dyson 	bcopy(newfs, fs, (u_int)fs->fs_sbsize);
425df8bae1dSRodney W. Grimes 	if (fs->fs_sbsize < SBSIZE)
426f2a2857bSKirk McKusick 		bp->b_flags |= B_INVAL | B_NOCACHE;
427df8bae1dSRodney W. Grimes 	brelse(bp);
428996c772fSJohn Dyson 	mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
429df8bae1dSRodney W. Grimes 	ffs_oldfscompat(fs);
430996c772fSJohn Dyson 
431df8bae1dSRodney W. Grimes 	/*
432df8bae1dSRodney W. Grimes 	 * Step 3: re-read summary information from disk.
433df8bae1dSRodney W. Grimes 	 */
434df8bae1dSRodney W. Grimes 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
435f55ff3f3SIan Dowse 	space = fs->fs_csp;
436df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
437df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
438df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
439df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
440c9671602SPoul-Henning Kamp 		error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
441c9671602SPoul-Henning Kamp 		    NOCRED, &bp);
442c9671602SPoul-Henning Kamp 		if (error)
443df8bae1dSRodney W. Grimes 			return (error);
444f55ff3f3SIan Dowse 		bcopy(bp->b_data, space, (u_int)size);
445f55ff3f3SIan Dowse 		space = (char *)space + size;
446df8bae1dSRodney W. Grimes 		brelse(bp);
447df8bae1dSRodney W. Grimes 	}
448996c772fSJohn Dyson 	/*
449996c772fSJohn Dyson 	 * We no longer know anything about clusters per cylinder group.
450996c772fSJohn Dyson 	 */
451996c772fSJohn Dyson 	if (fs->fs_contigsumsize > 0) {
452996c772fSJohn Dyson 		lp = fs->fs_maxcluster;
453996c772fSJohn Dyson 		for (i = 0; i < fs->fs_ncg; i++)
454996c772fSJohn Dyson 			*lp++ = fs->fs_contigsumsize;
455996c772fSJohn Dyson 	}
456996c772fSJohn Dyson 
457df8bae1dSRodney W. Grimes loop:
458996c772fSJohn Dyson 	simple_lock(&mntvnode_slock);
4592b14f991SJulian Elischer 	for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
460996c772fSJohn Dyson 		if (vp->v_mount != mp) {
461996c772fSJohn Dyson 			simple_unlock(&mntvnode_slock);
462996c772fSJohn Dyson 			goto loop;
463996c772fSJohn Dyson 		}
464df8bae1dSRodney W. Grimes 		nvp = vp->v_mntvnodes.le_next;
465df8bae1dSRodney W. Grimes 		/*
466df8bae1dSRodney W. Grimes 		 * Step 4: invalidate all inactive vnodes.
467df8bae1dSRodney W. Grimes 		 */
468996c772fSJohn Dyson 		if (vrecycle(vp, &mntvnode_slock, p))
469996c772fSJohn Dyson 			goto loop;
470df8bae1dSRodney W. Grimes 		/*
471df8bae1dSRodney W. Grimes 		 * Step 5: invalidate all cached file data.
472df8bae1dSRodney W. Grimes 		 */
473a18b1f1dSJason Evans 		mtx_enter(&vp->v_interlock, MTX_DEF);
474996c772fSJohn Dyson 		simple_unlock(&mntvnode_slock);
475996c772fSJohn Dyson 		if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) {
476df8bae1dSRodney W. Grimes 			goto loop;
477996c772fSJohn Dyson 		}
478df8bae1dSRodney W. Grimes 		if (vinvalbuf(vp, 0, cred, p, 0, 0))
479df8bae1dSRodney W. Grimes 			panic("ffs_reload: dirty2");
480df8bae1dSRodney W. Grimes 		/*
481df8bae1dSRodney W. Grimes 		 * Step 6: re-read inode data for all active vnodes.
482df8bae1dSRodney W. Grimes 		 */
483df8bae1dSRodney W. Grimes 		ip = VTOI(vp);
484c9671602SPoul-Henning Kamp 		error =
485df8bae1dSRodney W. Grimes 		    bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
486c9671602SPoul-Henning Kamp 		    (int)fs->fs_bsize, NOCRED, &bp);
487c9671602SPoul-Henning Kamp 		if (error) {
488df8bae1dSRodney W. Grimes 			vput(vp);
489df8bae1dSRodney W. Grimes 			return (error);
490df8bae1dSRodney W. Grimes 		}
491df8bae1dSRodney W. Grimes 		ip->i_din = *((struct dinode *)bp->b_data +
492df8bae1dSRodney W. Grimes 		    ino_to_fsbo(fs, ip->i_number));
493b1897c19SJulian Elischer 		ip->i_effnlink = ip->i_nlink;
494df8bae1dSRodney W. Grimes 		brelse(bp);
495df8bae1dSRodney W. Grimes 		vput(vp);
496996c772fSJohn Dyson 		simple_lock(&mntvnode_slock);
497df8bae1dSRodney W. Grimes 	}
498996c772fSJohn Dyson 	simple_unlock(&mntvnode_slock);
499df8bae1dSRodney W. Grimes 	return (0);
500df8bae1dSRodney W. Grimes }
501df8bae1dSRodney W. Grimes 
502df8bae1dSRodney W. Grimes /*
503df8bae1dSRodney W. Grimes  * Common code for mount and mountroot
504df8bae1dSRodney W. Grimes  */
505df8bae1dSRodney W. Grimes int
5060be6b890SPoul-Henning Kamp ffs_mountfs(devvp, mp, p, malloctype)
507df8bae1dSRodney W. Grimes 	register struct vnode *devvp;
508df8bae1dSRodney W. Grimes 	struct mount *mp;
509df8bae1dSRodney W. Grimes 	struct proc *p;
5100be6b890SPoul-Henning Kamp 	struct malloc_type *malloctype;
511df8bae1dSRodney W. Grimes {
512df8bae1dSRodney W. Grimes 	register struct ufsmount *ump;
513df8bae1dSRodney W. Grimes 	struct buf *bp;
514df8bae1dSRodney W. Grimes 	register struct fs *fs;
515996c772fSJohn Dyson 	dev_t dev;
516df8bae1dSRodney W. Grimes 	struct partinfo dpart;
517f55ff3f3SIan Dowse 	void *space;
518f5ef029eSPoul-Henning Kamp 	int error, i, blks, size, ronly;
519996c772fSJohn Dyson 	int32_t *lp;
520996c772fSJohn Dyson 	struct ucred *cred;
521996c772fSJohn Dyson 	u_int64_t maxfilesize;					/* XXX */
5228435e0aeSDoug Rabson 	size_t strsize;
5236476c0d2SJohn Dyson 	int ncount;
524df8bae1dSRodney W. Grimes 
525996c772fSJohn Dyson 	dev = devvp->v_rdev;
526996c772fSJohn Dyson 	cred = p ? p->p_ucred : NOCRED;
527df8bae1dSRodney W. Grimes 	/*
528df8bae1dSRodney W. Grimes 	 * Disallow multiple mounts of the same device.
529df8bae1dSRodney W. Grimes 	 * Disallow mounting of a device that is currently in use
530df8bae1dSRodney W. Grimes 	 * (except for root, which might share swap device for miniroot).
531df8bae1dSRodney W. Grimes 	 * Flush out any old buffers remaining from a previous use.
532df8bae1dSRodney W. Grimes 	 */
533c9671602SPoul-Henning Kamp 	error = vfs_mountedon(devvp);
534c9671602SPoul-Henning Kamp 	if (error)
535df8bae1dSRodney W. Grimes 		return (error);
5366476c0d2SJohn Dyson 	ncount = vcount(devvp);
5378f9110f6SJohn Dyson 
5386476c0d2SJohn Dyson 	if (ncount > 1 && devvp != rootvp)
539df8bae1dSRodney W. Grimes 		return (EBUSY);
540b1897c19SJulian Elischer 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
541b1897c19SJulian Elischer 	error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0);
542b1897c19SJulian Elischer 	VOP_UNLOCK(devvp, 0, p);
543b1897c19SJulian Elischer 	if (error)
544df8bae1dSRodney W. Grimes 		return (error);
545df8bae1dSRodney W. Grimes 
54695e5e988SJohn Dyson 	/*
54795e5e988SJohn Dyson 	 * Only VMIO the backing device if the backing device is a real
54895e5e988SJohn Dyson 	 * block device.  This excludes the original MFS implementation.
54995e5e988SJohn Dyson 	 * Note that it is optional that the backing device be VMIOed.  This
55095e5e988SJohn Dyson 	 * increases the opportunity for metadata caching.
55195e5e988SJohn Dyson 	 */
552ba4ad1fcSPoul-Henning Kamp 	if (devvp->v_tag != VT_MFS && vn_isdisk(devvp, NULL)) {
553a777e820SEivind Eklund 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
5543fbd9742SBoris Popov 		vfs_object_create(devvp, p, cred);
555a18b1f1dSJason Evans 		mtx_enter(&devvp->v_interlock, MTX_DEF);
556a777e820SEivind Eklund 		VOP_UNLOCK(devvp, LK_INTERLOCK, p);
55795e5e988SJohn Dyson 	}
55895e5e988SJohn Dyson 
559df8bae1dSRodney W. Grimes 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
560698f9cf8SPoul-Henning Kamp 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
561c9671602SPoul-Henning Kamp 	error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
562698f9cf8SPoul-Henning Kamp 	VOP_UNLOCK(devvp, 0, p);
563c9671602SPoul-Henning Kamp 	if (error)
564df8bae1dSRodney W. Grimes 		return (error);
5651b5464efSPoul-Henning Kamp 	if (devvp->v_rdev->si_iosize_max > mp->mnt_iosize_max)
5661b5464efSPoul-Henning Kamp 		mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max;
5671b5464efSPoul-Henning Kamp 	if (mp->mnt_iosize_max > MAXPHYS)
5681b5464efSPoul-Henning Kamp 		mp->mnt_iosize_max = MAXPHYS;
56995e5e988SJohn Dyson 
570996c772fSJohn Dyson 	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0)
571df8bae1dSRodney W. Grimes 		size = DEV_BSIZE;
572996c772fSJohn Dyson 	else
573df8bae1dSRodney W. Grimes 		size = dpart.disklab->d_secsize;
574df8bae1dSRodney W. Grimes 
575df8bae1dSRodney W. Grimes 	bp = NULL;
576df8bae1dSRodney W. Grimes 	ump = NULL;
5778aef1712SMatthew Dillon 	if ((error = bread(devvp, SBLOCK, SBSIZE, cred, &bp)) != 0)
578df8bae1dSRodney W. Grimes 		goto out;
579df8bae1dSRodney W. Grimes 	fs = (struct fs *)bp->b_data;
580df8bae1dSRodney W. Grimes 	if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
581df8bae1dSRodney W. Grimes 	    fs->fs_bsize < sizeof(struct fs)) {
582df8bae1dSRodney W. Grimes 		error = EINVAL;		/* XXX needs translation */
583df8bae1dSRodney W. Grimes 		goto out;
584df8bae1dSRodney W. Grimes 	}
5853f6f17eeSJulian Elischer 	fs->fs_fmod = 0;
5860922cce6SBruce Evans 	fs->fs_flags &= ~FS_UNCLEAN;
5870922cce6SBruce Evans 	if (fs->fs_clean == 0) {
5880922cce6SBruce Evans 		fs->fs_flags |= FS_UNCLEAN;
5891469eec8SDavid Greenman 		if (ronly || (mp->mnt_flag & MNT_FORCE)) {
5900922cce6SBruce Evans 			printf(
5910922cce6SBruce Evans "WARNING: %s was not properly dismounted\n",
5920922cce6SBruce Evans 			    fs->fs_fsmnt);
5931469eec8SDavid Greenman 		} else {
5940922cce6SBruce Evans 			printf(
5950922cce6SBruce Evans "WARNING: R/W mount of %s denied.  Filesystem is not clean - run fsck\n",
5960922cce6SBruce Evans 			    fs->fs_fsmnt);
5971469eec8SDavid Greenman 			error = EPERM;
5981469eec8SDavid Greenman 			goto out;
5991469eec8SDavid Greenman 		}
6001469eec8SDavid Greenman 	}
601996c772fSJohn Dyson 	/* XXX updating 4.2 FFS superblocks trashes rotational layout tables */
602996c772fSJohn Dyson 	if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) {
603996c772fSJohn Dyson 		error = EROFS;          /* needs translation */
604996c772fSJohn Dyson 		goto out;
605996c772fSJohn Dyson 	}
6067cc0979fSDavid Malone 	ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK | M_ZERO);
6070be6b890SPoul-Henning Kamp 	ump->um_malloctype = malloctype;
6085bd5c8b9SBruce Evans 	ump->um_i_effnlink_valid = 1;
609df8bae1dSRodney W. Grimes 	ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT,
610df8bae1dSRodney W. Grimes 	    M_WAITOK);
611cec0f20cSPoul-Henning Kamp 	ump->um_blkatoff = ffs_blkatoff;
612cec0f20cSPoul-Henning Kamp 	ump->um_truncate = ffs_truncate;
613987f5696SPoul-Henning Kamp 	ump->um_update = ffs_update;
614cec0f20cSPoul-Henning Kamp 	ump->um_valloc = ffs_valloc;
615cec0f20cSPoul-Henning Kamp 	ump->um_vfree = ffs_vfree;
616df8bae1dSRodney W. Grimes 	bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize);
617df8bae1dSRodney W. Grimes 	if (fs->fs_sbsize < SBSIZE)
618f2a2857bSKirk McKusick 		bp->b_flags |= B_INVAL | B_NOCACHE;
619df8bae1dSRodney W. Grimes 	brelse(bp);
620df8bae1dSRodney W. Grimes 	bp = NULL;
621df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
622df8bae1dSRodney W. Grimes 	fs->fs_ronly = ronly;
623996c772fSJohn Dyson 	size = fs->fs_cssize;
624996c772fSJohn Dyson 	blks = howmany(size, fs->fs_fsize);
625996c772fSJohn Dyson 	if (fs->fs_contigsumsize > 0)
626996c772fSJohn Dyson 		size += fs->fs_ncg * sizeof(int32_t);
627f55ff3f3SIan Dowse 	space = malloc((u_long)size, M_UFSMNT, M_WAITOK);
628f55ff3f3SIan Dowse 	fs->fs_csp = space;
629df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
630df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
631df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
632df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
6338aef1712SMatthew Dillon 		if ((error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
6348aef1712SMatthew Dillon 		    cred, &bp)) != 0) {
635f55ff3f3SIan Dowse 			free(fs->fs_csp, M_UFSMNT);
636df8bae1dSRodney W. Grimes 			goto out;
637df8bae1dSRodney W. Grimes 		}
638df8bae1dSRodney W. Grimes 		bcopy(bp->b_data, space, (u_int)size);
639f55ff3f3SIan Dowse 		space = (char *)space + size;
640df8bae1dSRodney W. Grimes 		brelse(bp);
641df8bae1dSRodney W. Grimes 		bp = NULL;
642df8bae1dSRodney W. Grimes 	}
643996c772fSJohn Dyson 	if (fs->fs_contigsumsize > 0) {
644f55ff3f3SIan Dowse 		fs->fs_maxcluster = lp = space;
645996c772fSJohn Dyson 		for (i = 0; i < fs->fs_ncg; i++)
646996c772fSJohn Dyson 			*lp++ = fs->fs_contigsumsize;
647996c772fSJohn Dyson 	}
648df8bae1dSRodney W. Grimes 	mp->mnt_data = (qaddr_t)ump;
64968de329eSPoul-Henning Kamp 	mp->mnt_stat.f_fsid.val[0] = fs->fs_id[0];
6508f89943eSGuido van Rooij 	mp->mnt_stat.f_fsid.val[1] = fs->fs_id[1];
65168de329eSPoul-Henning Kamp 	if (fs->fs_id[0] == 0 || fs->fs_id[1] == 0 ||
65268de329eSPoul-Henning Kamp 	    vfs_getvfs(&mp->mnt_stat.f_fsid))
65368de329eSPoul-Henning Kamp 		vfs_getnewfsid(mp);
654df8bae1dSRodney W. Grimes 	mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
655cc9d8990SPeter Wemm 	mp->mnt_flag |= MNT_LOCAL;
656df8bae1dSRodney W. Grimes 	ump->um_mountp = mp;
657df8bae1dSRodney W. Grimes 	ump->um_dev = dev;
658df8bae1dSRodney W. Grimes 	ump->um_devvp = devvp;
659df8bae1dSRodney W. Grimes 	ump->um_nindir = fs->fs_nindir;
660df8bae1dSRodney W. Grimes 	ump->um_bptrtodb = fs->fs_fsbtodb;
661df8bae1dSRodney W. Grimes 	ump->um_seqinc = fs->fs_frag;
662df8bae1dSRodney W. Grimes 	for (i = 0; i < MAXQUOTAS; i++)
663df8bae1dSRodney W. Grimes 		ump->um_quotas[i] = NULLVP;
664a64ed089SRobert Watson #ifdef FFS_EXTATTR
665a64ed089SRobert Watson 	ufs_extattr_uepm_init(&ump->um_extattr);
666a64ed089SRobert Watson #endif
6677eb9fca5SEivind Eklund 	devvp->v_rdev->si_mountpoint = mp;
668df8bae1dSRodney W. Grimes 	ffs_oldfscompat(fs);
6692b14f991SJulian Elischer 
6702b14f991SJulian Elischer 	/*
6712b14f991SJulian Elischer 	 * Set FS local "last mounted on" information (NULL pad)
6722b14f991SJulian Elischer 	 */
6732b14f991SJulian Elischer 	copystr(	mp->mnt_stat.f_mntonname,	/* mount point*/
6742b14f991SJulian Elischer 			fs->fs_fsmnt,			/* copy area*/
6752b14f991SJulian Elischer 			sizeof(fs->fs_fsmnt) - 1,	/* max size*/
6762b14f991SJulian Elischer 			&strsize);			/* real size*/
6772b14f991SJulian Elischer 	bzero( fs->fs_fsmnt + strsize, sizeof(fs->fs_fsmnt) - strsize);
6782b14f991SJulian Elischer 
6792b14f991SJulian Elischer 	if( mp->mnt_flag & MNT_ROOTFS) {
6802b14f991SJulian Elischer 		/*
6812b14f991SJulian Elischer 		 * Root mount; update timestamp in mount structure.
6822b14f991SJulian Elischer 		 * this will be used by the common root mount code
6832b14f991SJulian Elischer 		 * to update the system clock.
6842b14f991SJulian Elischer 		 */
6852b14f991SJulian Elischer 		mp->mnt_time = fs->fs_time;
6862b14f991SJulian Elischer 	}
687996c772fSJohn Dyson 
688996c772fSJohn Dyson 	ump->um_savedmaxfilesize = fs->fs_maxfilesize;		/* XXX */
689996c772fSJohn Dyson 	maxfilesize = (u_int64_t)0x40000000 * fs->fs_bsize - 1;	/* XXX */
690996c772fSJohn Dyson 	if (fs->fs_maxfilesize > maxfilesize)			/* XXX */
691996c772fSJohn Dyson 		fs->fs_maxfilesize = maxfilesize;		/* XXX */
692996c772fSJohn Dyson 	if (ronly == 0) {
693b1897c19SJulian Elischer 		if ((fs->fs_flags & FS_DOSOFTDEP) &&
694b1897c19SJulian Elischer 		    (error = softdep_mount(devvp, mp, fs, cred)) != 0) {
695f55ff3f3SIan Dowse 			free(fs->fs_csp, M_UFSMNT);
696b1897c19SJulian Elischer 			goto out;
697b1897c19SJulian Elischer 		}
698f2a2857bSKirk McKusick 		if (fs->fs_snapinum[0] != 0)
699f2a2857bSKirk McKusick 			ffs_snapshot_mount(mp);
700cf60e8e4SKirk McKusick 		fs->fs_fmod = 1;
701996c772fSJohn Dyson 		fs->fs_clean = 0;
702996c772fSJohn Dyson 		(void) ffs_sbupdate(ump, MNT_WAIT);
703996c772fSJohn Dyson 	}
7049de54ba5SRobert Watson #ifdef FFS_EXTATTR
7059de54ba5SRobert Watson 	/*
7069de54ba5SRobert Watson 	 * XXX Auto-starting of EAs would go here.
7079de54ba5SRobert Watson 	 *
7089de54ba5SRobert Watson 	 * Auto-starting would:
7099de54ba5SRobert Watson 	 *	- check for /.attribute in the fs, and extattr_start if so
7109de54ba5SRobert Watson 	 *	- for each file in .attribute, enable that file with
7119de54ba5SRobert Watson 	 * 	  an attribute of the same name.
7129de54ba5SRobert Watson 	 * Not clear how to report errors -- probably eat them.
7139de54ba5SRobert Watson 	 * This would all happen while the file system was busy/not
7149de54ba5SRobert Watson 	 * available, so would effectively be "atomic".
7159de54ba5SRobert Watson 	 */
7169de54ba5SRobert Watson 	/* ufs_extattr_autostart(mp, ump); */
7179de54ba5SRobert Watson #endif
718df8bae1dSRodney W. Grimes 	return (0);
719df8bae1dSRodney W. Grimes out:
7207eb9fca5SEivind Eklund 	devvp->v_rdev->si_mountpoint = NULL;
721df8bae1dSRodney W. Grimes 	if (bp)
722df8bae1dSRodney W. Grimes 		brelse(bp);
723996c772fSJohn Dyson 	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
724df8bae1dSRodney W. Grimes 	if (ump) {
725df8bae1dSRodney W. Grimes 		free(ump->um_fs, M_UFSMNT);
726df8bae1dSRodney W. Grimes 		free(ump, M_UFSMNT);
727df8bae1dSRodney W. Grimes 		mp->mnt_data = (qaddr_t)0;
728df8bae1dSRodney W. Grimes 	}
729df8bae1dSRodney W. Grimes 	return (error);
730df8bae1dSRodney W. Grimes }
731df8bae1dSRodney W. Grimes 
732df8bae1dSRodney W. Grimes /*
733df8bae1dSRodney W. Grimes  * Sanity checks for old file systems.
734df8bae1dSRodney W. Grimes  *
735df8bae1dSRodney W. Grimes  * XXX - goes away some day.
736df8bae1dSRodney W. Grimes  */
737b8dce649SPoul-Henning Kamp static int
738df8bae1dSRodney W. Grimes ffs_oldfscompat(fs)
739df8bae1dSRodney W. Grimes 	struct fs *fs;
740df8bae1dSRodney W. Grimes {
741df8bae1dSRodney W. Grimes 
742df8bae1dSRodney W. Grimes 	fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect);	/* XXX */
743df8bae1dSRodney W. Grimes 	fs->fs_interleave = max(fs->fs_interleave, 1);		/* XXX */
744df8bae1dSRodney W. Grimes 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
745df8bae1dSRodney W. Grimes 		fs->fs_nrpos = 8;				/* XXX */
746df8bae1dSRodney W. Grimes 	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
747c03020b2SPoul-Henning Kamp #if 0
748c03020b2SPoul-Henning Kamp 		int i;						/* XXX */
749996c772fSJohn Dyson 		u_int64_t sizepb = fs->fs_bsize;		/* XXX */
750996c772fSJohn Dyson 								/* XXX */
751df8bae1dSRodney W. Grimes 		fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1;	/* XXX */
752df8bae1dSRodney W. Grimes 		for (i = 0; i < NIADDR; i++) {			/* XXX */
753df8bae1dSRodney W. Grimes 			sizepb *= NINDIR(fs);			/* XXX */
754df8bae1dSRodney W. Grimes 			fs->fs_maxfilesize += sizepb;		/* XXX */
755df8bae1dSRodney W. Grimes 		}						/* XXX */
756901ba606SDavid Greenman #endif
757a316d390SJohn Dyson 		fs->fs_maxfilesize = (u_quad_t) 1LL << 39;
758df8bae1dSRodney W. Grimes 		fs->fs_qbmask = ~fs->fs_bmask;			/* XXX */
759df8bae1dSRodney W. Grimes 		fs->fs_qfmask = ~fs->fs_fmask;			/* XXX */
760df8bae1dSRodney W. Grimes 	}							/* XXX */
761df8bae1dSRodney W. Grimes 	return (0);
762df8bae1dSRodney W. Grimes }
763df8bae1dSRodney W. Grimes 
764df8bae1dSRodney W. Grimes /*
765df8bae1dSRodney W. Grimes  * unmount system call
766df8bae1dSRodney W. Grimes  */
767df8bae1dSRodney W. Grimes int
768df8bae1dSRodney W. Grimes ffs_unmount(mp, mntflags, p)
769df8bae1dSRodney W. Grimes 	struct mount *mp;
770df8bae1dSRodney W. Grimes 	int mntflags;
771df8bae1dSRodney W. Grimes 	struct proc *p;
772df8bae1dSRodney W. Grimes {
773ff435dcbSRobert Watson 	register struct ufsmount *ump = VFSTOUFS(mp);
774df8bae1dSRodney W. Grimes 	register struct fs *fs;
775996c772fSJohn Dyson 	int error, flags;
776df8bae1dSRodney W. Grimes 
777df8bae1dSRodney W. Grimes 	flags = 0;
778df8bae1dSRodney W. Grimes 	if (mntflags & MNT_FORCE) {
779df8bae1dSRodney W. Grimes 		flags |= FORCECLOSE;
780df8bae1dSRodney W. Grimes 	}
781a64ed089SRobert Watson #ifdef FFS_EXTATTR
782b2b0497aSRobert Watson 	if ((error = ufs_extattr_stop(mp, p)))
783b2b0497aSRobert Watson 		if (error != EOPNOTSUPP)
784b2b0497aSRobert Watson 			printf("ffs_unmount: ufs_extattr_stop returned %d\n",
785b2b0497aSRobert Watson 			    error);
7869de54ba5SRobert Watson 	ufs_extattr_uepm_destroy(&ump->um_extattr);
787a64ed089SRobert Watson #endif
788b1897c19SJulian Elischer 	if (mp->mnt_flag & MNT_SOFTDEP) {
789b1897c19SJulian Elischer 		if ((error = softdep_flushfiles(mp, flags, p)) != 0)
790df8bae1dSRodney W. Grimes 			return (error);
791b1897c19SJulian Elischer 	} else {
792b1897c19SJulian Elischer 		if ((error = ffs_flushfiles(mp, flags, p)) != 0)
793b1897c19SJulian Elischer 			return (error);
794b1897c19SJulian Elischer 	}
795df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
796996c772fSJohn Dyson 	if (fs->fs_ronly == 0) {
7970922cce6SBruce Evans 		fs->fs_clean = fs->fs_flags & FS_UNCLEAN ? 0 : 1;
798996c772fSJohn Dyson 		error = ffs_sbupdate(ump, MNT_WAIT);
799996c772fSJohn Dyson 		if (error) {
800996c772fSJohn Dyson 			fs->fs_clean = 0;
801996c772fSJohn Dyson 			return (error);
802996c772fSJohn Dyson 		}
803e0e9c421SDavid Greenman 	}
8047eb9fca5SEivind Eklund 	ump->um_devvp->v_rdev->si_mountpoint = NULL;
8056476c0d2SJohn Dyson 
80695e5e988SJohn Dyson 	vinvalbuf(ump->um_devvp, V_SAVE, NOCRED, p, 0, 0);
807996c772fSJohn Dyson 	error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE,
808df8bae1dSRodney W. Grimes 		NOCRED, p);
8096476c0d2SJohn Dyson 
8106476c0d2SJohn Dyson 	vrele(ump->um_devvp);
8116476c0d2SJohn Dyson 
812f55ff3f3SIan Dowse 	free(fs->fs_csp, M_UFSMNT);
813df8bae1dSRodney W. Grimes 	free(fs, M_UFSMNT);
814df8bae1dSRodney W. Grimes 	free(ump, M_UFSMNT);
815df8bae1dSRodney W. Grimes 	mp->mnt_data = (qaddr_t)0;
816cc9d8990SPeter Wemm 	mp->mnt_flag &= ~MNT_LOCAL;
817df8bae1dSRodney W. Grimes 	return (error);
818df8bae1dSRodney W. Grimes }
819df8bae1dSRodney W. Grimes 
820df8bae1dSRodney W. Grimes /*
821df8bae1dSRodney W. Grimes  * Flush out all the files in a filesystem.
822df8bae1dSRodney W. Grimes  */
82326f9a767SRodney W. Grimes int
824df8bae1dSRodney W. Grimes ffs_flushfiles(mp, flags, p)
825df8bae1dSRodney W. Grimes 	register struct mount *mp;
826df8bae1dSRodney W. Grimes 	int flags;
827df8bae1dSRodney W. Grimes 	struct proc *p;
828df8bae1dSRodney W. Grimes {
829df8bae1dSRodney W. Grimes 	register struct ufsmount *ump;
830c9671602SPoul-Henning Kamp 	int error;
831df8bae1dSRodney W. Grimes 
832df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
833df8bae1dSRodney W. Grimes #ifdef QUOTA
834df8bae1dSRodney W. Grimes 	if (mp->mnt_flag & MNT_QUOTA) {
835c1d9efcbSPoul-Henning Kamp 		int i;
836c1d9efcbSPoul-Henning Kamp 		error = vflush(mp, NULLVP, SKIPSYSTEM|flags);
837c1d9efcbSPoul-Henning Kamp 		if (error)
838df8bae1dSRodney W. Grimes 			return (error);
839df8bae1dSRodney W. Grimes 		for (i = 0; i < MAXQUOTAS; i++) {
840df8bae1dSRodney W. Grimes 			if (ump->um_quotas[i] == NULLVP)
841df8bae1dSRodney W. Grimes 				continue;
842df8bae1dSRodney W. Grimes 			quotaoff(p, mp, i);
843df8bae1dSRodney W. Grimes 		}
844df8bae1dSRodney W. Grimes 		/*
845df8bae1dSRodney W. Grimes 		 * Here we fall through to vflush again to ensure
846df8bae1dSRodney W. Grimes 		 * that we have gotten rid of all the system vnodes.
847df8bae1dSRodney W. Grimes 		 */
848df8bae1dSRodney W. Grimes 	}
849df8bae1dSRodney W. Grimes #endif
850f2a2857bSKirk McKusick 	if (ump->um_devvp->v_flag & VCOPYONWRITE) {
851f2a2857bSKirk McKusick 		if ((error = vflush(mp, NULL, SKIPSYSTEM | flags)) != 0)
852f2a2857bSKirk McKusick 			return (error);
853f2a2857bSKirk McKusick 		ffs_snapshot_unmount(mp);
854f2a2857bSKirk McKusick 		/*
855f2a2857bSKirk McKusick 		 * Here we fall through to vflush again to ensure
856f2a2857bSKirk McKusick 		 * that we have gotten rid of all the system vnodes.
857f2a2857bSKirk McKusick 		 */
858f2a2857bSKirk McKusick 	}
859b1897c19SJulian Elischer         /*
860b1897c19SJulian Elischer 	 * Flush all the files.
861b1897c19SJulian Elischer 	 */
862b1897c19SJulian Elischer 	if ((error = vflush(mp, NULL, flags)) != 0)
863b1897c19SJulian Elischer 		return (error);
864b1897c19SJulian Elischer 	/*
865b1897c19SJulian Elischer 	 * Flush filesystem metadata.
866b1897c19SJulian Elischer 	 */
867b1897c19SJulian Elischer 	vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p);
868b1897c19SJulian Elischer 	error = VOP_FSYNC(ump->um_devvp, p->p_ucred, MNT_WAIT, p);
869b1897c19SJulian Elischer 	VOP_UNLOCK(ump->um_devvp, 0, p);
870df8bae1dSRodney W. Grimes 	return (error);
871df8bae1dSRodney W. Grimes }
872df8bae1dSRodney W. Grimes 
873df8bae1dSRodney W. Grimes /*
874df8bae1dSRodney W. Grimes  * Get file system statistics.
875df8bae1dSRodney W. Grimes  */
876df8bae1dSRodney W. Grimes int
877df8bae1dSRodney W. Grimes ffs_statfs(mp, sbp, p)
878df8bae1dSRodney W. Grimes 	struct mount *mp;
879df8bae1dSRodney W. Grimes 	register struct statfs *sbp;
880df8bae1dSRodney W. Grimes 	struct proc *p;
881df8bae1dSRodney W. Grimes {
882df8bae1dSRodney W. Grimes 	register struct ufsmount *ump;
883df8bae1dSRodney W. Grimes 	register struct fs *fs;
884df8bae1dSRodney W. Grimes 
885df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
886df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
887df8bae1dSRodney W. Grimes 	if (fs->fs_magic != FS_MAGIC)
888df8bae1dSRodney W. Grimes 		panic("ffs_statfs");
889df8bae1dSRodney W. Grimes 	sbp->f_bsize = fs->fs_fsize;
890df8bae1dSRodney W. Grimes 	sbp->f_iosize = fs->fs_bsize;
891df8bae1dSRodney W. Grimes 	sbp->f_blocks = fs->fs_dsize;
892df8bae1dSRodney W. Grimes 	sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
893df8bae1dSRodney W. Grimes 		fs->fs_cstotal.cs_nffree;
89451ea8b57SBruce Evans 	sbp->f_bavail = freespace(fs, fs->fs_minfree);
895df8bae1dSRodney W. Grimes 	sbp->f_files =  fs->fs_ncg * fs->fs_ipg - ROOTINO;
896df8bae1dSRodney W. Grimes 	sbp->f_ffree = fs->fs_cstotal.cs_nifree;
897df8bae1dSRodney W. Grimes 	if (sbp != &mp->mnt_stat) {
898996c772fSJohn Dyson 		sbp->f_type = mp->mnt_vfc->vfc_typenum;
899df8bae1dSRodney W. Grimes 		bcopy((caddr_t)mp->mnt_stat.f_mntonname,
900df8bae1dSRodney W. Grimes 			(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
901df8bae1dSRodney W. Grimes 		bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
902df8bae1dSRodney W. Grimes 			(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
903df8bae1dSRodney W. Grimes 	}
904df8bae1dSRodney W. Grimes 	return (0);
905df8bae1dSRodney W. Grimes }
906df8bae1dSRodney W. Grimes 
907df8bae1dSRodney W. Grimes /*
908df8bae1dSRodney W. Grimes  * Go through the disk queues to initiate sandbagged IO;
909df8bae1dSRodney W. Grimes  * go through the inodes to write those that have been modified;
910df8bae1dSRodney W. Grimes  * initiate the writing of the super block if it has been modified.
911df8bae1dSRodney W. Grimes  *
912df8bae1dSRodney W. Grimes  * Note: we are always called with the filesystem marked `MPBUSY'.
913df8bae1dSRodney W. Grimes  */
914df8bae1dSRodney W. Grimes int
915df8bae1dSRodney W. Grimes ffs_sync(mp, waitfor, cred, p)
916df8bae1dSRodney W. Grimes 	struct mount *mp;
917df8bae1dSRodney W. Grimes 	int waitfor;
918df8bae1dSRodney W. Grimes 	struct ucred *cred;
919df8bae1dSRodney W. Grimes 	struct proc *p;
920df8bae1dSRodney W. Grimes {
921996c772fSJohn Dyson 	struct vnode *nvp, *vp;
922996c772fSJohn Dyson 	struct inode *ip;
923996c772fSJohn Dyson 	struct ufsmount *ump = VFSTOUFS(mp);
924996c772fSJohn Dyson 	struct fs *fs;
9259b971133SKirk McKusick 	int error, count, wait, lockreq, allerror = 0;
926df8bae1dSRodney W. Grimes 
927df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
928996c772fSJohn Dyson 	if (fs->fs_fmod != 0 && fs->fs_ronly != 0) {		/* XXX */
929df8bae1dSRodney W. Grimes 		printf("fs = %s\n", fs->fs_fsmnt);
9305ace3b26SMike Pritchard 		panic("ffs_sync: rofs mod");
931df8bae1dSRodney W. Grimes 	}
932df8bae1dSRodney W. Grimes 	/*
933df8bae1dSRodney W. Grimes 	 * Write back each (modified) inode.
934df8bae1dSRodney W. Grimes 	 */
9359b971133SKirk McKusick 	wait = 0;
9369b971133SKirk McKusick 	lockreq = LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK;
9379b971133SKirk McKusick 	if (waitfor == MNT_WAIT) {
9389b971133SKirk McKusick 		wait = 1;
9399b971133SKirk McKusick 		lockreq = LK_EXCLUSIVE | LK_INTERLOCK;
9409b971133SKirk McKusick 	}
941996c772fSJohn Dyson 	simple_lock(&mntvnode_slock);
942df8bae1dSRodney W. Grimes loop:
943a316d390SJohn Dyson 	for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
944df8bae1dSRodney W. Grimes 		/*
945df8bae1dSRodney W. Grimes 		 * If the vnode that we are about to sync is no longer
946df8bae1dSRodney W. Grimes 		 * associated with this mount point, start over.
947df8bae1dSRodney W. Grimes 		 */
948df8bae1dSRodney W. Grimes 		if (vp->v_mount != mp)
949df8bae1dSRodney W. Grimes 			goto loop;
950a18b1f1dSJason Evans 		mtx_enter(&vp->v_interlock, MTX_DEF);
951a316d390SJohn Dyson 		nvp = vp->v_mntvnodes.le_next;
952df8bae1dSRodney W. Grimes 		ip = VTOI(vp);
953cf60e8e4SKirk McKusick 		if (vp->v_type == VNON || ((ip->i_flag &
954cf60e8e4SKirk McKusick 		     (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
955cf60e8e4SKirk McKusick 		     TAILQ_EMPTY(&vp->v_dirtyblkhd))) {
956a18b1f1dSJason Evans 			mtx_exit(&vp->v_interlock, MTX_DEF);
957df8bae1dSRodney W. Grimes 			continue;
958996c772fSJohn Dyson 		}
95981c6e3e5SDavid Greenman 		if (vp->v_type != VCHR) {
960996c772fSJohn Dyson 			simple_unlock(&mntvnode_slock);
9619b971133SKirk McKusick 			if ((error = vget(vp, lockreq, p)) != 0) {
962996c772fSJohn Dyson 				simple_lock(&mntvnode_slock);
963996c772fSJohn Dyson 				if (error == ENOENT)
964df8bae1dSRodney W. Grimes 					goto loop;
965996c772fSJohn Dyson 				continue;
966996c772fSJohn Dyson 			}
9678aef1712SMatthew Dillon 			if ((error = VOP_FSYNC(vp, cred, waitfor, p)) != 0)
968df8bae1dSRodney W. Grimes 				allerror = error;
9698694d8e9SOllivier Robert 			VOP_UNLOCK(vp, 0, p);
9708694d8e9SOllivier Robert 			vrele(vp);
971996c772fSJohn Dyson 			simple_lock(&mntvnode_slock);
97281c6e3e5SDavid Greenman 		} else {
973996c772fSJohn Dyson 			simple_unlock(&mntvnode_slock);
974a18b1f1dSJason Evans 			mtx_exit(&vp->v_interlock, MTX_DEF);
9759b971133SKirk McKusick 			UFS_UPDATE(vp, wait);
976996c772fSJohn Dyson 			simple_lock(&mntvnode_slock);
97781c6e3e5SDavid Greenman 		}
978df8bae1dSRodney W. Grimes 	}
979996c772fSJohn Dyson 	simple_unlock(&mntvnode_slock);
980df8bae1dSRodney W. Grimes 	/*
981df8bae1dSRodney W. Grimes 	 * Force stale file system control information to be flushed.
982df8bae1dSRodney W. Grimes 	 */
9839b971133SKirk McKusick 	if (waitfor == MNT_WAIT) {
9849b971133SKirk McKusick 		if ((error = softdep_flushworklist(ump->um_mountp, &count, p)))
9859b971133SKirk McKusick 			allerror = error;
9869b971133SKirk McKusick 		/* Flushed work items may create new vnodes to clean */
9879b971133SKirk McKusick 		if (count) {
9889b971133SKirk McKusick 			simple_lock(&mntvnode_slock);
9899b971133SKirk McKusick 			goto loop;
9909b971133SKirk McKusick 		}
9919b971133SKirk McKusick 	}
9929b971133SKirk McKusick 	if (waitfor == MNT_NOWAIT) {
993b1897c19SJulian Elischer 		vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p);
994b1897c19SJulian Elischer 		if ((error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p)) != 0)
995df8bae1dSRodney W. Grimes 			allerror = error;
996b1897c19SJulian Elischer 		VOP_UNLOCK(ump->um_devvp, 0, p);
997b1897c19SJulian Elischer 	}
998df8bae1dSRodney W. Grimes #ifdef QUOTA
999df8bae1dSRodney W. Grimes 	qsync(mp);
1000df8bae1dSRodney W. Grimes #endif
1001996c772fSJohn Dyson 	/*
1002996c772fSJohn Dyson 	 * Write back modified superblock.
1003996c772fSJohn Dyson 	 */
1004b1897c19SJulian Elischer 	if (fs->fs_fmod != 0 && (error = ffs_sbupdate(ump, waitfor)) != 0)
1005996c772fSJohn Dyson 		allerror = error;
1006df8bae1dSRodney W. Grimes 	return (allerror);
1007df8bae1dSRodney W. Grimes }
1008df8bae1dSRodney W. Grimes 
1009df8bae1dSRodney W. Grimes /*
1010df8bae1dSRodney W. Grimes  * Look up a FFS dinode number to find its incore vnode, otherwise read it
1011df8bae1dSRodney W. Grimes  * in from disk.  If it is in core, wait for the lock bit to clear, then
1012df8bae1dSRodney W. Grimes  * return the inode locked.  Detection and handling of mount points must be
1013df8bae1dSRodney W. Grimes  * done by the calling routine.
1014df8bae1dSRodney W. Grimes  */
1015b8dce649SPoul-Henning Kamp static int ffs_inode_hash_lock;
1016937c4dfaSSeigo Tanimura /*
1017937c4dfaSSeigo Tanimura  * ffs_inode_hash_lock is a variable to manage mutual exclusion
1018937c4dfaSSeigo Tanimura  * of vnode allocation and intertion to the hash, especially to
1019937c4dfaSSeigo Tanimura  * avoid holding more than one vnodes for the same inode in the
1020937c4dfaSSeigo Tanimura  * hash table. ffs_inode_hash_lock must hence be tested-and-set
1021937c4dfaSSeigo Tanimura  * or cleared atomically, accomplished by ffs_inode_hash_mtx.
1022937c4dfaSSeigo Tanimura  *
1023937c4dfaSSeigo Tanimura  * As vnode allocation may block during MALLOC() and zone
1024937c4dfaSSeigo Tanimura  * allocation, we should also do msleep() to give away the CPU
1025937c4dfaSSeigo Tanimura  * if anyone else is allocating a vnode. lockmgr is not suitable
1026937c4dfaSSeigo Tanimura  * here because someone else may insert to the hash table the
1027937c4dfaSSeigo Tanimura  * vnode we are trying to allocate during our sleep, in which
1028937c4dfaSSeigo Tanimura  * case the hash table needs to be examined once again after
1029937c4dfaSSeigo Tanimura  * waking up.
1030937c4dfaSSeigo Tanimura  */
1031937c4dfaSSeigo Tanimura static struct mtx ffs_inode_hash_mtx;
10322094ddb6SDavid Greenman 
1033df8bae1dSRodney W. Grimes int
1034df8bae1dSRodney W. Grimes ffs_vget(mp, ino, vpp)
1035df8bae1dSRodney W. Grimes 	struct mount *mp;
1036df8bae1dSRodney W. Grimes 	ino_t ino;
1037df8bae1dSRodney W. Grimes 	struct vnode **vpp;
1038df8bae1dSRodney W. Grimes {
1039996c772fSJohn Dyson 	struct fs *fs;
1040996c772fSJohn Dyson 	struct inode *ip;
1041df8bae1dSRodney W. Grimes 	struct ufsmount *ump;
1042df8bae1dSRodney W. Grimes 	struct buf *bp;
1043df8bae1dSRodney W. Grimes 	struct vnode *vp;
1044df8bae1dSRodney W. Grimes 	dev_t dev;
1045937c4dfaSSeigo Tanimura 	int error, want_wakeup;
1046df8bae1dSRodney W. Grimes 
1047df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
1048df8bae1dSRodney W. Grimes 	dev = ump->um_dev;
10498997d94fSDavid Greenman restart:
10508f9110f6SJohn Dyson 	if ((*vpp = ufs_ihashget(dev, ino)) != NULL) {
1051df8bae1dSRodney W. Grimes 		return (0);
10528f9110f6SJohn Dyson 	}
1053df8bae1dSRodney W. Grimes 
10542094ddb6SDavid Greenman 	/*
10558997d94fSDavid Greenman 	 * Lock out the creation of new entries in the FFS hash table in
10568997d94fSDavid Greenman 	 * case getnewvnode() or MALLOC() blocks, otherwise a duplicate
10572094ddb6SDavid Greenman 	 * may occur!
10582094ddb6SDavid Greenman 	 */
1059937c4dfaSSeigo Tanimura 	mtx_enter(&ffs_inode_hash_mtx, MTX_DEF);
10602094ddb6SDavid Greenman 	if (ffs_inode_hash_lock) {
10612094ddb6SDavid Greenman 		while (ffs_inode_hash_lock) {
10622094ddb6SDavid Greenman 			ffs_inode_hash_lock = -1;
1063937c4dfaSSeigo Tanimura 			msleep(&ffs_inode_hash_lock, &ffs_inode_hash_mtx, PVM, "ffsvgt", 0);
10642094ddb6SDavid Greenman 		}
1065937c4dfaSSeigo Tanimura 		mtx_exit(&ffs_inode_hash_mtx, MTX_DEF);
10668997d94fSDavid Greenman 		goto restart;
10672094ddb6SDavid Greenman 	}
10682094ddb6SDavid Greenman 	ffs_inode_hash_lock = 1;
1069937c4dfaSSeigo Tanimura 	mtx_exit(&ffs_inode_hash_mtx, MTX_DEF);
10702094ddb6SDavid Greenman 
10712f9bae59SDavid Greenman 	/*
10722f9bae59SDavid Greenman 	 * If this MALLOC() is performed after the getnewvnode()
10732f9bae59SDavid Greenman 	 * it might block, leaving a vnode with a NULL v_data to be
10742f9bae59SDavid Greenman 	 * found by ffs_sync() if a sync happens to fire right then,
10752f9bae59SDavid Greenman 	 * which will cause a panic because ffs_sync() blindly
10762f9bae59SDavid Greenman 	 * dereferences vp->v_data (as well it should).
10772f9bae59SDavid Greenman 	 */
10780be6b890SPoul-Henning Kamp 	MALLOC(ip, struct inode *, sizeof(struct inode),
10790be6b890SPoul-Henning Kamp 	    ump->um_malloctype, M_WAITOK);
10802f9bae59SDavid Greenman 
1081df8bae1dSRodney W. Grimes 	/* Allocate a new vnode/inode. */
1082c9671602SPoul-Henning Kamp 	error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp);
1083c9671602SPoul-Henning Kamp 	if (error) {
1084937c4dfaSSeigo Tanimura 		/*
1085937c4dfaSSeigo Tanimura 		 * Do not wake up processes while holding the mutex,
1086937c4dfaSSeigo Tanimura 		 * otherwise the processes waken up immediately hit
1087937c4dfaSSeigo Tanimura 		 * themselves into the mutex.
1088937c4dfaSSeigo Tanimura 		 */
1089937c4dfaSSeigo Tanimura 		mtx_enter(&ffs_inode_hash_mtx, MTX_DEF);
1090937c4dfaSSeigo Tanimura 		want_wakeup = ffs_inode_hash_lock < 0;
10912094ddb6SDavid Greenman 		ffs_inode_hash_lock = 0;
1092937c4dfaSSeigo Tanimura 		mtx_exit(&ffs_inode_hash_mtx, MTX_DEF);
1093937c4dfaSSeigo Tanimura 		if (want_wakeup)
1094937c4dfaSSeigo Tanimura 			wakeup(&ffs_inode_hash_lock);
1095df8bae1dSRodney W. Grimes 		*vpp = NULL;
10960be6b890SPoul-Henning Kamp 		FREE(ip, ump->um_malloctype);
1097df8bae1dSRodney W. Grimes 		return (error);
1098df8bae1dSRodney W. Grimes 	}
1099df8bae1dSRodney W. Grimes 	bzero((caddr_t)ip, sizeof(struct inode));
110067e87166SBoris Popov 	/*
110167e87166SBoris Popov 	 * FFS supports lock sharing in the stack of vnodes
110267e87166SBoris Popov 	 */
110367e87166SBoris Popov 	vp->v_vnlock = &vp->v_lock;
110467e87166SBoris Popov 	lockinit(vp->v_vnlock, PINOD, "inode", 0, LK_CANRECURSE);
1105df8bae1dSRodney W. Grimes 	vp->v_data = ip;
1106df8bae1dSRodney W. Grimes 	ip->i_vnode = vp;
1107df8bae1dSRodney W. Grimes 	ip->i_fs = fs = ump->um_fs;
1108df8bae1dSRodney W. Grimes 	ip->i_dev = dev;
1109df8bae1dSRodney W. Grimes 	ip->i_number = ino;
1110df8bae1dSRodney W. Grimes #ifdef QUOTA
1111c1d9efcbSPoul-Henning Kamp 	{
1112c1d9efcbSPoul-Henning Kamp 		int i;
1113df8bae1dSRodney W. Grimes 		for (i = 0; i < MAXQUOTAS; i++)
1114df8bae1dSRodney W. Grimes 			ip->i_dquot[i] = NODQUOT;
1115c1d9efcbSPoul-Henning Kamp 	}
1116df8bae1dSRodney W. Grimes #endif
1117df8bae1dSRodney W. Grimes 	/*
1118df8bae1dSRodney W. Grimes 	 * Put it onto its hash chain and lock it so that other requests for
1119df8bae1dSRodney W. Grimes 	 * this inode will block if they arrive while we are sleeping waiting
1120df8bae1dSRodney W. Grimes 	 * for old data structures to be purged or for the contents of the
1121df8bae1dSRodney W. Grimes 	 * disk portion of this inode to be read.
1122df8bae1dSRodney W. Grimes 	 */
1123df8bae1dSRodney W. Grimes 	ufs_ihashins(ip);
1124df8bae1dSRodney W. Grimes 
1125937c4dfaSSeigo Tanimura 	/*
1126937c4dfaSSeigo Tanimura 	 * Do not wake up processes while holding the mutex,
1127937c4dfaSSeigo Tanimura 	 * otherwise the processes waken up immediately hit
1128937c4dfaSSeigo Tanimura 	 * themselves into the mutex.
1129937c4dfaSSeigo Tanimura 	 */
1130937c4dfaSSeigo Tanimura 	mtx_enter(&ffs_inode_hash_mtx, MTX_DEF);
1131937c4dfaSSeigo Tanimura 	want_wakeup = ffs_inode_hash_lock < 0;
11322094ddb6SDavid Greenman 	ffs_inode_hash_lock = 0;
1133937c4dfaSSeigo Tanimura 	mtx_exit(&ffs_inode_hash_mtx, MTX_DEF);
1134937c4dfaSSeigo Tanimura 	if (want_wakeup)
1135937c4dfaSSeigo Tanimura 		wakeup(&ffs_inode_hash_lock);
11362094ddb6SDavid Greenman 
1137df8bae1dSRodney W. Grimes 	/* Read in the disk contents for the inode, copy into the inode. */
1138c9671602SPoul-Henning Kamp 	error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
1139c9671602SPoul-Henning Kamp 	    (int)fs->fs_bsize, NOCRED, &bp);
1140c9671602SPoul-Henning Kamp 	if (error) {
1141df8bae1dSRodney W. Grimes 		/*
1142df8bae1dSRodney W. Grimes 		 * The inode does not contain anything useful, so it would
1143df8bae1dSRodney W. Grimes 		 * be misleading to leave it on its hash chain. With mode
1144df8bae1dSRodney W. Grimes 		 * still zero, it will be unlinked and returned to the free
1145df8bae1dSRodney W. Grimes 		 * list by vput().
1146df8bae1dSRodney W. Grimes 		 */
1147df8bae1dSRodney W. Grimes 		brelse(bp);
1148bd7e5f99SJohn Dyson 		vput(vp);
1149df8bae1dSRodney W. Grimes 		*vpp = NULL;
1150df8bae1dSRodney W. Grimes 		return (error);
1151df8bae1dSRodney W. Grimes 	}
1152df8bae1dSRodney W. Grimes 	ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ino));
1153b1897c19SJulian Elischer 	if (DOINGSOFTDEP(vp))
1154b1897c19SJulian Elischer 		softdep_load_inodeblock(ip);
1155b1897c19SJulian Elischer 	else
1156b1897c19SJulian Elischer 		ip->i_effnlink = ip->i_nlink;
1157bd7e5f99SJohn Dyson 	bqrelse(bp);
1158df8bae1dSRodney W. Grimes 
1159df8bae1dSRodney W. Grimes 	/*
1160df8bae1dSRodney W. Grimes 	 * Initialize the vnode from the inode, check for aliases.
1161df8bae1dSRodney W. Grimes 	 * Note that the underlying vnode may have changed.
1162df8bae1dSRodney W. Grimes 	 */
1163e6302eabSBruce Evans 	error = ufs_vinit(mp, ffs_specop_p, ffs_fifoop_p, &vp);
1164c9671602SPoul-Henning Kamp 	if (error) {
1165df8bae1dSRodney W. Grimes 		vput(vp);
1166df8bae1dSRodney W. Grimes 		*vpp = NULL;
1167df8bae1dSRodney W. Grimes 		return (error);
1168df8bae1dSRodney W. Grimes 	}
1169df8bae1dSRodney W. Grimes 	/*
1170df8bae1dSRodney W. Grimes 	 * Finish inode initialization now that aliasing has been resolved.
1171df8bae1dSRodney W. Grimes 	 */
1172df8bae1dSRodney W. Grimes 	ip->i_devvp = ump->um_devvp;
1173df8bae1dSRodney W. Grimes 	VREF(ip->i_devvp);
1174df8bae1dSRodney W. Grimes 	/*
1175df8bae1dSRodney W. Grimes 	 * Set up a generation number for this inode if it does not
1176df8bae1dSRodney W. Grimes 	 * already have one. This should only happen on old filesystems.
1177df8bae1dSRodney W. Grimes 	 */
1178df8bae1dSRodney W. Grimes 	if (ip->i_gen == 0) {
11798f89943eSGuido van Rooij 		ip->i_gen = random() / 2 + 1;
1180df8bae1dSRodney W. Grimes 		if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
1181df8bae1dSRodney W. Grimes 			ip->i_flag |= IN_MODIFIED;
1182df8bae1dSRodney W. Grimes 	}
1183df8bae1dSRodney W. Grimes 	/*
1184df8bae1dSRodney W. Grimes 	 * Ensure that uid and gid are correct. This is a temporary
1185df8bae1dSRodney W. Grimes 	 * fix until fsck has been changed to do the update.
1186df8bae1dSRodney W. Grimes 	 */
1187df8bae1dSRodney W. Grimes 	if (fs->fs_inodefmt < FS_44INODEFMT) {		/* XXX */
1188df8bae1dSRodney W. Grimes 		ip->i_uid = ip->i_din.di_ouid;		/* XXX */
1189df8bae1dSRodney W. Grimes 		ip->i_gid = ip->i_din.di_ogid;		/* XXX */
1190df8bae1dSRodney W. Grimes 	}						/* XXX */
1191df8bae1dSRodney W. Grimes 
1192df8bae1dSRodney W. Grimes 	*vpp = vp;
1193df8bae1dSRodney W. Grimes 	return (0);
1194df8bae1dSRodney W. Grimes }
1195df8bae1dSRodney W. Grimes 
1196df8bae1dSRodney W. Grimes /*
1197df8bae1dSRodney W. Grimes  * File handle to vnode
1198df8bae1dSRodney W. Grimes  *
1199df8bae1dSRodney W. Grimes  * Have to be really careful about stale file handles:
1200df8bae1dSRodney W. Grimes  * - check that the inode number is valid
1201df8bae1dSRodney W. Grimes  * - call ffs_vget() to get the locked inode
1202df8bae1dSRodney W. Grimes  * - check for an unallocated inode (i_mode == 0)
1203df8bae1dSRodney W. Grimes  * - check that the given client host has export rights and return
1204df8bae1dSRodney W. Grimes  *   those rights via. exflagsp and credanonp
1205df8bae1dSRodney W. Grimes  */
1206df8bae1dSRodney W. Grimes int
1207c24fda81SAlfred Perlstein ffs_fhtovp(mp, fhp, vpp)
1208df8bae1dSRodney W. Grimes 	register struct mount *mp;
1209df8bae1dSRodney W. Grimes 	struct fid *fhp;
1210df8bae1dSRodney W. Grimes 	struct vnode **vpp;
1211df8bae1dSRodney W. Grimes {
1212df8bae1dSRodney W. Grimes 	register struct ufid *ufhp;
1213df8bae1dSRodney W. Grimes 	struct fs *fs;
1214df8bae1dSRodney W. Grimes 
1215df8bae1dSRodney W. Grimes 	ufhp = (struct ufid *)fhp;
1216df8bae1dSRodney W. Grimes 	fs = VFSTOUFS(mp)->um_fs;
1217df8bae1dSRodney W. Grimes 	if (ufhp->ufid_ino < ROOTINO ||
1218df8bae1dSRodney W. Grimes 	    ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg)
1219df8bae1dSRodney W. Grimes 		return (ESTALE);
1220c24fda81SAlfred Perlstein 	return (ufs_fhtovp(mp, ufhp, vpp));
1221df8bae1dSRodney W. Grimes }
1222df8bae1dSRodney W. Grimes 
1223df8bae1dSRodney W. Grimes /*
1224df8bae1dSRodney W. Grimes  * Vnode pointer to File handle
1225df8bae1dSRodney W. Grimes  */
1226df8bae1dSRodney W. Grimes /* ARGSUSED */
122726f9a767SRodney W. Grimes int
1228df8bae1dSRodney W. Grimes ffs_vptofh(vp, fhp)
1229df8bae1dSRodney W. Grimes 	struct vnode *vp;
1230df8bae1dSRodney W. Grimes 	struct fid *fhp;
1231df8bae1dSRodney W. Grimes {
1232df8bae1dSRodney W. Grimes 	register struct inode *ip;
1233df8bae1dSRodney W. Grimes 	register struct ufid *ufhp;
1234df8bae1dSRodney W. Grimes 
1235df8bae1dSRodney W. Grimes 	ip = VTOI(vp);
1236df8bae1dSRodney W. Grimes 	ufhp = (struct ufid *)fhp;
1237df8bae1dSRodney W. Grimes 	ufhp->ufid_len = sizeof(struct ufid);
1238df8bae1dSRodney W. Grimes 	ufhp->ufid_ino = ip->i_number;
1239df8bae1dSRodney W. Grimes 	ufhp->ufid_gen = ip->i_gen;
1240df8bae1dSRodney W. Grimes 	return (0);
1241df8bae1dSRodney W. Grimes }
1242df8bae1dSRodney W. Grimes 
1243df8bae1dSRodney W. Grimes /*
1244996c772fSJohn Dyson  * Initialize the filesystem; just use ufs_init.
1245996c772fSJohn Dyson  */
1246996c772fSJohn Dyson static int
1247996c772fSJohn Dyson ffs_init(vfsp)
1248996c772fSJohn Dyson 	struct vfsconf *vfsp;
1249996c772fSJohn Dyson {
1250996c772fSJohn Dyson 
1251b1897c19SJulian Elischer 	softdep_initialize();
1252937c4dfaSSeigo Tanimura 	mtx_init(&ffs_inode_hash_mtx, "ifsvgt", MTX_DEF);
1253996c772fSJohn Dyson 	return (ufs_init(vfsp));
1254996c772fSJohn Dyson }
1255996c772fSJohn Dyson 
1256996c772fSJohn Dyson /*
1257df8bae1dSRodney W. Grimes  * Write a superblock and associated information back to disk.
1258df8bae1dSRodney W. Grimes  */
1259b8dce649SPoul-Henning Kamp static int
1260df8bae1dSRodney W. Grimes ffs_sbupdate(mp, waitfor)
1261df8bae1dSRodney W. Grimes 	struct ufsmount *mp;
1262df8bae1dSRodney W. Grimes 	int waitfor;
1263df8bae1dSRodney W. Grimes {
1264996c772fSJohn Dyson 	register struct fs *dfs, *fs = mp->um_fs;
1265df8bae1dSRodney W. Grimes 	register struct buf *bp;
1266df8bae1dSRodney W. Grimes 	int blks;
1267f55ff3f3SIan Dowse 	void *space;
1268996c772fSJohn Dyson 	int i, size, error, allerror = 0;
1269df8bae1dSRodney W. Grimes 
1270996c772fSJohn Dyson 	/*
1271996c772fSJohn Dyson 	 * First write back the summary information.
1272996c772fSJohn Dyson 	 */
1273df8bae1dSRodney W. Grimes 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
1274f55ff3f3SIan Dowse 	space = fs->fs_csp;
1275df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
1276df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
1277df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
1278df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
1279df8bae1dSRodney W. Grimes 		bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i),
1280df8bae1dSRodney W. Grimes 		    size, 0, 0);
1281df8bae1dSRodney W. Grimes 		bcopy(space, bp->b_data, (u_int)size);
1282f55ff3f3SIan Dowse 		space = (char *)space + size;
1283996c772fSJohn Dyson 		if (waitfor != MNT_WAIT)
1284df8bae1dSRodney W. Grimes 			bawrite(bp);
12858aef1712SMatthew Dillon 		else if ((error = bwrite(bp)) != 0)
1286996c772fSJohn Dyson 			allerror = error;
1287df8bae1dSRodney W. Grimes 	}
1288996c772fSJohn Dyson 	/*
1289996c772fSJohn Dyson 	 * Now write back the superblock itself. If any errors occurred
1290996c772fSJohn Dyson 	 * up to this point, then fail so that the superblock avoids
1291996c772fSJohn Dyson 	 * being written out as clean.
1292996c772fSJohn Dyson 	 */
1293996c772fSJohn Dyson 	if (allerror)
1294996c772fSJohn Dyson 		return (allerror);
1295996c772fSJohn Dyson 	bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0);
1296b1897c19SJulian Elischer 	fs->fs_fmod = 0;
1297227ee8a1SPoul-Henning Kamp 	fs->fs_time = time_second;
1298996c772fSJohn Dyson 	bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize);
1299996c772fSJohn Dyson 	/* Restore compatibility to old file systems.		   XXX */
1300996c772fSJohn Dyson 	dfs = (struct fs *)bp->b_data;				/* XXX */
1301996c772fSJohn Dyson 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
1302996c772fSJohn Dyson 		dfs->fs_nrpos = -1;				/* XXX */
1303996c772fSJohn Dyson 	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
1304996c772fSJohn Dyson 		int32_t *lp, tmp;				/* XXX */
1305996c772fSJohn Dyson 								/* XXX */
1306996c772fSJohn Dyson 		lp = (int32_t *)&dfs->fs_qbmask;		/* XXX */
1307996c772fSJohn Dyson 		tmp = lp[4];					/* XXX */
1308996c772fSJohn Dyson 		for (i = 4; i > 0; i--)				/* XXX */
1309996c772fSJohn Dyson 			lp[i] = lp[i-1];			/* XXX */
1310996c772fSJohn Dyson 		lp[0] = tmp;					/* XXX */
1311996c772fSJohn Dyson 	}							/* XXX */
1312996c772fSJohn Dyson 	dfs->fs_maxfilesize = mp->um_savedmaxfilesize;		/* XXX */
1313996c772fSJohn Dyson 	if (waitfor != MNT_WAIT)
1314996c772fSJohn Dyson 		bawrite(bp);
13158aef1712SMatthew Dillon 	else if ((error = bwrite(bp)) != 0)
1316996c772fSJohn Dyson 		allerror = error;
1317996c772fSJohn Dyson 	return (allerror);
1318df8bae1dSRodney W. Grimes }
1319