xref: /freebsd/sys/ufs/ffs/ffs_vfsops.c (revision 9b97113391a63a82eeac6ccbbdf607f67bce1d08)
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 
54a64ed089SRobert Watson #include <ufs/ufs/extattr.h>
55df8bae1dSRodney W. Grimes #include <ufs/ufs/quota.h>
56df8bae1dSRodney W. Grimes #include <ufs/ufs/ufsmount.h>
57df8bae1dSRodney W. Grimes #include <ufs/ufs/inode.h>
58df8bae1dSRodney W. Grimes #include <ufs/ufs/ufs_extern.h>
59df8bae1dSRodney W. Grimes 
60df8bae1dSRodney W. Grimes #include <ufs/ffs/fs.h>
61df8bae1dSRodney W. Grimes #include <ufs/ffs/ffs_extern.h>
62df8bae1dSRodney W. Grimes 
63f6b04d2bSDavid Greenman #include <vm/vm.h>
64f6b04d2bSDavid Greenman #include <vm/vm_page.h>
65f6b04d2bSDavid Greenman 
66a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_FFSNODE, "FFS node", "FFS vnode private part");
6755166637SPoul-Henning Kamp 
68b8dce649SPoul-Henning Kamp static int	ffs_sbupdate __P((struct ufsmount *, int));
69b8dce649SPoul-Henning Kamp static int	ffs_reload __P((struct mount *,struct ucred *,struct proc *));
70b8dce649SPoul-Henning Kamp static int	ffs_oldfscompat __P((struct fs *));
71996c772fSJohn Dyson static int	ffs_mount __P((struct mount *, char *, caddr_t,
72996c772fSJohn Dyson 				struct nameidata *, struct proc *));
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  */
135b8dce649SPoul-Henning Kamp static 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  */
360b8dce649SPoul-Henning Kamp static 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;
368df8bae1dSRodney W. Grimes 	struct csum *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);
3972d8acc0fSJohn Dyson 		simple_lock(&devvp->v_interlock);
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 	 */
422996c772fSJohn Dyson 	bcopy(&fs->fs_csp[0], &newfs->fs_csp[0], sizeof(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);
435df8bae1dSRodney W. Grimes 	space = fs->fs_csp[0];
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);
444df8bae1dSRodney W. Grimes 		bcopy(bp->b_data, fs->fs_csp[fragstoblks(fs, i)], (u_int)size);
445df8bae1dSRodney W. Grimes 		brelse(bp);
446df8bae1dSRodney W. Grimes 	}
447996c772fSJohn Dyson 	/*
448996c772fSJohn Dyson 	 * We no longer know anything about clusters per cylinder group.
449996c772fSJohn Dyson 	 */
450996c772fSJohn Dyson 	if (fs->fs_contigsumsize > 0) {
451996c772fSJohn Dyson 		lp = fs->fs_maxcluster;
452996c772fSJohn Dyson 		for (i = 0; i < fs->fs_ncg; i++)
453996c772fSJohn Dyson 			*lp++ = fs->fs_contigsumsize;
454996c772fSJohn Dyson 	}
455996c772fSJohn Dyson 
456df8bae1dSRodney W. Grimes loop:
457996c772fSJohn Dyson 	simple_lock(&mntvnode_slock);
4582b14f991SJulian Elischer 	for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
459996c772fSJohn Dyson 		if (vp->v_mount != mp) {
460996c772fSJohn Dyson 			simple_unlock(&mntvnode_slock);
461996c772fSJohn Dyson 			goto loop;
462996c772fSJohn Dyson 		}
463df8bae1dSRodney W. Grimes 		nvp = vp->v_mntvnodes.le_next;
464df8bae1dSRodney W. Grimes 		/*
465df8bae1dSRodney W. Grimes 		 * Step 4: invalidate all inactive vnodes.
466df8bae1dSRodney W. Grimes 		 */
467996c772fSJohn Dyson 		if (vrecycle(vp, &mntvnode_slock, p))
468996c772fSJohn Dyson 			goto loop;
469df8bae1dSRodney W. Grimes 		/*
470df8bae1dSRodney W. Grimes 		 * Step 5: invalidate all cached file data.
471df8bae1dSRodney W. Grimes 		 */
472996c772fSJohn Dyson 		simple_lock(&vp->v_interlock);
473996c772fSJohn Dyson 		simple_unlock(&mntvnode_slock);
474996c772fSJohn Dyson 		if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) {
475df8bae1dSRodney W. Grimes 			goto loop;
476996c772fSJohn Dyson 		}
477df8bae1dSRodney W. Grimes 		if (vinvalbuf(vp, 0, cred, p, 0, 0))
478df8bae1dSRodney W. Grimes 			panic("ffs_reload: dirty2");
479df8bae1dSRodney W. Grimes 		/*
480df8bae1dSRodney W. Grimes 		 * Step 6: re-read inode data for all active vnodes.
481df8bae1dSRodney W. Grimes 		 */
482df8bae1dSRodney W. Grimes 		ip = VTOI(vp);
483c9671602SPoul-Henning Kamp 		error =
484df8bae1dSRodney W. Grimes 		    bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
485c9671602SPoul-Henning Kamp 		    (int)fs->fs_bsize, NOCRED, &bp);
486c9671602SPoul-Henning Kamp 		if (error) {
487df8bae1dSRodney W. Grimes 			vput(vp);
488df8bae1dSRodney W. Grimes 			return (error);
489df8bae1dSRodney W. Grimes 		}
490df8bae1dSRodney W. Grimes 		ip->i_din = *((struct dinode *)bp->b_data +
491df8bae1dSRodney W. Grimes 		    ino_to_fsbo(fs, ip->i_number));
492b1897c19SJulian Elischer 		ip->i_effnlink = ip->i_nlink;
493df8bae1dSRodney W. Grimes 		brelse(bp);
494df8bae1dSRodney W. Grimes 		vput(vp);
495996c772fSJohn Dyson 		simple_lock(&mntvnode_slock);
496df8bae1dSRodney W. Grimes 	}
497996c772fSJohn Dyson 	simple_unlock(&mntvnode_slock);
498df8bae1dSRodney W. Grimes 	return (0);
499df8bae1dSRodney W. Grimes }
500df8bae1dSRodney W. Grimes 
501df8bae1dSRodney W. Grimes /*
502df8bae1dSRodney W. Grimes  * Common code for mount and mountroot
503df8bae1dSRodney W. Grimes  */
504df8bae1dSRodney W. Grimes int
5050be6b890SPoul-Henning Kamp ffs_mountfs(devvp, mp, p, malloctype)
506df8bae1dSRodney W. Grimes 	register struct vnode *devvp;
507df8bae1dSRodney W. Grimes 	struct mount *mp;
508df8bae1dSRodney W. Grimes 	struct proc *p;
5090be6b890SPoul-Henning Kamp 	struct malloc_type *malloctype;
510df8bae1dSRodney W. Grimes {
511df8bae1dSRodney W. Grimes 	register struct ufsmount *ump;
512df8bae1dSRodney W. Grimes 	struct buf *bp;
513df8bae1dSRodney W. Grimes 	register struct fs *fs;
514996c772fSJohn Dyson 	dev_t dev;
515df8bae1dSRodney W. Grimes 	struct partinfo dpart;
516df8bae1dSRodney W. Grimes 	caddr_t base, space;
517f5ef029eSPoul-Henning Kamp 	int error, i, blks, size, ronly;
518996c772fSJohn Dyson 	int32_t *lp;
519996c772fSJohn Dyson 	struct ucred *cred;
520996c772fSJohn Dyson 	u_int64_t maxfilesize;					/* XXX */
5218435e0aeSDoug Rabson 	size_t strsize;
5226476c0d2SJohn Dyson 	int ncount;
523df8bae1dSRodney W. Grimes 
524996c772fSJohn Dyson 	dev = devvp->v_rdev;
525996c772fSJohn Dyson 	cred = p ? p->p_ucred : NOCRED;
526df8bae1dSRodney W. Grimes 	/*
527df8bae1dSRodney W. Grimes 	 * Disallow multiple mounts of the same device.
528df8bae1dSRodney W. Grimes 	 * Disallow mounting of a device that is currently in use
529df8bae1dSRodney W. Grimes 	 * (except for root, which might share swap device for miniroot).
530df8bae1dSRodney W. Grimes 	 * Flush out any old buffers remaining from a previous use.
531df8bae1dSRodney W. Grimes 	 */
532c9671602SPoul-Henning Kamp 	error = vfs_mountedon(devvp);
533c9671602SPoul-Henning Kamp 	if (error)
534df8bae1dSRodney W. Grimes 		return (error);
5356476c0d2SJohn Dyson 	ncount = vcount(devvp);
5368f9110f6SJohn Dyson 
5376476c0d2SJohn Dyson 	if (ncount > 1 && devvp != rootvp)
538df8bae1dSRodney W. Grimes 		return (EBUSY);
539b1897c19SJulian Elischer 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
540b1897c19SJulian Elischer 	error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0);
541b1897c19SJulian Elischer 	VOP_UNLOCK(devvp, 0, p);
542b1897c19SJulian Elischer 	if (error)
543df8bae1dSRodney W. Grimes 		return (error);
544df8bae1dSRodney W. Grimes 
54595e5e988SJohn Dyson 	/*
54695e5e988SJohn Dyson 	 * Only VMIO the backing device if the backing device is a real
54795e5e988SJohn Dyson 	 * block device.  This excludes the original MFS implementation.
54895e5e988SJohn Dyson 	 * Note that it is optional that the backing device be VMIOed.  This
54995e5e988SJohn Dyson 	 * increases the opportunity for metadata caching.
55095e5e988SJohn Dyson 	 */
551ba4ad1fcSPoul-Henning Kamp 	if (devvp->v_tag != VT_MFS && vn_isdisk(devvp, NULL)) {
552a777e820SEivind Eklund 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
5533fbd9742SBoris Popov 		vfs_object_create(devvp, p, cred);
55416337c2eSBruce Evans 		simple_lock(&devvp->v_interlock);
555a777e820SEivind Eklund 		VOP_UNLOCK(devvp, LK_INTERLOCK, p);
55695e5e988SJohn Dyson 	}
55795e5e988SJohn Dyson 
558df8bae1dSRodney W. Grimes 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
559698f9cf8SPoul-Henning Kamp 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
560c9671602SPoul-Henning Kamp 	error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
561698f9cf8SPoul-Henning Kamp 	VOP_UNLOCK(devvp, 0, p);
562c9671602SPoul-Henning Kamp 	if (error)
563df8bae1dSRodney W. Grimes 		return (error);
5641b5464efSPoul-Henning Kamp 	if (devvp->v_rdev->si_iosize_max > mp->mnt_iosize_max)
5651b5464efSPoul-Henning Kamp 		mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max;
5661b5464efSPoul-Henning Kamp 	if (mp->mnt_iosize_max > MAXPHYS)
5671b5464efSPoul-Henning Kamp 		mp->mnt_iosize_max = MAXPHYS;
56895e5e988SJohn Dyson 
569996c772fSJohn Dyson 	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0)
570df8bae1dSRodney W. Grimes 		size = DEV_BSIZE;
571996c772fSJohn Dyson 	else
572df8bae1dSRodney W. Grimes 		size = dpart.disklab->d_secsize;
573df8bae1dSRodney W. Grimes 
574df8bae1dSRodney W. Grimes 	bp = NULL;
575df8bae1dSRodney W. Grimes 	ump = NULL;
5768aef1712SMatthew Dillon 	if ((error = bread(devvp, SBLOCK, SBSIZE, cred, &bp)) != 0)
577df8bae1dSRodney W. Grimes 		goto out;
578df8bae1dSRodney W. Grimes 	fs = (struct fs *)bp->b_data;
579df8bae1dSRodney W. Grimes 	if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
580df8bae1dSRodney W. Grimes 	    fs->fs_bsize < sizeof(struct fs)) {
581df8bae1dSRodney W. Grimes 		error = EINVAL;		/* XXX needs translation */
582df8bae1dSRodney W. Grimes 		goto out;
583df8bae1dSRodney W. Grimes 	}
5843f6f17eeSJulian Elischer 	fs->fs_fmod = 0;
5850922cce6SBruce Evans 	fs->fs_flags &= ~FS_UNCLEAN;
5860922cce6SBruce Evans 	if (fs->fs_clean == 0) {
5870922cce6SBruce Evans 		fs->fs_flags |= FS_UNCLEAN;
5881469eec8SDavid Greenman 		if (ronly || (mp->mnt_flag & MNT_FORCE)) {
5890922cce6SBruce Evans 			printf(
5900922cce6SBruce Evans "WARNING: %s was not properly dismounted\n",
5910922cce6SBruce Evans 			    fs->fs_fsmnt);
5921469eec8SDavid Greenman 		} else {
5930922cce6SBruce Evans 			printf(
5940922cce6SBruce Evans "WARNING: R/W mount of %s denied.  Filesystem is not clean - run fsck\n",
5950922cce6SBruce Evans 			    fs->fs_fsmnt);
5961469eec8SDavid Greenman 			error = EPERM;
5971469eec8SDavid Greenman 			goto out;
5981469eec8SDavid Greenman 		}
5991469eec8SDavid Greenman 	}
600996c772fSJohn Dyson 	/* XXX updating 4.2 FFS superblocks trashes rotational layout tables */
601996c772fSJohn Dyson 	if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) {
602996c772fSJohn Dyson 		error = EROFS;          /* needs translation */
603996c772fSJohn Dyson 		goto out;
604996c772fSJohn Dyson 	}
605df8bae1dSRodney W. Grimes 	ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
606df8bae1dSRodney W. Grimes 	bzero((caddr_t)ump, sizeof *ump);
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);
627996c772fSJohn Dyson 	base = space = malloc((u_long)size, M_UFSMNT, M_WAITOK);
628df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
629df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
630df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
631df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
6328aef1712SMatthew Dillon 		if ((error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
6338aef1712SMatthew Dillon 		    cred, &bp)) != 0) {
634df8bae1dSRodney W. Grimes 			free(base, M_UFSMNT);
635df8bae1dSRodney W. Grimes 			goto out;
636df8bae1dSRodney W. Grimes 		}
637df8bae1dSRodney W. Grimes 		bcopy(bp->b_data, space, (u_int)size);
638df8bae1dSRodney W. Grimes 		fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
639df8bae1dSRodney W. Grimes 		space += size;
640df8bae1dSRodney W. Grimes 		brelse(bp);
641df8bae1dSRodney W. Grimes 		bp = NULL;
642df8bae1dSRodney W. Grimes 	}
643996c772fSJohn Dyson 	if (fs->fs_contigsumsize > 0) {
644996c772fSJohn Dyson 		fs->fs_maxcluster = lp = (int32_t *)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
667b1897c19SJulian Elischer 	devvp->v_specmountpoint = 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) {
695b1897c19SJulian Elischer 			free(base, 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 	}
704df8bae1dSRodney W. Grimes 	return (0);
705df8bae1dSRodney W. Grimes out:
706b1897c19SJulian Elischer 	devvp->v_specmountpoint = NULL;
707df8bae1dSRodney W. Grimes 	if (bp)
708df8bae1dSRodney W. Grimes 		brelse(bp);
709996c772fSJohn Dyson 	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
710df8bae1dSRodney W. Grimes 	if (ump) {
711df8bae1dSRodney W. Grimes 		free(ump->um_fs, M_UFSMNT);
712df8bae1dSRodney W. Grimes 		free(ump, M_UFSMNT);
713df8bae1dSRodney W. Grimes 		mp->mnt_data = (qaddr_t)0;
714df8bae1dSRodney W. Grimes 	}
715df8bae1dSRodney W. Grimes 	return (error);
716df8bae1dSRodney W. Grimes }
717df8bae1dSRodney W. Grimes 
718df8bae1dSRodney W. Grimes /*
719df8bae1dSRodney W. Grimes  * Sanity checks for old file systems.
720df8bae1dSRodney W. Grimes  *
721df8bae1dSRodney W. Grimes  * XXX - goes away some day.
722df8bae1dSRodney W. Grimes  */
723b8dce649SPoul-Henning Kamp static int
724df8bae1dSRodney W. Grimes ffs_oldfscompat(fs)
725df8bae1dSRodney W. Grimes 	struct fs *fs;
726df8bae1dSRodney W. Grimes {
727df8bae1dSRodney W. Grimes 
728df8bae1dSRodney W. Grimes 	fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect);	/* XXX */
729df8bae1dSRodney W. Grimes 	fs->fs_interleave = max(fs->fs_interleave, 1);		/* XXX */
730df8bae1dSRodney W. Grimes 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
731df8bae1dSRodney W. Grimes 		fs->fs_nrpos = 8;				/* XXX */
732df8bae1dSRodney W. Grimes 	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
733c03020b2SPoul-Henning Kamp #if 0
734c03020b2SPoul-Henning Kamp 		int i;						/* XXX */
735996c772fSJohn Dyson 		u_int64_t sizepb = fs->fs_bsize;		/* XXX */
736996c772fSJohn Dyson 								/* XXX */
737df8bae1dSRodney W. Grimes 		fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1;	/* XXX */
738df8bae1dSRodney W. Grimes 		for (i = 0; i < NIADDR; i++) {			/* XXX */
739df8bae1dSRodney W. Grimes 			sizepb *= NINDIR(fs);			/* XXX */
740df8bae1dSRodney W. Grimes 			fs->fs_maxfilesize += sizepb;		/* XXX */
741df8bae1dSRodney W. Grimes 		}						/* XXX */
742901ba606SDavid Greenman #endif
743a316d390SJohn Dyson 		fs->fs_maxfilesize = (u_quad_t) 1LL << 39;
744df8bae1dSRodney W. Grimes 		fs->fs_qbmask = ~fs->fs_bmask;			/* XXX */
745df8bae1dSRodney W. Grimes 		fs->fs_qfmask = ~fs->fs_fmask;			/* XXX */
746df8bae1dSRodney W. Grimes 	}							/* XXX */
747df8bae1dSRodney W. Grimes 	return (0);
748df8bae1dSRodney W. Grimes }
749df8bae1dSRodney W. Grimes 
750df8bae1dSRodney W. Grimes /*
751df8bae1dSRodney W. Grimes  * unmount system call
752df8bae1dSRodney W. Grimes  */
753df8bae1dSRodney W. Grimes int
754df8bae1dSRodney W. Grimes ffs_unmount(mp, mntflags, p)
755df8bae1dSRodney W. Grimes 	struct mount *mp;
756df8bae1dSRodney W. Grimes 	int mntflags;
757df8bae1dSRodney W. Grimes 	struct proc *p;
758df8bae1dSRodney W. Grimes {
759df8bae1dSRodney W. Grimes 	register struct ufsmount *ump;
760df8bae1dSRodney W. Grimes 	register struct fs *fs;
761996c772fSJohn Dyson 	int error, flags;
762df8bae1dSRodney W. Grimes 
763df8bae1dSRodney W. Grimes 	flags = 0;
764df8bae1dSRodney W. Grimes 	if (mntflags & MNT_FORCE) {
765df8bae1dSRodney W. Grimes 		flags |= FORCECLOSE;
766df8bae1dSRodney W. Grimes 	}
767a64ed089SRobert Watson #ifdef FFS_EXTATTR
768b2b0497aSRobert Watson 	if ((error = ufs_extattr_stop(mp, p)))
769b2b0497aSRobert Watson 		if (error != EOPNOTSUPP)
770b2b0497aSRobert Watson 			printf("ffs_unmount: ufs_extattr_stop returned %d\n",
771b2b0497aSRobert Watson 			    error);
772a64ed089SRobert Watson #endif
773b1897c19SJulian Elischer 	if (mp->mnt_flag & MNT_SOFTDEP) {
774b1897c19SJulian Elischer 		if ((error = softdep_flushfiles(mp, flags, p)) != 0)
775df8bae1dSRodney W. Grimes 			return (error);
776b1897c19SJulian Elischer 	} else {
777b1897c19SJulian Elischer 		if ((error = ffs_flushfiles(mp, flags, p)) != 0)
778b1897c19SJulian Elischer 			return (error);
779b1897c19SJulian Elischer 	}
780df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
781df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
782996c772fSJohn Dyson 	if (fs->fs_ronly == 0) {
7830922cce6SBruce Evans 		fs->fs_clean = fs->fs_flags & FS_UNCLEAN ? 0 : 1;
784996c772fSJohn Dyson 		error = ffs_sbupdate(ump, MNT_WAIT);
785996c772fSJohn Dyson 		if (error) {
786996c772fSJohn Dyson 			fs->fs_clean = 0;
787996c772fSJohn Dyson 			return (error);
788996c772fSJohn Dyson 		}
789e0e9c421SDavid Greenman 	}
790b1897c19SJulian Elischer 	ump->um_devvp->v_specmountpoint = NULL;
7916476c0d2SJohn Dyson 
79295e5e988SJohn Dyson 	vinvalbuf(ump->um_devvp, V_SAVE, NOCRED, p, 0, 0);
793996c772fSJohn Dyson 	error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE,
794df8bae1dSRodney W. Grimes 		NOCRED, p);
7956476c0d2SJohn Dyson 
7966476c0d2SJohn Dyson 	vrele(ump->um_devvp);
7976476c0d2SJohn Dyson 
798df8bae1dSRodney W. Grimes 	free(fs->fs_csp[0], M_UFSMNT);
799df8bae1dSRodney W. Grimes 	free(fs, M_UFSMNT);
800df8bae1dSRodney W. Grimes 	free(ump, M_UFSMNT);
801df8bae1dSRodney W. Grimes 	mp->mnt_data = (qaddr_t)0;
802cc9d8990SPeter Wemm 	mp->mnt_flag &= ~MNT_LOCAL;
803df8bae1dSRodney W. Grimes 	return (error);
804df8bae1dSRodney W. Grimes }
805df8bae1dSRodney W. Grimes 
806df8bae1dSRodney W. Grimes /*
807df8bae1dSRodney W. Grimes  * Flush out all the files in a filesystem.
808df8bae1dSRodney W. Grimes  */
80926f9a767SRodney W. Grimes int
810df8bae1dSRodney W. Grimes ffs_flushfiles(mp, flags, p)
811df8bae1dSRodney W. Grimes 	register struct mount *mp;
812df8bae1dSRodney W. Grimes 	int flags;
813df8bae1dSRodney W. Grimes 	struct proc *p;
814df8bae1dSRodney W. Grimes {
815df8bae1dSRodney W. Grimes 	register struct ufsmount *ump;
816c9671602SPoul-Henning Kamp 	int error;
817df8bae1dSRodney W. Grimes 
818df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
819df8bae1dSRodney W. Grimes #ifdef QUOTA
820df8bae1dSRodney W. Grimes 	if (mp->mnt_flag & MNT_QUOTA) {
821c1d9efcbSPoul-Henning Kamp 		int i;
822c1d9efcbSPoul-Henning Kamp 		error = vflush(mp, NULLVP, SKIPSYSTEM|flags);
823c1d9efcbSPoul-Henning Kamp 		if (error)
824df8bae1dSRodney W. Grimes 			return (error);
825df8bae1dSRodney W. Grimes 		for (i = 0; i < MAXQUOTAS; i++) {
826df8bae1dSRodney W. Grimes 			if (ump->um_quotas[i] == NULLVP)
827df8bae1dSRodney W. Grimes 				continue;
828df8bae1dSRodney W. Grimes 			quotaoff(p, mp, i);
829df8bae1dSRodney W. Grimes 		}
830df8bae1dSRodney W. Grimes 		/*
831df8bae1dSRodney W. Grimes 		 * Here we fall through to vflush again to ensure
832df8bae1dSRodney W. Grimes 		 * that we have gotten rid of all the system vnodes.
833df8bae1dSRodney W. Grimes 		 */
834df8bae1dSRodney W. Grimes 	}
835df8bae1dSRodney W. Grimes #endif
836f2a2857bSKirk McKusick 	if (ump->um_devvp->v_flag & VCOPYONWRITE) {
837f2a2857bSKirk McKusick 		if ((error = vflush(mp, NULL, SKIPSYSTEM | flags)) != 0)
838f2a2857bSKirk McKusick 			return (error);
839f2a2857bSKirk McKusick 		ffs_snapshot_unmount(mp);
840f2a2857bSKirk McKusick 		/*
841f2a2857bSKirk McKusick 		 * Here we fall through to vflush again to ensure
842f2a2857bSKirk McKusick 		 * that we have gotten rid of all the system vnodes.
843f2a2857bSKirk McKusick 		 */
844f2a2857bSKirk McKusick 	}
845b1897c19SJulian Elischer         /*
846b1897c19SJulian Elischer 	 * Flush all the files.
847b1897c19SJulian Elischer 	 */
848b1897c19SJulian Elischer 	if ((error = vflush(mp, NULL, flags)) != 0)
849b1897c19SJulian Elischer 		return (error);
850b1897c19SJulian Elischer 	/*
851b1897c19SJulian Elischer 	 * Flush filesystem metadata.
852b1897c19SJulian Elischer 	 */
853b1897c19SJulian Elischer 	vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p);
854b1897c19SJulian Elischer 	error = VOP_FSYNC(ump->um_devvp, p->p_ucred, MNT_WAIT, p);
855b1897c19SJulian Elischer 	VOP_UNLOCK(ump->um_devvp, 0, p);
856df8bae1dSRodney W. Grimes 	return (error);
857df8bae1dSRodney W. Grimes }
858df8bae1dSRodney W. Grimes 
859df8bae1dSRodney W. Grimes /*
860df8bae1dSRodney W. Grimes  * Get file system statistics.
861df8bae1dSRodney W. Grimes  */
862df8bae1dSRodney W. Grimes int
863df8bae1dSRodney W. Grimes ffs_statfs(mp, sbp, p)
864df8bae1dSRodney W. Grimes 	struct mount *mp;
865df8bae1dSRodney W. Grimes 	register struct statfs *sbp;
866df8bae1dSRodney W. Grimes 	struct proc *p;
867df8bae1dSRodney W. Grimes {
868df8bae1dSRodney W. Grimes 	register struct ufsmount *ump;
869df8bae1dSRodney W. Grimes 	register struct fs *fs;
870df8bae1dSRodney W. Grimes 
871df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
872df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
873df8bae1dSRodney W. Grimes 	if (fs->fs_magic != FS_MAGIC)
874df8bae1dSRodney W. Grimes 		panic("ffs_statfs");
875df8bae1dSRodney W. Grimes 	sbp->f_bsize = fs->fs_fsize;
876df8bae1dSRodney W. Grimes 	sbp->f_iosize = fs->fs_bsize;
877df8bae1dSRodney W. Grimes 	sbp->f_blocks = fs->fs_dsize;
878df8bae1dSRodney W. Grimes 	sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
879df8bae1dSRodney W. Grimes 		fs->fs_cstotal.cs_nffree;
88051ea8b57SBruce Evans 	sbp->f_bavail = freespace(fs, fs->fs_minfree);
881df8bae1dSRodney W. Grimes 	sbp->f_files =  fs->fs_ncg * fs->fs_ipg - ROOTINO;
882df8bae1dSRodney W. Grimes 	sbp->f_ffree = fs->fs_cstotal.cs_nifree;
883df8bae1dSRodney W. Grimes 	if (sbp != &mp->mnt_stat) {
884996c772fSJohn Dyson 		sbp->f_type = mp->mnt_vfc->vfc_typenum;
885df8bae1dSRodney W. Grimes 		bcopy((caddr_t)mp->mnt_stat.f_mntonname,
886df8bae1dSRodney W. Grimes 			(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
887df8bae1dSRodney W. Grimes 		bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
888df8bae1dSRodney W. Grimes 			(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
889df8bae1dSRodney W. Grimes 	}
890df8bae1dSRodney W. Grimes 	return (0);
891df8bae1dSRodney W. Grimes }
892df8bae1dSRodney W. Grimes 
893df8bae1dSRodney W. Grimes /*
894df8bae1dSRodney W. Grimes  * Go through the disk queues to initiate sandbagged IO;
895df8bae1dSRodney W. Grimes  * go through the inodes to write those that have been modified;
896df8bae1dSRodney W. Grimes  * initiate the writing of the super block if it has been modified.
897df8bae1dSRodney W. Grimes  *
898df8bae1dSRodney W. Grimes  * Note: we are always called with the filesystem marked `MPBUSY'.
899df8bae1dSRodney W. Grimes  */
900df8bae1dSRodney W. Grimes int
901df8bae1dSRodney W. Grimes ffs_sync(mp, waitfor, cred, p)
902df8bae1dSRodney W. Grimes 	struct mount *mp;
903df8bae1dSRodney W. Grimes 	int waitfor;
904df8bae1dSRodney W. Grimes 	struct ucred *cred;
905df8bae1dSRodney W. Grimes 	struct proc *p;
906df8bae1dSRodney W. Grimes {
907996c772fSJohn Dyson 	struct vnode *nvp, *vp;
908996c772fSJohn Dyson 	struct inode *ip;
909996c772fSJohn Dyson 	struct ufsmount *ump = VFSTOUFS(mp);
910996c772fSJohn Dyson 	struct fs *fs;
9119b971133SKirk McKusick 	int error, count, wait, lockreq, allerror = 0;
912df8bae1dSRodney W. Grimes 
913df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
914996c772fSJohn Dyson 	if (fs->fs_fmod != 0 && fs->fs_ronly != 0) {		/* XXX */
915df8bae1dSRodney W. Grimes 		printf("fs = %s\n", fs->fs_fsmnt);
9165ace3b26SMike Pritchard 		panic("ffs_sync: rofs mod");
917df8bae1dSRodney W. Grimes 	}
918df8bae1dSRodney W. Grimes 	/*
919df8bae1dSRodney W. Grimes 	 * Write back each (modified) inode.
920df8bae1dSRodney W. Grimes 	 */
9219b971133SKirk McKusick 	wait = 0;
9229b971133SKirk McKusick 	lockreq = LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK;
9239b971133SKirk McKusick 	if (waitfor == MNT_WAIT) {
9249b971133SKirk McKusick 		wait = 1;
9259b971133SKirk McKusick 		lockreq = LK_EXCLUSIVE | LK_INTERLOCK;
9269b971133SKirk McKusick 	}
927996c772fSJohn Dyson 	simple_lock(&mntvnode_slock);
928df8bae1dSRodney W. Grimes loop:
929a316d390SJohn Dyson 	for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
930df8bae1dSRodney W. Grimes 		/*
931df8bae1dSRodney W. Grimes 		 * If the vnode that we are about to sync is no longer
932df8bae1dSRodney W. Grimes 		 * associated with this mount point, start over.
933df8bae1dSRodney W. Grimes 		 */
934df8bae1dSRodney W. Grimes 		if (vp->v_mount != mp)
935df8bae1dSRodney W. Grimes 			goto loop;
936996c772fSJohn Dyson 		simple_lock(&vp->v_interlock);
937a316d390SJohn Dyson 		nvp = vp->v_mntvnodes.le_next;
938df8bae1dSRodney W. Grimes 		ip = VTOI(vp);
939cf60e8e4SKirk McKusick 		if (vp->v_type == VNON || ((ip->i_flag &
940cf60e8e4SKirk McKusick 		     (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
941cf60e8e4SKirk McKusick 		     TAILQ_EMPTY(&vp->v_dirtyblkhd))) {
942996c772fSJohn Dyson 			simple_unlock(&vp->v_interlock);
943df8bae1dSRodney W. Grimes 			continue;
944996c772fSJohn Dyson 		}
94581c6e3e5SDavid Greenman 		if (vp->v_type != VCHR) {
946996c772fSJohn Dyson 			simple_unlock(&mntvnode_slock);
9479b971133SKirk McKusick 			if ((error = vget(vp, lockreq, p)) != 0) {
948996c772fSJohn Dyson 				simple_lock(&mntvnode_slock);
949996c772fSJohn Dyson 				if (error == ENOENT)
950df8bae1dSRodney W. Grimes 					goto loop;
951996c772fSJohn Dyson 				continue;
952996c772fSJohn Dyson 			}
9538aef1712SMatthew Dillon 			if ((error = VOP_FSYNC(vp, cred, waitfor, p)) != 0)
954df8bae1dSRodney W. Grimes 				allerror = error;
9559b971133SKirk McKusick 			vput(vp);
956996c772fSJohn Dyson 			simple_lock(&mntvnode_slock);
95781c6e3e5SDavid Greenman 		} else {
958996c772fSJohn Dyson 			simple_unlock(&mntvnode_slock);
959996c772fSJohn Dyson 			simple_unlock(&vp->v_interlock);
9609b971133SKirk McKusick 			UFS_UPDATE(vp, wait);
961996c772fSJohn Dyson 			simple_lock(&mntvnode_slock);
96281c6e3e5SDavid Greenman 		}
963df8bae1dSRodney W. Grimes 	}
964996c772fSJohn Dyson 	simple_unlock(&mntvnode_slock);
965df8bae1dSRodney W. Grimes 	/*
966df8bae1dSRodney W. Grimes 	 * Force stale file system control information to be flushed.
967df8bae1dSRodney W. Grimes 	 */
9689b971133SKirk McKusick 	if (waitfor == MNT_WAIT) {
9699b971133SKirk McKusick 		if ((error = softdep_flushworklist(ump->um_mountp, &count, p)))
9709b971133SKirk McKusick 			allerror = error;
9719b971133SKirk McKusick 		/* Flushed work items may create new vnodes to clean */
9729b971133SKirk McKusick 		if (count) {
9739b971133SKirk McKusick 			simple_lock(&mntvnode_slock);
9749b971133SKirk McKusick 			goto loop;
9759b971133SKirk McKusick 		}
9769b971133SKirk McKusick 	}
9779b971133SKirk McKusick 	if (waitfor == MNT_NOWAIT) {
978b1897c19SJulian Elischer 		vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p);
979b1897c19SJulian Elischer 		if ((error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p)) != 0)
980df8bae1dSRodney W. Grimes 			allerror = error;
981b1897c19SJulian Elischer 		VOP_UNLOCK(ump->um_devvp, 0, p);
982b1897c19SJulian Elischer 	}
983df8bae1dSRodney W. Grimes #ifdef QUOTA
984df8bae1dSRodney W. Grimes 	qsync(mp);
985df8bae1dSRodney W. Grimes #endif
986996c772fSJohn Dyson 	/*
987996c772fSJohn Dyson 	 * Write back modified superblock.
988996c772fSJohn Dyson 	 */
989b1897c19SJulian Elischer 	if (fs->fs_fmod != 0 && (error = ffs_sbupdate(ump, waitfor)) != 0)
990996c772fSJohn Dyson 		allerror = error;
991df8bae1dSRodney W. Grimes 	return (allerror);
992df8bae1dSRodney W. Grimes }
993df8bae1dSRodney W. Grimes 
994df8bae1dSRodney W. Grimes /*
995df8bae1dSRodney W. Grimes  * Look up a FFS dinode number to find its incore vnode, otherwise read it
996df8bae1dSRodney W. Grimes  * in from disk.  If it is in core, wait for the lock bit to clear, then
997df8bae1dSRodney W. Grimes  * return the inode locked.  Detection and handling of mount points must be
998df8bae1dSRodney W. Grimes  * done by the calling routine.
999df8bae1dSRodney W. Grimes  */
1000b8dce649SPoul-Henning Kamp static int ffs_inode_hash_lock;
10012094ddb6SDavid Greenman 
1002df8bae1dSRodney W. Grimes int
1003df8bae1dSRodney W. Grimes ffs_vget(mp, ino, vpp)
1004df8bae1dSRodney W. Grimes 	struct mount *mp;
1005df8bae1dSRodney W. Grimes 	ino_t ino;
1006df8bae1dSRodney W. Grimes 	struct vnode **vpp;
1007df8bae1dSRodney W. Grimes {
1008996c772fSJohn Dyson 	struct fs *fs;
1009996c772fSJohn Dyson 	struct inode *ip;
1010df8bae1dSRodney W. Grimes 	struct ufsmount *ump;
1011df8bae1dSRodney W. Grimes 	struct buf *bp;
1012df8bae1dSRodney W. Grimes 	struct vnode *vp;
1013df8bae1dSRodney W. Grimes 	dev_t dev;
10140be6b890SPoul-Henning Kamp 	int error;
1015df8bae1dSRodney W. Grimes 
1016df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
1017df8bae1dSRodney W. Grimes 	dev = ump->um_dev;
10188997d94fSDavid Greenman restart:
10198f9110f6SJohn Dyson 	if ((*vpp = ufs_ihashget(dev, ino)) != NULL) {
1020df8bae1dSRodney W. Grimes 		return (0);
10218f9110f6SJohn Dyson 	}
1022df8bae1dSRodney W. Grimes 
10232094ddb6SDavid Greenman 	/*
10248997d94fSDavid Greenman 	 * Lock out the creation of new entries in the FFS hash table in
10258997d94fSDavid Greenman 	 * case getnewvnode() or MALLOC() blocks, otherwise a duplicate
10262094ddb6SDavid Greenman 	 * may occur!
10272094ddb6SDavid Greenman 	 */
10282094ddb6SDavid Greenman 	if (ffs_inode_hash_lock) {
10292094ddb6SDavid Greenman 		while (ffs_inode_hash_lock) {
10302094ddb6SDavid Greenman 			ffs_inode_hash_lock = -1;
10312094ddb6SDavid Greenman 			tsleep(&ffs_inode_hash_lock, PVM, "ffsvgt", 0);
10322094ddb6SDavid Greenman 		}
10338997d94fSDavid Greenman 		goto restart;
10342094ddb6SDavid Greenman 	}
10352094ddb6SDavid Greenman 	ffs_inode_hash_lock = 1;
10362094ddb6SDavid Greenman 
10372f9bae59SDavid Greenman 	/*
10382f9bae59SDavid Greenman 	 * If this MALLOC() is performed after the getnewvnode()
10392f9bae59SDavid Greenman 	 * it might block, leaving a vnode with a NULL v_data to be
10402f9bae59SDavid Greenman 	 * found by ffs_sync() if a sync happens to fire right then,
10412f9bae59SDavid Greenman 	 * which will cause a panic because ffs_sync() blindly
10422f9bae59SDavid Greenman 	 * dereferences vp->v_data (as well it should).
10432f9bae59SDavid Greenman 	 */
10440be6b890SPoul-Henning Kamp 	MALLOC(ip, struct inode *, sizeof(struct inode),
10450be6b890SPoul-Henning Kamp 	    ump->um_malloctype, M_WAITOK);
10462f9bae59SDavid Greenman 
1047df8bae1dSRodney W. Grimes 	/* Allocate a new vnode/inode. */
1048c9671602SPoul-Henning Kamp 	error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp);
1049c9671602SPoul-Henning Kamp 	if (error) {
10508997d94fSDavid Greenman 		if (ffs_inode_hash_lock < 0)
10512094ddb6SDavid Greenman 			wakeup(&ffs_inode_hash_lock);
10522094ddb6SDavid Greenman 		ffs_inode_hash_lock = 0;
1053df8bae1dSRodney W. Grimes 		*vpp = NULL;
10540be6b890SPoul-Henning Kamp 		FREE(ip, ump->um_malloctype);
1055df8bae1dSRodney W. Grimes 		return (error);
1056df8bae1dSRodney W. Grimes 	}
1057df8bae1dSRodney W. Grimes 	bzero((caddr_t)ip, sizeof(struct inode));
1058cf60e8e4SKirk McKusick 	lockinit(&ip->i_lock, PINOD, "inode", 0, LK_CANRECURSE);
1059df8bae1dSRodney W. Grimes 	vp->v_data = ip;
1060df8bae1dSRodney W. Grimes 	ip->i_vnode = vp;
1061df8bae1dSRodney W. Grimes 	ip->i_fs = fs = ump->um_fs;
1062df8bae1dSRodney W. Grimes 	ip->i_dev = dev;
1063df8bae1dSRodney W. Grimes 	ip->i_number = ino;
1064df8bae1dSRodney W. Grimes #ifdef QUOTA
1065c1d9efcbSPoul-Henning Kamp 	{
1066c1d9efcbSPoul-Henning Kamp 		int i;
1067df8bae1dSRodney W. Grimes 		for (i = 0; i < MAXQUOTAS; i++)
1068df8bae1dSRodney W. Grimes 			ip->i_dquot[i] = NODQUOT;
1069c1d9efcbSPoul-Henning Kamp 	}
1070df8bae1dSRodney W. Grimes #endif
1071df8bae1dSRodney W. Grimes 	/*
1072df8bae1dSRodney W. Grimes 	 * Put it onto its hash chain and lock it so that other requests for
1073df8bae1dSRodney W. Grimes 	 * this inode will block if they arrive while we are sleeping waiting
1074df8bae1dSRodney W. Grimes 	 * for old data structures to be purged or for the contents of the
1075df8bae1dSRodney W. Grimes 	 * disk portion of this inode to be read.
1076df8bae1dSRodney W. Grimes 	 */
1077df8bae1dSRodney W. Grimes 	ufs_ihashins(ip);
1078df8bae1dSRodney W. Grimes 
10798997d94fSDavid Greenman 	if (ffs_inode_hash_lock < 0)
10802094ddb6SDavid Greenman 		wakeup(&ffs_inode_hash_lock);
10812094ddb6SDavid Greenman 	ffs_inode_hash_lock = 0;
10822094ddb6SDavid Greenman 
1083df8bae1dSRodney W. Grimes 	/* Read in the disk contents for the inode, copy into the inode. */
1084c9671602SPoul-Henning Kamp 	error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
1085c9671602SPoul-Henning Kamp 	    (int)fs->fs_bsize, NOCRED, &bp);
1086c9671602SPoul-Henning Kamp 	if (error) {
1087df8bae1dSRodney W. Grimes 		/*
1088df8bae1dSRodney W. Grimes 		 * The inode does not contain anything useful, so it would
1089df8bae1dSRodney W. Grimes 		 * be misleading to leave it on its hash chain. With mode
1090df8bae1dSRodney W. Grimes 		 * still zero, it will be unlinked and returned to the free
1091df8bae1dSRodney W. Grimes 		 * list by vput().
1092df8bae1dSRodney W. Grimes 		 */
1093df8bae1dSRodney W. Grimes 		brelse(bp);
1094bd7e5f99SJohn Dyson 		vput(vp);
1095df8bae1dSRodney W. Grimes 		*vpp = NULL;
1096df8bae1dSRodney W. Grimes 		return (error);
1097df8bae1dSRodney W. Grimes 	}
1098df8bae1dSRodney W. Grimes 	ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ino));
1099b1897c19SJulian Elischer 	if (DOINGSOFTDEP(vp))
1100b1897c19SJulian Elischer 		softdep_load_inodeblock(ip);
1101b1897c19SJulian Elischer 	else
1102b1897c19SJulian Elischer 		ip->i_effnlink = ip->i_nlink;
1103bd7e5f99SJohn Dyson 	bqrelse(bp);
1104df8bae1dSRodney W. Grimes 
1105df8bae1dSRodney W. Grimes 	/*
1106df8bae1dSRodney W. Grimes 	 * Initialize the vnode from the inode, check for aliases.
1107df8bae1dSRodney W. Grimes 	 * Note that the underlying vnode may have changed.
1108df8bae1dSRodney W. Grimes 	 */
1109e6302eabSBruce Evans 	error = ufs_vinit(mp, ffs_specop_p, ffs_fifoop_p, &vp);
1110c9671602SPoul-Henning Kamp 	if (error) {
1111df8bae1dSRodney W. Grimes 		vput(vp);
1112df8bae1dSRodney W. Grimes 		*vpp = NULL;
1113df8bae1dSRodney W. Grimes 		return (error);
1114df8bae1dSRodney W. Grimes 	}
1115df8bae1dSRodney W. Grimes 	/*
1116df8bae1dSRodney W. Grimes 	 * Finish inode initialization now that aliasing has been resolved.
1117df8bae1dSRodney W. Grimes 	 */
1118df8bae1dSRodney W. Grimes 	ip->i_devvp = ump->um_devvp;
1119df8bae1dSRodney W. Grimes 	VREF(ip->i_devvp);
1120df8bae1dSRodney W. Grimes 	/*
1121df8bae1dSRodney W. Grimes 	 * Set up a generation number for this inode if it does not
1122df8bae1dSRodney W. Grimes 	 * already have one. This should only happen on old filesystems.
1123df8bae1dSRodney W. Grimes 	 */
1124df8bae1dSRodney W. Grimes 	if (ip->i_gen == 0) {
11258f89943eSGuido van Rooij 		ip->i_gen = random() / 2 + 1;
1126df8bae1dSRodney W. Grimes 		if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
1127df8bae1dSRodney W. Grimes 			ip->i_flag |= IN_MODIFIED;
1128df8bae1dSRodney W. Grimes 	}
1129df8bae1dSRodney W. Grimes 	/*
1130df8bae1dSRodney W. Grimes 	 * Ensure that uid and gid are correct. This is a temporary
1131df8bae1dSRodney W. Grimes 	 * fix until fsck has been changed to do the update.
1132df8bae1dSRodney W. Grimes 	 */
1133df8bae1dSRodney W. Grimes 	if (fs->fs_inodefmt < FS_44INODEFMT) {		/* XXX */
1134df8bae1dSRodney W. Grimes 		ip->i_uid = ip->i_din.di_ouid;		/* XXX */
1135df8bae1dSRodney W. Grimes 		ip->i_gid = ip->i_din.di_ogid;		/* XXX */
1136df8bae1dSRodney W. Grimes 	}						/* XXX */
1137df8bae1dSRodney W. Grimes 
1138df8bae1dSRodney W. Grimes 	*vpp = vp;
1139df8bae1dSRodney W. Grimes 	return (0);
1140df8bae1dSRodney W. Grimes }
1141df8bae1dSRodney W. Grimes 
1142df8bae1dSRodney W. Grimes /*
1143df8bae1dSRodney W. Grimes  * File handle to vnode
1144df8bae1dSRodney W. Grimes  *
1145df8bae1dSRodney W. Grimes  * Have to be really careful about stale file handles:
1146df8bae1dSRodney W. Grimes  * - check that the inode number is valid
1147df8bae1dSRodney W. Grimes  * - call ffs_vget() to get the locked inode
1148df8bae1dSRodney W. Grimes  * - check for an unallocated inode (i_mode == 0)
1149df8bae1dSRodney W. Grimes  * - check that the given client host has export rights and return
1150df8bae1dSRodney W. Grimes  *   those rights via. exflagsp and credanonp
1151df8bae1dSRodney W. Grimes  */
1152df8bae1dSRodney W. Grimes int
1153c24fda81SAlfred Perlstein ffs_fhtovp(mp, fhp, vpp)
1154df8bae1dSRodney W. Grimes 	register struct mount *mp;
1155df8bae1dSRodney W. Grimes 	struct fid *fhp;
1156df8bae1dSRodney W. Grimes 	struct vnode **vpp;
1157df8bae1dSRodney W. Grimes {
1158df8bae1dSRodney W. Grimes 	register struct ufid *ufhp;
1159df8bae1dSRodney W. Grimes 	struct fs *fs;
1160df8bae1dSRodney W. Grimes 
1161df8bae1dSRodney W. Grimes 	ufhp = (struct ufid *)fhp;
1162df8bae1dSRodney W. Grimes 	fs = VFSTOUFS(mp)->um_fs;
1163df8bae1dSRodney W. Grimes 	if (ufhp->ufid_ino < ROOTINO ||
1164df8bae1dSRodney W. Grimes 	    ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg)
1165df8bae1dSRodney W. Grimes 		return (ESTALE);
1166c24fda81SAlfred Perlstein 	return (ufs_fhtovp(mp, ufhp, vpp));
1167df8bae1dSRodney W. Grimes }
1168df8bae1dSRodney W. Grimes 
1169df8bae1dSRodney W. Grimes /*
1170df8bae1dSRodney W. Grimes  * Vnode pointer to File handle
1171df8bae1dSRodney W. Grimes  */
1172df8bae1dSRodney W. Grimes /* ARGSUSED */
117326f9a767SRodney W. Grimes int
1174df8bae1dSRodney W. Grimes ffs_vptofh(vp, fhp)
1175df8bae1dSRodney W. Grimes 	struct vnode *vp;
1176df8bae1dSRodney W. Grimes 	struct fid *fhp;
1177df8bae1dSRodney W. Grimes {
1178df8bae1dSRodney W. Grimes 	register struct inode *ip;
1179df8bae1dSRodney W. Grimes 	register struct ufid *ufhp;
1180df8bae1dSRodney W. Grimes 
1181df8bae1dSRodney W. Grimes 	ip = VTOI(vp);
1182df8bae1dSRodney W. Grimes 	ufhp = (struct ufid *)fhp;
1183df8bae1dSRodney W. Grimes 	ufhp->ufid_len = sizeof(struct ufid);
1184df8bae1dSRodney W. Grimes 	ufhp->ufid_ino = ip->i_number;
1185df8bae1dSRodney W. Grimes 	ufhp->ufid_gen = ip->i_gen;
1186df8bae1dSRodney W. Grimes 	return (0);
1187df8bae1dSRodney W. Grimes }
1188df8bae1dSRodney W. Grimes 
1189df8bae1dSRodney W. Grimes /*
1190996c772fSJohn Dyson  * Initialize the filesystem; just use ufs_init.
1191996c772fSJohn Dyson  */
1192996c772fSJohn Dyson static int
1193996c772fSJohn Dyson ffs_init(vfsp)
1194996c772fSJohn Dyson 	struct vfsconf *vfsp;
1195996c772fSJohn Dyson {
1196996c772fSJohn Dyson 
1197b1897c19SJulian Elischer 	softdep_initialize();
1198996c772fSJohn Dyson 	return (ufs_init(vfsp));
1199996c772fSJohn Dyson }
1200996c772fSJohn Dyson 
1201996c772fSJohn Dyson /*
1202df8bae1dSRodney W. Grimes  * Write a superblock and associated information back to disk.
1203df8bae1dSRodney W. Grimes  */
1204b8dce649SPoul-Henning Kamp static int
1205df8bae1dSRodney W. Grimes ffs_sbupdate(mp, waitfor)
1206df8bae1dSRodney W. Grimes 	struct ufsmount *mp;
1207df8bae1dSRodney W. Grimes 	int waitfor;
1208df8bae1dSRodney W. Grimes {
1209996c772fSJohn Dyson 	register struct fs *dfs, *fs = mp->um_fs;
1210df8bae1dSRodney W. Grimes 	register struct buf *bp;
1211df8bae1dSRodney W. Grimes 	int blks;
1212df8bae1dSRodney W. Grimes 	caddr_t space;
1213996c772fSJohn Dyson 	int i, size, error, allerror = 0;
1214df8bae1dSRodney W. Grimes 
1215996c772fSJohn Dyson 	/*
1216996c772fSJohn Dyson 	 * First write back the summary information.
1217996c772fSJohn Dyson 	 */
1218df8bae1dSRodney W. Grimes 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
1219df8bae1dSRodney W. Grimes 	space = (caddr_t)fs->fs_csp[0];
1220df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
1221df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
1222df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
1223df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
1224df8bae1dSRodney W. Grimes 		bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i),
1225df8bae1dSRodney W. Grimes 		    size, 0, 0);
1226df8bae1dSRodney W. Grimes 		bcopy(space, bp->b_data, (u_int)size);
1227df8bae1dSRodney W. Grimes 		space += size;
1228996c772fSJohn Dyson 		if (waitfor != MNT_WAIT)
1229df8bae1dSRodney W. Grimes 			bawrite(bp);
12308aef1712SMatthew Dillon 		else if ((error = bwrite(bp)) != 0)
1231996c772fSJohn Dyson 			allerror = error;
1232df8bae1dSRodney W. Grimes 	}
1233996c772fSJohn Dyson 	/*
1234996c772fSJohn Dyson 	 * Now write back the superblock itself. If any errors occurred
1235996c772fSJohn Dyson 	 * up to this point, then fail so that the superblock avoids
1236996c772fSJohn Dyson 	 * being written out as clean.
1237996c772fSJohn Dyson 	 */
1238996c772fSJohn Dyson 	if (allerror)
1239996c772fSJohn Dyson 		return (allerror);
1240996c772fSJohn Dyson 	bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0);
1241b1897c19SJulian Elischer 	fs->fs_fmod = 0;
1242227ee8a1SPoul-Henning Kamp 	fs->fs_time = time_second;
1243996c772fSJohn Dyson 	bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize);
1244996c772fSJohn Dyson 	/* Restore compatibility to old file systems.		   XXX */
1245996c772fSJohn Dyson 	dfs = (struct fs *)bp->b_data;				/* XXX */
1246996c772fSJohn Dyson 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
1247996c772fSJohn Dyson 		dfs->fs_nrpos = -1;				/* XXX */
1248996c772fSJohn Dyson 	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
1249996c772fSJohn Dyson 		int32_t *lp, tmp;				/* XXX */
1250996c772fSJohn Dyson 								/* XXX */
1251996c772fSJohn Dyson 		lp = (int32_t *)&dfs->fs_qbmask;		/* XXX */
1252996c772fSJohn Dyson 		tmp = lp[4];					/* XXX */
1253996c772fSJohn Dyson 		for (i = 4; i > 0; i--)				/* XXX */
1254996c772fSJohn Dyson 			lp[i] = lp[i-1];			/* XXX */
1255996c772fSJohn Dyson 		lp[0] = tmp;					/* XXX */
1256996c772fSJohn Dyson 	}							/* XXX */
1257996c772fSJohn Dyson 	dfs->fs_maxfilesize = mp->um_savedmaxfilesize;		/* XXX */
1258996c772fSJohn Dyson 	if (waitfor != MNT_WAIT)
1259996c772fSJohn Dyson 		bawrite(bp);
12608aef1712SMatthew Dillon 	else if ((error = bwrite(bp)) != 0)
1261996c772fSJohn Dyson 		allerror = error;
1262996c772fSJohn Dyson 	return (allerror);
1263df8bae1dSRodney W. Grimes }
1264