xref: /freebsd/sys/ufs/ffs/ffs_vfsops.c (revision a163d034fadcfb4a25ca34a2ba5f491c47b6ff69)
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 
3780830407SRobert Watson #include "opt_mac.h"
3801733a9bSGarrett Wollman #include "opt_quota.h"
39516081f2SRobert Watson #include "opt_ufs.h"
4001733a9bSGarrett Wollman 
41df8bae1dSRodney W. Grimes #include <sys/param.h>
42df8bae1dSRodney W. Grimes #include <sys/systm.h>
431c85e6a3SKirk McKusick #include <sys/stdint.h>
44df8bae1dSRodney W. Grimes #include <sys/namei.h>
45df8bae1dSRodney W. Grimes #include <sys/proc.h>
46df8bae1dSRodney W. Grimes #include <sys/kernel.h>
47763bbd2fSRobert Watson #include <sys/mac.h>
48df8bae1dSRodney W. Grimes #include <sys/vnode.h>
49df8bae1dSRodney W. Grimes #include <sys/mount.h>
509626b608SPoul-Henning Kamp #include <sys/bio.h>
51df8bae1dSRodney W. Grimes #include <sys/buf.h>
5281bca6ddSKATO Takenori #include <sys/conf.h>
533ac4d1efSBruce Evans #include <sys/fcntl.h>
542dd527b3SPoul-Henning Kamp #include <sys/disk.h>
55df8bae1dSRodney W. Grimes #include <sys/malloc.h>
561b367556SJason Evans #include <sys/mutex.h>
57a18b1f1dSJason Evans 
58a64ed089SRobert Watson #include <ufs/ufs/extattr.h>
59df8bae1dSRodney W. Grimes #include <ufs/ufs/quota.h>
60df8bae1dSRodney W. Grimes #include <ufs/ufs/ufsmount.h>
61df8bae1dSRodney W. Grimes #include <ufs/ufs/inode.h>
62df8bae1dSRodney W. Grimes #include <ufs/ufs/ufs_extern.h>
63df8bae1dSRodney W. Grimes 
64df8bae1dSRodney W. Grimes #include <ufs/ffs/fs.h>
65df8bae1dSRodney W. Grimes #include <ufs/ffs/ffs_extern.h>
66df8bae1dSRodney W. Grimes 
67f6b04d2bSDavid Greenman #include <vm/vm.h>
68aa4d7a8aSPoul-Henning Kamp #include <vm/uma.h>
69f6b04d2bSDavid Greenman #include <vm/vm_page.h>
70f6b04d2bSDavid Greenman 
71aa4d7a8aSPoul-Henning Kamp uma_zone_t uma_inode, uma_ufs1, uma_ufs2;
7255166637SPoul-Henning Kamp 
736f1e8551SAlfred Perlstein static int	ffs_sbupdate(struct ufsmount *, int);
746f1e8551SAlfred Perlstein        int	ffs_reload(struct mount *,struct ucred *,struct thread *);
75975512a9SPoul-Henning Kamp static int	ffs_mountfs(struct vnode *, struct mount *, struct thread *);
761c85e6a3SKirk McKusick static void	ffs_oldfscompat_read(struct fs *, struct ufsmount *,
771c85e6a3SKirk McKusick 		    ufs2_daddr_t);
781c85e6a3SKirk McKusick static void	ffs_oldfscompat_write(struct fs *, struct ufsmount *);
79975512a9SPoul-Henning Kamp static void	ffs_ifree(struct ufsmount *ump, struct inode *ip);
809bf1a756SPoul-Henning Kamp static vfs_init_t ffs_init;
819bf1a756SPoul-Henning Kamp static vfs_uninit_t ffs_uninit;
82d6fe88e4SPoul-Henning Kamp static vfs_extattrctl_t ffs_extattrctl;
83df8bae1dSRodney W. Grimes 
84303b270bSEivind Eklund static struct vfsops ufs_vfsops = {
85df8bae1dSRodney W. Grimes 	ffs_mount,
86df8bae1dSRodney W. Grimes 	ufs_start,
87df8bae1dSRodney W. Grimes 	ffs_unmount,
88df8bae1dSRodney W. Grimes 	ufs_root,
89df8bae1dSRodney W. Grimes 	ufs_quotactl,
90df8bae1dSRodney W. Grimes 	ffs_statfs,
91df8bae1dSRodney W. Grimes 	ffs_sync,
92df8bae1dSRodney W. Grimes 	ffs_vget,
93df8bae1dSRodney W. Grimes 	ffs_fhtovp,
94a13234bbSPoul-Henning Kamp 	vfs_stdcheckexp,
95df8bae1dSRodney W. Grimes 	ffs_vptofh,
96df8bae1dSRodney W. Grimes 	ffs_init,
975346934fSIan Dowse 	ffs_uninit,
98d6fe88e4SPoul-Henning Kamp 	ffs_extattrctl,
99df8bae1dSRodney W. Grimes };
100df8bae1dSRodney W. Grimes 
1018994ca3cSBruce Evans VFS_SET(ufs_vfsops, ufs, 0);
102c901836cSGarrett Wollman 
103df8bae1dSRodney W. Grimes /*
1042b14f991SJulian Elischer  * ffs_mount
105df8bae1dSRodney W. Grimes  *
1062b14f991SJulian Elischer  * Called when mounting local physical media
107df8bae1dSRodney W. Grimes  *
1082b14f991SJulian Elischer  * PARAMETERS:
1092b14f991SJulian Elischer  *		mountroot
1102b14f991SJulian Elischer  *			mp	mount point structure
1112b14f991SJulian Elischer  *			path	NULL (flag for root mount!!!)
1122b14f991SJulian Elischer  *			data	<unused>
1132b14f991SJulian Elischer  *			ndp	<unused>
1142b14f991SJulian Elischer  *			p	process (user credentials check [statfs])
1152b14f991SJulian Elischer  *
1162b14f991SJulian Elischer  *		mount
1172b14f991SJulian Elischer  *			mp	mount point structure
1182b14f991SJulian Elischer  *			path	path to mount point
1192b14f991SJulian Elischer  *			data	pointer to argument struct in user space
1202b14f991SJulian Elischer  *			ndp	mount point namei() return (used for
1212b14f991SJulian Elischer  *				credentials on reload), reused to look
1222b14f991SJulian Elischer  *				up block device.
1232b14f991SJulian Elischer  *			p	process (user credentials check)
1242b14f991SJulian Elischer  *
1252b14f991SJulian Elischer  * RETURNS:	0	Success
1262b14f991SJulian Elischer  *		!0	error number (errno.h)
1272b14f991SJulian Elischer  *
1282b14f991SJulian Elischer  * LOCK STATE:
1292b14f991SJulian Elischer  *
1302b14f991SJulian Elischer  *		ENTRY
1312b14f991SJulian Elischer  *			mount point is locked
1322b14f991SJulian Elischer  *		EXIT
1332b14f991SJulian Elischer  *			mount point is locked
1342b14f991SJulian Elischer  *
1352b14f991SJulian Elischer  * NOTES:
1362b14f991SJulian Elischer  *		A NULL path can be used for a flag since the mount
1372b14f991SJulian Elischer  *		system call will fail with EFAULT in copyinstr in
1382b14f991SJulian Elischer  *		namei() if it is a genuine NULL from the user.
139df8bae1dSRodney W. Grimes  */
1400b0c10b4SAdrian Chadd int
141b40ce416SJulian Elischer ffs_mount(mp, path, data, ndp, td)
142996c772fSJohn Dyson         struct mount		*mp;	/* mount struct pointer*/
1432b14f991SJulian Elischer         char			*path;	/* path to mount point*/
1442b14f991SJulian Elischer         caddr_t			data;	/* arguments to FS specific mount*/
1452b14f991SJulian Elischer         struct nameidata	*ndp;	/* mount point credentials*/
146b40ce416SJulian Elischer         struct thread		*td;	/* process requesting mount*/
147df8bae1dSRodney W. Grimes {
1488435e0aeSDoug Rabson 	size_t size;
149df8bae1dSRodney W. Grimes 	struct vnode *devvp;
150df8bae1dSRodney W. Grimes 	struct ufs_args args;
15126f9a767SRodney W. Grimes 	struct ufsmount *ump = 0;
15205f4ff5dSPoul-Henning Kamp 	struct fs *fs;
153f2a2857bSKirk McKusick 	int error, flags;
154c9b99213SBruce Evans 	mode_t accessmode;
155df8bae1dSRodney W. Grimes 
156aa4d7a8aSPoul-Henning Kamp 	if (uma_inode == NULL) {
157aa4d7a8aSPoul-Henning Kamp 		uma_inode = uma_zcreate("FFS inode",
158aa4d7a8aSPoul-Henning Kamp 		    sizeof(struct inode), NULL, NULL, NULL, NULL,
159aa4d7a8aSPoul-Henning Kamp 		    UMA_ALIGN_PTR, 0);
160aa4d7a8aSPoul-Henning Kamp 		uma_ufs1 = uma_zcreate("FFS1 dinode",
161aa4d7a8aSPoul-Henning Kamp 		    sizeof(struct ufs1_dinode), NULL, NULL, NULL, NULL,
162aa4d7a8aSPoul-Henning Kamp 		    UMA_ALIGN_PTR, 0);
163aa4d7a8aSPoul-Henning Kamp 		uma_ufs2 = uma_zcreate("FFS2 dinode",
164aa4d7a8aSPoul-Henning Kamp 		    sizeof(struct ufs2_dinode), NULL, NULL, NULL, NULL,
165aa4d7a8aSPoul-Henning Kamp 		    UMA_ALIGN_PTR, 0);
166aa4d7a8aSPoul-Henning Kamp 	}
1672b14f991SJulian Elischer 	/*
168f2a2857bSKirk McKusick 	 * Use NULL path to indicate we are mounting the root filesystem.
1692b14f991SJulian Elischer 	 */
1702b14f991SJulian Elischer 	if (path == NULL) {
171f2a2857bSKirk McKusick 		if ((error = bdevvp(rootdev, &rootvp))) {
1726d147828SMike Smith 			printf("ffs_mountroot: can't find rootvp\n");
173f2a2857bSKirk McKusick 			return (error);
174996c772fSJohn Dyson 		}
1752b14f991SJulian Elischer 
176975512a9SPoul-Henning Kamp 		if ((error = ffs_mountfs(rootvp, mp, td)) != 0)
177f2a2857bSKirk McKusick 			return (error);
178b40ce416SJulian Elischer 		(void)VFS_STATFS(mp, &mp->mnt_stat, td);
179f2a2857bSKirk McKusick 		return (0);
1802b14f991SJulian Elischer 	}
1812b14f991SJulian Elischer 
1822b14f991SJulian Elischer 	/*
1832b14f991SJulian Elischer 	 * Mounting non-root filesystem or updating a filesystem
1842b14f991SJulian Elischer 	 */
185f2a2857bSKirk McKusick 	if ((error = copyin(data, (caddr_t)&args, sizeof(struct ufs_args)))!= 0)
186f2a2857bSKirk McKusick 		return (error);
1872b14f991SJulian Elischer 
188df8bae1dSRodney W. Grimes 	/*
189df8bae1dSRodney W. Grimes 	 * If updating, check whether changing from read-only to
190df8bae1dSRodney W. Grimes 	 * read/write; if there is no device name, that's all we do.
191df8bae1dSRodney W. Grimes 	 */
192df8bae1dSRodney W. Grimes 	if (mp->mnt_flag & MNT_UPDATE) {
193df8bae1dSRodney W. Grimes 		ump = VFSTOUFS(mp);
194df8bae1dSRodney W. Grimes 		fs = ump->um_fs;
19526cf9c3bSPeter Wemm 		devvp = ump->um_devvp;
196f2a2857bSKirk McKusick 		if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
197f2a2857bSKirk McKusick 			if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0)
198f2a2857bSKirk McKusick 				return (error);
199cd600596SKirk McKusick 			/*
200cd600596SKirk McKusick 			 * Flush any dirty data.
201cd600596SKirk McKusick 			 */
2029ab73fd1SKirk McKusick 			if ((error = VFS_SYNC(mp, MNT_WAIT,
2039ab73fd1SKirk McKusick 			    td->td_proc->p_ucred, td)) != 0) {
2049ab73fd1SKirk McKusick 				vn_finished_write(mp);
2059ab73fd1SKirk McKusick 				return (error);
2069ab73fd1SKirk McKusick 			}
207cd600596SKirk McKusick 			/*
208cd600596SKirk McKusick 			 * Check for and optionally get rid of files open
209cd600596SKirk McKusick 			 * for writing.
210cd600596SKirk McKusick 			 */
211df8bae1dSRodney W. Grimes 			flags = WRITECLOSE;
212df8bae1dSRodney W. Grimes 			if (mp->mnt_flag & MNT_FORCE)
213df8bae1dSRodney W. Grimes 				flags |= FORCECLOSE;
214b1897c19SJulian Elischer 			if (mp->mnt_flag & MNT_SOFTDEP) {
215b40ce416SJulian Elischer 				error = softdep_flushfiles(mp, flags, td);
216b1897c19SJulian Elischer 			} else {
217b40ce416SJulian Elischer 				error = ffs_flushfiles(mp, flags, td);
218df8bae1dSRodney W. Grimes 			}
219f2a2857bSKirk McKusick 			if (error) {
220f2a2857bSKirk McKusick 				vn_finished_write(mp);
221f2a2857bSKirk McKusick 				return (error);
222b1897c19SJulian Elischer 			}
2239ccb939eSKirk McKusick 			if (fs->fs_pendingblocks != 0 ||
2249ccb939eSKirk McKusick 			    fs->fs_pendinginodes != 0) {
225cfbf0a46SMaxime Henrion 				printf("%s: %s: blocks %jd files %d\n",
2261c85e6a3SKirk McKusick 				    fs->fs_fsmnt, "update error",
2271c85e6a3SKirk McKusick 				    (intmax_t)fs->fs_pendingblocks,
2289ccb939eSKirk McKusick 				    fs->fs_pendinginodes);
2299ccb939eSKirk McKusick 				fs->fs_pendingblocks = 0;
2309ccb939eSKirk McKusick 				fs->fs_pendinginodes = 0;
2319ccb939eSKirk McKusick 			}
232f2a2857bSKirk McKusick 			fs->fs_ronly = 1;
2331a6a6610SKirk McKusick 			if ((fs->fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) == 0)
234f2a2857bSKirk McKusick 				fs->fs_clean = 1;
235f2a2857bSKirk McKusick 			if ((error = ffs_sbupdate(ump, MNT_WAIT)) != 0) {
236f2a2857bSKirk McKusick 				fs->fs_ronly = 0;
237f2a2857bSKirk McKusick 				fs->fs_clean = 0;
238f2a2857bSKirk McKusick 				vn_finished_write(mp);
239f2a2857bSKirk McKusick 				return (error);
2402b14f991SJulian Elischer 			}
241f2a2857bSKirk McKusick 			vn_finished_write(mp);
242f2a2857bSKirk McKusick 		}
243f2a2857bSKirk McKusick 		if ((mp->mnt_flag & MNT_RELOAD) &&
244b40ce416SJulian Elischer 		    (error = ffs_reload(mp, ndp->ni_cnd.cn_cred, td)) != 0)
245f2a2857bSKirk McKusick 			return (error);
246f2a2857bSKirk McKusick 		if (fs->fs_ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) {
247c9b99213SBruce Evans 			/*
248c9b99213SBruce Evans 			 * If upgrade to read-write by non-root, then verify
249c9b99213SBruce Evans 			 * that user has necessary permissions on the device.
250c9b99213SBruce Evans 			 */
25144731cabSJohn Baldwin 			if (suser(td)) {
252b40ce416SJulian Elischer 				vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
2538aef1712SMatthew Dillon 				if ((error = VOP_ACCESS(devvp, VREAD | VWRITE,
254a854ed98SJohn Baldwin 				    td->td_ucred, td)) != 0) {
255b40ce416SJulian Elischer 					VOP_UNLOCK(devvp, 0, td);
256c9b99213SBruce Evans 					return (error);
257c9b99213SBruce Evans 				}
258b40ce416SJulian Elischer 				VOP_UNLOCK(devvp, 0, td);
259c9b99213SBruce Evans 			}
2607e58bfacSBruce Evans 			fs->fs_flags &= ~FS_UNCLEAN;
2610922cce6SBruce Evans 			if (fs->fs_clean == 0) {
2627e58bfacSBruce Evans 				fs->fs_flags |= FS_UNCLEAN;
263812b1d41SKirk McKusick 				if ((mp->mnt_flag & MNT_FORCE) ||
2641a6a6610SKirk McKusick 				    ((fs->fs_flags & FS_NEEDSFSCK) == 0 &&
2651a6a6610SKirk McKusick 				     (fs->fs_flags & FS_DOSOFTDEP))) {
266f2a2857bSKirk McKusick 					printf("WARNING: %s was not %s\n",
267f2a2857bSKirk McKusick 					   fs->fs_fsmnt, "properly dismounted");
2680922cce6SBruce Evans 				} else {
2690922cce6SBruce Evans 					printf(
2700922cce6SBruce Evans "WARNING: R/W mount of %s denied.  Filesystem is not clean - run fsck\n",
2710922cce6SBruce Evans 					    fs->fs_fsmnt);
272f2a2857bSKirk McKusick 					return (EPERM);
2730922cce6SBruce Evans 				}
2740922cce6SBruce Evans 			}
275f2a2857bSKirk McKusick 			if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0)
276f2a2857bSKirk McKusick 				return (error);
277f2a2857bSKirk McKusick 			fs->fs_ronly = 0;
278f2a2857bSKirk McKusick 			fs->fs_clean = 0;
279f2a2857bSKirk McKusick 			if ((error = ffs_sbupdate(ump, MNT_WAIT)) != 0) {
280f2a2857bSKirk McKusick 				vn_finished_write(mp);
281f2a2857bSKirk McKusick 				return (error);
282f2a2857bSKirk McKusick 			}
28326cf9c3bSPeter Wemm 			/* check to see if we need to start softdep */
284f2a2857bSKirk McKusick 			if ((fs->fs_flags & FS_DOSOFTDEP) &&
285a854ed98SJohn Baldwin 			    (error = softdep_mount(devvp, mp, fs, td->td_ucred))){
286f2a2857bSKirk McKusick 				vn_finished_write(mp);
287f2a2857bSKirk McKusick 				return (error);
28826cf9c3bSPeter Wemm 			}
289f2a2857bSKirk McKusick 			if (fs->fs_snapinum[0] != 0)
290f2a2857bSKirk McKusick 				ffs_snapshot_mount(mp);
291f2a2857bSKirk McKusick 			vn_finished_write(mp);
2921469eec8SDavid Greenman 		}
293c11d2981SJulian Elischer 		/*
294c11d2981SJulian Elischer 		 * Soft updates is incompatible with "async",
295c11d2981SJulian Elischer 		 * so if we are doing softupdates stop the user
296c11d2981SJulian Elischer 		 * from setting the async flag in an update.
297c11d2981SJulian Elischer 		 * Softdep_mount() clears it in an initial mount
298c11d2981SJulian Elischer 		 * or ro->rw remount.
299c11d2981SJulian Elischer 		 */
300f2a2857bSKirk McKusick 		if (mp->mnt_flag & MNT_SOFTDEP)
301c11d2981SJulian Elischer 			mp->mnt_flag &= ~MNT_ASYNC;
302df8bae1dSRodney W. Grimes 		/*
303f2a2857bSKirk McKusick 		 * If not updating name, process export requests.
304df8bae1dSRodney W. Grimes 		 */
305f2a2857bSKirk McKusick 		if (args.fspec == 0)
306a13234bbSPoul-Henning Kamp 			return (vfs_export(mp, &args.export));
307f2a2857bSKirk McKusick 		/*
308f2a2857bSKirk McKusick 		 * If this is a snapshot request, take the snapshot.
309f2a2857bSKirk McKusick 		 */
310f2a2857bSKirk McKusick 		if (mp->mnt_flag & MNT_SNAPSHOT)
311f2a2857bSKirk McKusick 			return (ffs_snapshot(mp, args.fspec));
312df8bae1dSRodney W. Grimes 	}
3132b14f991SJulian Elischer 
314df8bae1dSRodney W. Grimes 	/*
315df8bae1dSRodney W. Grimes 	 * Not an update, or updating the name: look up the name
316df8bae1dSRodney W. Grimes 	 * and verify that it refers to a sensible block device.
317df8bae1dSRodney W. Grimes 	 */
318b40ce416SJulian Elischer 	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, td);
319f2a2857bSKirk McKusick 	if ((error = namei(ndp)) != 0)
320f2a2857bSKirk McKusick 		return (error);
321762e6b85SEivind Eklund 	NDFREE(ndp, NDF_ONLY_PNBUF);
322df8bae1dSRodney W. Grimes 	devvp = ndp->ni_vp;
323f2a2857bSKirk McKusick 	if (!vn_isdisk(devvp, &error)) {
324f2a2857bSKirk McKusick 		vrele(devvp);
325f2a2857bSKirk McKusick 		return (error);
326f2a2857bSKirk McKusick 	}
327c9b99213SBruce Evans 
328c9b99213SBruce Evans 	/*
329c9b99213SBruce Evans 	 * If mount by non-root, then verify that user has necessary
330c9b99213SBruce Evans 	 * permissions on the device.
331c9b99213SBruce Evans 	 */
33244731cabSJohn Baldwin 	if (suser(td)) {
333c9b99213SBruce Evans 		accessmode = VREAD;
334c9b99213SBruce Evans 		if ((mp->mnt_flag & MNT_RDONLY) == 0)
335c9b99213SBruce Evans 			accessmode |= VWRITE;
336b40ce416SJulian Elischer 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
337a854ed98SJohn Baldwin 		if ((error = VOP_ACCESS(devvp, accessmode, td->td_ucred, td))!= 0){
338c9b99213SBruce Evans 			vput(devvp);
339c9b99213SBruce Evans 			return (error);
340c9b99213SBruce Evans 		}
341b40ce416SJulian Elischer 		VOP_UNLOCK(devvp, 0, td);
342c9b99213SBruce Evans 	}
343c9b99213SBruce Evans 
3442b14f991SJulian Elischer 	if (mp->mnt_flag & MNT_UPDATE) {
3452b14f991SJulian Elischer 		/*
346f2a2857bSKirk McKusick 		 * Update only
347f2a2857bSKirk McKusick 		 *
3483e425b96SJulian Elischer 		 * If it's not the same vnode, or at least the same device
3493e425b96SJulian Elischer 		 * then it's not correct.
3502b14f991SJulian Elischer 		 */
3512b14f991SJulian Elischer 
352f2a2857bSKirk McKusick 		if (devvp != ump->um_devvp &&
353f2a2857bSKirk McKusick 		    devvp->v_rdev != ump->um_devvp->v_rdev)
354f2a2857bSKirk McKusick 			error = EINVAL;	/* needs translation */
3553e425b96SJulian Elischer 		vrele(devvp);
356f2a2857bSKirk McKusick 		if (error)
357f2a2857bSKirk McKusick 			return (error);
3582b14f991SJulian Elischer 	} else {
3592b14f991SJulian Elischer 		/*
360f2a2857bSKirk McKusick 		 * New mount
3612b14f991SJulian Elischer 		 *
362f2a2857bSKirk McKusick 		 * We need the name for the mount point (also used for
363f2a2857bSKirk McKusick 		 * "last mounted on") copied in. If an error occurs,
364f2a2857bSKirk McKusick 		 * the mount point is discarded by the upper level code.
365f3a90da9SAdrian Chadd 		 * Note that vfs_mount() populates f_mntonname for us.
366f2a2857bSKirk McKusick 		 */
367975512a9SPoul-Henning Kamp 		if ((error = ffs_mountfs(devvp, mp, td)) != 0) {
368f2a2857bSKirk McKusick 			vrele(devvp);
369f2a2857bSKirk McKusick 			return (error);
370f2a2857bSKirk McKusick 		}
371f2a2857bSKirk McKusick 	}
372f2a2857bSKirk McKusick 	/*
373f2a2857bSKirk McKusick 	 * Save "mounted from" device name info for mount point (NULL pad).
374f2a2857bSKirk McKusick 	 */
375f2a2857bSKirk McKusick 	copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
376f2a2857bSKirk McKusick 	bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
377f2a2857bSKirk McKusick 	/*
378f2a2857bSKirk McKusick 	 * Initialize filesystem stat information in mount struct.
3792b14f991SJulian Elischer 	 */
380b40ce416SJulian Elischer 	(void)VFS_STATFS(mp, &mp->mnt_stat, td);
381f2a2857bSKirk McKusick 	return (0);
3822b14f991SJulian Elischer }
3832b14f991SJulian Elischer 
384df8bae1dSRodney W. Grimes /*
385df8bae1dSRodney W. Grimes  * Reload all incore data for a filesystem (used after running fsck on
386df8bae1dSRodney W. Grimes  * the root filesystem and finding things to fix). The filesystem must
387df8bae1dSRodney W. Grimes  * be mounted read-only.
388df8bae1dSRodney W. Grimes  *
389df8bae1dSRodney W. Grimes  * Things to do to update the mount:
390df8bae1dSRodney W. Grimes  *	1) invalidate all cached meta-data.
391df8bae1dSRodney W. Grimes  *	2) re-read superblock from disk.
392df8bae1dSRodney W. Grimes  *	3) re-read summary information from disk.
393df8bae1dSRodney W. Grimes  *	4) invalidate all inactive vnodes.
394df8bae1dSRodney W. Grimes  *	5) invalidate all cached file data.
395df8bae1dSRodney W. Grimes  *	6) re-read inode data for all active vnodes.
396df8bae1dSRodney W. Grimes  */
3970b0c10b4SAdrian Chadd int
398b40ce416SJulian Elischer ffs_reload(mp, cred, td)
39905f4ff5dSPoul-Henning Kamp 	struct mount *mp;
400df8bae1dSRodney W. Grimes 	struct ucred *cred;
401b40ce416SJulian Elischer 	struct thread *td;
402df8bae1dSRodney W. Grimes {
40305f4ff5dSPoul-Henning Kamp 	struct vnode *vp, *nvp, *devvp;
404df8bae1dSRodney W. Grimes 	struct inode *ip;
405f55ff3f3SIan Dowse 	void *space;
406df8bae1dSRodney W. Grimes 	struct buf *bp;
407996c772fSJohn Dyson 	struct fs *fs, *newfs;
40895e5e988SJohn Dyson 	dev_t dev;
4091c85e6a3SKirk McKusick 	ufs2_daddr_t sblockloc;
410df8bae1dSRodney W. Grimes 	int i, blks, size, error;
411996c772fSJohn Dyson 	int32_t *lp;
412df8bae1dSRodney W. Grimes 
4132b14f991SJulian Elischer 	if ((mp->mnt_flag & MNT_RDONLY) == 0)
414df8bae1dSRodney W. Grimes 		return (EINVAL);
415df8bae1dSRodney W. Grimes 	/*
416df8bae1dSRodney W. Grimes 	 * Step 1: invalidate all cached meta-data.
417df8bae1dSRodney W. Grimes 	 */
4182b14f991SJulian Elischer 	devvp = VFSTOUFS(mp)->um_devvp;
419b40ce416SJulian Elischer 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
420b40ce416SJulian Elischer 	error = vinvalbuf(devvp, 0, cred, td, 0, 0);
421b40ce416SJulian Elischer 	VOP_UNLOCK(devvp, 0, td);
422b1897c19SJulian Elischer 	if (error)
423df8bae1dSRodney W. Grimes 		panic("ffs_reload: dirty1");
42495e5e988SJohn Dyson 
42595e5e988SJohn Dyson 	dev = devvp->v_rdev;
426b5ee1640SBruce Evans 
42795e5e988SJohn Dyson 	/*
42895e5e988SJohn Dyson 	 * Only VMIO the backing device if the backing device is a real
429c7a3e237SPoul-Henning Kamp 	 * block device.
43095e5e988SJohn Dyson 	 */
431c7a3e237SPoul-Henning Kamp 	if (vn_isdisk(devvp, NULL)) {
432b40ce416SJulian Elischer 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
433a854ed98SJohn Baldwin 		vfs_object_create(devvp, td, td->td_ucred);
4342ee5711eSJeff Roberson 		/* XXX Why lock only to release immediately?? */
4359ed346baSBosko Milekic 		mtx_lock(&devvp->v_interlock);
436b40ce416SJulian Elischer 		VOP_UNLOCK(devvp, LK_INTERLOCK, td);
43795e5e988SJohn Dyson 	}
43895e5e988SJohn Dyson 
439df8bae1dSRodney W. Grimes 	/*
440df8bae1dSRodney W. Grimes 	 * Step 2: re-read superblock from disk.
441df8bae1dSRodney W. Grimes 	 */
4421c85e6a3SKirk McKusick 	fs = VFSTOUFS(mp)->um_fs;
443ada981b2SKirk McKusick 	if ((error = bread(devvp, btodb(fs->fs_sblockloc), fs->fs_sbsize,
4441c85e6a3SKirk McKusick 	    NOCRED, &bp)) != 0)
445df8bae1dSRodney W. Grimes 		return (error);
446996c772fSJohn Dyson 	newfs = (struct fs *)bp->b_data;
4471c85e6a3SKirk McKusick 	if ((newfs->fs_magic != FS_UFS1_MAGIC &&
4481c85e6a3SKirk McKusick 	     newfs->fs_magic != FS_UFS2_MAGIC) ||
4491c85e6a3SKirk McKusick 	    newfs->fs_bsize > MAXBSIZE ||
450996c772fSJohn Dyson 	    newfs->fs_bsize < sizeof(struct fs)) {
451df8bae1dSRodney W. Grimes 			brelse(bp);
452df8bae1dSRodney W. Grimes 			return (EIO);		/* XXX needs translation */
453df8bae1dSRodney W. Grimes 	}
454996c772fSJohn Dyson 	/*
455996c772fSJohn Dyson 	 * Copy pointer fields back into superblock before copying in	XXX
456996c772fSJohn Dyson 	 * new superblock. These should really be in the ufsmount.	XXX
457996c772fSJohn Dyson 	 * Note that important parameters (eg fs_ncg) are unchanged.
458996c772fSJohn Dyson 	 */
459f55ff3f3SIan Dowse 	newfs->fs_csp = fs->fs_csp;
460996c772fSJohn Dyson 	newfs->fs_maxcluster = fs->fs_maxcluster;
4615d69bac4SIan Dowse 	newfs->fs_contigdirs = fs->fs_contigdirs;
462143a5346SIan Dowse 	newfs->fs_active = fs->fs_active;
4631c85e6a3SKirk McKusick 	sblockloc = fs->fs_sblockloc;
464996c772fSJohn Dyson 	bcopy(newfs, fs, (u_int)fs->fs_sbsize);
465df8bae1dSRodney W. Grimes 	brelse(bp);
466996c772fSJohn Dyson 	mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
4671c85e6a3SKirk McKusick 	ffs_oldfscompat_read(fs, VFSTOUFS(mp), sblockloc);
4689ccb939eSKirk McKusick 	if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
469cfbf0a46SMaxime Henrion 		printf("%s: reload pending error: blocks %jd files %d\n",
4701c85e6a3SKirk McKusick 		    fs->fs_fsmnt, (intmax_t)fs->fs_pendingblocks,
4711c85e6a3SKirk McKusick 		    fs->fs_pendinginodes);
4729ccb939eSKirk McKusick 		fs->fs_pendingblocks = 0;
4739ccb939eSKirk McKusick 		fs->fs_pendinginodes = 0;
4749ccb939eSKirk McKusick 	}
475996c772fSJohn Dyson 
476df8bae1dSRodney W. Grimes 	/*
477df8bae1dSRodney W. Grimes 	 * Step 3: re-read summary information from disk.
478df8bae1dSRodney W. Grimes 	 */
479df8bae1dSRodney W. Grimes 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
480f55ff3f3SIan Dowse 	space = fs->fs_csp;
481df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
482df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
483df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
484df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
485c9671602SPoul-Henning Kamp 		error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
486c9671602SPoul-Henning Kamp 		    NOCRED, &bp);
487c9671602SPoul-Henning Kamp 		if (error)
488df8bae1dSRodney W. Grimes 			return (error);
489f55ff3f3SIan Dowse 		bcopy(bp->b_data, space, (u_int)size);
490f55ff3f3SIan Dowse 		space = (char *)space + size;
491df8bae1dSRodney W. Grimes 		brelse(bp);
492df8bae1dSRodney W. Grimes 	}
493996c772fSJohn Dyson 	/*
494996c772fSJohn Dyson 	 * We no longer know anything about clusters per cylinder group.
495996c772fSJohn Dyson 	 */
496996c772fSJohn Dyson 	if (fs->fs_contigsumsize > 0) {
497996c772fSJohn Dyson 		lp = fs->fs_maxcluster;
498996c772fSJohn Dyson 		for (i = 0; i < fs->fs_ncg; i++)
499996c772fSJohn Dyson 			*lp++ = fs->fs_contigsumsize;
500996c772fSJohn Dyson 	}
501996c772fSJohn Dyson 
502df8bae1dSRodney W. Grimes loop:
5039ed346baSBosko Milekic 	mtx_lock(&mntvnode_mtx);
504c72ccd01SMatthew Dillon 	for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist); vp != NULL; vp = nvp) {
505996c772fSJohn Dyson 		if (vp->v_mount != mp) {
5069ed346baSBosko Milekic 			mtx_unlock(&mntvnode_mtx);
507996c772fSJohn Dyson 			goto loop;
508996c772fSJohn Dyson 		}
509c72ccd01SMatthew Dillon 		nvp = TAILQ_NEXT(vp, v_nmntvnodes);
510ed87274dSJohn Baldwin 		mtx_unlock(&mntvnode_mtx);
511df8bae1dSRodney W. Grimes 		/*
512df8bae1dSRodney W. Grimes 		 * Step 4: invalidate all inactive vnodes.
513df8bae1dSRodney W. Grimes 		 */
514b40ce416SJulian Elischer 		if (vrecycle(vp, NULL, td))
515996c772fSJohn Dyson 			goto loop;
516df8bae1dSRodney W. Grimes 		/*
517df8bae1dSRodney W. Grimes 		 * Step 5: invalidate all cached file data.
518df8bae1dSRodney W. Grimes 		 */
5192ee5711eSJeff Roberson 		/* XXX Why lock only to release immediately? */
52049d2d9f4SJohn Baldwin 		mtx_lock(&vp->v_interlock);
521b40ce416SJulian Elischer 		if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) {
522df8bae1dSRodney W. Grimes 			goto loop;
523996c772fSJohn Dyson 		}
524b40ce416SJulian Elischer 		if (vinvalbuf(vp, 0, cred, td, 0, 0))
525df8bae1dSRodney W. Grimes 			panic("ffs_reload: dirty2");
526df8bae1dSRodney W. Grimes 		/*
527df8bae1dSRodney W. Grimes 		 * Step 6: re-read inode data for all active vnodes.
528df8bae1dSRodney W. Grimes 		 */
529df8bae1dSRodney W. Grimes 		ip = VTOI(vp);
530c9671602SPoul-Henning Kamp 		error =
531df8bae1dSRodney W. Grimes 		    bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
532c9671602SPoul-Henning Kamp 		    (int)fs->fs_bsize, NOCRED, &bp);
533c9671602SPoul-Henning Kamp 		if (error) {
534df8bae1dSRodney W. Grimes 			vput(vp);
535df8bae1dSRodney W. Grimes 			return (error);
536df8bae1dSRodney W. Grimes 		}
537de6ba7c0SPoul-Henning Kamp 		ffs_load_inode(bp, ip, fs, ip->i_number);
538b1897c19SJulian Elischer 		ip->i_effnlink = ip->i_nlink;
539df8bae1dSRodney W. Grimes 		brelse(bp);
540df8bae1dSRodney W. Grimes 		vput(vp);
5419ed346baSBosko Milekic 		mtx_lock(&mntvnode_mtx);
542df8bae1dSRodney W. Grimes 	}
5439ed346baSBosko Milekic 	mtx_unlock(&mntvnode_mtx);
544df8bae1dSRodney W. Grimes 	return (0);
545df8bae1dSRodney W. Grimes }
546df8bae1dSRodney W. Grimes 
5471c85e6a3SKirk McKusick /*
5481c85e6a3SKirk McKusick  * Possible superblock locations ordered from most to least likely.
5491c85e6a3SKirk McKusick  */
5501c85e6a3SKirk McKusick static int sblock_try[] = SBLOCKSEARCH;
5515819ab3fSKirk McKusick 
552df8bae1dSRodney W. Grimes /*
553df8bae1dSRodney W. Grimes  * Common code for mount and mountroot
554df8bae1dSRodney W. Grimes  */
555975512a9SPoul-Henning Kamp static int
556975512a9SPoul-Henning Kamp ffs_mountfs(devvp, mp, td)
55705f4ff5dSPoul-Henning Kamp 	struct vnode *devvp;
558df8bae1dSRodney W. Grimes 	struct mount *mp;
559b40ce416SJulian Elischer 	struct thread *td;
560df8bae1dSRodney W. Grimes {
56105f4ff5dSPoul-Henning Kamp 	struct ufsmount *ump;
562df8bae1dSRodney W. Grimes 	struct buf *bp;
56305f4ff5dSPoul-Henning Kamp 	struct fs *fs;
564996c772fSJohn Dyson 	dev_t dev;
565f55ff3f3SIan Dowse 	void *space;
5661c85e6a3SKirk McKusick 	ufs2_daddr_t sblockloc;
567f5ef029eSPoul-Henning Kamp 	int error, i, blks, size, ronly;
568996c772fSJohn Dyson 	int32_t *lp;
569996c772fSJohn Dyson 	struct ucred *cred;
5708435e0aeSDoug Rabson 	size_t strsize;
5716476c0d2SJohn Dyson 	int ncount;
572df8bae1dSRodney W. Grimes 
573996c772fSJohn Dyson 	dev = devvp->v_rdev;
574a854ed98SJohn Baldwin 	cred = td ? td->td_ucred : NOCRED;
575df8bae1dSRodney W. Grimes 	/*
576df8bae1dSRodney W. Grimes 	 * Disallow multiple mounts of the same device.
577df8bae1dSRodney W. Grimes 	 * Disallow mounting of a device that is currently in use
578df8bae1dSRodney W. Grimes 	 * (except for root, which might share swap device for miniroot).
579df8bae1dSRodney W. Grimes 	 * Flush out any old buffers remaining from a previous use.
580df8bae1dSRodney W. Grimes 	 */
581c9671602SPoul-Henning Kamp 	error = vfs_mountedon(devvp);
582c9671602SPoul-Henning Kamp 	if (error)
583df8bae1dSRodney W. Grimes 		return (error);
5846476c0d2SJohn Dyson 	ncount = vcount(devvp);
5858f9110f6SJohn Dyson 
5866476c0d2SJohn Dyson 	if (ncount > 1 && devvp != rootvp)
587df8bae1dSRodney W. Grimes 		return (EBUSY);
588b40ce416SJulian Elischer 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
589b40ce416SJulian Elischer 	error = vinvalbuf(devvp, V_SAVE, cred, td, 0, 0);
590b40ce416SJulian Elischer 	VOP_UNLOCK(devvp, 0, td);
591b1897c19SJulian Elischer 	if (error)
592df8bae1dSRodney W. Grimes 		return (error);
593df8bae1dSRodney W. Grimes 
59495e5e988SJohn Dyson 	/*
59595e5e988SJohn Dyson 	 * Only VMIO the backing device if the backing device is a real
596c7a3e237SPoul-Henning Kamp 	 * block device.
59795e5e988SJohn Dyson 	 * Note that it is optional that the backing device be VMIOed.  This
59895e5e988SJohn Dyson 	 * increases the opportunity for metadata caching.
59995e5e988SJohn Dyson 	 */
600c7a3e237SPoul-Henning Kamp 	if (vn_isdisk(devvp, NULL)) {
601b40ce416SJulian Elischer 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
602b40ce416SJulian Elischer 		vfs_object_create(devvp, td, cred);
6032ee5711eSJeff Roberson 		/* XXX Why lock only to release immediately?? */
6049ed346baSBosko Milekic 		mtx_lock(&devvp->v_interlock);
605b40ce416SJulian Elischer 		VOP_UNLOCK(devvp, LK_INTERLOCK, td);
60695e5e988SJohn Dyson 	}
60795e5e988SJohn Dyson 
608df8bae1dSRodney W. Grimes 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
609b40ce416SJulian Elischer 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
6103dbceccbSPoul-Henning Kamp 	/*
6113dbceccbSPoul-Henning Kamp 	 * XXX: We don't re-VOP_OPEN in FREAD|FWRITE mode if the filesystem
6123dbceccbSPoul-Henning Kamp 	 * XXX: is subsequently remounted, so open it FREAD|FWRITE from the
6133dbceccbSPoul-Henning Kamp 	 * XXX: start to avoid getting trashed later on.
6143dbceccbSPoul-Henning Kamp 	 */
6153dbceccbSPoul-Henning Kamp #ifdef notyet
616b40ce416SJulian Elischer 	error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, td);
6173dbceccbSPoul-Henning Kamp #else
6183dbceccbSPoul-Henning Kamp 	error = VOP_OPEN(devvp, FREAD|FWRITE, FSCRED, td);
6193dbceccbSPoul-Henning Kamp #endif
620b40ce416SJulian Elischer 	VOP_UNLOCK(devvp, 0, td);
621c9671602SPoul-Henning Kamp 	if (error)
622df8bae1dSRodney W. Grimes 		return (error);
6230508986cSBruce Evans 	if (devvp->v_rdev->si_iosize_max != 0)
6241b5464efSPoul-Henning Kamp 		mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max;
6251b5464efSPoul-Henning Kamp 	if (mp->mnt_iosize_max > MAXPHYS)
6261b5464efSPoul-Henning Kamp 		mp->mnt_iosize_max = MAXPHYS;
62795e5e988SJohn Dyson 
628df8bae1dSRodney W. Grimes 	bp = NULL;
629df8bae1dSRodney W. Grimes 	ump = NULL;
6301c85e6a3SKirk McKusick 	fs = NULL;
6311c85e6a3SKirk McKusick 	sblockloc = 0;
6321c85e6a3SKirk McKusick 	/*
6331c85e6a3SKirk McKusick 	 * Try reading the superblock in each of its possible locations.
6341c85e6a3SKirk McKusick 	 */
6351c85e6a3SKirk McKusick 	for (i = 0; sblock_try[i] != -1; i++) {
636b6cef564SKirk McKusick 		if ((error = bread(devvp, sblock_try[i] / DEV_BSIZE, SBLOCKSIZE,
6371c85e6a3SKirk McKusick 		    cred, &bp)) != 0)
638df8bae1dSRodney W. Grimes 			goto out;
639df8bae1dSRodney W. Grimes 		fs = (struct fs *)bp->b_data;
640ada981b2SKirk McKusick 		sblockloc = sblock_try[i];
6411c85e6a3SKirk McKusick 		if ((fs->fs_magic == FS_UFS1_MAGIC ||
6421c85e6a3SKirk McKusick 		     (fs->fs_magic == FS_UFS2_MAGIC &&
643ada981b2SKirk McKusick 		      (fs->fs_sblockloc == sblockloc ||
644ada981b2SKirk McKusick 		       (fs->fs_old_flags & FS_FLAGS_UPDATED) == 0))) &&
6451c85e6a3SKirk McKusick 		    fs->fs_bsize <= MAXBSIZE &&
6461c85e6a3SKirk McKusick 		    fs->fs_bsize >= sizeof(struct fs))
6471c85e6a3SKirk McKusick 			break;
6481c85e6a3SKirk McKusick 		brelse(bp);
6491c85e6a3SKirk McKusick 		bp = NULL;
6501c85e6a3SKirk McKusick 	}
6511c85e6a3SKirk McKusick 	if (sblock_try[i] == -1) {
652df8bae1dSRodney W. Grimes 		error = EINVAL;		/* XXX needs translation */
653df8bae1dSRodney W. Grimes 		goto out;
654df8bae1dSRodney W. Grimes 	}
6553f6f17eeSJulian Elischer 	fs->fs_fmod = 0;
6561c85e6a3SKirk McKusick 	fs->fs_flags &= ~FS_INDEXDIRS;	/* no support for directory indicies */
6570922cce6SBruce Evans 	fs->fs_flags &= ~FS_UNCLEAN;
6580922cce6SBruce Evans 	if (fs->fs_clean == 0) {
6590922cce6SBruce Evans 		fs->fs_flags |= FS_UNCLEAN;
660812b1d41SKirk McKusick 		if (ronly || (mp->mnt_flag & MNT_FORCE) ||
6611a6a6610SKirk McKusick 		    ((fs->fs_flags & FS_NEEDSFSCK) == 0 &&
6621a6a6610SKirk McKusick 		     (fs->fs_flags & FS_DOSOFTDEP))) {
6630922cce6SBruce Evans 			printf(
6640922cce6SBruce Evans "WARNING: %s was not properly dismounted\n",
6650922cce6SBruce Evans 			    fs->fs_fsmnt);
6661469eec8SDavid Greenman 		} else {
6670922cce6SBruce Evans 			printf(
6680922cce6SBruce Evans "WARNING: R/W mount of %s denied.  Filesystem is not clean - run fsck\n",
6690922cce6SBruce Evans 			    fs->fs_fsmnt);
6701469eec8SDavid Greenman 			error = EPERM;
6711469eec8SDavid Greenman 			goto out;
6721469eec8SDavid Greenman 		}
6731c85e6a3SKirk McKusick 		if ((fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) &&
6741c85e6a3SKirk McKusick 		    (mp->mnt_flag & MNT_FORCE)) {
675cfbf0a46SMaxime Henrion 			printf("%s: lost blocks %jd files %d\n", fs->fs_fsmnt,
6761c85e6a3SKirk McKusick 			    (intmax_t)fs->fs_pendingblocks,
6771c85e6a3SKirk McKusick 			    fs->fs_pendinginodes);
6789ccb939eSKirk McKusick 			fs->fs_pendingblocks = 0;
6799ccb939eSKirk McKusick 			fs->fs_pendinginodes = 0;
6809ccb939eSKirk McKusick 		}
6819ccb939eSKirk McKusick 	}
6829ccb939eSKirk McKusick 	if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
683cfbf0a46SMaxime Henrion 		printf("%s: mount pending error: blocks %jd files %d\n",
6841c85e6a3SKirk McKusick 		    fs->fs_fsmnt, (intmax_t)fs->fs_pendingblocks,
6851c85e6a3SKirk McKusick 		    fs->fs_pendinginodes);
6869ccb939eSKirk McKusick 		fs->fs_pendingblocks = 0;
6879ccb939eSKirk McKusick 		fs->fs_pendinginodes = 0;
6881469eec8SDavid Greenman 	}
689a163d034SWarner Losh 	ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK | M_ZERO);
690df8bae1dSRodney W. Grimes 	ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT,
691a163d034SWarner Losh 	    M_WAITOK);
6921c85e6a3SKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC) {
6931c85e6a3SKirk McKusick 		ump->um_fstype = UFS1;
6941c85e6a3SKirk McKusick 		ump->um_balloc = ffs_balloc_ufs1;
6951c85e6a3SKirk McKusick 	} else {
6961c85e6a3SKirk McKusick 		ump->um_fstype = UFS2;
6971c85e6a3SKirk McKusick 		ump->um_balloc = ffs_balloc_ufs2;
6981c85e6a3SKirk McKusick 	}
699cec0f20cSPoul-Henning Kamp 	ump->um_blkatoff = ffs_blkatoff;
700cec0f20cSPoul-Henning Kamp 	ump->um_truncate = ffs_truncate;
701987f5696SPoul-Henning Kamp 	ump->um_update = ffs_update;
702cec0f20cSPoul-Henning Kamp 	ump->um_valloc = ffs_valloc;
703cec0f20cSPoul-Henning Kamp 	ump->um_vfree = ffs_vfree;
704975512a9SPoul-Henning Kamp 	ump->um_ifree = ffs_ifree;
705df8bae1dSRodney W. Grimes 	bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize);
7061c85e6a3SKirk McKusick 	if (fs->fs_sbsize < SBLOCKSIZE)
707f2a2857bSKirk McKusick 		bp->b_flags |= B_INVAL | B_NOCACHE;
708df8bae1dSRodney W. Grimes 	brelse(bp);
709df8bae1dSRodney W. Grimes 	bp = NULL;
710df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
7111c85e6a3SKirk McKusick 	ffs_oldfscompat_read(fs, ump, sblockloc);
712df8bae1dSRodney W. Grimes 	fs->fs_ronly = ronly;
713996c772fSJohn Dyson 	size = fs->fs_cssize;
714996c772fSJohn Dyson 	blks = howmany(size, fs->fs_fsize);
715996c772fSJohn Dyson 	if (fs->fs_contigsumsize > 0)
716996c772fSJohn Dyson 		size += fs->fs_ncg * sizeof(int32_t);
717a61ab64aSKirk McKusick 	size += fs->fs_ncg * sizeof(u_int8_t);
718a163d034SWarner Losh 	space = malloc((u_long)size, M_UFSMNT, M_WAITOK);
719f55ff3f3SIan Dowse 	fs->fs_csp = space;
720df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
721df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
722df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
723df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
7248aef1712SMatthew Dillon 		if ((error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
7258aef1712SMatthew Dillon 		    cred, &bp)) != 0) {
726f55ff3f3SIan Dowse 			free(fs->fs_csp, M_UFSMNT);
727df8bae1dSRodney W. Grimes 			goto out;
728df8bae1dSRodney W. Grimes 		}
729df8bae1dSRodney W. Grimes 		bcopy(bp->b_data, space, (u_int)size);
730f55ff3f3SIan Dowse 		space = (char *)space + size;
731df8bae1dSRodney W. Grimes 		brelse(bp);
732df8bae1dSRodney W. Grimes 		bp = NULL;
733df8bae1dSRodney W. Grimes 	}
734996c772fSJohn Dyson 	if (fs->fs_contigsumsize > 0) {
735f55ff3f3SIan Dowse 		fs->fs_maxcluster = lp = space;
736996c772fSJohn Dyson 		for (i = 0; i < fs->fs_ncg; i++)
737996c772fSJohn Dyson 			*lp++ = fs->fs_contigsumsize;
7384691e9eaSIan Dowse 		space = lp;
739996c772fSJohn Dyson 	}
740a61ab64aSKirk McKusick 	size = fs->fs_ncg * sizeof(u_int8_t);
741a61ab64aSKirk McKusick 	fs->fs_contigdirs = (u_int8_t *)space;
742a61ab64aSKirk McKusick 	bzero(fs->fs_contigdirs, size);
743143a5346SIan Dowse 	fs->fs_active = NULL;
744df8bae1dSRodney W. Grimes 	mp->mnt_data = (qaddr_t)ump;
74568de329eSPoul-Henning Kamp 	mp->mnt_stat.f_fsid.val[0] = fs->fs_id[0];
7468f89943eSGuido van Rooij 	mp->mnt_stat.f_fsid.val[1] = fs->fs_id[1];
74768de329eSPoul-Henning Kamp 	if (fs->fs_id[0] == 0 || fs->fs_id[1] == 0 ||
74868de329eSPoul-Henning Kamp 	    vfs_getvfs(&mp->mnt_stat.f_fsid))
74968de329eSPoul-Henning Kamp 		vfs_getnewfsid(mp);
750df8bae1dSRodney W. Grimes 	mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
751cc9d8990SPeter Wemm 	mp->mnt_flag |= MNT_LOCAL;
75280830407SRobert Watson 	if ((fs->fs_flags & FS_MULTILABEL) != 0)
75380830407SRobert Watson #ifdef MAC
75480830407SRobert Watson 		mp->mnt_flag |= MNT_MULTILABEL;
75580830407SRobert Watson #else
75680830407SRobert Watson 		printf(
75780830407SRobert Watson "WARNING: %s: multilabel flag on fs but no MAC support\n",
75880830407SRobert Watson 		    fs->fs_fsmnt);
75980830407SRobert Watson #endif
76080830407SRobert Watson 	if ((fs->fs_flags & FS_ACLS) != 0)
76180830407SRobert Watson #ifdef UFS_ACL
76280830407SRobert Watson 		mp->mnt_flag |= MNT_ACLS;
76380830407SRobert Watson #else
76480830407SRobert Watson 		printf(
76580830407SRobert Watson "WARNING: %s: ACLs flag on fs but no ACLs support\n",
76680830407SRobert Watson 		    fs->fs_fsmnt);
76780830407SRobert Watson #endif
768df8bae1dSRodney W. Grimes 	ump->um_mountp = mp;
769df8bae1dSRodney W. Grimes 	ump->um_dev = dev;
770df8bae1dSRodney W. Grimes 	ump->um_devvp = devvp;
771df8bae1dSRodney W. Grimes 	ump->um_nindir = fs->fs_nindir;
772df8bae1dSRodney W. Grimes 	ump->um_bptrtodb = fs->fs_fsbtodb;
773df8bae1dSRodney W. Grimes 	ump->um_seqinc = fs->fs_frag;
774df8bae1dSRodney W. Grimes 	for (i = 0; i < MAXQUOTAS; i++)
775df8bae1dSRodney W. Grimes 		ump->um_quotas[i] = NULLVP;
776516081f2SRobert Watson #ifdef UFS_EXTATTR
777a64ed089SRobert Watson 	ufs_extattr_uepm_init(&ump->um_extattr);
778a64ed089SRobert Watson #endif
7797eb9fca5SEivind Eklund 	devvp->v_rdev->si_mountpoint = mp;
7802b14f991SJulian Elischer 
7812b14f991SJulian Elischer 	/*
7822b14f991SJulian Elischer 	 * Set FS local "last mounted on" information (NULL pad)
7832b14f991SJulian Elischer 	 */
7842b14f991SJulian Elischer 	copystr(	mp->mnt_stat.f_mntonname,	/* mount point*/
7852b14f991SJulian Elischer 			fs->fs_fsmnt,			/* copy area*/
7862b14f991SJulian Elischer 			sizeof(fs->fs_fsmnt) - 1,	/* max size*/
7872b14f991SJulian Elischer 			&strsize);			/* real size*/
7882b14f991SJulian Elischer 	bzero( fs->fs_fsmnt + strsize, sizeof(fs->fs_fsmnt) - strsize);
7892b14f991SJulian Elischer 
7902b14f991SJulian Elischer 	if( mp->mnt_flag & MNT_ROOTFS) {
7912b14f991SJulian Elischer 		/*
7922b14f991SJulian Elischer 		 * Root mount; update timestamp in mount structure.
7932b14f991SJulian Elischer 		 * this will be used by the common root mount code
7942b14f991SJulian Elischer 		 * to update the system clock.
7952b14f991SJulian Elischer 		 */
7962b14f991SJulian Elischer 		mp->mnt_time = fs->fs_time;
7972b14f991SJulian Elischer 	}
798996c772fSJohn Dyson 
799996c772fSJohn Dyson 	if (ronly == 0) {
800b1897c19SJulian Elischer 		if ((fs->fs_flags & FS_DOSOFTDEP) &&
801b1897c19SJulian Elischer 		    (error = softdep_mount(devvp, mp, fs, cred)) != 0) {
802f55ff3f3SIan Dowse 			free(fs->fs_csp, M_UFSMNT);
803b1897c19SJulian Elischer 			goto out;
804b1897c19SJulian Elischer 		}
805f2a2857bSKirk McKusick 		if (fs->fs_snapinum[0] != 0)
806f2a2857bSKirk McKusick 			ffs_snapshot_mount(mp);
807cf60e8e4SKirk McKusick 		fs->fs_fmod = 1;
808996c772fSJohn Dyson 		fs->fs_clean = 0;
809996c772fSJohn Dyson 		(void) ffs_sbupdate(ump, MNT_WAIT);
810996c772fSJohn Dyson 	}
811516081f2SRobert Watson #ifdef UFS_EXTATTR
812516081f2SRobert Watson #ifdef UFS_EXTATTR_AUTOSTART
8139de54ba5SRobert Watson 	/*
8149de54ba5SRobert Watson 	 *
815f5161237SRobert Watson 	 * Auto-starting does the following:
8169de54ba5SRobert Watson 	 *	- check for /.attribute in the fs, and extattr_start if so
8179de54ba5SRobert Watson 	 *	- for each file in .attribute, enable that file with
8189de54ba5SRobert Watson 	 * 	  an attribute of the same name.
8199de54ba5SRobert Watson 	 * Not clear how to report errors -- probably eat them.
8209de54ba5SRobert Watson 	 * This would all happen while the filesystem was busy/not
8219de54ba5SRobert Watson 	 * available, so would effectively be "atomic".
8229de54ba5SRobert Watson 	 */
823b40ce416SJulian Elischer 	(void) ufs_extattr_autostart(mp, td);
824516081f2SRobert Watson #endif /* !UFS_EXTATTR_AUTOSTART */
825516081f2SRobert Watson #endif /* !UFS_EXTATTR */
826df8bae1dSRodney W. Grimes 	return (0);
827df8bae1dSRodney W. Grimes out:
8287eb9fca5SEivind Eklund 	devvp->v_rdev->si_mountpoint = NULL;
829df8bae1dSRodney W. Grimes 	if (bp)
830df8bae1dSRodney W. Grimes 		brelse(bp);
8313dbceccbSPoul-Henning Kamp 	/* XXX: see comment above VOP_OPEN */
8323dbceccbSPoul-Henning Kamp #ifdef notyet
833b40ce416SJulian Elischer 	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, td);
8343dbceccbSPoul-Henning Kamp #else
8353dbceccbSPoul-Henning Kamp 	(void)VOP_CLOSE(devvp, FREAD|FWRITE, cred, td);
8363dbceccbSPoul-Henning Kamp #endif
837df8bae1dSRodney W. Grimes 	if (ump) {
838df8bae1dSRodney W. Grimes 		free(ump->um_fs, M_UFSMNT);
839df8bae1dSRodney W. Grimes 		free(ump, M_UFSMNT);
840df8bae1dSRodney W. Grimes 		mp->mnt_data = (qaddr_t)0;
841df8bae1dSRodney W. Grimes 	}
842df8bae1dSRodney W. Grimes 	return (error);
843df8bae1dSRodney W. Grimes }
844df8bae1dSRodney W. Grimes 
8451c85e6a3SKirk McKusick #include <sys/sysctl.h>
8461c85e6a3SKirk McKusick int bigcgs = 0;
8471c85e6a3SKirk McKusick SYSCTL_INT(_debug, OID_AUTO, bigcgs, CTLFLAG_RW, &bigcgs, 0, "");
8481c85e6a3SKirk McKusick 
849df8bae1dSRodney W. Grimes /*
8501c85e6a3SKirk McKusick  * Sanity checks for loading old filesystem superblocks.
8511c85e6a3SKirk McKusick  * See ffs_oldfscompat_write below for unwound actions.
852df8bae1dSRodney W. Grimes  *
8531c85e6a3SKirk McKusick  * XXX - Parts get retired eventually.
8541c85e6a3SKirk McKusick  * Unfortunately new bits get added.
855df8bae1dSRodney W. Grimes  */
8561c85e6a3SKirk McKusick static void
8571c85e6a3SKirk McKusick ffs_oldfscompat_read(fs, ump, sblockloc)
858df8bae1dSRodney W. Grimes 	struct fs *fs;
8591c85e6a3SKirk McKusick 	struct ufsmount *ump;
8601c85e6a3SKirk McKusick 	ufs2_daddr_t sblockloc;
8611c85e6a3SKirk McKusick {
8621c85e6a3SKirk McKusick 	off_t maxfilesize;
8631c85e6a3SKirk McKusick 
8641c85e6a3SKirk McKusick 	/*
865ada981b2SKirk McKusick 	 * If not yet done, update fs_flags location and value of fs_sblockloc.
866ada981b2SKirk McKusick 	 */
867ada981b2SKirk McKusick 	if ((fs->fs_old_flags & FS_FLAGS_UPDATED) == 0) {
868ada981b2SKirk McKusick 		fs->fs_flags = fs->fs_old_flags;
869ada981b2SKirk McKusick 		fs->fs_old_flags |= FS_FLAGS_UPDATED;
870ada981b2SKirk McKusick 		fs->fs_sblockloc = sblockloc;
871ada981b2SKirk McKusick 	}
872ada981b2SKirk McKusick 	/*
8731c85e6a3SKirk McKusick 	 * If not yet done, update UFS1 superblock with new wider fields.
8741c85e6a3SKirk McKusick 	 */
875ada981b2SKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_size != fs->fs_old_size) {
8761c85e6a3SKirk McKusick 		fs->fs_maxbsize = fs->fs_bsize;
8771c85e6a3SKirk McKusick 		fs->fs_time = fs->fs_old_time;
8781c85e6a3SKirk McKusick 		fs->fs_size = fs->fs_old_size;
8791c85e6a3SKirk McKusick 		fs->fs_dsize = fs->fs_old_dsize;
8801c85e6a3SKirk McKusick 		fs->fs_csaddr = fs->fs_old_csaddr;
8811c85e6a3SKirk McKusick 		fs->fs_cstotal.cs_ndir = fs->fs_old_cstotal.cs_ndir;
8821c85e6a3SKirk McKusick 		fs->fs_cstotal.cs_nbfree = fs->fs_old_cstotal.cs_nbfree;
8831c85e6a3SKirk McKusick 		fs->fs_cstotal.cs_nifree = fs->fs_old_cstotal.cs_nifree;
8841c85e6a3SKirk McKusick 		fs->fs_cstotal.cs_nffree = fs->fs_old_cstotal.cs_nffree;
8851c85e6a3SKirk McKusick 	}
8861c85e6a3SKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC &&
8871c85e6a3SKirk McKusick 	    fs->fs_old_inodefmt < FS_44INODEFMT) {
8881c85e6a3SKirk McKusick 		fs->fs_maxfilesize = (u_quad_t) 1LL << 39;
8891c85e6a3SKirk McKusick 		fs->fs_qbmask = ~fs->fs_bmask;
8901c85e6a3SKirk McKusick 		fs->fs_qfmask = ~fs->fs_fmask;
8911c85e6a3SKirk McKusick 	}
8928f42fb8fSIan Dowse 	if (fs->fs_magic == FS_UFS1_MAGIC) {
8931c85e6a3SKirk McKusick 		ump->um_savedmaxfilesize = fs->fs_maxfilesize;
8941c85e6a3SKirk McKusick 		maxfilesize = (u_int64_t)0x40000000 * fs->fs_bsize - 1;
8951c85e6a3SKirk McKusick 		if (fs->fs_maxfilesize > maxfilesize)
8961c85e6a3SKirk McKusick 			fs->fs_maxfilesize = maxfilesize;
8978f42fb8fSIan Dowse 	}
8981c85e6a3SKirk McKusick 	/* Compatibility for old filesystems */
8991c85e6a3SKirk McKusick 	if (fs->fs_avgfilesize <= 0)
9001c85e6a3SKirk McKusick 		fs->fs_avgfilesize = AVFILESIZ;
9011c85e6a3SKirk McKusick 	if (fs->fs_avgfpdir <= 0)
9021c85e6a3SKirk McKusick 		fs->fs_avgfpdir = AFPDIR;
9031c85e6a3SKirk McKusick 	if (bigcgs) {
9041c85e6a3SKirk McKusick 		fs->fs_save_cgsize = fs->fs_cgsize;
9051c85e6a3SKirk McKusick 		fs->fs_cgsize = fs->fs_bsize;
9061c85e6a3SKirk McKusick 	}
9071c85e6a3SKirk McKusick }
9081c85e6a3SKirk McKusick 
9091c85e6a3SKirk McKusick /*
9101c85e6a3SKirk McKusick  * Unwinding superblock updates for old filesystems.
9111c85e6a3SKirk McKusick  * See ffs_oldfscompat_read above for details.
9121c85e6a3SKirk McKusick  *
9131c85e6a3SKirk McKusick  * XXX - Parts get retired eventually.
9141c85e6a3SKirk McKusick  * Unfortunately new bits get added.
9151c85e6a3SKirk McKusick  */
9161c85e6a3SKirk McKusick static void
9171c85e6a3SKirk McKusick ffs_oldfscompat_write(fs, ump)
9181c85e6a3SKirk McKusick 	struct fs *fs;
9191c85e6a3SKirk McKusick 	struct ufsmount *ump;
920df8bae1dSRodney W. Grimes {
921df8bae1dSRodney W. Grimes 
9221c85e6a3SKirk McKusick 	/*
9231c85e6a3SKirk McKusick 	 * Copy back UFS2 updated fields that UFS1 inspects.
9241c85e6a3SKirk McKusick 	 */
9251c85e6a3SKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC) {
9261c85e6a3SKirk McKusick 		fs->fs_old_time = fs->fs_time;
9271c85e6a3SKirk McKusick 		fs->fs_old_cstotal.cs_ndir = fs->fs_cstotal.cs_ndir;
9281c85e6a3SKirk McKusick 		fs->fs_old_cstotal.cs_nbfree = fs->fs_cstotal.cs_nbfree;
9291c85e6a3SKirk McKusick 		fs->fs_old_cstotal.cs_nifree = fs->fs_cstotal.cs_nifree;
9301c85e6a3SKirk McKusick 		fs->fs_old_cstotal.cs_nffree = fs->fs_cstotal.cs_nffree;
9311c85e6a3SKirk McKusick 		fs->fs_maxfilesize = ump->um_savedmaxfilesize;
9328f42fb8fSIan Dowse 	}
9331c85e6a3SKirk McKusick 	if (bigcgs) {
9341c85e6a3SKirk McKusick 		fs->fs_cgsize = fs->fs_save_cgsize;
9351c85e6a3SKirk McKusick 		fs->fs_save_cgsize = 0;
9361c85e6a3SKirk McKusick 	}
937df8bae1dSRodney W. Grimes }
938df8bae1dSRodney W. Grimes 
939df8bae1dSRodney W. Grimes /*
940df8bae1dSRodney W. Grimes  * unmount system call
941df8bae1dSRodney W. Grimes  */
942df8bae1dSRodney W. Grimes int
943b40ce416SJulian Elischer ffs_unmount(mp, mntflags, td)
944df8bae1dSRodney W. Grimes 	struct mount *mp;
945df8bae1dSRodney W. Grimes 	int mntflags;
946b40ce416SJulian Elischer 	struct thread *td;
947df8bae1dSRodney W. Grimes {
94805f4ff5dSPoul-Henning Kamp 	struct ufsmount *ump = VFSTOUFS(mp);
94905f4ff5dSPoul-Henning Kamp 	struct fs *fs;
950996c772fSJohn Dyson 	int error, flags;
951df8bae1dSRodney W. Grimes 
952df8bae1dSRodney W. Grimes 	flags = 0;
953df8bae1dSRodney W. Grimes 	if (mntflags & MNT_FORCE) {
954df8bae1dSRodney W. Grimes 		flags |= FORCECLOSE;
955df8bae1dSRodney W. Grimes 	}
956516081f2SRobert Watson #ifdef UFS_EXTATTR
957b40ce416SJulian Elischer 	if ((error = ufs_extattr_stop(mp, td))) {
958b2b0497aSRobert Watson 		if (error != EOPNOTSUPP)
959b2b0497aSRobert Watson 			printf("ffs_unmount: ufs_extattr_stop returned %d\n",
960b2b0497aSRobert Watson 			    error);
9617df97b61SRobert Watson 	} else {
9629de54ba5SRobert Watson 		ufs_extattr_uepm_destroy(&ump->um_extattr);
9637df97b61SRobert Watson 	}
964a64ed089SRobert Watson #endif
965b1897c19SJulian Elischer 	if (mp->mnt_flag & MNT_SOFTDEP) {
966b40ce416SJulian Elischer 		if ((error = softdep_flushfiles(mp, flags, td)) != 0)
967df8bae1dSRodney W. Grimes 			return (error);
968b1897c19SJulian Elischer 	} else {
969b40ce416SJulian Elischer 		if ((error = ffs_flushfiles(mp, flags, td)) != 0)
970b1897c19SJulian Elischer 			return (error);
971b1897c19SJulian Elischer 	}
972df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
9739ccb939eSKirk McKusick 	if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
974cfbf0a46SMaxime Henrion 		printf("%s: unmount pending error: blocks %jd files %d\n",
9751c85e6a3SKirk McKusick 		    fs->fs_fsmnt, (intmax_t)fs->fs_pendingblocks,
9761c85e6a3SKirk McKusick 		    fs->fs_pendinginodes);
9779ccb939eSKirk McKusick 		fs->fs_pendingblocks = 0;
9789ccb939eSKirk McKusick 		fs->fs_pendinginodes = 0;
9799ccb939eSKirk McKusick 	}
980996c772fSJohn Dyson 	if (fs->fs_ronly == 0) {
9811a6a6610SKirk McKusick 		fs->fs_clean = fs->fs_flags & (FS_UNCLEAN|FS_NEEDSFSCK) ? 0 : 1;
982996c772fSJohn Dyson 		error = ffs_sbupdate(ump, MNT_WAIT);
983996c772fSJohn Dyson 		if (error) {
984996c772fSJohn Dyson 			fs->fs_clean = 0;
985996c772fSJohn Dyson 			return (error);
986996c772fSJohn Dyson 		}
987e0e9c421SDavid Greenman 	}
9887eb9fca5SEivind Eklund 	ump->um_devvp->v_rdev->si_mountpoint = NULL;
9896476c0d2SJohn Dyson 
990b40ce416SJulian Elischer 	vinvalbuf(ump->um_devvp, V_SAVE, NOCRED, td, 0, 0);
991063f7763SPoul-Henning Kamp 	/* XXX: see comment above VOP_OPEN */
992063f7763SPoul-Henning Kamp #ifdef notyet
993996c772fSJohn Dyson 	error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE,
994b40ce416SJulian Elischer 		NOCRED, td);
995063f7763SPoul-Henning Kamp #else
996063f7763SPoul-Henning Kamp 	error = VOP_CLOSE(ump->um_devvp, FREAD|FWRITE, NOCRED, td);
997063f7763SPoul-Henning Kamp #endif
9986476c0d2SJohn Dyson 
9996476c0d2SJohn Dyson 	vrele(ump->um_devvp);
10006476c0d2SJohn Dyson 
1001f55ff3f3SIan Dowse 	free(fs->fs_csp, M_UFSMNT);
1002df8bae1dSRodney W. Grimes 	free(fs, M_UFSMNT);
1003df8bae1dSRodney W. Grimes 	free(ump, M_UFSMNT);
1004df8bae1dSRodney W. Grimes 	mp->mnt_data = (qaddr_t)0;
1005cc9d8990SPeter Wemm 	mp->mnt_flag &= ~MNT_LOCAL;
1006df8bae1dSRodney W. Grimes 	return (error);
1007df8bae1dSRodney W. Grimes }
1008df8bae1dSRodney W. Grimes 
1009df8bae1dSRodney W. Grimes /*
1010df8bae1dSRodney W. Grimes  * Flush out all the files in a filesystem.
1011df8bae1dSRodney W. Grimes  */
101226f9a767SRodney W. Grimes int
1013b40ce416SJulian Elischer ffs_flushfiles(mp, flags, td)
101405f4ff5dSPoul-Henning Kamp 	struct mount *mp;
1015df8bae1dSRodney W. Grimes 	int flags;
1016b40ce416SJulian Elischer 	struct thread *td;
1017df8bae1dSRodney W. Grimes {
101805f4ff5dSPoul-Henning Kamp 	struct ufsmount *ump;
1019c9671602SPoul-Henning Kamp 	int error;
1020df8bae1dSRodney W. Grimes 
1021df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
1022df8bae1dSRodney W. Grimes #ifdef QUOTA
1023df8bae1dSRodney W. Grimes 	if (mp->mnt_flag & MNT_QUOTA) {
1024c1d9efcbSPoul-Henning Kamp 		int i;
10250864ef1eSIan Dowse 		error = vflush(mp, 0, SKIPSYSTEM|flags);
1026c1d9efcbSPoul-Henning Kamp 		if (error)
1027df8bae1dSRodney W. Grimes 			return (error);
1028df8bae1dSRodney W. Grimes 		for (i = 0; i < MAXQUOTAS; i++) {
1029df8bae1dSRodney W. Grimes 			if (ump->um_quotas[i] == NULLVP)
1030df8bae1dSRodney W. Grimes 				continue;
1031b40ce416SJulian Elischer 			quotaoff(td, mp, i);
1032df8bae1dSRodney W. Grimes 		}
1033df8bae1dSRodney W. Grimes 		/*
1034df8bae1dSRodney W. Grimes 		 * Here we fall through to vflush again to ensure
1035df8bae1dSRodney W. Grimes 		 * that we have gotten rid of all the system vnodes.
1036df8bae1dSRodney W. Grimes 		 */
1037df8bae1dSRodney W. Grimes 	}
1038df8bae1dSRodney W. Grimes #endif
1039e6e370a7SJeff Roberson 	ASSERT_VOP_LOCKED(ump->um_devvp, "ffs_flushfiles");
1040e6e370a7SJeff Roberson 	if (ump->um_devvp->v_vflag & VV_COPYONWRITE) {
10410864ef1eSIan Dowse 		if ((error = vflush(mp, 0, SKIPSYSTEM | flags)) != 0)
1042f2a2857bSKirk McKusick 			return (error);
1043f2a2857bSKirk McKusick 		ffs_snapshot_unmount(mp);
1044f2a2857bSKirk McKusick 		/*
1045f2a2857bSKirk McKusick 		 * Here we fall through to vflush again to ensure
1046f2a2857bSKirk McKusick 		 * that we have gotten rid of all the system vnodes.
1047f2a2857bSKirk McKusick 		 */
1048f2a2857bSKirk McKusick 	}
1049b1897c19SJulian Elischer         /*
1050b1897c19SJulian Elischer 	 * Flush all the files.
1051b1897c19SJulian Elischer 	 */
10520864ef1eSIan Dowse 	if ((error = vflush(mp, 0, flags)) != 0)
1053b1897c19SJulian Elischer 		return (error);
1054b1897c19SJulian Elischer 	/*
1055b1897c19SJulian Elischer 	 * Flush filesystem metadata.
1056b1897c19SJulian Elischer 	 */
1057b40ce416SJulian Elischer 	vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, td);
1058a854ed98SJohn Baldwin 	error = VOP_FSYNC(ump->um_devvp, td->td_ucred, MNT_WAIT, td);
1059b40ce416SJulian Elischer 	VOP_UNLOCK(ump->um_devvp, 0, td);
1060df8bae1dSRodney W. Grimes 	return (error);
1061df8bae1dSRodney W. Grimes }
1062df8bae1dSRodney W. Grimes 
1063df8bae1dSRodney W. Grimes /*
1064df8bae1dSRodney W. Grimes  * Get filesystem statistics.
1065df8bae1dSRodney W. Grimes  */
1066df8bae1dSRodney W. Grimes int
1067b40ce416SJulian Elischer ffs_statfs(mp, sbp, td)
1068df8bae1dSRodney W. Grimes 	struct mount *mp;
106905f4ff5dSPoul-Henning Kamp 	struct statfs *sbp;
1070b40ce416SJulian Elischer 	struct thread *td;
1071df8bae1dSRodney W. Grimes {
107205f4ff5dSPoul-Henning Kamp 	struct ufsmount *ump;
107305f4ff5dSPoul-Henning Kamp 	struct fs *fs;
1074df8bae1dSRodney W. Grimes 
1075df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
1076df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
10771c85e6a3SKirk McKusick 	if (fs->fs_magic != FS_UFS1_MAGIC && fs->fs_magic != FS_UFS2_MAGIC)
1078df8bae1dSRodney W. Grimes 		panic("ffs_statfs");
1079df8bae1dSRodney W. Grimes 	sbp->f_bsize = fs->fs_fsize;
1080df8bae1dSRodney W. Grimes 	sbp->f_iosize = fs->fs_bsize;
1081df8bae1dSRodney W. Grimes 	sbp->f_blocks = fs->fs_dsize;
1082df8bae1dSRodney W. Grimes 	sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
10839ccb939eSKirk McKusick 	    fs->fs_cstotal.cs_nffree + dbtofsb(fs, fs->fs_pendingblocks);
10849ccb939eSKirk McKusick 	sbp->f_bavail = freespace(fs, fs->fs_minfree) +
10859ccb939eSKirk McKusick 	    dbtofsb(fs, fs->fs_pendingblocks);
1086df8bae1dSRodney W. Grimes 	sbp->f_files =  fs->fs_ncg * fs->fs_ipg - ROOTINO;
10879ccb939eSKirk McKusick 	sbp->f_ffree = fs->fs_cstotal.cs_nifree + fs->fs_pendinginodes;
1088df8bae1dSRodney W. Grimes 	if (sbp != &mp->mnt_stat) {
1089996c772fSJohn Dyson 		sbp->f_type = mp->mnt_vfc->vfc_typenum;
1090df8bae1dSRodney W. Grimes 		bcopy((caddr_t)mp->mnt_stat.f_mntonname,
1091df8bae1dSRodney W. Grimes 			(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
1092df8bae1dSRodney W. Grimes 		bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
1093df8bae1dSRodney W. Grimes 			(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
1094df8bae1dSRodney W. Grimes 	}
1095df8bae1dSRodney W. Grimes 	return (0);
1096df8bae1dSRodney W. Grimes }
1097df8bae1dSRodney W. Grimes 
1098df8bae1dSRodney W. Grimes /*
1099df8bae1dSRodney W. Grimes  * Go through the disk queues to initiate sandbagged IO;
1100df8bae1dSRodney W. Grimes  * go through the inodes to write those that have been modified;
1101df8bae1dSRodney W. Grimes  * initiate the writing of the super block if it has been modified.
1102df8bae1dSRodney W. Grimes  *
1103df8bae1dSRodney W. Grimes  * Note: we are always called with the filesystem marked `MPBUSY'.
1104df8bae1dSRodney W. Grimes  */
1105df8bae1dSRodney W. Grimes int
1106b40ce416SJulian Elischer ffs_sync(mp, waitfor, cred, td)
1107df8bae1dSRodney W. Grimes 	struct mount *mp;
1108df8bae1dSRodney W. Grimes 	int waitfor;
1109df8bae1dSRodney W. Grimes 	struct ucred *cred;
1110b40ce416SJulian Elischer 	struct thread *td;
1111df8bae1dSRodney W. Grimes {
1112112f7372SKirk McKusick 	struct vnode *nvp, *vp, *devvp;
1113996c772fSJohn Dyson 	struct inode *ip;
1114996c772fSJohn Dyson 	struct ufsmount *ump = VFSTOUFS(mp);
1115996c772fSJohn Dyson 	struct fs *fs;
11169b971133SKirk McKusick 	int error, count, wait, lockreq, allerror = 0;
1117df8bae1dSRodney W. Grimes 
1118df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
1119996c772fSJohn Dyson 	if (fs->fs_fmod != 0 && fs->fs_ronly != 0) {		/* XXX */
1120df8bae1dSRodney W. Grimes 		printf("fs = %s\n", fs->fs_fsmnt);
11215ace3b26SMike Pritchard 		panic("ffs_sync: rofs mod");
1122df8bae1dSRodney W. Grimes 	}
1123df8bae1dSRodney W. Grimes 	/*
1124df8bae1dSRodney W. Grimes 	 * Write back each (modified) inode.
1125df8bae1dSRodney W. Grimes 	 */
11269b971133SKirk McKusick 	wait = 0;
1127245df27cSMatthew Dillon 	lockreq = LK_EXCLUSIVE | LK_NOWAIT;
11289b971133SKirk McKusick 	if (waitfor == MNT_WAIT) {
11299b971133SKirk McKusick 		wait = 1;
1130245df27cSMatthew Dillon 		lockreq = LK_EXCLUSIVE;
11319b971133SKirk McKusick 	}
11329ed346baSBosko Milekic 	mtx_lock(&mntvnode_mtx);
1133df8bae1dSRodney W. Grimes loop:
1134c72ccd01SMatthew Dillon 	for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist); vp != NULL; vp = nvp) {
1135df8bae1dSRodney W. Grimes 		/*
1136df8bae1dSRodney W. Grimes 		 * If the vnode that we are about to sync is no longer
1137df8bae1dSRodney W. Grimes 		 * associated with this mount point, start over.
1138df8bae1dSRodney W. Grimes 		 */
1139df8bae1dSRodney W. Grimes 		if (vp->v_mount != mp)
1140df8bae1dSRodney W. Grimes 			goto loop;
114149d2d9f4SJohn Baldwin 
1142245df27cSMatthew Dillon 		/*
1143245df27cSMatthew Dillon 		 * Depend on the mntvnode_slock to keep things stable enough
1144245df27cSMatthew Dillon 		 * for a quick test.  Since there might be hundreds of
1145245df27cSMatthew Dillon 		 * thousands of vnodes, we cannot afford even a subroutine
1146245df27cSMatthew Dillon 		 * call unless there's a good chance that we have work to do.
1147245df27cSMatthew Dillon 		 */
1148245df27cSMatthew Dillon 		nvp = TAILQ_NEXT(vp, v_nmntvnodes);
1149df8bae1dSRodney W. Grimes 		ip = VTOI(vp);
1150cf60e8e4SKirk McKusick 		if (vp->v_type == VNON || ((ip->i_flag &
1151cf60e8e4SKirk McKusick 		    (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
1152cf60e8e4SKirk McKusick 		    TAILQ_EMPTY(&vp->v_dirtyblkhd))) {
1153df8bae1dSRodney W. Grimes 			continue;
1154996c772fSJohn Dyson 		}
115581c6e3e5SDavid Greenman 		if (vp->v_type != VCHR) {
1156245df27cSMatthew Dillon 			mtx_unlock(&mntvnode_mtx);
1157b40ce416SJulian Elischer 			if ((error = vget(vp, lockreq, td)) != 0) {
11589ed346baSBosko Milekic 				mtx_lock(&mntvnode_mtx);
1159996c772fSJohn Dyson 				if (error == ENOENT)
1160df8bae1dSRodney W. Grimes 					goto loop;
1161245df27cSMatthew Dillon 			} else {
1162b40ce416SJulian Elischer 				if ((error = VOP_FSYNC(vp, cred, waitfor, td)) != 0)
1163df8bae1dSRodney W. Grimes 					allerror = error;
1164b40ce416SJulian Elischer 				VOP_UNLOCK(vp, 0, td);
11658694d8e9SOllivier Robert 				vrele(vp);
116649d2d9f4SJohn Baldwin 				mtx_lock(&mntvnode_mtx);
1167df8bae1dSRodney W. Grimes 			}
1168245df27cSMatthew Dillon 		} else {
1169245df27cSMatthew Dillon 			mtx_unlock(&mntvnode_mtx);
1170245df27cSMatthew Dillon 			UFS_UPDATE(vp, wait);
1171245df27cSMatthew Dillon 			mtx_lock(&mntvnode_mtx);
1172245df27cSMatthew Dillon 		}
1173245df27cSMatthew Dillon 		if (TAILQ_NEXT(vp, v_nmntvnodes) != nvp)
1174245df27cSMatthew Dillon 			goto loop;
1175245df27cSMatthew Dillon 	}
11769ed346baSBosko Milekic 	mtx_unlock(&mntvnode_mtx);
1177df8bae1dSRodney W. Grimes 	/*
1178df8bae1dSRodney W. Grimes 	 * Force stale filesystem control information to be flushed.
1179df8bae1dSRodney W. Grimes 	 */
11809b971133SKirk McKusick 	if (waitfor == MNT_WAIT) {
1181b40ce416SJulian Elischer 		if ((error = softdep_flushworklist(ump->um_mountp, &count, td)))
11829b971133SKirk McKusick 			allerror = error;
11839b971133SKirk McKusick 		/* Flushed work items may create new vnodes to clean */
11849ab73fd1SKirk McKusick 		if (allerror == 0 && count) {
11859ed346baSBosko Milekic 			mtx_lock(&mntvnode_mtx);
11869b971133SKirk McKusick 			goto loop;
11879b971133SKirk McKusick 		}
11889b971133SKirk McKusick 	}
1189589c7af9SKirk McKusick #ifdef QUOTA
1190589c7af9SKirk McKusick 	qsync(mp);
1191589c7af9SKirk McKusick #endif
1192112f7372SKirk McKusick 	devvp = ump->um_devvp;
11932ee5711eSJeff Roberson 	VI_LOCK(devvp);
1194112f7372SKirk McKusick 	if (waitfor != MNT_LAZY &&
1195112f7372SKirk McKusick 	    (devvp->v_numoutput > 0 || TAILQ_FIRST(&devvp->v_dirtyblkhd))) {
11962ee5711eSJeff Roberson 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY | LK_INTERLOCK, td);
1197b40ce416SJulian Elischer 		if ((error = VOP_FSYNC(devvp, cred, waitfor, td)) != 0)
1198df8bae1dSRodney W. Grimes 			allerror = error;
1199b40ce416SJulian Elischer 		VOP_UNLOCK(devvp, 0, td);
12009ab73fd1SKirk McKusick 		if (allerror == 0 && waitfor == MNT_WAIT) {
1201112f7372SKirk McKusick 			mtx_lock(&mntvnode_mtx);
1202112f7372SKirk McKusick 			goto loop;
1203b1897c19SJulian Elischer 		}
1204112f7372SKirk McKusick 	} else
12052ee5711eSJeff Roberson 		VI_UNLOCK(devvp);
1206996c772fSJohn Dyson 	/*
1207996c772fSJohn Dyson 	 * Write back modified superblock.
1208996c772fSJohn Dyson 	 */
1209b1897c19SJulian Elischer 	if (fs->fs_fmod != 0 && (error = ffs_sbupdate(ump, waitfor)) != 0)
1210996c772fSJohn Dyson 		allerror = error;
1211df8bae1dSRodney W. Grimes 	return (allerror);
1212df8bae1dSRodney W. Grimes }
1213df8bae1dSRodney W. Grimes 
1214df8bae1dSRodney W. Grimes int
1215a0595d02SKirk McKusick ffs_vget(mp, ino, flags, vpp)
1216df8bae1dSRodney W. Grimes 	struct mount *mp;
1217df8bae1dSRodney W. Grimes 	ino_t ino;
1218a0595d02SKirk McKusick 	int flags;
1219df8bae1dSRodney W. Grimes 	struct vnode **vpp;
1220df8bae1dSRodney W. Grimes {
1221f576a00dSSemen Ustimenko 	struct thread *td = curthread; 		/* XXX */
1222996c772fSJohn Dyson 	struct fs *fs;
1223996c772fSJohn Dyson 	struct inode *ip;
1224df8bae1dSRodney W. Grimes 	struct ufsmount *ump;
1225df8bae1dSRodney W. Grimes 	struct buf *bp;
1226df8bae1dSRodney W. Grimes 	struct vnode *vp;
1227df8bae1dSRodney W. Grimes 	dev_t dev;
1228f576a00dSSemen Ustimenko 	int error;
1229df8bae1dSRodney W. Grimes 
1230df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
1231df8bae1dSRodney W. Grimes 	dev = ump->um_dev;
1232f576a00dSSemen Ustimenko 
1233f576a00dSSemen Ustimenko 	/*
123413866b3fSSemen Ustimenko 	 * We do not lock vnode creation as it is believed to be too
1235f576a00dSSemen Ustimenko 	 * expensive for such rare case as simultaneous creation of vnode
1236f576a00dSSemen Ustimenko 	 * for same ino by different processes. We just allow them to race
1237f576a00dSSemen Ustimenko 	 * and check later to decide who wins. Let the race begin!
1238f576a00dSSemen Ustimenko 	 */
1239a0595d02SKirk McKusick 	if ((error = ufs_ihashget(dev, ino, flags, vpp)) != 0)
1240a0595d02SKirk McKusick 		return (error);
1241a0595d02SKirk McKusick 	if (*vpp != NULL)
1242df8bae1dSRodney W. Grimes 		return (0);
1243df8bae1dSRodney W. Grimes 
12442094ddb6SDavid Greenman 	/*
12452f9bae59SDavid Greenman 	 * If this MALLOC() is performed after the getnewvnode()
12462f9bae59SDavid Greenman 	 * it might block, leaving a vnode with a NULL v_data to be
12472f9bae59SDavid Greenman 	 * found by ffs_sync() if a sync happens to fire right then,
12482f9bae59SDavid Greenman 	 * which will cause a panic because ffs_sync() blindly
12492f9bae59SDavid Greenman 	 * dereferences vp->v_data (as well it should).
12502f9bae59SDavid Greenman 	 */
1251a163d034SWarner Losh 	ip = uma_zalloc(uma_inode, M_WAITOK);
12522f9bae59SDavid Greenman 
1253df8bae1dSRodney W. Grimes 	/* Allocate a new vnode/inode. */
125406be2aaaSNate Lawson 	error = getnewvnode("ufs", mp, ffs_vnodeop_p, &vp);
1255c9671602SPoul-Henning Kamp 	if (error) {
1256df8bae1dSRodney W. Grimes 		*vpp = NULL;
1257aa4d7a8aSPoul-Henning Kamp 		uma_zfree(uma_inode, ip);
1258df8bae1dSRodney W. Grimes 		return (error);
1259df8bae1dSRodney W. Grimes 	}
1260df8bae1dSRodney W. Grimes 	bzero((caddr_t)ip, sizeof(struct inode));
126167e87166SBoris Popov 	/*
1262a5b65058SKirk McKusick 	 * FFS supports recursive locking.
126367e87166SBoris Popov 	 */
1264a5b65058SKirk McKusick 	vp->v_vnlock->lk_flags |= LK_CANRECURSE;
1265df8bae1dSRodney W. Grimes 	vp->v_data = ip;
1266df8bae1dSRodney W. Grimes 	ip->i_vnode = vp;
12671c85e6a3SKirk McKusick 	ip->i_ump = ump;
1268df8bae1dSRodney W. Grimes 	ip->i_fs = fs = ump->um_fs;
1269df8bae1dSRodney W. Grimes 	ip->i_dev = dev;
1270df8bae1dSRodney W. Grimes 	ip->i_number = ino;
1271df8bae1dSRodney W. Grimes #ifdef QUOTA
1272c1d9efcbSPoul-Henning Kamp 	{
1273c1d9efcbSPoul-Henning Kamp 		int i;
1274df8bae1dSRodney W. Grimes 		for (i = 0; i < MAXQUOTAS; i++)
1275df8bae1dSRodney W. Grimes 			ip->i_dquot[i] = NODQUOT;
1276c1d9efcbSPoul-Henning Kamp 	}
1277df8bae1dSRodney W. Grimes #endif
1278df8bae1dSRodney W. Grimes 	/*
1279f576a00dSSemen Ustimenko 	 * Exclusively lock the vnode before adding to hash. Note, that we
1280f576a00dSSemen Ustimenko 	 * must not release nor downgrade the lock (despite flags argument
1281f576a00dSSemen Ustimenko 	 * says) till it is fully initialized.
1282df8bae1dSRodney W. Grimes 	 */
1283f576a00dSSemen Ustimenko 	lockmgr(vp->v_vnlock, LK_EXCLUSIVE, (struct mtx *)0, td);
1284df8bae1dSRodney W. Grimes 
1285937c4dfaSSeigo Tanimura 	/*
1286f576a00dSSemen Ustimenko 	 * Atomicaly (in terms of ufs_hash operations) check the hash for
1287f576a00dSSemen Ustimenko 	 * duplicate of vnode being created and add it to the hash. If a
1288f576a00dSSemen Ustimenko 	 * duplicate vnode was found, it will be vget()ed from hash for us.
1289937c4dfaSSeigo Tanimura 	 */
1290f576a00dSSemen Ustimenko 	if ((error = ufs_ihashins(ip, flags, vpp)) != 0) {
1291f576a00dSSemen Ustimenko 		vput(vp);
1292f576a00dSSemen Ustimenko 		*vpp = NULL;
1293f576a00dSSemen Ustimenko 		return (error);
1294f576a00dSSemen Ustimenko 	}
1295f576a00dSSemen Ustimenko 
1296f576a00dSSemen Ustimenko 	/* We lost the race, then throw away our vnode and return existing */
1297f576a00dSSemen Ustimenko 	if (*vpp != NULL) {
1298f576a00dSSemen Ustimenko 		vput(vp);
1299f576a00dSSemen Ustimenko 		return (0);
1300f576a00dSSemen Ustimenko 	}
13012094ddb6SDavid Greenman 
1302df8bae1dSRodney W. Grimes 	/* Read in the disk contents for the inode, copy into the inode. */
1303c9671602SPoul-Henning Kamp 	error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
1304c9671602SPoul-Henning Kamp 	    (int)fs->fs_bsize, NOCRED, &bp);
1305c9671602SPoul-Henning Kamp 	if (error) {
1306df8bae1dSRodney W. Grimes 		/*
1307df8bae1dSRodney W. Grimes 		 * The inode does not contain anything useful, so it would
1308df8bae1dSRodney W. Grimes 		 * be misleading to leave it on its hash chain. With mode
1309df8bae1dSRodney W. Grimes 		 * still zero, it will be unlinked and returned to the free
1310df8bae1dSRodney W. Grimes 		 * list by vput().
1311df8bae1dSRodney W. Grimes 		 */
1312df8bae1dSRodney W. Grimes 		brelse(bp);
1313bd7e5f99SJohn Dyson 		vput(vp);
1314df8bae1dSRodney W. Grimes 		*vpp = NULL;
1315df8bae1dSRodney W. Grimes 		return (error);
1316df8bae1dSRodney W. Grimes 	}
1317de6ba7c0SPoul-Henning Kamp 	if (ip->i_ump->um_fstype == UFS1)
1318a163d034SWarner Losh 		ip->i_din1 = uma_zalloc(uma_ufs1, M_WAITOK);
1319de6ba7c0SPoul-Henning Kamp 	else
1320a163d034SWarner Losh 		ip->i_din2 = uma_zalloc(uma_ufs2, M_WAITOK);
1321de6ba7c0SPoul-Henning Kamp 	ffs_load_inode(bp, ip, fs, ino);
1322b1897c19SJulian Elischer 	if (DOINGSOFTDEP(vp))
1323b1897c19SJulian Elischer 		softdep_load_inodeblock(ip);
1324b1897c19SJulian Elischer 	else
1325b1897c19SJulian Elischer 		ip->i_effnlink = ip->i_nlink;
1326bd7e5f99SJohn Dyson 	bqrelse(bp);
1327df8bae1dSRodney W. Grimes 
1328df8bae1dSRodney W. Grimes 	/*
1329df8bae1dSRodney W. Grimes 	 * Initialize the vnode from the inode, check for aliases.
1330df8bae1dSRodney W. Grimes 	 * Note that the underlying vnode may have changed.
1331df8bae1dSRodney W. Grimes 	 */
1332e6302eabSBruce Evans 	error = ufs_vinit(mp, ffs_specop_p, ffs_fifoop_p, &vp);
1333c9671602SPoul-Henning Kamp 	if (error) {
1334df8bae1dSRodney W. Grimes 		vput(vp);
1335df8bae1dSRodney W. Grimes 		*vpp = NULL;
1336df8bae1dSRodney W. Grimes 		return (error);
1337df8bae1dSRodney W. Grimes 	}
1338df8bae1dSRodney W. Grimes 	/*
1339df8bae1dSRodney W. Grimes 	 * Finish inode initialization now that aliasing has been resolved.
1340df8bae1dSRodney W. Grimes 	 */
1341df8bae1dSRodney W. Grimes 	ip->i_devvp = ump->um_devvp;
1342df8bae1dSRodney W. Grimes 	VREF(ip->i_devvp);
1343df8bae1dSRodney W. Grimes 	/*
1344df8bae1dSRodney W. Grimes 	 * Set up a generation number for this inode if it does not
1345df8bae1dSRodney W. Grimes 	 * already have one. This should only happen on old filesystems.
1346df8bae1dSRodney W. Grimes 	 */
1347df8bae1dSRodney W. Grimes 	if (ip->i_gen == 0) {
1348aca3e497SKirk McKusick 		ip->i_gen = arc4random() / 2 + 1;
13491c85e6a3SKirk McKusick 		if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
1350df8bae1dSRodney W. Grimes 			ip->i_flag |= IN_MODIFIED;
13511c85e6a3SKirk McKusick 			DIP(ip, i_gen) = ip->i_gen;
13521c85e6a3SKirk McKusick 		}
1353df8bae1dSRodney W. Grimes 	}
1354df8bae1dSRodney W. Grimes 	/*
1355df8bae1dSRodney W. Grimes 	 * Ensure that uid and gid are correct. This is a temporary
1356df8bae1dSRodney W. Grimes 	 * fix until fsck has been changed to do the update.
1357df8bae1dSRodney W. Grimes 	 */
13581c85e6a3SKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC &&		/* XXX */
13591c85e6a3SKirk McKusick 	    fs->fs_old_inodefmt < FS_44INODEFMT) {	/* XXX */
13601c85e6a3SKirk McKusick 		ip->i_uid = ip->i_din1->di_ouid;	/* XXX */
13611c85e6a3SKirk McKusick 		ip->i_gid = ip->i_din1->di_ogid;	/* XXX */
1362df8bae1dSRodney W. Grimes 	}						/* XXX */
1363df8bae1dSRodney W. Grimes 
1364763bbd2fSRobert Watson #ifdef MAC
1365763bbd2fSRobert Watson 	if ((mp->mnt_flag & MNT_MULTILABEL) && ip->i_mode) {
1366763bbd2fSRobert Watson 		/*
1367763bbd2fSRobert Watson 		 * If this vnode is already allocated, and we're running
1368763bbd2fSRobert Watson 		 * multi-label, attempt to perform a label association
1369763bbd2fSRobert Watson 		 * from the extended attributes on the inode.
1370763bbd2fSRobert Watson 		 */
1371763bbd2fSRobert Watson 		error = mac_associate_vnode_extattr(mp, vp);
1372763bbd2fSRobert Watson 		if (error) {
1373763bbd2fSRobert Watson 			/* ufs_inactive will release ip->i_devvp ref. */
1374763bbd2fSRobert Watson 			vput(vp);
1375763bbd2fSRobert Watson 			*vpp = NULL;
1376763bbd2fSRobert Watson 			return (error);
1377763bbd2fSRobert Watson 		}
1378763bbd2fSRobert Watson 	}
1379763bbd2fSRobert Watson #endif
1380763bbd2fSRobert Watson 
1381df8bae1dSRodney W. Grimes 	*vpp = vp;
1382df8bae1dSRodney W. Grimes 	return (0);
1383df8bae1dSRodney W. Grimes }
1384df8bae1dSRodney W. Grimes 
1385df8bae1dSRodney W. Grimes /*
1386df8bae1dSRodney W. Grimes  * File handle to vnode
1387df8bae1dSRodney W. Grimes  *
1388df8bae1dSRodney W. Grimes  * Have to be really careful about stale file handles:
1389df8bae1dSRodney W. Grimes  * - check that the inode number is valid
1390df8bae1dSRodney W. Grimes  * - call ffs_vget() to get the locked inode
1391df8bae1dSRodney W. Grimes  * - check for an unallocated inode (i_mode == 0)
1392df8bae1dSRodney W. Grimes  * - check that the given client host has export rights and return
1393df8bae1dSRodney W. Grimes  *   those rights via. exflagsp and credanonp
1394df8bae1dSRodney W. Grimes  */
1395df8bae1dSRodney W. Grimes int
1396c24fda81SAlfred Perlstein ffs_fhtovp(mp, fhp, vpp)
139705f4ff5dSPoul-Henning Kamp 	struct mount *mp;
1398df8bae1dSRodney W. Grimes 	struct fid *fhp;
1399df8bae1dSRodney W. Grimes 	struct vnode **vpp;
1400df8bae1dSRodney W. Grimes {
140105f4ff5dSPoul-Henning Kamp 	struct ufid *ufhp;
1402df8bae1dSRodney W. Grimes 	struct fs *fs;
1403df8bae1dSRodney W. Grimes 
1404df8bae1dSRodney W. Grimes 	ufhp = (struct ufid *)fhp;
1405df8bae1dSRodney W. Grimes 	fs = VFSTOUFS(mp)->um_fs;
1406df8bae1dSRodney W. Grimes 	if (ufhp->ufid_ino < ROOTINO ||
1407df8bae1dSRodney W. Grimes 	    ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg)
1408df8bae1dSRodney W. Grimes 		return (ESTALE);
1409c24fda81SAlfred Perlstein 	return (ufs_fhtovp(mp, ufhp, vpp));
1410df8bae1dSRodney W. Grimes }
1411df8bae1dSRodney W. Grimes 
1412df8bae1dSRodney W. Grimes /*
1413df8bae1dSRodney W. Grimes  * Vnode pointer to File handle
1414df8bae1dSRodney W. Grimes  */
1415df8bae1dSRodney W. Grimes /* ARGSUSED */
141626f9a767SRodney W. Grimes int
1417df8bae1dSRodney W. Grimes ffs_vptofh(vp, fhp)
1418df8bae1dSRodney W. Grimes 	struct vnode *vp;
1419df8bae1dSRodney W. Grimes 	struct fid *fhp;
1420df8bae1dSRodney W. Grimes {
142105f4ff5dSPoul-Henning Kamp 	struct inode *ip;
142205f4ff5dSPoul-Henning Kamp 	struct ufid *ufhp;
1423df8bae1dSRodney W. Grimes 
1424df8bae1dSRodney W. Grimes 	ip = VTOI(vp);
1425df8bae1dSRodney W. Grimes 	ufhp = (struct ufid *)fhp;
1426df8bae1dSRodney W. Grimes 	ufhp->ufid_len = sizeof(struct ufid);
1427df8bae1dSRodney W. Grimes 	ufhp->ufid_ino = ip->i_number;
1428df8bae1dSRodney W. Grimes 	ufhp->ufid_gen = ip->i_gen;
1429df8bae1dSRodney W. Grimes 	return (0);
1430df8bae1dSRodney W. Grimes }
1431df8bae1dSRodney W. Grimes 
1432df8bae1dSRodney W. Grimes /*
14335346934fSIan Dowse  * Initialize the filesystem.
1434996c772fSJohn Dyson  */
1435996c772fSJohn Dyson static int
1436996c772fSJohn Dyson ffs_init(vfsp)
1437996c772fSJohn Dyson 	struct vfsconf *vfsp;
1438996c772fSJohn Dyson {
1439996c772fSJohn Dyson 
1440b1897c19SJulian Elischer 	softdep_initialize();
1441996c772fSJohn Dyson 	return (ufs_init(vfsp));
1442996c772fSJohn Dyson }
1443996c772fSJohn Dyson 
1444996c772fSJohn Dyson /*
14455346934fSIan Dowse  * Undo the work of ffs_init().
14465346934fSIan Dowse  */
14475346934fSIan Dowse static int
14485346934fSIan Dowse ffs_uninit(vfsp)
14495346934fSIan Dowse 	struct vfsconf *vfsp;
14505346934fSIan Dowse {
14515346934fSIan Dowse 	int ret;
14525346934fSIan Dowse 
14535346934fSIan Dowse 	ret = ufs_uninit(vfsp);
14545346934fSIan Dowse 	softdep_uninitialize();
14555346934fSIan Dowse 	return (ret);
14565346934fSIan Dowse }
14575346934fSIan Dowse 
14585346934fSIan Dowse /*
1459df8bae1dSRodney W. Grimes  * Write a superblock and associated information back to disk.
1460df8bae1dSRodney W. Grimes  */
1461b8dce649SPoul-Henning Kamp static int
1462df8bae1dSRodney W. Grimes ffs_sbupdate(mp, waitfor)
1463df8bae1dSRodney W. Grimes 	struct ufsmount *mp;
1464df8bae1dSRodney W. Grimes 	int waitfor;
1465df8bae1dSRodney W. Grimes {
14661c85e6a3SKirk McKusick 	struct fs *fs = mp->um_fs;
146705f4ff5dSPoul-Henning Kamp 	struct buf *bp;
1468df8bae1dSRodney W. Grimes 	int blks;
1469f55ff3f3SIan Dowse 	void *space;
1470996c772fSJohn Dyson 	int i, size, error, allerror = 0;
1471df8bae1dSRodney W. Grimes 
1472996c772fSJohn Dyson 	/*
1473996c772fSJohn Dyson 	 * First write back the summary information.
1474996c772fSJohn Dyson 	 */
1475df8bae1dSRodney W. Grimes 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
1476f55ff3f3SIan Dowse 	space = fs->fs_csp;
1477df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
1478df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
1479df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
1480df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
1481df8bae1dSRodney W. Grimes 		bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i),
1482df8bae1dSRodney W. Grimes 		    size, 0, 0);
1483df8bae1dSRodney W. Grimes 		bcopy(space, bp->b_data, (u_int)size);
1484f55ff3f3SIan Dowse 		space = (char *)space + size;
1485996c772fSJohn Dyson 		if (waitfor != MNT_WAIT)
1486df8bae1dSRodney W. Grimes 			bawrite(bp);
14878aef1712SMatthew Dillon 		else if ((error = bwrite(bp)) != 0)
1488996c772fSJohn Dyson 			allerror = error;
1489df8bae1dSRodney W. Grimes 	}
1490996c772fSJohn Dyson 	/*
1491996c772fSJohn Dyson 	 * Now write back the superblock itself. If any errors occurred
1492996c772fSJohn Dyson 	 * up to this point, then fail so that the superblock avoids
1493996c772fSJohn Dyson 	 * being written out as clean.
1494996c772fSJohn Dyson 	 */
1495996c772fSJohn Dyson 	if (allerror)
1496996c772fSJohn Dyson 		return (allerror);
149731574422SKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_sblockloc != SBLOCK_UFS1 &&
149831574422SKirk McKusick 	    (fs->fs_flags & FS_FLAGS_UPDATED) == 0) {
1499fa5d33e2SKirk McKusick 		printf("%s: correcting fs_sblockloc from %jd to %d\n",
1500fa5d33e2SKirk McKusick 		    fs->fs_fsmnt, fs->fs_sblockloc, SBLOCK_UFS1);
1501fa5d33e2SKirk McKusick 		fs->fs_sblockloc = SBLOCK_UFS1;
1502fa5d33e2SKirk McKusick 	}
150331574422SKirk McKusick 	if (fs->fs_magic == FS_UFS2_MAGIC && fs->fs_sblockloc != SBLOCK_UFS2 &&
150431574422SKirk McKusick 	    (fs->fs_flags & FS_FLAGS_UPDATED) == 0) {
1505fa5d33e2SKirk McKusick 		printf("%s: correcting fs_sblockloc from %jd to %d\n",
1506fa5d33e2SKirk McKusick 		    fs->fs_fsmnt, fs->fs_sblockloc, SBLOCK_UFS2);
1507fa5d33e2SKirk McKusick 		fs->fs_sblockloc = SBLOCK_UFS2;
1508fa5d33e2SKirk McKusick 	}
1509ada981b2SKirk McKusick 	bp = getblk(mp->um_devvp, btodb(fs->fs_sblockloc), (int)fs->fs_sbsize,
1510ada981b2SKirk McKusick 	    0, 0);
1511b1897c19SJulian Elischer 	fs->fs_fmod = 0;
1512227ee8a1SPoul-Henning Kamp 	fs->fs_time = time_second;
1513996c772fSJohn Dyson 	bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize);
15141c85e6a3SKirk McKusick 	ffs_oldfscompat_write((struct fs *)bp->b_data, mp);
1515996c772fSJohn Dyson 	if (waitfor != MNT_WAIT)
1516996c772fSJohn Dyson 		bawrite(bp);
15178aef1712SMatthew Dillon 	else if ((error = bwrite(bp)) != 0)
1518996c772fSJohn Dyson 		allerror = error;
1519996c772fSJohn Dyson 	return (allerror);
1520df8bae1dSRodney W. Grimes }
1521d6fe88e4SPoul-Henning Kamp 
1522d6fe88e4SPoul-Henning Kamp static int
1523d6fe88e4SPoul-Henning Kamp ffs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp,
1524d6fe88e4SPoul-Henning Kamp 	int attrnamespace, const char *attrname, struct thread *td)
1525d6fe88e4SPoul-Henning Kamp {
1526d6fe88e4SPoul-Henning Kamp 
1527d6fe88e4SPoul-Henning Kamp #ifdef UFS_EXTATTR
1528d6fe88e4SPoul-Henning Kamp 	return (ufs_extattrctl(mp, cmd, filename_vp, attrnamespace,
1529d6fe88e4SPoul-Henning Kamp 	    attrname, td));
1530d6fe88e4SPoul-Henning Kamp #else
1531d6fe88e4SPoul-Henning Kamp 	return (vfs_stdextattrctl(mp, cmd, filename_vp, attrnamespace,
1532d6fe88e4SPoul-Henning Kamp 	    attrname, td));
1533d6fe88e4SPoul-Henning Kamp #endif
1534d6fe88e4SPoul-Henning Kamp }
1535975512a9SPoul-Henning Kamp 
1536975512a9SPoul-Henning Kamp static void
1537975512a9SPoul-Henning Kamp ffs_ifree(struct ufsmount *ump, struct inode *ip)
1538975512a9SPoul-Henning Kamp {
1539975512a9SPoul-Henning Kamp 
1540975512a9SPoul-Henning Kamp 	if (ump->um_fstype == UFS1)
1541aa4d7a8aSPoul-Henning Kamp 		uma_zfree(uma_ufs1, ip->i_din1);
1542975512a9SPoul-Henning Kamp 	else
1543aa4d7a8aSPoul-Henning Kamp 		uma_zfree(uma_ufs2, ip->i_din1);
1544aa4d7a8aSPoul-Henning Kamp 	uma_zfree(uma_inode, ip);
1545975512a9SPoul-Henning Kamp }
1546