xref: /freebsd/sys/ufs/ffs/ffs_vfsops.c (revision 16b1f68d8c153996c03f8e73d09d57c1af93f77b)
160727d8bSWarner Losh /*-
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 
3501733a9bSGarrett Wollman #include "opt_quota.h"
36516081f2SRobert Watson #include "opt_ufs.h"
376e77a041SPoul-Henning Kamp #include "opt_ffs.h"
3852dfc8d7SKonstantin Belousov #include "opt_ddb.h"
3901733a9bSGarrett Wollman 
40df8bae1dSRodney W. Grimes #include <sys/param.h>
41df8bae1dSRodney W. Grimes #include <sys/systm.h>
42df8bae1dSRodney W. Grimes #include <sys/namei.h>
43acd3428bSRobert Watson #include <sys/priv.h>
44df8bae1dSRodney W. Grimes #include <sys/proc.h>
45df8bae1dSRodney W. Grimes #include <sys/kernel.h>
46df8bae1dSRodney W. Grimes #include <sys/vnode.h>
47df8bae1dSRodney W. Grimes #include <sys/mount.h>
489626b608SPoul-Henning Kamp #include <sys/bio.h>
49df8bae1dSRodney W. Grimes #include <sys/buf.h>
5081bca6ddSKATO Takenori #include <sys/conf.h>
513ac4d1efSBruce Evans #include <sys/fcntl.h>
52df8bae1dSRodney W. Grimes #include <sys/malloc.h>
531b367556SJason Evans #include <sys/mutex.h>
54a18b1f1dSJason Evans 
55aed55708SRobert Watson #include <security/mac/mac_framework.h>
56aed55708SRobert Watson 
57a64ed089SRobert Watson #include <ufs/ufs/extattr.h>
581a60c7fcSPawel Jakub Dawidek #include <ufs/ufs/gjournal.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 
7143920011SPoul-Henning Kamp #include <geom/geom.h>
7243920011SPoul-Henning Kamp #include <geom/geom_vfs.h>
7343920011SPoul-Henning Kamp 
7452dfc8d7SKonstantin Belousov #include <ddb/ddb.h>
7552dfc8d7SKonstantin Belousov 
76adf41577SPoul-Henning Kamp static uma_zone_t uma_inode, uma_ufs1, uma_ufs2;
7755166637SPoul-Henning Kamp 
785e8c582aSPoul-Henning Kamp static int	ffs_reload(struct mount *, struct thread *);
79975512a9SPoul-Henning Kamp static int	ffs_mountfs(struct vnode *, struct mount *, struct thread *);
801c85e6a3SKirk McKusick static void	ffs_oldfscompat_read(struct fs *, struct ufsmount *,
811c85e6a3SKirk McKusick 		    ufs2_daddr_t);
82975512a9SPoul-Henning Kamp static void	ffs_ifree(struct ufsmount *ump, struct inode *ip);
839bf1a756SPoul-Henning Kamp static vfs_init_t ffs_init;
849bf1a756SPoul-Henning Kamp static vfs_uninit_t ffs_uninit;
85d6fe88e4SPoul-Henning Kamp static vfs_extattrctl_t ffs_extattrctl;
8620a92a18SPoul-Henning Kamp static vfs_cmount_t ffs_cmount;
87adf41577SPoul-Henning Kamp static vfs_unmount_t ffs_unmount;
8820a92a18SPoul-Henning Kamp static vfs_mount_t ffs_mount;
89adf41577SPoul-Henning Kamp static vfs_statfs_t ffs_statfs;
90adf41577SPoul-Henning Kamp static vfs_fhtovp_t ffs_fhtovp;
91adf41577SPoul-Henning Kamp static vfs_sync_t ffs_sync;
92df8bae1dSRodney W. Grimes 
93303b270bSEivind Eklund static struct vfsops ufs_vfsops = {
947652131bSPoul-Henning Kamp 	.vfs_extattrctl =	ffs_extattrctl,
957652131bSPoul-Henning Kamp 	.vfs_fhtovp =		ffs_fhtovp,
967652131bSPoul-Henning Kamp 	.vfs_init =		ffs_init,
9720a92a18SPoul-Henning Kamp 	.vfs_mount =		ffs_mount,
9820a92a18SPoul-Henning Kamp 	.vfs_cmount =		ffs_cmount,
997652131bSPoul-Henning Kamp 	.vfs_quotactl =		ufs_quotactl,
1007652131bSPoul-Henning Kamp 	.vfs_root =		ufs_root,
1017652131bSPoul-Henning Kamp 	.vfs_statfs =		ffs_statfs,
1027652131bSPoul-Henning Kamp 	.vfs_sync =		ffs_sync,
1037652131bSPoul-Henning Kamp 	.vfs_uninit =		ffs_uninit,
1047652131bSPoul-Henning Kamp 	.vfs_unmount =		ffs_unmount,
1057652131bSPoul-Henning Kamp 	.vfs_vget =		ffs_vget,
1062814d5baSKonstantin Belousov 	.vfs_susp_clean =	process_deferred_inactive,
107df8bae1dSRodney W. Grimes };
108df8bae1dSRodney W. Grimes 
1098994ca3cSBruce Evans VFS_SET(ufs_vfsops, ufs, 0);
1105fe6d2beSPawel Jakub Dawidek MODULE_VERSION(ufs, 1);
111c901836cSGarrett Wollman 
1126e77a041SPoul-Henning Kamp static b_strategy_t ffs_geom_strategy;
113dd19a799SPoul-Henning Kamp static b_write_t ffs_bufwrite;
1146e77a041SPoul-Henning Kamp 
1156e77a041SPoul-Henning Kamp static struct buf_ops ffs_ops = {
1166e77a041SPoul-Henning Kamp 	.bop_name =	"FFS",
117dd19a799SPoul-Henning Kamp 	.bop_write =	ffs_bufwrite,
1186e77a041SPoul-Henning Kamp 	.bop_strategy =	ffs_geom_strategy,
1196ef8480aSPoul-Henning Kamp 	.bop_sync =	bufsync,
1202cc7d26fSKonstantin Belousov #ifdef NO_FFS_SNAPSHOT
1212cc7d26fSKonstantin Belousov 	.bop_bdflush =	bufbdflush,
1222cc7d26fSKonstantin Belousov #else
1232cc7d26fSKonstantin Belousov 	.bop_bdflush =	ffs_bdflush,
1242cc7d26fSKonstantin Belousov #endif
1256e77a041SPoul-Henning Kamp };
1266e77a041SPoul-Henning Kamp 
1270b962648SAndriy Gapon /*
1280b962648SAndriy Gapon  * Note that userquota and groupquota options are not currently used
1290b962648SAndriy Gapon  * by UFS/FFS code and generally mount(8) does not pass those options
1300b962648SAndriy Gapon  * from userland, but they can be passed by loader(8) via
1310b962648SAndriy Gapon  * vfs.root.mountfrom.options.
1320b962648SAndriy Gapon  */
133d952ba1bSJohn Baldwin static const char *ffs_opts[] = { "acls", "async", "noatime", "noclusterr",
1340b962648SAndriy Gapon     "noclusterw", "noexec", "export", "force", "from", "groupquota",
1350b962648SAndriy Gapon     "multilabel", "nfsv4acls", "snapshot", "nosuid", "suiddir", "nosymfollow",
1360b962648SAndriy Gapon     "sync", "union", "userquota", NULL };
13720a92a18SPoul-Henning Kamp 
1385e8c582aSPoul-Henning Kamp static int
139dfd233edSAttilio Rao ffs_mount(struct mount *mp)
140df8bae1dSRodney W. Grimes {
14120a92a18SPoul-Henning Kamp 	struct vnode *devvp;
142dfd233edSAttilio Rao 	struct thread *td;
14326f9a767SRodney W. Grimes 	struct ufsmount *ump = 0;
14405f4ff5dSPoul-Henning Kamp 	struct fs *fs;
145f2a2857bSKirk McKusick 	int error, flags;
14661996181SEdward Tomasz Napierala 	u_int mntorflags;
14715bc6b2bSEdward Tomasz Napierala 	accmode_t accmode;
1485e8c582aSPoul-Henning Kamp 	struct nameidata ndp;
14920a92a18SPoul-Henning Kamp 	char *fspec;
150df8bae1dSRodney W. Grimes 
151dfd233edSAttilio Rao 	td = curthread;
15220a92a18SPoul-Henning Kamp 	if (vfs_filteropt(mp->mnt_optnew, ffs_opts))
15320a92a18SPoul-Henning Kamp 		return (EINVAL);
154aa4d7a8aSPoul-Henning Kamp 	if (uma_inode == NULL) {
155aa4d7a8aSPoul-Henning Kamp 		uma_inode = uma_zcreate("FFS inode",
156aa4d7a8aSPoul-Henning Kamp 		    sizeof(struct inode), NULL, NULL, NULL, NULL,
157aa4d7a8aSPoul-Henning Kamp 		    UMA_ALIGN_PTR, 0);
158aa4d7a8aSPoul-Henning Kamp 		uma_ufs1 = uma_zcreate("FFS1 dinode",
159aa4d7a8aSPoul-Henning Kamp 		    sizeof(struct ufs1_dinode), NULL, NULL, NULL, NULL,
160aa4d7a8aSPoul-Henning Kamp 		    UMA_ALIGN_PTR, 0);
161aa4d7a8aSPoul-Henning Kamp 		uma_ufs2 = uma_zcreate("FFS2 dinode",
162aa4d7a8aSPoul-Henning Kamp 		    sizeof(struct ufs2_dinode), NULL, NULL, NULL, NULL,
163aa4d7a8aSPoul-Henning Kamp 		    UMA_ALIGN_PTR, 0);
164aa4d7a8aSPoul-Henning Kamp 	}
1658d02a378SPawel Jakub Dawidek 
1660b962648SAndriy Gapon 	vfs_deleteopt(mp->mnt_optnew, "groupquota");
1670b962648SAndriy Gapon 	vfs_deleteopt(mp->mnt_optnew, "userquota");
1680b962648SAndriy Gapon 
16920a92a18SPoul-Henning Kamp 	fspec = vfs_getopts(mp->mnt_optnew, "from", &error);
17051ac12abSPoul-Henning Kamp 	if (error)
171f2a2857bSKirk McKusick 		return (error);
1722b14f991SJulian Elischer 
1735da56ddbSTor Egge 	mntorflags = 0;
17426f59b64SCraig Rodrigues 	if (vfs_getopt(mp->mnt_optnew, "acls", NULL, NULL) == 0)
1755da56ddbSTor Egge 		mntorflags |= MNT_ACLS;
17626f59b64SCraig Rodrigues 
177fb77e0afSCraig Rodrigues 	if (vfs_getopt(mp->mnt_optnew, "snapshot", NULL, NULL) == 0) {
1785da56ddbSTor Egge 		mntorflags |= MNT_SNAPSHOT;
179fb77e0afSCraig Rodrigues 		/*
180fb77e0afSCraig Rodrigues 		 * Once we have set the MNT_SNAPSHOT flag, do not
181fb77e0afSCraig Rodrigues 		 * persist "snapshot" in the options list.
182fb77e0afSCraig Rodrigues 		 */
183fb77e0afSCraig Rodrigues 		vfs_deleteopt(mp->mnt_optnew, "snapshot");
184fb77e0afSCraig Rodrigues 		vfs_deleteopt(mp->mnt_opt, "snapshot");
185fb77e0afSCraig Rodrigues 	}
18626f59b64SCraig Rodrigues 
1879340fc72SEdward Tomasz Napierala 	if (vfs_getopt(mp->mnt_optnew, "nfsv4acls", NULL, NULL) == 0) {
1889340fc72SEdward Tomasz Napierala 		if (mntorflags & MNT_ACLS) {
1899340fc72SEdward Tomasz Napierala 			printf("WARNING: \"acls\" and \"nfsv4acls\" "
1909340fc72SEdward Tomasz Napierala 			    "options are mutually exclusive\n");
1919340fc72SEdward Tomasz Napierala 			return (EINVAL);
1929340fc72SEdward Tomasz Napierala 		}
1939340fc72SEdward Tomasz Napierala 		mntorflags |= MNT_NFS4ACLS;
1949340fc72SEdward Tomasz Napierala 	}
1959340fc72SEdward Tomasz Napierala 
1965da56ddbSTor Egge 	MNT_ILOCK(mp);
19761996181SEdward Tomasz Napierala 	mp->mnt_flag |= mntorflags;
1985da56ddbSTor Egge 	MNT_IUNLOCK(mp);
199df8bae1dSRodney W. Grimes 	/*
200df8bae1dSRodney W. Grimes 	 * If updating, check whether changing from read-only to
201df8bae1dSRodney W. Grimes 	 * read/write; if there is no device name, that's all we do.
202df8bae1dSRodney W. Grimes 	 */
203df8bae1dSRodney W. Grimes 	if (mp->mnt_flag & MNT_UPDATE) {
204df8bae1dSRodney W. Grimes 		ump = VFSTOUFS(mp);
205df8bae1dSRodney W. Grimes 		fs = ump->um_fs;
20626cf9c3bSPeter Wemm 		devvp = ump->um_devvp;
20720a92a18SPoul-Henning Kamp 		if (fs->fs_ronly == 0 &&
20820a92a18SPoul-Henning Kamp 		    vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) {
2096fecb4e4SKonstantin Belousov 			/*
2106fecb4e4SKonstantin Belousov 			 * Flush any dirty data and suspend filesystem.
2116fecb4e4SKonstantin Belousov 			 */
212f2a2857bSKirk McKusick 			if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0)
213f2a2857bSKirk McKusick 				return (error);
2146fecb4e4SKonstantin Belousov 			for (;;) {
2159ab73fd1SKirk McKusick 				vn_finished_write(mp);
2166fecb4e4SKonstantin Belousov 				if ((error = vfs_write_suspend(mp)) != 0)
2179ab73fd1SKirk McKusick 					return (error);
2186fecb4e4SKonstantin Belousov 				MNT_ILOCK(mp);
2196fecb4e4SKonstantin Belousov 				if (mp->mnt_kern_flag & MNTK_SUSPENDED) {
2206fecb4e4SKonstantin Belousov 					/*
2216fecb4e4SKonstantin Belousov 					 * Allow the secondary writes
2226fecb4e4SKonstantin Belousov 					 * to proceed.
2236fecb4e4SKonstantin Belousov 					 */
2246fecb4e4SKonstantin Belousov 					mp->mnt_kern_flag &= ~(MNTK_SUSPENDED |
2256fecb4e4SKonstantin Belousov 					    MNTK_SUSPEND2);
2266fecb4e4SKonstantin Belousov 					wakeup(&mp->mnt_flag);
2276fecb4e4SKonstantin Belousov 					MNT_IUNLOCK(mp);
2286fecb4e4SKonstantin Belousov 					/*
2296fecb4e4SKonstantin Belousov 					 * Allow the curthread to
2306fecb4e4SKonstantin Belousov 					 * ignore the suspension to
2316fecb4e4SKonstantin Belousov 					 * synchronize on-disk state.
2326fecb4e4SKonstantin Belousov 					 */
233dfd233edSAttilio Rao 					td->td_pflags |= TDP_IGNSUSP;
2346fecb4e4SKonstantin Belousov 					break;
2356fecb4e4SKonstantin Belousov 				}
2366fecb4e4SKonstantin Belousov 				MNT_IUNLOCK(mp);
2376fecb4e4SKonstantin Belousov 				vn_start_write(NULL, &mp, V_WAIT);
2389ab73fd1SKirk McKusick 			}
239cd600596SKirk McKusick 			/*
240cd600596SKirk McKusick 			 * Check for and optionally get rid of files open
241cd600596SKirk McKusick 			 * for writing.
242cd600596SKirk McKusick 			 */
243df8bae1dSRodney W. Grimes 			flags = WRITECLOSE;
244df8bae1dSRodney W. Grimes 			if (mp->mnt_flag & MNT_FORCE)
245df8bae1dSRodney W. Grimes 				flags |= FORCECLOSE;
246b1897c19SJulian Elischer 			if (mp->mnt_flag & MNT_SOFTDEP) {
247b40ce416SJulian Elischer 				error = softdep_flushfiles(mp, flags, td);
248b1897c19SJulian Elischer 			} else {
249b40ce416SJulian Elischer 				error = ffs_flushfiles(mp, flags, td);
250df8bae1dSRodney W. Grimes 			}
251f2a2857bSKirk McKusick 			if (error) {
2526fecb4e4SKonstantin Belousov 				vfs_write_resume(mp);
253f2a2857bSKirk McKusick 				return (error);
254b1897c19SJulian Elischer 			}
2559ccb939eSKirk McKusick 			if (fs->fs_pendingblocks != 0 ||
2569ccb939eSKirk McKusick 			    fs->fs_pendinginodes != 0) {
257cfbf0a46SMaxime Henrion 				printf("%s: %s: blocks %jd files %d\n",
2581c85e6a3SKirk McKusick 				    fs->fs_fsmnt, "update error",
2591c85e6a3SKirk McKusick 				    (intmax_t)fs->fs_pendingblocks,
2609ccb939eSKirk McKusick 				    fs->fs_pendinginodes);
2619ccb939eSKirk McKusick 				fs->fs_pendingblocks = 0;
2629ccb939eSKirk McKusick 				fs->fs_pendinginodes = 0;
2639ccb939eSKirk McKusick 			}
2641a6a6610SKirk McKusick 			if ((fs->fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) == 0)
265f2a2857bSKirk McKusick 				fs->fs_clean = 1;
266791dd2faSTor Egge 			if ((error = ffs_sbupdate(ump, MNT_WAIT, 0)) != 0) {
267f2a2857bSKirk McKusick 				fs->fs_ronly = 0;
268f2a2857bSKirk McKusick 				fs->fs_clean = 0;
2696fecb4e4SKonstantin Belousov 				vfs_write_resume(mp);
270f2a2857bSKirk McKusick 				return (error);
2712b14f991SJulian Elischer 			}
27243920011SPoul-Henning Kamp 			DROP_GIANT();
27343920011SPoul-Henning Kamp 			g_topology_lock();
27443920011SPoul-Henning Kamp 			g_access(ump->um_cp, 0, -1, 0);
27543920011SPoul-Henning Kamp 			g_topology_unlock();
27643920011SPoul-Henning Kamp 			PICKUP_GIANT();
27720a92a18SPoul-Henning Kamp 			fs->fs_ronly = 1;
2785da56ddbSTor Egge 			MNT_ILOCK(mp);
27920a92a18SPoul-Henning Kamp 			mp->mnt_flag |= MNT_RDONLY;
2805da56ddbSTor Egge 			MNT_IUNLOCK(mp);
2816fecb4e4SKonstantin Belousov 			/*
2826fecb4e4SKonstantin Belousov 			 * Allow the writers to note that filesystem
2836fecb4e4SKonstantin Belousov 			 * is ro now.
2846fecb4e4SKonstantin Belousov 			 */
2856fecb4e4SKonstantin Belousov 			vfs_write_resume(mp);
286f2a2857bSKirk McKusick 		}
287f2a2857bSKirk McKusick 		if ((mp->mnt_flag & MNT_RELOAD) &&
2885e8c582aSPoul-Henning Kamp 		    (error = ffs_reload(mp, td)) != 0)
289f2a2857bSKirk McKusick 			return (error);
29020a92a18SPoul-Henning Kamp 		if (fs->fs_ronly &&
29120a92a18SPoul-Henning Kamp 		    !vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) {
292c9b99213SBruce Evans 			/*
293c9b99213SBruce Evans 			 * If upgrade to read-write by non-root, then verify
294c9b99213SBruce Evans 			 * that user has necessary permissions on the device.
295c9b99213SBruce Evans 			 */
296cb05b60aSAttilio Rao 			vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
297acd3428bSRobert Watson 			error = VOP_ACCESS(devvp, VREAD | VWRITE,
298acd3428bSRobert Watson 			    td->td_ucred, td);
299acd3428bSRobert Watson 			if (error)
300acd3428bSRobert Watson 				error = priv_check(td, PRIV_VFS_MOUNT_PERM);
301acd3428bSRobert Watson 			if (error) {
30222db15c0SAttilio Rao 				VOP_UNLOCK(devvp, 0);
303c9b99213SBruce Evans 				return (error);
304c9b99213SBruce Evans 			}
30522db15c0SAttilio Rao 			VOP_UNLOCK(devvp, 0);
3067e58bfacSBruce Evans 			fs->fs_flags &= ~FS_UNCLEAN;
3070922cce6SBruce Evans 			if (fs->fs_clean == 0) {
3087e58bfacSBruce Evans 				fs->fs_flags |= FS_UNCLEAN;
309812b1d41SKirk McKusick 				if ((mp->mnt_flag & MNT_FORCE) ||
310113db2ddSJeff Roberson 				    ((fs->fs_flags &
311113db2ddSJeff Roberson 				     (FS_SUJ | FS_NEEDSFSCK)) == 0 &&
3121a6a6610SKirk McKusick 				     (fs->fs_flags & FS_DOSOFTDEP))) {
313f2a2857bSKirk McKusick 					printf("WARNING: %s was not %s\n",
314f2a2857bSKirk McKusick 					   fs->fs_fsmnt, "properly dismounted");
3150922cce6SBruce Evans 				} else {
3160922cce6SBruce Evans 					printf(
3170922cce6SBruce Evans "WARNING: R/W mount of %s denied.  Filesystem is not clean - run fsck\n",
3180922cce6SBruce Evans 					    fs->fs_fsmnt);
319113db2ddSJeff Roberson 					if (fs->fs_flags & FS_SUJ)
320113db2ddSJeff Roberson 						printf(
32159b3a4ebSDavid E. O'Brien "WARNING: Forced mount will invalidate journal contents\n");
322f2a2857bSKirk McKusick 					return (EPERM);
3230922cce6SBruce Evans 				}
3240922cce6SBruce Evans 			}
32540c340aaSPoul-Henning Kamp 			DROP_GIANT();
32640c340aaSPoul-Henning Kamp 			g_topology_lock();
32740c340aaSPoul-Henning Kamp 			/*
32840c340aaSPoul-Henning Kamp 			 * If we're the root device, we may not have an E count
32940c340aaSPoul-Henning Kamp 			 * yet, get it now.
33040c340aaSPoul-Henning Kamp 			 */
33140c340aaSPoul-Henning Kamp 			if (ump->um_cp->ace == 0)
33240c340aaSPoul-Henning Kamp 				error = g_access(ump->um_cp, 0, 1, 1);
33340c340aaSPoul-Henning Kamp 			else
33440c340aaSPoul-Henning Kamp 				error = g_access(ump->um_cp, 0, 1, 0);
33540c340aaSPoul-Henning Kamp 			g_topology_unlock();
33640c340aaSPoul-Henning Kamp 			PICKUP_GIANT();
33740c340aaSPoul-Henning Kamp 			if (error)
33840c340aaSPoul-Henning Kamp 				return (error);
339f2a2857bSKirk McKusick 			if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0)
340f2a2857bSKirk McKusick 				return (error);
341f2a2857bSKirk McKusick 			fs->fs_ronly = 0;
3425da56ddbSTor Egge 			MNT_ILOCK(mp);
34320a92a18SPoul-Henning Kamp 			mp->mnt_flag &= ~MNT_RDONLY;
3445da56ddbSTor Egge 			MNT_IUNLOCK(mp);
345113db2ddSJeff Roberson 			fs->fs_mtime = time_second;
34626cf9c3bSPeter Wemm 			/* check to see if we need to start softdep */
347f2a2857bSKirk McKusick 			if ((fs->fs_flags & FS_DOSOFTDEP) &&
348a854ed98SJohn Baldwin 			    (error = softdep_mount(devvp, mp, fs, td->td_ucred))){
349f2a2857bSKirk McKusick 				vn_finished_write(mp);
350f2a2857bSKirk McKusick 				return (error);
35126cf9c3bSPeter Wemm 			}
352113db2ddSJeff Roberson 			fs->fs_clean = 0;
353113db2ddSJeff Roberson 			if ((error = ffs_sbupdate(ump, MNT_WAIT, 0)) != 0) {
354113db2ddSJeff Roberson 				vn_finished_write(mp);
355113db2ddSJeff Roberson 				return (error);
356113db2ddSJeff Roberson 			}
357f2a2857bSKirk McKusick 			if (fs->fs_snapinum[0] != 0)
358f2a2857bSKirk McKusick 				ffs_snapshot_mount(mp);
359f2a2857bSKirk McKusick 			vn_finished_write(mp);
3601469eec8SDavid Greenman 		}
361c11d2981SJulian Elischer 		/*
362c11d2981SJulian Elischer 		 * Soft updates is incompatible with "async",
363c11d2981SJulian Elischer 		 * so if we are doing softupdates stop the user
364c11d2981SJulian Elischer 		 * from setting the async flag in an update.
365c11d2981SJulian Elischer 		 * Softdep_mount() clears it in an initial mount
366c11d2981SJulian Elischer 		 * or ro->rw remount.
367c11d2981SJulian Elischer 		 */
3685da56ddbSTor Egge 		if (mp->mnt_flag & MNT_SOFTDEP) {
3695da56ddbSTor Egge 			/* XXX: Reset too late ? */
3705da56ddbSTor Egge 			MNT_ILOCK(mp);
371c11d2981SJulian Elischer 			mp->mnt_flag &= ~MNT_ASYNC;
3725da56ddbSTor Egge 			MNT_IUNLOCK(mp);
3735da56ddbSTor Egge 		}
374df8bae1dSRodney W. Grimes 		/*
37539cfb239SPawel Jakub Dawidek 		 * Keep MNT_ACLS flag if it is stored in superblock.
37639cfb239SPawel Jakub Dawidek 		 */
3775da56ddbSTor Egge 		if ((fs->fs_flags & FS_ACLS) != 0) {
3785da56ddbSTor Egge 			/* XXX: Set too late ? */
3795da56ddbSTor Egge 			MNT_ILOCK(mp);
38039cfb239SPawel Jakub Dawidek 			mp->mnt_flag |= MNT_ACLS;
3815da56ddbSTor Egge 			MNT_IUNLOCK(mp);
3825da56ddbSTor Egge 		}
383cea90362SCraig Rodrigues 
3849340fc72SEdward Tomasz Napierala 		if ((fs->fs_flags & FS_NFS4ACLS) != 0) {
3859340fc72SEdward Tomasz Napierala 			/* XXX: Set too late ? */
3869340fc72SEdward Tomasz Napierala 			MNT_ILOCK(mp);
3879340fc72SEdward Tomasz Napierala 			mp->mnt_flag |= MNT_NFS4ACLS;
3889340fc72SEdward Tomasz Napierala 			MNT_IUNLOCK(mp);
3899340fc72SEdward Tomasz Napierala 		}
3909340fc72SEdward Tomasz Napierala 
391f2a2857bSKirk McKusick 		/*
392f2a2857bSKirk McKusick 		 * If this is a snapshot request, take the snapshot.
393f2a2857bSKirk McKusick 		 */
394f2a2857bSKirk McKusick 		if (mp->mnt_flag & MNT_SNAPSHOT)
39520a92a18SPoul-Henning Kamp 			return (ffs_snapshot(mp, fspec));
396df8bae1dSRodney W. Grimes 	}
3972b14f991SJulian Elischer 
398df8bae1dSRodney W. Grimes 	/*
399df8bae1dSRodney W. Grimes 	 * Not an update, or updating the name: look up the name
400e9827c6dSBruce Evans 	 * and verify that it refers to a sensible disk device.
401df8bae1dSRodney W. Grimes 	 */
402fdedad76SSuleiman Souhlal 	NDINIT(&ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspec, td);
4035e8c582aSPoul-Henning Kamp 	if ((error = namei(&ndp)) != 0)
404f2a2857bSKirk McKusick 		return (error);
4055e8c582aSPoul-Henning Kamp 	NDFREE(&ndp, NDF_ONLY_PNBUF);
4065e8c582aSPoul-Henning Kamp 	devvp = ndp.ni_vp;
407f2a2857bSKirk McKusick 	if (!vn_isdisk(devvp, &error)) {
408fdedad76SSuleiman Souhlal 		vput(devvp);
409f2a2857bSKirk McKusick 		return (error);
410f2a2857bSKirk McKusick 	}
411c9b99213SBruce Evans 
412c9b99213SBruce Evans 	/*
413c9b99213SBruce Evans 	 * If mount by non-root, then verify that user has necessary
414c9b99213SBruce Evans 	 * permissions on the device.
415c9b99213SBruce Evans 	 */
41615bc6b2bSEdward Tomasz Napierala 	accmode = VREAD;
417c9b99213SBruce Evans 	if ((mp->mnt_flag & MNT_RDONLY) == 0)
41815bc6b2bSEdward Tomasz Napierala 		accmode |= VWRITE;
41915bc6b2bSEdward Tomasz Napierala 	error = VOP_ACCESS(devvp, accmode, td->td_ucred, td);
420acd3428bSRobert Watson 	if (error)
421acd3428bSRobert Watson 		error = priv_check(td, PRIV_VFS_MOUNT_PERM);
422acd3428bSRobert Watson 	if (error) {
423c9b99213SBruce Evans 		vput(devvp);
424c9b99213SBruce Evans 		return (error);
425c9b99213SBruce Evans 	}
426c9b99213SBruce Evans 
4272b14f991SJulian Elischer 	if (mp->mnt_flag & MNT_UPDATE) {
4282b14f991SJulian Elischer 		/*
429f2a2857bSKirk McKusick 		 * Update only
430f2a2857bSKirk McKusick 		 *
4313e425b96SJulian Elischer 		 * If it's not the same vnode, or at least the same device
4323e425b96SJulian Elischer 		 * then it's not correct.
4332b14f991SJulian Elischer 		 */
4342b14f991SJulian Elischer 
43543920011SPoul-Henning Kamp 		if (devvp->v_rdev != ump->um_devvp->v_rdev)
436f2a2857bSKirk McKusick 			error = EINVAL;	/* needs translation */
437fdedad76SSuleiman Souhlal 		vput(devvp);
438f2a2857bSKirk McKusick 		if (error)
439f2a2857bSKirk McKusick 			return (error);
4402b14f991SJulian Elischer 	} else {
4412b14f991SJulian Elischer 		/*
442f2a2857bSKirk McKusick 		 * New mount
4432b14f991SJulian Elischer 		 *
444f2a2857bSKirk McKusick 		 * We need the name for the mount point (also used for
445f2a2857bSKirk McKusick 		 * "last mounted on") copied in. If an error occurs,
446f2a2857bSKirk McKusick 		 * the mount point is discarded by the upper level code.
447f3a90da9SAdrian Chadd 		 * Note that vfs_mount() populates f_mntonname for us.
448f2a2857bSKirk McKusick 		 */
449975512a9SPoul-Henning Kamp 		if ((error = ffs_mountfs(devvp, mp, td)) != 0) {
450f2a2857bSKirk McKusick 			vrele(devvp);
451f2a2857bSKirk McKusick 			return (error);
452f2a2857bSKirk McKusick 		}
453f2a2857bSKirk McKusick 	}
45420a92a18SPoul-Henning Kamp 	vfs_mountedfrom(mp, fspec);
455f2a2857bSKirk McKusick 	return (0);
4562b14f991SJulian Elischer }
4572b14f991SJulian Elischer 
458df8bae1dSRodney W. Grimes /*
45920a92a18SPoul-Henning Kamp  * Compatibility with old mount system call.
46020a92a18SPoul-Henning Kamp  */
46120a92a18SPoul-Henning Kamp 
46220a92a18SPoul-Henning Kamp static int
463dfd233edSAttilio Rao ffs_cmount(struct mntarg *ma, void *data, int flags)
46420a92a18SPoul-Henning Kamp {
46520a92a18SPoul-Henning Kamp 	struct ufs_args args;
466d0cc54f3SKonstantin Belousov 	struct export_args exp;
46720a92a18SPoul-Henning Kamp 	int error;
46820a92a18SPoul-Henning Kamp 
46920a92a18SPoul-Henning Kamp 	if (data == NULL)
47020a92a18SPoul-Henning Kamp 		return (EINVAL);
47120a92a18SPoul-Henning Kamp 	error = copyin(data, &args, sizeof args);
47220a92a18SPoul-Henning Kamp 	if (error)
47320a92a18SPoul-Henning Kamp 		return (error);
474d0cc54f3SKonstantin Belousov 	vfs_oexport_conv(&args.export, &exp);
47520a92a18SPoul-Henning Kamp 
47620a92a18SPoul-Henning Kamp 	ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN);
477d0cc54f3SKonstantin Belousov 	ma = mount_arg(ma, "export", &exp, sizeof(exp));
47820a92a18SPoul-Henning Kamp 	error = kernel_mount(ma, flags);
47920a92a18SPoul-Henning Kamp 
48020a92a18SPoul-Henning Kamp 	return (error);
48120a92a18SPoul-Henning Kamp }
48220a92a18SPoul-Henning Kamp 
48320a92a18SPoul-Henning Kamp /*
484df8bae1dSRodney W. Grimes  * Reload all incore data for a filesystem (used after running fsck on
485df8bae1dSRodney W. Grimes  * the root filesystem and finding things to fix). The filesystem must
486df8bae1dSRodney W. Grimes  * be mounted read-only.
487df8bae1dSRodney W. Grimes  *
488df8bae1dSRodney W. Grimes  * Things to do to update the mount:
489df8bae1dSRodney W. Grimes  *	1) invalidate all cached meta-data.
490df8bae1dSRodney W. Grimes  *	2) re-read superblock from disk.
491df8bae1dSRodney W. Grimes  *	3) re-read summary information from disk.
492df8bae1dSRodney W. Grimes  *	4) invalidate all inactive vnodes.
493df8bae1dSRodney W. Grimes  *	5) invalidate all cached file data.
494df8bae1dSRodney W. Grimes  *	6) re-read inode data for all active vnodes.
495df8bae1dSRodney W. Grimes  */
4965e8c582aSPoul-Henning Kamp static int
4975e8c582aSPoul-Henning Kamp ffs_reload(struct mount *mp, struct thread *td)
498df8bae1dSRodney W. Grimes {
49982be0a5aSTor Egge 	struct vnode *vp, *mvp, *devvp;
500df8bae1dSRodney W. Grimes 	struct inode *ip;
501f55ff3f3SIan Dowse 	void *space;
502df8bae1dSRodney W. Grimes 	struct buf *bp;
503996c772fSJohn Dyson 	struct fs *fs, *newfs;
5043ba649d7SJeff Roberson 	struct ufsmount *ump;
5051c85e6a3SKirk McKusick 	ufs2_daddr_t sblockloc;
506df8bae1dSRodney W. Grimes 	int i, blks, size, error;
507996c772fSJohn Dyson 	int32_t *lp;
508df8bae1dSRodney W. Grimes 
5092b14f991SJulian Elischer 	if ((mp->mnt_flag & MNT_RDONLY) == 0)
510df8bae1dSRodney W. Grimes 		return (EINVAL);
5113ba649d7SJeff Roberson 	ump = VFSTOUFS(mp);
512df8bae1dSRodney W. Grimes 	/*
513df8bae1dSRodney W. Grimes 	 * Step 1: invalidate all cached meta-data.
514df8bae1dSRodney W. Grimes 	 */
5152b14f991SJulian Elischer 	devvp = VFSTOUFS(mp)->um_devvp;
516cb05b60aSAttilio Rao 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
5170d7935fdSAttilio Rao 	if (vinvalbuf(devvp, 0, 0, 0) != 0)
518df8bae1dSRodney W. Grimes 		panic("ffs_reload: dirty1");
51922db15c0SAttilio Rao 	VOP_UNLOCK(devvp, 0);
52095e5e988SJohn Dyson 
521df8bae1dSRodney W. Grimes 	/*
522df8bae1dSRodney W. Grimes 	 * Step 2: re-read superblock from disk.
523df8bae1dSRodney W. Grimes 	 */
5241c85e6a3SKirk McKusick 	fs = VFSTOUFS(mp)->um_fs;
525ada981b2SKirk McKusick 	if ((error = bread(devvp, btodb(fs->fs_sblockloc), fs->fs_sbsize,
5261c85e6a3SKirk McKusick 	    NOCRED, &bp)) != 0)
527df8bae1dSRodney W. Grimes 		return (error);
528996c772fSJohn Dyson 	newfs = (struct fs *)bp->b_data;
5291c85e6a3SKirk McKusick 	if ((newfs->fs_magic != FS_UFS1_MAGIC &&
5301c85e6a3SKirk McKusick 	     newfs->fs_magic != FS_UFS2_MAGIC) ||
5311c85e6a3SKirk McKusick 	    newfs->fs_bsize > MAXBSIZE ||
532996c772fSJohn Dyson 	    newfs->fs_bsize < sizeof(struct fs)) {
533df8bae1dSRodney W. Grimes 			brelse(bp);
534df8bae1dSRodney W. Grimes 			return (EIO);		/* XXX needs translation */
535df8bae1dSRodney W. Grimes 	}
536996c772fSJohn Dyson 	/*
537996c772fSJohn Dyson 	 * Copy pointer fields back into superblock before copying in	XXX
538996c772fSJohn Dyson 	 * new superblock. These should really be in the ufsmount.	XXX
539996c772fSJohn Dyson 	 * Note that important parameters (eg fs_ncg) are unchanged.
540996c772fSJohn Dyson 	 */
541f55ff3f3SIan Dowse 	newfs->fs_csp = fs->fs_csp;
542996c772fSJohn Dyson 	newfs->fs_maxcluster = fs->fs_maxcluster;
5435d69bac4SIan Dowse 	newfs->fs_contigdirs = fs->fs_contigdirs;
544143a5346SIan Dowse 	newfs->fs_active = fs->fs_active;
54531c81e4bSDon Lewis 	/* The file system is still read-only. */
54631c81e4bSDon Lewis 	newfs->fs_ronly = 1;
5471c85e6a3SKirk McKusick 	sblockloc = fs->fs_sblockloc;
548996c772fSJohn Dyson 	bcopy(newfs, fs, (u_int)fs->fs_sbsize);
549df8bae1dSRodney W. Grimes 	brelse(bp);
550996c772fSJohn Dyson 	mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
5511c85e6a3SKirk McKusick 	ffs_oldfscompat_read(fs, VFSTOUFS(mp), sblockloc);
5523ba649d7SJeff Roberson 	UFS_LOCK(ump);
5539ccb939eSKirk McKusick 	if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
554cfbf0a46SMaxime Henrion 		printf("%s: reload pending error: blocks %jd files %d\n",
5551c85e6a3SKirk McKusick 		    fs->fs_fsmnt, (intmax_t)fs->fs_pendingblocks,
5561c85e6a3SKirk McKusick 		    fs->fs_pendinginodes);
5579ccb939eSKirk McKusick 		fs->fs_pendingblocks = 0;
5589ccb939eSKirk McKusick 		fs->fs_pendinginodes = 0;
5599ccb939eSKirk McKusick 	}
5603ba649d7SJeff Roberson 	UFS_UNLOCK(ump);
561996c772fSJohn Dyson 
562df8bae1dSRodney W. Grimes 	/*
563df8bae1dSRodney W. Grimes 	 * Step 3: re-read summary information from disk.
564df8bae1dSRodney W. Grimes 	 */
565df8bae1dSRodney W. Grimes 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
566f55ff3f3SIan Dowse 	space = fs->fs_csp;
567df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
568df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
569df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
570df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
571c9671602SPoul-Henning Kamp 		error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
572c9671602SPoul-Henning Kamp 		    NOCRED, &bp);
573c9671602SPoul-Henning Kamp 		if (error)
574df8bae1dSRodney W. Grimes 			return (error);
575f55ff3f3SIan Dowse 		bcopy(bp->b_data, space, (u_int)size);
576f55ff3f3SIan Dowse 		space = (char *)space + size;
577df8bae1dSRodney W. Grimes 		brelse(bp);
578df8bae1dSRodney W. Grimes 	}
579996c772fSJohn Dyson 	/*
580996c772fSJohn Dyson 	 * We no longer know anything about clusters per cylinder group.
581996c772fSJohn Dyson 	 */
582996c772fSJohn Dyson 	if (fs->fs_contigsumsize > 0) {
583996c772fSJohn Dyson 		lp = fs->fs_maxcluster;
584996c772fSJohn Dyson 		for (i = 0; i < fs->fs_ncg; i++)
585996c772fSJohn Dyson 			*lp++ = fs->fs_contigsumsize;
586996c772fSJohn Dyson 	}
587996c772fSJohn Dyson 
588df8bae1dSRodney W. Grimes loop:
589ca430f2eSAlexander Kabaev 	MNT_ILOCK(mp);
59082be0a5aSTor Egge 	MNT_VNODE_FOREACH(vp, mp, mvp) {
59104a17687SJeff Roberson 		VI_LOCK(vp);
592fe68abe2SJeff Roberson 		if (vp->v_iflag & VI_DOOMED) {
5932f05568aSJeff Roberson 			VI_UNLOCK(vp);
5942f05568aSJeff Roberson 			continue;
5952f05568aSJeff Roberson 		}
596ca430f2eSAlexander Kabaev 		MNT_IUNLOCK(mp);
597df8bae1dSRodney W. Grimes 		/*
598fe68abe2SJeff Roberson 		 * Step 4: invalidate all cached file data.
599df8bae1dSRodney W. Grimes 		 */
600b40ce416SJulian Elischer 		if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) {
60182be0a5aSTor Egge 			MNT_VNODE_FOREACH_ABORT(mp, mvp);
602df8bae1dSRodney W. Grimes 			goto loop;
603996c772fSJohn Dyson 		}
6040d7935fdSAttilio Rao 		if (vinvalbuf(vp, 0, 0, 0))
605df8bae1dSRodney W. Grimes 			panic("ffs_reload: dirty2");
606df8bae1dSRodney W. Grimes 		/*
607fe68abe2SJeff Roberson 		 * Step 5: re-read inode data for all active vnodes.
608df8bae1dSRodney W. Grimes 		 */
609df8bae1dSRodney W. Grimes 		ip = VTOI(vp);
610c9671602SPoul-Henning Kamp 		error =
611df8bae1dSRodney W. Grimes 		    bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
612c9671602SPoul-Henning Kamp 		    (int)fs->fs_bsize, NOCRED, &bp);
613c9671602SPoul-Henning Kamp 		if (error) {
61422db15c0SAttilio Rao 			VOP_UNLOCK(vp, 0);
61545d45c6cSAlexander Kabaev 			vrele(vp);
61682be0a5aSTor Egge 			MNT_VNODE_FOREACH_ABORT(mp, mvp);
617df8bae1dSRodney W. Grimes 			return (error);
618df8bae1dSRodney W. Grimes 		}
619de6ba7c0SPoul-Henning Kamp 		ffs_load_inode(bp, ip, fs, ip->i_number);
620b1897c19SJulian Elischer 		ip->i_effnlink = ip->i_nlink;
621df8bae1dSRodney W. Grimes 		brelse(bp);
62222db15c0SAttilio Rao 		VOP_UNLOCK(vp, 0);
623cb9ddc80SAlexander Kabaev 		vrele(vp);
624ca430f2eSAlexander Kabaev 		MNT_ILOCK(mp);
625df8bae1dSRodney W. Grimes 	}
626ca430f2eSAlexander Kabaev 	MNT_IUNLOCK(mp);
627df8bae1dSRodney W. Grimes 	return (0);
628df8bae1dSRodney W. Grimes }
629df8bae1dSRodney W. Grimes 
6301c85e6a3SKirk McKusick /*
6311c85e6a3SKirk McKusick  * Possible superblock locations ordered from most to least likely.
6321c85e6a3SKirk McKusick  */
6331c85e6a3SKirk McKusick static int sblock_try[] = SBLOCKSEARCH;
6345819ab3fSKirk McKusick 
635df8bae1dSRodney W. Grimes /*
636df8bae1dSRodney W. Grimes  * Common code for mount and mountroot
637df8bae1dSRodney W. Grimes  */
638975512a9SPoul-Henning Kamp static int
639975512a9SPoul-Henning Kamp ffs_mountfs(devvp, mp, td)
64005f4ff5dSPoul-Henning Kamp 	struct vnode *devvp;
641df8bae1dSRodney W. Grimes 	struct mount *mp;
642b40ce416SJulian Elischer 	struct thread *td;
643df8bae1dSRodney W. Grimes {
64405f4ff5dSPoul-Henning Kamp 	struct ufsmount *ump;
645df8bae1dSRodney W. Grimes 	struct buf *bp;
64605f4ff5dSPoul-Henning Kamp 	struct fs *fs;
64789c9c53dSPoul-Henning Kamp 	struct cdev *dev;
648f55ff3f3SIan Dowse 	void *space;
6491c85e6a3SKirk McKusick 	ufs2_daddr_t sblockloc;
650f5ef029eSPoul-Henning Kamp 	int error, i, blks, size, ronly;
651996c772fSJohn Dyson 	int32_t *lp;
652996c772fSJohn Dyson 	struct ucred *cred;
65343920011SPoul-Henning Kamp 	struct g_consumer *cp;
6543bbd6d8aSJeff Roberson 	struct mount *nmp;
655df8bae1dSRodney W. Grimes 
656ee445a69SJohn Baldwin 	bp = NULL;
657ee445a69SJohn Baldwin 	ump = NULL;
658a854ed98SJohn Baldwin 	cred = td ? td->td_ucred : NOCRED;
65943920011SPoul-Henning Kamp 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
660ee445a69SJohn Baldwin 
661ee445a69SJohn Baldwin 	dev = devvp->v_rdev;
662ee445a69SJohn Baldwin 	dev_ref(dev);
66343920011SPoul-Henning Kamp 	DROP_GIANT();
66443920011SPoul-Henning Kamp 	g_topology_lock();
66543920011SPoul-Henning Kamp 	error = g_vfs_open(devvp, &cp, "ffs", ronly ? 0 : 1);
66643920011SPoul-Henning Kamp 
66743920011SPoul-Henning Kamp 	/*
66843920011SPoul-Henning Kamp 	 * If we are a root mount, drop the E flag so fsck can do its magic.
66993e0b506SPoul-Henning Kamp 	 * We will pick it up again when we remount R/W.
67043920011SPoul-Henning Kamp 	 */
67143920011SPoul-Henning Kamp 	if (error == 0 && ronly && (mp->mnt_flag & MNT_ROOTFS))
67243920011SPoul-Henning Kamp 		error = g_access(cp, 0, 0, -1);
67343920011SPoul-Henning Kamp 	g_topology_unlock();
67443920011SPoul-Henning Kamp 	PICKUP_GIANT();
67522db15c0SAttilio Rao 	VOP_UNLOCK(devvp, 0);
676c9671602SPoul-Henning Kamp 	if (error)
677ee445a69SJohn Baldwin 		goto out;
6780508986cSBruce Evans 	if (devvp->v_rdev->si_iosize_max != 0)
6791b5464efSPoul-Henning Kamp 		mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max;
6801b5464efSPoul-Henning Kamp 	if (mp->mnt_iosize_max > MAXPHYS)
6811b5464efSPoul-Henning Kamp 		mp->mnt_iosize_max = MAXPHYS;
68295e5e988SJohn Dyson 
6836e77a041SPoul-Henning Kamp 	devvp->v_bufobj.bo_ops = &ffs_ops;
6846e77a041SPoul-Henning Kamp 
6851c85e6a3SKirk McKusick 	fs = NULL;
6861c85e6a3SKirk McKusick 	sblockloc = 0;
6871c85e6a3SKirk McKusick 	/*
6881c85e6a3SKirk McKusick 	 * Try reading the superblock in each of its possible locations.
6891c85e6a3SKirk McKusick 	 */
6901c85e6a3SKirk McKusick 	for (i = 0; sblock_try[i] != -1; i++) {
69171ac2d7cSCraig Rodrigues 		if ((SBLOCKSIZE % cp->provider->sectorsize) != 0) {
69271ac2d7cSCraig Rodrigues 			error = EINVAL;
69371ac2d7cSCraig Rodrigues 			vfs_mount_error(mp,
69471ac2d7cSCraig Rodrigues 			    "Invalid sectorsize %d for superblock size %d",
69571ac2d7cSCraig Rodrigues 			    cp->provider->sectorsize, SBLOCKSIZE);
69671ac2d7cSCraig Rodrigues 			goto out;
69771ac2d7cSCraig Rodrigues 		}
69871ac2d7cSCraig Rodrigues 		if ((error = bread(devvp, btodb(sblock_try[i]), SBLOCKSIZE,
6991c85e6a3SKirk McKusick 		    cred, &bp)) != 0)
700df8bae1dSRodney W. Grimes 			goto out;
701df8bae1dSRodney W. Grimes 		fs = (struct fs *)bp->b_data;
702ada981b2SKirk McKusick 		sblockloc = sblock_try[i];
7031c85e6a3SKirk McKusick 		if ((fs->fs_magic == FS_UFS1_MAGIC ||
7041c85e6a3SKirk McKusick 		     (fs->fs_magic == FS_UFS2_MAGIC &&
705ada981b2SKirk McKusick 		      (fs->fs_sblockloc == sblockloc ||
706ada981b2SKirk McKusick 		       (fs->fs_old_flags & FS_FLAGS_UPDATED) == 0))) &&
7071c85e6a3SKirk McKusick 		    fs->fs_bsize <= MAXBSIZE &&
7081c85e6a3SKirk McKusick 		    fs->fs_bsize >= sizeof(struct fs))
7091c85e6a3SKirk McKusick 			break;
7101c85e6a3SKirk McKusick 		brelse(bp);
7111c85e6a3SKirk McKusick 		bp = NULL;
7121c85e6a3SKirk McKusick 	}
7131c85e6a3SKirk McKusick 	if (sblock_try[i] == -1) {
714df8bae1dSRodney W. Grimes 		error = EINVAL;		/* XXX needs translation */
715df8bae1dSRodney W. Grimes 		goto out;
716df8bae1dSRodney W. Grimes 	}
7173f6f17eeSJulian Elischer 	fs->fs_fmod = 0;
7181c85e6a3SKirk McKusick 	fs->fs_flags &= ~FS_INDEXDIRS;	/* no support for directory indicies */
7190922cce6SBruce Evans 	fs->fs_flags &= ~FS_UNCLEAN;
7200922cce6SBruce Evans 	if (fs->fs_clean == 0) {
7210922cce6SBruce Evans 		fs->fs_flags |= FS_UNCLEAN;
722812b1d41SKirk McKusick 		if (ronly || (mp->mnt_flag & MNT_FORCE) ||
723113db2ddSJeff Roberson 		    ((fs->fs_flags & (FS_SUJ | FS_NEEDSFSCK)) == 0 &&
7241a6a6610SKirk McKusick 		     (fs->fs_flags & FS_DOSOFTDEP))) {
72559b3a4ebSDavid E. O'Brien 			printf("WARNING: %s was not properly dismounted\n",
7260922cce6SBruce Evans 			    fs->fs_fsmnt);
7271469eec8SDavid Greenman 		} else {
7280922cce6SBruce Evans 			printf(
7290922cce6SBruce Evans "WARNING: R/W mount of %s denied.  Filesystem is not clean - run fsck\n",
7300922cce6SBruce Evans 			    fs->fs_fsmnt);
731113db2ddSJeff Roberson 			if (fs->fs_flags & FS_SUJ)
732113db2ddSJeff Roberson 				printf(
73359b3a4ebSDavid E. O'Brien "WARNING: Forced mount will invalidate journal contents\n");
7341469eec8SDavid Greenman 			error = EPERM;
7351469eec8SDavid Greenman 			goto out;
7361469eec8SDavid Greenman 		}
7371c85e6a3SKirk McKusick 		if ((fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) &&
7381c85e6a3SKirk McKusick 		    (mp->mnt_flag & MNT_FORCE)) {
739cfbf0a46SMaxime Henrion 			printf("%s: lost blocks %jd files %d\n", fs->fs_fsmnt,
7401c85e6a3SKirk McKusick 			    (intmax_t)fs->fs_pendingblocks,
7411c85e6a3SKirk McKusick 			    fs->fs_pendinginodes);
7429ccb939eSKirk McKusick 			fs->fs_pendingblocks = 0;
7439ccb939eSKirk McKusick 			fs->fs_pendinginodes = 0;
7449ccb939eSKirk McKusick 		}
7459ccb939eSKirk McKusick 	}
7469ccb939eSKirk McKusick 	if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
747cfbf0a46SMaxime Henrion 		printf("%s: mount pending error: blocks %jd files %d\n",
7481c85e6a3SKirk McKusick 		    fs->fs_fsmnt, (intmax_t)fs->fs_pendingblocks,
7491c85e6a3SKirk McKusick 		    fs->fs_pendinginodes);
7509ccb939eSKirk McKusick 		fs->fs_pendingblocks = 0;
7519ccb939eSKirk McKusick 		fs->fs_pendinginodes = 0;
7521469eec8SDavid Greenman 	}
7531a60c7fcSPawel Jakub Dawidek 	if ((fs->fs_flags & FS_GJOURNAL) != 0) {
7541a60c7fcSPawel Jakub Dawidek #ifdef UFS_GJOURNAL
7551a60c7fcSPawel Jakub Dawidek 		/*
7561a60c7fcSPawel Jakub Dawidek 		 * Get journal provider name.
7571a60c7fcSPawel Jakub Dawidek 		 */
7581a60c7fcSPawel Jakub Dawidek 		size = 1024;
7591a60c7fcSPawel Jakub Dawidek 		mp->mnt_gjprovider = malloc(size, M_UFSMNT, M_WAITOK);
7601a60c7fcSPawel Jakub Dawidek 		if (g_io_getattr("GJOURNAL::provider", cp, &size,
7611a60c7fcSPawel Jakub Dawidek 		    mp->mnt_gjprovider) == 0) {
7621a60c7fcSPawel Jakub Dawidek 			mp->mnt_gjprovider = realloc(mp->mnt_gjprovider, size,
7631a60c7fcSPawel Jakub Dawidek 			    M_UFSMNT, M_WAITOK);
7641a60c7fcSPawel Jakub Dawidek 			MNT_ILOCK(mp);
7651a60c7fcSPawel Jakub Dawidek 			mp->mnt_flag |= MNT_GJOURNAL;
7661a60c7fcSPawel Jakub Dawidek 			MNT_IUNLOCK(mp);
7671a60c7fcSPawel Jakub Dawidek 		} else {
7681a60c7fcSPawel Jakub Dawidek 			printf(
7691a60c7fcSPawel Jakub Dawidek "WARNING: %s: GJOURNAL flag on fs but no gjournal provider below\n",
7701a60c7fcSPawel Jakub Dawidek 			    mp->mnt_stat.f_mntonname);
7711a60c7fcSPawel Jakub Dawidek 			free(mp->mnt_gjprovider, M_UFSMNT);
7721a60c7fcSPawel Jakub Dawidek 			mp->mnt_gjprovider = NULL;
7731a60c7fcSPawel Jakub Dawidek 		}
7741a60c7fcSPawel Jakub Dawidek #else
7751a60c7fcSPawel Jakub Dawidek 		printf(
7761a60c7fcSPawel Jakub Dawidek "WARNING: %s: GJOURNAL flag on fs but no UFS_GJOURNAL support\n",
7771a60c7fcSPawel Jakub Dawidek 		    mp->mnt_stat.f_mntonname);
7781a60c7fcSPawel Jakub Dawidek #endif
7791a60c7fcSPawel Jakub Dawidek 	} else {
7801a60c7fcSPawel Jakub Dawidek 		mp->mnt_gjprovider = NULL;
7811a60c7fcSPawel Jakub Dawidek 	}
782a163d034SWarner Losh 	ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK | M_ZERO);
78343920011SPoul-Henning Kamp 	ump->um_cp = cp;
78443920011SPoul-Henning Kamp 	ump->um_bo = &devvp->v_bufobj;
7858dd56505SPoul-Henning Kamp 	ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT, M_WAITOK);
7861c85e6a3SKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC) {
7871c85e6a3SKirk McKusick 		ump->um_fstype = UFS1;
7881c85e6a3SKirk McKusick 		ump->um_balloc = ffs_balloc_ufs1;
7891c85e6a3SKirk McKusick 	} else {
7901c85e6a3SKirk McKusick 		ump->um_fstype = UFS2;
7911c85e6a3SKirk McKusick 		ump->um_balloc = ffs_balloc_ufs2;
7921c85e6a3SKirk McKusick 	}
793cec0f20cSPoul-Henning Kamp 	ump->um_blkatoff = ffs_blkatoff;
794cec0f20cSPoul-Henning Kamp 	ump->um_truncate = ffs_truncate;
795987f5696SPoul-Henning Kamp 	ump->um_update = ffs_update;
796cec0f20cSPoul-Henning Kamp 	ump->um_valloc = ffs_valloc;
797cec0f20cSPoul-Henning Kamp 	ump->um_vfree = ffs_vfree;
798975512a9SPoul-Henning Kamp 	ump->um_ifree = ffs_ifree;
79990446e36SKonstantin Belousov 	ump->um_rdonly = ffs_rdonly;
800*16b1f68dSKonstantin Belousov 	ump->um_snapgone = ffs_snapgone;
8013ba649d7SJeff Roberson 	mtx_init(UFS_MTX(ump), "FFS", "FFS Lock", MTX_DEF);
802df8bae1dSRodney W. Grimes 	bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize);
8031c85e6a3SKirk McKusick 	if (fs->fs_sbsize < SBLOCKSIZE)
804f2a2857bSKirk McKusick 		bp->b_flags |= B_INVAL | B_NOCACHE;
805df8bae1dSRodney W. Grimes 	brelse(bp);
806df8bae1dSRodney W. Grimes 	bp = NULL;
807df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
8081c85e6a3SKirk McKusick 	ffs_oldfscompat_read(fs, ump, sblockloc);
809df8bae1dSRodney W. Grimes 	fs->fs_ronly = ronly;
810996c772fSJohn Dyson 	size = fs->fs_cssize;
811996c772fSJohn Dyson 	blks = howmany(size, fs->fs_fsize);
812996c772fSJohn Dyson 	if (fs->fs_contigsumsize > 0)
813996c772fSJohn Dyson 		size += fs->fs_ncg * sizeof(int32_t);
814a61ab64aSKirk McKusick 	size += fs->fs_ncg * sizeof(u_int8_t);
815a163d034SWarner Losh 	space = malloc((u_long)size, M_UFSMNT, M_WAITOK);
816f55ff3f3SIan Dowse 	fs->fs_csp = space;
817df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
818df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
819df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
820df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
8218aef1712SMatthew Dillon 		if ((error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
8228aef1712SMatthew Dillon 		    cred, &bp)) != 0) {
823f55ff3f3SIan Dowse 			free(fs->fs_csp, M_UFSMNT);
824df8bae1dSRodney W. Grimes 			goto out;
825df8bae1dSRodney W. Grimes 		}
826df8bae1dSRodney W. Grimes 		bcopy(bp->b_data, space, (u_int)size);
827f55ff3f3SIan Dowse 		space = (char *)space + size;
828df8bae1dSRodney W. Grimes 		brelse(bp);
829df8bae1dSRodney W. Grimes 		bp = NULL;
830df8bae1dSRodney W. Grimes 	}
831996c772fSJohn Dyson 	if (fs->fs_contigsumsize > 0) {
832f55ff3f3SIan Dowse 		fs->fs_maxcluster = lp = space;
833996c772fSJohn Dyson 		for (i = 0; i < fs->fs_ncg; i++)
834996c772fSJohn Dyson 			*lp++ = fs->fs_contigsumsize;
8354691e9eaSIan Dowse 		space = lp;
836996c772fSJohn Dyson 	}
837a61ab64aSKirk McKusick 	size = fs->fs_ncg * sizeof(u_int8_t);
838a61ab64aSKirk McKusick 	fs->fs_contigdirs = (u_int8_t *)space;
839a61ab64aSKirk McKusick 	bzero(fs->fs_contigdirs, size);
840143a5346SIan Dowse 	fs->fs_active = NULL;
84177465d93SAlfred Perlstein 	mp->mnt_data = ump;
84268de329eSPoul-Henning Kamp 	mp->mnt_stat.f_fsid.val[0] = fs->fs_id[0];
8438f89943eSGuido van Rooij 	mp->mnt_stat.f_fsid.val[1] = fs->fs_id[1];
8443bbd6d8aSJeff Roberson 	nmp = NULL;
84568de329eSPoul-Henning Kamp 	if (fs->fs_id[0] == 0 || fs->fs_id[1] == 0 ||
8463bbd6d8aSJeff Roberson 	    (nmp = vfs_getvfs(&mp->mnt_stat.f_fsid))) {
8473bbd6d8aSJeff Roberson 		if (nmp)
8483bbd6d8aSJeff Roberson 			vfs_rel(nmp);
84968de329eSPoul-Henning Kamp 		vfs_getnewfsid(mp);
8503bbd6d8aSJeff Roberson 	}
851df8bae1dSRodney W. Grimes 	mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
8525da56ddbSTor Egge 	MNT_ILOCK(mp);
853cc9d8990SPeter Wemm 	mp->mnt_flag |= MNT_LOCAL;
8545da56ddbSTor Egge 	MNT_IUNLOCK(mp);
8555da56ddbSTor Egge 	if ((fs->fs_flags & FS_MULTILABEL) != 0) {
8567b3f1bbdSTom Rhodes #ifdef MAC
8575da56ddbSTor Egge 		MNT_ILOCK(mp);
85880830407SRobert Watson 		mp->mnt_flag |= MNT_MULTILABEL;
8595da56ddbSTor Egge 		MNT_IUNLOCK(mp);
8607b3f1bbdSTom Rhodes #else
8617b3f1bbdSTom Rhodes 		printf(
8627b3f1bbdSTom Rhodes "WARNING: %s: multilabel flag on fs but no MAC support\n",
863946478fcSPawel Jakub Dawidek 		    mp->mnt_stat.f_mntonname);
8647b3f1bbdSTom Rhodes #endif
8655da56ddbSTor Egge 	}
8665da56ddbSTor Egge 	if ((fs->fs_flags & FS_ACLS) != 0) {
8677b3f1bbdSTom Rhodes #ifdef UFS_ACL
8685da56ddbSTor Egge 		MNT_ILOCK(mp);
8699340fc72SEdward Tomasz Napierala 
8709340fc72SEdward Tomasz Napierala 		if (mp->mnt_flag & MNT_NFS4ACLS)
8719340fc72SEdward Tomasz Napierala 			printf("WARNING: ACLs flag on fs conflicts with "
8729340fc72SEdward Tomasz Napierala 			    "\"nfsv4acls\" mount option; option ignored\n");
8739340fc72SEdward Tomasz Napierala 		mp->mnt_flag &= ~MNT_NFS4ACLS;
87480830407SRobert Watson 		mp->mnt_flag |= MNT_ACLS;
8759340fc72SEdward Tomasz Napierala 
8765da56ddbSTor Egge 		MNT_IUNLOCK(mp);
8777b3f1bbdSTom Rhodes #else
87859b3a4ebSDavid E. O'Brien 		printf("WARNING: %s: ACLs flag on fs but no ACLs support\n",
879946478fcSPawel Jakub Dawidek 		    mp->mnt_stat.f_mntonname);
8807b3f1bbdSTom Rhodes #endif
8815da56ddbSTor Egge 	}
8829340fc72SEdward Tomasz Napierala 	if ((fs->fs_flags & FS_NFS4ACLS) != 0) {
8839340fc72SEdward Tomasz Napierala #ifdef UFS_ACL
8849340fc72SEdward Tomasz Napierala 		MNT_ILOCK(mp);
8859340fc72SEdward Tomasz Napierala 
8869340fc72SEdward Tomasz Napierala 		if (mp->mnt_flag & MNT_ACLS)
8879340fc72SEdward Tomasz Napierala 			printf("WARNING: NFSv4 ACLs flag on fs conflicts with "
8889340fc72SEdward Tomasz Napierala 			    "\"acls\" mount option; option ignored\n");
8899340fc72SEdward Tomasz Napierala 		mp->mnt_flag &= ~MNT_ACLS;
8909340fc72SEdward Tomasz Napierala 		mp->mnt_flag |= MNT_NFS4ACLS;
8919340fc72SEdward Tomasz Napierala 
8929340fc72SEdward Tomasz Napierala 		MNT_IUNLOCK(mp);
8939340fc72SEdward Tomasz Napierala #else
8949340fc72SEdward Tomasz Napierala 		printf(
8959340fc72SEdward Tomasz Napierala "WARNING: %s: NFSv4 ACLs flag on fs but no ACLs support\n",
8969340fc72SEdward Tomasz Napierala 		    mp->mnt_stat.f_mntonname);
8979340fc72SEdward Tomasz Napierala #endif
8989340fc72SEdward Tomasz Napierala 	}
8998c2a54deSKonstantin Belousov 	if ((fs->fs_flags & FS_TRIM) != 0) {
9008c2a54deSKonstantin Belousov 		size = sizeof(int);
9018c2a54deSKonstantin Belousov 		if (g_io_getattr("GEOM::candelete", cp, &size,
9028c2a54deSKonstantin Belousov 		    &ump->um_candelete) == 0) {
9038c2a54deSKonstantin Belousov 			if (!ump->um_candelete)
9048c2a54deSKonstantin Belousov 				printf(
9058c2a54deSKonstantin Belousov "WARNING: %s: TRIM flag on fs but disk does not support TRIM\n",
9068c2a54deSKonstantin Belousov 				    mp->mnt_stat.f_mntonname);
9078c2a54deSKonstantin Belousov 		} else {
9088c2a54deSKonstantin Belousov 			printf(
9098c2a54deSKonstantin Belousov "WARNING: %s: TRIM flag on fs but cannot get whether disk supports TRIM\n",
9108c2a54deSKonstantin Belousov 			    mp->mnt_stat.f_mntonname);
9118c2a54deSKonstantin Belousov 			ump->um_candelete = 0;
9128c2a54deSKonstantin Belousov 		}
9138c2a54deSKonstantin Belousov 	}
9149340fc72SEdward Tomasz Napierala 
915df8bae1dSRodney W. Grimes 	ump->um_mountp = mp;
916df8bae1dSRodney W. Grimes 	ump->um_dev = dev;
917df8bae1dSRodney W. Grimes 	ump->um_devvp = devvp;
918df8bae1dSRodney W. Grimes 	ump->um_nindir = fs->fs_nindir;
919df8bae1dSRodney W. Grimes 	ump->um_bptrtodb = fs->fs_fsbtodb;
920df8bae1dSRodney W. Grimes 	ump->um_seqinc = fs->fs_frag;
921df8bae1dSRodney W. Grimes 	for (i = 0; i < MAXQUOTAS; i++)
922df8bae1dSRodney W. Grimes 		ump->um_quotas[i] = NULLVP;
923516081f2SRobert Watson #ifdef UFS_EXTATTR
924a64ed089SRobert Watson 	ufs_extattr_uepm_init(&ump->um_extattr);
925a64ed089SRobert Watson #endif
9262b14f991SJulian Elischer 	/*
9272b14f991SJulian Elischer 	 * Set FS local "last mounted on" information (NULL pad)
9282b14f991SJulian Elischer 	 */
92993373c42SSuleiman Souhlal 	bzero(fs->fs_fsmnt, MAXMNTLEN);
93093373c42SSuleiman Souhlal 	strlcpy(fs->fs_fsmnt, mp->mnt_stat.f_mntonname, MAXMNTLEN);
931113db2ddSJeff Roberson 	mp->mnt_stat.f_iosize = fs->fs_bsize;
9322b14f991SJulian Elischer 
9332b14f991SJulian Elischer 	if( mp->mnt_flag & MNT_ROOTFS) {
9342b14f991SJulian Elischer 		/*
9352b14f991SJulian Elischer 		 * Root mount; update timestamp in mount structure.
9362b14f991SJulian Elischer 		 * this will be used by the common root mount code
9372b14f991SJulian Elischer 		 * to update the system clock.
9382b14f991SJulian Elischer 		 */
9392b14f991SJulian Elischer 		mp->mnt_time = fs->fs_time;
9402b14f991SJulian Elischer 	}
941996c772fSJohn Dyson 
942996c772fSJohn Dyson 	if (ronly == 0) {
943113db2ddSJeff Roberson 		fs->fs_mtime = time_second;
944b1897c19SJulian Elischer 		if ((fs->fs_flags & FS_DOSOFTDEP) &&
945b1897c19SJulian Elischer 		    (error = softdep_mount(devvp, mp, fs, cred)) != 0) {
946f55ff3f3SIan Dowse 			free(fs->fs_csp, M_UFSMNT);
947fddd463dSKonstantin Belousov 			ffs_flushfiles(mp, FORCECLOSE, td);
948b1897c19SJulian Elischer 			goto out;
949b1897c19SJulian Elischer 		}
950f2a2857bSKirk McKusick 		if (fs->fs_snapinum[0] != 0)
951f2a2857bSKirk McKusick 			ffs_snapshot_mount(mp);
952cf60e8e4SKirk McKusick 		fs->fs_fmod = 1;
953996c772fSJohn Dyson 		fs->fs_clean = 0;
954791dd2faSTor Egge 		(void) ffs_sbupdate(ump, MNT_WAIT, 0);
955996c772fSJohn Dyson 	}
956d8d3d415SPoul-Henning Kamp 	/*
957d8d3d415SPoul-Henning Kamp 	 * Initialize filesystem stat information in mount struct.
958d8d3d415SPoul-Henning Kamp 	 */
9596cf7bc60SRobert Watson 	MNT_ILOCK(mp);
96033fc3625SJohn Baldwin 	mp->mnt_kern_flag |= MNTK_MPSAFE | MNTK_LOOKUP_SHARED |
96133fc3625SJohn Baldwin 	    MNTK_EXTENDED_SHARED;
9626cf7bc60SRobert Watson 	MNT_IUNLOCK(mp);
963516081f2SRobert Watson #ifdef UFS_EXTATTR
964516081f2SRobert Watson #ifdef UFS_EXTATTR_AUTOSTART
9659de54ba5SRobert Watson 	/*
9669de54ba5SRobert Watson 	 *
967f5161237SRobert Watson 	 * Auto-starting does the following:
9689de54ba5SRobert Watson 	 *	- check for /.attribute in the fs, and extattr_start if so
9699de54ba5SRobert Watson 	 *	- for each file in .attribute, enable that file with
9709de54ba5SRobert Watson 	 * 	  an attribute of the same name.
9719de54ba5SRobert Watson 	 * Not clear how to report errors -- probably eat them.
9729de54ba5SRobert Watson 	 * This would all happen while the filesystem was busy/not
9739de54ba5SRobert Watson 	 * available, so would effectively be "atomic".
9749de54ba5SRobert Watson 	 */
975b40ce416SJulian Elischer 	(void) ufs_extattr_autostart(mp, td);
976516081f2SRobert Watson #endif /* !UFS_EXTATTR_AUTOSTART */
977516081f2SRobert Watson #endif /* !UFS_EXTATTR */
978df8bae1dSRodney W. Grimes 	return (0);
979df8bae1dSRodney W. Grimes out:
980df8bae1dSRodney W. Grimes 	if (bp)
981df8bae1dSRodney W. Grimes 		brelse(bp);
98243920011SPoul-Henning Kamp 	if (cp != NULL) {
98343920011SPoul-Henning Kamp 		DROP_GIANT();
98443920011SPoul-Henning Kamp 		g_topology_lock();
9850d7935fdSAttilio Rao 		g_vfs_close(cp);
98643920011SPoul-Henning Kamp 		g_topology_unlock();
98743920011SPoul-Henning Kamp 		PICKUP_GIANT();
98843920011SPoul-Henning Kamp 	}
989df8bae1dSRodney W. Grimes 	if (ump) {
9903ba649d7SJeff Roberson 		mtx_destroy(UFS_MTX(ump));
9911a60c7fcSPawel Jakub Dawidek 		if (mp->mnt_gjprovider != NULL) {
9921a60c7fcSPawel Jakub Dawidek 			free(mp->mnt_gjprovider, M_UFSMNT);
9931a60c7fcSPawel Jakub Dawidek 			mp->mnt_gjprovider = NULL;
9941a60c7fcSPawel Jakub Dawidek 		}
995df8bae1dSRodney W. Grimes 		free(ump->um_fs, M_UFSMNT);
996df8bae1dSRodney W. Grimes 		free(ump, M_UFSMNT);
99777465d93SAlfred Perlstein 		mp->mnt_data = NULL;
998df8bae1dSRodney W. Grimes 	}
99949c4791cSEdward Tomasz Napierala 	dev_rel(dev);
1000df8bae1dSRodney W. Grimes 	return (error);
1001df8bae1dSRodney W. Grimes }
1002df8bae1dSRodney W. Grimes 
10031c85e6a3SKirk McKusick #include <sys/sysctl.h>
1004adf41577SPoul-Henning Kamp static int bigcgs = 0;
10051c85e6a3SKirk McKusick SYSCTL_INT(_debug, OID_AUTO, bigcgs, CTLFLAG_RW, &bigcgs, 0, "");
10061c85e6a3SKirk McKusick 
1007df8bae1dSRodney W. Grimes /*
10081c85e6a3SKirk McKusick  * Sanity checks for loading old filesystem superblocks.
10091c85e6a3SKirk McKusick  * See ffs_oldfscompat_write below for unwound actions.
1010df8bae1dSRodney W. Grimes  *
10111c85e6a3SKirk McKusick  * XXX - Parts get retired eventually.
10121c85e6a3SKirk McKusick  * Unfortunately new bits get added.
1013df8bae1dSRodney W. Grimes  */
10141c85e6a3SKirk McKusick static void
10151c85e6a3SKirk McKusick ffs_oldfscompat_read(fs, ump, sblockloc)
1016df8bae1dSRodney W. Grimes 	struct fs *fs;
10171c85e6a3SKirk McKusick 	struct ufsmount *ump;
10181c85e6a3SKirk McKusick 	ufs2_daddr_t sblockloc;
10191c85e6a3SKirk McKusick {
10201c85e6a3SKirk McKusick 	off_t maxfilesize;
10211c85e6a3SKirk McKusick 
10221c85e6a3SKirk McKusick 	/*
1023ada981b2SKirk McKusick 	 * If not yet done, update fs_flags location and value of fs_sblockloc.
1024ada981b2SKirk McKusick 	 */
1025ada981b2SKirk McKusick 	if ((fs->fs_old_flags & FS_FLAGS_UPDATED) == 0) {
1026ada981b2SKirk McKusick 		fs->fs_flags = fs->fs_old_flags;
1027ada981b2SKirk McKusick 		fs->fs_old_flags |= FS_FLAGS_UPDATED;
1028ada981b2SKirk McKusick 		fs->fs_sblockloc = sblockloc;
1029ada981b2SKirk McKusick 	}
1030ada981b2SKirk McKusick 	/*
10311c85e6a3SKirk McKusick 	 * If not yet done, update UFS1 superblock with new wider fields.
10321c85e6a3SKirk McKusick 	 */
103374f3809aSKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_maxbsize != fs->fs_bsize) {
10341c85e6a3SKirk McKusick 		fs->fs_maxbsize = fs->fs_bsize;
10351c85e6a3SKirk McKusick 		fs->fs_time = fs->fs_old_time;
10361c85e6a3SKirk McKusick 		fs->fs_size = fs->fs_old_size;
10371c85e6a3SKirk McKusick 		fs->fs_dsize = fs->fs_old_dsize;
10381c85e6a3SKirk McKusick 		fs->fs_csaddr = fs->fs_old_csaddr;
10391c85e6a3SKirk McKusick 		fs->fs_cstotal.cs_ndir = fs->fs_old_cstotal.cs_ndir;
10401c85e6a3SKirk McKusick 		fs->fs_cstotal.cs_nbfree = fs->fs_old_cstotal.cs_nbfree;
10411c85e6a3SKirk McKusick 		fs->fs_cstotal.cs_nifree = fs->fs_old_cstotal.cs_nifree;
10421c85e6a3SKirk McKusick 		fs->fs_cstotal.cs_nffree = fs->fs_old_cstotal.cs_nffree;
10431c85e6a3SKirk McKusick 	}
10441c85e6a3SKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC &&
10451c85e6a3SKirk McKusick 	    fs->fs_old_inodefmt < FS_44INODEFMT) {
10468680d698SNate Lawson 		fs->fs_maxfilesize = ((uint64_t)1 << 31) - 1;
10471c85e6a3SKirk McKusick 		fs->fs_qbmask = ~fs->fs_bmask;
10481c85e6a3SKirk McKusick 		fs->fs_qfmask = ~fs->fs_fmask;
10491c85e6a3SKirk McKusick 	}
10508f42fb8fSIan Dowse 	if (fs->fs_magic == FS_UFS1_MAGIC) {
10511c85e6a3SKirk McKusick 		ump->um_savedmaxfilesize = fs->fs_maxfilesize;
10528680d698SNate Lawson 		maxfilesize = (uint64_t)0x80000000 * fs->fs_bsize - 1;
10531c85e6a3SKirk McKusick 		if (fs->fs_maxfilesize > maxfilesize)
10541c85e6a3SKirk McKusick 			fs->fs_maxfilesize = maxfilesize;
10558f42fb8fSIan Dowse 	}
10561c85e6a3SKirk McKusick 	/* Compatibility for old filesystems */
10571c85e6a3SKirk McKusick 	if (fs->fs_avgfilesize <= 0)
10581c85e6a3SKirk McKusick 		fs->fs_avgfilesize = AVFILESIZ;
10591c85e6a3SKirk McKusick 	if (fs->fs_avgfpdir <= 0)
10601c85e6a3SKirk McKusick 		fs->fs_avgfpdir = AFPDIR;
10611c85e6a3SKirk McKusick 	if (bigcgs) {
10621c85e6a3SKirk McKusick 		fs->fs_save_cgsize = fs->fs_cgsize;
10631c85e6a3SKirk McKusick 		fs->fs_cgsize = fs->fs_bsize;
10641c85e6a3SKirk McKusick 	}
10651c85e6a3SKirk McKusick }
10661c85e6a3SKirk McKusick 
10671c85e6a3SKirk McKusick /*
10681c85e6a3SKirk McKusick  * Unwinding superblock updates for old filesystems.
10691c85e6a3SKirk McKusick  * See ffs_oldfscompat_read above for details.
10701c85e6a3SKirk McKusick  *
10711c85e6a3SKirk McKusick  * XXX - Parts get retired eventually.
10721c85e6a3SKirk McKusick  * Unfortunately new bits get added.
10731c85e6a3SKirk McKusick  */
1074113db2ddSJeff Roberson void
10751c85e6a3SKirk McKusick ffs_oldfscompat_write(fs, ump)
10761c85e6a3SKirk McKusick 	struct fs *fs;
10771c85e6a3SKirk McKusick 	struct ufsmount *ump;
1078df8bae1dSRodney W. Grimes {
1079df8bae1dSRodney W. Grimes 
10801c85e6a3SKirk McKusick 	/*
10811c85e6a3SKirk McKusick 	 * Copy back UFS2 updated fields that UFS1 inspects.
10821c85e6a3SKirk McKusick 	 */
10831c85e6a3SKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC) {
10841c85e6a3SKirk McKusick 		fs->fs_old_time = fs->fs_time;
10851c85e6a3SKirk McKusick 		fs->fs_old_cstotal.cs_ndir = fs->fs_cstotal.cs_ndir;
10861c85e6a3SKirk McKusick 		fs->fs_old_cstotal.cs_nbfree = fs->fs_cstotal.cs_nbfree;
10871c85e6a3SKirk McKusick 		fs->fs_old_cstotal.cs_nifree = fs->fs_cstotal.cs_nifree;
10881c85e6a3SKirk McKusick 		fs->fs_old_cstotal.cs_nffree = fs->fs_cstotal.cs_nffree;
10891c85e6a3SKirk McKusick 		fs->fs_maxfilesize = ump->um_savedmaxfilesize;
10908f42fb8fSIan Dowse 	}
10911c85e6a3SKirk McKusick 	if (bigcgs) {
10921c85e6a3SKirk McKusick 		fs->fs_cgsize = fs->fs_save_cgsize;
10931c85e6a3SKirk McKusick 		fs->fs_save_cgsize = 0;
10941c85e6a3SKirk McKusick 	}
1095df8bae1dSRodney W. Grimes }
1096df8bae1dSRodney W. Grimes 
1097df8bae1dSRodney W. Grimes /*
1098df8bae1dSRodney W. Grimes  * unmount system call
1099df8bae1dSRodney W. Grimes  */
1100adf41577SPoul-Henning Kamp static int
1101dfd233edSAttilio Rao ffs_unmount(mp, mntflags)
1102df8bae1dSRodney W. Grimes 	struct mount *mp;
1103df8bae1dSRodney W. Grimes 	int mntflags;
1104df8bae1dSRodney W. Grimes {
1105dfd233edSAttilio Rao 	struct thread *td;
110605f4ff5dSPoul-Henning Kamp 	struct ufsmount *ump = VFSTOUFS(mp);
110705f4ff5dSPoul-Henning Kamp 	struct fs *fs;
11086fecb4e4SKonstantin Belousov 	int error, flags, susp;
1109df86ccf6SKonstantin Belousov #ifdef UFS_EXTATTR
1110df86ccf6SKonstantin Belousov 	int e_restart;
1111df86ccf6SKonstantin Belousov #endif
1112df8bae1dSRodney W. Grimes 
1113df8bae1dSRodney W. Grimes 	flags = 0;
1114dfd233edSAttilio Rao 	td = curthread;
11156fecb4e4SKonstantin Belousov 	fs = ump->um_fs;
1116df8bae1dSRodney W. Grimes 	if (mntflags & MNT_FORCE) {
1117df8bae1dSRodney W. Grimes 		flags |= FORCECLOSE;
11186fecb4e4SKonstantin Belousov 		susp = fs->fs_ronly != 0;
11196fecb4e4SKonstantin Belousov 	} else
11206fecb4e4SKonstantin Belousov 		susp = 0;
1121516081f2SRobert Watson #ifdef UFS_EXTATTR
1122b40ce416SJulian Elischer 	if ((error = ufs_extattr_stop(mp, td))) {
1123b2b0497aSRobert Watson 		if (error != EOPNOTSUPP)
1124b2b0497aSRobert Watson 			printf("ffs_unmount: ufs_extattr_stop returned %d\n",
1125b2b0497aSRobert Watson 			    error);
1126df86ccf6SKonstantin Belousov 		e_restart = 0;
11277df97b61SRobert Watson 	} else {
11289de54ba5SRobert Watson 		ufs_extattr_uepm_destroy(&ump->um_extattr);
1129df86ccf6SKonstantin Belousov 		e_restart = 1;
11307df97b61SRobert Watson 	}
1131a64ed089SRobert Watson #endif
11326fecb4e4SKonstantin Belousov 	if (susp) {
11336fecb4e4SKonstantin Belousov 		/*
11346fecb4e4SKonstantin Belousov 		 * dounmount already called vn_start_write().
11356fecb4e4SKonstantin Belousov 		 */
11366fecb4e4SKonstantin Belousov 		for (;;) {
11376fecb4e4SKonstantin Belousov 			vn_finished_write(mp);
11386fecb4e4SKonstantin Belousov 			if ((error = vfs_write_suspend(mp)) != 0)
11396fecb4e4SKonstantin Belousov 				return (error);
11406fecb4e4SKonstantin Belousov 			MNT_ILOCK(mp);
11416fecb4e4SKonstantin Belousov 			if (mp->mnt_kern_flag & MNTK_SUSPENDED) {
11426fecb4e4SKonstantin Belousov 				mp->mnt_kern_flag &= ~(MNTK_SUSPENDED |
11436fecb4e4SKonstantin Belousov 				    MNTK_SUSPEND2);
11446fecb4e4SKonstantin Belousov 				wakeup(&mp->mnt_flag);
11456fecb4e4SKonstantin Belousov 				MNT_IUNLOCK(mp);
1146dfd233edSAttilio Rao 				td->td_pflags |= TDP_IGNSUSP;
11476fecb4e4SKonstantin Belousov 				break;
11486fecb4e4SKonstantin Belousov 			}
11496fecb4e4SKonstantin Belousov 			MNT_IUNLOCK(mp);
11506fecb4e4SKonstantin Belousov 			vn_start_write(NULL, &mp, V_WAIT);
11516fecb4e4SKonstantin Belousov 		}
11526fecb4e4SKonstantin Belousov 	}
11533c140b2dSEdward Tomasz Napierala 	if (mp->mnt_flag & MNT_SOFTDEP)
11543c140b2dSEdward Tomasz Napierala 		error = softdep_flushfiles(mp, flags, td);
11553c140b2dSEdward Tomasz Napierala 	else
11563c140b2dSEdward Tomasz Napierala 		error = ffs_flushfiles(mp, flags, td);
11574f560d75SEdward Tomasz Napierala 	if (error != 0 && error != ENXIO)
11586fecb4e4SKonstantin Belousov 		goto fail;
11593c140b2dSEdward Tomasz Napierala 
11603ba649d7SJeff Roberson 	UFS_LOCK(ump);
11619ccb939eSKirk McKusick 	if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
1162cfbf0a46SMaxime Henrion 		printf("%s: unmount pending error: blocks %jd files %d\n",
11631c85e6a3SKirk McKusick 		    fs->fs_fsmnt, (intmax_t)fs->fs_pendingblocks,
11641c85e6a3SKirk McKusick 		    fs->fs_pendinginodes);
11659ccb939eSKirk McKusick 		fs->fs_pendingblocks = 0;
11669ccb939eSKirk McKusick 		fs->fs_pendinginodes = 0;
11679ccb939eSKirk McKusick 	}
11683ba649d7SJeff Roberson 	UFS_UNLOCK(ump);
1169113db2ddSJeff Roberson 	softdep_unmount(mp);
1170996c772fSJohn Dyson 	if (fs->fs_ronly == 0) {
11711a6a6610SKirk McKusick 		fs->fs_clean = fs->fs_flags & (FS_UNCLEAN|FS_NEEDSFSCK) ? 0 : 1;
1172791dd2faSTor Egge 		error = ffs_sbupdate(ump, MNT_WAIT, 0);
11734f560d75SEdward Tomasz Napierala 		if (error && error != ENXIO) {
1174996c772fSJohn Dyson 			fs->fs_clean = 0;
11756fecb4e4SKonstantin Belousov 			goto fail;
1176996c772fSJohn Dyson 		}
1177e0e9c421SDavid Greenman 	}
11786fecb4e4SKonstantin Belousov 	if (susp) {
11796fecb4e4SKonstantin Belousov 		vfs_write_resume(mp);
11806fecb4e4SKonstantin Belousov 		vn_start_write(NULL, &mp, V_WAIT);
11816fecb4e4SKonstantin Belousov 	}
118243920011SPoul-Henning Kamp 	DROP_GIANT();
118343920011SPoul-Henning Kamp 	g_topology_lock();
11840d7935fdSAttilio Rao 	g_vfs_close(ump->um_cp);
118543920011SPoul-Henning Kamp 	g_topology_unlock();
118643920011SPoul-Henning Kamp 	PICKUP_GIANT();
11876476c0d2SJohn Dyson 	vrele(ump->um_devvp);
118849c4791cSEdward Tomasz Napierala 	dev_rel(ump->um_dev);
11893ba649d7SJeff Roberson 	mtx_destroy(UFS_MTX(ump));
11901a60c7fcSPawel Jakub Dawidek 	if (mp->mnt_gjprovider != NULL) {
11911a60c7fcSPawel Jakub Dawidek 		free(mp->mnt_gjprovider, M_UFSMNT);
11921a60c7fcSPawel Jakub Dawidek 		mp->mnt_gjprovider = NULL;
11931a60c7fcSPawel Jakub Dawidek 	}
1194f55ff3f3SIan Dowse 	free(fs->fs_csp, M_UFSMNT);
1195df8bae1dSRodney W. Grimes 	free(fs, M_UFSMNT);
1196df8bae1dSRodney W. Grimes 	free(ump, M_UFSMNT);
119777465d93SAlfred Perlstein 	mp->mnt_data = NULL;
11985da56ddbSTor Egge 	MNT_ILOCK(mp);
1199cc9d8990SPeter Wemm 	mp->mnt_flag &= ~MNT_LOCAL;
12005da56ddbSTor Egge 	MNT_IUNLOCK(mp);
1201df8bae1dSRodney W. Grimes 	return (error);
12026fecb4e4SKonstantin Belousov 
12036fecb4e4SKonstantin Belousov fail:
12046fecb4e4SKonstantin Belousov 	if (susp) {
12056fecb4e4SKonstantin Belousov 		vfs_write_resume(mp);
12066fecb4e4SKonstantin Belousov 		vn_start_write(NULL, &mp, V_WAIT);
12076fecb4e4SKonstantin Belousov 	}
1208df86ccf6SKonstantin Belousov #ifdef UFS_EXTATTR
1209df86ccf6SKonstantin Belousov 	if (e_restart) {
1210df86ccf6SKonstantin Belousov 		ufs_extattr_uepm_init(&ump->um_extattr);
1211df86ccf6SKonstantin Belousov #ifdef UFS_EXTATTR_AUTOSTART
1212df86ccf6SKonstantin Belousov 		(void) ufs_extattr_autostart(mp, td);
1213df86ccf6SKonstantin Belousov #endif
1214df86ccf6SKonstantin Belousov 	}
1215df86ccf6SKonstantin Belousov #endif
1216df86ccf6SKonstantin Belousov 
12176fecb4e4SKonstantin Belousov 	return (error);
1218df8bae1dSRodney W. Grimes }
1219df8bae1dSRodney W. Grimes 
1220df8bae1dSRodney W. Grimes /*
1221df8bae1dSRodney W. Grimes  * Flush out all the files in a filesystem.
1222df8bae1dSRodney W. Grimes  */
122326f9a767SRodney W. Grimes int
1224b40ce416SJulian Elischer ffs_flushfiles(mp, flags, td)
122505f4ff5dSPoul-Henning Kamp 	struct mount *mp;
1226df8bae1dSRodney W. Grimes 	int flags;
1227b40ce416SJulian Elischer 	struct thread *td;
1228df8bae1dSRodney W. Grimes {
122905f4ff5dSPoul-Henning Kamp 	struct ufsmount *ump;
1230c9671602SPoul-Henning Kamp 	int error;
1231df8bae1dSRodney W. Grimes 
1232df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
1233df8bae1dSRodney W. Grimes #ifdef QUOTA
1234df8bae1dSRodney W. Grimes 	if (mp->mnt_flag & MNT_QUOTA) {
1235c1d9efcbSPoul-Henning Kamp 		int i;
1236f257b7a5SAlfred Perlstein 		error = vflush(mp, 0, SKIPSYSTEM|flags, td);
1237c1d9efcbSPoul-Henning Kamp 		if (error)
1238df8bae1dSRodney W. Grimes 			return (error);
1239df8bae1dSRodney W. Grimes 		for (i = 0; i < MAXQUOTAS; i++) {
1240b40ce416SJulian Elischer 			quotaoff(td, mp, i);
1241df8bae1dSRodney W. Grimes 		}
1242df8bae1dSRodney W. Grimes 		/*
1243df8bae1dSRodney W. Grimes 		 * Here we fall through to vflush again to ensure
1244df8bae1dSRodney W. Grimes 		 * that we have gotten rid of all the system vnodes.
1245df8bae1dSRodney W. Grimes 		 */
1246df8bae1dSRodney W. Grimes 	}
1247df8bae1dSRodney W. Grimes #endif
1248e6e370a7SJeff Roberson 	ASSERT_VOP_LOCKED(ump->um_devvp, "ffs_flushfiles");
1249e6e370a7SJeff Roberson 	if (ump->um_devvp->v_vflag & VV_COPYONWRITE) {
1250f257b7a5SAlfred Perlstein 		if ((error = vflush(mp, 0, SKIPSYSTEM | flags, td)) != 0)
1251f2a2857bSKirk McKusick 			return (error);
1252f2a2857bSKirk McKusick 		ffs_snapshot_unmount(mp);
125395e7a3c3STor Egge 		flags |= FORCECLOSE;
1254f2a2857bSKirk McKusick 		/*
1255f2a2857bSKirk McKusick 		 * Here we fall through to vflush again to ensure
1256f2a2857bSKirk McKusick 		 * that we have gotten rid of all the system vnodes.
1257f2a2857bSKirk McKusick 		 */
1258f2a2857bSKirk McKusick 	}
1259b1897c19SJulian Elischer         /*
1260b1897c19SJulian Elischer 	 * Flush all the files.
1261b1897c19SJulian Elischer 	 */
1262f257b7a5SAlfred Perlstein 	if ((error = vflush(mp, 0, flags, td)) != 0)
1263b1897c19SJulian Elischer 		return (error);
1264b1897c19SJulian Elischer 	/*
1265b1897c19SJulian Elischer 	 * Flush filesystem metadata.
1266b1897c19SJulian Elischer 	 */
1267cb05b60aSAttilio Rao 	vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
12688df6bac4SPoul-Henning Kamp 	error = VOP_FSYNC(ump->um_devvp, MNT_WAIT, td);
126922db15c0SAttilio Rao 	VOP_UNLOCK(ump->um_devvp, 0);
1270df8bae1dSRodney W. Grimes 	return (error);
1271df8bae1dSRodney W. Grimes }
1272df8bae1dSRodney W. Grimes 
1273df8bae1dSRodney W. Grimes /*
1274df8bae1dSRodney W. Grimes  * Get filesystem statistics.
1275df8bae1dSRodney W. Grimes  */
1276adf41577SPoul-Henning Kamp static int
1277dfd233edSAttilio Rao ffs_statfs(mp, sbp)
1278df8bae1dSRodney W. Grimes 	struct mount *mp;
127905f4ff5dSPoul-Henning Kamp 	struct statfs *sbp;
1280df8bae1dSRodney W. Grimes {
128105f4ff5dSPoul-Henning Kamp 	struct ufsmount *ump;
128205f4ff5dSPoul-Henning Kamp 	struct fs *fs;
1283df8bae1dSRodney W. Grimes 
1284df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
1285df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
12861c85e6a3SKirk McKusick 	if (fs->fs_magic != FS_UFS1_MAGIC && fs->fs_magic != FS_UFS2_MAGIC)
1287df8bae1dSRodney W. Grimes 		panic("ffs_statfs");
1288fde81c7dSKirk McKusick 	sbp->f_version = STATFS_VERSION;
1289df8bae1dSRodney W. Grimes 	sbp->f_bsize = fs->fs_fsize;
1290df8bae1dSRodney W. Grimes 	sbp->f_iosize = fs->fs_bsize;
1291df8bae1dSRodney W. Grimes 	sbp->f_blocks = fs->fs_dsize;
12923ba649d7SJeff Roberson 	UFS_LOCK(ump);
1293df8bae1dSRodney W. Grimes 	sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
12949ccb939eSKirk McKusick 	    fs->fs_cstotal.cs_nffree + dbtofsb(fs, fs->fs_pendingblocks);
12959ccb939eSKirk McKusick 	sbp->f_bavail = freespace(fs, fs->fs_minfree) +
12969ccb939eSKirk McKusick 	    dbtofsb(fs, fs->fs_pendingblocks);
1297df8bae1dSRodney W. Grimes 	sbp->f_files =  fs->fs_ncg * fs->fs_ipg - ROOTINO;
12989ccb939eSKirk McKusick 	sbp->f_ffree = fs->fs_cstotal.cs_nifree + fs->fs_pendinginodes;
12993ba649d7SJeff Roberson 	UFS_UNLOCK(ump);
1300fde81c7dSKirk McKusick 	sbp->f_namemax = NAME_MAX;
1301df8bae1dSRodney W. Grimes 	return (0);
1302df8bae1dSRodney W. Grimes }
1303df8bae1dSRodney W. Grimes 
1304df8bae1dSRodney W. Grimes /*
1305df8bae1dSRodney W. Grimes  * Go through the disk queues to initiate sandbagged IO;
1306df8bae1dSRodney W. Grimes  * go through the inodes to write those that have been modified;
1307df8bae1dSRodney W. Grimes  * initiate the writing of the super block if it has been modified.
1308df8bae1dSRodney W. Grimes  *
1309df8bae1dSRodney W. Grimes  * Note: we are always called with the filesystem marked `MPBUSY'.
1310df8bae1dSRodney W. Grimes  */
1311adf41577SPoul-Henning Kamp static int
1312dfd233edSAttilio Rao ffs_sync(mp, waitfor)
1313df8bae1dSRodney W. Grimes 	struct mount *mp;
1314df8bae1dSRodney W. Grimes 	int waitfor;
1315df8bae1dSRodney W. Grimes {
131682be0a5aSTor Egge 	struct vnode *mvp, *vp, *devvp;
1317dfd233edSAttilio Rao 	struct thread *td;
1318996c772fSJohn Dyson 	struct inode *ip;
1319996c772fSJohn Dyson 	struct ufsmount *ump = VFSTOUFS(mp);
1320996c772fSJohn Dyson 	struct fs *fs;
13219b971133SKirk McKusick 	int error, count, wait, lockreq, allerror = 0;
1322791dd2faSTor Egge 	int suspend;
1323791dd2faSTor Egge 	int suspended;
1324791dd2faSTor Egge 	int secondary_writes;
1325791dd2faSTor Egge 	int secondary_accwrites;
1326791dd2faSTor Egge 	int softdep_deps;
1327791dd2faSTor Egge 	int softdep_accdeps;
1328156cb265SPoul-Henning Kamp 	struct bufobj *bo;
1329df8bae1dSRodney W. Grimes 
1330dfd233edSAttilio Rao 	td = curthread;
1331df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
1332996c772fSJohn Dyson 	if (fs->fs_fmod != 0 && fs->fs_ronly != 0) {		/* XXX */
1333df8bae1dSRodney W. Grimes 		printf("fs = %s\n", fs->fs_fsmnt);
13345ace3b26SMike Pritchard 		panic("ffs_sync: rofs mod");
1335df8bae1dSRodney W. Grimes 	}
1336df8bae1dSRodney W. Grimes 	/*
1337df8bae1dSRodney W. Grimes 	 * Write back each (modified) inode.
1338df8bae1dSRodney W. Grimes 	 */
13399b971133SKirk McKusick 	wait = 0;
1340791dd2faSTor Egge 	suspend = 0;
1341791dd2faSTor Egge 	suspended = 0;
1342245df27cSMatthew Dillon 	lockreq = LK_EXCLUSIVE | LK_NOWAIT;
1343791dd2faSTor Egge 	if (waitfor == MNT_SUSPEND) {
1344791dd2faSTor Egge 		suspend = 1;
1345791dd2faSTor Egge 		waitfor = MNT_WAIT;
1346791dd2faSTor Egge 	}
13479b971133SKirk McKusick 	if (waitfor == MNT_WAIT) {
13489b971133SKirk McKusick 		wait = 1;
1349245df27cSMatthew Dillon 		lockreq = LK_EXCLUSIVE;
13509b971133SKirk McKusick 	}
135141d4783dSJeff Roberson 	lockreq |= LK_INTERLOCK | LK_SLEEPFAIL;
1352ca430f2eSAlexander Kabaev 	MNT_ILOCK(mp);
1353df8bae1dSRodney W. Grimes loop:
1354791dd2faSTor Egge 	/* Grab snapshot of secondary write counts */
1355791dd2faSTor Egge 	secondary_writes = mp->mnt_secondary_writes;
1356791dd2faSTor Egge 	secondary_accwrites = mp->mnt_secondary_accwrites;
1357791dd2faSTor Egge 
1358791dd2faSTor Egge 	/* Grab snapshot of softdep dependency counts */
1359791dd2faSTor Egge 	MNT_IUNLOCK(mp);
1360791dd2faSTor Egge 	softdep_get_depcounts(mp, &softdep_deps, &softdep_accdeps);
1361791dd2faSTor Egge 	MNT_ILOCK(mp);
1362791dd2faSTor Egge 
136382be0a5aSTor Egge 	MNT_VNODE_FOREACH(vp, mp, mvp) {
1364245df27cSMatthew Dillon 		/*
1365245df27cSMatthew Dillon 		 * Depend on the mntvnode_slock to keep things stable enough
1366245df27cSMatthew Dillon 		 * for a quick test.  Since there might be hundreds of
1367245df27cSMatthew Dillon 		 * thousands of vnodes, we cannot afford even a subroutine
1368245df27cSMatthew Dillon 		 * call unless there's a good chance that we have work to do.
1369245df27cSMatthew Dillon 		 */
13702f05568aSJeff Roberson 		VI_LOCK(vp);
1371fe68abe2SJeff Roberson 		if (vp->v_iflag & VI_DOOMED) {
13722f05568aSJeff Roberson 			VI_UNLOCK(vp);
13732f05568aSJeff Roberson 			continue;
13742f05568aSJeff Roberson 		}
1375df8bae1dSRodney W. Grimes 		ip = VTOI(vp);
1376cf60e8e4SKirk McKusick 		if (vp->v_type == VNON || ((ip->i_flag &
1377cf60e8e4SKirk McKusick 		    (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
1378156cb265SPoul-Henning Kamp 		    vp->v_bufobj.bo_dirty.bv_cnt == 0)) {
13792f05568aSJeff Roberson 			VI_UNLOCK(vp);
1380df8bae1dSRodney W. Grimes 			continue;
1381996c772fSJohn Dyson 		}
1382ca430f2eSAlexander Kabaev 		MNT_IUNLOCK(mp);
1383b40ce416SJulian Elischer 		if ((error = vget(vp, lockreq, td)) != 0) {
1384ca430f2eSAlexander Kabaev 			MNT_ILOCK(mp);
138582be0a5aSTor Egge 			if (error == ENOENT || error == ENOLCK) {
138682be0a5aSTor Egge 				MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp);
1387df8bae1dSRodney W. Grimes 				goto loop;
138882be0a5aSTor Egge 			}
13892f05568aSJeff Roberson 			continue;
13902f05568aSJeff Roberson 		}
139140854ff5SPoul-Henning Kamp 		if ((error = ffs_syncvnode(vp, waitfor)) != 0)
1392df8bae1dSRodney W. Grimes 			allerror = error;
139341d4783dSJeff Roberson 		vput(vp);
1394ca430f2eSAlexander Kabaev 		MNT_ILOCK(mp);
1395245df27cSMatthew Dillon 	}
1396ca430f2eSAlexander Kabaev 	MNT_IUNLOCK(mp);
1397df8bae1dSRodney W. Grimes 	/*
1398df8bae1dSRodney W. Grimes 	 * Force stale filesystem control information to be flushed.
1399df8bae1dSRodney W. Grimes 	 */
14009b971133SKirk McKusick 	if (waitfor == MNT_WAIT) {
1401b40ce416SJulian Elischer 		if ((error = softdep_flushworklist(ump->um_mountp, &count, td)))
14029b971133SKirk McKusick 			allerror = error;
14039b971133SKirk McKusick 		/* Flushed work items may create new vnodes to clean */
14049ab73fd1SKirk McKusick 		if (allerror == 0 && count) {
1405ca430f2eSAlexander Kabaev 			MNT_ILOCK(mp);
14069b971133SKirk McKusick 			goto loop;
14079b971133SKirk McKusick 		}
14089b971133SKirk McKusick 	}
1409589c7af9SKirk McKusick #ifdef QUOTA
1410589c7af9SKirk McKusick 	qsync(mp);
1411589c7af9SKirk McKusick #endif
1412112f7372SKirk McKusick 	devvp = ump->um_devvp;
1413156cb265SPoul-Henning Kamp 	bo = &devvp->v_bufobj;
1414698b1a66SJeff Roberson 	BO_LOCK(bo);
1415112f7372SKirk McKusick 	if (waitfor != MNT_LAZY &&
1416156cb265SPoul-Henning Kamp 	    (bo->bo_numoutput > 0 || bo->bo_dirty.bv_cnt > 0)) {
1417698b1a66SJeff Roberson 		BO_UNLOCK(bo);
1418698b1a66SJeff Roberson 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
14198df6bac4SPoul-Henning Kamp 		if ((error = VOP_FSYNC(devvp, waitfor, td)) != 0)
1420df8bae1dSRodney W. Grimes 			allerror = error;
142122db15c0SAttilio Rao 		VOP_UNLOCK(devvp, 0);
14229ab73fd1SKirk McKusick 		if (allerror == 0 && waitfor == MNT_WAIT) {
1423ca430f2eSAlexander Kabaev 			MNT_ILOCK(mp);
1424112f7372SKirk McKusick 			goto loop;
1425b1897c19SJulian Elischer 		}
1426791dd2faSTor Egge 	} else if (suspend != 0) {
1427791dd2faSTor Egge 		if (softdep_check_suspend(mp,
1428791dd2faSTor Egge 					  devvp,
1429791dd2faSTor Egge 					  softdep_deps,
1430791dd2faSTor Egge 					  softdep_accdeps,
1431791dd2faSTor Egge 					  secondary_writes,
1432791dd2faSTor Egge 					  secondary_accwrites) != 0)
1433791dd2faSTor Egge 			goto loop;	/* More work needed */
1434791dd2faSTor Egge 		mtx_assert(MNT_MTX(mp), MA_OWNED);
1435ca2fa807STor Egge 		mp->mnt_kern_flag |= MNTK_SUSPEND2 | MNTK_SUSPENDED;
1436791dd2faSTor Egge 		MNT_IUNLOCK(mp);
1437791dd2faSTor Egge 		suspended = 1;
1438112f7372SKirk McKusick 	} else
1439698b1a66SJeff Roberson 		BO_UNLOCK(bo);
1440996c772fSJohn Dyson 	/*
1441996c772fSJohn Dyson 	 * Write back modified superblock.
1442996c772fSJohn Dyson 	 */
1443791dd2faSTor Egge 	if (fs->fs_fmod != 0 &&
1444791dd2faSTor Egge 	    (error = ffs_sbupdate(ump, waitfor, suspended)) != 0)
1445996c772fSJohn Dyson 		allerror = error;
1446df8bae1dSRodney W. Grimes 	return (allerror);
1447df8bae1dSRodney W. Grimes }
1448df8bae1dSRodney W. Grimes 
1449df8bae1dSRodney W. Grimes int
1450a0595d02SKirk McKusick ffs_vget(mp, ino, flags, vpp)
1451df8bae1dSRodney W. Grimes 	struct mount *mp;
1452df8bae1dSRodney W. Grimes 	ino_t ino;
1453a0595d02SKirk McKusick 	int flags;
1454df8bae1dSRodney W. Grimes 	struct vnode **vpp;
1455df8bae1dSRodney W. Grimes {
14567b7ed832SKonstantin Belousov 	return (ffs_vgetf(mp, ino, flags, vpp, 0));
14577b7ed832SKonstantin Belousov }
14587b7ed832SKonstantin Belousov 
14597b7ed832SKonstantin Belousov int
14607b7ed832SKonstantin Belousov ffs_vgetf(mp, ino, flags, vpp, ffs_flags)
14617b7ed832SKonstantin Belousov 	struct mount *mp;
14627b7ed832SKonstantin Belousov 	ino_t ino;
14637b7ed832SKonstantin Belousov 	int flags;
14647b7ed832SKonstantin Belousov 	struct vnode **vpp;
14657b7ed832SKonstantin Belousov 	int ffs_flags;
14667b7ed832SKonstantin Belousov {
1467996c772fSJohn Dyson 	struct fs *fs;
1468996c772fSJohn Dyson 	struct inode *ip;
1469df8bae1dSRodney W. Grimes 	struct ufsmount *ump;
1470df8bae1dSRodney W. Grimes 	struct buf *bp;
1471df8bae1dSRodney W. Grimes 	struct vnode *vp;
147289c9c53dSPoul-Henning Kamp 	struct cdev *dev;
1473f576a00dSSemen Ustimenko 	int error;
1474df8bae1dSRodney W. Grimes 
147551f5ce0cSPoul-Henning Kamp 	error = vfs_hash_get(mp, ino, flags, curthread, vpp, NULL, NULL);
1476e82ef95cSPoul-Henning Kamp 	if (error || *vpp != NULL)
147714bc0685SPoul-Henning Kamp 		return (error);
1478f576a00dSSemen Ustimenko 
1479f576a00dSSemen Ustimenko 	/*
1480d6919865SJeff Roberson 	 * We must promote to an exclusive lock for vnode creation.  This
1481d6919865SJeff Roberson 	 * can happen if lookup is passed LOCKSHARED.
1482d6919865SJeff Roberson  	 */
1483d6919865SJeff Roberson 	if ((flags & LK_TYPE_MASK) == LK_SHARED) {
1484d6919865SJeff Roberson 		flags &= ~LK_TYPE_MASK;
1485d6919865SJeff Roberson 		flags |= LK_EXCLUSIVE;
1486d6919865SJeff Roberson 	}
1487d6919865SJeff Roberson 
1488d6919865SJeff Roberson 	/*
148913866b3fSSemen Ustimenko 	 * We do not lock vnode creation as it is believed to be too
1490f576a00dSSemen Ustimenko 	 * expensive for such rare case as simultaneous creation of vnode
1491f576a00dSSemen Ustimenko 	 * for same ino by different processes. We just allow them to race
1492f576a00dSSemen Ustimenko 	 * and check later to decide who wins. Let the race begin!
1493f576a00dSSemen Ustimenko 	 */
149414bc0685SPoul-Henning Kamp 
149514bc0685SPoul-Henning Kamp 	ump = VFSTOUFS(mp);
149614bc0685SPoul-Henning Kamp 	dev = ump->um_dev;
149714bc0685SPoul-Henning Kamp 	fs = ump->um_fs;
1498df8bae1dSRodney W. Grimes 
14992094ddb6SDavid Greenman 	/*
15001ede983cSDag-Erling Smørgrav 	 * If this malloc() is performed after the getnewvnode()
15012f9bae59SDavid Greenman 	 * it might block, leaving a vnode with a NULL v_data to be
15022f9bae59SDavid Greenman 	 * found by ffs_sync() if a sync happens to fire right then,
15032f9bae59SDavid Greenman 	 * which will cause a panic because ffs_sync() blindly
15042f9bae59SDavid Greenman 	 * dereferences vp->v_data (as well it should).
15052f9bae59SDavid Greenman 	 */
150614bc0685SPoul-Henning Kamp 	ip = uma_zalloc(uma_inode, M_WAITOK | M_ZERO);
15072f9bae59SDavid Greenman 
1508df8bae1dSRodney W. Grimes 	/* Allocate a new vnode/inode. */
150902f2c6a9SPoul-Henning Kamp 	if (fs->fs_magic == FS_UFS1_MAGIC)
151002f2c6a9SPoul-Henning Kamp 		error = getnewvnode("ufs", mp, &ffs_vnodeops1, &vp);
151102f2c6a9SPoul-Henning Kamp 	else
151202f2c6a9SPoul-Henning Kamp 		error = getnewvnode("ufs", mp, &ffs_vnodeops2, &vp);
1513c9671602SPoul-Henning Kamp 	if (error) {
1514df8bae1dSRodney W. Grimes 		*vpp = NULL;
1515aa4d7a8aSPoul-Henning Kamp 		uma_zfree(uma_inode, ip);
1516df8bae1dSRodney W. Grimes 		return (error);
1517df8bae1dSRodney W. Grimes 	}
151867e87166SBoris Popov 	/*
151933fc3625SJohn Baldwin 	 * FFS supports recursive locking.
152067e87166SBoris Popov 	 */
15213634d5b2SJohn Baldwin 	lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL);
1522628f51d2SAttilio Rao 	VN_LOCK_AREC(vp);
1523df8bae1dSRodney W. Grimes 	vp->v_data = ip;
15245d9d81e7SPoul-Henning Kamp 	vp->v_bufobj.bo_bsize = fs->fs_bsize;
1525df8bae1dSRodney W. Grimes 	ip->i_vnode = vp;
15261c85e6a3SKirk McKusick 	ip->i_ump = ump;
1527c94cd5fcSPoul-Henning Kamp 	ip->i_fs = fs;
1528df8bae1dSRodney W. Grimes 	ip->i_dev = dev;
1529df8bae1dSRodney W. Grimes 	ip->i_number = ino;
1530e65f5a4eSKonstantin Belousov 	ip->i_ea_refs = 0;
1531df8bae1dSRodney W. Grimes #ifdef QUOTA
1532c1d9efcbSPoul-Henning Kamp 	{
1533c1d9efcbSPoul-Henning Kamp 		int i;
1534df8bae1dSRodney W. Grimes 		for (i = 0; i < MAXQUOTAS; i++)
1535df8bae1dSRodney W. Grimes 			ip->i_dquot[i] = NODQUOT;
1536c1d9efcbSPoul-Henning Kamp 	}
1537df8bae1dSRodney W. Grimes #endif
1538df8bae1dSRodney W. Grimes 
15397b7ed832SKonstantin Belousov 	if (ffs_flags & FFSV_FORCEINSMQ)
15407b7ed832SKonstantin Belousov 		vp->v_vflag |= VV_FORCEINSMQ;
154161b9d89fSTor Egge 	error = insmntque(vp, mp);
154261b9d89fSTor Egge 	if (error != 0) {
15436cc745d2SKonstantin Belousov 		uma_zfree(uma_inode, ip);
154461b9d89fSTor Egge 		*vpp = NULL;
154561b9d89fSTor Egge 		return (error);
154661b9d89fSTor Egge 	}
15477b7ed832SKonstantin Belousov 	vp->v_vflag &= ~VV_FORCEINSMQ;
1548a80d8caaSPawel Jakub Dawidek 	error = vfs_hash_insert(vp, ino, flags, curthread, vpp, NULL, NULL);
154945c26fa2SPoul-Henning Kamp 	if (error || *vpp != NULL)
1550f576a00dSSemen Ustimenko 		return (error);
1551f576a00dSSemen Ustimenko 
1552df8bae1dSRodney W. Grimes 	/* Read in the disk contents for the inode, copy into the inode. */
1553c9671602SPoul-Henning Kamp 	error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
1554c9671602SPoul-Henning Kamp 	    (int)fs->fs_bsize, NOCRED, &bp);
1555c9671602SPoul-Henning Kamp 	if (error) {
1556df8bae1dSRodney W. Grimes 		/*
1557df8bae1dSRodney W. Grimes 		 * The inode does not contain anything useful, so it would
1558df8bae1dSRodney W. Grimes 		 * be misleading to leave it on its hash chain. With mode
1559df8bae1dSRodney W. Grimes 		 * still zero, it will be unlinked and returned to the free
1560df8bae1dSRodney W. Grimes 		 * list by vput().
1561df8bae1dSRodney W. Grimes 		 */
1562df8bae1dSRodney W. Grimes 		brelse(bp);
1563bd7e5f99SJohn Dyson 		vput(vp);
1564df8bae1dSRodney W. Grimes 		*vpp = NULL;
1565df8bae1dSRodney W. Grimes 		return (error);
1566df8bae1dSRodney W. Grimes 	}
1567de6ba7c0SPoul-Henning Kamp 	if (ip->i_ump->um_fstype == UFS1)
1568a163d034SWarner Losh 		ip->i_din1 = uma_zalloc(uma_ufs1, M_WAITOK);
1569de6ba7c0SPoul-Henning Kamp 	else
1570a163d034SWarner Losh 		ip->i_din2 = uma_zalloc(uma_ufs2, M_WAITOK);
1571de6ba7c0SPoul-Henning Kamp 	ffs_load_inode(bp, ip, fs, ino);
1572b1897c19SJulian Elischer 	if (DOINGSOFTDEP(vp))
1573b1897c19SJulian Elischer 		softdep_load_inodeblock(ip);
1574b1897c19SJulian Elischer 	else
1575b1897c19SJulian Elischer 		ip->i_effnlink = ip->i_nlink;
1576bd7e5f99SJohn Dyson 	bqrelse(bp);
1577df8bae1dSRodney W. Grimes 
1578df8bae1dSRodney W. Grimes 	/*
1579df8bae1dSRodney W. Grimes 	 * Initialize the vnode from the inode, check for aliases.
1580df8bae1dSRodney W. Grimes 	 * Note that the underlying vnode may have changed.
1581df8bae1dSRodney W. Grimes 	 */
158202f2c6a9SPoul-Henning Kamp 	if (ip->i_ump->um_fstype == UFS1)
158302f2c6a9SPoul-Henning Kamp 		error = ufs_vinit(mp, &ffs_fifoops1, &vp);
158402f2c6a9SPoul-Henning Kamp 	else
158502f2c6a9SPoul-Henning Kamp 		error = ufs_vinit(mp, &ffs_fifoops2, &vp);
1586c9671602SPoul-Henning Kamp 	if (error) {
1587df8bae1dSRodney W. Grimes 		vput(vp);
1588df8bae1dSRodney W. Grimes 		*vpp = NULL;
1589df8bae1dSRodney W. Grimes 		return (error);
1590df8bae1dSRodney W. Grimes 	}
1591de68347bSPoul-Henning Kamp 
1592df8bae1dSRodney W. Grimes 	/*
15935c24d6eeSPoul-Henning Kamp 	 * Finish inode initialization.
1594df8bae1dSRodney W. Grimes 	 */
159533fc3625SJohn Baldwin 	if (vp->v_type != VFIFO) {
159633fc3625SJohn Baldwin 		/* FFS supports shared locking for all files except fifos. */
159733fc3625SJohn Baldwin 		VN_LOCK_ASHARE(vp);
159833fc3625SJohn Baldwin 	}
1599de68347bSPoul-Henning Kamp 
1600df8bae1dSRodney W. Grimes 	/*
1601df8bae1dSRodney W. Grimes 	 * Set up a generation number for this inode if it does not
1602df8bae1dSRodney W. Grimes 	 * already have one. This should only happen on old filesystems.
1603df8bae1dSRodney W. Grimes 	 */
1604df8bae1dSRodney W. Grimes 	if (ip->i_gen == 0) {
1605aca3e497SKirk McKusick 		ip->i_gen = arc4random() / 2 + 1;
16061c85e6a3SKirk McKusick 		if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
1607df8bae1dSRodney W. Grimes 			ip->i_flag |= IN_MODIFIED;
1608b403319bSAlexander Kabaev 			DIP_SET(ip, i_gen, ip->i_gen);
16091c85e6a3SKirk McKusick 		}
1610df8bae1dSRodney W. Grimes 	}
1611763bbd2fSRobert Watson #ifdef MAC
1612763bbd2fSRobert Watson 	if ((mp->mnt_flag & MNT_MULTILABEL) && ip->i_mode) {
1613763bbd2fSRobert Watson 		/*
1614763bbd2fSRobert Watson 		 * If this vnode is already allocated, and we're running
1615763bbd2fSRobert Watson 		 * multi-label, attempt to perform a label association
1616763bbd2fSRobert Watson 		 * from the extended attributes on the inode.
1617763bbd2fSRobert Watson 		 */
161830d239bcSRobert Watson 		error = mac_vnode_associate_extattr(mp, vp);
1619763bbd2fSRobert Watson 		if (error) {
1620763bbd2fSRobert Watson 			/* ufs_inactive will release ip->i_devvp ref. */
1621763bbd2fSRobert Watson 			vput(vp);
1622763bbd2fSRobert Watson 			*vpp = NULL;
1623763bbd2fSRobert Watson 			return (error);
1624763bbd2fSRobert Watson 		}
1625763bbd2fSRobert Watson 	}
1626763bbd2fSRobert Watson #endif
1627763bbd2fSRobert Watson 
1628df8bae1dSRodney W. Grimes 	*vpp = vp;
1629df8bae1dSRodney W. Grimes 	return (0);
1630df8bae1dSRodney W. Grimes }
1631df8bae1dSRodney W. Grimes 
1632df8bae1dSRodney W. Grimes /*
1633df8bae1dSRodney W. Grimes  * File handle to vnode
1634df8bae1dSRodney W. Grimes  *
1635df8bae1dSRodney W. Grimes  * Have to be really careful about stale file handles:
1636df8bae1dSRodney W. Grimes  * - check that the inode number is valid
1637df8bae1dSRodney W. Grimes  * - call ffs_vget() to get the locked inode
1638df8bae1dSRodney W. Grimes  * - check for an unallocated inode (i_mode == 0)
1639df8bae1dSRodney W. Grimes  * - check that the given client host has export rights and return
1640df8bae1dSRodney W. Grimes  *   those rights via. exflagsp and credanonp
1641df8bae1dSRodney W. Grimes  */
1642adf41577SPoul-Henning Kamp static int
1643c24fda81SAlfred Perlstein ffs_fhtovp(mp, fhp, vpp)
164405f4ff5dSPoul-Henning Kamp 	struct mount *mp;
1645df8bae1dSRodney W. Grimes 	struct fid *fhp;
1646df8bae1dSRodney W. Grimes 	struct vnode **vpp;
1647df8bae1dSRodney W. Grimes {
164805f4ff5dSPoul-Henning Kamp 	struct ufid *ufhp;
1649df8bae1dSRodney W. Grimes 	struct fs *fs;
1650df8bae1dSRodney W. Grimes 
1651df8bae1dSRodney W. Grimes 	ufhp = (struct ufid *)fhp;
1652df8bae1dSRodney W. Grimes 	fs = VFSTOUFS(mp)->um_fs;
1653df8bae1dSRodney W. Grimes 	if (ufhp->ufid_ino < ROOTINO ||
1654df8bae1dSRodney W. Grimes 	    ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg)
1655df8bae1dSRodney W. Grimes 		return (ESTALE);
1656c24fda81SAlfred Perlstein 	return (ufs_fhtovp(mp, ufhp, vpp));
1657df8bae1dSRodney W. Grimes }
1658df8bae1dSRodney W. Grimes 
1659df8bae1dSRodney W. Grimes /*
16605346934fSIan Dowse  * Initialize the filesystem.
1661996c772fSJohn Dyson  */
1662996c772fSJohn Dyson static int
1663996c772fSJohn Dyson ffs_init(vfsp)
1664996c772fSJohn Dyson 	struct vfsconf *vfsp;
1665996c772fSJohn Dyson {
1666996c772fSJohn Dyson 
1667b1897c19SJulian Elischer 	softdep_initialize();
1668996c772fSJohn Dyson 	return (ufs_init(vfsp));
1669996c772fSJohn Dyson }
1670996c772fSJohn Dyson 
1671996c772fSJohn Dyson /*
16725346934fSIan Dowse  * Undo the work of ffs_init().
16735346934fSIan Dowse  */
16745346934fSIan Dowse static int
16755346934fSIan Dowse ffs_uninit(vfsp)
16765346934fSIan Dowse 	struct vfsconf *vfsp;
16775346934fSIan Dowse {
16785346934fSIan Dowse 	int ret;
16795346934fSIan Dowse 
16805346934fSIan Dowse 	ret = ufs_uninit(vfsp);
16815346934fSIan Dowse 	softdep_uninitialize();
16825346934fSIan Dowse 	return (ret);
16835346934fSIan Dowse }
16845346934fSIan Dowse 
16855346934fSIan Dowse /*
1686df8bae1dSRodney W. Grimes  * Write a superblock and associated information back to disk.
1687df8bae1dSRodney W. Grimes  */
16881a60c7fcSPawel Jakub Dawidek int
1689791dd2faSTor Egge ffs_sbupdate(mp, waitfor, suspended)
1690df8bae1dSRodney W. Grimes 	struct ufsmount *mp;
1691df8bae1dSRodney W. Grimes 	int waitfor;
1692791dd2faSTor Egge 	int suspended;
1693df8bae1dSRodney W. Grimes {
16941c85e6a3SKirk McKusick 	struct fs *fs = mp->um_fs;
16953ba649d7SJeff Roberson 	struct buf *sbbp;
169605f4ff5dSPoul-Henning Kamp 	struct buf *bp;
1697df8bae1dSRodney W. Grimes 	int blks;
1698f55ff3f3SIan Dowse 	void *space;
1699996c772fSJohn Dyson 	int i, size, error, allerror = 0;
1700df8bae1dSRodney W. Grimes 
170174f3809aSKirk McKusick 	if (fs->fs_ronly == 1 &&
170274f3809aSKirk McKusick 	    (mp->um_mountp->mnt_flag & (MNT_RDONLY | MNT_UPDATE)) !=
170374f3809aSKirk McKusick 	    (MNT_RDONLY | MNT_UPDATE))
170474f3809aSKirk McKusick 		panic("ffs_sbupdate: write read-only filesystem");
1705996c772fSJohn Dyson 	/*
17063ba649d7SJeff Roberson 	 * We use the superblock's buf to serialize calls to ffs_sbupdate().
17073ba649d7SJeff Roberson 	 */
17083ba649d7SJeff Roberson 	sbbp = getblk(mp->um_devvp, btodb(fs->fs_sblockloc), (int)fs->fs_sbsize,
17093ba649d7SJeff Roberson 	    0, 0, 0);
17103ba649d7SJeff Roberson 	/*
1711996c772fSJohn Dyson 	 * First write back the summary information.
1712996c772fSJohn Dyson 	 */
1713df8bae1dSRodney W. Grimes 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
1714f55ff3f3SIan Dowse 	space = fs->fs_csp;
1715df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
1716df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
1717df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
1718df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
1719df8bae1dSRodney W. Grimes 		bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i),
17207261f5f6SJeff Roberson 		    size, 0, 0, 0);
1721df8bae1dSRodney W. Grimes 		bcopy(space, bp->b_data, (u_int)size);
1722f55ff3f3SIan Dowse 		space = (char *)space + size;
1723791dd2faSTor Egge 		if (suspended)
1724791dd2faSTor Egge 			bp->b_flags |= B_VALIDSUSPWRT;
1725996c772fSJohn Dyson 		if (waitfor != MNT_WAIT)
1726df8bae1dSRodney W. Grimes 			bawrite(bp);
17278aef1712SMatthew Dillon 		else if ((error = bwrite(bp)) != 0)
1728996c772fSJohn Dyson 			allerror = error;
1729df8bae1dSRodney W. Grimes 	}
1730996c772fSJohn Dyson 	/*
1731996c772fSJohn Dyson 	 * Now write back the superblock itself. If any errors occurred
1732996c772fSJohn Dyson 	 * up to this point, then fail so that the superblock avoids
1733996c772fSJohn Dyson 	 * being written out as clean.
1734996c772fSJohn Dyson 	 */
17353ba649d7SJeff Roberson 	if (allerror) {
17363ba649d7SJeff Roberson 		brelse(sbbp);
1737996c772fSJohn Dyson 		return (allerror);
17383ba649d7SJeff Roberson 	}
17393ba649d7SJeff Roberson 	bp = sbbp;
174031574422SKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_sblockloc != SBLOCK_UFS1 &&
174131574422SKirk McKusick 	    (fs->fs_flags & FS_FLAGS_UPDATED) == 0) {
1742fa5d33e2SKirk McKusick 		printf("%s: correcting fs_sblockloc from %jd to %d\n",
1743fa5d33e2SKirk McKusick 		    fs->fs_fsmnt, fs->fs_sblockloc, SBLOCK_UFS1);
1744fa5d33e2SKirk McKusick 		fs->fs_sblockloc = SBLOCK_UFS1;
1745fa5d33e2SKirk McKusick 	}
174631574422SKirk McKusick 	if (fs->fs_magic == FS_UFS2_MAGIC && fs->fs_sblockloc != SBLOCK_UFS2 &&
174731574422SKirk McKusick 	    (fs->fs_flags & FS_FLAGS_UPDATED) == 0) {
1748fa5d33e2SKirk McKusick 		printf("%s: correcting fs_sblockloc from %jd to %d\n",
1749fa5d33e2SKirk McKusick 		    fs->fs_fsmnt, fs->fs_sblockloc, SBLOCK_UFS2);
1750fa5d33e2SKirk McKusick 		fs->fs_sblockloc = SBLOCK_UFS2;
1751fa5d33e2SKirk McKusick 	}
1752b1897c19SJulian Elischer 	fs->fs_fmod = 0;
1753227ee8a1SPoul-Henning Kamp 	fs->fs_time = time_second;
1754113db2ddSJeff Roberson 	if (fs->fs_flags & FS_DOSOFTDEP)
1755113db2ddSJeff Roberson 		softdep_setup_sbupdate(mp, (struct fs *)bp->b_data, bp);
1756996c772fSJohn Dyson 	bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize);
17571c85e6a3SKirk McKusick 	ffs_oldfscompat_write((struct fs *)bp->b_data, mp);
1758791dd2faSTor Egge 	if (suspended)
1759791dd2faSTor Egge 		bp->b_flags |= B_VALIDSUSPWRT;
1760996c772fSJohn Dyson 	if (waitfor != MNT_WAIT)
1761996c772fSJohn Dyson 		bawrite(bp);
17628aef1712SMatthew Dillon 	else if ((error = bwrite(bp)) != 0)
1763996c772fSJohn Dyson 		allerror = error;
1764996c772fSJohn Dyson 	return (allerror);
1765df8bae1dSRodney W. Grimes }
1766d6fe88e4SPoul-Henning Kamp 
1767d6fe88e4SPoul-Henning Kamp static int
1768d6fe88e4SPoul-Henning Kamp ffs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp,
1769dfd233edSAttilio Rao 	int attrnamespace, const char *attrname)
1770d6fe88e4SPoul-Henning Kamp {
1771d6fe88e4SPoul-Henning Kamp 
1772d6fe88e4SPoul-Henning Kamp #ifdef UFS_EXTATTR
1773d6fe88e4SPoul-Henning Kamp 	return (ufs_extattrctl(mp, cmd, filename_vp, attrnamespace,
1774dfd233edSAttilio Rao 	    attrname));
1775d6fe88e4SPoul-Henning Kamp #else
1776d6fe88e4SPoul-Henning Kamp 	return (vfs_stdextattrctl(mp, cmd, filename_vp, attrnamespace,
1777dfd233edSAttilio Rao 	    attrname));
1778d6fe88e4SPoul-Henning Kamp #endif
1779d6fe88e4SPoul-Henning Kamp }
1780975512a9SPoul-Henning Kamp 
1781975512a9SPoul-Henning Kamp static void
1782975512a9SPoul-Henning Kamp ffs_ifree(struct ufsmount *ump, struct inode *ip)
1783975512a9SPoul-Henning Kamp {
1784975512a9SPoul-Henning Kamp 
178536329289STim J. Robbins 	if (ump->um_fstype == UFS1 && ip->i_din1 != NULL)
1786aa4d7a8aSPoul-Henning Kamp 		uma_zfree(uma_ufs1, ip->i_din1);
178736329289STim J. Robbins 	else if (ip->i_din2 != NULL)
17888d721e87STim J. Robbins 		uma_zfree(uma_ufs2, ip->i_din2);
1789aa4d7a8aSPoul-Henning Kamp 	uma_zfree(uma_inode, ip);
1790975512a9SPoul-Henning Kamp }
17916e77a041SPoul-Henning Kamp 
1792dd19a799SPoul-Henning Kamp static int dobkgrdwrite = 1;
1793dd19a799SPoul-Henning Kamp SYSCTL_INT(_debug, OID_AUTO, dobkgrdwrite, CTLFLAG_RW, &dobkgrdwrite, 0,
1794dd19a799SPoul-Henning Kamp     "Do background writes (honoring the BV_BKGRDWRITE flag)?");
1795dd19a799SPoul-Henning Kamp 
1796dd19a799SPoul-Henning Kamp /*
1797dd19a799SPoul-Henning Kamp  * Complete a background write started from bwrite.
1798dd19a799SPoul-Henning Kamp  */
1799dd19a799SPoul-Henning Kamp static void
1800dd19a799SPoul-Henning Kamp ffs_backgroundwritedone(struct buf *bp)
1801dd19a799SPoul-Henning Kamp {
1802204ec66dSJeff Roberson 	struct bufobj *bufobj;
1803dd19a799SPoul-Henning Kamp 	struct buf *origbp;
1804dd19a799SPoul-Henning Kamp 
1805dd19a799SPoul-Henning Kamp 	/*
1806dd19a799SPoul-Henning Kamp 	 * Find the original buffer that we are writing.
1807dd19a799SPoul-Henning Kamp 	 */
1808204ec66dSJeff Roberson 	bufobj = bp->b_bufobj;
1809204ec66dSJeff Roberson 	BO_LOCK(bufobj);
1810dd19a799SPoul-Henning Kamp 	if ((origbp = gbincore(bp->b_bufobj, bp->b_lblkno)) == NULL)
1811dd19a799SPoul-Henning Kamp 		panic("backgroundwritedone: lost buffer");
1812204ec66dSJeff Roberson 	/* Grab an extra reference to be dropped by the bufdone() below. */
1813204ec66dSJeff Roberson 	bufobj_wrefl(bufobj);
1814204ec66dSJeff Roberson 	BO_UNLOCK(bufobj);
1815dd19a799SPoul-Henning Kamp 	/*
1816dd19a799SPoul-Henning Kamp 	 * Process dependencies then return any unfinished ones.
1817dd19a799SPoul-Henning Kamp 	 */
181804533fc6SXin LI 	if (!LIST_EMPTY(&bp->b_dep))
1819dd19a799SPoul-Henning Kamp 		buf_complete(bp);
1820dd19a799SPoul-Henning Kamp #ifdef SOFTUPDATES
182104533fc6SXin LI 	if (!LIST_EMPTY(&bp->b_dep))
1822dd19a799SPoul-Henning Kamp 		softdep_move_dependencies(bp, origbp);
1823dd19a799SPoul-Henning Kamp #endif
1824dd19a799SPoul-Henning Kamp 	/*
1825204ec66dSJeff Roberson 	 * This buffer is marked B_NOCACHE so when it is released
1826204ec66dSJeff Roberson 	 * by biodone it will be tossed.
1827dd19a799SPoul-Henning Kamp 	 */
1828dd19a799SPoul-Henning Kamp 	bp->b_flags |= B_NOCACHE;
1829ec9c9e73SAlan Cox 	bp->b_flags &= ~B_CACHE;
1830dd19a799SPoul-Henning Kamp 	bufdone(bp);
1831204ec66dSJeff Roberson 	BO_LOCK(bufobj);
1832dd19a799SPoul-Henning Kamp 	/*
1833dd19a799SPoul-Henning Kamp 	 * Clear the BV_BKGRDINPROG flag in the original buffer
1834dd19a799SPoul-Henning Kamp 	 * and awaken it if it is waiting for the write to complete.
1835dd19a799SPoul-Henning Kamp 	 * If BV_BKGRDINPROG is not set in the original buffer it must
1836dd19a799SPoul-Henning Kamp 	 * have been released and re-instantiated - which is not legal.
1837dd19a799SPoul-Henning Kamp 	 */
1838dd19a799SPoul-Henning Kamp 	KASSERT((origbp->b_vflags & BV_BKGRDINPROG),
1839dd19a799SPoul-Henning Kamp 	    ("backgroundwritedone: lost buffer2"));
1840dd19a799SPoul-Henning Kamp 	origbp->b_vflags &= ~BV_BKGRDINPROG;
1841dd19a799SPoul-Henning Kamp 	if (origbp->b_vflags & BV_BKGRDWAIT) {
1842dd19a799SPoul-Henning Kamp 		origbp->b_vflags &= ~BV_BKGRDWAIT;
1843dd19a799SPoul-Henning Kamp 		wakeup(&origbp->b_xflags);
1844dd19a799SPoul-Henning Kamp 	}
1845204ec66dSJeff Roberson 	BO_UNLOCK(bufobj);
1846dd19a799SPoul-Henning Kamp }
1847dd19a799SPoul-Henning Kamp 
1848dd19a799SPoul-Henning Kamp 
1849dd19a799SPoul-Henning Kamp /*
1850dd19a799SPoul-Henning Kamp  * Write, release buffer on completion.  (Done by iodone
1851dd19a799SPoul-Henning Kamp  * if async).  Do not bother writing anything if the buffer
1852dd19a799SPoul-Henning Kamp  * is invalid.
1853dd19a799SPoul-Henning Kamp  *
1854dd19a799SPoul-Henning Kamp  * Note that we set B_CACHE here, indicating that buffer is
1855dd19a799SPoul-Henning Kamp  * fully valid and thus cacheable.  This is true even of NFS
1856dd19a799SPoul-Henning Kamp  * now so we set it generally.  This could be set either here
1857dd19a799SPoul-Henning Kamp  * or in biodone() since the I/O is synchronous.  We put it
1858dd19a799SPoul-Henning Kamp  * here.
1859dd19a799SPoul-Henning Kamp  */
1860dd19a799SPoul-Henning Kamp static int
1861dd19a799SPoul-Henning Kamp ffs_bufwrite(struct buf *bp)
1862dd19a799SPoul-Henning Kamp {
1863dd19a799SPoul-Henning Kamp 	int oldflags, s;
1864dd19a799SPoul-Henning Kamp 	struct buf *newbp;
1865dd19a799SPoul-Henning Kamp 
1866dd19a799SPoul-Henning Kamp 	CTR3(KTR_BUF, "bufwrite(%p) vp %p flags %X", bp, bp->b_vp, bp->b_flags);
1867dd19a799SPoul-Henning Kamp 	if (bp->b_flags & B_INVAL) {
1868dd19a799SPoul-Henning Kamp 		brelse(bp);
1869dd19a799SPoul-Henning Kamp 		return (0);
1870dd19a799SPoul-Henning Kamp 	}
1871dd19a799SPoul-Henning Kamp 
1872dd19a799SPoul-Henning Kamp 	oldflags = bp->b_flags;
1873dd19a799SPoul-Henning Kamp 
1874d638e093SAttilio Rao 	if (!BUF_ISLOCKED(bp))
1875dd19a799SPoul-Henning Kamp 		panic("bufwrite: buffer is not busy???");
1876dd19a799SPoul-Henning Kamp 	s = splbio();
1877dd19a799SPoul-Henning Kamp 	/*
1878dd19a799SPoul-Henning Kamp 	 * If a background write is already in progress, delay
1879dd19a799SPoul-Henning Kamp 	 * writing this block if it is asynchronous. Otherwise
1880dd19a799SPoul-Henning Kamp 	 * wait for the background write to complete.
1881dd19a799SPoul-Henning Kamp 	 */
1882dd19a799SPoul-Henning Kamp 	BO_LOCK(bp->b_bufobj);
1883dd19a799SPoul-Henning Kamp 	if (bp->b_vflags & BV_BKGRDINPROG) {
1884dd19a799SPoul-Henning Kamp 		if (bp->b_flags & B_ASYNC) {
1885dd19a799SPoul-Henning Kamp 			BO_UNLOCK(bp->b_bufobj);
1886dd19a799SPoul-Henning Kamp 			splx(s);
1887dd19a799SPoul-Henning Kamp 			bdwrite(bp);
1888dd19a799SPoul-Henning Kamp 			return (0);
1889dd19a799SPoul-Henning Kamp 		}
1890dd19a799SPoul-Henning Kamp 		bp->b_vflags |= BV_BKGRDWAIT;
1891dd19a799SPoul-Henning Kamp 		msleep(&bp->b_xflags, BO_MTX(bp->b_bufobj), PRIBIO, "bwrbg", 0);
1892dd19a799SPoul-Henning Kamp 		if (bp->b_vflags & BV_BKGRDINPROG)
1893dd19a799SPoul-Henning Kamp 			panic("bufwrite: still writing");
1894dd19a799SPoul-Henning Kamp 	}
1895dd19a799SPoul-Henning Kamp 	BO_UNLOCK(bp->b_bufobj);
1896dd19a799SPoul-Henning Kamp 
1897dd19a799SPoul-Henning Kamp 	/*
1898dd19a799SPoul-Henning Kamp 	 * If this buffer is marked for background writing and we
1899dd19a799SPoul-Henning Kamp 	 * do not have to wait for it, make a copy and write the
1900dd19a799SPoul-Henning Kamp 	 * copy so as to leave this buffer ready for further use.
1901dd19a799SPoul-Henning Kamp 	 *
1902dd19a799SPoul-Henning Kamp 	 * This optimization eats a lot of memory.  If we have a page
1903dd19a799SPoul-Henning Kamp 	 * or buffer shortfall we can't do it.
1904dd19a799SPoul-Henning Kamp 	 */
1905dd19a799SPoul-Henning Kamp 	if (dobkgrdwrite && (bp->b_xflags & BX_BKGRDWRITE) &&
1906dd19a799SPoul-Henning Kamp 	    (bp->b_flags & B_ASYNC) &&
1907dd19a799SPoul-Henning Kamp 	    !vm_page_count_severe() &&
1908dd19a799SPoul-Henning Kamp 	    !buf_dirty_count_severe()) {
1909dd19a799SPoul-Henning Kamp 		KASSERT(bp->b_iodone == NULL,
1910dd19a799SPoul-Henning Kamp 		    ("bufwrite: needs chained iodone (%p)", bp->b_iodone));
1911dd19a799SPoul-Henning Kamp 
1912dd19a799SPoul-Henning Kamp 		/* get a new block */
1913c1d8b5e8SKonstantin Belousov 		newbp = geteblk(bp->b_bufsize, GB_NOWAIT_BD);
1914c1d8b5e8SKonstantin Belousov 		if (newbp == NULL)
1915c1d8b5e8SKonstantin Belousov 			goto normal_write;
1916dd19a799SPoul-Henning Kamp 
1917dd19a799SPoul-Henning Kamp 		/*
1918dd19a799SPoul-Henning Kamp 		 * set it to be identical to the old block.  We have to
1919dd19a799SPoul-Henning Kamp 		 * set b_lblkno and BKGRDMARKER before calling bgetvp()
1920dd19a799SPoul-Henning Kamp 		 * to avoid confusing the splay tree and gbincore().
1921dd19a799SPoul-Henning Kamp 		 */
1922dd19a799SPoul-Henning Kamp 		memcpy(newbp->b_data, bp->b_data, bp->b_bufsize);
1923dd19a799SPoul-Henning Kamp 		newbp->b_lblkno = bp->b_lblkno;
1924dd19a799SPoul-Henning Kamp 		newbp->b_xflags |= BX_BKGRDMARKER;
1925dd19a799SPoul-Henning Kamp 		BO_LOCK(bp->b_bufobj);
1926dd19a799SPoul-Henning Kamp 		bp->b_vflags |= BV_BKGRDINPROG;
1927dd19a799SPoul-Henning Kamp 		bgetvp(bp->b_vp, newbp);
1928dd19a799SPoul-Henning Kamp 		BO_UNLOCK(bp->b_bufobj);
1929dd19a799SPoul-Henning Kamp 		newbp->b_bufobj = &bp->b_vp->v_bufobj;
1930dd19a799SPoul-Henning Kamp 		newbp->b_blkno = bp->b_blkno;
1931dd19a799SPoul-Henning Kamp 		newbp->b_offset = bp->b_offset;
1932dd19a799SPoul-Henning Kamp 		newbp->b_iodone = ffs_backgroundwritedone;
1933dd19a799SPoul-Henning Kamp 		newbp->b_flags |= B_ASYNC;
1934dd19a799SPoul-Henning Kamp 		newbp->b_flags &= ~B_INVAL;
1935dd19a799SPoul-Henning Kamp 
1936dd19a799SPoul-Henning Kamp #ifdef SOFTUPDATES
1937113db2ddSJeff Roberson 		/*
1938113db2ddSJeff Roberson 		 * Move over the dependencies.  If there are rollbacks,
1939113db2ddSJeff Roberson 		 * leave the parent buffer dirtied as it will need to
1940113db2ddSJeff Roberson 		 * be written again.
1941113db2ddSJeff Roberson 		 */
1942113db2ddSJeff Roberson 		if (LIST_EMPTY(&bp->b_dep) ||
1943113db2ddSJeff Roberson 		    softdep_move_dependencies(bp, newbp) == 0)
1944113db2ddSJeff Roberson 			bundirty(bp);
1945113db2ddSJeff Roberson #else
1946113db2ddSJeff Roberson 		bundirty(bp);
1947dd19a799SPoul-Henning Kamp #endif
1948dd19a799SPoul-Henning Kamp 
1949dd19a799SPoul-Henning Kamp 		/*
1950dd19a799SPoul-Henning Kamp 		 * Initiate write on the copy, release the original to
1951dd19a799SPoul-Henning Kamp 		 * the B_LOCKED queue so that it cannot go away until
1952dd19a799SPoul-Henning Kamp 		 * the background write completes. If not locked it could go
1953dd19a799SPoul-Henning Kamp 		 * away and then be reconstituted while it was being written.
1954dd19a799SPoul-Henning Kamp 		 * If the reconstituted buffer were written, we could end up
1955dd19a799SPoul-Henning Kamp 		 * with two background copies being written at the same time.
1956dd19a799SPoul-Henning Kamp 		 */
1957dd19a799SPoul-Henning Kamp 		bqrelse(bp);
1958dd19a799SPoul-Henning Kamp 		bp = newbp;
1959113db2ddSJeff Roberson 	} else
1960113db2ddSJeff Roberson 		/* Mark the buffer clean */
1961113db2ddSJeff Roberson 		bundirty(bp);
1962113db2ddSJeff Roberson 
1963dd19a799SPoul-Henning Kamp 
1964dd19a799SPoul-Henning Kamp 	/* Let the normal bufwrite do the rest for us */
1965c1d8b5e8SKonstantin Belousov normal_write:
19669248a827STor Egge 	return (bufwrite(bp));
1967dd19a799SPoul-Henning Kamp }
1968dd19a799SPoul-Henning Kamp 
1969dd19a799SPoul-Henning Kamp 
19708dd56505SPoul-Henning Kamp static void
19716e77a041SPoul-Henning Kamp ffs_geom_strategy(struct bufobj *bo, struct buf *bp)
19726e77a041SPoul-Henning Kamp {
1973153910e0SJeff Roberson 	struct vnode *vp;
1974153910e0SJeff Roberson 	int error;
19757de3839dSTor Egge 	struct buf *tbp;
1976113db2ddSJeff Roberson 	int nocopy;
19776e77a041SPoul-Henning Kamp 
1978153910e0SJeff Roberson 	vp = bo->__bo_vnode;
1979153910e0SJeff Roberson 	if (bp->b_iocmd == BIO_WRITE) {
1980153910e0SJeff Roberson 		if ((bp->b_flags & B_VALIDSUSPWRT) == 0 &&
1981153910e0SJeff Roberson 		    bp->b_vp != NULL && bp->b_vp->v_mount != NULL &&
1982153910e0SJeff Roberson 		    (bp->b_vp->v_mount->mnt_kern_flag & MNTK_SUSPENDED) != 0)
1983153910e0SJeff Roberson 			panic("ffs_geom_strategy: bad I/O");
1984113db2ddSJeff Roberson 		nocopy = bp->b_flags & B_NOCOPY;
1985113db2ddSJeff Roberson 		bp->b_flags &= ~(B_VALIDSUSPWRT | B_NOCOPY);
1986113db2ddSJeff Roberson 		if ((vp->v_vflag & VV_COPYONWRITE) && nocopy == 0 &&
19877de3839dSTor Egge 		    vp->v_rdev->si_snapdata != NULL) {
19887de3839dSTor Egge 			if ((bp->b_flags & B_CLUSTER) != 0) {
1989868bb88fSTor Egge 				runningbufwakeup(bp);
19907de3839dSTor Egge 				TAILQ_FOREACH(tbp, &bp->b_cluster.cluster_head,
19917de3839dSTor Egge 					      b_cluster.cluster_entry) {
19927de3839dSTor Egge 					error = ffs_copyonwrite(vp, tbp);
19937de3839dSTor Egge 					if (error != 0 &&
1994153910e0SJeff Roberson 					    error != EOPNOTSUPP) {
1995153910e0SJeff Roberson 						bp->b_error = error;
1996153910e0SJeff Roberson 						bp->b_ioflags |= BIO_ERROR;
1997153910e0SJeff Roberson 						bufdone(bp);
1998153910e0SJeff Roberson 						return;
1999153910e0SJeff Roberson 					}
2000153910e0SJeff Roberson 				}
2001868bb88fSTor Egge 				bp->b_runningbufspace = bp->b_bufsize;
20025bd65606SJohn Baldwin 				atomic_add_long(&runningbufspace,
2003868bb88fSTor Egge 					       bp->b_runningbufspace);
20047de3839dSTor Egge 			} else {
20057de3839dSTor Egge 				error = ffs_copyonwrite(vp, bp);
20067de3839dSTor Egge 				if (error != 0 && error != EOPNOTSUPP) {
20077de3839dSTor Egge 					bp->b_error = error;
20087de3839dSTor Egge 					bp->b_ioflags |= BIO_ERROR;
20097de3839dSTor Egge 					bufdone(bp);
20107de3839dSTor Egge 					return;
20117de3839dSTor Egge 				}
20127de3839dSTor Egge 			}
20137de3839dSTor Egge 		}
20147de3839dSTor Egge #ifdef SOFTUPDATES
20157de3839dSTor Egge 		if ((bp->b_flags & B_CLUSTER) != 0) {
20167de3839dSTor Egge 			TAILQ_FOREACH(tbp, &bp->b_cluster.cluster_head,
20177de3839dSTor Egge 				      b_cluster.cluster_entry) {
201804533fc6SXin LI 				if (!LIST_EMPTY(&tbp->b_dep))
20197de3839dSTor Egge 					buf_start(tbp);
20207de3839dSTor Egge 			}
20217de3839dSTor Egge 		} else {
202204533fc6SXin LI 			if (!LIST_EMPTY(&bp->b_dep))
20237de3839dSTor Egge 				buf_start(bp);
20247de3839dSTor Egge 		}
20257de3839dSTor Egge 
20267de3839dSTor Egge #endif
20277de3839dSTor Egge 	}
202843920011SPoul-Henning Kamp 	g_vfs_strategy(bo, bp);
20296e77a041SPoul-Henning Kamp }
203052dfc8d7SKonstantin Belousov 
203152dfc8d7SKonstantin Belousov #ifdef	DDB
203252dfc8d7SKonstantin Belousov 
203352dfc8d7SKonstantin Belousov static void
203452dfc8d7SKonstantin Belousov db_print_ffs(struct ufsmount *ump)
203552dfc8d7SKonstantin Belousov {
203652dfc8d7SKonstantin Belousov 	db_printf("mp %p %s devvp %p fs %p su_wl %d su_wl_in %d su_deps %d "
203752dfc8d7SKonstantin Belousov 		  "su_req %d\n",
203852dfc8d7SKonstantin Belousov 	    ump->um_mountp, ump->um_mountp->mnt_stat.f_mntonname,
203952dfc8d7SKonstantin Belousov 	    ump->um_devvp, ump->um_fs, ump->softdep_on_worklist,
204052dfc8d7SKonstantin Belousov 	    ump->softdep_on_worklist_inprogress, ump->softdep_deps,
204152dfc8d7SKonstantin Belousov 	    ump->softdep_req);
204252dfc8d7SKonstantin Belousov }
204352dfc8d7SKonstantin Belousov 
204452dfc8d7SKonstantin Belousov DB_SHOW_COMMAND(ffs, db_show_ffs)
204552dfc8d7SKonstantin Belousov {
204652dfc8d7SKonstantin Belousov 	struct mount *mp;
204752dfc8d7SKonstantin Belousov 	struct ufsmount *ump;
204852dfc8d7SKonstantin Belousov 
204952dfc8d7SKonstantin Belousov 	if (have_addr) {
205052dfc8d7SKonstantin Belousov 		ump = VFSTOUFS((struct mount *)addr);
205152dfc8d7SKonstantin Belousov 		db_print_ffs(ump);
205252dfc8d7SKonstantin Belousov 		return;
205352dfc8d7SKonstantin Belousov 	}
205452dfc8d7SKonstantin Belousov 
205552dfc8d7SKonstantin Belousov 	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
205652dfc8d7SKonstantin Belousov 		if (!strcmp(mp->mnt_stat.f_fstypename, ufs_vfsconf.vfc_name))
205752dfc8d7SKonstantin Belousov 			db_print_ffs(VFSTOUFS(mp));
205852dfc8d7SKonstantin Belousov 	}
205952dfc8d7SKonstantin Belousov }
206052dfc8d7SKonstantin Belousov 
206152dfc8d7SKonstantin Belousov #endif	/* DDB */
2062