xref: /freebsd/sys/ufs/ffs/ffs_vfsops.c (revision 9bf1a756976b17430a9a0c6f58052edb24d1cf9d)
1df8bae1dSRodney W. Grimes /*
2df8bae1dSRodney W. Grimes  * Copyright (c) 1989, 1991, 1993, 1994
3df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
4df8bae1dSRodney W. Grimes  *
5df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
6df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
7df8bae1dSRodney W. Grimes  * are met:
8df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
9df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
10df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
11df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
12df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
13df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
14df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
15df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
16df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
17df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
18df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
19df8bae1dSRodney W. Grimes  *    without specific prior written permission.
20df8bae1dSRodney W. Grimes  *
21df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
32df8bae1dSRodney W. Grimes  *
33996c772fSJohn Dyson  *	@(#)ffs_vfsops.c	8.31 (Berkeley) 5/20/95
34c3aac50fSPeter Wemm  * $FreeBSD$
35df8bae1dSRodney W. Grimes  */
36df8bae1dSRodney W. Grimes 
3701733a9bSGarrett Wollman #include "opt_quota.h"
38516081f2SRobert Watson #include "opt_ufs.h"
3901733a9bSGarrett Wollman 
40df8bae1dSRodney W. Grimes #include <sys/param.h>
41df8bae1dSRodney W. Grimes #include <sys/systm.h>
421c85e6a3SKirk McKusick #include <sys/stdint.h>
43df8bae1dSRodney W. Grimes #include <sys/namei.h>
44df8bae1dSRodney W. Grimes #include <sys/proc.h>
45df8bae1dSRodney W. Grimes #include <sys/kernel.h>
46df8bae1dSRodney W. Grimes #include <sys/vnode.h>
47df8bae1dSRodney W. Grimes #include <sys/mount.h>
489626b608SPoul-Henning Kamp #include <sys/bio.h>
49df8bae1dSRodney W. Grimes #include <sys/buf.h>
5081bca6ddSKATO Takenori #include <sys/conf.h>
513ac4d1efSBruce Evans #include <sys/fcntl.h>
522dd527b3SPoul-Henning Kamp #include <sys/disk.h>
53df8bae1dSRodney W. Grimes #include <sys/malloc.h>
541b367556SJason Evans #include <sys/mutex.h>
55a18b1f1dSJason Evans 
56a64ed089SRobert Watson #include <ufs/ufs/extattr.h>
57df8bae1dSRodney W. Grimes #include <ufs/ufs/quota.h>
58df8bae1dSRodney W. Grimes #include <ufs/ufs/ufsmount.h>
59df8bae1dSRodney W. Grimes #include <ufs/ufs/inode.h>
60df8bae1dSRodney W. Grimes #include <ufs/ufs/ufs_extern.h>
61df8bae1dSRodney W. Grimes 
62df8bae1dSRodney W. Grimes #include <ufs/ffs/fs.h>
63df8bae1dSRodney W. Grimes #include <ufs/ffs/ffs_extern.h>
64df8bae1dSRodney W. Grimes 
65f6b04d2bSDavid Greenman #include <vm/vm.h>
66f6b04d2bSDavid Greenman #include <vm/vm_page.h>
67f6b04d2bSDavid Greenman 
68a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_FFSNODE, "FFS node", "FFS vnode private part");
6955166637SPoul-Henning Kamp 
706f1e8551SAlfred Perlstein static int	ffs_sbupdate(struct ufsmount *, int);
716f1e8551SAlfred Perlstein        int	ffs_reload(struct mount *,struct ucred *,struct thread *);
721c85e6a3SKirk McKusick static void	ffs_oldfscompat_read(struct fs *, struct ufsmount *,
731c85e6a3SKirk McKusick 		    ufs2_daddr_t);
741c85e6a3SKirk McKusick static void	ffs_oldfscompat_write(struct fs *, struct ufsmount *);
759bf1a756SPoul-Henning Kamp static vfs_init_t ffs_init;
769bf1a756SPoul-Henning Kamp static vfs_uninit_t ffs_uninit;
77df8bae1dSRodney W. Grimes 
78303b270bSEivind Eklund static struct vfsops ufs_vfsops = {
79df8bae1dSRodney W. Grimes 	ffs_mount,
80df8bae1dSRodney W. Grimes 	ufs_start,
81df8bae1dSRodney W. Grimes 	ffs_unmount,
82df8bae1dSRodney W. Grimes 	ufs_root,
83df8bae1dSRodney W. Grimes 	ufs_quotactl,
84df8bae1dSRodney W. Grimes 	ffs_statfs,
85df8bae1dSRodney W. Grimes 	ffs_sync,
86df8bae1dSRodney W. Grimes 	ffs_vget,
87df8bae1dSRodney W. Grimes 	ffs_fhtovp,
88a13234bbSPoul-Henning Kamp 	vfs_stdcheckexp,
89df8bae1dSRodney W. Grimes 	ffs_vptofh,
90df8bae1dSRodney W. Grimes 	ffs_init,
915346934fSIan Dowse 	ffs_uninit,
92516081f2SRobert Watson #ifdef UFS_EXTATTR
93a64ed089SRobert Watson 	ufs_extattrctl,
94a64ed089SRobert Watson #else
9591f37dcbSRobert Watson 	vfs_stdextattrctl,
96a64ed089SRobert Watson #endif
97df8bae1dSRodney W. Grimes };
98df8bae1dSRodney W. Grimes 
998994ca3cSBruce Evans VFS_SET(ufs_vfsops, ufs, 0);
100c901836cSGarrett Wollman 
101df8bae1dSRodney W. Grimes /*
1022b14f991SJulian Elischer  * ffs_mount
103df8bae1dSRodney W. Grimes  *
1042b14f991SJulian Elischer  * Called when mounting local physical media
105df8bae1dSRodney W. Grimes  *
1062b14f991SJulian Elischer  * PARAMETERS:
1072b14f991SJulian Elischer  *		mountroot
1082b14f991SJulian Elischer  *			mp	mount point structure
1092b14f991SJulian Elischer  *			path	NULL (flag for root mount!!!)
1102b14f991SJulian Elischer  *			data	<unused>
1112b14f991SJulian Elischer  *			ndp	<unused>
1122b14f991SJulian Elischer  *			p	process (user credentials check [statfs])
1132b14f991SJulian Elischer  *
1142b14f991SJulian Elischer  *		mount
1152b14f991SJulian Elischer  *			mp	mount point structure
1162b14f991SJulian Elischer  *			path	path to mount point
1172b14f991SJulian Elischer  *			data	pointer to argument struct in user space
1182b14f991SJulian Elischer  *			ndp	mount point namei() return (used for
1192b14f991SJulian Elischer  *				credentials on reload), reused to look
1202b14f991SJulian Elischer  *				up block device.
1212b14f991SJulian Elischer  *			p	process (user credentials check)
1222b14f991SJulian Elischer  *
1232b14f991SJulian Elischer  * RETURNS:	0	Success
1242b14f991SJulian Elischer  *		!0	error number (errno.h)
1252b14f991SJulian Elischer  *
1262b14f991SJulian Elischer  * LOCK STATE:
1272b14f991SJulian Elischer  *
1282b14f991SJulian Elischer  *		ENTRY
1292b14f991SJulian Elischer  *			mount point is locked
1302b14f991SJulian Elischer  *		EXIT
1312b14f991SJulian Elischer  *			mount point is locked
1322b14f991SJulian Elischer  *
1332b14f991SJulian Elischer  * NOTES:
1342b14f991SJulian Elischer  *		A NULL path can be used for a flag since the mount
1352b14f991SJulian Elischer  *		system call will fail with EFAULT in copyinstr in
1362b14f991SJulian Elischer  *		namei() if it is a genuine NULL from the user.
137df8bae1dSRodney W. Grimes  */
1380b0c10b4SAdrian Chadd int
139b40ce416SJulian Elischer ffs_mount(mp, path, data, ndp, td)
140996c772fSJohn Dyson         struct mount		*mp;	/* mount struct pointer*/
1412b14f991SJulian Elischer         char			*path;	/* path to mount point*/
1422b14f991SJulian Elischer         caddr_t			data;	/* arguments to FS specific mount*/
1432b14f991SJulian Elischer         struct nameidata	*ndp;	/* mount point credentials*/
144b40ce416SJulian Elischer         struct thread		*td;	/* process requesting mount*/
145df8bae1dSRodney W. Grimes {
1468435e0aeSDoug Rabson 	size_t size;
147df8bae1dSRodney W. Grimes 	struct vnode *devvp;
148df8bae1dSRodney W. Grimes 	struct ufs_args args;
14926f9a767SRodney W. Grimes 	struct ufsmount *ump = 0;
15005f4ff5dSPoul-Henning Kamp 	struct fs *fs;
151f2a2857bSKirk McKusick 	int error, flags;
152c9b99213SBruce Evans 	mode_t accessmode;
153df8bae1dSRodney W. Grimes 
1542b14f991SJulian Elischer 	/*
155f2a2857bSKirk McKusick 	 * Use NULL path to indicate we are mounting the root filesystem.
1562b14f991SJulian Elischer 	 */
1572b14f991SJulian Elischer 	if (path == NULL) {
158f2a2857bSKirk McKusick 		if ((error = bdevvp(rootdev, &rootvp))) {
1596d147828SMike Smith 			printf("ffs_mountroot: can't find rootvp\n");
160f2a2857bSKirk McKusick 			return (error);
161996c772fSJohn Dyson 		}
1622b14f991SJulian Elischer 
163b40ce416SJulian Elischer 		if ((error = ffs_mountfs(rootvp, mp, td, M_FFSNODE)) != 0)
164f2a2857bSKirk McKusick 			return (error);
165b40ce416SJulian Elischer 		(void)VFS_STATFS(mp, &mp->mnt_stat, td);
166f2a2857bSKirk McKusick 		return (0);
1672b14f991SJulian Elischer 	}
1682b14f991SJulian Elischer 
1692b14f991SJulian Elischer 	/*
1702b14f991SJulian Elischer 	 * Mounting non-root filesystem or updating a filesystem
1712b14f991SJulian Elischer 	 */
172f2a2857bSKirk McKusick 	if ((error = copyin(data, (caddr_t)&args, sizeof(struct ufs_args)))!= 0)
173f2a2857bSKirk McKusick 		return (error);
1742b14f991SJulian Elischer 
175df8bae1dSRodney W. Grimes 	/*
176df8bae1dSRodney W. Grimes 	 * If updating, check whether changing from read-only to
177df8bae1dSRodney W. Grimes 	 * read/write; if there is no device name, that's all we do.
178df8bae1dSRodney W. Grimes 	 */
179df8bae1dSRodney W. Grimes 	if (mp->mnt_flag & MNT_UPDATE) {
180df8bae1dSRodney W. Grimes 		ump = VFSTOUFS(mp);
181df8bae1dSRodney W. Grimes 		fs = ump->um_fs;
18226cf9c3bSPeter Wemm 		devvp = ump->um_devvp;
183f2a2857bSKirk McKusick 		if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
184f2a2857bSKirk McKusick 			if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0)
185f2a2857bSKirk McKusick 				return (error);
186cd600596SKirk McKusick 			/*
187cd600596SKirk McKusick 			 * Flush any dirty data.
188cd600596SKirk McKusick 			 */
189cd600596SKirk McKusick 			VFS_SYNC(mp, MNT_WAIT, td->td_proc->p_ucred, td);
190cd600596SKirk McKusick 			/*
191cd600596SKirk McKusick 			 * Check for and optionally get rid of files open
192cd600596SKirk McKusick 			 * for writing.
193cd600596SKirk McKusick 			 */
194df8bae1dSRodney W. Grimes 			flags = WRITECLOSE;
195df8bae1dSRodney W. Grimes 			if (mp->mnt_flag & MNT_FORCE)
196df8bae1dSRodney W. Grimes 				flags |= FORCECLOSE;
197b1897c19SJulian Elischer 			if (mp->mnt_flag & MNT_SOFTDEP) {
198b40ce416SJulian Elischer 				error = softdep_flushfiles(mp, flags, td);
199b1897c19SJulian Elischer 			} else {
200b40ce416SJulian Elischer 				error = ffs_flushfiles(mp, flags, td);
201df8bae1dSRodney W. Grimes 			}
202f2a2857bSKirk McKusick 			if (error) {
203f2a2857bSKirk McKusick 				vn_finished_write(mp);
204f2a2857bSKirk McKusick 				return (error);
205b1897c19SJulian Elischer 			}
2069ccb939eSKirk McKusick 			if (fs->fs_pendingblocks != 0 ||
2079ccb939eSKirk McKusick 			    fs->fs_pendinginodes != 0) {
208cfbf0a46SMaxime Henrion 				printf("%s: %s: blocks %jd files %d\n",
2091c85e6a3SKirk McKusick 				    fs->fs_fsmnt, "update error",
2101c85e6a3SKirk McKusick 				    (intmax_t)fs->fs_pendingblocks,
2119ccb939eSKirk McKusick 				    fs->fs_pendinginodes);
2129ccb939eSKirk McKusick 				fs->fs_pendingblocks = 0;
2139ccb939eSKirk McKusick 				fs->fs_pendinginodes = 0;
2149ccb939eSKirk McKusick 			}
215f2a2857bSKirk McKusick 			fs->fs_ronly = 1;
2161a6a6610SKirk McKusick 			if ((fs->fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) == 0)
217f2a2857bSKirk McKusick 				fs->fs_clean = 1;
218f2a2857bSKirk McKusick 			if ((error = ffs_sbupdate(ump, MNT_WAIT)) != 0) {
219f2a2857bSKirk McKusick 				fs->fs_ronly = 0;
220f2a2857bSKirk McKusick 				fs->fs_clean = 0;
221f2a2857bSKirk McKusick 				vn_finished_write(mp);
222f2a2857bSKirk McKusick 				return (error);
2232b14f991SJulian Elischer 			}
224f2a2857bSKirk McKusick 			vn_finished_write(mp);
225f2a2857bSKirk McKusick 		}
226f2a2857bSKirk McKusick 		if ((mp->mnt_flag & MNT_RELOAD) &&
227b40ce416SJulian Elischer 		    (error = ffs_reload(mp, ndp->ni_cnd.cn_cred, td)) != 0)
228f2a2857bSKirk McKusick 			return (error);
229f2a2857bSKirk McKusick 		if (fs->fs_ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) {
230c9b99213SBruce Evans 			/*
231c9b99213SBruce Evans 			 * If upgrade to read-write by non-root, then verify
232c9b99213SBruce Evans 			 * that user has necessary permissions on the device.
233c9b99213SBruce Evans 			 */
23444731cabSJohn Baldwin 			if (suser(td)) {
235b40ce416SJulian Elischer 				vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
2368aef1712SMatthew Dillon 				if ((error = VOP_ACCESS(devvp, VREAD | VWRITE,
237a854ed98SJohn Baldwin 				    td->td_ucred, td)) != 0) {
238b40ce416SJulian Elischer 					VOP_UNLOCK(devvp, 0, td);
239c9b99213SBruce Evans 					return (error);
240c9b99213SBruce Evans 				}
241b40ce416SJulian Elischer 				VOP_UNLOCK(devvp, 0, td);
242c9b99213SBruce Evans 			}
2437e58bfacSBruce Evans 			fs->fs_flags &= ~FS_UNCLEAN;
2440922cce6SBruce Evans 			if (fs->fs_clean == 0) {
2457e58bfacSBruce Evans 				fs->fs_flags |= FS_UNCLEAN;
246812b1d41SKirk McKusick 				if ((mp->mnt_flag & MNT_FORCE) ||
2471a6a6610SKirk McKusick 				    ((fs->fs_flags & FS_NEEDSFSCK) == 0 &&
2481a6a6610SKirk McKusick 				     (fs->fs_flags & FS_DOSOFTDEP))) {
249f2a2857bSKirk McKusick 					printf("WARNING: %s was not %s\n",
250f2a2857bSKirk McKusick 					   fs->fs_fsmnt, "properly dismounted");
2510922cce6SBruce Evans 				} else {
2520922cce6SBruce Evans 					printf(
2530922cce6SBruce Evans "WARNING: R/W mount of %s denied.  Filesystem is not clean - run fsck\n",
2540922cce6SBruce Evans 					    fs->fs_fsmnt);
255f2a2857bSKirk McKusick 					return (EPERM);
2560922cce6SBruce Evans 				}
2570922cce6SBruce Evans 			}
258f2a2857bSKirk McKusick 			if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0)
259f2a2857bSKirk McKusick 				return (error);
260f2a2857bSKirk McKusick 			fs->fs_ronly = 0;
261f2a2857bSKirk McKusick 			fs->fs_clean = 0;
262f2a2857bSKirk McKusick 			if ((error = ffs_sbupdate(ump, MNT_WAIT)) != 0) {
263f2a2857bSKirk McKusick 				vn_finished_write(mp);
264f2a2857bSKirk McKusick 				return (error);
265f2a2857bSKirk McKusick 			}
26626cf9c3bSPeter Wemm 			/* check to see if we need to start softdep */
267f2a2857bSKirk McKusick 			if ((fs->fs_flags & FS_DOSOFTDEP) &&
268a854ed98SJohn Baldwin 			    (error = softdep_mount(devvp, mp, fs, td->td_ucred))){
269f2a2857bSKirk McKusick 				vn_finished_write(mp);
270f2a2857bSKirk McKusick 				return (error);
27126cf9c3bSPeter Wemm 			}
272f2a2857bSKirk McKusick 			if (fs->fs_snapinum[0] != 0)
273f2a2857bSKirk McKusick 				ffs_snapshot_mount(mp);
274f2a2857bSKirk McKusick 			vn_finished_write(mp);
2751469eec8SDavid Greenman 		}
276c11d2981SJulian Elischer 		/*
277c11d2981SJulian Elischer 		 * Soft updates is incompatible with "async",
278c11d2981SJulian Elischer 		 * so if we are doing softupdates stop the user
279c11d2981SJulian Elischer 		 * from setting the async flag in an update.
280c11d2981SJulian Elischer 		 * Softdep_mount() clears it in an initial mount
281c11d2981SJulian Elischer 		 * or ro->rw remount.
282c11d2981SJulian Elischer 		 */
283f2a2857bSKirk McKusick 		if (mp->mnt_flag & MNT_SOFTDEP)
284c11d2981SJulian Elischer 			mp->mnt_flag &= ~MNT_ASYNC;
285df8bae1dSRodney W. Grimes 		/*
286f2a2857bSKirk McKusick 		 * If not updating name, process export requests.
287df8bae1dSRodney W. Grimes 		 */
288f2a2857bSKirk McKusick 		if (args.fspec == 0)
289a13234bbSPoul-Henning Kamp 			return (vfs_export(mp, &args.export));
290f2a2857bSKirk McKusick 		/*
291f2a2857bSKirk McKusick 		 * If this is a snapshot request, take the snapshot.
292f2a2857bSKirk McKusick 		 */
293f2a2857bSKirk McKusick 		if (mp->mnt_flag & MNT_SNAPSHOT)
294f2a2857bSKirk McKusick 			return (ffs_snapshot(mp, args.fspec));
295df8bae1dSRodney W. Grimes 	}
2962b14f991SJulian Elischer 
297df8bae1dSRodney W. Grimes 	/*
298df8bae1dSRodney W. Grimes 	 * Not an update, or updating the name: look up the name
299df8bae1dSRodney W. Grimes 	 * and verify that it refers to a sensible block device.
300df8bae1dSRodney W. Grimes 	 */
301b40ce416SJulian Elischer 	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, td);
302f2a2857bSKirk McKusick 	if ((error = namei(ndp)) != 0)
303f2a2857bSKirk McKusick 		return (error);
304762e6b85SEivind Eklund 	NDFREE(ndp, NDF_ONLY_PNBUF);
305df8bae1dSRodney W. Grimes 	devvp = ndp->ni_vp;
306f2a2857bSKirk McKusick 	if (!vn_isdisk(devvp, &error)) {
307f2a2857bSKirk McKusick 		vrele(devvp);
308f2a2857bSKirk McKusick 		return (error);
309f2a2857bSKirk McKusick 	}
310c9b99213SBruce Evans 
311c9b99213SBruce Evans 	/*
312c9b99213SBruce Evans 	 * If mount by non-root, then verify that user has necessary
313c9b99213SBruce Evans 	 * permissions on the device.
314c9b99213SBruce Evans 	 */
31544731cabSJohn Baldwin 	if (suser(td)) {
316c9b99213SBruce Evans 		accessmode = VREAD;
317c9b99213SBruce Evans 		if ((mp->mnt_flag & MNT_RDONLY) == 0)
318c9b99213SBruce Evans 			accessmode |= VWRITE;
319b40ce416SJulian Elischer 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
320a854ed98SJohn Baldwin 		if ((error = VOP_ACCESS(devvp, accessmode, td->td_ucred, td))!= 0){
321c9b99213SBruce Evans 			vput(devvp);
322c9b99213SBruce Evans 			return (error);
323c9b99213SBruce Evans 		}
324b40ce416SJulian Elischer 		VOP_UNLOCK(devvp, 0, td);
325c9b99213SBruce Evans 	}
326c9b99213SBruce Evans 
3272b14f991SJulian Elischer 	if (mp->mnt_flag & MNT_UPDATE) {
3282b14f991SJulian Elischer 		/*
329f2a2857bSKirk McKusick 		 * Update only
330f2a2857bSKirk McKusick 		 *
3313e425b96SJulian Elischer 		 * If it's not the same vnode, or at least the same device
3323e425b96SJulian Elischer 		 * then it's not correct.
3332b14f991SJulian Elischer 		 */
3342b14f991SJulian Elischer 
335f2a2857bSKirk McKusick 		if (devvp != ump->um_devvp &&
336f2a2857bSKirk McKusick 		    devvp->v_rdev != ump->um_devvp->v_rdev)
337f2a2857bSKirk McKusick 			error = EINVAL;	/* needs translation */
3383e425b96SJulian Elischer 		vrele(devvp);
339f2a2857bSKirk McKusick 		if (error)
340f2a2857bSKirk McKusick 			return (error);
3412b14f991SJulian Elischer 	} else {
3422b14f991SJulian Elischer 		/*
343f2a2857bSKirk McKusick 		 * New mount
3442b14f991SJulian Elischer 		 *
345f2a2857bSKirk McKusick 		 * We need the name for the mount point (also used for
346f2a2857bSKirk McKusick 		 * "last mounted on") copied in. If an error occurs,
347f2a2857bSKirk McKusick 		 * the mount point is discarded by the upper level code.
348f3a90da9SAdrian Chadd 		 * Note that vfs_mount() populates f_mntonname for us.
349f2a2857bSKirk McKusick 		 */
350b40ce416SJulian Elischer 		if ((error = ffs_mountfs(devvp, mp, td, M_FFSNODE)) != 0) {
351f2a2857bSKirk McKusick 			vrele(devvp);
352f2a2857bSKirk McKusick 			return (error);
353f2a2857bSKirk McKusick 		}
354f2a2857bSKirk McKusick 	}
355f2a2857bSKirk McKusick 	/*
356f2a2857bSKirk McKusick 	 * Save "mounted from" device name info for mount point (NULL pad).
357f2a2857bSKirk McKusick 	 */
358f2a2857bSKirk McKusick 	copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
359f2a2857bSKirk McKusick 	bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
360f2a2857bSKirk McKusick 	/*
361f2a2857bSKirk McKusick 	 * Initialize filesystem stat information in mount struct.
3622b14f991SJulian Elischer 	 */
363b40ce416SJulian Elischer 	(void)VFS_STATFS(mp, &mp->mnt_stat, td);
364f2a2857bSKirk McKusick 	return (0);
3652b14f991SJulian Elischer }
3662b14f991SJulian Elischer 
367df8bae1dSRodney W. Grimes /*
368df8bae1dSRodney W. Grimes  * Reload all incore data for a filesystem (used after running fsck on
369df8bae1dSRodney W. Grimes  * the root filesystem and finding things to fix). The filesystem must
370df8bae1dSRodney W. Grimes  * be mounted read-only.
371df8bae1dSRodney W. Grimes  *
372df8bae1dSRodney W. Grimes  * Things to do to update the mount:
373df8bae1dSRodney W. Grimes  *	1) invalidate all cached meta-data.
374df8bae1dSRodney W. Grimes  *	2) re-read superblock from disk.
375df8bae1dSRodney W. Grimes  *	3) re-read summary information from disk.
376df8bae1dSRodney W. Grimes  *	4) invalidate all inactive vnodes.
377df8bae1dSRodney W. Grimes  *	5) invalidate all cached file data.
378df8bae1dSRodney W. Grimes  *	6) re-read inode data for all active vnodes.
379df8bae1dSRodney W. Grimes  */
3800b0c10b4SAdrian Chadd int
381b40ce416SJulian Elischer ffs_reload(mp, cred, td)
38205f4ff5dSPoul-Henning Kamp 	struct mount *mp;
383df8bae1dSRodney W. Grimes 	struct ucred *cred;
384b40ce416SJulian Elischer 	struct thread *td;
385df8bae1dSRodney W. Grimes {
38605f4ff5dSPoul-Henning Kamp 	struct vnode *vp, *nvp, *devvp;
387df8bae1dSRodney W. Grimes 	struct inode *ip;
388f55ff3f3SIan Dowse 	void *space;
389df8bae1dSRodney W. Grimes 	struct buf *bp;
390996c772fSJohn Dyson 	struct fs *fs, *newfs;
39195e5e988SJohn Dyson 	dev_t dev;
3921c85e6a3SKirk McKusick 	ufs2_daddr_t sblockloc;
393df8bae1dSRodney W. Grimes 	int i, blks, size, error;
394996c772fSJohn Dyson 	int32_t *lp;
395df8bae1dSRodney W. Grimes 
3962b14f991SJulian Elischer 	if ((mp->mnt_flag & MNT_RDONLY) == 0)
397df8bae1dSRodney W. Grimes 		return (EINVAL);
398df8bae1dSRodney W. Grimes 	/*
399df8bae1dSRodney W. Grimes 	 * Step 1: invalidate all cached meta-data.
400df8bae1dSRodney W. Grimes 	 */
4012b14f991SJulian Elischer 	devvp = VFSTOUFS(mp)->um_devvp;
402b40ce416SJulian Elischer 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
403b40ce416SJulian Elischer 	error = vinvalbuf(devvp, 0, cred, td, 0, 0);
404b40ce416SJulian Elischer 	VOP_UNLOCK(devvp, 0, td);
405b1897c19SJulian Elischer 	if (error)
406df8bae1dSRodney W. Grimes 		panic("ffs_reload: dirty1");
40795e5e988SJohn Dyson 
40895e5e988SJohn Dyson 	dev = devvp->v_rdev;
409b5ee1640SBruce Evans 
41095e5e988SJohn Dyson 	/*
41195e5e988SJohn Dyson 	 * Only VMIO the backing device if the backing device is a real
412c7a3e237SPoul-Henning Kamp 	 * block device.
41395e5e988SJohn Dyson 	 */
414c7a3e237SPoul-Henning Kamp 	if (vn_isdisk(devvp, NULL)) {
415b40ce416SJulian Elischer 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
416a854ed98SJohn Baldwin 		vfs_object_create(devvp, td, td->td_ucred);
4179ed346baSBosko Milekic 		mtx_lock(&devvp->v_interlock);
418b40ce416SJulian Elischer 		VOP_UNLOCK(devvp, LK_INTERLOCK, td);
41995e5e988SJohn Dyson 	}
42095e5e988SJohn Dyson 
421df8bae1dSRodney W. Grimes 	/*
422df8bae1dSRodney W. Grimes 	 * Step 2: re-read superblock from disk.
423df8bae1dSRodney W. Grimes 	 */
4241c85e6a3SKirk McKusick 	fs = VFSTOUFS(mp)->um_fs;
4251c85e6a3SKirk McKusick 	if ((error = bread(devvp, fsbtodb(fs, fs->fs_sblockloc), fs->fs_sbsize,
4261c85e6a3SKirk McKusick 	    NOCRED, &bp)) != 0)
427df8bae1dSRodney W. Grimes 		return (error);
428996c772fSJohn Dyson 	newfs = (struct fs *)bp->b_data;
4291c85e6a3SKirk McKusick 	if ((newfs->fs_magic != FS_UFS1_MAGIC &&
4301c85e6a3SKirk McKusick 	     newfs->fs_magic != FS_UFS2_MAGIC) ||
4311c85e6a3SKirk McKusick 	    newfs->fs_bsize > MAXBSIZE ||
432996c772fSJohn Dyson 	    newfs->fs_bsize < sizeof(struct fs)) {
433df8bae1dSRodney W. Grimes 			brelse(bp);
434df8bae1dSRodney W. Grimes 			return (EIO);		/* XXX needs translation */
435df8bae1dSRodney W. Grimes 	}
436996c772fSJohn Dyson 	/*
437996c772fSJohn Dyson 	 * Copy pointer fields back into superblock before copying in	XXX
438996c772fSJohn Dyson 	 * new superblock. These should really be in the ufsmount.	XXX
439996c772fSJohn Dyson 	 * Note that important parameters (eg fs_ncg) are unchanged.
440996c772fSJohn Dyson 	 */
441f55ff3f3SIan Dowse 	newfs->fs_csp = fs->fs_csp;
442996c772fSJohn Dyson 	newfs->fs_maxcluster = fs->fs_maxcluster;
4435d69bac4SIan Dowse 	newfs->fs_contigdirs = fs->fs_contigdirs;
444143a5346SIan Dowse 	newfs->fs_active = fs->fs_active;
4451c85e6a3SKirk McKusick 	sblockloc = fs->fs_sblockloc;
446996c772fSJohn Dyson 	bcopy(newfs, fs, (u_int)fs->fs_sbsize);
447df8bae1dSRodney W. Grimes 	brelse(bp);
448996c772fSJohn Dyson 	mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
4491c85e6a3SKirk McKusick 	ffs_oldfscompat_read(fs, VFSTOUFS(mp), sblockloc);
4509ccb939eSKirk McKusick 	if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
451cfbf0a46SMaxime Henrion 		printf("%s: reload pending error: blocks %jd files %d\n",
4521c85e6a3SKirk McKusick 		    fs->fs_fsmnt, (intmax_t)fs->fs_pendingblocks,
4531c85e6a3SKirk McKusick 		    fs->fs_pendinginodes);
4549ccb939eSKirk McKusick 		fs->fs_pendingblocks = 0;
4559ccb939eSKirk McKusick 		fs->fs_pendinginodes = 0;
4569ccb939eSKirk McKusick 	}
457996c772fSJohn Dyson 
458df8bae1dSRodney W. Grimes 	/*
459df8bae1dSRodney W. Grimes 	 * Step 3: re-read summary information from disk.
460df8bae1dSRodney W. Grimes 	 */
461df8bae1dSRodney W. Grimes 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
462f55ff3f3SIan Dowse 	space = fs->fs_csp;
463df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
464df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
465df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
466df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
467c9671602SPoul-Henning Kamp 		error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
468c9671602SPoul-Henning Kamp 		    NOCRED, &bp);
469c9671602SPoul-Henning Kamp 		if (error)
470df8bae1dSRodney W. Grimes 			return (error);
471f55ff3f3SIan Dowse 		bcopy(bp->b_data, space, (u_int)size);
472f55ff3f3SIan Dowse 		space = (char *)space + size;
473df8bae1dSRodney W. Grimes 		brelse(bp);
474df8bae1dSRodney W. Grimes 	}
475996c772fSJohn Dyson 	/*
476996c772fSJohn Dyson 	 * We no longer know anything about clusters per cylinder group.
477996c772fSJohn Dyson 	 */
478996c772fSJohn Dyson 	if (fs->fs_contigsumsize > 0) {
479996c772fSJohn Dyson 		lp = fs->fs_maxcluster;
480996c772fSJohn Dyson 		for (i = 0; i < fs->fs_ncg; i++)
481996c772fSJohn Dyson 			*lp++ = fs->fs_contigsumsize;
482996c772fSJohn Dyson 	}
483996c772fSJohn Dyson 
484df8bae1dSRodney W. Grimes loop:
4859ed346baSBosko Milekic 	mtx_lock(&mntvnode_mtx);
486c72ccd01SMatthew Dillon 	for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist); vp != NULL; vp = nvp) {
487996c772fSJohn Dyson 		if (vp->v_mount != mp) {
4889ed346baSBosko Milekic 			mtx_unlock(&mntvnode_mtx);
489996c772fSJohn Dyson 			goto loop;
490996c772fSJohn Dyson 		}
491c72ccd01SMatthew Dillon 		nvp = TAILQ_NEXT(vp, v_nmntvnodes);
492ed87274dSJohn Baldwin 		mtx_unlock(&mntvnode_mtx);
493df8bae1dSRodney W. Grimes 		/*
494df8bae1dSRodney W. Grimes 		 * Step 4: invalidate all inactive vnodes.
495df8bae1dSRodney W. Grimes 		 */
496b40ce416SJulian Elischer 		if (vrecycle(vp, NULL, td))
497996c772fSJohn Dyson 			goto loop;
498df8bae1dSRodney W. Grimes 		/*
499df8bae1dSRodney W. Grimes 		 * Step 5: invalidate all cached file data.
500df8bae1dSRodney W. Grimes 		 */
50149d2d9f4SJohn Baldwin 		mtx_lock(&vp->v_interlock);
502b40ce416SJulian Elischer 		if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) {
503df8bae1dSRodney W. Grimes 			goto loop;
504996c772fSJohn Dyson 		}
505b40ce416SJulian Elischer 		if (vinvalbuf(vp, 0, cred, td, 0, 0))
506df8bae1dSRodney W. Grimes 			panic("ffs_reload: dirty2");
507df8bae1dSRodney W. Grimes 		/*
508df8bae1dSRodney W. Grimes 		 * Step 6: re-read inode data for all active vnodes.
509df8bae1dSRodney W. Grimes 		 */
510df8bae1dSRodney W. Grimes 		ip = VTOI(vp);
511c9671602SPoul-Henning Kamp 		error =
512df8bae1dSRodney W. Grimes 		    bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
513c9671602SPoul-Henning Kamp 		    (int)fs->fs_bsize, NOCRED, &bp);
514c9671602SPoul-Henning Kamp 		if (error) {
515df8bae1dSRodney W. Grimes 			vput(vp);
516df8bae1dSRodney W. Grimes 			return (error);
517df8bae1dSRodney W. Grimes 		}
5181c85e6a3SKirk McKusick 		ffs_load_inode(bp, ip, NULL, fs, ip->i_number);
519b1897c19SJulian Elischer 		ip->i_effnlink = ip->i_nlink;
520df8bae1dSRodney W. Grimes 		brelse(bp);
521df8bae1dSRodney W. Grimes 		vput(vp);
5229ed346baSBosko Milekic 		mtx_lock(&mntvnode_mtx);
523df8bae1dSRodney W. Grimes 	}
5249ed346baSBosko Milekic 	mtx_unlock(&mntvnode_mtx);
525df8bae1dSRodney W. Grimes 	return (0);
526df8bae1dSRodney W. Grimes }
527df8bae1dSRodney W. Grimes 
5281c85e6a3SKirk McKusick /*
5291c85e6a3SKirk McKusick  * Possible superblock locations ordered from most to least likely.
5301c85e6a3SKirk McKusick  */
5311c85e6a3SKirk McKusick static int sblock_try[] = SBLOCKSEARCH;
5325819ab3fSKirk McKusick 
533df8bae1dSRodney W. Grimes /*
534df8bae1dSRodney W. Grimes  * Common code for mount and mountroot
535df8bae1dSRodney W. Grimes  */
536df8bae1dSRodney W. Grimes int
537b40ce416SJulian Elischer ffs_mountfs(devvp, mp, td, malloctype)
53805f4ff5dSPoul-Henning Kamp 	struct vnode *devvp;
539df8bae1dSRodney W. Grimes 	struct mount *mp;
540b40ce416SJulian Elischer 	struct thread *td;
5410be6b890SPoul-Henning Kamp 	struct malloc_type *malloctype;
542df8bae1dSRodney W. Grimes {
54305f4ff5dSPoul-Henning Kamp 	struct ufsmount *ump;
544df8bae1dSRodney W. Grimes 	struct buf *bp;
54505f4ff5dSPoul-Henning Kamp 	struct fs *fs;
546996c772fSJohn Dyson 	dev_t dev;
547f55ff3f3SIan Dowse 	void *space;
5481c85e6a3SKirk McKusick 	ufs2_daddr_t sblockloc;
549f5ef029eSPoul-Henning Kamp 	int error, i, blks, size, ronly;
550996c772fSJohn Dyson 	int32_t *lp;
551996c772fSJohn Dyson 	struct ucred *cred;
5528435e0aeSDoug Rabson 	size_t strsize;
5536476c0d2SJohn Dyson 	int ncount;
55446a67eacSPoul-Henning Kamp 	u_int sectorsize;
555df8bae1dSRodney W. Grimes 
556996c772fSJohn Dyson 	dev = devvp->v_rdev;
557a854ed98SJohn Baldwin 	cred = td ? td->td_ucred : NOCRED;
558df8bae1dSRodney W. Grimes 	/*
559df8bae1dSRodney W. Grimes 	 * Disallow multiple mounts of the same device.
560df8bae1dSRodney W. Grimes 	 * Disallow mounting of a device that is currently in use
561df8bae1dSRodney W. Grimes 	 * (except for root, which might share swap device for miniroot).
562df8bae1dSRodney W. Grimes 	 * Flush out any old buffers remaining from a previous use.
563df8bae1dSRodney W. Grimes 	 */
564c9671602SPoul-Henning Kamp 	error = vfs_mountedon(devvp);
565c9671602SPoul-Henning Kamp 	if (error)
566df8bae1dSRodney W. Grimes 		return (error);
5676476c0d2SJohn Dyson 	ncount = vcount(devvp);
5688f9110f6SJohn Dyson 
5696476c0d2SJohn Dyson 	if (ncount > 1 && devvp != rootvp)
570df8bae1dSRodney W. Grimes 		return (EBUSY);
571b40ce416SJulian Elischer 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
572b40ce416SJulian Elischer 	error = vinvalbuf(devvp, V_SAVE, cred, td, 0, 0);
573b40ce416SJulian Elischer 	VOP_UNLOCK(devvp, 0, td);
574b1897c19SJulian Elischer 	if (error)
575df8bae1dSRodney W. Grimes 		return (error);
576df8bae1dSRodney W. Grimes 
57795e5e988SJohn Dyson 	/*
57895e5e988SJohn Dyson 	 * Only VMIO the backing device if the backing device is a real
579c7a3e237SPoul-Henning Kamp 	 * block device.
58095e5e988SJohn Dyson 	 * Note that it is optional that the backing device be VMIOed.  This
58195e5e988SJohn Dyson 	 * increases the opportunity for metadata caching.
58295e5e988SJohn Dyson 	 */
583c7a3e237SPoul-Henning Kamp 	if (vn_isdisk(devvp, NULL)) {
584b40ce416SJulian Elischer 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
585b40ce416SJulian Elischer 		vfs_object_create(devvp, td, cred);
5869ed346baSBosko Milekic 		mtx_lock(&devvp->v_interlock);
587b40ce416SJulian Elischer 		VOP_UNLOCK(devvp, LK_INTERLOCK, td);
58895e5e988SJohn Dyson 	}
58995e5e988SJohn Dyson 
590df8bae1dSRodney W. Grimes 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
591b40ce416SJulian Elischer 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
5923dbceccbSPoul-Henning Kamp 	/*
5933dbceccbSPoul-Henning Kamp 	 * XXX: We don't re-VOP_OPEN in FREAD|FWRITE mode if the filesystem
5943dbceccbSPoul-Henning Kamp 	 * XXX: is subsequently remounted, so open it FREAD|FWRITE from the
5953dbceccbSPoul-Henning Kamp 	 * XXX: start to avoid getting trashed later on.
5963dbceccbSPoul-Henning Kamp 	 */
5973dbceccbSPoul-Henning Kamp #ifdef notyet
598b40ce416SJulian Elischer 	error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, td);
5993dbceccbSPoul-Henning Kamp #else
6003dbceccbSPoul-Henning Kamp 	error = VOP_OPEN(devvp, FREAD|FWRITE, FSCRED, td);
6013dbceccbSPoul-Henning Kamp #endif
602b40ce416SJulian Elischer 	VOP_UNLOCK(devvp, 0, td);
603c9671602SPoul-Henning Kamp 	if (error)
604df8bae1dSRodney W. Grimes 		return (error);
6050508986cSBruce Evans 	if (devvp->v_rdev->si_iosize_max != 0)
6061b5464efSPoul-Henning Kamp 		mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max;
6071b5464efSPoul-Henning Kamp 	if (mp->mnt_iosize_max > MAXPHYS)
6081b5464efSPoul-Henning Kamp 		mp->mnt_iosize_max = MAXPHYS;
60995e5e988SJohn Dyson 
61046a67eacSPoul-Henning Kamp 	if (VOP_IOCTL(devvp, DIOCGSECTORSIZE, (caddr_t)&sectorsize,
61146a67eacSPoul-Henning Kamp 	    FREAD, cred, td) != 0)
612df8bae1dSRodney W. Grimes 		size = DEV_BSIZE;
613996c772fSJohn Dyson 	else
61446a67eacSPoul-Henning Kamp 		size = sectorsize;
615df8bae1dSRodney W. Grimes 
616df8bae1dSRodney W. Grimes 	bp = NULL;
617df8bae1dSRodney W. Grimes 	ump = NULL;
6181c85e6a3SKirk McKusick 	fs = NULL;
6191c85e6a3SKirk McKusick 	sblockloc = 0;
6201c85e6a3SKirk McKusick 	/*
6211c85e6a3SKirk McKusick 	 * Try reading the superblock in each of its possible locations.
6221c85e6a3SKirk McKusick 	 */
6231c85e6a3SKirk McKusick 	for (i = 0; sblock_try[i] != -1; i++) {
6241c85e6a3SKirk McKusick 		if ((error = bread(devvp, sblock_try[i] / size, SBLOCKSIZE,
6251c85e6a3SKirk McKusick 		    cred, &bp)) != 0)
626df8bae1dSRodney W. Grimes 			goto out;
627df8bae1dSRodney W. Grimes 		fs = (struct fs *)bp->b_data;
6281c85e6a3SKirk McKusick 		sblockloc = numfrags(fs, sblock_try[i]);
6291c85e6a3SKirk McKusick 		if ((fs->fs_magic == FS_UFS1_MAGIC ||
6301c85e6a3SKirk McKusick 		     (fs->fs_magic == FS_UFS2_MAGIC &&
6311c85e6a3SKirk McKusick 		      fs->fs_sblockloc == sblockloc)) &&
6321c85e6a3SKirk McKusick 		    fs->fs_bsize <= MAXBSIZE &&
6331c85e6a3SKirk McKusick 		    fs->fs_bsize >= sizeof(struct fs))
6341c85e6a3SKirk McKusick 			break;
6351c85e6a3SKirk McKusick 		brelse(bp);
6361c85e6a3SKirk McKusick 		bp = NULL;
6371c85e6a3SKirk McKusick 	}
6381c85e6a3SKirk McKusick 	if (sblock_try[i] == -1) {
639df8bae1dSRodney W. Grimes 		error = EINVAL;		/* XXX needs translation */
640df8bae1dSRodney W. Grimes 		goto out;
641df8bae1dSRodney W. Grimes 	}
6423f6f17eeSJulian Elischer 	fs->fs_fmod = 0;
6431c85e6a3SKirk McKusick 	fs->fs_flags &= ~FS_INDEXDIRS;	/* no support for directory indicies */
6440922cce6SBruce Evans 	fs->fs_flags &= ~FS_UNCLEAN;
6450922cce6SBruce Evans 	if (fs->fs_clean == 0) {
6460922cce6SBruce Evans 		fs->fs_flags |= FS_UNCLEAN;
647812b1d41SKirk McKusick 		if (ronly || (mp->mnt_flag & MNT_FORCE) ||
6481a6a6610SKirk McKusick 		    ((fs->fs_flags & FS_NEEDSFSCK) == 0 &&
6491a6a6610SKirk McKusick 		     (fs->fs_flags & FS_DOSOFTDEP))) {
6500922cce6SBruce Evans 			printf(
6510922cce6SBruce Evans "WARNING: %s was not properly dismounted\n",
6520922cce6SBruce Evans 			    fs->fs_fsmnt);
6531469eec8SDavid Greenman 		} else {
6540922cce6SBruce Evans 			printf(
6550922cce6SBruce Evans "WARNING: R/W mount of %s denied.  Filesystem is not clean - run fsck\n",
6560922cce6SBruce Evans 			    fs->fs_fsmnt);
6571469eec8SDavid Greenman 			error = EPERM;
6581469eec8SDavid Greenman 			goto out;
6591469eec8SDavid Greenman 		}
6601c85e6a3SKirk McKusick 		if ((fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) &&
6611c85e6a3SKirk McKusick 		    (mp->mnt_flag & MNT_FORCE)) {
662cfbf0a46SMaxime Henrion 			printf("%s: lost blocks %jd files %d\n", fs->fs_fsmnt,
6631c85e6a3SKirk McKusick 			    (intmax_t)fs->fs_pendingblocks,
6641c85e6a3SKirk McKusick 			    fs->fs_pendinginodes);
6659ccb939eSKirk McKusick 			fs->fs_pendingblocks = 0;
6669ccb939eSKirk McKusick 			fs->fs_pendinginodes = 0;
6679ccb939eSKirk McKusick 		}
6689ccb939eSKirk McKusick 	}
6699ccb939eSKirk McKusick 	if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
670cfbf0a46SMaxime Henrion 		printf("%s: mount pending error: blocks %jd files %d\n",
6711c85e6a3SKirk McKusick 		    fs->fs_fsmnt, (intmax_t)fs->fs_pendingblocks,
6721c85e6a3SKirk McKusick 		    fs->fs_pendinginodes);
6739ccb939eSKirk McKusick 		fs->fs_pendingblocks = 0;
6749ccb939eSKirk McKusick 		fs->fs_pendinginodes = 0;
6751469eec8SDavid Greenman 	}
6767cc0979fSDavid Malone 	ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK | M_ZERO);
6770be6b890SPoul-Henning Kamp 	ump->um_malloctype = malloctype;
678df8bae1dSRodney W. Grimes 	ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT,
679df8bae1dSRodney W. Grimes 	    M_WAITOK);
6801c85e6a3SKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC) {
6811c85e6a3SKirk McKusick 		ump->um_fstype = UFS1;
6821c85e6a3SKirk McKusick 		ump->um_balloc = ffs_balloc_ufs1;
6831c85e6a3SKirk McKusick 	} else {
6841c85e6a3SKirk McKusick 		ump->um_fstype = UFS2;
6851c85e6a3SKirk McKusick 		ump->um_balloc = ffs_balloc_ufs2;
6861c85e6a3SKirk McKusick 	}
687cec0f20cSPoul-Henning Kamp 	ump->um_blkatoff = ffs_blkatoff;
688cec0f20cSPoul-Henning Kamp 	ump->um_truncate = ffs_truncate;
689987f5696SPoul-Henning Kamp 	ump->um_update = ffs_update;
690cec0f20cSPoul-Henning Kamp 	ump->um_valloc = ffs_valloc;
691cec0f20cSPoul-Henning Kamp 	ump->um_vfree = ffs_vfree;
692df8bae1dSRodney W. Grimes 	bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize);
6931c85e6a3SKirk McKusick 	if (fs->fs_sbsize < SBLOCKSIZE)
694f2a2857bSKirk McKusick 		bp->b_flags |= B_INVAL | B_NOCACHE;
695df8bae1dSRodney W. Grimes 	brelse(bp);
696df8bae1dSRodney W. Grimes 	bp = NULL;
697df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
6981c85e6a3SKirk McKusick 	ffs_oldfscompat_read(fs, ump, sblockloc);
699df8bae1dSRodney W. Grimes 	fs->fs_ronly = ronly;
700996c772fSJohn Dyson 	size = fs->fs_cssize;
701996c772fSJohn Dyson 	blks = howmany(size, fs->fs_fsize);
702996c772fSJohn Dyson 	if (fs->fs_contigsumsize > 0)
703996c772fSJohn Dyson 		size += fs->fs_ncg * sizeof(int32_t);
704a61ab64aSKirk McKusick 	size += fs->fs_ncg * sizeof(u_int8_t);
705f55ff3f3SIan Dowse 	space = malloc((u_long)size, M_UFSMNT, M_WAITOK);
706f55ff3f3SIan Dowse 	fs->fs_csp = space;
707df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
708df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
709df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
710df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
7118aef1712SMatthew Dillon 		if ((error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
7128aef1712SMatthew Dillon 		    cred, &bp)) != 0) {
713f55ff3f3SIan Dowse 			free(fs->fs_csp, M_UFSMNT);
714df8bae1dSRodney W. Grimes 			goto out;
715df8bae1dSRodney W. Grimes 		}
716df8bae1dSRodney W. Grimes 		bcopy(bp->b_data, space, (u_int)size);
717f55ff3f3SIan Dowse 		space = (char *)space + size;
718df8bae1dSRodney W. Grimes 		brelse(bp);
719df8bae1dSRodney W. Grimes 		bp = NULL;
720df8bae1dSRodney W. Grimes 	}
721996c772fSJohn Dyson 	if (fs->fs_contigsumsize > 0) {
722f55ff3f3SIan Dowse 		fs->fs_maxcluster = lp = space;
723996c772fSJohn Dyson 		for (i = 0; i < fs->fs_ncg; i++)
724996c772fSJohn Dyson 			*lp++ = fs->fs_contigsumsize;
7254691e9eaSIan Dowse 		space = lp;
726996c772fSJohn Dyson 	}
727a61ab64aSKirk McKusick 	size = fs->fs_ncg * sizeof(u_int8_t);
728a61ab64aSKirk McKusick 	fs->fs_contigdirs = (u_int8_t *)space;
729a61ab64aSKirk McKusick 	bzero(fs->fs_contigdirs, size);
730143a5346SIan Dowse 	fs->fs_active = NULL;
731df8bae1dSRodney W. Grimes 	mp->mnt_data = (qaddr_t)ump;
73268de329eSPoul-Henning Kamp 	mp->mnt_stat.f_fsid.val[0] = fs->fs_id[0];
7338f89943eSGuido van Rooij 	mp->mnt_stat.f_fsid.val[1] = fs->fs_id[1];
73468de329eSPoul-Henning Kamp 	if (fs->fs_id[0] == 0 || fs->fs_id[1] == 0 ||
73568de329eSPoul-Henning Kamp 	    vfs_getvfs(&mp->mnt_stat.f_fsid))
73668de329eSPoul-Henning Kamp 		vfs_getnewfsid(mp);
737df8bae1dSRodney W. Grimes 	mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
738cc9d8990SPeter Wemm 	mp->mnt_flag |= MNT_LOCAL;
739df8bae1dSRodney W. Grimes 	ump->um_mountp = mp;
740df8bae1dSRodney W. Grimes 	ump->um_dev = dev;
741df8bae1dSRodney W. Grimes 	ump->um_devvp = devvp;
742df8bae1dSRodney W. Grimes 	ump->um_nindir = fs->fs_nindir;
743df8bae1dSRodney W. Grimes 	ump->um_bptrtodb = fs->fs_fsbtodb;
744df8bae1dSRodney W. Grimes 	ump->um_seqinc = fs->fs_frag;
745df8bae1dSRodney W. Grimes 	for (i = 0; i < MAXQUOTAS; i++)
746df8bae1dSRodney W. Grimes 		ump->um_quotas[i] = NULLVP;
747516081f2SRobert Watson #ifdef UFS_EXTATTR
748a64ed089SRobert Watson 	ufs_extattr_uepm_init(&ump->um_extattr);
749a64ed089SRobert Watson #endif
7507eb9fca5SEivind Eklund 	devvp->v_rdev->si_mountpoint = mp;
7512b14f991SJulian Elischer 
7522b14f991SJulian Elischer 	/*
7532b14f991SJulian Elischer 	 * Set FS local "last mounted on" information (NULL pad)
7542b14f991SJulian Elischer 	 */
7552b14f991SJulian Elischer 	copystr(	mp->mnt_stat.f_mntonname,	/* mount point*/
7562b14f991SJulian Elischer 			fs->fs_fsmnt,			/* copy area*/
7572b14f991SJulian Elischer 			sizeof(fs->fs_fsmnt) - 1,	/* max size*/
7582b14f991SJulian Elischer 			&strsize);			/* real size*/
7592b14f991SJulian Elischer 	bzero( fs->fs_fsmnt + strsize, sizeof(fs->fs_fsmnt) - strsize);
7602b14f991SJulian Elischer 
7612b14f991SJulian Elischer 	if( mp->mnt_flag & MNT_ROOTFS) {
7622b14f991SJulian Elischer 		/*
7632b14f991SJulian Elischer 		 * Root mount; update timestamp in mount structure.
7642b14f991SJulian Elischer 		 * this will be used by the common root mount code
7652b14f991SJulian Elischer 		 * to update the system clock.
7662b14f991SJulian Elischer 		 */
7672b14f991SJulian Elischer 		mp->mnt_time = fs->fs_time;
7682b14f991SJulian Elischer 	}
769996c772fSJohn Dyson 
770996c772fSJohn Dyson 	if (ronly == 0) {
771b1897c19SJulian Elischer 		if ((fs->fs_flags & FS_DOSOFTDEP) &&
772b1897c19SJulian Elischer 		    (error = softdep_mount(devvp, mp, fs, cred)) != 0) {
773f55ff3f3SIan Dowse 			free(fs->fs_csp, M_UFSMNT);
774b1897c19SJulian Elischer 			goto out;
775b1897c19SJulian Elischer 		}
776f2a2857bSKirk McKusick 		if (fs->fs_snapinum[0] != 0)
777f2a2857bSKirk McKusick 			ffs_snapshot_mount(mp);
778cf60e8e4SKirk McKusick 		fs->fs_fmod = 1;
779996c772fSJohn Dyson 		fs->fs_clean = 0;
780996c772fSJohn Dyson 		(void) ffs_sbupdate(ump, MNT_WAIT);
781996c772fSJohn Dyson 	}
782516081f2SRobert Watson #ifdef UFS_EXTATTR
783516081f2SRobert Watson #ifdef UFS_EXTATTR_AUTOSTART
7849de54ba5SRobert Watson 	/*
7859de54ba5SRobert Watson 	 *
786f5161237SRobert Watson 	 * Auto-starting does the following:
7879de54ba5SRobert Watson 	 *	- check for /.attribute in the fs, and extattr_start if so
7889de54ba5SRobert Watson 	 *	- for each file in .attribute, enable that file with
7899de54ba5SRobert Watson 	 * 	  an attribute of the same name.
7909de54ba5SRobert Watson 	 * Not clear how to report errors -- probably eat them.
7919de54ba5SRobert Watson 	 * This would all happen while the filesystem was busy/not
7929de54ba5SRobert Watson 	 * available, so would effectively be "atomic".
7939de54ba5SRobert Watson 	 */
794b40ce416SJulian Elischer 	(void) ufs_extattr_autostart(mp, td);
795516081f2SRobert Watson #endif /* !UFS_EXTATTR_AUTOSTART */
796516081f2SRobert Watson #endif /* !UFS_EXTATTR */
797df8bae1dSRodney W. Grimes 	return (0);
798df8bae1dSRodney W. Grimes out:
7997eb9fca5SEivind Eklund 	devvp->v_rdev->si_mountpoint = NULL;
800df8bae1dSRodney W. Grimes 	if (bp)
801df8bae1dSRodney W. Grimes 		brelse(bp);
8023dbceccbSPoul-Henning Kamp 	/* XXX: see comment above VOP_OPEN */
8033dbceccbSPoul-Henning Kamp #ifdef notyet
804b40ce416SJulian Elischer 	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, td);
8053dbceccbSPoul-Henning Kamp #else
8063dbceccbSPoul-Henning Kamp 	(void)VOP_CLOSE(devvp, FREAD|FWRITE, cred, td);
8073dbceccbSPoul-Henning Kamp #endif
808df8bae1dSRodney W. Grimes 	if (ump) {
809df8bae1dSRodney W. Grimes 		free(ump->um_fs, M_UFSMNT);
810df8bae1dSRodney W. Grimes 		free(ump, M_UFSMNT);
811df8bae1dSRodney W. Grimes 		mp->mnt_data = (qaddr_t)0;
812df8bae1dSRodney W. Grimes 	}
813df8bae1dSRodney W. Grimes 	return (error);
814df8bae1dSRodney W. Grimes }
815df8bae1dSRodney W. Grimes 
8161c85e6a3SKirk McKusick #include <sys/sysctl.h>
8171c85e6a3SKirk McKusick int bigcgs = 0;
8181c85e6a3SKirk McKusick SYSCTL_INT(_debug, OID_AUTO, bigcgs, CTLFLAG_RW, &bigcgs, 0, "");
8191c85e6a3SKirk McKusick 
820df8bae1dSRodney W. Grimes /*
8211c85e6a3SKirk McKusick  * Sanity checks for loading old filesystem superblocks.
8221c85e6a3SKirk McKusick  * See ffs_oldfscompat_write below for unwound actions.
823df8bae1dSRodney W. Grimes  *
8241c85e6a3SKirk McKusick  * XXX - Parts get retired eventually.
8251c85e6a3SKirk McKusick  * Unfortunately new bits get added.
826df8bae1dSRodney W. Grimes  */
8271c85e6a3SKirk McKusick static void
8281c85e6a3SKirk McKusick ffs_oldfscompat_read(fs, ump, sblockloc)
829df8bae1dSRodney W. Grimes 	struct fs *fs;
8301c85e6a3SKirk McKusick 	struct ufsmount *ump;
8311c85e6a3SKirk McKusick 	ufs2_daddr_t sblockloc;
8321c85e6a3SKirk McKusick {
8331c85e6a3SKirk McKusick 	off_t maxfilesize;
8341c85e6a3SKirk McKusick 
8351c85e6a3SKirk McKusick 	/*
8361c85e6a3SKirk McKusick 	 * If not yet done, update UFS1 superblock with new wider fields.
8371c85e6a3SKirk McKusick 	 */
8381c85e6a3SKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC &&
8391c85e6a3SKirk McKusick 	    fs->fs_sblockloc != sblockloc) {
8401c85e6a3SKirk McKusick 		fs->fs_maxbsize = fs->fs_bsize;
8411c85e6a3SKirk McKusick 		fs->fs_sblockloc = sblockloc;
8421c85e6a3SKirk McKusick 		fs->fs_time = fs->fs_old_time;
8431c85e6a3SKirk McKusick 		fs->fs_size = fs->fs_old_size;
8441c85e6a3SKirk McKusick 		fs->fs_dsize = fs->fs_old_dsize;
8451c85e6a3SKirk McKusick 		fs->fs_csaddr = fs->fs_old_csaddr;
8461c85e6a3SKirk McKusick 		fs->fs_cstotal.cs_ndir = fs->fs_old_cstotal.cs_ndir;
8471c85e6a3SKirk McKusick 		fs->fs_cstotal.cs_nbfree = fs->fs_old_cstotal.cs_nbfree;
8481c85e6a3SKirk McKusick 		fs->fs_cstotal.cs_nifree = fs->fs_old_cstotal.cs_nifree;
8491c85e6a3SKirk McKusick 		fs->fs_cstotal.cs_nffree = fs->fs_old_cstotal.cs_nffree;
8501c85e6a3SKirk McKusick 	}
8511c85e6a3SKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC &&
8521c85e6a3SKirk McKusick 	    fs->fs_old_inodefmt < FS_44INODEFMT) {
8531c85e6a3SKirk McKusick 		fs->fs_maxfilesize = (u_quad_t) 1LL << 39;
8541c85e6a3SKirk McKusick 		fs->fs_qbmask = ~fs->fs_bmask;
8551c85e6a3SKirk McKusick 		fs->fs_qfmask = ~fs->fs_fmask;
8561c85e6a3SKirk McKusick 	}
8578f42fb8fSIan Dowse 	if (fs->fs_magic == FS_UFS1_MAGIC) {
8581c85e6a3SKirk McKusick 		ump->um_savedmaxfilesize = fs->fs_maxfilesize;
8591c85e6a3SKirk McKusick 		maxfilesize = (u_int64_t)0x40000000 * fs->fs_bsize - 1;
8601c85e6a3SKirk McKusick 		if (fs->fs_maxfilesize > maxfilesize)
8611c85e6a3SKirk McKusick 			fs->fs_maxfilesize = maxfilesize;
8628f42fb8fSIan Dowse 	}
8631c85e6a3SKirk McKusick 	/* Compatibility for old filesystems */
8641c85e6a3SKirk McKusick 	if (fs->fs_avgfilesize <= 0)
8651c85e6a3SKirk McKusick 		fs->fs_avgfilesize = AVFILESIZ;
8661c85e6a3SKirk McKusick 	if (fs->fs_avgfpdir <= 0)
8671c85e6a3SKirk McKusick 		fs->fs_avgfpdir = AFPDIR;
8681c85e6a3SKirk McKusick 	if (bigcgs) {
8691c85e6a3SKirk McKusick 		fs->fs_save_cgsize = fs->fs_cgsize;
8701c85e6a3SKirk McKusick 		fs->fs_cgsize = fs->fs_bsize;
8711c85e6a3SKirk McKusick 	}
8721c85e6a3SKirk McKusick }
8731c85e6a3SKirk McKusick 
8741c85e6a3SKirk McKusick /*
8751c85e6a3SKirk McKusick  * Unwinding superblock updates for old filesystems.
8761c85e6a3SKirk McKusick  * See ffs_oldfscompat_read above for details.
8771c85e6a3SKirk McKusick  *
8781c85e6a3SKirk McKusick  * XXX - Parts get retired eventually.
8791c85e6a3SKirk McKusick  * Unfortunately new bits get added.
8801c85e6a3SKirk McKusick  */
8811c85e6a3SKirk McKusick static void
8821c85e6a3SKirk McKusick ffs_oldfscompat_write(fs, ump)
8831c85e6a3SKirk McKusick 	struct fs *fs;
8841c85e6a3SKirk McKusick 	struct ufsmount *ump;
885df8bae1dSRodney W. Grimes {
886df8bae1dSRodney W. Grimes 
8871c85e6a3SKirk McKusick 	/*
8881c85e6a3SKirk McKusick 	 * Copy back UFS2 updated fields that UFS1 inspects.
8891c85e6a3SKirk McKusick 	 */
8901c85e6a3SKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC) {
8911c85e6a3SKirk McKusick 		fs->fs_old_time = fs->fs_time;
8921c85e6a3SKirk McKusick 		fs->fs_old_cstotal.cs_ndir = fs->fs_cstotal.cs_ndir;
8931c85e6a3SKirk McKusick 		fs->fs_old_cstotal.cs_nbfree = fs->fs_cstotal.cs_nbfree;
8941c85e6a3SKirk McKusick 		fs->fs_old_cstotal.cs_nifree = fs->fs_cstotal.cs_nifree;
8951c85e6a3SKirk McKusick 		fs->fs_old_cstotal.cs_nffree = fs->fs_cstotal.cs_nffree;
8961c85e6a3SKirk McKusick 		fs->fs_maxfilesize = ump->um_savedmaxfilesize;
8978f42fb8fSIan Dowse 	}
8981c85e6a3SKirk McKusick 	if (bigcgs) {
8991c85e6a3SKirk McKusick 		fs->fs_cgsize = fs->fs_save_cgsize;
9001c85e6a3SKirk McKusick 		fs->fs_save_cgsize = 0;
9011c85e6a3SKirk McKusick 	}
902df8bae1dSRodney W. Grimes }
903df8bae1dSRodney W. Grimes 
904df8bae1dSRodney W. Grimes /*
905df8bae1dSRodney W. Grimes  * unmount system call
906df8bae1dSRodney W. Grimes  */
907df8bae1dSRodney W. Grimes int
908b40ce416SJulian Elischer ffs_unmount(mp, mntflags, td)
909df8bae1dSRodney W. Grimes 	struct mount *mp;
910df8bae1dSRodney W. Grimes 	int mntflags;
911b40ce416SJulian Elischer 	struct thread *td;
912df8bae1dSRodney W. Grimes {
91305f4ff5dSPoul-Henning Kamp 	struct ufsmount *ump = VFSTOUFS(mp);
91405f4ff5dSPoul-Henning Kamp 	struct fs *fs;
915996c772fSJohn Dyson 	int error, flags;
916df8bae1dSRodney W. Grimes 
917df8bae1dSRodney W. Grimes 	flags = 0;
918df8bae1dSRodney W. Grimes 	if (mntflags & MNT_FORCE) {
919df8bae1dSRodney W. Grimes 		flags |= FORCECLOSE;
920df8bae1dSRodney W. Grimes 	}
921516081f2SRobert Watson #ifdef UFS_EXTATTR
922b40ce416SJulian Elischer 	if ((error = ufs_extattr_stop(mp, td))) {
923b2b0497aSRobert Watson 		if (error != EOPNOTSUPP)
924b2b0497aSRobert Watson 			printf("ffs_unmount: ufs_extattr_stop returned %d\n",
925b2b0497aSRobert Watson 			    error);
9267df97b61SRobert Watson 	} else {
9279de54ba5SRobert Watson 		ufs_extattr_uepm_destroy(&ump->um_extattr);
9287df97b61SRobert Watson 	}
929a64ed089SRobert Watson #endif
930b1897c19SJulian Elischer 	if (mp->mnt_flag & MNT_SOFTDEP) {
931b40ce416SJulian Elischer 		if ((error = softdep_flushfiles(mp, flags, td)) != 0)
932df8bae1dSRodney W. Grimes 			return (error);
933b1897c19SJulian Elischer 	} else {
934b40ce416SJulian Elischer 		if ((error = ffs_flushfiles(mp, flags, td)) != 0)
935b1897c19SJulian Elischer 			return (error);
936b1897c19SJulian Elischer 	}
937df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
9389ccb939eSKirk McKusick 	if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
939cfbf0a46SMaxime Henrion 		printf("%s: unmount pending error: blocks %jd files %d\n",
9401c85e6a3SKirk McKusick 		    fs->fs_fsmnt, (intmax_t)fs->fs_pendingblocks,
9411c85e6a3SKirk McKusick 		    fs->fs_pendinginodes);
9429ccb939eSKirk McKusick 		fs->fs_pendingblocks = 0;
9439ccb939eSKirk McKusick 		fs->fs_pendinginodes = 0;
9449ccb939eSKirk McKusick 	}
945996c772fSJohn Dyson 	if (fs->fs_ronly == 0) {
9461a6a6610SKirk McKusick 		fs->fs_clean = fs->fs_flags & (FS_UNCLEAN|FS_NEEDSFSCK) ? 0 : 1;
947996c772fSJohn Dyson 		error = ffs_sbupdate(ump, MNT_WAIT);
948996c772fSJohn Dyson 		if (error) {
949996c772fSJohn Dyson 			fs->fs_clean = 0;
950996c772fSJohn Dyson 			return (error);
951996c772fSJohn Dyson 		}
952e0e9c421SDavid Greenman 	}
9537eb9fca5SEivind Eklund 	ump->um_devvp->v_rdev->si_mountpoint = NULL;
9546476c0d2SJohn Dyson 
955b40ce416SJulian Elischer 	vinvalbuf(ump->um_devvp, V_SAVE, NOCRED, td, 0, 0);
956063f7763SPoul-Henning Kamp 	/* XXX: see comment above VOP_OPEN */
957063f7763SPoul-Henning Kamp #ifdef notyet
958996c772fSJohn Dyson 	error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE,
959b40ce416SJulian Elischer 		NOCRED, td);
960063f7763SPoul-Henning Kamp #else
961063f7763SPoul-Henning Kamp 	error = VOP_CLOSE(ump->um_devvp, FREAD|FWRITE, NOCRED, td);
962063f7763SPoul-Henning Kamp #endif
9636476c0d2SJohn Dyson 
9646476c0d2SJohn Dyson 	vrele(ump->um_devvp);
9656476c0d2SJohn Dyson 
966f55ff3f3SIan Dowse 	free(fs->fs_csp, M_UFSMNT);
967df8bae1dSRodney W. Grimes 	free(fs, M_UFSMNT);
968df8bae1dSRodney W. Grimes 	free(ump, M_UFSMNT);
969df8bae1dSRodney W. Grimes 	mp->mnt_data = (qaddr_t)0;
970cc9d8990SPeter Wemm 	mp->mnt_flag &= ~MNT_LOCAL;
971df8bae1dSRodney W. Grimes 	return (error);
972df8bae1dSRodney W. Grimes }
973df8bae1dSRodney W. Grimes 
974df8bae1dSRodney W. Grimes /*
975df8bae1dSRodney W. Grimes  * Flush out all the files in a filesystem.
976df8bae1dSRodney W. Grimes  */
97726f9a767SRodney W. Grimes int
978b40ce416SJulian Elischer ffs_flushfiles(mp, flags, td)
97905f4ff5dSPoul-Henning Kamp 	struct mount *mp;
980df8bae1dSRodney W. Grimes 	int flags;
981b40ce416SJulian Elischer 	struct thread *td;
982df8bae1dSRodney W. Grimes {
98305f4ff5dSPoul-Henning Kamp 	struct ufsmount *ump;
984c9671602SPoul-Henning Kamp 	int error;
985df8bae1dSRodney W. Grimes 
986df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
987df8bae1dSRodney W. Grimes #ifdef QUOTA
988df8bae1dSRodney W. Grimes 	if (mp->mnt_flag & MNT_QUOTA) {
989c1d9efcbSPoul-Henning Kamp 		int i;
9900864ef1eSIan Dowse 		error = vflush(mp, 0, SKIPSYSTEM|flags);
991c1d9efcbSPoul-Henning Kamp 		if (error)
992df8bae1dSRodney W. Grimes 			return (error);
993df8bae1dSRodney W. Grimes 		for (i = 0; i < MAXQUOTAS; i++) {
994df8bae1dSRodney W. Grimes 			if (ump->um_quotas[i] == NULLVP)
995df8bae1dSRodney W. Grimes 				continue;
996b40ce416SJulian Elischer 			quotaoff(td, mp, i);
997df8bae1dSRodney W. Grimes 		}
998df8bae1dSRodney W. Grimes 		/*
999df8bae1dSRodney W. Grimes 		 * Here we fall through to vflush again to ensure
1000df8bae1dSRodney W. Grimes 		 * that we have gotten rid of all the system vnodes.
1001df8bae1dSRodney W. Grimes 		 */
1002df8bae1dSRodney W. Grimes 	}
1003df8bae1dSRodney W. Grimes #endif
1004e6e370a7SJeff Roberson 	ASSERT_VOP_LOCKED(ump->um_devvp, "ffs_flushfiles");
1005e6e370a7SJeff Roberson 	if (ump->um_devvp->v_vflag & VV_COPYONWRITE) {
10060864ef1eSIan Dowse 		if ((error = vflush(mp, 0, SKIPSYSTEM | flags)) != 0)
1007f2a2857bSKirk McKusick 			return (error);
1008f2a2857bSKirk McKusick 		ffs_snapshot_unmount(mp);
1009f2a2857bSKirk McKusick 		/*
1010f2a2857bSKirk McKusick 		 * Here we fall through to vflush again to ensure
1011f2a2857bSKirk McKusick 		 * that we have gotten rid of all the system vnodes.
1012f2a2857bSKirk McKusick 		 */
1013f2a2857bSKirk McKusick 	}
1014b1897c19SJulian Elischer         /*
1015b1897c19SJulian Elischer 	 * Flush all the files.
1016b1897c19SJulian Elischer 	 */
10170864ef1eSIan Dowse 	if ((error = vflush(mp, 0, flags)) != 0)
1018b1897c19SJulian Elischer 		return (error);
1019b1897c19SJulian Elischer 	/*
1020b1897c19SJulian Elischer 	 * Flush filesystem metadata.
1021b1897c19SJulian Elischer 	 */
1022b40ce416SJulian Elischer 	vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, td);
1023a854ed98SJohn Baldwin 	error = VOP_FSYNC(ump->um_devvp, td->td_ucred, MNT_WAIT, td);
1024b40ce416SJulian Elischer 	VOP_UNLOCK(ump->um_devvp, 0, td);
1025df8bae1dSRodney W. Grimes 	return (error);
1026df8bae1dSRodney W. Grimes }
1027df8bae1dSRodney W. Grimes 
1028df8bae1dSRodney W. Grimes /*
1029df8bae1dSRodney W. Grimes  * Get filesystem statistics.
1030df8bae1dSRodney W. Grimes  */
1031df8bae1dSRodney W. Grimes int
1032b40ce416SJulian Elischer ffs_statfs(mp, sbp, td)
1033df8bae1dSRodney W. Grimes 	struct mount *mp;
103405f4ff5dSPoul-Henning Kamp 	struct statfs *sbp;
1035b40ce416SJulian Elischer 	struct thread *td;
1036df8bae1dSRodney W. Grimes {
103705f4ff5dSPoul-Henning Kamp 	struct ufsmount *ump;
103805f4ff5dSPoul-Henning Kamp 	struct fs *fs;
1039df8bae1dSRodney W. Grimes 
1040df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
1041df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
10421c85e6a3SKirk McKusick 	if (fs->fs_magic != FS_UFS1_MAGIC && fs->fs_magic != FS_UFS2_MAGIC)
1043df8bae1dSRodney W. Grimes 		panic("ffs_statfs");
1044df8bae1dSRodney W. Grimes 	sbp->f_bsize = fs->fs_fsize;
1045df8bae1dSRodney W. Grimes 	sbp->f_iosize = fs->fs_bsize;
1046df8bae1dSRodney W. Grimes 	sbp->f_blocks = fs->fs_dsize;
1047df8bae1dSRodney W. Grimes 	sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
10489ccb939eSKirk McKusick 	    fs->fs_cstotal.cs_nffree + dbtofsb(fs, fs->fs_pendingblocks);
10499ccb939eSKirk McKusick 	sbp->f_bavail = freespace(fs, fs->fs_minfree) +
10509ccb939eSKirk McKusick 	    dbtofsb(fs, fs->fs_pendingblocks);
1051df8bae1dSRodney W. Grimes 	sbp->f_files =  fs->fs_ncg * fs->fs_ipg - ROOTINO;
10529ccb939eSKirk McKusick 	sbp->f_ffree = fs->fs_cstotal.cs_nifree + fs->fs_pendinginodes;
1053df8bae1dSRodney W. Grimes 	if (sbp != &mp->mnt_stat) {
1054996c772fSJohn Dyson 		sbp->f_type = mp->mnt_vfc->vfc_typenum;
1055df8bae1dSRodney W. Grimes 		bcopy((caddr_t)mp->mnt_stat.f_mntonname,
1056df8bae1dSRodney W. Grimes 			(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
1057df8bae1dSRodney W. Grimes 		bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
1058df8bae1dSRodney W. Grimes 			(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
1059df8bae1dSRodney W. Grimes 	}
1060df8bae1dSRodney W. Grimes 	return (0);
1061df8bae1dSRodney W. Grimes }
1062df8bae1dSRodney W. Grimes 
1063df8bae1dSRodney W. Grimes /*
1064df8bae1dSRodney W. Grimes  * Go through the disk queues to initiate sandbagged IO;
1065df8bae1dSRodney W. Grimes  * go through the inodes to write those that have been modified;
1066df8bae1dSRodney W. Grimes  * initiate the writing of the super block if it has been modified.
1067df8bae1dSRodney W. Grimes  *
1068df8bae1dSRodney W. Grimes  * Note: we are always called with the filesystem marked `MPBUSY'.
1069df8bae1dSRodney W. Grimes  */
1070df8bae1dSRodney W. Grimes int
1071b40ce416SJulian Elischer ffs_sync(mp, waitfor, cred, td)
1072df8bae1dSRodney W. Grimes 	struct mount *mp;
1073df8bae1dSRodney W. Grimes 	int waitfor;
1074df8bae1dSRodney W. Grimes 	struct ucred *cred;
1075b40ce416SJulian Elischer 	struct thread *td;
1076df8bae1dSRodney W. Grimes {
1077112f7372SKirk McKusick 	struct vnode *nvp, *vp, *devvp;
1078996c772fSJohn Dyson 	struct inode *ip;
1079996c772fSJohn Dyson 	struct ufsmount *ump = VFSTOUFS(mp);
1080996c772fSJohn Dyson 	struct fs *fs;
10819b971133SKirk McKusick 	int error, count, wait, lockreq, allerror = 0;
1082df8bae1dSRodney W. Grimes 
1083df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
1084996c772fSJohn Dyson 	if (fs->fs_fmod != 0 && fs->fs_ronly != 0) {		/* XXX */
1085df8bae1dSRodney W. Grimes 		printf("fs = %s\n", fs->fs_fsmnt);
10865ace3b26SMike Pritchard 		panic("ffs_sync: rofs mod");
1087df8bae1dSRodney W. Grimes 	}
1088df8bae1dSRodney W. Grimes 	/*
1089df8bae1dSRodney W. Grimes 	 * Write back each (modified) inode.
1090df8bae1dSRodney W. Grimes 	 */
10919b971133SKirk McKusick 	wait = 0;
1092245df27cSMatthew Dillon 	lockreq = LK_EXCLUSIVE | LK_NOWAIT;
10939b971133SKirk McKusick 	if (waitfor == MNT_WAIT) {
10949b971133SKirk McKusick 		wait = 1;
1095245df27cSMatthew Dillon 		lockreq = LK_EXCLUSIVE;
10969b971133SKirk McKusick 	}
10979ed346baSBosko Milekic 	mtx_lock(&mntvnode_mtx);
1098df8bae1dSRodney W. Grimes loop:
1099c72ccd01SMatthew Dillon 	for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist); vp != NULL; vp = nvp) {
1100df8bae1dSRodney W. Grimes 		/*
1101df8bae1dSRodney W. Grimes 		 * If the vnode that we are about to sync is no longer
1102df8bae1dSRodney W. Grimes 		 * associated with this mount point, start over.
1103df8bae1dSRodney W. Grimes 		 */
1104df8bae1dSRodney W. Grimes 		if (vp->v_mount != mp)
1105df8bae1dSRodney W. Grimes 			goto loop;
110649d2d9f4SJohn Baldwin 
1107245df27cSMatthew Dillon 		/*
1108245df27cSMatthew Dillon 		 * Depend on the mntvnode_slock to keep things stable enough
1109245df27cSMatthew Dillon 		 * for a quick test.  Since there might be hundreds of
1110245df27cSMatthew Dillon 		 * thousands of vnodes, we cannot afford even a subroutine
1111245df27cSMatthew Dillon 		 * call unless there's a good chance that we have work to do.
1112245df27cSMatthew Dillon 		 */
1113245df27cSMatthew Dillon 		nvp = TAILQ_NEXT(vp, v_nmntvnodes);
1114df8bae1dSRodney W. Grimes 		ip = VTOI(vp);
1115cf60e8e4SKirk McKusick 		if (vp->v_type == VNON || ((ip->i_flag &
1116cf60e8e4SKirk McKusick 		    (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
1117cf60e8e4SKirk McKusick 		    TAILQ_EMPTY(&vp->v_dirtyblkhd))) {
1118df8bae1dSRodney W. Grimes 			continue;
1119996c772fSJohn Dyson 		}
112081c6e3e5SDavid Greenman 		if (vp->v_type != VCHR) {
1121245df27cSMatthew Dillon 			mtx_unlock(&mntvnode_mtx);
1122b40ce416SJulian Elischer 			if ((error = vget(vp, lockreq, td)) != 0) {
11239ed346baSBosko Milekic 				mtx_lock(&mntvnode_mtx);
1124996c772fSJohn Dyson 				if (error == ENOENT)
1125df8bae1dSRodney W. Grimes 					goto loop;
1126245df27cSMatthew Dillon 			} else {
1127b40ce416SJulian Elischer 				if ((error = VOP_FSYNC(vp, cred, waitfor, td)) != 0)
1128df8bae1dSRodney W. Grimes 					allerror = error;
1129b40ce416SJulian Elischer 				VOP_UNLOCK(vp, 0, td);
11308694d8e9SOllivier Robert 				vrele(vp);
113149d2d9f4SJohn Baldwin 				mtx_lock(&mntvnode_mtx);
1132df8bae1dSRodney W. Grimes 			}
1133245df27cSMatthew Dillon 		} else {
1134245df27cSMatthew Dillon 			mtx_unlock(&mntvnode_mtx);
1135245df27cSMatthew Dillon 			UFS_UPDATE(vp, wait);
1136245df27cSMatthew Dillon 			mtx_lock(&mntvnode_mtx);
1137245df27cSMatthew Dillon 		}
1138245df27cSMatthew Dillon 		if (TAILQ_NEXT(vp, v_nmntvnodes) != nvp)
1139245df27cSMatthew Dillon 			goto loop;
1140245df27cSMatthew Dillon 	}
11419ed346baSBosko Milekic 	mtx_unlock(&mntvnode_mtx);
1142df8bae1dSRodney W. Grimes 	/*
1143df8bae1dSRodney W. Grimes 	 * Force stale filesystem control information to be flushed.
1144df8bae1dSRodney W. Grimes 	 */
11459b971133SKirk McKusick 	if (waitfor == MNT_WAIT) {
1146b40ce416SJulian Elischer 		if ((error = softdep_flushworklist(ump->um_mountp, &count, td)))
11479b971133SKirk McKusick 			allerror = error;
11489b971133SKirk McKusick 		/* Flushed work items may create new vnodes to clean */
11499b971133SKirk McKusick 		if (count) {
11509ed346baSBosko Milekic 			mtx_lock(&mntvnode_mtx);
11519b971133SKirk McKusick 			goto loop;
11529b971133SKirk McKusick 		}
11539b971133SKirk McKusick 	}
1154589c7af9SKirk McKusick #ifdef QUOTA
1155589c7af9SKirk McKusick 	qsync(mp);
1156589c7af9SKirk McKusick #endif
1157112f7372SKirk McKusick 	devvp = ump->um_devvp;
1158112f7372SKirk McKusick 	mtx_lock(&devvp->v_interlock);
1159112f7372SKirk McKusick 	if (waitfor != MNT_LAZY &&
1160112f7372SKirk McKusick 	    (devvp->v_numoutput > 0 || TAILQ_FIRST(&devvp->v_dirtyblkhd))) {
1161112f7372SKirk McKusick 		mtx_unlock(&devvp->v_interlock);
1162b40ce416SJulian Elischer 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
1163b40ce416SJulian Elischer 		if ((error = VOP_FSYNC(devvp, cred, waitfor, td)) != 0)
1164df8bae1dSRodney W. Grimes 			allerror = error;
1165b40ce416SJulian Elischer 		VOP_UNLOCK(devvp, 0, td);
1166112f7372SKirk McKusick 		if (waitfor == MNT_WAIT) {
1167112f7372SKirk McKusick 			mtx_lock(&mntvnode_mtx);
1168112f7372SKirk McKusick 			goto loop;
1169b1897c19SJulian Elischer 		}
1170112f7372SKirk McKusick 	} else
1171112f7372SKirk McKusick 		mtx_unlock(&devvp->v_interlock);
1172996c772fSJohn Dyson 	/*
1173996c772fSJohn Dyson 	 * Write back modified superblock.
1174996c772fSJohn Dyson 	 */
1175b1897c19SJulian Elischer 	if (fs->fs_fmod != 0 && (error = ffs_sbupdate(ump, waitfor)) != 0)
1176996c772fSJohn Dyson 		allerror = error;
1177df8bae1dSRodney W. Grimes 	return (allerror);
1178df8bae1dSRodney W. Grimes }
1179df8bae1dSRodney W. Grimes 
1180df8bae1dSRodney W. Grimes int
1181a0595d02SKirk McKusick ffs_vget(mp, ino, flags, vpp)
1182df8bae1dSRodney W. Grimes 	struct mount *mp;
1183df8bae1dSRodney W. Grimes 	ino_t ino;
1184a0595d02SKirk McKusick 	int flags;
1185df8bae1dSRodney W. Grimes 	struct vnode **vpp;
1186df8bae1dSRodney W. Grimes {
1187f576a00dSSemen Ustimenko 	struct thread *td = curthread; 		/* XXX */
1188996c772fSJohn Dyson 	struct fs *fs;
1189996c772fSJohn Dyson 	struct inode *ip;
1190df8bae1dSRodney W. Grimes 	struct ufsmount *ump;
1191df8bae1dSRodney W. Grimes 	struct buf *bp;
1192df8bae1dSRodney W. Grimes 	struct vnode *vp;
1193df8bae1dSRodney W. Grimes 	dev_t dev;
1194f576a00dSSemen Ustimenko 	int error;
1195df8bae1dSRodney W. Grimes 
1196df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
1197df8bae1dSRodney W. Grimes 	dev = ump->um_dev;
1198f576a00dSSemen Ustimenko 
1199f576a00dSSemen Ustimenko 	/*
120013866b3fSSemen Ustimenko 	 * We do not lock vnode creation as it is believed to be too
1201f576a00dSSemen Ustimenko 	 * expensive for such rare case as simultaneous creation of vnode
1202f576a00dSSemen Ustimenko 	 * for same ino by different processes. We just allow them to race
1203f576a00dSSemen Ustimenko 	 * and check later to decide who wins. Let the race begin!
1204f576a00dSSemen Ustimenko 	 */
1205a0595d02SKirk McKusick 	if ((error = ufs_ihashget(dev, ino, flags, vpp)) != 0)
1206a0595d02SKirk McKusick 		return (error);
1207a0595d02SKirk McKusick 	if (*vpp != NULL)
1208df8bae1dSRodney W. Grimes 		return (0);
1209df8bae1dSRodney W. Grimes 
12102094ddb6SDavid Greenman 	/*
12112f9bae59SDavid Greenman 	 * If this MALLOC() is performed after the getnewvnode()
12122f9bae59SDavid Greenman 	 * it might block, leaving a vnode with a NULL v_data to be
12132f9bae59SDavid Greenman 	 * found by ffs_sync() if a sync happens to fire right then,
12142f9bae59SDavid Greenman 	 * which will cause a panic because ffs_sync() blindly
12152f9bae59SDavid Greenman 	 * dereferences vp->v_data (as well it should).
12162f9bae59SDavid Greenman 	 */
12170be6b890SPoul-Henning Kamp 	MALLOC(ip, struct inode *, sizeof(struct inode),
12180be6b890SPoul-Henning Kamp 	    ump->um_malloctype, M_WAITOK);
12192f9bae59SDavid Greenman 
1220df8bae1dSRodney W. Grimes 	/* Allocate a new vnode/inode. */
1221c9671602SPoul-Henning Kamp 	error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp);
1222c9671602SPoul-Henning Kamp 	if (error) {
1223df8bae1dSRodney W. Grimes 		*vpp = NULL;
12240be6b890SPoul-Henning Kamp 		FREE(ip, ump->um_malloctype);
1225df8bae1dSRodney W. Grimes 		return (error);
1226df8bae1dSRodney W. Grimes 	}
1227df8bae1dSRodney W. Grimes 	bzero((caddr_t)ip, sizeof(struct inode));
122867e87166SBoris Popov 	/*
122967e87166SBoris Popov 	 * FFS supports lock sharing in the stack of vnodes
123067e87166SBoris Popov 	 */
123167e87166SBoris Popov 	vp->v_vnlock = &vp->v_lock;
123223b59018SMatthew Dillon 	lockinit(vp->v_vnlock, PINOD, "inode", VLKTIMEOUT, LK_CANRECURSE);
1233df8bae1dSRodney W. Grimes 	vp->v_data = ip;
1234df8bae1dSRodney W. Grimes 	ip->i_vnode = vp;
12351c85e6a3SKirk McKusick 	ip->i_ump = ump;
1236df8bae1dSRodney W. Grimes 	ip->i_fs = fs = ump->um_fs;
1237df8bae1dSRodney W. Grimes 	ip->i_dev = dev;
1238df8bae1dSRodney W. Grimes 	ip->i_number = ino;
1239df8bae1dSRodney W. Grimes #ifdef QUOTA
1240c1d9efcbSPoul-Henning Kamp 	{
1241c1d9efcbSPoul-Henning Kamp 		int i;
1242df8bae1dSRodney W. Grimes 		for (i = 0; i < MAXQUOTAS; i++)
1243df8bae1dSRodney W. Grimes 			ip->i_dquot[i] = NODQUOT;
1244c1d9efcbSPoul-Henning Kamp 	}
1245df8bae1dSRodney W. Grimes #endif
1246df8bae1dSRodney W. Grimes 	/*
1247f576a00dSSemen Ustimenko 	 * Exclusively lock the vnode before adding to hash. Note, that we
1248f576a00dSSemen Ustimenko 	 * must not release nor downgrade the lock (despite flags argument
1249f576a00dSSemen Ustimenko 	 * says) till it is fully initialized.
1250df8bae1dSRodney W. Grimes 	 */
1251f576a00dSSemen Ustimenko 	lockmgr(vp->v_vnlock, LK_EXCLUSIVE, (struct mtx *)0, td);
1252df8bae1dSRodney W. Grimes 
1253937c4dfaSSeigo Tanimura 	/*
1254f576a00dSSemen Ustimenko 	 * Atomicaly (in terms of ufs_hash operations) check the hash for
1255f576a00dSSemen Ustimenko 	 * duplicate of vnode being created and add it to the hash. If a
1256f576a00dSSemen Ustimenko 	 * duplicate vnode was found, it will be vget()ed from hash for us.
1257937c4dfaSSeigo Tanimura 	 */
1258f576a00dSSemen Ustimenko 	if ((error = ufs_ihashins(ip, flags, vpp)) != 0) {
1259f576a00dSSemen Ustimenko 		vput(vp);
1260f576a00dSSemen Ustimenko 		*vpp = NULL;
1261f576a00dSSemen Ustimenko 		return (error);
1262f576a00dSSemen Ustimenko 	}
1263f576a00dSSemen Ustimenko 
1264f576a00dSSemen Ustimenko 	/* We lost the race, then throw away our vnode and return existing */
1265f576a00dSSemen Ustimenko 	if (*vpp != NULL) {
1266f576a00dSSemen Ustimenko 		vput(vp);
1267f576a00dSSemen Ustimenko 		return (0);
1268f576a00dSSemen Ustimenko 	}
12692094ddb6SDavid Greenman 
1270df8bae1dSRodney W. Grimes 	/* Read in the disk contents for the inode, copy into the inode. */
1271c9671602SPoul-Henning Kamp 	error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
1272c9671602SPoul-Henning Kamp 	    (int)fs->fs_bsize, NOCRED, &bp);
1273c9671602SPoul-Henning Kamp 	if (error) {
1274df8bae1dSRodney W. Grimes 		/*
1275df8bae1dSRodney W. Grimes 		 * The inode does not contain anything useful, so it would
1276df8bae1dSRodney W. Grimes 		 * be misleading to leave it on its hash chain. With mode
1277df8bae1dSRodney W. Grimes 		 * still zero, it will be unlinked and returned to the free
1278df8bae1dSRodney W. Grimes 		 * list by vput().
1279df8bae1dSRodney W. Grimes 		 */
1280df8bae1dSRodney W. Grimes 		brelse(bp);
1281bd7e5f99SJohn Dyson 		vput(vp);
1282df8bae1dSRodney W. Grimes 		*vpp = NULL;
1283df8bae1dSRodney W. Grimes 		return (error);
1284df8bae1dSRodney W. Grimes 	}
12851c85e6a3SKirk McKusick 	ffs_load_inode(bp, ip, ump->um_malloctype, fs, ino);
1286b1897c19SJulian Elischer 	if (DOINGSOFTDEP(vp))
1287b1897c19SJulian Elischer 		softdep_load_inodeblock(ip);
1288b1897c19SJulian Elischer 	else
1289b1897c19SJulian Elischer 		ip->i_effnlink = ip->i_nlink;
1290bd7e5f99SJohn Dyson 	bqrelse(bp);
1291df8bae1dSRodney W. Grimes 
1292df8bae1dSRodney W. Grimes 	/*
1293df8bae1dSRodney W. Grimes 	 * Initialize the vnode from the inode, check for aliases.
1294df8bae1dSRodney W. Grimes 	 * Note that the underlying vnode may have changed.
1295df8bae1dSRodney W. Grimes 	 */
1296e6302eabSBruce Evans 	error = ufs_vinit(mp, ffs_specop_p, ffs_fifoop_p, &vp);
1297c9671602SPoul-Henning Kamp 	if (error) {
1298df8bae1dSRodney W. Grimes 		vput(vp);
1299df8bae1dSRodney W. Grimes 		*vpp = NULL;
1300df8bae1dSRodney W. Grimes 		return (error);
1301df8bae1dSRodney W. Grimes 	}
1302df8bae1dSRodney W. Grimes 	/*
1303df8bae1dSRodney W. Grimes 	 * Finish inode initialization now that aliasing has been resolved.
1304df8bae1dSRodney W. Grimes 	 */
1305df8bae1dSRodney W. Grimes 	ip->i_devvp = ump->um_devvp;
1306df8bae1dSRodney W. Grimes 	VREF(ip->i_devvp);
1307df8bae1dSRodney W. Grimes 	/*
1308df8bae1dSRodney W. Grimes 	 * Set up a generation number for this inode if it does not
1309df8bae1dSRodney W. Grimes 	 * already have one. This should only happen on old filesystems.
1310df8bae1dSRodney W. Grimes 	 */
1311df8bae1dSRodney W. Grimes 	if (ip->i_gen == 0) {
13128f89943eSGuido van Rooij 		ip->i_gen = random() / 2 + 1;
13131c85e6a3SKirk McKusick 		if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
1314df8bae1dSRodney W. Grimes 			ip->i_flag |= IN_MODIFIED;
13151c85e6a3SKirk McKusick 			DIP(ip, i_gen) = ip->i_gen;
13161c85e6a3SKirk McKusick 		}
1317df8bae1dSRodney W. Grimes 	}
1318df8bae1dSRodney W. Grimes 	/*
1319df8bae1dSRodney W. Grimes 	 * Ensure that uid and gid are correct. This is a temporary
1320df8bae1dSRodney W. Grimes 	 * fix until fsck has been changed to do the update.
1321df8bae1dSRodney W. Grimes 	 */
13221c85e6a3SKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC &&		/* XXX */
13231c85e6a3SKirk McKusick 	    fs->fs_old_inodefmt < FS_44INODEFMT) {	/* XXX */
13241c85e6a3SKirk McKusick 		ip->i_uid = ip->i_din1->di_ouid;	/* XXX */
13251c85e6a3SKirk McKusick 		ip->i_gid = ip->i_din1->di_ogid;	/* XXX */
1326df8bae1dSRodney W. Grimes 	}						/* XXX */
1327df8bae1dSRodney W. Grimes 
1328df8bae1dSRodney W. Grimes 	*vpp = vp;
1329df8bae1dSRodney W. Grimes 	return (0);
1330df8bae1dSRodney W. Grimes }
1331df8bae1dSRodney W. Grimes 
1332df8bae1dSRodney W. Grimes /*
1333df8bae1dSRodney W. Grimes  * File handle to vnode
1334df8bae1dSRodney W. Grimes  *
1335df8bae1dSRodney W. Grimes  * Have to be really careful about stale file handles:
1336df8bae1dSRodney W. Grimes  * - check that the inode number is valid
1337df8bae1dSRodney W. Grimes  * - call ffs_vget() to get the locked inode
1338df8bae1dSRodney W. Grimes  * - check for an unallocated inode (i_mode == 0)
1339df8bae1dSRodney W. Grimes  * - check that the given client host has export rights and return
1340df8bae1dSRodney W. Grimes  *   those rights via. exflagsp and credanonp
1341df8bae1dSRodney W. Grimes  */
1342df8bae1dSRodney W. Grimes int
1343c24fda81SAlfred Perlstein ffs_fhtovp(mp, fhp, vpp)
134405f4ff5dSPoul-Henning Kamp 	struct mount *mp;
1345df8bae1dSRodney W. Grimes 	struct fid *fhp;
1346df8bae1dSRodney W. Grimes 	struct vnode **vpp;
1347df8bae1dSRodney W. Grimes {
134805f4ff5dSPoul-Henning Kamp 	struct ufid *ufhp;
1349df8bae1dSRodney W. Grimes 	struct fs *fs;
1350df8bae1dSRodney W. Grimes 
1351df8bae1dSRodney W. Grimes 	ufhp = (struct ufid *)fhp;
1352df8bae1dSRodney W. Grimes 	fs = VFSTOUFS(mp)->um_fs;
1353df8bae1dSRodney W. Grimes 	if (ufhp->ufid_ino < ROOTINO ||
1354df8bae1dSRodney W. Grimes 	    ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg)
1355df8bae1dSRodney W. Grimes 		return (ESTALE);
1356c24fda81SAlfred Perlstein 	return (ufs_fhtovp(mp, ufhp, vpp));
1357df8bae1dSRodney W. Grimes }
1358df8bae1dSRodney W. Grimes 
1359df8bae1dSRodney W. Grimes /*
1360df8bae1dSRodney W. Grimes  * Vnode pointer to File handle
1361df8bae1dSRodney W. Grimes  */
1362df8bae1dSRodney W. Grimes /* ARGSUSED */
136326f9a767SRodney W. Grimes int
1364df8bae1dSRodney W. Grimes ffs_vptofh(vp, fhp)
1365df8bae1dSRodney W. Grimes 	struct vnode *vp;
1366df8bae1dSRodney W. Grimes 	struct fid *fhp;
1367df8bae1dSRodney W. Grimes {
136805f4ff5dSPoul-Henning Kamp 	struct inode *ip;
136905f4ff5dSPoul-Henning Kamp 	struct ufid *ufhp;
1370df8bae1dSRodney W. Grimes 
1371df8bae1dSRodney W. Grimes 	ip = VTOI(vp);
1372df8bae1dSRodney W. Grimes 	ufhp = (struct ufid *)fhp;
1373df8bae1dSRodney W. Grimes 	ufhp->ufid_len = sizeof(struct ufid);
1374df8bae1dSRodney W. Grimes 	ufhp->ufid_ino = ip->i_number;
1375df8bae1dSRodney W. Grimes 	ufhp->ufid_gen = ip->i_gen;
1376df8bae1dSRodney W. Grimes 	return (0);
1377df8bae1dSRodney W. Grimes }
1378df8bae1dSRodney W. Grimes 
1379df8bae1dSRodney W. Grimes /*
13805346934fSIan Dowse  * Initialize the filesystem.
1381996c772fSJohn Dyson  */
1382996c772fSJohn Dyson static int
1383996c772fSJohn Dyson ffs_init(vfsp)
1384996c772fSJohn Dyson 	struct vfsconf *vfsp;
1385996c772fSJohn Dyson {
1386996c772fSJohn Dyson 
1387b1897c19SJulian Elischer 	softdep_initialize();
1388996c772fSJohn Dyson 	return (ufs_init(vfsp));
1389996c772fSJohn Dyson }
1390996c772fSJohn Dyson 
1391996c772fSJohn Dyson /*
13925346934fSIan Dowse  * Undo the work of ffs_init().
13935346934fSIan Dowse  */
13945346934fSIan Dowse static int
13955346934fSIan Dowse ffs_uninit(vfsp)
13965346934fSIan Dowse 	struct vfsconf *vfsp;
13975346934fSIan Dowse {
13985346934fSIan Dowse 	int ret;
13995346934fSIan Dowse 
14005346934fSIan Dowse 	ret = ufs_uninit(vfsp);
14015346934fSIan Dowse 	softdep_uninitialize();
14025346934fSIan Dowse 	return (ret);
14035346934fSIan Dowse }
14045346934fSIan Dowse 
14055346934fSIan Dowse /*
1406df8bae1dSRodney W. Grimes  * Write a superblock and associated information back to disk.
1407df8bae1dSRodney W. Grimes  */
1408b8dce649SPoul-Henning Kamp static int
1409df8bae1dSRodney W. Grimes ffs_sbupdate(mp, waitfor)
1410df8bae1dSRodney W. Grimes 	struct ufsmount *mp;
1411df8bae1dSRodney W. Grimes 	int waitfor;
1412df8bae1dSRodney W. Grimes {
14131c85e6a3SKirk McKusick 	struct fs *fs = mp->um_fs;
141405f4ff5dSPoul-Henning Kamp 	struct buf *bp;
1415df8bae1dSRodney W. Grimes 	int blks;
1416f55ff3f3SIan Dowse 	void *space;
1417996c772fSJohn Dyson 	int i, size, error, allerror = 0;
1418df8bae1dSRodney W. Grimes 
1419996c772fSJohn Dyson 	/*
1420996c772fSJohn Dyson 	 * First write back the summary information.
1421996c772fSJohn Dyson 	 */
1422df8bae1dSRodney W. Grimes 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
1423f55ff3f3SIan Dowse 	space = fs->fs_csp;
1424df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
1425df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
1426df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
1427df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
1428df8bae1dSRodney W. Grimes 		bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i),
1429df8bae1dSRodney W. Grimes 		    size, 0, 0);
1430df8bae1dSRodney W. Grimes 		bcopy(space, bp->b_data, (u_int)size);
1431f55ff3f3SIan Dowse 		space = (char *)space + size;
1432996c772fSJohn Dyson 		if (waitfor != MNT_WAIT)
1433df8bae1dSRodney W. Grimes 			bawrite(bp);
14348aef1712SMatthew Dillon 		else if ((error = bwrite(bp)) != 0)
1435996c772fSJohn Dyson 			allerror = error;
1436df8bae1dSRodney W. Grimes 	}
1437996c772fSJohn Dyson 	/*
1438996c772fSJohn Dyson 	 * Now write back the superblock itself. If any errors occurred
1439996c772fSJohn Dyson 	 * up to this point, then fail so that the superblock avoids
1440996c772fSJohn Dyson 	 * being written out as clean.
1441996c772fSJohn Dyson 	 */
1442996c772fSJohn Dyson 	if (allerror)
1443996c772fSJohn Dyson 		return (allerror);
14441c85e6a3SKirk McKusick 	bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_sblockloc),
14451c85e6a3SKirk McKusick 	    (int)fs->fs_sbsize, 0, 0);
1446b1897c19SJulian Elischer 	fs->fs_fmod = 0;
1447227ee8a1SPoul-Henning Kamp 	fs->fs_time = time_second;
1448996c772fSJohn Dyson 	bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize);
14491c85e6a3SKirk McKusick 	ffs_oldfscompat_write((struct fs *)bp->b_data, mp);
1450996c772fSJohn Dyson 	if (waitfor != MNT_WAIT)
1451996c772fSJohn Dyson 		bawrite(bp);
14528aef1712SMatthew Dillon 	else if ((error = bwrite(bp)) != 0)
1453996c772fSJohn Dyson 		allerror = error;
1454996c772fSJohn Dyson 	return (allerror);
1455df8bae1dSRodney W. Grimes }
1456