xref: /freebsd/sys/ufs/ffs/ffs_vfsops.c (revision 68de329e34e589ead319ec4eef1440bc55a80b23)
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
3468de329eSPoul-Henning Kamp  * $Id: ffs_vfsops.c,v 1.99 1999/05/31 11:29:24 phk Exp $
35df8bae1dSRodney W. Grimes  */
36df8bae1dSRodney W. Grimes 
3701733a9bSGarrett Wollman #include "opt_quota.h"
3801733a9bSGarrett Wollman 
39df8bae1dSRodney W. Grimes #include <sys/param.h>
40df8bae1dSRodney W. Grimes #include <sys/systm.h>
41df8bae1dSRodney W. Grimes #include <sys/namei.h>
42df8bae1dSRodney W. Grimes #include <sys/proc.h>
43df8bae1dSRodney W. Grimes #include <sys/kernel.h>
44df8bae1dSRodney W. Grimes #include <sys/vnode.h>
45df8bae1dSRodney W. Grimes #include <sys/mount.h>
46df8bae1dSRodney W. Grimes #include <sys/buf.h>
4781bca6ddSKATO Takenori #include <sys/conf.h>
483ac4d1efSBruce Evans #include <sys/fcntl.h>
49df8bae1dSRodney W. Grimes #include <sys/disklabel.h>
50df8bae1dSRodney W. Grimes #include <sys/malloc.h>
51df8bae1dSRodney W. Grimes 
52df8bae1dSRodney W. Grimes #include <miscfs/specfs/specdev.h>
53df8bae1dSRodney W. Grimes 
54df8bae1dSRodney W. Grimes #include <ufs/ufs/quota.h>
55df8bae1dSRodney W. Grimes #include <ufs/ufs/ufsmount.h>
56df8bae1dSRodney W. Grimes #include <ufs/ufs/inode.h>
57df8bae1dSRodney W. Grimes #include <ufs/ufs/ufs_extern.h>
58df8bae1dSRodney W. Grimes 
59df8bae1dSRodney W. Grimes #include <ufs/ffs/fs.h>
60df8bae1dSRodney W. Grimes #include <ufs/ffs/ffs_extern.h>
61df8bae1dSRodney W. Grimes 
62f6b04d2bSDavid Greenman #include <vm/vm.h>
63efeaf95aSDavid Greenman #include <vm/vm_prot.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,
85df8bae1dSRodney W. Grimes 	ffs_vptofh,
86df8bae1dSRodney W. Grimes 	ffs_init,
87df8bae1dSRodney W. Grimes };
88df8bae1dSRodney W. Grimes 
898994ca3cSBruce Evans VFS_SET(ufs_vfsops, ufs, 0);
90c901836cSGarrett Wollman 
91df8bae1dSRodney W. Grimes /*
922b14f991SJulian Elischer  * ffs_mount
93df8bae1dSRodney W. Grimes  *
942b14f991SJulian Elischer  * Called when mounting local physical media
95df8bae1dSRodney W. Grimes  *
962b14f991SJulian Elischer  * PARAMETERS:
972b14f991SJulian Elischer  *		mountroot
982b14f991SJulian Elischer  *			mp	mount point structure
992b14f991SJulian Elischer  *			path	NULL (flag for root mount!!!)
1002b14f991SJulian Elischer  *			data	<unused>
1012b14f991SJulian Elischer  *			ndp	<unused>
1022b14f991SJulian Elischer  *			p	process (user credentials check [statfs])
1032b14f991SJulian Elischer  *
1042b14f991SJulian Elischer  *		mount
1052b14f991SJulian Elischer  *			mp	mount point structure
1062b14f991SJulian Elischer  *			path	path to mount point
1072b14f991SJulian Elischer  *			data	pointer to argument struct in user space
1082b14f991SJulian Elischer  *			ndp	mount point namei() return (used for
1092b14f991SJulian Elischer  *				credentials on reload), reused to look
1102b14f991SJulian Elischer  *				up block device.
1112b14f991SJulian Elischer  *			p	process (user credentials check)
1122b14f991SJulian Elischer  *
1132b14f991SJulian Elischer  * RETURNS:	0	Success
1142b14f991SJulian Elischer  *		!0	error number (errno.h)
1152b14f991SJulian Elischer  *
1162b14f991SJulian Elischer  * LOCK STATE:
1172b14f991SJulian Elischer  *
1182b14f991SJulian Elischer  *		ENTRY
1192b14f991SJulian Elischer  *			mount point is locked
1202b14f991SJulian Elischer  *		EXIT
1212b14f991SJulian Elischer  *			mount point is locked
1222b14f991SJulian Elischer  *
1232b14f991SJulian Elischer  * NOTES:
1242b14f991SJulian Elischer  *		A NULL path can be used for a flag since the mount
1252b14f991SJulian Elischer  *		system call will fail with EFAULT in copyinstr in
1262b14f991SJulian Elischer  *		namei() if it is a genuine NULL from the user.
127df8bae1dSRodney W. Grimes  */
128b8dce649SPoul-Henning Kamp static int
129df8bae1dSRodney W. Grimes ffs_mount( mp, path, data, ndp, p)
130996c772fSJohn Dyson         struct mount		*mp;	/* mount struct pointer*/
1312b14f991SJulian Elischer         char			*path;	/* path to mount point*/
1322b14f991SJulian Elischer         caddr_t			data;	/* arguments to FS specific mount*/
1332b14f991SJulian Elischer         struct nameidata	*ndp;	/* mount point credentials*/
1342b14f991SJulian Elischer         struct proc		*p;	/* process requesting mount*/
135df8bae1dSRodney W. Grimes {
1368435e0aeSDoug Rabson 	size_t		size;
1372b14f991SJulian Elischer 	int		err = 0;
138df8bae1dSRodney W. Grimes 	struct vnode	*devvp;
1392b14f991SJulian Elischer 
140df8bae1dSRodney W. Grimes 	struct ufs_args args;
14126f9a767SRodney W. Grimes 	struct ufsmount *ump = 0;
142df8bae1dSRodney W. Grimes 	register struct fs *fs;
1430922cce6SBruce Evans 	int error, flags, ronly = 0;
144c9b99213SBruce Evans 	mode_t accessmode;
145df8bae1dSRodney W. Grimes 
1462b14f991SJulian Elischer 	/*
1472b14f991SJulian Elischer 	 * Use NULL path to flag a root mount
1482b14f991SJulian Elischer 	 */
1492b14f991SJulian Elischer 	if( path == NULL) {
1502b14f991SJulian Elischer 		/*
1512b14f991SJulian Elischer 		 ***
1522b14f991SJulian Elischer 		 * Mounting root file system
1532b14f991SJulian Elischer 		 ***
1542b14f991SJulian Elischer 		 */
1552b14f991SJulian Elischer 
156996c772fSJohn Dyson 		if ((err = bdevvp(rootdev, &rootvp))) {
15741fadeebSBruce Evans 			printf("ffs_mountroot: can't find rootvp");
158996c772fSJohn Dyson 			return (err);
159996c772fSJohn Dyson 		}
1602b14f991SJulian Elischer 
1614be2eb8cSPoul-Henning Kamp 		if (bdevsw(rootdev)->d_flags & D_NOCLUSTERR)
16281bca6ddSKATO Takenori 			mp->mnt_flag |= MNT_NOCLUSTERR;
1634be2eb8cSPoul-Henning Kamp 		if (bdevsw(rootdev)->d_flags & D_NOCLUSTERW)
16481bca6ddSKATO Takenori 			mp->mnt_flag |= MNT_NOCLUSTERW;
1650be6b890SPoul-Henning Kamp 		if( ( err = ffs_mountfs(rootvp, mp, p, M_FFSNODE)) != 0) {
1662b14f991SJulian Elischer 			/* fs specific cleanup (if any)*/
1672b14f991SJulian Elischer 			goto error_1;
1682b14f991SJulian Elischer 		}
1692b14f991SJulian Elischer 
1702b14f991SJulian Elischer 		goto dostatfs;		/* success*/
1712b14f991SJulian Elischer 
1722b14f991SJulian Elischer 	}
1732b14f991SJulian Elischer 
1742b14f991SJulian Elischer 	/*
1752b14f991SJulian Elischer 	 ***
1762b14f991SJulian Elischer 	 * Mounting non-root file system or updating a file system
1772b14f991SJulian Elischer 	 ***
1782b14f991SJulian Elischer 	 */
1792b14f991SJulian Elischer 
1802b14f991SJulian Elischer 	/* copy in user arguments*/
1812b14f991SJulian Elischer 	err = copyin(data, (caddr_t)&args, sizeof (struct ufs_args));
1822b14f991SJulian Elischer 	if (err)
1832b14f991SJulian Elischer 		goto error_1;		/* can't get arguments*/
1842b14f991SJulian Elischer 
185df8bae1dSRodney W. Grimes 	/*
186df8bae1dSRodney W. Grimes 	 * If updating, check whether changing from read-only to
187df8bae1dSRodney W. Grimes 	 * read/write; if there is no device name, that's all we do.
18881bca6ddSKATO Takenori 	 * Disallow clearing MNT_NOCLUSTERR and MNT_NOCLUSTERW flags,
18981bca6ddSKATO Takenori 	 * if block device requests.
190df8bae1dSRodney W. Grimes 	 */
191df8bae1dSRodney W. Grimes 	if (mp->mnt_flag & MNT_UPDATE) {
192df8bae1dSRodney W. Grimes 		ump = VFSTOUFS(mp);
193df8bae1dSRodney W. Grimes 		fs = ump->um_fs;
19426cf9c3bSPeter Wemm 		devvp = ump->um_devvp;
1952b14f991SJulian Elischer 		err = 0;
196bcbd6c6fSJulian Elischer 		ronly = fs->fs_ronly;	/* MNT_RELOAD might change this */
1974be2eb8cSPoul-Henning Kamp 		if (bdevsw(ump->um_dev)->d_flags & D_NOCLUSTERR)
19881bca6ddSKATO Takenori 			mp->mnt_flag |= MNT_NOCLUSTERR;
1994be2eb8cSPoul-Henning Kamp 		if (bdevsw(ump->um_dev)->d_flags & D_NOCLUSTERW)
20081bca6ddSKATO Takenori 			mp->mnt_flag |= MNT_NOCLUSTERW;
2010922cce6SBruce Evans 		if (ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
202df8bae1dSRodney W. Grimes 			flags = WRITECLOSE;
203df8bae1dSRodney W. Grimes 			if (mp->mnt_flag & MNT_FORCE)
204df8bae1dSRodney W. Grimes 				flags |= FORCECLOSE;
205b1897c19SJulian Elischer 			if (mp->mnt_flag & MNT_SOFTDEP) {
206b1897c19SJulian Elischer 				err = softdep_flushfiles(mp, flags, p);
207b1897c19SJulian Elischer 			} else {
2082b14f991SJulian Elischer 				err = ffs_flushfiles(mp, flags, p);
209df8bae1dSRodney W. Grimes 			}
2100922cce6SBruce Evans 			ronly = 1;
211b1897c19SJulian Elischer 		}
2122b14f991SJulian Elischer 		if (!err && (mp->mnt_flag & MNT_RELOAD))
2132b14f991SJulian Elischer 			err = ffs_reload(mp, ndp->ni_cnd.cn_cred, p);
2142b14f991SJulian Elischer 		if (err) {
2152b14f991SJulian Elischer 			goto error_1;
2162b14f991SJulian Elischer 		}
217bcbd6c6fSJulian Elischer 		if (ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) {
218c9b99213SBruce Evans 			/*
219c9b99213SBruce Evans 			 * If upgrade to read-write by non-root, then verify
220c9b99213SBruce Evans 			 * that user has necessary permissions on the device.
221c9b99213SBruce Evans 			 */
222c9b99213SBruce Evans 			if (p->p_ucred->cr_uid != 0) {
223c9b99213SBruce Evans 				vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
2248aef1712SMatthew Dillon 				if ((error = VOP_ACCESS(devvp, VREAD | VWRITE,
2258aef1712SMatthew Dillon 				    p->p_ucred, p)) != 0) {
226c9b99213SBruce Evans 					VOP_UNLOCK(devvp, 0, p);
227c9b99213SBruce Evans 					return (error);
228c9b99213SBruce Evans 				}
229c9b99213SBruce Evans 				VOP_UNLOCK(devvp, 0, p);
230c9b99213SBruce Evans 			}
231c9b99213SBruce Evans 
2320922cce6SBruce Evans 			if (fs->fs_clean == 0) {
2330922cce6SBruce Evans 				if (mp->mnt_flag & MNT_FORCE) {
2340922cce6SBruce Evans 					printf(
2350922cce6SBruce Evans "WARNING: %s was not properly dismounted\n",
2360922cce6SBruce Evans 					    fs->fs_fsmnt);
2370922cce6SBruce Evans 				} else {
2380922cce6SBruce Evans 					printf(
2390922cce6SBruce Evans "WARNING: R/W mount of %s denied.  Filesystem is not clean - run fsck\n",
2400922cce6SBruce Evans 					    fs->fs_fsmnt);
2410922cce6SBruce Evans 					err = EPERM;
2420922cce6SBruce Evans 					goto error_1;
2430922cce6SBruce Evans 				}
2440922cce6SBruce Evans 			}
2450922cce6SBruce Evans 
24626cf9c3bSPeter Wemm 			/* check to see if we need to start softdep */
24726cf9c3bSPeter Wemm 			if (fs->fs_flags & FS_DOSOFTDEP) {
24826cf9c3bSPeter Wemm 				err = softdep_mount(devvp, mp, fs, p->p_ucred);
24926cf9c3bSPeter Wemm 				if (err)
25026cf9c3bSPeter Wemm 					goto error_1;
25126cf9c3bSPeter Wemm 			}
25226cf9c3bSPeter Wemm 
253bcbd6c6fSJulian Elischer 			ronly = 0;
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 		 */
262c11d2981SJulian Elischer 		if (mp->mnt_flag & MNT_SOFTDEP) {
263c11d2981SJulian Elischer 			mp->mnt_flag &= ~MNT_ASYNC;
264c11d2981SJulian Elischer 		}
2652b14f991SJulian Elischer 		/* if not updating name...*/
266df8bae1dSRodney W. Grimes 		if (args.fspec == 0) {
267df8bae1dSRodney W. Grimes 			/*
2682b14f991SJulian Elischer 			 * Process export requests.  Jumping to "success"
2692b14f991SJulian Elischer 			 * will return the vfs_export() error code.
270df8bae1dSRodney W. Grimes 			 */
2712b14f991SJulian Elischer 			err = vfs_export(mp, &ump->um_export, &args.export);
2722b14f991SJulian Elischer 			goto success;
273df8bae1dSRodney W. Grimes 		}
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);
2812b14f991SJulian Elischer 	err = namei(ndp);
2822b14f991SJulian Elischer 	if (err) {
2832b14f991SJulian Elischer 		/* can't get devvp!*/
2842b14f991SJulian Elischer 		goto error_1;
2852b14f991SJulian Elischer 	}
2862b14f991SJulian Elischer 
287df8bae1dSRodney W. Grimes 	devvp = ndp->ni_vp;
288df8bae1dSRodney W. Grimes 
289df8bae1dSRodney W. Grimes 	if (devvp->v_type != VBLK) {
2902b14f991SJulian Elischer 		err = ENOTBLK;
2912b14f991SJulian Elischer 		goto error_2;
292df8bae1dSRodney W. Grimes 	}
2932447bec8SPoul-Henning Kamp 	if (bdevsw(devvp->v_rdev) == NULL) {
2942b14f991SJulian Elischer 		err = ENXIO;
2952b14f991SJulian Elischer 		goto error_2;
296df8bae1dSRodney W. Grimes 	}
297c9b99213SBruce Evans 
298c9b99213SBruce Evans 	/*
299c9b99213SBruce Evans 	 * If mount by non-root, then verify that user has necessary
300c9b99213SBruce Evans 	 * permissions on the device.
301c9b99213SBruce Evans 	 */
302c9b99213SBruce Evans 	if (p->p_ucred->cr_uid != 0) {
303c9b99213SBruce Evans 		accessmode = VREAD;
304c9b99213SBruce Evans 		if ((mp->mnt_flag & MNT_RDONLY) == 0)
305c9b99213SBruce Evans 			accessmode |= VWRITE;
306c9b99213SBruce Evans 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
3078aef1712SMatthew Dillon 		if ((error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p)) != 0) {
308c9b99213SBruce Evans 			vput(devvp);
309c9b99213SBruce Evans 			return (error);
310c9b99213SBruce Evans 		}
311c9b99213SBruce Evans 		VOP_UNLOCK(devvp, 0, p);
312c9b99213SBruce Evans 	}
313c9b99213SBruce Evans 
3142b14f991SJulian Elischer 	if (mp->mnt_flag & MNT_UPDATE) {
3152b14f991SJulian Elischer 		/*
3162b14f991SJulian Elischer 		 ********************
3172b14f991SJulian Elischer 		 * UPDATE
3183e425b96SJulian Elischer 		 * If it's not the same vnode, or at least the same device
3193e425b96SJulian Elischer 		 * then it's not correct.
3202b14f991SJulian Elischer 		 ********************
3212b14f991SJulian Elischer 		 */
3222b14f991SJulian Elischer 
3233e425b96SJulian Elischer 		if (devvp != ump->um_devvp) {
3243e425b96SJulian Elischer 			if ( devvp->v_rdev == ump->um_devvp->v_rdev) {
3253e425b96SJulian Elischer 				vrele(devvp);
3263e425b96SJulian Elischer 			} else {
3272b14f991SJulian Elischer 				err = EINVAL;	/* needs translation */
3283e425b96SJulian Elischer 			}
3293e425b96SJulian Elischer 		} else
330df8bae1dSRodney W. Grimes 			vrele(devvp);
3312b14f991SJulian Elischer 		/*
3322b14f991SJulian Elischer 		 * Update device name only on success
3332b14f991SJulian Elischer 		 */
3342b14f991SJulian Elischer 		if( !err) {
3352b14f991SJulian Elischer 			/* Save "mounted from" info for mount point (NULL pad)*/
3362b14f991SJulian Elischer 			copyinstr(	args.fspec,
3372b14f991SJulian Elischer 					mp->mnt_stat.f_mntfromname,
3382b14f991SJulian Elischer 					MNAMELEN - 1,
339df8bae1dSRodney W. Grimes 					&size);
340df8bae1dSRodney W. Grimes 			bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
341df8bae1dSRodney W. Grimes 		}
3422b14f991SJulian Elischer 	} else {
3432b14f991SJulian Elischer 		/*
3442b14f991SJulian Elischer 		 ********************
3452b14f991SJulian Elischer 		 * NEW MOUNT
3462b14f991SJulian Elischer 		 ********************
3472b14f991SJulian Elischer 		 */
3482b14f991SJulian Elischer 
3494be2eb8cSPoul-Henning Kamp 		if (bdevsw(devvp->v_rdev)->d_flags & D_NOCLUSTERR)
35081bca6ddSKATO Takenori 			mp->mnt_flag |= MNT_NOCLUSTERR;
3514be2eb8cSPoul-Henning Kamp 		if (bdevsw(devvp->v_rdev)->d_flags & D_NOCLUSTERW)
35281bca6ddSKATO Takenori 			mp->mnt_flag |= MNT_NOCLUSTERW;
35381bca6ddSKATO Takenori 
3542b14f991SJulian Elischer 		/*
3552b14f991SJulian Elischer 		 * Since this is a new mount, we want the names for
3562b14f991SJulian Elischer 		 * the device and the mount point copied in.  If an
3572b14f991SJulian Elischer 		 * error occurs,  the mountpoint is discarded by the
3582b14f991SJulian Elischer 		 * upper level code.
3592b14f991SJulian Elischer 		 */
3602b14f991SJulian Elischer 		/* Save "last mounted on" info for mount point (NULL pad)*/
3612b14f991SJulian Elischer 		copyinstr(	path,				/* mount point*/
3622b14f991SJulian Elischer 				mp->mnt_stat.f_mntonname,	/* save area*/
3632b14f991SJulian Elischer 				MNAMELEN - 1,			/* max size*/
3642b14f991SJulian Elischer 				&size);				/* real size*/
3652b14f991SJulian Elischer 		bzero( mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
3662b14f991SJulian Elischer 
3672b14f991SJulian Elischer 		/* Save "mounted from" info for mount point (NULL pad)*/
3682b14f991SJulian Elischer 		copyinstr(	args.fspec,			/* device name*/
3692b14f991SJulian Elischer 				mp->mnt_stat.f_mntfromname,	/* save area*/
3702b14f991SJulian Elischer 				MNAMELEN - 1,			/* max size*/
3712b14f991SJulian Elischer 				&size);				/* real size*/
3722b14f991SJulian Elischer 		bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
3732b14f991SJulian Elischer 
3740be6b890SPoul-Henning Kamp 		err = ffs_mountfs(devvp, mp, p, M_FFSNODE);
3752b14f991SJulian Elischer 	}
3762b14f991SJulian Elischer 	if (err) {
3772b14f991SJulian Elischer 		goto error_2;
3782b14f991SJulian Elischer 	}
3792b14f991SJulian Elischer 
3802b14f991SJulian Elischer dostatfs:
3812b14f991SJulian Elischer 	/*
3822b14f991SJulian Elischer 	 * Initialize FS stat information in mount struct; uses both
3832b14f991SJulian Elischer 	 * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname
3842b14f991SJulian Elischer 	 *
3852b14f991SJulian Elischer 	 * This code is common to root and non-root mounts
3862b14f991SJulian Elischer 	 */
3872b14f991SJulian Elischer 	(void)VFS_STATFS(mp, &mp->mnt_stat, p);
3882b14f991SJulian Elischer 
3892b14f991SJulian Elischer 	goto success;
3902b14f991SJulian Elischer 
3912b14f991SJulian Elischer 
3922b14f991SJulian Elischer error_2:	/* error with devvp held*/
3932b14f991SJulian Elischer 
3942b14f991SJulian Elischer 	/* release devvp before failing*/
3952b14f991SJulian Elischer 	vrele(devvp);
3962b14f991SJulian Elischer 
3972b14f991SJulian Elischer error_1:	/* no state to back out*/
3982b14f991SJulian Elischer 
3992b14f991SJulian Elischer success:
400bcbd6c6fSJulian Elischer 	if (!err && path && (mp->mnt_flag & MNT_UPDATE)) {
4010922cce6SBruce Evans 		/* Update clean flag after changing read-onlyness. */
402bcbd6c6fSJulian Elischer 		fs = ump->um_fs;
4030922cce6SBruce Evans 		if (ronly != fs->fs_ronly) {
4040922cce6SBruce Evans 			fs->fs_ronly = ronly;
4050922cce6SBruce Evans 			fs->fs_clean = ronly &&
4060922cce6SBruce Evans 			    (fs->fs_flags & FS_UNCLEAN) == 0 ? 1 : 0;
407bcbd6c6fSJulian Elischer 			ffs_sbupdate(ump, MNT_WAIT);
408bcbd6c6fSJulian Elischer 		}
409bcbd6c6fSJulian Elischer 	}
4102b14f991SJulian Elischer 	return (err);
4112b14f991SJulian Elischer }
4122b14f991SJulian Elischer 
413df8bae1dSRodney W. Grimes /*
414df8bae1dSRodney W. Grimes  * Reload all incore data for a filesystem (used after running fsck on
415df8bae1dSRodney W. Grimes  * the root filesystem and finding things to fix). The filesystem must
416df8bae1dSRodney W. Grimes  * be mounted read-only.
417df8bae1dSRodney W. Grimes  *
418df8bae1dSRodney W. Grimes  * Things to do to update the mount:
419df8bae1dSRodney W. Grimes  *	1) invalidate all cached meta-data.
420df8bae1dSRodney W. Grimes  *	2) re-read superblock from disk.
421df8bae1dSRodney W. Grimes  *	3) re-read summary information from disk.
422df8bae1dSRodney W. Grimes  *	4) invalidate all inactive vnodes.
423df8bae1dSRodney W. Grimes  *	5) invalidate all cached file data.
424df8bae1dSRodney W. Grimes  *	6) re-read inode data for all active vnodes.
425df8bae1dSRodney W. Grimes  */
426b8dce649SPoul-Henning Kamp static int
4272b14f991SJulian Elischer ffs_reload(mp, cred, p)
4282b14f991SJulian Elischer 	register struct mount *mp;
429df8bae1dSRodney W. Grimes 	struct ucred *cred;
430df8bae1dSRodney W. Grimes 	struct proc *p;
431df8bae1dSRodney W. Grimes {
432df8bae1dSRodney W. Grimes 	register struct vnode *vp, *nvp, *devvp;
433df8bae1dSRodney W. Grimes 	struct inode *ip;
434df8bae1dSRodney W. Grimes 	struct csum *space;
435df8bae1dSRodney W. Grimes 	struct buf *bp;
436996c772fSJohn Dyson 	struct fs *fs, *newfs;
437996c772fSJohn Dyson 	struct partinfo dpart;
43895e5e988SJohn Dyson 	dev_t dev;
439df8bae1dSRodney W. Grimes 	int i, blks, size, error;
440996c772fSJohn Dyson 	int32_t *lp;
441df8bae1dSRodney W. Grimes 
4422b14f991SJulian Elischer 	if ((mp->mnt_flag & MNT_RDONLY) == 0)
443df8bae1dSRodney W. Grimes 		return (EINVAL);
444df8bae1dSRodney W. Grimes 	/*
445df8bae1dSRodney W. Grimes 	 * Step 1: invalidate all cached meta-data.
446df8bae1dSRodney W. Grimes 	 */
4472b14f991SJulian Elischer 	devvp = VFSTOUFS(mp)->um_devvp;
448b1897c19SJulian Elischer 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
449b1897c19SJulian Elischer 	error = vinvalbuf(devvp, 0, cred, p, 0, 0);
450b1897c19SJulian Elischer 	VOP_UNLOCK(devvp, 0, p);
451b1897c19SJulian Elischer 	if (error)
452df8bae1dSRodney W. Grimes 		panic("ffs_reload: dirty1");
45395e5e988SJohn Dyson 
45495e5e988SJohn Dyson 	dev = devvp->v_rdev;
455b5ee1640SBruce Evans 
45695e5e988SJohn Dyson 	/*
45795e5e988SJohn Dyson 	 * Only VMIO the backing device if the backing device is a real
458b5ee1640SBruce Evans 	 * block device.  See ffs_mountmfs() for more details.
45995e5e988SJohn Dyson 	 */
460b5ee1640SBruce Evans 	if (devvp->v_tag != VT_MFS && devvp->v_type == VBLK) {
461a777e820SEivind Eklund 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
462fb116777SEivind Eklund 		vfs_object_create(devvp, p, p->p_ucred);
4632d8acc0fSJohn Dyson 		simple_lock(&devvp->v_interlock);
464a777e820SEivind Eklund 		VOP_UNLOCK(devvp, LK_INTERLOCK, p);
46595e5e988SJohn Dyson 	}
46695e5e988SJohn Dyson 
467df8bae1dSRodney W. Grimes 	/*
468df8bae1dSRodney W. Grimes 	 * Step 2: re-read superblock from disk.
469df8bae1dSRodney W. Grimes 	 */
470996c772fSJohn Dyson 	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
471996c772fSJohn Dyson 		size = DEV_BSIZE;
472996c772fSJohn Dyson 	else
473996c772fSJohn Dyson 		size = dpart.disklab->d_secsize;
4748aef1712SMatthew Dillon 	if ((error = bread(devvp, (ufs_daddr_t)(SBOFF/size), SBSIZE, NOCRED,&bp)) != 0)
475df8bae1dSRodney W. Grimes 		return (error);
476996c772fSJohn Dyson 	newfs = (struct fs *)bp->b_data;
477996c772fSJohn Dyson 	if (newfs->fs_magic != FS_MAGIC || newfs->fs_bsize > MAXBSIZE ||
478996c772fSJohn Dyson 		newfs->fs_bsize < sizeof(struct fs)) {
479df8bae1dSRodney W. Grimes 			brelse(bp);
480df8bae1dSRodney W. Grimes 			return (EIO);		/* XXX needs translation */
481df8bae1dSRodney W. Grimes 	}
4822b14f991SJulian Elischer 	fs = VFSTOUFS(mp)->um_fs;
483996c772fSJohn Dyson 	/*
484996c772fSJohn Dyson 	 * Copy pointer fields back into superblock before copying in	XXX
485996c772fSJohn Dyson 	 * new superblock. These should really be in the ufsmount.	XXX
486996c772fSJohn Dyson 	 * Note that important parameters (eg fs_ncg) are unchanged.
487996c772fSJohn Dyson 	 */
488996c772fSJohn Dyson 	bcopy(&fs->fs_csp[0], &newfs->fs_csp[0], sizeof(fs->fs_csp));
489996c772fSJohn Dyson 	newfs->fs_maxcluster = fs->fs_maxcluster;
490996c772fSJohn Dyson 	bcopy(newfs, fs, (u_int)fs->fs_sbsize);
491df8bae1dSRodney W. Grimes 	if (fs->fs_sbsize < SBSIZE)
492df8bae1dSRodney W. Grimes 		bp->b_flags |= B_INVAL;
493df8bae1dSRodney W. Grimes 	brelse(bp);
494996c772fSJohn Dyson 	mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
495df8bae1dSRodney W. Grimes 	ffs_oldfscompat(fs);
496996c772fSJohn Dyson 
497df8bae1dSRodney W. Grimes 	/*
498df8bae1dSRodney W. Grimes 	 * Step 3: re-read summary information from disk.
499df8bae1dSRodney W. Grimes 	 */
500df8bae1dSRodney W. Grimes 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
501df8bae1dSRodney W. Grimes 	space = fs->fs_csp[0];
502df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
503df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
504df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
505df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
506c9671602SPoul-Henning Kamp 		error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
507c9671602SPoul-Henning Kamp 		    NOCRED, &bp);
508c9671602SPoul-Henning Kamp 		if (error)
509df8bae1dSRodney W. Grimes 			return (error);
510df8bae1dSRodney W. Grimes 		bcopy(bp->b_data, fs->fs_csp[fragstoblks(fs, i)], (u_int)size);
511df8bae1dSRodney W. Grimes 		brelse(bp);
512df8bae1dSRodney W. Grimes 	}
513996c772fSJohn Dyson 	/*
514996c772fSJohn Dyson 	 * We no longer know anything about clusters per cylinder group.
515996c772fSJohn Dyson 	 */
516996c772fSJohn Dyson 	if (fs->fs_contigsumsize > 0) {
517996c772fSJohn Dyson 		lp = fs->fs_maxcluster;
518996c772fSJohn Dyson 		for (i = 0; i < fs->fs_ncg; i++)
519996c772fSJohn Dyson 			*lp++ = fs->fs_contigsumsize;
520996c772fSJohn Dyson 	}
521996c772fSJohn Dyson 
522df8bae1dSRodney W. Grimes loop:
523996c772fSJohn Dyson 	simple_lock(&mntvnode_slock);
5242b14f991SJulian Elischer 	for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
525996c772fSJohn Dyson 		if (vp->v_mount != mp) {
526996c772fSJohn Dyson 			simple_unlock(&mntvnode_slock);
527996c772fSJohn Dyson 			goto loop;
528996c772fSJohn Dyson 		}
529df8bae1dSRodney W. Grimes 		nvp = vp->v_mntvnodes.le_next;
530df8bae1dSRodney W. Grimes 		/*
531df8bae1dSRodney W. Grimes 		 * Step 4: invalidate all inactive vnodes.
532df8bae1dSRodney W. Grimes 		 */
533996c772fSJohn Dyson 		if (vrecycle(vp, &mntvnode_slock, p))
534996c772fSJohn Dyson 			goto loop;
535df8bae1dSRodney W. Grimes 		/*
536df8bae1dSRodney W. Grimes 		 * Step 5: invalidate all cached file data.
537df8bae1dSRodney W. Grimes 		 */
538996c772fSJohn Dyson 		simple_lock(&vp->v_interlock);
539996c772fSJohn Dyson 		simple_unlock(&mntvnode_slock);
540996c772fSJohn Dyson 		if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) {
541df8bae1dSRodney W. Grimes 			goto loop;
542996c772fSJohn Dyson 		}
543df8bae1dSRodney W. Grimes 		if (vinvalbuf(vp, 0, cred, p, 0, 0))
544df8bae1dSRodney W. Grimes 			panic("ffs_reload: dirty2");
545df8bae1dSRodney W. Grimes 		/*
546df8bae1dSRodney W. Grimes 		 * Step 6: re-read inode data for all active vnodes.
547df8bae1dSRodney W. Grimes 		 */
548df8bae1dSRodney W. Grimes 		ip = VTOI(vp);
549c9671602SPoul-Henning Kamp 		error =
550df8bae1dSRodney W. Grimes 		    bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
551c9671602SPoul-Henning Kamp 		    (int)fs->fs_bsize, NOCRED, &bp);
552c9671602SPoul-Henning Kamp 		if (error) {
553df8bae1dSRodney W. Grimes 			vput(vp);
554df8bae1dSRodney W. Grimes 			return (error);
555df8bae1dSRodney W. Grimes 		}
556df8bae1dSRodney W. Grimes 		ip->i_din = *((struct dinode *)bp->b_data +
557df8bae1dSRodney W. Grimes 		    ino_to_fsbo(fs, ip->i_number));
558b1897c19SJulian Elischer 		ip->i_effnlink = ip->i_nlink;
559df8bae1dSRodney W. Grimes 		brelse(bp);
560df8bae1dSRodney W. Grimes 		vput(vp);
561996c772fSJohn Dyson 		simple_lock(&mntvnode_slock);
562df8bae1dSRodney W. Grimes 	}
563996c772fSJohn Dyson 	simple_unlock(&mntvnode_slock);
564df8bae1dSRodney W. Grimes 	return (0);
565df8bae1dSRodney W. Grimes }
566df8bae1dSRodney W. Grimes 
567df8bae1dSRodney W. Grimes /*
568df8bae1dSRodney W. Grimes  * Common code for mount and mountroot
569df8bae1dSRodney W. Grimes  */
570df8bae1dSRodney W. Grimes int
5710be6b890SPoul-Henning Kamp ffs_mountfs(devvp, mp, p, malloctype)
572df8bae1dSRodney W. Grimes 	register struct vnode *devvp;
573df8bae1dSRodney W. Grimes 	struct mount *mp;
574df8bae1dSRodney W. Grimes 	struct proc *p;
5750be6b890SPoul-Henning Kamp 	struct malloc_type *malloctype;
576df8bae1dSRodney W. Grimes {
577df8bae1dSRodney W. Grimes 	register struct ufsmount *ump;
578df8bae1dSRodney W. Grimes 	struct buf *bp;
579df8bae1dSRodney W. Grimes 	register struct fs *fs;
580996c772fSJohn Dyson 	dev_t dev;
581df8bae1dSRodney W. Grimes 	struct partinfo dpart;
582df8bae1dSRodney W. Grimes 	caddr_t base, space;
583f5ef029eSPoul-Henning Kamp 	int error, i, blks, size, ronly;
584996c772fSJohn Dyson 	int32_t *lp;
585996c772fSJohn Dyson 	struct ucred *cred;
586996c772fSJohn Dyson 	u_int64_t maxfilesize;					/* XXX */
5878435e0aeSDoug Rabson 	size_t strsize;
5886476c0d2SJohn Dyson 	int ncount;
589df8bae1dSRodney W. Grimes 
590996c772fSJohn Dyson 	dev = devvp->v_rdev;
591996c772fSJohn Dyson 	cred = p ? p->p_ucred : NOCRED;
592df8bae1dSRodney W. Grimes 	/*
593df8bae1dSRodney W. Grimes 	 * Disallow multiple mounts of the same device.
594df8bae1dSRodney W. Grimes 	 * Disallow mounting of a device that is currently in use
595df8bae1dSRodney W. Grimes 	 * (except for root, which might share swap device for miniroot).
596df8bae1dSRodney W. Grimes 	 * Flush out any old buffers remaining from a previous use.
597df8bae1dSRodney W. Grimes 	 */
598c9671602SPoul-Henning Kamp 	error = vfs_mountedon(devvp);
599c9671602SPoul-Henning Kamp 	if (error)
600df8bae1dSRodney W. Grimes 		return (error);
6016476c0d2SJohn Dyson 	ncount = vcount(devvp);
6028f9110f6SJohn Dyson 
6036476c0d2SJohn Dyson 	if (ncount > 1 && devvp != rootvp)
604df8bae1dSRodney W. Grimes 		return (EBUSY);
605b1897c19SJulian Elischer 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
606b1897c19SJulian Elischer 	error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0);
607b1897c19SJulian Elischer 	VOP_UNLOCK(devvp, 0, p);
608b1897c19SJulian Elischer 	if (error)
609df8bae1dSRodney W. Grimes 		return (error);
610df8bae1dSRodney W. Grimes 
61195e5e988SJohn Dyson 	/*
61295e5e988SJohn Dyson 	 * Only VMIO the backing device if the backing device is a real
61395e5e988SJohn Dyson 	 * block device.  This excludes the original MFS implementation.
61495e5e988SJohn Dyson 	 * Note that it is optional that the backing device be VMIOed.  This
61595e5e988SJohn Dyson 	 * increases the opportunity for metadata caching.
61695e5e988SJohn Dyson 	 */
617b5ee1640SBruce Evans 	if (devvp->v_tag != VT_MFS && devvp->v_type == VBLK) {
618a777e820SEivind Eklund 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
619fb116777SEivind Eklund 		vfs_object_create(devvp, p, p->p_ucred);
62016337c2eSBruce Evans 		simple_lock(&devvp->v_interlock);
621a777e820SEivind Eklund 		VOP_UNLOCK(devvp, LK_INTERLOCK, p);
62295e5e988SJohn Dyson 	}
62395e5e988SJohn Dyson 
624df8bae1dSRodney W. Grimes 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
625c9671602SPoul-Henning Kamp 	error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
626c9671602SPoul-Henning Kamp 	if (error)
627df8bae1dSRodney W. Grimes 		return (error);
62895e5e988SJohn Dyson 
629996c772fSJohn Dyson 	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0)
630df8bae1dSRodney W. Grimes 		size = DEV_BSIZE;
631996c772fSJohn Dyson 	else
632df8bae1dSRodney W. Grimes 		size = dpart.disklab->d_secsize;
633df8bae1dSRodney W. Grimes 
634df8bae1dSRodney W. Grimes 	bp = NULL;
635df8bae1dSRodney W. Grimes 	ump = NULL;
6368aef1712SMatthew Dillon 	if ((error = bread(devvp, SBLOCK, SBSIZE, cred, &bp)) != 0)
637df8bae1dSRodney W. Grimes 		goto out;
638df8bae1dSRodney W. Grimes 	fs = (struct fs *)bp->b_data;
639df8bae1dSRodney W. Grimes 	if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
640df8bae1dSRodney W. Grimes 	    fs->fs_bsize < sizeof(struct fs)) {
641df8bae1dSRodney W. Grimes 		error = EINVAL;		/* XXX needs translation */
642df8bae1dSRodney W. Grimes 		goto out;
643df8bae1dSRodney W. Grimes 	}
6443f6f17eeSJulian Elischer 	fs->fs_fmod = 0;
6450922cce6SBruce Evans 	fs->fs_flags &= ~FS_UNCLEAN;
6460922cce6SBruce Evans 	if (fs->fs_clean == 0) {
6470922cce6SBruce Evans 		fs->fs_flags |= FS_UNCLEAN;
6481469eec8SDavid Greenman 		if (ronly || (mp->mnt_flag & MNT_FORCE)) {
6490922cce6SBruce Evans 			printf(
6500922cce6SBruce Evans "WARNING: %s was not properly dismounted\n",
6510922cce6SBruce Evans 			    fs->fs_fsmnt);
6521469eec8SDavid Greenman 		} else {
6530922cce6SBruce Evans 			printf(
6540922cce6SBruce Evans "WARNING: R/W mount of %s denied.  Filesystem is not clean - run fsck\n",
6550922cce6SBruce Evans 			    fs->fs_fsmnt);
6561469eec8SDavid Greenman 			error = EPERM;
6571469eec8SDavid Greenman 			goto out;
6581469eec8SDavid Greenman 		}
6591469eec8SDavid Greenman 	}
660996c772fSJohn Dyson 	/* XXX updating 4.2 FFS superblocks trashes rotational layout tables */
661996c772fSJohn Dyson 	if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) {
662996c772fSJohn Dyson 		error = EROFS;          /* needs translation */
663996c772fSJohn Dyson 		goto out;
664996c772fSJohn Dyson 	}
665df8bae1dSRodney W. Grimes 	ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
666df8bae1dSRodney W. Grimes 	bzero((caddr_t)ump, sizeof *ump);
6670be6b890SPoul-Henning Kamp 	ump->um_malloctype = malloctype;
668df8bae1dSRodney W. Grimes 	ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT,
669df8bae1dSRodney W. Grimes 	    M_WAITOK);
670cec0f20cSPoul-Henning Kamp 	ump->um_blkatoff = ffs_blkatoff;
671cec0f20cSPoul-Henning Kamp 	ump->um_truncate = ffs_truncate;
672987f5696SPoul-Henning Kamp 	ump->um_update = ffs_update;
673cec0f20cSPoul-Henning Kamp 	ump->um_valloc = ffs_valloc;
674cec0f20cSPoul-Henning Kamp 	ump->um_vfree = ffs_vfree;
675df8bae1dSRodney W. Grimes 	bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize);
676df8bae1dSRodney W. Grimes 	if (fs->fs_sbsize < SBSIZE)
677df8bae1dSRodney W. Grimes 		bp->b_flags |= B_INVAL;
678df8bae1dSRodney W. Grimes 	brelse(bp);
679df8bae1dSRodney W. Grimes 	bp = NULL;
680df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
681df8bae1dSRodney W. Grimes 	fs->fs_ronly = ronly;
682e0e9c421SDavid Greenman 	if (ronly == 0) {
683df8bae1dSRodney W. Grimes 		fs->fs_fmod = 1;
684e0e9c421SDavid Greenman 		fs->fs_clean = 0;
685e0e9c421SDavid Greenman 	}
686996c772fSJohn Dyson 	size = fs->fs_cssize;
687996c772fSJohn Dyson 	blks = howmany(size, fs->fs_fsize);
688996c772fSJohn Dyson 	if (fs->fs_contigsumsize > 0)
689996c772fSJohn Dyson 		size += fs->fs_ncg * sizeof(int32_t);
690996c772fSJohn Dyson 	base = space = malloc((u_long)size, M_UFSMNT, M_WAITOK);
691df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
692df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
693df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
694df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
6958aef1712SMatthew Dillon 		if ((error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
6968aef1712SMatthew Dillon 		    cred, &bp)) != 0) {
697df8bae1dSRodney W. Grimes 			free(base, M_UFSMNT);
698df8bae1dSRodney W. Grimes 			goto out;
699df8bae1dSRodney W. Grimes 		}
700df8bae1dSRodney W. Grimes 		bcopy(bp->b_data, space, (u_int)size);
701df8bae1dSRodney W. Grimes 		fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
702df8bae1dSRodney W. Grimes 		space += size;
703df8bae1dSRodney W. Grimes 		brelse(bp);
704df8bae1dSRodney W. Grimes 		bp = NULL;
705df8bae1dSRodney W. Grimes 	}
706996c772fSJohn Dyson 	if (fs->fs_contigsumsize > 0) {
707996c772fSJohn Dyson 		fs->fs_maxcluster = lp = (int32_t *)space;
708996c772fSJohn Dyson 		for (i = 0; i < fs->fs_ncg; i++)
709996c772fSJohn Dyson 			*lp++ = fs->fs_contigsumsize;
710996c772fSJohn Dyson 	}
711df8bae1dSRodney W. Grimes 	mp->mnt_data = (qaddr_t)ump;
71268de329eSPoul-Henning Kamp 	mp->mnt_stat.f_fsid.val[0] = fs->fs_id[0];
7138f89943eSGuido van Rooij 	mp->mnt_stat.f_fsid.val[1] = fs->fs_id[1];
71468de329eSPoul-Henning Kamp 	if (fs->fs_id[0] == 0 || fs->fs_id[1] == 0 ||
71568de329eSPoul-Henning Kamp 	    vfs_getvfs(&mp->mnt_stat.f_fsid))
71668de329eSPoul-Henning Kamp 		vfs_getnewfsid(mp);
717df8bae1dSRodney W. Grimes 	mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
718cc9d8990SPeter Wemm 	mp->mnt_flag |= MNT_LOCAL;
719df8bae1dSRodney W. Grimes 	ump->um_mountp = mp;
720df8bae1dSRodney W. Grimes 	ump->um_dev = dev;
721df8bae1dSRodney W. Grimes 	ump->um_devvp = devvp;
722df8bae1dSRodney W. Grimes 	ump->um_nindir = fs->fs_nindir;
723df8bae1dSRodney W. Grimes 	ump->um_bptrtodb = fs->fs_fsbtodb;
724df8bae1dSRodney W. Grimes 	ump->um_seqinc = fs->fs_frag;
725df8bae1dSRodney W. Grimes 	for (i = 0; i < MAXQUOTAS; i++)
726df8bae1dSRodney W. Grimes 		ump->um_quotas[i] = NULLVP;
727b1897c19SJulian Elischer 	devvp->v_specmountpoint = mp;
728df8bae1dSRodney W. Grimes 	ffs_oldfscompat(fs);
7292b14f991SJulian Elischer 
7302b14f991SJulian Elischer 	/*
7312b14f991SJulian Elischer 	 * Set FS local "last mounted on" information (NULL pad)
7322b14f991SJulian Elischer 	 */
7332b14f991SJulian Elischer 	copystr(	mp->mnt_stat.f_mntonname,	/* mount point*/
7342b14f991SJulian Elischer 			fs->fs_fsmnt,			/* copy area*/
7352b14f991SJulian Elischer 			sizeof(fs->fs_fsmnt) - 1,	/* max size*/
7362b14f991SJulian Elischer 			&strsize);			/* real size*/
7372b14f991SJulian Elischer 	bzero( fs->fs_fsmnt + strsize, sizeof(fs->fs_fsmnt) - strsize);
7382b14f991SJulian Elischer 
7392b14f991SJulian Elischer 	if( mp->mnt_flag & MNT_ROOTFS) {
7402b14f991SJulian Elischer 		/*
7412b14f991SJulian Elischer 		 * Root mount; update timestamp in mount structure.
7422b14f991SJulian Elischer 		 * this will be used by the common root mount code
7432b14f991SJulian Elischer 		 * to update the system clock.
7442b14f991SJulian Elischer 		 */
7452b14f991SJulian Elischer 		mp->mnt_time = fs->fs_time;
7462b14f991SJulian Elischer 	}
747996c772fSJohn Dyson 
748996c772fSJohn Dyson 	ump->um_savedmaxfilesize = fs->fs_maxfilesize;		/* XXX */
749996c772fSJohn Dyson 	maxfilesize = (u_int64_t)0x40000000 * fs->fs_bsize - 1;	/* XXX */
750996c772fSJohn Dyson 	if (fs->fs_maxfilesize > maxfilesize)			/* XXX */
751996c772fSJohn Dyson 		fs->fs_maxfilesize = maxfilesize;		/* XXX */
752996c772fSJohn Dyson 	if (ronly == 0) {
753b1897c19SJulian Elischer 		if ((fs->fs_flags & FS_DOSOFTDEP) &&
754b1897c19SJulian Elischer 		    (error = softdep_mount(devvp, mp, fs, cred)) != 0) {
755b1897c19SJulian Elischer 			free(base, M_UFSMNT);
756b1897c19SJulian Elischer 			goto out;
757b1897c19SJulian Elischer 		}
758996c772fSJohn Dyson 		fs->fs_clean = 0;
759996c772fSJohn Dyson 		(void) ffs_sbupdate(ump, MNT_WAIT);
760996c772fSJohn Dyson 	}
761df8bae1dSRodney W. Grimes 	return (0);
762df8bae1dSRodney W. Grimes out:
763b1897c19SJulian Elischer 	devvp->v_specmountpoint = NULL;
764df8bae1dSRodney W. Grimes 	if (bp)
765df8bae1dSRodney W. Grimes 		brelse(bp);
766996c772fSJohn Dyson 	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
767df8bae1dSRodney W. Grimes 	if (ump) {
768df8bae1dSRodney W. Grimes 		free(ump->um_fs, M_UFSMNT);
769df8bae1dSRodney W. Grimes 		free(ump, M_UFSMNT);
770df8bae1dSRodney W. Grimes 		mp->mnt_data = (qaddr_t)0;
771df8bae1dSRodney W. Grimes 	}
772df8bae1dSRodney W. Grimes 	return (error);
773df8bae1dSRodney W. Grimes }
774df8bae1dSRodney W. Grimes 
775df8bae1dSRodney W. Grimes /*
776df8bae1dSRodney W. Grimes  * Sanity checks for old file systems.
777df8bae1dSRodney W. Grimes  *
778df8bae1dSRodney W. Grimes  * XXX - goes away some day.
779df8bae1dSRodney W. Grimes  */
780b8dce649SPoul-Henning Kamp static int
781df8bae1dSRodney W. Grimes ffs_oldfscompat(fs)
782df8bae1dSRodney W. Grimes 	struct fs *fs;
783df8bae1dSRodney W. Grimes {
784df8bae1dSRodney W. Grimes 
785df8bae1dSRodney W. Grimes 	fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect);	/* XXX */
786df8bae1dSRodney W. Grimes 	fs->fs_interleave = max(fs->fs_interleave, 1);		/* XXX */
787df8bae1dSRodney W. Grimes 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
788df8bae1dSRodney W. Grimes 		fs->fs_nrpos = 8;				/* XXX */
789df8bae1dSRodney W. Grimes 	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
790c03020b2SPoul-Henning Kamp #if 0
791c03020b2SPoul-Henning Kamp 		int i;						/* XXX */
792996c772fSJohn Dyson 		u_int64_t sizepb = fs->fs_bsize;		/* XXX */
793996c772fSJohn Dyson 								/* XXX */
794df8bae1dSRodney W. Grimes 		fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1;	/* XXX */
795df8bae1dSRodney W. Grimes 		for (i = 0; i < NIADDR; i++) {			/* XXX */
796df8bae1dSRodney W. Grimes 			sizepb *= NINDIR(fs);			/* XXX */
797df8bae1dSRodney W. Grimes 			fs->fs_maxfilesize += sizepb;		/* XXX */
798df8bae1dSRodney W. Grimes 		}						/* XXX */
799901ba606SDavid Greenman #endif
800a316d390SJohn Dyson 		fs->fs_maxfilesize = (u_quad_t) 1LL << 39;
801df8bae1dSRodney W. Grimes 		fs->fs_qbmask = ~fs->fs_bmask;			/* XXX */
802df8bae1dSRodney W. Grimes 		fs->fs_qfmask = ~fs->fs_fmask;			/* XXX */
803df8bae1dSRodney W. Grimes 	}							/* XXX */
804df8bae1dSRodney W. Grimes 	return (0);
805df8bae1dSRodney W. Grimes }
806df8bae1dSRodney W. Grimes 
807df8bae1dSRodney W. Grimes /*
808df8bae1dSRodney W. Grimes  * unmount system call
809df8bae1dSRodney W. Grimes  */
810df8bae1dSRodney W. Grimes int
811df8bae1dSRodney W. Grimes ffs_unmount(mp, mntflags, p)
812df8bae1dSRodney W. Grimes 	struct mount *mp;
813df8bae1dSRodney W. Grimes 	int mntflags;
814df8bae1dSRodney W. Grimes 	struct proc *p;
815df8bae1dSRodney W. Grimes {
816df8bae1dSRodney W. Grimes 	register struct ufsmount *ump;
817df8bae1dSRodney W. Grimes 	register struct fs *fs;
818996c772fSJohn Dyson 	int error, flags;
819df8bae1dSRodney W. Grimes 
820df8bae1dSRodney W. Grimes 	flags = 0;
821df8bae1dSRodney W. Grimes 	if (mntflags & MNT_FORCE) {
822df8bae1dSRodney W. Grimes 		flags |= FORCECLOSE;
823df8bae1dSRodney W. Grimes 	}
824b1897c19SJulian Elischer 	if (mp->mnt_flag & MNT_SOFTDEP) {
825b1897c19SJulian Elischer 		if ((error = softdep_flushfiles(mp, flags, p)) != 0)
826df8bae1dSRodney W. Grimes 			return (error);
827b1897c19SJulian Elischer 	} else {
828b1897c19SJulian Elischer 		if ((error = ffs_flushfiles(mp, flags, p)) != 0)
829b1897c19SJulian Elischer 			return (error);
830b1897c19SJulian Elischer 	}
831df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
832df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
833996c772fSJohn Dyson 	if (fs->fs_ronly == 0) {
8340922cce6SBruce Evans 		fs->fs_clean = fs->fs_flags & FS_UNCLEAN ? 0 : 1;
835996c772fSJohn Dyson 		error = ffs_sbupdate(ump, MNT_WAIT);
836996c772fSJohn Dyson 		if (error) {
837996c772fSJohn Dyson 			fs->fs_clean = 0;
838996c772fSJohn Dyson 			return (error);
839996c772fSJohn Dyson 		}
840e0e9c421SDavid Greenman 	}
841b1897c19SJulian Elischer 	ump->um_devvp->v_specmountpoint = NULL;
8426476c0d2SJohn Dyson 
84395e5e988SJohn Dyson 	vinvalbuf(ump->um_devvp, V_SAVE, NOCRED, p, 0, 0);
844996c772fSJohn Dyson 	error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE,
845df8bae1dSRodney W. Grimes 		NOCRED, p);
8466476c0d2SJohn Dyson 
8476476c0d2SJohn Dyson 	vrele(ump->um_devvp);
8486476c0d2SJohn Dyson 
849df8bae1dSRodney W. Grimes 	free(fs->fs_csp[0], M_UFSMNT);
850df8bae1dSRodney W. Grimes 	free(fs, M_UFSMNT);
851df8bae1dSRodney W. Grimes 	free(ump, M_UFSMNT);
852df8bae1dSRodney W. Grimes 	mp->mnt_data = (qaddr_t)0;
853cc9d8990SPeter Wemm 	mp->mnt_flag &= ~MNT_LOCAL;
854df8bae1dSRodney W. Grimes 	return (error);
855df8bae1dSRodney W. Grimes }
856df8bae1dSRodney W. Grimes 
857df8bae1dSRodney W. Grimes /*
858df8bae1dSRodney W. Grimes  * Flush out all the files in a filesystem.
859df8bae1dSRodney W. Grimes  */
86026f9a767SRodney W. Grimes int
861df8bae1dSRodney W. Grimes ffs_flushfiles(mp, flags, p)
862df8bae1dSRodney W. Grimes 	register struct mount *mp;
863df8bae1dSRodney W. Grimes 	int flags;
864df8bae1dSRodney W. Grimes 	struct proc *p;
865df8bae1dSRodney W. Grimes {
866df8bae1dSRodney W. Grimes 	register struct ufsmount *ump;
867c9671602SPoul-Henning Kamp 	int error;
868df8bae1dSRodney W. Grimes 
869df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
870df8bae1dSRodney W. Grimes #ifdef QUOTA
871df8bae1dSRodney W. Grimes 	if (mp->mnt_flag & MNT_QUOTA) {
872c1d9efcbSPoul-Henning Kamp 		int i;
873c1d9efcbSPoul-Henning Kamp 		error = vflush(mp, NULLVP, SKIPSYSTEM|flags);
874c1d9efcbSPoul-Henning Kamp 		if (error)
875df8bae1dSRodney W. Grimes 			return (error);
876df8bae1dSRodney W. Grimes 		for (i = 0; i < MAXQUOTAS; i++) {
877df8bae1dSRodney W. Grimes 			if (ump->um_quotas[i] == NULLVP)
878df8bae1dSRodney W. Grimes 				continue;
879df8bae1dSRodney W. Grimes 			quotaoff(p, mp, i);
880df8bae1dSRodney W. Grimes 		}
881df8bae1dSRodney W. Grimes 		/*
882df8bae1dSRodney W. Grimes 		 * Here we fall through to vflush again to ensure
883df8bae1dSRodney W. Grimes 		 * that we have gotten rid of all the system vnodes.
884df8bae1dSRodney W. Grimes 		 */
885df8bae1dSRodney W. Grimes 	}
886df8bae1dSRodney W. Grimes #endif
887b1897c19SJulian Elischer         /*
888b1897c19SJulian Elischer 	 * Flush all the files.
889b1897c19SJulian Elischer 	 */
890b1897c19SJulian Elischer 	if ((error = vflush(mp, NULL, flags)) != 0)
891b1897c19SJulian Elischer 		return (error);
892b1897c19SJulian Elischer 	/*
893b1897c19SJulian Elischer 	 * Flush filesystem metadata.
894b1897c19SJulian Elischer 	 */
895b1897c19SJulian Elischer 	vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p);
896b1897c19SJulian Elischer 	error = VOP_FSYNC(ump->um_devvp, p->p_ucred, MNT_WAIT, p);
897b1897c19SJulian Elischer 	VOP_UNLOCK(ump->um_devvp, 0, p);
898df8bae1dSRodney W. Grimes 	return (error);
899df8bae1dSRodney W. Grimes }
900df8bae1dSRodney W. Grimes 
901df8bae1dSRodney W. Grimes /*
902df8bae1dSRodney W. Grimes  * Get file system statistics.
903df8bae1dSRodney W. Grimes  */
904df8bae1dSRodney W. Grimes int
905df8bae1dSRodney W. Grimes ffs_statfs(mp, sbp, p)
906df8bae1dSRodney W. Grimes 	struct mount *mp;
907df8bae1dSRodney W. Grimes 	register struct statfs *sbp;
908df8bae1dSRodney W. Grimes 	struct proc *p;
909df8bae1dSRodney W. Grimes {
910df8bae1dSRodney W. Grimes 	register struct ufsmount *ump;
911df8bae1dSRodney W. Grimes 	register struct fs *fs;
912df8bae1dSRodney W. Grimes 
913df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
914df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
915df8bae1dSRodney W. Grimes 	if (fs->fs_magic != FS_MAGIC)
916df8bae1dSRodney W. Grimes 		panic("ffs_statfs");
917df8bae1dSRodney W. Grimes 	sbp->f_bsize = fs->fs_fsize;
918df8bae1dSRodney W. Grimes 	sbp->f_iosize = fs->fs_bsize;
919df8bae1dSRodney W. Grimes 	sbp->f_blocks = fs->fs_dsize;
920df8bae1dSRodney W. Grimes 	sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
921df8bae1dSRodney W. Grimes 		fs->fs_cstotal.cs_nffree;
92251ea8b57SBruce Evans 	sbp->f_bavail = freespace(fs, fs->fs_minfree);
923df8bae1dSRodney W. Grimes 	sbp->f_files =  fs->fs_ncg * fs->fs_ipg - ROOTINO;
924df8bae1dSRodney W. Grimes 	sbp->f_ffree = fs->fs_cstotal.cs_nifree;
925df8bae1dSRodney W. Grimes 	if (sbp != &mp->mnt_stat) {
926996c772fSJohn Dyson 		sbp->f_type = mp->mnt_vfc->vfc_typenum;
927df8bae1dSRodney W. Grimes 		bcopy((caddr_t)mp->mnt_stat.f_mntonname,
928df8bae1dSRodney W. Grimes 			(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
929df8bae1dSRodney W. Grimes 		bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
930df8bae1dSRodney W. Grimes 			(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
931df8bae1dSRodney W. Grimes 	}
932df8bae1dSRodney W. Grimes 	return (0);
933df8bae1dSRodney W. Grimes }
934df8bae1dSRodney W. Grimes 
935df8bae1dSRodney W. Grimes /*
936df8bae1dSRodney W. Grimes  * Go through the disk queues to initiate sandbagged IO;
937df8bae1dSRodney W. Grimes  * go through the inodes to write those that have been modified;
938df8bae1dSRodney W. Grimes  * initiate the writing of the super block if it has been modified.
939df8bae1dSRodney W. Grimes  *
940df8bae1dSRodney W. Grimes  * Note: we are always called with the filesystem marked `MPBUSY'.
941df8bae1dSRodney W. Grimes  */
942df8bae1dSRodney W. Grimes int
943df8bae1dSRodney W. Grimes ffs_sync(mp, waitfor, cred, p)
944df8bae1dSRodney W. Grimes 	struct mount *mp;
945df8bae1dSRodney W. Grimes 	int waitfor;
946df8bae1dSRodney W. Grimes 	struct ucred *cred;
947df8bae1dSRodney W. Grimes 	struct proc *p;
948df8bae1dSRodney W. Grimes {
949996c772fSJohn Dyson 	struct vnode *nvp, *vp;
950996c772fSJohn Dyson 	struct inode *ip;
951996c772fSJohn Dyson 	struct ufsmount *ump = VFSTOUFS(mp);
952996c772fSJohn Dyson 	struct fs *fs;
953df8bae1dSRodney W. Grimes 	int error, allerror = 0;
954df8bae1dSRodney W. Grimes 
955df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
956996c772fSJohn Dyson 	if (fs->fs_fmod != 0 && fs->fs_ronly != 0) {		/* XXX */
957df8bae1dSRodney W. Grimes 		printf("fs = %s\n", fs->fs_fsmnt);
9585ace3b26SMike Pritchard 		panic("ffs_sync: rofs mod");
959df8bae1dSRodney W. Grimes 	}
960df8bae1dSRodney W. Grimes 	/*
961df8bae1dSRodney W. Grimes 	 * Write back each (modified) inode.
962df8bae1dSRodney W. Grimes 	 */
963996c772fSJohn Dyson 	simple_lock(&mntvnode_slock);
964df8bae1dSRodney W. Grimes loop:
965a316d390SJohn Dyson 	for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
966df8bae1dSRodney W. Grimes 		/*
967df8bae1dSRodney W. Grimes 		 * If the vnode that we are about to sync is no longer
968df8bae1dSRodney W. Grimes 		 * associated with this mount point, start over.
969df8bae1dSRodney W. Grimes 		 */
970df8bae1dSRodney W. Grimes 		if (vp->v_mount != mp)
971df8bae1dSRodney W. Grimes 			goto loop;
972996c772fSJohn Dyson 		simple_lock(&vp->v_interlock);
973a316d390SJohn Dyson 		nvp = vp->v_mntvnodes.le_next;
974df8bae1dSRodney W. Grimes 		ip = VTOI(vp);
9758aef1712SMatthew Dillon 		if ((vp->v_type == VNON) || (((ip->i_flag &
9769cfcd011SJohn Dyson 		     (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) &&
9778aef1712SMatthew Dillon 		    (TAILQ_EMPTY(&vp->v_dirtyblkhd) || (waitfor == MNT_LAZY)))) {
978996c772fSJohn Dyson 			simple_unlock(&vp->v_interlock);
979df8bae1dSRodney W. Grimes 			continue;
980996c772fSJohn Dyson 		}
98181c6e3e5SDavid Greenman 		if (vp->v_type != VCHR) {
982996c772fSJohn Dyson 			simple_unlock(&mntvnode_slock);
983996c772fSJohn Dyson 			error =
984996c772fSJohn Dyson 			  vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
985996c772fSJohn Dyson 			if (error) {
986996c772fSJohn Dyson 				simple_lock(&mntvnode_slock);
987996c772fSJohn Dyson 				if (error == ENOENT)
988df8bae1dSRodney W. Grimes 					goto loop;
989996c772fSJohn Dyson 				continue;
990996c772fSJohn Dyson 			}
9918aef1712SMatthew Dillon 			if ((error = VOP_FSYNC(vp, cred, waitfor, p)) != 0)
992df8bae1dSRodney W. Grimes 				allerror = error;
993996c772fSJohn Dyson 			VOP_UNLOCK(vp, 0, p);
994996c772fSJohn Dyson 			vrele(vp);
995996c772fSJohn Dyson 			simple_lock(&mntvnode_slock);
99681c6e3e5SDavid Greenman 		} else {
997996c772fSJohn Dyson 			simple_unlock(&mntvnode_slock);
998996c772fSJohn Dyson 			simple_unlock(&vp->v_interlock);
999de5d1ba5SBruce Evans 			/* UFS_UPDATE(vp, waitfor == MNT_WAIT); */
1000de5d1ba5SBruce Evans 			UFS_UPDATE(vp, 0);
1001996c772fSJohn Dyson 			simple_lock(&mntvnode_slock);
100281c6e3e5SDavid Greenman 		}
1003df8bae1dSRodney W. Grimes 	}
1004996c772fSJohn Dyson 	simple_unlock(&mntvnode_slock);
1005df8bae1dSRodney W. Grimes 	/*
1006df8bae1dSRodney W. Grimes 	 * Force stale file system control information to be flushed.
1007df8bae1dSRodney W. Grimes 	 */
1008b1897c19SJulian Elischer 	if (waitfor != MNT_LAZY) {
1009b1897c19SJulian Elischer 		if (ump->um_mountp->mnt_flag & MNT_SOFTDEP)
1010b1897c19SJulian Elischer 			waitfor = MNT_NOWAIT;
1011b1897c19SJulian Elischer 		vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p);
1012b1897c19SJulian Elischer 		if ((error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p)) != 0)
1013df8bae1dSRodney W. Grimes 			allerror = error;
1014b1897c19SJulian Elischer 		VOP_UNLOCK(ump->um_devvp, 0, p);
1015b1897c19SJulian Elischer 	}
1016df8bae1dSRodney W. Grimes #ifdef QUOTA
1017df8bae1dSRodney W. Grimes 	qsync(mp);
1018df8bae1dSRodney W. Grimes #endif
1019996c772fSJohn Dyson 	/*
1020996c772fSJohn Dyson 	 * Write back modified superblock.
1021996c772fSJohn Dyson 	 */
1022b1897c19SJulian Elischer 	if (fs->fs_fmod != 0 && (error = ffs_sbupdate(ump, waitfor)) != 0)
1023996c772fSJohn Dyson 		allerror = error;
1024df8bae1dSRodney W. Grimes 	return (allerror);
1025df8bae1dSRodney W. Grimes }
1026df8bae1dSRodney W. Grimes 
1027df8bae1dSRodney W. Grimes /*
1028df8bae1dSRodney W. Grimes  * Look up a FFS dinode number to find its incore vnode, otherwise read it
1029df8bae1dSRodney W. Grimes  * in from disk.  If it is in core, wait for the lock bit to clear, then
1030df8bae1dSRodney W. Grimes  * return the inode locked.  Detection and handling of mount points must be
1031df8bae1dSRodney W. Grimes  * done by the calling routine.
1032df8bae1dSRodney W. Grimes  */
1033b8dce649SPoul-Henning Kamp static int ffs_inode_hash_lock;
10342094ddb6SDavid Greenman 
1035df8bae1dSRodney W. Grimes int
1036df8bae1dSRodney W. Grimes ffs_vget(mp, ino, vpp)
1037df8bae1dSRodney W. Grimes 	struct mount *mp;
1038df8bae1dSRodney W. Grimes 	ino_t ino;
1039df8bae1dSRodney W. Grimes 	struct vnode **vpp;
1040df8bae1dSRodney W. Grimes {
1041996c772fSJohn Dyson 	struct fs *fs;
1042996c772fSJohn Dyson 	struct inode *ip;
1043df8bae1dSRodney W. Grimes 	struct ufsmount *ump;
1044df8bae1dSRodney W. Grimes 	struct buf *bp;
1045df8bae1dSRodney W. Grimes 	struct vnode *vp;
1046df8bae1dSRodney W. Grimes 	dev_t dev;
10470be6b890SPoul-Henning Kamp 	int error;
1048df8bae1dSRodney W. Grimes 
1049df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
1050df8bae1dSRodney W. Grimes 	dev = ump->um_dev;
10518997d94fSDavid Greenman restart:
10528f9110f6SJohn Dyson 	if ((*vpp = ufs_ihashget(dev, ino)) != NULL) {
1053df8bae1dSRodney W. Grimes 		return (0);
10548f9110f6SJohn Dyson 	}
1055df8bae1dSRodney W. Grimes 
10562094ddb6SDavid Greenman 	/*
10578997d94fSDavid Greenman 	 * Lock out the creation of new entries in the FFS hash table in
10588997d94fSDavid Greenman 	 * case getnewvnode() or MALLOC() blocks, otherwise a duplicate
10592094ddb6SDavid Greenman 	 * may occur!
10602094ddb6SDavid Greenman 	 */
10612094ddb6SDavid Greenman 	if (ffs_inode_hash_lock) {
10622094ddb6SDavid Greenman 		while (ffs_inode_hash_lock) {
10632094ddb6SDavid Greenman 			ffs_inode_hash_lock = -1;
10642094ddb6SDavid Greenman 			tsleep(&ffs_inode_hash_lock, PVM, "ffsvgt", 0);
10652094ddb6SDavid Greenman 		}
10668997d94fSDavid Greenman 		goto restart;
10672094ddb6SDavid Greenman 	}
10682094ddb6SDavid Greenman 	ffs_inode_hash_lock = 1;
10692094ddb6SDavid Greenman 
10702f9bae59SDavid Greenman 	/*
10712f9bae59SDavid Greenman 	 * If this MALLOC() is performed after the getnewvnode()
10722f9bae59SDavid Greenman 	 * it might block, leaving a vnode with a NULL v_data to be
10732f9bae59SDavid Greenman 	 * found by ffs_sync() if a sync happens to fire right then,
10742f9bae59SDavid Greenman 	 * which will cause a panic because ffs_sync() blindly
10752f9bae59SDavid Greenman 	 * dereferences vp->v_data (as well it should).
10762f9bae59SDavid Greenman 	 */
10770be6b890SPoul-Henning Kamp 	MALLOC(ip, struct inode *, sizeof(struct inode),
10780be6b890SPoul-Henning Kamp 	    ump->um_malloctype, M_WAITOK);
10792f9bae59SDavid Greenman 
1080df8bae1dSRodney W. Grimes 	/* Allocate a new vnode/inode. */
1081c9671602SPoul-Henning Kamp 	error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp);
1082c9671602SPoul-Henning Kamp 	if (error) {
10838997d94fSDavid Greenman 		if (ffs_inode_hash_lock < 0)
10842094ddb6SDavid Greenman 			wakeup(&ffs_inode_hash_lock);
10852094ddb6SDavid Greenman 		ffs_inode_hash_lock = 0;
1086df8bae1dSRodney W. Grimes 		*vpp = NULL;
10870be6b890SPoul-Henning Kamp 		FREE(ip, ump->um_malloctype);
1088df8bae1dSRodney W. Grimes 		return (error);
1089df8bae1dSRodney W. Grimes 	}
1090df8bae1dSRodney W. Grimes 	bzero((caddr_t)ip, sizeof(struct inode));
1091996c772fSJohn Dyson 	lockinit(&ip->i_lock, PINOD, "inode", 0, 0);
1092df8bae1dSRodney W. Grimes 	vp->v_data = ip;
1093df8bae1dSRodney W. Grimes 	ip->i_vnode = vp;
1094df8bae1dSRodney W. Grimes 	ip->i_fs = fs = ump->um_fs;
1095df8bae1dSRodney W. Grimes 	ip->i_dev = dev;
1096df8bae1dSRodney W. Grimes 	ip->i_number = ino;
1097df8bae1dSRodney W. Grimes #ifdef QUOTA
1098c1d9efcbSPoul-Henning Kamp 	{
1099c1d9efcbSPoul-Henning Kamp 		int i;
1100df8bae1dSRodney W. Grimes 		for (i = 0; i < MAXQUOTAS; i++)
1101df8bae1dSRodney W. Grimes 			ip->i_dquot[i] = NODQUOT;
1102c1d9efcbSPoul-Henning Kamp 	}
1103df8bae1dSRodney W. Grimes #endif
1104df8bae1dSRodney W. Grimes 	/*
1105df8bae1dSRodney W. Grimes 	 * Put it onto its hash chain and lock it so that other requests for
1106df8bae1dSRodney W. Grimes 	 * this inode will block if they arrive while we are sleeping waiting
1107df8bae1dSRodney W. Grimes 	 * for old data structures to be purged or for the contents of the
1108df8bae1dSRodney W. Grimes 	 * disk portion of this inode to be read.
1109df8bae1dSRodney W. Grimes 	 */
1110df8bae1dSRodney W. Grimes 	ufs_ihashins(ip);
1111df8bae1dSRodney W. Grimes 
11128997d94fSDavid Greenman 	if (ffs_inode_hash_lock < 0)
11132094ddb6SDavid Greenman 		wakeup(&ffs_inode_hash_lock);
11142094ddb6SDavid Greenman 	ffs_inode_hash_lock = 0;
11152094ddb6SDavid Greenman 
1116df8bae1dSRodney W. Grimes 	/* Read in the disk contents for the inode, copy into the inode. */
1117c9671602SPoul-Henning Kamp 	error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
1118c9671602SPoul-Henning Kamp 	    (int)fs->fs_bsize, NOCRED, &bp);
1119c9671602SPoul-Henning Kamp 	if (error) {
1120df8bae1dSRodney W. Grimes 		/*
1121df8bae1dSRodney W. Grimes 		 * The inode does not contain anything useful, so it would
1122df8bae1dSRodney W. Grimes 		 * be misleading to leave it on its hash chain. With mode
1123df8bae1dSRodney W. Grimes 		 * still zero, it will be unlinked and returned to the free
1124df8bae1dSRodney W. Grimes 		 * list by vput().
1125df8bae1dSRodney W. Grimes 		 */
1126df8bae1dSRodney W. Grimes 		brelse(bp);
1127bd7e5f99SJohn Dyson 		vput(vp);
1128df8bae1dSRodney W. Grimes 		*vpp = NULL;
1129df8bae1dSRodney W. Grimes 		return (error);
1130df8bae1dSRodney W. Grimes 	}
1131df8bae1dSRodney W. Grimes 	ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ino));
1132b1897c19SJulian Elischer 	if (DOINGSOFTDEP(vp))
1133b1897c19SJulian Elischer 		softdep_load_inodeblock(ip);
1134b1897c19SJulian Elischer 	else
1135b1897c19SJulian Elischer 		ip->i_effnlink = ip->i_nlink;
1136bd7e5f99SJohn Dyson 	bqrelse(bp);
1137df8bae1dSRodney W. Grimes 
1138df8bae1dSRodney W. Grimes 	/*
1139df8bae1dSRodney W. Grimes 	 * Initialize the vnode from the inode, check for aliases.
1140df8bae1dSRodney W. Grimes 	 * Note that the underlying vnode may have changed.
1141df8bae1dSRodney W. Grimes 	 */
1142e6302eabSBruce Evans 	error = ufs_vinit(mp, ffs_specop_p, ffs_fifoop_p, &vp);
1143c9671602SPoul-Henning Kamp 	if (error) {
1144df8bae1dSRodney W. Grimes 		vput(vp);
1145df8bae1dSRodney W. Grimes 		*vpp = NULL;
1146df8bae1dSRodney W. Grimes 		return (error);
1147df8bae1dSRodney W. Grimes 	}
1148df8bae1dSRodney W. Grimes 	/*
1149df8bae1dSRodney W. Grimes 	 * Finish inode initialization now that aliasing has been resolved.
1150df8bae1dSRodney W. Grimes 	 */
1151df8bae1dSRodney W. Grimes 	ip->i_devvp = ump->um_devvp;
1152df8bae1dSRodney W. Grimes 	VREF(ip->i_devvp);
1153df8bae1dSRodney W. Grimes 	/*
1154df8bae1dSRodney W. Grimes 	 * Set up a generation number for this inode if it does not
1155df8bae1dSRodney W. Grimes 	 * already have one. This should only happen on old filesystems.
1156df8bae1dSRodney W. Grimes 	 */
1157df8bae1dSRodney W. Grimes 	if (ip->i_gen == 0) {
11588f89943eSGuido van Rooij 		ip->i_gen = random() / 2 + 1;
1159df8bae1dSRodney W. Grimes 		if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
1160df8bae1dSRodney W. Grimes 			ip->i_flag |= IN_MODIFIED;
1161df8bae1dSRodney W. Grimes 	}
1162df8bae1dSRodney W. Grimes 	/*
1163df8bae1dSRodney W. Grimes 	 * Ensure that uid and gid are correct. This is a temporary
1164df8bae1dSRodney W. Grimes 	 * fix until fsck has been changed to do the update.
1165df8bae1dSRodney W. Grimes 	 */
1166df8bae1dSRodney W. Grimes 	if (fs->fs_inodefmt < FS_44INODEFMT) {		/* XXX */
1167df8bae1dSRodney W. Grimes 		ip->i_uid = ip->i_din.di_ouid;		/* XXX */
1168df8bae1dSRodney W. Grimes 		ip->i_gid = ip->i_din.di_ogid;		/* XXX */
1169df8bae1dSRodney W. Grimes 	}						/* XXX */
1170df8bae1dSRodney W. Grimes 
1171df8bae1dSRodney W. Grimes 	*vpp = vp;
1172df8bae1dSRodney W. Grimes 	return (0);
1173df8bae1dSRodney W. Grimes }
1174df8bae1dSRodney W. Grimes 
1175df8bae1dSRodney W. Grimes /*
1176df8bae1dSRodney W. Grimes  * File handle to vnode
1177df8bae1dSRodney W. Grimes  *
1178df8bae1dSRodney W. Grimes  * Have to be really careful about stale file handles:
1179df8bae1dSRodney W. Grimes  * - check that the inode number is valid
1180df8bae1dSRodney W. Grimes  * - call ffs_vget() to get the locked inode
1181df8bae1dSRodney W. Grimes  * - check for an unallocated inode (i_mode == 0)
1182df8bae1dSRodney W. Grimes  * - check that the given client host has export rights and return
1183df8bae1dSRodney W. Grimes  *   those rights via. exflagsp and credanonp
1184df8bae1dSRodney W. Grimes  */
1185df8bae1dSRodney W. Grimes int
1186df8bae1dSRodney W. Grimes ffs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
1187df8bae1dSRodney W. Grimes 	register struct mount *mp;
1188df8bae1dSRodney W. Grimes 	struct fid *fhp;
118957bf258eSGarrett Wollman 	struct sockaddr *nam;
1190df8bae1dSRodney W. Grimes 	struct vnode **vpp;
1191df8bae1dSRodney W. Grimes 	int *exflagsp;
1192df8bae1dSRodney W. Grimes 	struct ucred **credanonp;
1193df8bae1dSRodney W. Grimes {
1194df8bae1dSRodney W. Grimes 	register struct ufid *ufhp;
1195df8bae1dSRodney W. Grimes 	struct fs *fs;
1196df8bae1dSRodney W. Grimes 
1197df8bae1dSRodney W. Grimes 	ufhp = (struct ufid *)fhp;
1198df8bae1dSRodney W. Grimes 	fs = VFSTOUFS(mp)->um_fs;
1199df8bae1dSRodney W. Grimes 	if (ufhp->ufid_ino < ROOTINO ||
1200df8bae1dSRodney W. Grimes 	    ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg)
1201df8bae1dSRodney W. Grimes 		return (ESTALE);
1202df8bae1dSRodney W. Grimes 	return (ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp));
1203df8bae1dSRodney W. Grimes }
1204df8bae1dSRodney W. Grimes 
1205df8bae1dSRodney W. Grimes /*
1206df8bae1dSRodney W. Grimes  * Vnode pointer to File handle
1207df8bae1dSRodney W. Grimes  */
1208df8bae1dSRodney W. Grimes /* ARGSUSED */
120926f9a767SRodney W. Grimes int
1210df8bae1dSRodney W. Grimes ffs_vptofh(vp, fhp)
1211df8bae1dSRodney W. Grimes 	struct vnode *vp;
1212df8bae1dSRodney W. Grimes 	struct fid *fhp;
1213df8bae1dSRodney W. Grimes {
1214df8bae1dSRodney W. Grimes 	register struct inode *ip;
1215df8bae1dSRodney W. Grimes 	register struct ufid *ufhp;
1216df8bae1dSRodney W. Grimes 
1217df8bae1dSRodney W. Grimes 	ip = VTOI(vp);
1218df8bae1dSRodney W. Grimes 	ufhp = (struct ufid *)fhp;
1219df8bae1dSRodney W. Grimes 	ufhp->ufid_len = sizeof(struct ufid);
1220df8bae1dSRodney W. Grimes 	ufhp->ufid_ino = ip->i_number;
1221df8bae1dSRodney W. Grimes 	ufhp->ufid_gen = ip->i_gen;
1222df8bae1dSRodney W. Grimes 	return (0);
1223df8bae1dSRodney W. Grimes }
1224df8bae1dSRodney W. Grimes 
1225df8bae1dSRodney W. Grimes /*
1226996c772fSJohn Dyson  * Initialize the filesystem; just use ufs_init.
1227996c772fSJohn Dyson  */
1228996c772fSJohn Dyson static int
1229996c772fSJohn Dyson ffs_init(vfsp)
1230996c772fSJohn Dyson 	struct vfsconf *vfsp;
1231996c772fSJohn Dyson {
1232996c772fSJohn Dyson 
1233b1897c19SJulian Elischer 	softdep_initialize();
1234996c772fSJohn Dyson 	return (ufs_init(vfsp));
1235996c772fSJohn Dyson }
1236996c772fSJohn Dyson 
1237996c772fSJohn Dyson /*
1238df8bae1dSRodney W. Grimes  * Write a superblock and associated information back to disk.
1239df8bae1dSRodney W. Grimes  */
1240b8dce649SPoul-Henning Kamp static int
1241df8bae1dSRodney W. Grimes ffs_sbupdate(mp, waitfor)
1242df8bae1dSRodney W. Grimes 	struct ufsmount *mp;
1243df8bae1dSRodney W. Grimes 	int waitfor;
1244df8bae1dSRodney W. Grimes {
1245996c772fSJohn Dyson 	register struct fs *dfs, *fs = mp->um_fs;
1246df8bae1dSRodney W. Grimes 	register struct buf *bp;
1247df8bae1dSRodney W. Grimes 	int blks;
1248df8bae1dSRodney W. Grimes 	caddr_t space;
1249996c772fSJohn Dyson 	int i, size, error, allerror = 0;
1250df8bae1dSRodney W. Grimes 
1251996c772fSJohn Dyson 	/*
1252996c772fSJohn Dyson 	 * First write back the summary information.
1253996c772fSJohn Dyson 	 */
1254df8bae1dSRodney W. Grimes 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
1255df8bae1dSRodney W. Grimes 	space = (caddr_t)fs->fs_csp[0];
1256df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
1257df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
1258df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
1259df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
1260df8bae1dSRodney W. Grimes 		bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i),
1261df8bae1dSRodney W. Grimes 		    size, 0, 0);
1262df8bae1dSRodney W. Grimes 		bcopy(space, bp->b_data, (u_int)size);
1263df8bae1dSRodney W. Grimes 		space += size;
1264996c772fSJohn Dyson 		if (waitfor != MNT_WAIT)
1265df8bae1dSRodney W. Grimes 			bawrite(bp);
12668aef1712SMatthew Dillon 		else if ((error = bwrite(bp)) != 0)
1267996c772fSJohn Dyson 			allerror = error;
1268df8bae1dSRodney W. Grimes 	}
1269996c772fSJohn Dyson 	/*
1270996c772fSJohn Dyson 	 * Now write back the superblock itself. If any errors occurred
1271996c772fSJohn Dyson 	 * up to this point, then fail so that the superblock avoids
1272996c772fSJohn Dyson 	 * being written out as clean.
1273996c772fSJohn Dyson 	 */
1274996c772fSJohn Dyson 	if (allerror)
1275996c772fSJohn Dyson 		return (allerror);
1276996c772fSJohn Dyson 	bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0);
1277b1897c19SJulian Elischer 	fs->fs_fmod = 0;
1278227ee8a1SPoul-Henning Kamp 	fs->fs_time = time_second;
1279996c772fSJohn Dyson 	bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize);
1280996c772fSJohn Dyson 	/* Restore compatibility to old file systems.		   XXX */
1281996c772fSJohn Dyson 	dfs = (struct fs *)bp->b_data;				/* XXX */
1282996c772fSJohn Dyson 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
1283996c772fSJohn Dyson 		dfs->fs_nrpos = -1;				/* XXX */
1284996c772fSJohn Dyson 	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
1285996c772fSJohn Dyson 		int32_t *lp, tmp;				/* XXX */
1286996c772fSJohn Dyson 								/* XXX */
1287996c772fSJohn Dyson 		lp = (int32_t *)&dfs->fs_qbmask;		/* XXX */
1288996c772fSJohn Dyson 		tmp = lp[4];					/* XXX */
1289996c772fSJohn Dyson 		for (i = 4; i > 0; i--)				/* XXX */
1290996c772fSJohn Dyson 			lp[i] = lp[i-1];			/* XXX */
1291996c772fSJohn Dyson 		lp[0] = tmp;					/* XXX */
1292996c772fSJohn Dyson 	}							/* XXX */
1293996c772fSJohn Dyson 	dfs->fs_maxfilesize = mp->um_savedmaxfilesize;		/* XXX */
1294996c772fSJohn Dyson 	if (waitfor != MNT_WAIT)
1295996c772fSJohn Dyson 		bawrite(bp);
12968aef1712SMatthew Dillon 	else if ((error = bwrite(bp)) != 0)
1297996c772fSJohn Dyson 		allerror = error;
1298996c772fSJohn Dyson 	return (allerror);
1299df8bae1dSRodney W. Grimes }
1300