xref: /freebsd/sys/ufs/ffs/ffs_vfsops.c (revision 6e77a04170db6c8a1a87918dd1baff938ac3dc98)
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  * 4. Neither the name of the University nor the names of its contributors
14df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
15df8bae1dSRodney W. Grimes  *    without specific prior written permission.
16df8bae1dSRodney W. Grimes  *
17df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
28df8bae1dSRodney W. Grimes  *
29996c772fSJohn Dyson  *	@(#)ffs_vfsops.c	8.31 (Berkeley) 5/20/95
30df8bae1dSRodney W. Grimes  */
31df8bae1dSRodney W. Grimes 
32f4636c59SDavid E. O'Brien #include <sys/cdefs.h>
33f4636c59SDavid E. O'Brien __FBSDID("$FreeBSD$");
34f4636c59SDavid E. O'Brien 
3580830407SRobert Watson #include "opt_mac.h"
3601733a9bSGarrett Wollman #include "opt_quota.h"
37516081f2SRobert Watson #include "opt_ufs.h"
386e77a041SPoul-Henning Kamp #include "opt_ffs.h"
3901733a9bSGarrett Wollman 
40df8bae1dSRodney W. Grimes #include <sys/param.h>
41df8bae1dSRodney W. Grimes #include <sys/systm.h>
42df8bae1dSRodney W. Grimes #include <sys/namei.h>
43df8bae1dSRodney W. Grimes #include <sys/proc.h>
44df8bae1dSRodney W. Grimes #include <sys/kernel.h>
45763bbd2fSRobert Watson #include <sys/mac.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>
66aa4d7a8aSPoul-Henning Kamp #include <vm/uma.h>
67f6b04d2bSDavid Greenman #include <vm/vm_page.h>
68f6b04d2bSDavid Greenman 
69aa4d7a8aSPoul-Henning Kamp uma_zone_t uma_inode, uma_ufs1, uma_ufs2;
7055166637SPoul-Henning Kamp 
716f1e8551SAlfred Perlstein static int	ffs_sbupdate(struct ufsmount *, int);
725e8c582aSPoul-Henning Kamp static int	ffs_reload(struct mount *, struct thread *);
73975512a9SPoul-Henning Kamp static int	ffs_mountfs(struct vnode *, struct mount *, struct thread *);
741c85e6a3SKirk McKusick static void	ffs_oldfscompat_read(struct fs *, struct ufsmount *,
751c85e6a3SKirk McKusick 		    ufs2_daddr_t);
761c85e6a3SKirk McKusick static void	ffs_oldfscompat_write(struct fs *, struct ufsmount *);
77975512a9SPoul-Henning Kamp static void	ffs_ifree(struct ufsmount *ump, struct inode *ip);
789bf1a756SPoul-Henning Kamp static vfs_init_t ffs_init;
799bf1a756SPoul-Henning Kamp static vfs_uninit_t ffs_uninit;
80d6fe88e4SPoul-Henning Kamp static vfs_extattrctl_t ffs_extattrctl;
815e8c582aSPoul-Henning Kamp static vfs_omount_t ffs_omount;
82df8bae1dSRodney W. Grimes 
83303b270bSEivind Eklund static struct vfsops ufs_vfsops = {
847652131bSPoul-Henning Kamp 	.vfs_extattrctl =	ffs_extattrctl,
857652131bSPoul-Henning Kamp 	.vfs_fhtovp =		ffs_fhtovp,
867652131bSPoul-Henning Kamp 	.vfs_init =		ffs_init,
875e8c582aSPoul-Henning Kamp 	.vfs_omount =		ffs_omount,
887652131bSPoul-Henning Kamp 	.vfs_quotactl =		ufs_quotactl,
897652131bSPoul-Henning Kamp 	.vfs_root =		ufs_root,
907652131bSPoul-Henning Kamp 	.vfs_start =		ufs_start,
917652131bSPoul-Henning Kamp 	.vfs_statfs =		ffs_statfs,
927652131bSPoul-Henning Kamp 	.vfs_sync =		ffs_sync,
937652131bSPoul-Henning Kamp 	.vfs_uninit =		ffs_uninit,
947652131bSPoul-Henning Kamp 	.vfs_unmount =		ffs_unmount,
957652131bSPoul-Henning Kamp 	.vfs_vget =		ffs_vget,
967652131bSPoul-Henning Kamp 	.vfs_vptofh =		ffs_vptofh,
97df8bae1dSRodney W. Grimes };
98df8bae1dSRodney W. Grimes 
998994ca3cSBruce Evans VFS_SET(ufs_vfsops, ufs, 0);
100c901836cSGarrett Wollman 
1016e77a041SPoul-Henning Kamp static b_strategy_t ffs_geom_strategy;
1026e77a041SPoul-Henning Kamp 
1036e77a041SPoul-Henning Kamp static struct buf_ops ffs_ops = {
1046e77a041SPoul-Henning Kamp 	.bop_name =     "FFS",
1056e77a041SPoul-Henning Kamp 	.bop_write =    bufwrite,
1066e77a041SPoul-Henning Kamp 	.bop_strategy = ffs_geom_strategy,
1076e77a041SPoul-Henning Kamp };
1086e77a041SPoul-Henning Kamp 
109df8bae1dSRodney W. Grimes /*
1105e8c582aSPoul-Henning Kamp  * ffs_omount
111df8bae1dSRodney W. Grimes  *
1122b14f991SJulian Elischer  * Called when mounting local physical media
113df8bae1dSRodney W. Grimes  *
1142b14f991SJulian Elischer  * PARAMETERS:
1152b14f991SJulian Elischer  *		mountroot
1162b14f991SJulian Elischer  *			mp	mount point structure
1172b14f991SJulian Elischer  *			path	NULL (flag for root mount!!!)
1182b14f991SJulian Elischer  *			data	<unused>
1192b14f991SJulian Elischer  *			ndp	<unused>
1202b14f991SJulian Elischer  *			p	process (user credentials check [statfs])
1212b14f991SJulian Elischer  *
1222b14f991SJulian Elischer  *		mount
1232b14f991SJulian Elischer  *			mp	mount point structure
1242b14f991SJulian Elischer  *			path	path to mount point
1252b14f991SJulian Elischer  *			data	pointer to argument struct in user space
1262b14f991SJulian Elischer  *			ndp	mount point namei() return (used for
1272b14f991SJulian Elischer  *				credentials on reload), reused to look
1282b14f991SJulian Elischer  *				up block device.
1292b14f991SJulian Elischer  *			p	process (user credentials check)
1302b14f991SJulian Elischer  *
1312b14f991SJulian Elischer  * RETURNS:	0	Success
1322b14f991SJulian Elischer  *		!0	error number (errno.h)
1332b14f991SJulian Elischer  *
1342b14f991SJulian Elischer  * LOCK STATE:
1352b14f991SJulian Elischer  *
1362b14f991SJulian Elischer  *		ENTRY
1372b14f991SJulian Elischer  *			mount point is locked
1382b14f991SJulian Elischer  *		EXIT
1392b14f991SJulian Elischer  *			mount point is locked
1402b14f991SJulian Elischer  *
1412b14f991SJulian Elischer  * NOTES:
1422b14f991SJulian Elischer  *		A NULL path can be used for a flag since the mount
1432b14f991SJulian Elischer  *		system call will fail with EFAULT in copyinstr in
1442b14f991SJulian Elischer  *		namei() if it is a genuine NULL from the user.
145df8bae1dSRodney W. Grimes  */
1465e8c582aSPoul-Henning Kamp static int
1475e8c582aSPoul-Henning Kamp ffs_omount(struct mount *mp, char *path, caddr_t data, struct thread *td)
148df8bae1dSRodney W. Grimes {
1498435e0aeSDoug Rabson 	size_t size;
150d634f693SPoul-Henning Kamp 	struct vnode *devvp, *rootvp;
151df8bae1dSRodney W. Grimes 	struct ufs_args args;
15226f9a767SRodney W. Grimes 	struct ufsmount *ump = 0;
15305f4ff5dSPoul-Henning Kamp 	struct fs *fs;
154f2a2857bSKirk McKusick 	int error, flags;
155c9b99213SBruce Evans 	mode_t accessmode;
1565e8c582aSPoul-Henning Kamp 	struct nameidata ndp;
157df8bae1dSRodney W. Grimes 
158aa4d7a8aSPoul-Henning Kamp 	if (uma_inode == NULL) {
159aa4d7a8aSPoul-Henning Kamp 		uma_inode = uma_zcreate("FFS inode",
160aa4d7a8aSPoul-Henning Kamp 		    sizeof(struct inode), NULL, NULL, NULL, NULL,
161aa4d7a8aSPoul-Henning Kamp 		    UMA_ALIGN_PTR, 0);
162aa4d7a8aSPoul-Henning Kamp 		uma_ufs1 = uma_zcreate("FFS1 dinode",
163aa4d7a8aSPoul-Henning Kamp 		    sizeof(struct ufs1_dinode), NULL, NULL, NULL, NULL,
164aa4d7a8aSPoul-Henning Kamp 		    UMA_ALIGN_PTR, 0);
165aa4d7a8aSPoul-Henning Kamp 		uma_ufs2 = uma_zcreate("FFS2 dinode",
166aa4d7a8aSPoul-Henning Kamp 		    sizeof(struct ufs2_dinode), NULL, NULL, NULL, NULL,
167aa4d7a8aSPoul-Henning Kamp 		    UMA_ALIGN_PTR, 0);
168aa4d7a8aSPoul-Henning Kamp 	}
1692b14f991SJulian Elischer 	/*
170f2a2857bSKirk McKusick 	 * Use NULL path to indicate we are mounting the root filesystem.
1712b14f991SJulian Elischer 	 */
1722b14f991SJulian Elischer 	if (path == NULL) {
1738d02a378SPawel Jakub Dawidek 		if ((error = bdevvp(rootdev, &rootvp))) {
1748d02a378SPawel Jakub Dawidek 			printf("ffs_mountroot: can't find rootvp\n");
175f2a2857bSKirk McKusick 			return (error);
1768d02a378SPawel Jakub Dawidek 		}
1778d02a378SPawel Jakub Dawidek 
178975512a9SPoul-Henning Kamp 		if ((error = ffs_mountfs(rootvp, mp, td)) != 0)
179f2a2857bSKirk McKusick 			return (error);
180f2a2857bSKirk McKusick 		return (0);
1812b14f991SJulian Elischer 	}
1822b14f991SJulian Elischer 
1832b14f991SJulian Elischer 	/*
1842b14f991SJulian Elischer 	 * Mounting non-root filesystem or updating a filesystem
1852b14f991SJulian Elischer 	 */
186f2a2857bSKirk McKusick 	if ((error = copyin(data, (caddr_t)&args, sizeof(struct ufs_args)))!= 0)
187f2a2857bSKirk McKusick 		return (error);
1882b14f991SJulian Elischer 
189df8bae1dSRodney W. Grimes 	/*
190df8bae1dSRodney W. Grimes 	 * If updating, check whether changing from read-only to
191df8bae1dSRodney W. Grimes 	 * read/write; if there is no device name, that's all we do.
192df8bae1dSRodney W. Grimes 	 */
193df8bae1dSRodney W. Grimes 	if (mp->mnt_flag & MNT_UPDATE) {
194df8bae1dSRodney W. Grimes 		ump = VFSTOUFS(mp);
195df8bae1dSRodney W. Grimes 		fs = ump->um_fs;
19626cf9c3bSPeter Wemm 		devvp = ump->um_devvp;
197f2a2857bSKirk McKusick 		if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
198f2a2857bSKirk McKusick 			if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0)
199f2a2857bSKirk McKusick 				return (error);
200cd600596SKirk McKusick 			/*
201cd600596SKirk McKusick 			 * Flush any dirty data.
202cd600596SKirk McKusick 			 */
2039ab73fd1SKirk McKusick 			if ((error = VFS_SYNC(mp, MNT_WAIT,
20431566c96SJohn Baldwin 			    td->td_ucred, td)) != 0) {
2059ab73fd1SKirk McKusick 				vn_finished_write(mp);
2069ab73fd1SKirk McKusick 				return (error);
2079ab73fd1SKirk McKusick 			}
208cd600596SKirk McKusick 			/*
209cd600596SKirk McKusick 			 * Check for and optionally get rid of files open
210cd600596SKirk McKusick 			 * for writing.
211cd600596SKirk McKusick 			 */
212df8bae1dSRodney W. Grimes 			flags = WRITECLOSE;
213df8bae1dSRodney W. Grimes 			if (mp->mnt_flag & MNT_FORCE)
214df8bae1dSRodney W. Grimes 				flags |= FORCECLOSE;
215b1897c19SJulian Elischer 			if (mp->mnt_flag & MNT_SOFTDEP) {
216b40ce416SJulian Elischer 				error = softdep_flushfiles(mp, flags, td);
217b1897c19SJulian Elischer 			} else {
218b40ce416SJulian Elischer 				error = ffs_flushfiles(mp, flags, td);
219df8bae1dSRodney W. Grimes 			}
220f2a2857bSKirk McKusick 			if (error) {
221f2a2857bSKirk McKusick 				vn_finished_write(mp);
222f2a2857bSKirk McKusick 				return (error);
223b1897c19SJulian Elischer 			}
2249ccb939eSKirk McKusick 			if (fs->fs_pendingblocks != 0 ||
2259ccb939eSKirk McKusick 			    fs->fs_pendinginodes != 0) {
226cfbf0a46SMaxime Henrion 				printf("%s: %s: blocks %jd files %d\n",
2271c85e6a3SKirk McKusick 				    fs->fs_fsmnt, "update error",
2281c85e6a3SKirk McKusick 				    (intmax_t)fs->fs_pendingblocks,
2299ccb939eSKirk McKusick 				    fs->fs_pendinginodes);
2309ccb939eSKirk McKusick 				fs->fs_pendingblocks = 0;
2319ccb939eSKirk McKusick 				fs->fs_pendinginodes = 0;
2329ccb939eSKirk McKusick 			}
233f2a2857bSKirk McKusick 			fs->fs_ronly = 1;
2341a6a6610SKirk McKusick 			if ((fs->fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) == 0)
235f2a2857bSKirk McKusick 				fs->fs_clean = 1;
236f2a2857bSKirk McKusick 			if ((error = ffs_sbupdate(ump, MNT_WAIT)) != 0) {
237f2a2857bSKirk McKusick 				fs->fs_ronly = 0;
238f2a2857bSKirk McKusick 				fs->fs_clean = 0;
239f2a2857bSKirk McKusick 				vn_finished_write(mp);
240f2a2857bSKirk McKusick 				return (error);
2412b14f991SJulian Elischer 			}
242f2a2857bSKirk McKusick 			vn_finished_write(mp);
243f2a2857bSKirk McKusick 		}
244f2a2857bSKirk McKusick 		if ((mp->mnt_flag & MNT_RELOAD) &&
2455e8c582aSPoul-Henning Kamp 		    (error = ffs_reload(mp, td)) != 0)
246f2a2857bSKirk McKusick 			return (error);
247f2a2857bSKirk McKusick 		if (fs->fs_ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) {
248c9b99213SBruce Evans 			/*
249c9b99213SBruce Evans 			 * If upgrade to read-write by non-root, then verify
250c9b99213SBruce Evans 			 * that user has necessary permissions on the device.
251c9b99213SBruce Evans 			 */
25244731cabSJohn Baldwin 			if (suser(td)) {
253b40ce416SJulian Elischer 				vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
2548aef1712SMatthew Dillon 				if ((error = VOP_ACCESS(devvp, VREAD | VWRITE,
255a854ed98SJohn Baldwin 				    td->td_ucred, td)) != 0) {
256b40ce416SJulian Elischer 					VOP_UNLOCK(devvp, 0, td);
257c9b99213SBruce Evans 					return (error);
258c9b99213SBruce Evans 				}
259b40ce416SJulian Elischer 				VOP_UNLOCK(devvp, 0, td);
260c9b99213SBruce Evans 			}
2617e58bfacSBruce Evans 			fs->fs_flags &= ~FS_UNCLEAN;
2620922cce6SBruce Evans 			if (fs->fs_clean == 0) {
2637e58bfacSBruce Evans 				fs->fs_flags |= FS_UNCLEAN;
264812b1d41SKirk McKusick 				if ((mp->mnt_flag & MNT_FORCE) ||
2651a6a6610SKirk McKusick 				    ((fs->fs_flags & FS_NEEDSFSCK) == 0 &&
2661a6a6610SKirk McKusick 				     (fs->fs_flags & FS_DOSOFTDEP))) {
267f2a2857bSKirk McKusick 					printf("WARNING: %s was not %s\n",
268f2a2857bSKirk McKusick 					   fs->fs_fsmnt, "properly dismounted");
2690922cce6SBruce Evans 				} else {
2700922cce6SBruce Evans 					printf(
2710922cce6SBruce Evans "WARNING: R/W mount of %s denied.  Filesystem is not clean - run fsck\n",
2720922cce6SBruce Evans 					    fs->fs_fsmnt);
273f2a2857bSKirk McKusick 					return (EPERM);
2740922cce6SBruce Evans 				}
2750922cce6SBruce Evans 			}
276f2a2857bSKirk McKusick 			if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0)
277f2a2857bSKirk McKusick 				return (error);
278f2a2857bSKirk McKusick 			fs->fs_ronly = 0;
279f2a2857bSKirk McKusick 			fs->fs_clean = 0;
280f2a2857bSKirk McKusick 			if ((error = ffs_sbupdate(ump, MNT_WAIT)) != 0) {
281f2a2857bSKirk McKusick 				vn_finished_write(mp);
282f2a2857bSKirk McKusick 				return (error);
283f2a2857bSKirk McKusick 			}
28426cf9c3bSPeter Wemm 			/* check to see if we need to start softdep */
285f2a2857bSKirk McKusick 			if ((fs->fs_flags & FS_DOSOFTDEP) &&
286a854ed98SJohn Baldwin 			    (error = softdep_mount(devvp, mp, fs, td->td_ucred))){
287f2a2857bSKirk McKusick 				vn_finished_write(mp);
288f2a2857bSKirk McKusick 				return (error);
28926cf9c3bSPeter Wemm 			}
290f2a2857bSKirk McKusick 			if (fs->fs_snapinum[0] != 0)
291f2a2857bSKirk McKusick 				ffs_snapshot_mount(mp);
292f2a2857bSKirk McKusick 			vn_finished_write(mp);
2931469eec8SDavid Greenman 		}
294c11d2981SJulian Elischer 		/*
295c11d2981SJulian Elischer 		 * Soft updates is incompatible with "async",
296c11d2981SJulian Elischer 		 * so if we are doing softupdates stop the user
297c11d2981SJulian Elischer 		 * from setting the async flag in an update.
298c11d2981SJulian Elischer 		 * Softdep_mount() clears it in an initial mount
299c11d2981SJulian Elischer 		 * or ro->rw remount.
300c11d2981SJulian Elischer 		 */
301f2a2857bSKirk McKusick 		if (mp->mnt_flag & MNT_SOFTDEP)
302c11d2981SJulian Elischer 			mp->mnt_flag &= ~MNT_ASYNC;
303df8bae1dSRodney W. Grimes 		/*
304f2a2857bSKirk McKusick 		 * If not updating name, process export requests.
305df8bae1dSRodney W. Grimes 		 */
306f2a2857bSKirk McKusick 		if (args.fspec == 0)
307a13234bbSPoul-Henning Kamp 			return (vfs_export(mp, &args.export));
308f2a2857bSKirk McKusick 		/*
309f2a2857bSKirk McKusick 		 * If this is a snapshot request, take the snapshot.
310f2a2857bSKirk McKusick 		 */
311f2a2857bSKirk McKusick 		if (mp->mnt_flag & MNT_SNAPSHOT)
312f2a2857bSKirk McKusick 			return (ffs_snapshot(mp, args.fspec));
313df8bae1dSRodney W. Grimes 	}
3142b14f991SJulian Elischer 
315df8bae1dSRodney W. Grimes 	/*
316df8bae1dSRodney W. Grimes 	 * Not an update, or updating the name: look up the name
317e9827c6dSBruce Evans 	 * and verify that it refers to a sensible disk device.
318df8bae1dSRodney W. Grimes 	 */
3195e8c582aSPoul-Henning Kamp 	NDINIT(&ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, td);
3205e8c582aSPoul-Henning Kamp 	if ((error = namei(&ndp)) != 0)
321f2a2857bSKirk McKusick 		return (error);
3225e8c582aSPoul-Henning Kamp 	NDFREE(&ndp, NDF_ONLY_PNBUF);
3235e8c582aSPoul-Henning Kamp 	devvp = ndp.ni_vp;
324f2a2857bSKirk McKusick 	if (!vn_isdisk(devvp, &error)) {
325f2a2857bSKirk McKusick 		vrele(devvp);
326f2a2857bSKirk McKusick 		return (error);
327f2a2857bSKirk McKusick 	}
328c9b99213SBruce Evans 
329c9b99213SBruce Evans 	/*
330c9b99213SBruce Evans 	 * If mount by non-root, then verify that user has necessary
331c9b99213SBruce Evans 	 * permissions on the device.
332c9b99213SBruce Evans 	 */
33344731cabSJohn Baldwin 	if (suser(td)) {
334c9b99213SBruce Evans 		accessmode = VREAD;
335c9b99213SBruce Evans 		if ((mp->mnt_flag & MNT_RDONLY) == 0)
336c9b99213SBruce Evans 			accessmode |= VWRITE;
337b40ce416SJulian Elischer 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
338a854ed98SJohn Baldwin 		if ((error = VOP_ACCESS(devvp, accessmode, td->td_ucred, td))!= 0){
339c9b99213SBruce Evans 			vput(devvp);
340c9b99213SBruce Evans 			return (error);
341c9b99213SBruce Evans 		}
342b40ce416SJulian Elischer 		VOP_UNLOCK(devvp, 0, td);
343c9b99213SBruce Evans 	}
344c9b99213SBruce Evans 
3452b14f991SJulian Elischer 	if (mp->mnt_flag & MNT_UPDATE) {
3462b14f991SJulian Elischer 		/*
347f2a2857bSKirk McKusick 		 * Update only
348f2a2857bSKirk McKusick 		 *
3493e425b96SJulian Elischer 		 * If it's not the same vnode, or at least the same device
3503e425b96SJulian Elischer 		 * then it's not correct.
3512b14f991SJulian Elischer 		 */
3522b14f991SJulian Elischer 
353f2a2857bSKirk McKusick 		if (devvp != ump->um_devvp &&
354f2a2857bSKirk McKusick 		    devvp->v_rdev != ump->um_devvp->v_rdev)
355f2a2857bSKirk McKusick 			error = EINVAL;	/* needs translation */
3563e425b96SJulian Elischer 		vrele(devvp);
357f2a2857bSKirk McKusick 		if (error)
358f2a2857bSKirk McKusick 			return (error);
3592b14f991SJulian Elischer 	} else {
3602b14f991SJulian Elischer 		/*
361f2a2857bSKirk McKusick 		 * New mount
3622b14f991SJulian Elischer 		 *
363f2a2857bSKirk McKusick 		 * We need the name for the mount point (also used for
364f2a2857bSKirk McKusick 		 * "last mounted on") copied in. If an error occurs,
365f2a2857bSKirk McKusick 		 * the mount point is discarded by the upper level code.
366f3a90da9SAdrian Chadd 		 * Note that vfs_mount() populates f_mntonname for us.
367f2a2857bSKirk McKusick 		 */
368975512a9SPoul-Henning Kamp 		if ((error = ffs_mountfs(devvp, mp, td)) != 0) {
369f2a2857bSKirk McKusick 			vrele(devvp);
370f2a2857bSKirk McKusick 			return (error);
371f2a2857bSKirk McKusick 		}
372f2a2857bSKirk McKusick 	}
373f2a2857bSKirk McKusick 	/*
374f2a2857bSKirk McKusick 	 * Save "mounted from" device name info for mount point (NULL pad).
375f2a2857bSKirk McKusick 	 */
376f2a2857bSKirk McKusick 	copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
377f2a2857bSKirk McKusick 	bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
378f2a2857bSKirk McKusick 	return (0);
3792b14f991SJulian Elischer }
3802b14f991SJulian Elischer 
381df8bae1dSRodney W. Grimes /*
382df8bae1dSRodney W. Grimes  * Reload all incore data for a filesystem (used after running fsck on
383df8bae1dSRodney W. Grimes  * the root filesystem and finding things to fix). The filesystem must
384df8bae1dSRodney W. Grimes  * be mounted read-only.
385df8bae1dSRodney W. Grimes  *
386df8bae1dSRodney W. Grimes  * Things to do to update the mount:
387df8bae1dSRodney W. Grimes  *	1) invalidate all cached meta-data.
388df8bae1dSRodney W. Grimes  *	2) re-read superblock from disk.
389df8bae1dSRodney W. Grimes  *	3) re-read summary information from disk.
390df8bae1dSRodney W. Grimes  *	4) invalidate all inactive vnodes.
391df8bae1dSRodney W. Grimes  *	5) invalidate all cached file data.
392df8bae1dSRodney W. Grimes  *	6) re-read inode data for all active vnodes.
393df8bae1dSRodney W. Grimes  */
3945e8c582aSPoul-Henning Kamp static int
3955e8c582aSPoul-Henning Kamp ffs_reload(struct mount *mp, struct thread *td)
396df8bae1dSRodney W. Grimes {
39705f4ff5dSPoul-Henning Kamp 	struct vnode *vp, *nvp, *devvp;
398df8bae1dSRodney W. Grimes 	struct inode *ip;
399f55ff3f3SIan Dowse 	void *space;
400df8bae1dSRodney W. Grimes 	struct buf *bp;
401996c772fSJohn Dyson 	struct fs *fs, *newfs;
4021c85e6a3SKirk McKusick 	ufs2_daddr_t sblockloc;
403df8bae1dSRodney W. Grimes 	int i, blks, size, error;
404996c772fSJohn Dyson 	int32_t *lp;
405df8bae1dSRodney W. Grimes 
4062b14f991SJulian Elischer 	if ((mp->mnt_flag & MNT_RDONLY) == 0)
407df8bae1dSRodney W. Grimes 		return (EINVAL);
408df8bae1dSRodney W. Grimes 	/*
409df8bae1dSRodney W. Grimes 	 * Step 1: invalidate all cached meta-data.
410df8bae1dSRodney W. Grimes 	 */
4112b14f991SJulian Elischer 	devvp = VFSTOUFS(mp)->um_devvp;
412b40ce416SJulian Elischer 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
4135e8c582aSPoul-Henning Kamp 	if (vinvalbuf(devvp, 0, td->td_ucred, td, 0, 0) != 0)
414df8bae1dSRodney W. Grimes 		panic("ffs_reload: dirty1");
41595e5e988SJohn Dyson 	/*
41695e5e988SJohn Dyson 	 * Only VMIO the backing device if the backing device is a real
417e9827c6dSBruce Evans 	 * disk device.  See ffs_mountfs() for more details.
41895e5e988SJohn Dyson 	 */
419e9827c6dSBruce Evans 	if (vn_isdisk(devvp, NULL))
420a854ed98SJohn Baldwin 		vfs_object_create(devvp, td, td->td_ucred);
42104a17687SJeff Roberson 	VOP_UNLOCK(devvp, 0, td);
42295e5e988SJohn Dyson 
423df8bae1dSRodney W. Grimes 	/*
424df8bae1dSRodney W. Grimes 	 * Step 2: re-read superblock from disk.
425df8bae1dSRodney W. Grimes 	 */
4261c85e6a3SKirk McKusick 	fs = VFSTOUFS(mp)->um_fs;
427ada981b2SKirk McKusick 	if ((error = bread(devvp, btodb(fs->fs_sblockloc), fs->fs_sbsize,
4281c85e6a3SKirk McKusick 	    NOCRED, &bp)) != 0)
429df8bae1dSRodney W. Grimes 		return (error);
430996c772fSJohn Dyson 	newfs = (struct fs *)bp->b_data;
4311c85e6a3SKirk McKusick 	if ((newfs->fs_magic != FS_UFS1_MAGIC &&
4321c85e6a3SKirk McKusick 	     newfs->fs_magic != FS_UFS2_MAGIC) ||
4331c85e6a3SKirk McKusick 	    newfs->fs_bsize > MAXBSIZE ||
434996c772fSJohn Dyson 	    newfs->fs_bsize < sizeof(struct fs)) {
435df8bae1dSRodney W. Grimes 			brelse(bp);
436df8bae1dSRodney W. Grimes 			return (EIO);		/* XXX needs translation */
437df8bae1dSRodney W. Grimes 	}
438996c772fSJohn Dyson 	/*
439996c772fSJohn Dyson 	 * Copy pointer fields back into superblock before copying in	XXX
440996c772fSJohn Dyson 	 * new superblock. These should really be in the ufsmount.	XXX
441996c772fSJohn Dyson 	 * Note that important parameters (eg fs_ncg) are unchanged.
442996c772fSJohn Dyson 	 */
443f55ff3f3SIan Dowse 	newfs->fs_csp = fs->fs_csp;
444996c772fSJohn Dyson 	newfs->fs_maxcluster = fs->fs_maxcluster;
4455d69bac4SIan Dowse 	newfs->fs_contigdirs = fs->fs_contigdirs;
446143a5346SIan Dowse 	newfs->fs_active = fs->fs_active;
44731c81e4bSDon Lewis 	/* The file system is still read-only. */
44831c81e4bSDon Lewis 	newfs->fs_ronly = 1;
4491c85e6a3SKirk McKusick 	sblockloc = fs->fs_sblockloc;
450996c772fSJohn Dyson 	bcopy(newfs, fs, (u_int)fs->fs_sbsize);
451df8bae1dSRodney W. Grimes 	brelse(bp);
452996c772fSJohn Dyson 	mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
4531c85e6a3SKirk McKusick 	ffs_oldfscompat_read(fs, VFSTOUFS(mp), sblockloc);
4549ccb939eSKirk McKusick 	if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
455cfbf0a46SMaxime Henrion 		printf("%s: reload pending error: blocks %jd files %d\n",
4561c85e6a3SKirk McKusick 		    fs->fs_fsmnt, (intmax_t)fs->fs_pendingblocks,
4571c85e6a3SKirk McKusick 		    fs->fs_pendinginodes);
4589ccb939eSKirk McKusick 		fs->fs_pendingblocks = 0;
4599ccb939eSKirk McKusick 		fs->fs_pendinginodes = 0;
4609ccb939eSKirk McKusick 	}
461996c772fSJohn Dyson 
462df8bae1dSRodney W. Grimes 	/*
463df8bae1dSRodney W. Grimes 	 * Step 3: re-read summary information from disk.
464df8bae1dSRodney W. Grimes 	 */
465df8bae1dSRodney W. Grimes 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
466f55ff3f3SIan Dowse 	space = fs->fs_csp;
467df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
468df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
469df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
470df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
471c9671602SPoul-Henning Kamp 		error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
472c9671602SPoul-Henning Kamp 		    NOCRED, &bp);
473c9671602SPoul-Henning Kamp 		if (error)
474df8bae1dSRodney W. Grimes 			return (error);
475f55ff3f3SIan Dowse 		bcopy(bp->b_data, space, (u_int)size);
476f55ff3f3SIan Dowse 		space = (char *)space + size;
477df8bae1dSRodney W. Grimes 		brelse(bp);
478df8bae1dSRodney W. Grimes 	}
479996c772fSJohn Dyson 	/*
480996c772fSJohn Dyson 	 * We no longer know anything about clusters per cylinder group.
481996c772fSJohn Dyson 	 */
482996c772fSJohn Dyson 	if (fs->fs_contigsumsize > 0) {
483996c772fSJohn Dyson 		lp = fs->fs_maxcluster;
484996c772fSJohn Dyson 		for (i = 0; i < fs->fs_ncg; i++)
485996c772fSJohn Dyson 			*lp++ = fs->fs_contigsumsize;
486996c772fSJohn Dyson 	}
487996c772fSJohn Dyson 
488df8bae1dSRodney W. Grimes loop:
489ca430f2eSAlexander Kabaev 	MNT_ILOCK(mp);
490e3c5a7a4SPoul-Henning Kamp 	MNT_VNODE_FOREACH(vp, mp, nvp) {
49104a17687SJeff Roberson 		VI_LOCK(vp);
4922f05568aSJeff Roberson 		if (vp->v_iflag & VI_XLOCK) {
4932f05568aSJeff Roberson 			VI_UNLOCK(vp);
4942f05568aSJeff Roberson 			continue;
4952f05568aSJeff Roberson 		}
496ca430f2eSAlexander Kabaev 		MNT_IUNLOCK(mp);
497df8bae1dSRodney W. Grimes 		/*
498df8bae1dSRodney W. Grimes 		 * Step 4: invalidate all inactive vnodes.
499df8bae1dSRodney W. Grimes 		 */
50004a17687SJeff Roberson 		if (vp->v_usecount == 0) {
50104a17687SJeff Roberson 			vgonel(vp, td);
502996c772fSJohn Dyson 			goto loop;
50304a17687SJeff Roberson 		}
504df8bae1dSRodney W. Grimes 		/*
505df8bae1dSRodney W. Grimes 		 * Step 5: invalidate all cached file data.
506df8bae1dSRodney W. Grimes 		 */
507b40ce416SJulian Elischer 		if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) {
508df8bae1dSRodney W. Grimes 			goto loop;
509996c772fSJohn Dyson 		}
5105e8c582aSPoul-Henning Kamp 		if (vinvalbuf(vp, 0, td->td_ucred, td, 0, 0))
511df8bae1dSRodney W. Grimes 			panic("ffs_reload: dirty2");
512df8bae1dSRodney W. Grimes 		/*
513df8bae1dSRodney W. Grimes 		 * Step 6: re-read inode data for all active vnodes.
514df8bae1dSRodney W. Grimes 		 */
515df8bae1dSRodney W. Grimes 		ip = VTOI(vp);
516c9671602SPoul-Henning Kamp 		error =
517df8bae1dSRodney W. Grimes 		    bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
518c9671602SPoul-Henning Kamp 		    (int)fs->fs_bsize, NOCRED, &bp);
519c9671602SPoul-Henning Kamp 		if (error) {
52045d45c6cSAlexander Kabaev 			VOP_UNLOCK(vp, 0, td);
52145d45c6cSAlexander Kabaev 			vrele(vp);
522df8bae1dSRodney W. Grimes 			return (error);
523df8bae1dSRodney W. Grimes 		}
524de6ba7c0SPoul-Henning Kamp 		ffs_load_inode(bp, ip, fs, ip->i_number);
525b1897c19SJulian Elischer 		ip->i_effnlink = ip->i_nlink;
526df8bae1dSRodney W. Grimes 		brelse(bp);
527cb9ddc80SAlexander Kabaev 		VOP_UNLOCK(vp, 0, td);
528cb9ddc80SAlexander Kabaev 		vrele(vp);
529ca430f2eSAlexander Kabaev 		MNT_ILOCK(mp);
530df8bae1dSRodney W. Grimes 	}
531ca430f2eSAlexander Kabaev 	MNT_IUNLOCK(mp);
532df8bae1dSRodney W. Grimes 	return (0);
533df8bae1dSRodney W. Grimes }
534df8bae1dSRodney W. Grimes 
5351c85e6a3SKirk McKusick /*
5361c85e6a3SKirk McKusick  * Possible superblock locations ordered from most to least likely.
5371c85e6a3SKirk McKusick  */
5381c85e6a3SKirk McKusick static int sblock_try[] = SBLOCKSEARCH;
5395819ab3fSKirk McKusick 
540df8bae1dSRodney W. Grimes /*
541df8bae1dSRodney W. Grimes  * Common code for mount and mountroot
542df8bae1dSRodney W. Grimes  */
543975512a9SPoul-Henning Kamp static int
544975512a9SPoul-Henning Kamp ffs_mountfs(devvp, mp, td)
54505f4ff5dSPoul-Henning Kamp 	struct vnode *devvp;
546df8bae1dSRodney W. Grimes 	struct mount *mp;
547b40ce416SJulian Elischer 	struct thread *td;
548df8bae1dSRodney W. Grimes {
54905f4ff5dSPoul-Henning Kamp 	struct ufsmount *ump;
550df8bae1dSRodney W. Grimes 	struct buf *bp;
55105f4ff5dSPoul-Henning Kamp 	struct fs *fs;
55289c9c53dSPoul-Henning Kamp 	struct cdev *dev;
553f55ff3f3SIan Dowse 	void *space;
5541c85e6a3SKirk McKusick 	ufs2_daddr_t sblockloc;
555f5ef029eSPoul-Henning Kamp 	int error, i, blks, size, ronly;
556996c772fSJohn Dyson 	int32_t *lp;
557996c772fSJohn Dyson 	struct ucred *cred;
5588435e0aeSDoug Rabson 	size_t strsize;
559df8bae1dSRodney W. Grimes 
560996c772fSJohn Dyson 	dev = devvp->v_rdev;
561a854ed98SJohn Baldwin 	cred = td ? td->td_ucred : NOCRED;
562df8bae1dSRodney W. Grimes 	/*
563df8bae1dSRodney W. Grimes 	 * Disallow multiple mounts of the same device.
564df8bae1dSRodney W. Grimes 	 * Disallow mounting of a device that is currently in use
565df8bae1dSRodney W. Grimes 	 * (except for root, which might share swap device for miniroot).
566df8bae1dSRodney W. Grimes 	 * Flush out any old buffers remaining from a previous use.
567df8bae1dSRodney W. Grimes 	 */
568c9671602SPoul-Henning Kamp 	error = vfs_mountedon(devvp);
569c9671602SPoul-Henning Kamp 	if (error)
570df8bae1dSRodney W. Grimes 		return (error);
571d634f693SPoul-Henning Kamp 	if (vcount(devvp) > 1)
572df8bae1dSRodney W. Grimes 		return (EBUSY);
573b40ce416SJulian Elischer 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
574b40ce416SJulian Elischer 	error = vinvalbuf(devvp, V_SAVE, cred, td, 0, 0);
575e9827c6dSBruce Evans 	if (error) {
576b40ce416SJulian Elischer 		VOP_UNLOCK(devvp, 0, td);
577df8bae1dSRodney W. Grimes 		return (error);
578e9827c6dSBruce Evans 	}
579df8bae1dSRodney W. Grimes 
58095e5e988SJohn Dyson 	/*
58195e5e988SJohn Dyson 	 * Only VMIO the backing device if the backing device is a real
582e9827c6dSBruce Evans 	 * disk device.
58395e5e988SJohn Dyson 	 * Note that it is optional that the backing device be VMIOed.  This
58495e5e988SJohn Dyson 	 * increases the opportunity for metadata caching.
58595e5e988SJohn Dyson 	 */
586e9827c6dSBruce Evans 	if (vn_isdisk(devvp, NULL))
587b40ce416SJulian Elischer 		vfs_object_create(devvp, td, cred);
58895e5e988SJohn Dyson 
589df8bae1dSRodney W. Grimes 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
5903dbceccbSPoul-Henning Kamp 	/*
5918adff5fcSBruce Evans 	 * XXX: open the device with read and write access even if only
5928adff5fcSBruce Evans 	 * read access is needed now.  Write access is needed if the
5938adff5fcSBruce Evans 	 * filesystem is ever mounted read/write, and we don't change the
5948adff5fcSBruce Evans 	 * access mode for remounts.
5953dbceccbSPoul-Henning Kamp 	 */
5963dbceccbSPoul-Henning Kamp #ifdef notyet
597a8d43c90SPoul-Henning Kamp 	error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE, FSCRED, td, -1);
5983dbceccbSPoul-Henning Kamp #else
599a8d43c90SPoul-Henning Kamp 	error = VOP_OPEN(devvp, FREAD | FWRITE, FSCRED, td, -1);
6003dbceccbSPoul-Henning Kamp #endif
601b40ce416SJulian Elischer 	VOP_UNLOCK(devvp, 0, td);
602c9671602SPoul-Henning Kamp 	if (error)
603df8bae1dSRodney W. Grimes 		return (error);
6040508986cSBruce Evans 	if (devvp->v_rdev->si_iosize_max != 0)
6051b5464efSPoul-Henning Kamp 		mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max;
6061b5464efSPoul-Henning Kamp 	if (mp->mnt_iosize_max > MAXPHYS)
6071b5464efSPoul-Henning Kamp 		mp->mnt_iosize_max = MAXPHYS;
60895e5e988SJohn Dyson 
6096e77a041SPoul-Henning Kamp 	devvp->v_bufobj.bo_ops = &ffs_ops;
6106e77a041SPoul-Henning Kamp 
611df8bae1dSRodney W. Grimes 	bp = NULL;
612df8bae1dSRodney W. Grimes 	ump = NULL;
6131c85e6a3SKirk McKusick 	fs = NULL;
6141c85e6a3SKirk McKusick 	sblockloc = 0;
6151c85e6a3SKirk McKusick 	/*
6161c85e6a3SKirk McKusick 	 * Try reading the superblock in each of its possible locations.
6171c85e6a3SKirk McKusick 	 */
6181c85e6a3SKirk McKusick 	for (i = 0; sblock_try[i] != -1; i++) {
619b6cef564SKirk McKusick 		if ((error = bread(devvp, sblock_try[i] / DEV_BSIZE, SBLOCKSIZE,
6201c85e6a3SKirk McKusick 		    cred, &bp)) != 0)
621df8bae1dSRodney W. Grimes 			goto out;
622df8bae1dSRodney W. Grimes 		fs = (struct fs *)bp->b_data;
623ada981b2SKirk McKusick 		sblockloc = sblock_try[i];
6241c85e6a3SKirk McKusick 		if ((fs->fs_magic == FS_UFS1_MAGIC ||
6251c85e6a3SKirk McKusick 		     (fs->fs_magic == FS_UFS2_MAGIC &&
626ada981b2SKirk McKusick 		      (fs->fs_sblockloc == sblockloc ||
627ada981b2SKirk McKusick 		       (fs->fs_old_flags & FS_FLAGS_UPDATED) == 0))) &&
6281c85e6a3SKirk McKusick 		    fs->fs_bsize <= MAXBSIZE &&
6291c85e6a3SKirk McKusick 		    fs->fs_bsize >= sizeof(struct fs))
6301c85e6a3SKirk McKusick 			break;
6311c85e6a3SKirk McKusick 		brelse(bp);
6321c85e6a3SKirk McKusick 		bp = NULL;
6331c85e6a3SKirk McKusick 	}
6341c85e6a3SKirk McKusick 	if (sblock_try[i] == -1) {
635df8bae1dSRodney W. Grimes 		error = EINVAL;		/* XXX needs translation */
636df8bae1dSRodney W. Grimes 		goto out;
637df8bae1dSRodney W. Grimes 	}
6383f6f17eeSJulian Elischer 	fs->fs_fmod = 0;
6391c85e6a3SKirk McKusick 	fs->fs_flags &= ~FS_INDEXDIRS;	/* no support for directory indicies */
6400922cce6SBruce Evans 	fs->fs_flags &= ~FS_UNCLEAN;
6410922cce6SBruce Evans 	if (fs->fs_clean == 0) {
6420922cce6SBruce Evans 		fs->fs_flags |= FS_UNCLEAN;
643812b1d41SKirk McKusick 		if (ronly || (mp->mnt_flag & MNT_FORCE) ||
6441a6a6610SKirk McKusick 		    ((fs->fs_flags & FS_NEEDSFSCK) == 0 &&
6451a6a6610SKirk McKusick 		     (fs->fs_flags & FS_DOSOFTDEP))) {
6460922cce6SBruce Evans 			printf(
6470922cce6SBruce Evans "WARNING: %s was not properly dismounted\n",
6480922cce6SBruce Evans 			    fs->fs_fsmnt);
6491469eec8SDavid Greenman 		} else {
6500922cce6SBruce Evans 			printf(
6510922cce6SBruce Evans "WARNING: R/W mount of %s denied.  Filesystem is not clean - run fsck\n",
6520922cce6SBruce Evans 			    fs->fs_fsmnt);
6531469eec8SDavid Greenman 			error = EPERM;
6541469eec8SDavid Greenman 			goto out;
6551469eec8SDavid Greenman 		}
6561c85e6a3SKirk McKusick 		if ((fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) &&
6571c85e6a3SKirk McKusick 		    (mp->mnt_flag & MNT_FORCE)) {
658cfbf0a46SMaxime Henrion 			printf("%s: lost blocks %jd files %d\n", fs->fs_fsmnt,
6591c85e6a3SKirk McKusick 			    (intmax_t)fs->fs_pendingblocks,
6601c85e6a3SKirk McKusick 			    fs->fs_pendinginodes);
6619ccb939eSKirk McKusick 			fs->fs_pendingblocks = 0;
6629ccb939eSKirk McKusick 			fs->fs_pendinginodes = 0;
6639ccb939eSKirk McKusick 		}
6649ccb939eSKirk McKusick 	}
6659ccb939eSKirk McKusick 	if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
666cfbf0a46SMaxime Henrion 		printf("%s: mount pending error: blocks %jd files %d\n",
6671c85e6a3SKirk McKusick 		    fs->fs_fsmnt, (intmax_t)fs->fs_pendingblocks,
6681c85e6a3SKirk McKusick 		    fs->fs_pendinginodes);
6699ccb939eSKirk McKusick 		fs->fs_pendingblocks = 0;
6709ccb939eSKirk McKusick 		fs->fs_pendinginodes = 0;
6711469eec8SDavid Greenman 	}
672a163d034SWarner Losh 	ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK | M_ZERO);
673df8bae1dSRodney W. Grimes 	ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT,
674a163d034SWarner Losh 	    M_WAITOK);
6751c85e6a3SKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC) {
6761c85e6a3SKirk McKusick 		ump->um_fstype = UFS1;
6771c85e6a3SKirk McKusick 		ump->um_balloc = ffs_balloc_ufs1;
6781c85e6a3SKirk McKusick 	} else {
6791c85e6a3SKirk McKusick 		ump->um_fstype = UFS2;
6801c85e6a3SKirk McKusick 		ump->um_balloc = ffs_balloc_ufs2;
6811c85e6a3SKirk McKusick 	}
682cec0f20cSPoul-Henning Kamp 	ump->um_blkatoff = ffs_blkatoff;
683cec0f20cSPoul-Henning Kamp 	ump->um_truncate = ffs_truncate;
684987f5696SPoul-Henning Kamp 	ump->um_update = ffs_update;
685cec0f20cSPoul-Henning Kamp 	ump->um_valloc = ffs_valloc;
686cec0f20cSPoul-Henning Kamp 	ump->um_vfree = ffs_vfree;
687975512a9SPoul-Henning Kamp 	ump->um_ifree = ffs_ifree;
688df8bae1dSRodney W. Grimes 	bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize);
6891c85e6a3SKirk McKusick 	if (fs->fs_sbsize < SBLOCKSIZE)
690f2a2857bSKirk McKusick 		bp->b_flags |= B_INVAL | B_NOCACHE;
691df8bae1dSRodney W. Grimes 	brelse(bp);
692df8bae1dSRodney W. Grimes 	bp = NULL;
693df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
6941c85e6a3SKirk McKusick 	ffs_oldfscompat_read(fs, ump, sblockloc);
695df8bae1dSRodney W. Grimes 	fs->fs_ronly = ronly;
696996c772fSJohn Dyson 	size = fs->fs_cssize;
697996c772fSJohn Dyson 	blks = howmany(size, fs->fs_fsize);
698996c772fSJohn Dyson 	if (fs->fs_contigsumsize > 0)
699996c772fSJohn Dyson 		size += fs->fs_ncg * sizeof(int32_t);
700a61ab64aSKirk McKusick 	size += fs->fs_ncg * sizeof(u_int8_t);
701a163d034SWarner Losh 	space = malloc((u_long)size, M_UFSMNT, M_WAITOK);
702f55ff3f3SIan Dowse 	fs->fs_csp = space;
703df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
704df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
705df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
706df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
7078aef1712SMatthew Dillon 		if ((error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
7088aef1712SMatthew Dillon 		    cred, &bp)) != 0) {
709f55ff3f3SIan Dowse 			free(fs->fs_csp, M_UFSMNT);
710df8bae1dSRodney W. Grimes 			goto out;
711df8bae1dSRodney W. Grimes 		}
712df8bae1dSRodney W. Grimes 		bcopy(bp->b_data, space, (u_int)size);
713f55ff3f3SIan Dowse 		space = (char *)space + size;
714df8bae1dSRodney W. Grimes 		brelse(bp);
715df8bae1dSRodney W. Grimes 		bp = NULL;
716df8bae1dSRodney W. Grimes 	}
717996c772fSJohn Dyson 	if (fs->fs_contigsumsize > 0) {
718f55ff3f3SIan Dowse 		fs->fs_maxcluster = lp = space;
719996c772fSJohn Dyson 		for (i = 0; i < fs->fs_ncg; i++)
720996c772fSJohn Dyson 			*lp++ = fs->fs_contigsumsize;
7214691e9eaSIan Dowse 		space = lp;
722996c772fSJohn Dyson 	}
723a61ab64aSKirk McKusick 	size = fs->fs_ncg * sizeof(u_int8_t);
724a61ab64aSKirk McKusick 	fs->fs_contigdirs = (u_int8_t *)space;
725a61ab64aSKirk McKusick 	bzero(fs->fs_contigdirs, size);
726143a5346SIan Dowse 	fs->fs_active = NULL;
727df8bae1dSRodney W. Grimes 	mp->mnt_data = (qaddr_t)ump;
72868de329eSPoul-Henning Kamp 	mp->mnt_stat.f_fsid.val[0] = fs->fs_id[0];
7298f89943eSGuido van Rooij 	mp->mnt_stat.f_fsid.val[1] = fs->fs_id[1];
73068de329eSPoul-Henning Kamp 	if (fs->fs_id[0] == 0 || fs->fs_id[1] == 0 ||
73168de329eSPoul-Henning Kamp 	    vfs_getvfs(&mp->mnt_stat.f_fsid))
73268de329eSPoul-Henning Kamp 		vfs_getnewfsid(mp);
733df8bae1dSRodney W. Grimes 	mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
734cc9d8990SPeter Wemm 	mp->mnt_flag |= MNT_LOCAL;
73580830407SRobert Watson 	if ((fs->fs_flags & FS_MULTILABEL) != 0)
73680830407SRobert Watson #ifdef MAC
73780830407SRobert Watson 		mp->mnt_flag |= MNT_MULTILABEL;
73880830407SRobert Watson #else
73980830407SRobert Watson 		printf(
74080830407SRobert Watson "WARNING: %s: multilabel flag on fs but no MAC support\n",
74180830407SRobert Watson 		    fs->fs_fsmnt);
74280830407SRobert Watson #endif
74380830407SRobert Watson 	if ((fs->fs_flags & FS_ACLS) != 0)
74480830407SRobert Watson #ifdef UFS_ACL
74580830407SRobert Watson 		mp->mnt_flag |= MNT_ACLS;
74680830407SRobert Watson #else
74780830407SRobert Watson 		printf(
74880830407SRobert Watson "WARNING: %s: ACLs flag on fs but no ACLs support\n",
74980830407SRobert Watson 		    fs->fs_fsmnt);
75080830407SRobert Watson #endif
751df8bae1dSRodney W. Grimes 	ump->um_mountp = mp;
752df8bae1dSRodney W. Grimes 	ump->um_dev = dev;
753df8bae1dSRodney W. Grimes 	ump->um_devvp = devvp;
754df8bae1dSRodney W. Grimes 	ump->um_nindir = fs->fs_nindir;
755df8bae1dSRodney W. Grimes 	ump->um_bptrtodb = fs->fs_fsbtodb;
756df8bae1dSRodney W. Grimes 	ump->um_seqinc = fs->fs_frag;
757df8bae1dSRodney W. Grimes 	for (i = 0; i < MAXQUOTAS; i++)
758df8bae1dSRodney W. Grimes 		ump->um_quotas[i] = NULLVP;
759516081f2SRobert Watson #ifdef UFS_EXTATTR
760a64ed089SRobert Watson 	ufs_extattr_uepm_init(&ump->um_extattr);
761a64ed089SRobert Watson #endif
7627eb9fca5SEivind Eklund 	devvp->v_rdev->si_mountpoint = mp;
7632b14f991SJulian Elischer 
7642b14f991SJulian Elischer 	/*
7652b14f991SJulian Elischer 	 * Set FS local "last mounted on" information (NULL pad)
7662b14f991SJulian Elischer 	 */
7672b14f991SJulian Elischer 	copystr(	mp->mnt_stat.f_mntonname,	/* mount point*/
7682b14f991SJulian Elischer 			fs->fs_fsmnt,			/* copy area*/
7692b14f991SJulian Elischer 			sizeof(fs->fs_fsmnt) - 1,	/* max size*/
7702b14f991SJulian Elischer 			&strsize);			/* real size*/
7712b14f991SJulian Elischer 	bzero( fs->fs_fsmnt + strsize, sizeof(fs->fs_fsmnt) - strsize);
7722b14f991SJulian Elischer 
7732b14f991SJulian Elischer 	if( mp->mnt_flag & MNT_ROOTFS) {
7742b14f991SJulian Elischer 		/*
7752b14f991SJulian Elischer 		 * Root mount; update timestamp in mount structure.
7762b14f991SJulian Elischer 		 * this will be used by the common root mount code
7772b14f991SJulian Elischer 		 * to update the system clock.
7782b14f991SJulian Elischer 		 */
7792b14f991SJulian Elischer 		mp->mnt_time = fs->fs_time;
7802b14f991SJulian Elischer 	}
781996c772fSJohn Dyson 
782996c772fSJohn Dyson 	if (ronly == 0) {
783b1897c19SJulian Elischer 		if ((fs->fs_flags & FS_DOSOFTDEP) &&
784b1897c19SJulian Elischer 		    (error = softdep_mount(devvp, mp, fs, cred)) != 0) {
785f55ff3f3SIan Dowse 			free(fs->fs_csp, M_UFSMNT);
786b1897c19SJulian Elischer 			goto out;
787b1897c19SJulian Elischer 		}
788f2a2857bSKirk McKusick 		if (fs->fs_snapinum[0] != 0)
789f2a2857bSKirk McKusick 			ffs_snapshot_mount(mp);
790cf60e8e4SKirk McKusick 		fs->fs_fmod = 1;
791996c772fSJohn Dyson 		fs->fs_clean = 0;
792996c772fSJohn Dyson 		(void) ffs_sbupdate(ump, MNT_WAIT);
793996c772fSJohn Dyson 	}
794d8d3d415SPoul-Henning Kamp 	/*
795d8d3d415SPoul-Henning Kamp 	 * Initialize filesystem stat information in mount struct.
796d8d3d415SPoul-Henning Kamp 	 */
797d8d3d415SPoul-Henning Kamp 	(void)VFS_STATFS(mp, &mp->mnt_stat, td);
798516081f2SRobert Watson #ifdef UFS_EXTATTR
799516081f2SRobert Watson #ifdef UFS_EXTATTR_AUTOSTART
8009de54ba5SRobert Watson 	/*
8019de54ba5SRobert Watson 	 *
802f5161237SRobert Watson 	 * Auto-starting does the following:
8039de54ba5SRobert Watson 	 *	- check for /.attribute in the fs, and extattr_start if so
8049de54ba5SRobert Watson 	 *	- for each file in .attribute, enable that file with
8059de54ba5SRobert Watson 	 * 	  an attribute of the same name.
8069de54ba5SRobert Watson 	 * Not clear how to report errors -- probably eat them.
8079de54ba5SRobert Watson 	 * This would all happen while the filesystem was busy/not
8089de54ba5SRobert Watson 	 * available, so would effectively be "atomic".
8099de54ba5SRobert Watson 	 */
810b40ce416SJulian Elischer 	(void) ufs_extattr_autostart(mp, td);
811516081f2SRobert Watson #endif /* !UFS_EXTATTR_AUTOSTART */
812516081f2SRobert Watson #endif /* !UFS_EXTATTR */
813df8bae1dSRodney W. Grimes 	return (0);
814df8bae1dSRodney W. Grimes out:
8157eb9fca5SEivind Eklund 	devvp->v_rdev->si_mountpoint = NULL;
816df8bae1dSRodney W. Grimes 	if (bp)
817df8bae1dSRodney W. Grimes 		brelse(bp);
8188adff5fcSBruce Evans 	/* XXX: see comment above VOP_OPEN. */
8193dbceccbSPoul-Henning Kamp #ifdef notyet
820b40ce416SJulian Elischer 	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE, cred, td);
8213dbceccbSPoul-Henning Kamp #else
8223dbceccbSPoul-Henning Kamp 	(void)VOP_CLOSE(devvp, FREAD | FWRITE, cred, td);
8233dbceccbSPoul-Henning Kamp #endif
824df8bae1dSRodney W. Grimes 	if (ump) {
825df8bae1dSRodney W. Grimes 		free(ump->um_fs, M_UFSMNT);
826df8bae1dSRodney W. Grimes 		free(ump, M_UFSMNT);
827df8bae1dSRodney W. Grimes 		mp->mnt_data = (qaddr_t)0;
828df8bae1dSRodney W. Grimes 	}
829df8bae1dSRodney W. Grimes 	return (error);
830df8bae1dSRodney W. Grimes }
831df8bae1dSRodney W. Grimes 
8321c85e6a3SKirk McKusick #include <sys/sysctl.h>
8331c85e6a3SKirk McKusick int bigcgs = 0;
8341c85e6a3SKirk McKusick SYSCTL_INT(_debug, OID_AUTO, bigcgs, CTLFLAG_RW, &bigcgs, 0, "");
8351c85e6a3SKirk McKusick 
836df8bae1dSRodney W. Grimes /*
8371c85e6a3SKirk McKusick  * Sanity checks for loading old filesystem superblocks.
8381c85e6a3SKirk McKusick  * See ffs_oldfscompat_write below for unwound actions.
839df8bae1dSRodney W. Grimes  *
8401c85e6a3SKirk McKusick  * XXX - Parts get retired eventually.
8411c85e6a3SKirk McKusick  * Unfortunately new bits get added.
842df8bae1dSRodney W. Grimes  */
8431c85e6a3SKirk McKusick static void
8441c85e6a3SKirk McKusick ffs_oldfscompat_read(fs, ump, sblockloc)
845df8bae1dSRodney W. Grimes 	struct fs *fs;
8461c85e6a3SKirk McKusick 	struct ufsmount *ump;
8471c85e6a3SKirk McKusick 	ufs2_daddr_t sblockloc;
8481c85e6a3SKirk McKusick {
8491c85e6a3SKirk McKusick 	off_t maxfilesize;
8501c85e6a3SKirk McKusick 
8511c85e6a3SKirk McKusick 	/*
852ada981b2SKirk McKusick 	 * If not yet done, update fs_flags location and value of fs_sblockloc.
853ada981b2SKirk McKusick 	 */
854ada981b2SKirk McKusick 	if ((fs->fs_old_flags & FS_FLAGS_UPDATED) == 0) {
855ada981b2SKirk McKusick 		fs->fs_flags = fs->fs_old_flags;
856ada981b2SKirk McKusick 		fs->fs_old_flags |= FS_FLAGS_UPDATED;
857ada981b2SKirk McKusick 		fs->fs_sblockloc = sblockloc;
858ada981b2SKirk McKusick 	}
859ada981b2SKirk McKusick 	/*
8601c85e6a3SKirk McKusick 	 * If not yet done, update UFS1 superblock with new wider fields.
8611c85e6a3SKirk McKusick 	 */
86274f3809aSKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_maxbsize != fs->fs_bsize) {
8631c85e6a3SKirk McKusick 		fs->fs_maxbsize = fs->fs_bsize;
8641c85e6a3SKirk McKusick 		fs->fs_time = fs->fs_old_time;
8651c85e6a3SKirk McKusick 		fs->fs_size = fs->fs_old_size;
8661c85e6a3SKirk McKusick 		fs->fs_dsize = fs->fs_old_dsize;
8671c85e6a3SKirk McKusick 		fs->fs_csaddr = fs->fs_old_csaddr;
8681c85e6a3SKirk McKusick 		fs->fs_cstotal.cs_ndir = fs->fs_old_cstotal.cs_ndir;
8691c85e6a3SKirk McKusick 		fs->fs_cstotal.cs_nbfree = fs->fs_old_cstotal.cs_nbfree;
8701c85e6a3SKirk McKusick 		fs->fs_cstotal.cs_nifree = fs->fs_old_cstotal.cs_nifree;
8711c85e6a3SKirk McKusick 		fs->fs_cstotal.cs_nffree = fs->fs_old_cstotal.cs_nffree;
8721c85e6a3SKirk McKusick 	}
8731c85e6a3SKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC &&
8741c85e6a3SKirk McKusick 	    fs->fs_old_inodefmt < FS_44INODEFMT) {
8751c85e6a3SKirk McKusick 		fs->fs_maxfilesize = (u_quad_t) 1LL << 39;
8761c85e6a3SKirk McKusick 		fs->fs_qbmask = ~fs->fs_bmask;
8771c85e6a3SKirk McKusick 		fs->fs_qfmask = ~fs->fs_fmask;
8781c85e6a3SKirk McKusick 	}
8798f42fb8fSIan Dowse 	if (fs->fs_magic == FS_UFS1_MAGIC) {
8801c85e6a3SKirk McKusick 		ump->um_savedmaxfilesize = fs->fs_maxfilesize;
8811c85e6a3SKirk McKusick 		maxfilesize = (u_int64_t)0x40000000 * fs->fs_bsize - 1;
8821c85e6a3SKirk McKusick 		if (fs->fs_maxfilesize > maxfilesize)
8831c85e6a3SKirk McKusick 			fs->fs_maxfilesize = maxfilesize;
8848f42fb8fSIan Dowse 	}
8851c85e6a3SKirk McKusick 	/* Compatibility for old filesystems */
8861c85e6a3SKirk McKusick 	if (fs->fs_avgfilesize <= 0)
8871c85e6a3SKirk McKusick 		fs->fs_avgfilesize = AVFILESIZ;
8881c85e6a3SKirk McKusick 	if (fs->fs_avgfpdir <= 0)
8891c85e6a3SKirk McKusick 		fs->fs_avgfpdir = AFPDIR;
8901c85e6a3SKirk McKusick 	if (bigcgs) {
8911c85e6a3SKirk McKusick 		fs->fs_save_cgsize = fs->fs_cgsize;
8921c85e6a3SKirk McKusick 		fs->fs_cgsize = fs->fs_bsize;
8931c85e6a3SKirk McKusick 	}
8941c85e6a3SKirk McKusick }
8951c85e6a3SKirk McKusick 
8961c85e6a3SKirk McKusick /*
8971c85e6a3SKirk McKusick  * Unwinding superblock updates for old filesystems.
8981c85e6a3SKirk McKusick  * See ffs_oldfscompat_read above for details.
8991c85e6a3SKirk McKusick  *
9001c85e6a3SKirk McKusick  * XXX - Parts get retired eventually.
9011c85e6a3SKirk McKusick  * Unfortunately new bits get added.
9021c85e6a3SKirk McKusick  */
9031c85e6a3SKirk McKusick static void
9041c85e6a3SKirk McKusick ffs_oldfscompat_write(fs, ump)
9051c85e6a3SKirk McKusick 	struct fs *fs;
9061c85e6a3SKirk McKusick 	struct ufsmount *ump;
907df8bae1dSRodney W. Grimes {
908df8bae1dSRodney W. Grimes 
9091c85e6a3SKirk McKusick 	/*
9101c85e6a3SKirk McKusick 	 * Copy back UFS2 updated fields that UFS1 inspects.
9111c85e6a3SKirk McKusick 	 */
9121c85e6a3SKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC) {
9131c85e6a3SKirk McKusick 		fs->fs_old_time = fs->fs_time;
9141c85e6a3SKirk McKusick 		fs->fs_old_cstotal.cs_ndir = fs->fs_cstotal.cs_ndir;
9151c85e6a3SKirk McKusick 		fs->fs_old_cstotal.cs_nbfree = fs->fs_cstotal.cs_nbfree;
9161c85e6a3SKirk McKusick 		fs->fs_old_cstotal.cs_nifree = fs->fs_cstotal.cs_nifree;
9171c85e6a3SKirk McKusick 		fs->fs_old_cstotal.cs_nffree = fs->fs_cstotal.cs_nffree;
9181c85e6a3SKirk McKusick 		fs->fs_maxfilesize = ump->um_savedmaxfilesize;
9198f42fb8fSIan Dowse 	}
9201c85e6a3SKirk McKusick 	if (bigcgs) {
9211c85e6a3SKirk McKusick 		fs->fs_cgsize = fs->fs_save_cgsize;
9221c85e6a3SKirk McKusick 		fs->fs_save_cgsize = 0;
9231c85e6a3SKirk McKusick 	}
924df8bae1dSRodney W. Grimes }
925df8bae1dSRodney W. Grimes 
926df8bae1dSRodney W. Grimes /*
927df8bae1dSRodney W. Grimes  * unmount system call
928df8bae1dSRodney W. Grimes  */
929df8bae1dSRodney W. Grimes int
930b40ce416SJulian Elischer ffs_unmount(mp, mntflags, td)
931df8bae1dSRodney W. Grimes 	struct mount *mp;
932df8bae1dSRodney W. Grimes 	int mntflags;
933b40ce416SJulian Elischer 	struct thread *td;
934df8bae1dSRodney W. Grimes {
93505f4ff5dSPoul-Henning Kamp 	struct ufsmount *ump = VFSTOUFS(mp);
93605f4ff5dSPoul-Henning Kamp 	struct fs *fs;
937996c772fSJohn Dyson 	int error, flags;
938df8bae1dSRodney W. Grimes 
939df8bae1dSRodney W. Grimes 	flags = 0;
940df8bae1dSRodney W. Grimes 	if (mntflags & MNT_FORCE) {
941df8bae1dSRodney W. Grimes 		flags |= FORCECLOSE;
942df8bae1dSRodney W. Grimes 	}
943516081f2SRobert Watson #ifdef UFS_EXTATTR
944b40ce416SJulian Elischer 	if ((error = ufs_extattr_stop(mp, td))) {
945b2b0497aSRobert Watson 		if (error != EOPNOTSUPP)
946b2b0497aSRobert Watson 			printf("ffs_unmount: ufs_extattr_stop returned %d\n",
947b2b0497aSRobert Watson 			    error);
9487df97b61SRobert Watson 	} else {
9499de54ba5SRobert Watson 		ufs_extattr_uepm_destroy(&ump->um_extattr);
9507df97b61SRobert Watson 	}
951a64ed089SRobert Watson #endif
952b1897c19SJulian Elischer 	if (mp->mnt_flag & MNT_SOFTDEP) {
953b40ce416SJulian Elischer 		if ((error = softdep_flushfiles(mp, flags, td)) != 0)
954df8bae1dSRodney W. Grimes 			return (error);
955b1897c19SJulian Elischer 	} else {
956b40ce416SJulian Elischer 		if ((error = ffs_flushfiles(mp, flags, td)) != 0)
957b1897c19SJulian Elischer 			return (error);
958b1897c19SJulian Elischer 	}
959df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
9609ccb939eSKirk McKusick 	if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
961cfbf0a46SMaxime Henrion 		printf("%s: unmount pending error: blocks %jd files %d\n",
9621c85e6a3SKirk McKusick 		    fs->fs_fsmnt, (intmax_t)fs->fs_pendingblocks,
9631c85e6a3SKirk McKusick 		    fs->fs_pendinginodes);
9649ccb939eSKirk McKusick 		fs->fs_pendingblocks = 0;
9659ccb939eSKirk McKusick 		fs->fs_pendinginodes = 0;
9669ccb939eSKirk McKusick 	}
967996c772fSJohn Dyson 	if (fs->fs_ronly == 0) {
9681a6a6610SKirk McKusick 		fs->fs_clean = fs->fs_flags & (FS_UNCLEAN|FS_NEEDSFSCK) ? 0 : 1;
969996c772fSJohn Dyson 		error = ffs_sbupdate(ump, MNT_WAIT);
970996c772fSJohn Dyson 		if (error) {
971996c772fSJohn Dyson 			fs->fs_clean = 0;
972996c772fSJohn Dyson 			return (error);
973996c772fSJohn Dyson 		}
974e0e9c421SDavid Greenman 	}
9757eb9fca5SEivind Eklund 	ump->um_devvp->v_rdev->si_mountpoint = NULL;
9766476c0d2SJohn Dyson 
977b40ce416SJulian Elischer 	vinvalbuf(ump->um_devvp, V_SAVE, NOCRED, td, 0, 0);
9788adff5fcSBruce Evans 	/* XXX: see comment above VOP_OPEN. */
979063f7763SPoul-Henning Kamp #ifdef notyet
980996c772fSJohn Dyson 	error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD | FWRITE,
981b40ce416SJulian Elischer 	    NOCRED, td);
982063f7763SPoul-Henning Kamp #else
983063f7763SPoul-Henning Kamp 	error = VOP_CLOSE(ump->um_devvp, FREAD | FWRITE, NOCRED, td);
984063f7763SPoul-Henning Kamp #endif
9856476c0d2SJohn Dyson 	vrele(ump->um_devvp);
986f55ff3f3SIan Dowse 	free(fs->fs_csp, M_UFSMNT);
987df8bae1dSRodney W. Grimes 	free(fs, M_UFSMNT);
988df8bae1dSRodney W. Grimes 	free(ump, M_UFSMNT);
989df8bae1dSRodney W. Grimes 	mp->mnt_data = (qaddr_t)0;
990cc9d8990SPeter Wemm 	mp->mnt_flag &= ~MNT_LOCAL;
991df8bae1dSRodney W. Grimes 	return (error);
992df8bae1dSRodney W. Grimes }
993df8bae1dSRodney W. Grimes 
994df8bae1dSRodney W. Grimes /*
995df8bae1dSRodney W. Grimes  * Flush out all the files in a filesystem.
996df8bae1dSRodney W. Grimes  */
99726f9a767SRodney W. Grimes int
998b40ce416SJulian Elischer ffs_flushfiles(mp, flags, td)
99905f4ff5dSPoul-Henning Kamp 	struct mount *mp;
1000df8bae1dSRodney W. Grimes 	int flags;
1001b40ce416SJulian Elischer 	struct thread *td;
1002df8bae1dSRodney W. Grimes {
100305f4ff5dSPoul-Henning Kamp 	struct ufsmount *ump;
1004c9671602SPoul-Henning Kamp 	int error;
1005df8bae1dSRodney W. Grimes 
1006df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
1007df8bae1dSRodney W. Grimes #ifdef QUOTA
1008df8bae1dSRodney W. Grimes 	if (mp->mnt_flag & MNT_QUOTA) {
1009c1d9efcbSPoul-Henning Kamp 		int i;
1010f257b7a5SAlfred Perlstein 		error = vflush(mp, 0, SKIPSYSTEM|flags, td);
1011c1d9efcbSPoul-Henning Kamp 		if (error)
1012df8bae1dSRodney W. Grimes 			return (error);
1013df8bae1dSRodney W. Grimes 		for (i = 0; i < MAXQUOTAS; i++) {
1014df8bae1dSRodney W. Grimes 			if (ump->um_quotas[i] == NULLVP)
1015df8bae1dSRodney W. Grimes 				continue;
1016b40ce416SJulian Elischer 			quotaoff(td, mp, i);
1017df8bae1dSRodney W. Grimes 		}
1018df8bae1dSRodney W. Grimes 		/*
1019df8bae1dSRodney W. Grimes 		 * Here we fall through to vflush again to ensure
1020df8bae1dSRodney W. Grimes 		 * that we have gotten rid of all the system vnodes.
1021df8bae1dSRodney W. Grimes 		 */
1022df8bae1dSRodney W. Grimes 	}
1023df8bae1dSRodney W. Grimes #endif
1024e6e370a7SJeff Roberson 	ASSERT_VOP_LOCKED(ump->um_devvp, "ffs_flushfiles");
1025e6e370a7SJeff Roberson 	if (ump->um_devvp->v_vflag & VV_COPYONWRITE) {
1026f257b7a5SAlfred Perlstein 		if ((error = vflush(mp, 0, SKIPSYSTEM | flags, td)) != 0)
1027f2a2857bSKirk McKusick 			return (error);
1028f2a2857bSKirk McKusick 		ffs_snapshot_unmount(mp);
1029f2a2857bSKirk McKusick 		/*
1030f2a2857bSKirk McKusick 		 * Here we fall through to vflush again to ensure
1031f2a2857bSKirk McKusick 		 * that we have gotten rid of all the system vnodes.
1032f2a2857bSKirk McKusick 		 */
1033f2a2857bSKirk McKusick 	}
1034b1897c19SJulian Elischer         /*
1035b1897c19SJulian Elischer 	 * Flush all the files.
1036b1897c19SJulian Elischer 	 */
1037f257b7a5SAlfred Perlstein 	if ((error = vflush(mp, 0, flags, td)) != 0)
1038b1897c19SJulian Elischer 		return (error);
1039b1897c19SJulian Elischer 	/*
1040b1897c19SJulian Elischer 	 * Flush filesystem metadata.
1041b1897c19SJulian Elischer 	 */
1042b40ce416SJulian Elischer 	vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, td);
1043a854ed98SJohn Baldwin 	error = VOP_FSYNC(ump->um_devvp, td->td_ucred, MNT_WAIT, td);
1044b40ce416SJulian Elischer 	VOP_UNLOCK(ump->um_devvp, 0, td);
1045df8bae1dSRodney W. Grimes 	return (error);
1046df8bae1dSRodney W. Grimes }
1047df8bae1dSRodney W. Grimes 
1048df8bae1dSRodney W. Grimes /*
1049df8bae1dSRodney W. Grimes  * Get filesystem statistics.
1050df8bae1dSRodney W. Grimes  */
1051df8bae1dSRodney W. Grimes int
1052b40ce416SJulian Elischer ffs_statfs(mp, sbp, td)
1053df8bae1dSRodney W. Grimes 	struct mount *mp;
105405f4ff5dSPoul-Henning Kamp 	struct statfs *sbp;
1055b40ce416SJulian Elischer 	struct thread *td;
1056df8bae1dSRodney W. Grimes {
105705f4ff5dSPoul-Henning Kamp 	struct ufsmount *ump;
105805f4ff5dSPoul-Henning Kamp 	struct fs *fs;
1059df8bae1dSRodney W. Grimes 
1060df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
1061df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
10621c85e6a3SKirk McKusick 	if (fs->fs_magic != FS_UFS1_MAGIC && fs->fs_magic != FS_UFS2_MAGIC)
1063df8bae1dSRodney W. Grimes 		panic("ffs_statfs");
1064fde81c7dSKirk McKusick 	sbp->f_version = STATFS_VERSION;
1065df8bae1dSRodney W. Grimes 	sbp->f_bsize = fs->fs_fsize;
1066df8bae1dSRodney W. Grimes 	sbp->f_iosize = fs->fs_bsize;
1067df8bae1dSRodney W. Grimes 	sbp->f_blocks = fs->fs_dsize;
1068df8bae1dSRodney W. Grimes 	sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
10699ccb939eSKirk McKusick 	    fs->fs_cstotal.cs_nffree + dbtofsb(fs, fs->fs_pendingblocks);
10709ccb939eSKirk McKusick 	sbp->f_bavail = freespace(fs, fs->fs_minfree) +
10719ccb939eSKirk McKusick 	    dbtofsb(fs, fs->fs_pendingblocks);
1072df8bae1dSRodney W. Grimes 	sbp->f_files =  fs->fs_ncg * fs->fs_ipg - ROOTINO;
10739ccb939eSKirk McKusick 	sbp->f_ffree = fs->fs_cstotal.cs_nifree + fs->fs_pendinginodes;
1074fde81c7dSKirk McKusick 	sbp->f_namemax = NAME_MAX;
1075df8bae1dSRodney W. Grimes 	if (sbp != &mp->mnt_stat) {
1076fde81c7dSKirk McKusick 		sbp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
1077996c772fSJohn Dyson 		sbp->f_type = mp->mnt_vfc->vfc_typenum;
1078fde81c7dSKirk McKusick 		sbp->f_syncwrites = mp->mnt_stat.f_syncwrites;
1079fde81c7dSKirk McKusick 		sbp->f_asyncwrites = mp->mnt_stat.f_asyncwrites;
1080fde81c7dSKirk McKusick 		sbp->f_syncreads = mp->mnt_stat.f_syncreads;
1081fde81c7dSKirk McKusick 		sbp->f_asyncreads = mp->mnt_stat.f_asyncreads;
1082fde81c7dSKirk McKusick 		sbp->f_owner = mp->mnt_stat.f_owner;
1083fde81c7dSKirk McKusick 		sbp->f_fsid = mp->mnt_stat.f_fsid;
1084fde81c7dSKirk McKusick 		bcopy((caddr_t)mp->mnt_stat.f_fstypename,
1085fde81c7dSKirk McKusick 			(caddr_t)&sbp->f_fstypename[0], MFSNAMELEN);
1086df8bae1dSRodney W. Grimes 		bcopy((caddr_t)mp->mnt_stat.f_mntonname,
1087df8bae1dSRodney W. Grimes 			(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
1088df8bae1dSRodney W. Grimes 		bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
1089df8bae1dSRodney W. Grimes 			(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
1090df8bae1dSRodney W. Grimes 	}
1091df8bae1dSRodney W. Grimes 	return (0);
1092df8bae1dSRodney W. Grimes }
1093df8bae1dSRodney W. Grimes 
1094df8bae1dSRodney W. Grimes /*
1095df8bae1dSRodney W. Grimes  * Go through the disk queues to initiate sandbagged IO;
1096df8bae1dSRodney W. Grimes  * go through the inodes to write those that have been modified;
1097df8bae1dSRodney W. Grimes  * initiate the writing of the super block if it has been modified.
1098df8bae1dSRodney W. Grimes  *
1099df8bae1dSRodney W. Grimes  * Note: we are always called with the filesystem marked `MPBUSY'.
1100df8bae1dSRodney W. Grimes  */
1101df8bae1dSRodney W. Grimes int
1102b40ce416SJulian Elischer ffs_sync(mp, waitfor, cred, td)
1103df8bae1dSRodney W. Grimes 	struct mount *mp;
1104df8bae1dSRodney W. Grimes 	int waitfor;
1105df8bae1dSRodney W. Grimes 	struct ucred *cred;
1106b40ce416SJulian Elischer 	struct thread *td;
1107df8bae1dSRodney W. Grimes {
1108112f7372SKirk McKusick 	struct vnode *nvp, *vp, *devvp;
1109996c772fSJohn Dyson 	struct inode *ip;
1110996c772fSJohn Dyson 	struct ufsmount *ump = VFSTOUFS(mp);
1111996c772fSJohn Dyson 	struct fs *fs;
11129b971133SKirk McKusick 	int error, count, wait, lockreq, allerror = 0;
1113156cb265SPoul-Henning Kamp 	struct bufobj *bo;
1114df8bae1dSRodney W. Grimes 
1115df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
1116996c772fSJohn Dyson 	if (fs->fs_fmod != 0 && fs->fs_ronly != 0) {		/* XXX */
1117df8bae1dSRodney W. Grimes 		printf("fs = %s\n", fs->fs_fsmnt);
11185ace3b26SMike Pritchard 		panic("ffs_sync: rofs mod");
1119df8bae1dSRodney W. Grimes 	}
1120df8bae1dSRodney W. Grimes 	/*
1121df8bae1dSRodney W. Grimes 	 * Write back each (modified) inode.
1122df8bae1dSRodney W. Grimes 	 */
11239b971133SKirk McKusick 	wait = 0;
1124245df27cSMatthew Dillon 	lockreq = LK_EXCLUSIVE | LK_NOWAIT;
11259b971133SKirk McKusick 	if (waitfor == MNT_WAIT) {
11269b971133SKirk McKusick 		wait = 1;
1127245df27cSMatthew Dillon 		lockreq = LK_EXCLUSIVE;
11289b971133SKirk McKusick 	}
11292f05568aSJeff Roberson 	lockreq |= LK_INTERLOCK;
1130ca430f2eSAlexander Kabaev 	MNT_ILOCK(mp);
1131df8bae1dSRodney W. Grimes loop:
1132e3c5a7a4SPoul-Henning Kamp 	MNT_VNODE_FOREACH(vp, mp, nvp) {
1133245df27cSMatthew Dillon 		/*
1134245df27cSMatthew Dillon 		 * Depend on the mntvnode_slock to keep things stable enough
1135245df27cSMatthew Dillon 		 * for a quick test.  Since there might be hundreds of
1136245df27cSMatthew Dillon 		 * thousands of vnodes, we cannot afford even a subroutine
1137245df27cSMatthew Dillon 		 * call unless there's a good chance that we have work to do.
1138245df27cSMatthew Dillon 		 */
11392f05568aSJeff Roberson 		VI_LOCK(vp);
11402f05568aSJeff Roberson 		if (vp->v_iflag & VI_XLOCK) {
11412f05568aSJeff Roberson 			VI_UNLOCK(vp);
11422f05568aSJeff Roberson 			continue;
11432f05568aSJeff Roberson 		}
1144df8bae1dSRodney W. Grimes 		ip = VTOI(vp);
1145cf60e8e4SKirk McKusick 		if (vp->v_type == VNON || ((ip->i_flag &
1146cf60e8e4SKirk McKusick 		    (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
1147156cb265SPoul-Henning Kamp 		    vp->v_bufobj.bo_dirty.bv_cnt == 0)) {
11482f05568aSJeff Roberson 			VI_UNLOCK(vp);
1149df8bae1dSRodney W. Grimes 			continue;
1150996c772fSJohn Dyson 		}
1151ca430f2eSAlexander Kabaev 		MNT_IUNLOCK(mp);
1152b40ce416SJulian Elischer 		if ((error = vget(vp, lockreq, td)) != 0) {
1153ca430f2eSAlexander Kabaev 			MNT_ILOCK(mp);
1154996c772fSJohn Dyson 			if (error == ENOENT)
1155df8bae1dSRodney W. Grimes 				goto loop;
11562f05568aSJeff Roberson 			continue;
11572f05568aSJeff Roberson 		}
1158b40ce416SJulian Elischer 		if ((error = VOP_FSYNC(vp, cred, waitfor, td)) != 0)
1159df8bae1dSRodney W. Grimes 			allerror = error;
1160cb9ddc80SAlexander Kabaev 		VOP_UNLOCK(vp, 0, td);
1161cb9ddc80SAlexander Kabaev 		vrele(vp);
1162ca430f2eSAlexander Kabaev 		MNT_ILOCK(mp);
1163245df27cSMatthew Dillon 	}
1164ca430f2eSAlexander Kabaev 	MNT_IUNLOCK(mp);
1165df8bae1dSRodney W. Grimes 	/*
1166df8bae1dSRodney W. Grimes 	 * Force stale filesystem control information to be flushed.
1167df8bae1dSRodney W. Grimes 	 */
11689b971133SKirk McKusick 	if (waitfor == MNT_WAIT) {
1169b40ce416SJulian Elischer 		if ((error = softdep_flushworklist(ump->um_mountp, &count, td)))
11709b971133SKirk McKusick 			allerror = error;
11719b971133SKirk McKusick 		/* Flushed work items may create new vnodes to clean */
11729ab73fd1SKirk McKusick 		if (allerror == 0 && count) {
1173ca430f2eSAlexander Kabaev 			MNT_ILOCK(mp);
11749b971133SKirk McKusick 			goto loop;
11759b971133SKirk McKusick 		}
11769b971133SKirk McKusick 	}
1177589c7af9SKirk McKusick #ifdef QUOTA
1178589c7af9SKirk McKusick 	qsync(mp);
1179589c7af9SKirk McKusick #endif
1180112f7372SKirk McKusick 	devvp = ump->um_devvp;
11812ee5711eSJeff Roberson 	VI_LOCK(devvp);
1182156cb265SPoul-Henning Kamp 	bo = &devvp->v_bufobj;
1183112f7372SKirk McKusick 	if (waitfor != MNT_LAZY &&
1184156cb265SPoul-Henning Kamp 	    (bo->bo_numoutput > 0 || bo->bo_dirty.bv_cnt > 0)) {
11852ee5711eSJeff Roberson 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY | LK_INTERLOCK, td);
1186b40ce416SJulian Elischer 		if ((error = VOP_FSYNC(devvp, cred, waitfor, td)) != 0)
1187df8bae1dSRodney W. Grimes 			allerror = error;
1188b40ce416SJulian Elischer 		VOP_UNLOCK(devvp, 0, td);
11899ab73fd1SKirk McKusick 		if (allerror == 0 && waitfor == MNT_WAIT) {
1190ca430f2eSAlexander Kabaev 			MNT_ILOCK(mp);
1191112f7372SKirk McKusick 			goto loop;
1192b1897c19SJulian Elischer 		}
1193112f7372SKirk McKusick 	} else
11942ee5711eSJeff Roberson 		VI_UNLOCK(devvp);
1195996c772fSJohn Dyson 	/*
1196996c772fSJohn Dyson 	 * Write back modified superblock.
1197996c772fSJohn Dyson 	 */
1198b1897c19SJulian Elischer 	if (fs->fs_fmod != 0 && (error = ffs_sbupdate(ump, waitfor)) != 0)
1199996c772fSJohn Dyson 		allerror = error;
1200df8bae1dSRodney W. Grimes 	return (allerror);
1201df8bae1dSRodney W. Grimes }
1202df8bae1dSRodney W. Grimes 
1203df8bae1dSRodney W. Grimes int
1204a0595d02SKirk McKusick ffs_vget(mp, ino, flags, vpp)
1205df8bae1dSRodney W. Grimes 	struct mount *mp;
1206df8bae1dSRodney W. Grimes 	ino_t ino;
1207a0595d02SKirk McKusick 	int flags;
1208df8bae1dSRodney W. Grimes 	struct vnode **vpp;
1209df8bae1dSRodney W. Grimes {
1210f576a00dSSemen Ustimenko 	struct thread *td = curthread; 		/* XXX */
1211996c772fSJohn Dyson 	struct fs *fs;
1212996c772fSJohn Dyson 	struct inode *ip;
1213df8bae1dSRodney W. Grimes 	struct ufsmount *ump;
1214df8bae1dSRodney W. Grimes 	struct buf *bp;
1215df8bae1dSRodney W. Grimes 	struct vnode *vp;
121689c9c53dSPoul-Henning Kamp 	struct cdev *dev;
1217f576a00dSSemen Ustimenko 	int error;
1218df8bae1dSRodney W. Grimes 
1219df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
1220df8bae1dSRodney W. Grimes 	dev = ump->um_dev;
1221f576a00dSSemen Ustimenko 
1222f576a00dSSemen Ustimenko 	/*
122313866b3fSSemen Ustimenko 	 * We do not lock vnode creation as it is believed to be too
1224f576a00dSSemen Ustimenko 	 * expensive for such rare case as simultaneous creation of vnode
1225f576a00dSSemen Ustimenko 	 * for same ino by different processes. We just allow them to race
1226f576a00dSSemen Ustimenko 	 * and check later to decide who wins. Let the race begin!
1227f576a00dSSemen Ustimenko 	 */
1228a0595d02SKirk McKusick 	if ((error = ufs_ihashget(dev, ino, flags, vpp)) != 0)
1229a0595d02SKirk McKusick 		return (error);
1230a0595d02SKirk McKusick 	if (*vpp != NULL)
1231df8bae1dSRodney W. Grimes 		return (0);
1232df8bae1dSRodney W. Grimes 
12332094ddb6SDavid Greenman 	/*
12342f9bae59SDavid Greenman 	 * If this MALLOC() is performed after the getnewvnode()
12352f9bae59SDavid Greenman 	 * it might block, leaving a vnode with a NULL v_data to be
12362f9bae59SDavid Greenman 	 * found by ffs_sync() if a sync happens to fire right then,
12372f9bae59SDavid Greenman 	 * which will cause a panic because ffs_sync() blindly
12382f9bae59SDavid Greenman 	 * dereferences vp->v_data (as well it should).
12392f9bae59SDavid Greenman 	 */
1240a163d034SWarner Losh 	ip = uma_zalloc(uma_inode, M_WAITOK);
12412f9bae59SDavid Greenman 
1242df8bae1dSRodney W. Grimes 	/* Allocate a new vnode/inode. */
124306be2aaaSNate Lawson 	error = getnewvnode("ufs", mp, ffs_vnodeop_p, &vp);
1244c9671602SPoul-Henning Kamp 	if (error) {
1245df8bae1dSRodney W. Grimes 		*vpp = NULL;
1246aa4d7a8aSPoul-Henning Kamp 		uma_zfree(uma_inode, ip);
1247df8bae1dSRodney W. Grimes 		return (error);
1248df8bae1dSRodney W. Grimes 	}
1249df8bae1dSRodney W. Grimes 	bzero((caddr_t)ip, sizeof(struct inode));
125067e87166SBoris Popov 	/*
1251a5b65058SKirk McKusick 	 * FFS supports recursive locking.
125267e87166SBoris Popov 	 */
1253c94cd5fcSPoul-Henning Kamp 	fs = ump->um_fs;
1254a5b65058SKirk McKusick 	vp->v_vnlock->lk_flags |= LK_CANRECURSE;
1255df8bae1dSRodney W. Grimes 	vp->v_data = ip;
12565d9d81e7SPoul-Henning Kamp 	vp->v_bufobj.bo_bsize = fs->fs_bsize;
1257df8bae1dSRodney W. Grimes 	ip->i_vnode = vp;
12581c85e6a3SKirk McKusick 	ip->i_ump = ump;
1259c94cd5fcSPoul-Henning Kamp 	ip->i_fs = fs;
1260df8bae1dSRodney W. Grimes 	ip->i_dev = dev;
1261df8bae1dSRodney W. Grimes 	ip->i_number = ino;
1262df8bae1dSRodney W. Grimes #ifdef QUOTA
1263c1d9efcbSPoul-Henning Kamp 	{
1264c1d9efcbSPoul-Henning Kamp 		int i;
1265df8bae1dSRodney W. Grimes 		for (i = 0; i < MAXQUOTAS; i++)
1266df8bae1dSRodney W. Grimes 			ip->i_dquot[i] = NODQUOT;
1267c1d9efcbSPoul-Henning Kamp 	}
1268df8bae1dSRodney W. Grimes #endif
1269df8bae1dSRodney W. Grimes 	/*
1270f576a00dSSemen Ustimenko 	 * Exclusively lock the vnode before adding to hash. Note, that we
1271f576a00dSSemen Ustimenko 	 * must not release nor downgrade the lock (despite flags argument
1272f576a00dSSemen Ustimenko 	 * says) till it is fully initialized.
1273df8bae1dSRodney W. Grimes 	 */
1274f576a00dSSemen Ustimenko 	lockmgr(vp->v_vnlock, LK_EXCLUSIVE, (struct mtx *)0, td);
1275df8bae1dSRodney W. Grimes 
1276937c4dfaSSeigo Tanimura 	/*
1277f576a00dSSemen Ustimenko 	 * Atomicaly (in terms of ufs_hash operations) check the hash for
1278f576a00dSSemen Ustimenko 	 * duplicate of vnode being created and add it to the hash. If a
1279f576a00dSSemen Ustimenko 	 * duplicate vnode was found, it will be vget()ed from hash for us.
1280937c4dfaSSeigo Tanimura 	 */
1281f576a00dSSemen Ustimenko 	if ((error = ufs_ihashins(ip, flags, vpp)) != 0) {
1282f576a00dSSemen Ustimenko 		vput(vp);
1283f576a00dSSemen Ustimenko 		*vpp = NULL;
1284f576a00dSSemen Ustimenko 		return (error);
1285f576a00dSSemen Ustimenko 	}
1286f576a00dSSemen Ustimenko 
1287f576a00dSSemen Ustimenko 	/* We lost the race, then throw away our vnode and return existing */
1288f576a00dSSemen Ustimenko 	if (*vpp != NULL) {
1289f576a00dSSemen Ustimenko 		vput(vp);
1290f576a00dSSemen Ustimenko 		return (0);
1291f576a00dSSemen Ustimenko 	}
12922094ddb6SDavid Greenman 
1293df8bae1dSRodney W. Grimes 	/* Read in the disk contents for the inode, copy into the inode. */
1294c9671602SPoul-Henning Kamp 	error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
1295c9671602SPoul-Henning Kamp 	    (int)fs->fs_bsize, NOCRED, &bp);
1296c9671602SPoul-Henning Kamp 	if (error) {
1297df8bae1dSRodney W. Grimes 		/*
1298df8bae1dSRodney W. Grimes 		 * The inode does not contain anything useful, so it would
1299df8bae1dSRodney W. Grimes 		 * be misleading to leave it on its hash chain. With mode
1300df8bae1dSRodney W. Grimes 		 * still zero, it will be unlinked and returned to the free
1301df8bae1dSRodney W. Grimes 		 * list by vput().
1302df8bae1dSRodney W. Grimes 		 */
1303df8bae1dSRodney W. Grimes 		brelse(bp);
1304bd7e5f99SJohn Dyson 		vput(vp);
1305df8bae1dSRodney W. Grimes 		*vpp = NULL;
1306df8bae1dSRodney W. Grimes 		return (error);
1307df8bae1dSRodney W. Grimes 	}
1308de6ba7c0SPoul-Henning Kamp 	if (ip->i_ump->um_fstype == UFS1)
1309a163d034SWarner Losh 		ip->i_din1 = uma_zalloc(uma_ufs1, M_WAITOK);
1310de6ba7c0SPoul-Henning Kamp 	else
1311a163d034SWarner Losh 		ip->i_din2 = uma_zalloc(uma_ufs2, M_WAITOK);
1312de6ba7c0SPoul-Henning Kamp 	ffs_load_inode(bp, ip, fs, ino);
1313b1897c19SJulian Elischer 	if (DOINGSOFTDEP(vp))
1314b1897c19SJulian Elischer 		softdep_load_inodeblock(ip);
1315b1897c19SJulian Elischer 	else
1316b1897c19SJulian Elischer 		ip->i_effnlink = ip->i_nlink;
1317bd7e5f99SJohn Dyson 	bqrelse(bp);
1318df8bae1dSRodney W. Grimes 
1319df8bae1dSRodney W. Grimes 	/*
1320df8bae1dSRodney W. Grimes 	 * Initialize the vnode from the inode, check for aliases.
1321df8bae1dSRodney W. Grimes 	 * Note that the underlying vnode may have changed.
1322df8bae1dSRodney W. Grimes 	 */
13234f116178SPoul-Henning Kamp 	error = ufs_vinit(mp, ffs_fifoop_p, &vp);
1324c9671602SPoul-Henning Kamp 	if (error) {
1325df8bae1dSRodney W. Grimes 		vput(vp);
1326df8bae1dSRodney W. Grimes 		*vpp = NULL;
1327df8bae1dSRodney W. Grimes 		return (error);
1328df8bae1dSRodney W. Grimes 	}
1329df8bae1dSRodney W. Grimes 	/*
13305c24d6eeSPoul-Henning Kamp 	 * Finish inode initialization.
1331df8bae1dSRodney W. Grimes 	 */
1332df8bae1dSRodney W. Grimes 	VREF(ip->i_devvp);
1333df8bae1dSRodney W. Grimes 	/*
1334df8bae1dSRodney W. Grimes 	 * Set up a generation number for this inode if it does not
1335df8bae1dSRodney W. Grimes 	 * already have one. This should only happen on old filesystems.
1336df8bae1dSRodney W. Grimes 	 */
1337df8bae1dSRodney W. Grimes 	if (ip->i_gen == 0) {
1338aca3e497SKirk McKusick 		ip->i_gen = arc4random() / 2 + 1;
13391c85e6a3SKirk McKusick 		if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
1340df8bae1dSRodney W. Grimes 			ip->i_flag |= IN_MODIFIED;
1341b403319bSAlexander Kabaev 			DIP_SET(ip, i_gen, ip->i_gen);
13421c85e6a3SKirk McKusick 		}
1343df8bae1dSRodney W. Grimes 	}
1344df8bae1dSRodney W. Grimes 	/*
1345df8bae1dSRodney W. Grimes 	 * Ensure that uid and gid are correct. This is a temporary
1346df8bae1dSRodney W. Grimes 	 * fix until fsck has been changed to do the update.
1347df8bae1dSRodney W. Grimes 	 */
13481c85e6a3SKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC &&		/* XXX */
13491c85e6a3SKirk McKusick 	    fs->fs_old_inodefmt < FS_44INODEFMT) {	/* XXX */
13501c85e6a3SKirk McKusick 		ip->i_uid = ip->i_din1->di_ouid;	/* XXX */
13511c85e6a3SKirk McKusick 		ip->i_gid = ip->i_din1->di_ogid;	/* XXX */
1352df8bae1dSRodney W. Grimes 	}						/* XXX */
1353df8bae1dSRodney W. Grimes 
1354763bbd2fSRobert Watson #ifdef MAC
1355763bbd2fSRobert Watson 	if ((mp->mnt_flag & MNT_MULTILABEL) && ip->i_mode) {
1356763bbd2fSRobert Watson 		/*
1357763bbd2fSRobert Watson 		 * If this vnode is already allocated, and we're running
1358763bbd2fSRobert Watson 		 * multi-label, attempt to perform a label association
1359763bbd2fSRobert Watson 		 * from the extended attributes on the inode.
1360763bbd2fSRobert Watson 		 */
1361763bbd2fSRobert Watson 		error = mac_associate_vnode_extattr(mp, vp);
1362763bbd2fSRobert Watson 		if (error) {
1363763bbd2fSRobert Watson 			/* ufs_inactive will release ip->i_devvp ref. */
1364763bbd2fSRobert Watson 			vput(vp);
1365763bbd2fSRobert Watson 			*vpp = NULL;
1366763bbd2fSRobert Watson 			return (error);
1367763bbd2fSRobert Watson 		}
1368763bbd2fSRobert Watson 	}
1369763bbd2fSRobert Watson #endif
1370763bbd2fSRobert Watson 
1371df8bae1dSRodney W. Grimes 	*vpp = vp;
1372df8bae1dSRodney W. Grimes 	return (0);
1373df8bae1dSRodney W. Grimes }
1374df8bae1dSRodney W. Grimes 
1375df8bae1dSRodney W. Grimes /*
1376df8bae1dSRodney W. Grimes  * File handle to vnode
1377df8bae1dSRodney W. Grimes  *
1378df8bae1dSRodney W. Grimes  * Have to be really careful about stale file handles:
1379df8bae1dSRodney W. Grimes  * - check that the inode number is valid
1380df8bae1dSRodney W. Grimes  * - call ffs_vget() to get the locked inode
1381df8bae1dSRodney W. Grimes  * - check for an unallocated inode (i_mode == 0)
1382df8bae1dSRodney W. Grimes  * - check that the given client host has export rights and return
1383df8bae1dSRodney W. Grimes  *   those rights via. exflagsp and credanonp
1384df8bae1dSRodney W. Grimes  */
1385df8bae1dSRodney W. Grimes int
1386c24fda81SAlfred Perlstein ffs_fhtovp(mp, fhp, vpp)
138705f4ff5dSPoul-Henning Kamp 	struct mount *mp;
1388df8bae1dSRodney W. Grimes 	struct fid *fhp;
1389df8bae1dSRodney W. Grimes 	struct vnode **vpp;
1390df8bae1dSRodney W. Grimes {
139105f4ff5dSPoul-Henning Kamp 	struct ufid *ufhp;
1392df8bae1dSRodney W. Grimes 	struct fs *fs;
1393df8bae1dSRodney W. Grimes 
1394df8bae1dSRodney W. Grimes 	ufhp = (struct ufid *)fhp;
1395df8bae1dSRodney W. Grimes 	fs = VFSTOUFS(mp)->um_fs;
1396df8bae1dSRodney W. Grimes 	if (ufhp->ufid_ino < ROOTINO ||
1397df8bae1dSRodney W. Grimes 	    ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg)
1398df8bae1dSRodney W. Grimes 		return (ESTALE);
1399c24fda81SAlfred Perlstein 	return (ufs_fhtovp(mp, ufhp, vpp));
1400df8bae1dSRodney W. Grimes }
1401df8bae1dSRodney W. Grimes 
1402df8bae1dSRodney W. Grimes /*
1403df8bae1dSRodney W. Grimes  * Vnode pointer to File handle
1404df8bae1dSRodney W. Grimes  */
1405df8bae1dSRodney W. Grimes /* ARGSUSED */
140626f9a767SRodney W. Grimes int
1407df8bae1dSRodney W. Grimes ffs_vptofh(vp, fhp)
1408df8bae1dSRodney W. Grimes 	struct vnode *vp;
1409df8bae1dSRodney W. Grimes 	struct fid *fhp;
1410df8bae1dSRodney W. Grimes {
141105f4ff5dSPoul-Henning Kamp 	struct inode *ip;
141205f4ff5dSPoul-Henning Kamp 	struct ufid *ufhp;
1413df8bae1dSRodney W. Grimes 
1414df8bae1dSRodney W. Grimes 	ip = VTOI(vp);
1415df8bae1dSRodney W. Grimes 	ufhp = (struct ufid *)fhp;
1416df8bae1dSRodney W. Grimes 	ufhp->ufid_len = sizeof(struct ufid);
1417df8bae1dSRodney W. Grimes 	ufhp->ufid_ino = ip->i_number;
1418df8bae1dSRodney W. Grimes 	ufhp->ufid_gen = ip->i_gen;
1419df8bae1dSRodney W. Grimes 	return (0);
1420df8bae1dSRodney W. Grimes }
1421df8bae1dSRodney W. Grimes 
1422df8bae1dSRodney W. Grimes /*
14235346934fSIan Dowse  * Initialize the filesystem.
1424996c772fSJohn Dyson  */
1425996c772fSJohn Dyson static int
1426996c772fSJohn Dyson ffs_init(vfsp)
1427996c772fSJohn Dyson 	struct vfsconf *vfsp;
1428996c772fSJohn Dyson {
1429996c772fSJohn Dyson 
1430b1897c19SJulian Elischer 	softdep_initialize();
1431996c772fSJohn Dyson 	return (ufs_init(vfsp));
1432996c772fSJohn Dyson }
1433996c772fSJohn Dyson 
1434996c772fSJohn Dyson /*
14355346934fSIan Dowse  * Undo the work of ffs_init().
14365346934fSIan Dowse  */
14375346934fSIan Dowse static int
14385346934fSIan Dowse ffs_uninit(vfsp)
14395346934fSIan Dowse 	struct vfsconf *vfsp;
14405346934fSIan Dowse {
14415346934fSIan Dowse 	int ret;
14425346934fSIan Dowse 
14435346934fSIan Dowse 	ret = ufs_uninit(vfsp);
14445346934fSIan Dowse 	softdep_uninitialize();
14455346934fSIan Dowse 	return (ret);
14465346934fSIan Dowse }
14475346934fSIan Dowse 
14485346934fSIan Dowse /*
1449df8bae1dSRodney W. Grimes  * Write a superblock and associated information back to disk.
1450df8bae1dSRodney W. Grimes  */
1451b8dce649SPoul-Henning Kamp static int
1452df8bae1dSRodney W. Grimes ffs_sbupdate(mp, waitfor)
1453df8bae1dSRodney W. Grimes 	struct ufsmount *mp;
1454df8bae1dSRodney W. Grimes 	int waitfor;
1455df8bae1dSRodney W. Grimes {
14561c85e6a3SKirk McKusick 	struct fs *fs = mp->um_fs;
145705f4ff5dSPoul-Henning Kamp 	struct buf *bp;
1458df8bae1dSRodney W. Grimes 	int blks;
1459f55ff3f3SIan Dowse 	void *space;
1460996c772fSJohn Dyson 	int i, size, error, allerror = 0;
1461df8bae1dSRodney W. Grimes 
146274f3809aSKirk McKusick 	if (fs->fs_ronly == 1 &&
146374f3809aSKirk McKusick 	    (mp->um_mountp->mnt_flag & (MNT_RDONLY | MNT_UPDATE)) !=
146474f3809aSKirk McKusick 	    (MNT_RDONLY | MNT_UPDATE))
146574f3809aSKirk McKusick 		panic("ffs_sbupdate: write read-only filesystem");
1466996c772fSJohn Dyson 	/*
1467996c772fSJohn Dyson 	 * First write back the summary information.
1468996c772fSJohn Dyson 	 */
1469df8bae1dSRodney W. Grimes 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
1470f55ff3f3SIan Dowse 	space = fs->fs_csp;
1471df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
1472df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
1473df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
1474df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
1475df8bae1dSRodney W. Grimes 		bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i),
14767261f5f6SJeff Roberson 		    size, 0, 0, 0);
1477df8bae1dSRodney W. Grimes 		bcopy(space, bp->b_data, (u_int)size);
1478f55ff3f3SIan Dowse 		space = (char *)space + size;
1479996c772fSJohn Dyson 		if (waitfor != MNT_WAIT)
1480df8bae1dSRodney W. Grimes 			bawrite(bp);
14818aef1712SMatthew Dillon 		else if ((error = bwrite(bp)) != 0)
1482996c772fSJohn Dyson 			allerror = error;
1483df8bae1dSRodney W. Grimes 	}
1484996c772fSJohn Dyson 	/*
1485996c772fSJohn Dyson 	 * Now write back the superblock itself. If any errors occurred
1486996c772fSJohn Dyson 	 * up to this point, then fail so that the superblock avoids
1487996c772fSJohn Dyson 	 * being written out as clean.
1488996c772fSJohn Dyson 	 */
1489996c772fSJohn Dyson 	if (allerror)
1490996c772fSJohn Dyson 		return (allerror);
149131574422SKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_sblockloc != SBLOCK_UFS1 &&
149231574422SKirk McKusick 	    (fs->fs_flags & FS_FLAGS_UPDATED) == 0) {
1493fa5d33e2SKirk McKusick 		printf("%s: correcting fs_sblockloc from %jd to %d\n",
1494fa5d33e2SKirk McKusick 		    fs->fs_fsmnt, fs->fs_sblockloc, SBLOCK_UFS1);
1495fa5d33e2SKirk McKusick 		fs->fs_sblockloc = SBLOCK_UFS1;
1496fa5d33e2SKirk McKusick 	}
149731574422SKirk McKusick 	if (fs->fs_magic == FS_UFS2_MAGIC && fs->fs_sblockloc != SBLOCK_UFS2 &&
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_UFS2);
1501fa5d33e2SKirk McKusick 		fs->fs_sblockloc = SBLOCK_UFS2;
1502fa5d33e2SKirk McKusick 	}
1503ada981b2SKirk McKusick 	bp = getblk(mp->um_devvp, btodb(fs->fs_sblockloc), (int)fs->fs_sbsize,
15047261f5f6SJeff Roberson 	    0, 0, 0);
1505b1897c19SJulian Elischer 	fs->fs_fmod = 0;
1506227ee8a1SPoul-Henning Kamp 	fs->fs_time = time_second;
1507996c772fSJohn Dyson 	bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize);
15081c85e6a3SKirk McKusick 	ffs_oldfscompat_write((struct fs *)bp->b_data, mp);
1509996c772fSJohn Dyson 	if (waitfor != MNT_WAIT)
1510996c772fSJohn Dyson 		bawrite(bp);
15118aef1712SMatthew Dillon 	else if ((error = bwrite(bp)) != 0)
1512996c772fSJohn Dyson 		allerror = error;
1513996c772fSJohn Dyson 	return (allerror);
1514df8bae1dSRodney W. Grimes }
1515d6fe88e4SPoul-Henning Kamp 
1516d6fe88e4SPoul-Henning Kamp static int
1517d6fe88e4SPoul-Henning Kamp ffs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp,
1518d6fe88e4SPoul-Henning Kamp 	int attrnamespace, const char *attrname, struct thread *td)
1519d6fe88e4SPoul-Henning Kamp {
1520d6fe88e4SPoul-Henning Kamp 
1521d6fe88e4SPoul-Henning Kamp #ifdef UFS_EXTATTR
1522d6fe88e4SPoul-Henning Kamp 	return (ufs_extattrctl(mp, cmd, filename_vp, attrnamespace,
1523d6fe88e4SPoul-Henning Kamp 	    attrname, td));
1524d6fe88e4SPoul-Henning Kamp #else
1525d6fe88e4SPoul-Henning Kamp 	return (vfs_stdextattrctl(mp, cmd, filename_vp, attrnamespace,
1526d6fe88e4SPoul-Henning Kamp 	    attrname, td));
1527d6fe88e4SPoul-Henning Kamp #endif
1528d6fe88e4SPoul-Henning Kamp }
1529975512a9SPoul-Henning Kamp 
1530975512a9SPoul-Henning Kamp static void
1531975512a9SPoul-Henning Kamp ffs_ifree(struct ufsmount *ump, struct inode *ip)
1532975512a9SPoul-Henning Kamp {
1533975512a9SPoul-Henning Kamp 
153436329289STim J. Robbins 	if (ump->um_fstype == UFS1 && ip->i_din1 != NULL)
1535aa4d7a8aSPoul-Henning Kamp 		uma_zfree(uma_ufs1, ip->i_din1);
153636329289STim J. Robbins 	else if (ip->i_din2 != NULL)
15378d721e87STim J. Robbins 		uma_zfree(uma_ufs2, ip->i_din2);
1538aa4d7a8aSPoul-Henning Kamp 	uma_zfree(uma_inode, ip);
1539975512a9SPoul-Henning Kamp }
15406e77a041SPoul-Henning Kamp 
15416e77a041SPoul-Henning Kamp void
15426e77a041SPoul-Henning Kamp ffs_geom_strategy(struct bufobj *bo, struct buf *bp)
15436e77a041SPoul-Henning Kamp {
15446e77a041SPoul-Henning Kamp 	int i = 0;
15456e77a041SPoul-Henning Kamp 	struct vnode *vp;
15466e77a041SPoul-Henning Kamp 
15476e77a041SPoul-Henning Kamp 	vp = bp->b_vp;
15486e77a041SPoul-Henning Kamp #if 0
15496e77a041SPoul-Henning Kamp 	KASSERT(vp == bo->bo_vnode, ("Inconsistent vnode bufstrategy"));
15506e77a041SPoul-Henning Kamp 	KASSERT(vp->v_type != VCHR && vp->v_type != VBLK,
15516e77a041SPoul-Henning Kamp 	    ("Wrong vnode in bufstrategy(bp=%p, vp=%p)", bp, vp));
15526e77a041SPoul-Henning Kamp #endif
15536e77a041SPoul-Henning Kamp 	if (vp->v_type == VCHR) {
15546e77a041SPoul-Henning Kamp #ifdef SOFTUPDATES
15556e77a041SPoul-Henning Kamp 		if (bp->b_iocmd == BIO_WRITE && softdep_disk_prewrite(bp->b_vp, bp))
15566e77a041SPoul-Henning Kamp 			return;
15576e77a041SPoul-Henning Kamp #endif
15586e77a041SPoul-Henning Kamp 		i = VOP_SPECSTRATEGY(vp, bp);
15596e77a041SPoul-Henning Kamp 	} else {
15606e77a041SPoul-Henning Kamp 		i = VOP_STRATEGY(vp, bp);
15616e77a041SPoul-Henning Kamp 	}
15626e77a041SPoul-Henning Kamp 	KASSERT(i == 0, ("VOP_STRATEGY failed bp=%p vp=%p", bp, bp->b_vp));
15636e77a041SPoul-Henning Kamp }
15646e77a041SPoul-Henning Kamp 
1565