1*0a6a1f1dSLionel Sambuc /* $NetBSD: ffs_vfsops.c,v 1.335 2015/07/24 13:02:52 maxv Exp $ */
2d65f6f70SBen Gras
3d65f6f70SBen Gras /*-
4d65f6f70SBen Gras * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
5d65f6f70SBen Gras * All rights reserved.
6d65f6f70SBen Gras *
7d65f6f70SBen Gras * This code is derived from software contributed to The NetBSD Foundation
8d65f6f70SBen Gras * by Wasabi Systems, Inc, and by Andrew Doran.
9d65f6f70SBen Gras *
10d65f6f70SBen Gras * Redistribution and use in source and binary forms, with or without
11d65f6f70SBen Gras * modification, are permitted provided that the following conditions
12d65f6f70SBen Gras * are met:
13d65f6f70SBen Gras * 1. Redistributions of source code must retain the above copyright
14d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer.
15d65f6f70SBen Gras * 2. Redistributions in binary form must reproduce the above copyright
16d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer in the
17d65f6f70SBen Gras * documentation and/or other materials provided with the distribution.
18d65f6f70SBen Gras *
19d65f6f70SBen Gras * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20d65f6f70SBen Gras * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21d65f6f70SBen Gras * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22d65f6f70SBen Gras * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23d65f6f70SBen Gras * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24d65f6f70SBen Gras * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25d65f6f70SBen Gras * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26d65f6f70SBen Gras * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27d65f6f70SBen Gras * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28d65f6f70SBen Gras * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29d65f6f70SBen Gras * POSSIBILITY OF SUCH DAMAGE.
30d65f6f70SBen Gras */
31d65f6f70SBen Gras
32d65f6f70SBen Gras /*
33d65f6f70SBen Gras * Copyright (c) 1989, 1991, 1993, 1994
34d65f6f70SBen Gras * The Regents of the University of California. All rights reserved.
35d65f6f70SBen Gras *
36d65f6f70SBen Gras * Redistribution and use in source and binary forms, with or without
37d65f6f70SBen Gras * modification, are permitted provided that the following conditions
38d65f6f70SBen Gras * are met:
39d65f6f70SBen Gras * 1. Redistributions of source code must retain the above copyright
40d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer.
41d65f6f70SBen Gras * 2. Redistributions in binary form must reproduce the above copyright
42d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer in the
43d65f6f70SBen Gras * documentation and/or other materials provided with the distribution.
44d65f6f70SBen Gras * 3. Neither the name of the University nor the names of its contributors
45d65f6f70SBen Gras * may be used to endorse or promote products derived from this software
46d65f6f70SBen Gras * without specific prior written permission.
47d65f6f70SBen Gras *
48d65f6f70SBen Gras * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49d65f6f70SBen Gras * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50d65f6f70SBen Gras * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51d65f6f70SBen Gras * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52d65f6f70SBen Gras * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53d65f6f70SBen Gras * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54d65f6f70SBen Gras * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55d65f6f70SBen Gras * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56d65f6f70SBen Gras * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57d65f6f70SBen Gras * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58d65f6f70SBen Gras * SUCH DAMAGE.
59d65f6f70SBen Gras *
60d65f6f70SBen Gras * @(#)ffs_vfsops.c 8.31 (Berkeley) 5/20/95
61d65f6f70SBen Gras */
62d65f6f70SBen Gras
63d65f6f70SBen Gras #include <sys/cdefs.h>
64*0a6a1f1dSLionel Sambuc __KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.335 2015/07/24 13:02:52 maxv Exp $");
65d65f6f70SBen Gras
66d65f6f70SBen Gras #if defined(_KERNEL_OPT)
67d65f6f70SBen Gras #include "opt_ffs.h"
68d65f6f70SBen Gras #include "opt_quota.h"
69d65f6f70SBen Gras #include "opt_wapbl.h"
70d65f6f70SBen Gras #endif
71d65f6f70SBen Gras
72d65f6f70SBen Gras #include <sys/param.h>
73d65f6f70SBen Gras #include <sys/systm.h>
74d65f6f70SBen Gras #include <sys/namei.h>
75d65f6f70SBen Gras #include <sys/proc.h>
76d65f6f70SBen Gras #include <sys/kernel.h>
77d65f6f70SBen Gras #include <sys/vnode.h>
78d65f6f70SBen Gras #include <sys/socket.h>
79d65f6f70SBen Gras #include <sys/mount.h>
80d65f6f70SBen Gras #include <sys/buf.h>
81d65f6f70SBen Gras #include <sys/device.h>
82d65f6f70SBen Gras #include <sys/disk.h>
83d65f6f70SBen Gras #include <sys/mbuf.h>
84d65f6f70SBen Gras #include <sys/file.h>
85d65f6f70SBen Gras #include <sys/disklabel.h>
86d65f6f70SBen Gras #include <sys/ioctl.h>
87d65f6f70SBen Gras #include <sys/errno.h>
8884d9c625SLionel Sambuc #include <sys/kmem.h>
89d65f6f70SBen Gras #include <sys/pool.h>
90d65f6f70SBen Gras #include <sys/lock.h>
91d65f6f70SBen Gras #include <sys/sysctl.h>
92d65f6f70SBen Gras #include <sys/conf.h>
93d65f6f70SBen Gras #include <sys/kauth.h>
94d65f6f70SBen Gras #include <sys/wapbl.h>
95d65f6f70SBen Gras #include <sys/fstrans.h>
96d65f6f70SBen Gras #include <sys/module.h>
97d65f6f70SBen Gras
98d65f6f70SBen Gras #include <miscfs/genfs/genfs.h>
99d65f6f70SBen Gras #include <miscfs/specfs/specdev.h>
100d65f6f70SBen Gras
101d65f6f70SBen Gras #include <ufs/ufs/quota.h>
102d65f6f70SBen Gras #include <ufs/ufs/ufsmount.h>
103d65f6f70SBen Gras #include <ufs/ufs/inode.h>
104d65f6f70SBen Gras #include <ufs/ufs/dir.h>
105d65f6f70SBen Gras #include <ufs/ufs/ufs_extern.h>
106d65f6f70SBen Gras #include <ufs/ufs/ufs_bswap.h>
107d65f6f70SBen Gras #include <ufs/ufs/ufs_wapbl.h>
108d65f6f70SBen Gras
109d65f6f70SBen Gras #include <ufs/ffs/fs.h>
110d65f6f70SBen Gras #include <ufs/ffs/ffs_extern.h>
111d65f6f70SBen Gras
112d65f6f70SBen Gras MODULE(MODULE_CLASS_VFS, ffs, NULL);
113d65f6f70SBen Gras
114d65f6f70SBen Gras static int ffs_vfs_fsync(vnode_t *, int);
115*0a6a1f1dSLionel Sambuc static int ffs_superblock_validate(struct fs *);
116*0a6a1f1dSLionel Sambuc static int ffs_is_appleufs(struct vnode *, struct fs *);
117*0a6a1f1dSLionel Sambuc
118*0a6a1f1dSLionel Sambuc static int ffs_init_vnode(struct ufsmount *, struct vnode *, ino_t);
119*0a6a1f1dSLionel Sambuc static void ffs_deinit_vnode(struct ufsmount *, struct vnode *);
120d65f6f70SBen Gras
121d65f6f70SBen Gras static struct sysctllog *ffs_sysctl_log;
122d65f6f70SBen Gras
12384d9c625SLionel Sambuc static kauth_listener_t ffs_snapshot_listener;
12484d9c625SLionel Sambuc
125d65f6f70SBen Gras /* how many times ffs_init() was called */
126d65f6f70SBen Gras int ffs_initcount = 0;
127d65f6f70SBen Gras
128*0a6a1f1dSLionel Sambuc #ifdef DEBUG_FFS_MOUNT
129*0a6a1f1dSLionel Sambuc #define DPRINTF(_fmt, args...) printf("%s: " _fmt "\n", __func__, ##args)
130*0a6a1f1dSLionel Sambuc #else
131*0a6a1f1dSLionel Sambuc #define DPRINTF(_fmt, args...) do {} while (/*CONSTCOND*/0)
132*0a6a1f1dSLionel Sambuc #endif
133*0a6a1f1dSLionel Sambuc
134d65f6f70SBen Gras extern const struct vnodeopv_desc ffs_vnodeop_opv_desc;
135d65f6f70SBen Gras extern const struct vnodeopv_desc ffs_specop_opv_desc;
136d65f6f70SBen Gras extern const struct vnodeopv_desc ffs_fifoop_opv_desc;
137d65f6f70SBen Gras
138d65f6f70SBen Gras const struct vnodeopv_desc * const ffs_vnodeopv_descs[] = {
139d65f6f70SBen Gras &ffs_vnodeop_opv_desc,
140d65f6f70SBen Gras &ffs_specop_opv_desc,
141d65f6f70SBen Gras &ffs_fifoop_opv_desc,
142d65f6f70SBen Gras NULL,
143d65f6f70SBen Gras };
144d65f6f70SBen Gras
145d65f6f70SBen Gras struct vfsops ffs_vfsops = {
146*0a6a1f1dSLionel Sambuc .vfs_name = MOUNT_FFS,
147*0a6a1f1dSLionel Sambuc .vfs_min_mount_data = sizeof (struct ufs_args),
148*0a6a1f1dSLionel Sambuc .vfs_mount = ffs_mount,
149*0a6a1f1dSLionel Sambuc .vfs_start = ufs_start,
150*0a6a1f1dSLionel Sambuc .vfs_unmount = ffs_unmount,
151*0a6a1f1dSLionel Sambuc .vfs_root = ufs_root,
152*0a6a1f1dSLionel Sambuc .vfs_quotactl = ufs_quotactl,
153*0a6a1f1dSLionel Sambuc .vfs_statvfs = ffs_statvfs,
154*0a6a1f1dSLionel Sambuc .vfs_sync = ffs_sync,
155*0a6a1f1dSLionel Sambuc .vfs_vget = ufs_vget,
156*0a6a1f1dSLionel Sambuc .vfs_loadvnode = ffs_loadvnode,
157*0a6a1f1dSLionel Sambuc .vfs_newvnode = ffs_newvnode,
158*0a6a1f1dSLionel Sambuc .vfs_fhtovp = ffs_fhtovp,
159*0a6a1f1dSLionel Sambuc .vfs_vptofh = ffs_vptofh,
160*0a6a1f1dSLionel Sambuc .vfs_init = ffs_init,
161*0a6a1f1dSLionel Sambuc .vfs_reinit = ffs_reinit,
162*0a6a1f1dSLionel Sambuc .vfs_done = ffs_done,
163*0a6a1f1dSLionel Sambuc .vfs_mountroot = ffs_mountroot,
164*0a6a1f1dSLionel Sambuc .vfs_snapshot = ffs_snapshot,
165*0a6a1f1dSLionel Sambuc .vfs_extattrctl = ffs_extattrctl,
166*0a6a1f1dSLionel Sambuc .vfs_suspendctl = ffs_suspendctl,
167*0a6a1f1dSLionel Sambuc .vfs_renamelock_enter = genfs_renamelock_enter,
168*0a6a1f1dSLionel Sambuc .vfs_renamelock_exit = genfs_renamelock_exit,
169*0a6a1f1dSLionel Sambuc .vfs_fsync = ffs_vfs_fsync,
170*0a6a1f1dSLionel Sambuc .vfs_opv_descs = ffs_vnodeopv_descs
171d65f6f70SBen Gras };
172d65f6f70SBen Gras
173d65f6f70SBen Gras static const struct genfs_ops ffs_genfsops = {
174d65f6f70SBen Gras .gop_size = ffs_gop_size,
175d65f6f70SBen Gras .gop_alloc = ufs_gop_alloc,
176d65f6f70SBen Gras .gop_write = genfs_gop_write,
177d65f6f70SBen Gras .gop_markupdate = ufs_gop_markupdate,
178d65f6f70SBen Gras };
179d65f6f70SBen Gras
180d65f6f70SBen Gras static const struct ufs_ops ffs_ufsops = {
181d65f6f70SBen Gras .uo_itimes = ffs_itimes,
182d65f6f70SBen Gras .uo_update = ffs_update,
183d65f6f70SBen Gras .uo_truncate = ffs_truncate,
184d65f6f70SBen Gras .uo_balloc = ffs_balloc,
18584d9c625SLionel Sambuc .uo_snapgone = ffs_snapgone,
186*0a6a1f1dSLionel Sambuc .uo_bufrd = ffs_bufrd,
187*0a6a1f1dSLionel Sambuc .uo_bufwr = ffs_bufwr,
188d65f6f70SBen Gras };
189d65f6f70SBen Gras
190d65f6f70SBen Gras static int
ffs_snapshot_cb(kauth_cred_t cred,kauth_action_t action,void * cookie,void * arg0,void * arg1,void * arg2,void * arg3)19184d9c625SLionel Sambuc ffs_snapshot_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
19284d9c625SLionel Sambuc void *arg0, void *arg1, void *arg2, void *arg3)
19384d9c625SLionel Sambuc {
19484d9c625SLionel Sambuc vnode_t *vp = arg2;
195*0a6a1f1dSLionel Sambuc int result = KAUTH_RESULT_DEFER;
19684d9c625SLionel Sambuc
19784d9c625SLionel Sambuc if (action != KAUTH_SYSTEM_FS_SNAPSHOT)
19884d9c625SLionel Sambuc return result;
19984d9c625SLionel Sambuc
20084d9c625SLionel Sambuc if (VTOI(vp)->i_uid == kauth_cred_geteuid(cred))
20184d9c625SLionel Sambuc result = KAUTH_RESULT_ALLOW;
20284d9c625SLionel Sambuc
20384d9c625SLionel Sambuc return result;
20484d9c625SLionel Sambuc }
20584d9c625SLionel Sambuc
20684d9c625SLionel Sambuc static int
ffs_modcmd(modcmd_t cmd,void * arg)207d65f6f70SBen Gras ffs_modcmd(modcmd_t cmd, void *arg)
208d65f6f70SBen Gras {
209d65f6f70SBen Gras int error;
210d65f6f70SBen Gras
211d65f6f70SBen Gras #if 0
212d65f6f70SBen Gras extern int doasyncfree;
213d65f6f70SBen Gras #endif
214d65f6f70SBen Gras #ifdef UFS_EXTATTR
215d65f6f70SBen Gras extern int ufs_extattr_autocreate;
216d65f6f70SBen Gras #endif
217d65f6f70SBen Gras extern int ffs_log_changeopt;
218d65f6f70SBen Gras
219d65f6f70SBen Gras switch (cmd) {
220d65f6f70SBen Gras case MODULE_CMD_INIT:
221d65f6f70SBen Gras error = vfs_attach(&ffs_vfsops);
222d65f6f70SBen Gras if (error != 0)
223d65f6f70SBen Gras break;
224d65f6f70SBen Gras
225d65f6f70SBen Gras sysctl_createv(&ffs_sysctl_log, 0, NULL, NULL,
226d65f6f70SBen Gras CTLFLAG_PERMANENT,
227d65f6f70SBen Gras CTLTYPE_NODE, "ffs",
228d65f6f70SBen Gras SYSCTL_DESCR("Berkeley Fast File System"),
229d65f6f70SBen Gras NULL, 0, NULL, 0,
230d65f6f70SBen Gras CTL_VFS, 1, CTL_EOL);
231d65f6f70SBen Gras /*
232d65f6f70SBen Gras * @@@ should we even bother with these first three?
233d65f6f70SBen Gras */
234d65f6f70SBen Gras sysctl_createv(&ffs_sysctl_log, 0, NULL, NULL,
235d65f6f70SBen Gras CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
236d65f6f70SBen Gras CTLTYPE_INT, "doclusterread", NULL,
237d65f6f70SBen Gras sysctl_notavail, 0, NULL, 0,
238d65f6f70SBen Gras CTL_VFS, 1, FFS_CLUSTERREAD, CTL_EOL);
239d65f6f70SBen Gras sysctl_createv(&ffs_sysctl_log, 0, NULL, NULL,
240d65f6f70SBen Gras CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
241d65f6f70SBen Gras CTLTYPE_INT, "doclusterwrite", NULL,
242d65f6f70SBen Gras sysctl_notavail, 0, NULL, 0,
243d65f6f70SBen Gras CTL_VFS, 1, FFS_CLUSTERWRITE, CTL_EOL);
244d65f6f70SBen Gras sysctl_createv(&ffs_sysctl_log, 0, NULL, NULL,
245d65f6f70SBen Gras CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
246d65f6f70SBen Gras CTLTYPE_INT, "doreallocblks", NULL,
247d65f6f70SBen Gras sysctl_notavail, 0, NULL, 0,
248d65f6f70SBen Gras CTL_VFS, 1, FFS_REALLOCBLKS, CTL_EOL);
249d65f6f70SBen Gras #if 0
250d65f6f70SBen Gras sysctl_createv(&ffs_sysctl_log, 0, NULL, NULL,
251d65f6f70SBen Gras CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
252d65f6f70SBen Gras CTLTYPE_INT, "doasyncfree",
253d65f6f70SBen Gras SYSCTL_DESCR("Release dirty blocks asynchronously"),
254d65f6f70SBen Gras NULL, 0, &doasyncfree, 0,
255d65f6f70SBen Gras CTL_VFS, 1, FFS_ASYNCFREE, CTL_EOL);
256d65f6f70SBen Gras #endif
257d65f6f70SBen Gras sysctl_createv(&ffs_sysctl_log, 0, NULL, NULL,
258d65f6f70SBen Gras CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
259d65f6f70SBen Gras CTLTYPE_INT, "log_changeopt",
260d65f6f70SBen Gras SYSCTL_DESCR("Log changes in optimization strategy"),
261d65f6f70SBen Gras NULL, 0, &ffs_log_changeopt, 0,
262d65f6f70SBen Gras CTL_VFS, 1, FFS_LOG_CHANGEOPT, CTL_EOL);
263d65f6f70SBen Gras #ifdef UFS_EXTATTR
264d65f6f70SBen Gras sysctl_createv(&ffs_sysctl_log, 0, NULL, NULL,
265d65f6f70SBen Gras CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
266d65f6f70SBen Gras CTLTYPE_INT, "extattr_autocreate",
267d65f6f70SBen Gras SYSCTL_DESCR("Size of attribute for "
268d65f6f70SBen Gras "backing file autocreation"),
269d65f6f70SBen Gras NULL, 0, &ufs_extattr_autocreate, 0,
270d65f6f70SBen Gras CTL_VFS, 1, FFS_EXTATTR_AUTOCREATE, CTL_EOL);
271d65f6f70SBen Gras
272d65f6f70SBen Gras #endif /* UFS_EXTATTR */
273d65f6f70SBen Gras
27484d9c625SLionel Sambuc ffs_snapshot_listener = kauth_listen_scope(KAUTH_SCOPE_SYSTEM,
27584d9c625SLionel Sambuc ffs_snapshot_cb, NULL);
27684d9c625SLionel Sambuc if (ffs_snapshot_listener == NULL)
27784d9c625SLionel Sambuc printf("ffs_modcmd: can't listen on system scope.\n");
27884d9c625SLionel Sambuc
279d65f6f70SBen Gras break;
280d65f6f70SBen Gras case MODULE_CMD_FINI:
281d65f6f70SBen Gras error = vfs_detach(&ffs_vfsops);
282d65f6f70SBen Gras if (error != 0)
283d65f6f70SBen Gras break;
284d65f6f70SBen Gras sysctl_teardown(&ffs_sysctl_log);
28584d9c625SLionel Sambuc if (ffs_snapshot_listener != NULL)
28684d9c625SLionel Sambuc kauth_unlisten_scope(ffs_snapshot_listener);
287d65f6f70SBen Gras break;
288d65f6f70SBen Gras default:
289d65f6f70SBen Gras error = ENOTTY;
290d65f6f70SBen Gras break;
291d65f6f70SBen Gras }
292d65f6f70SBen Gras
293d65f6f70SBen Gras return (error);
294d65f6f70SBen Gras }
295d65f6f70SBen Gras
296d65f6f70SBen Gras pool_cache_t ffs_inode_cache;
297d65f6f70SBen Gras pool_cache_t ffs_dinode1_cache;
298d65f6f70SBen Gras pool_cache_t ffs_dinode2_cache;
299d65f6f70SBen Gras
300d65f6f70SBen Gras static void ffs_oldfscompat_read(struct fs *, struct ufsmount *, daddr_t);
301d65f6f70SBen Gras static void ffs_oldfscompat_write(struct fs *, struct ufsmount *);
302d65f6f70SBen Gras
303d65f6f70SBen Gras /*
304d65f6f70SBen Gras * Called by main() when ffs is going to be mounted as root.
305d65f6f70SBen Gras */
306d65f6f70SBen Gras
307d65f6f70SBen Gras int
ffs_mountroot(void)308d65f6f70SBen Gras ffs_mountroot(void)
309d65f6f70SBen Gras {
310d65f6f70SBen Gras struct fs *fs;
311d65f6f70SBen Gras struct mount *mp;
312d65f6f70SBen Gras struct lwp *l = curlwp; /* XXX */
313d65f6f70SBen Gras struct ufsmount *ump;
314d65f6f70SBen Gras int error;
315d65f6f70SBen Gras
316d65f6f70SBen Gras if (device_class(root_device) != DV_DISK)
317d65f6f70SBen Gras return (ENODEV);
318d65f6f70SBen Gras
319d65f6f70SBen Gras if ((error = vfs_rootmountalloc(MOUNT_FFS, "root_device", &mp))) {
320d65f6f70SBen Gras vrele(rootvp);
321d65f6f70SBen Gras return (error);
322d65f6f70SBen Gras }
323d65f6f70SBen Gras
324d65f6f70SBen Gras /*
325d65f6f70SBen Gras * We always need to be able to mount the root file system.
326d65f6f70SBen Gras */
327d65f6f70SBen Gras mp->mnt_flag |= MNT_FORCE;
328d65f6f70SBen Gras if ((error = ffs_mountfs(rootvp, mp, l)) != 0) {
329d65f6f70SBen Gras vfs_unbusy(mp, false, NULL);
330d65f6f70SBen Gras vfs_destroy(mp);
331d65f6f70SBen Gras return (error);
332d65f6f70SBen Gras }
333d65f6f70SBen Gras mp->mnt_flag &= ~MNT_FORCE;
33484d9c625SLionel Sambuc mountlist_append(mp);
335d65f6f70SBen Gras ump = VFSTOUFS(mp);
336d65f6f70SBen Gras fs = ump->um_fs;
337d65f6f70SBen Gras memset(fs->fs_fsmnt, 0, sizeof(fs->fs_fsmnt));
338d65f6f70SBen Gras (void)copystr(mp->mnt_stat.f_mntonname, fs->fs_fsmnt, MNAMELEN - 1, 0);
339d65f6f70SBen Gras (void)ffs_statvfs(mp, &mp->mnt_stat);
340d65f6f70SBen Gras vfs_unbusy(mp, false, NULL);
341d65f6f70SBen Gras setrootfstime((time_t)fs->fs_time);
342d65f6f70SBen Gras return (0);
343d65f6f70SBen Gras }
344d65f6f70SBen Gras
345d65f6f70SBen Gras /*
346d65f6f70SBen Gras * VFS Operations.
347d65f6f70SBen Gras *
348d65f6f70SBen Gras * mount system call
349d65f6f70SBen Gras */
350d65f6f70SBen Gras int
ffs_mount(struct mount * mp,const char * path,void * data,size_t * data_len)351d65f6f70SBen Gras ffs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
352d65f6f70SBen Gras {
353d65f6f70SBen Gras struct lwp *l = curlwp;
354d65f6f70SBen Gras struct vnode *devvp = NULL;
355d65f6f70SBen Gras struct ufs_args *args = data;
356d65f6f70SBen Gras struct ufsmount *ump = NULL;
357d65f6f70SBen Gras struct fs *fs;
358d65f6f70SBen Gras int error = 0, flags, update;
359d65f6f70SBen Gras mode_t accessmode;
360d65f6f70SBen Gras
361*0a6a1f1dSLionel Sambuc if (args == NULL) {
362*0a6a1f1dSLionel Sambuc DPRINTF("NULL args");
363d65f6f70SBen Gras return EINVAL;
364*0a6a1f1dSLionel Sambuc }
365*0a6a1f1dSLionel Sambuc if (*data_len < sizeof(*args)) {
366*0a6a1f1dSLionel Sambuc DPRINTF("bad size args %zu != %zu", *data_len, sizeof(*args));
367*0a6a1f1dSLionel Sambuc return EINVAL;
368*0a6a1f1dSLionel Sambuc }
369d65f6f70SBen Gras
370d65f6f70SBen Gras if (mp->mnt_flag & MNT_GETARGS) {
371d65f6f70SBen Gras ump = VFSTOUFS(mp);
372*0a6a1f1dSLionel Sambuc if (ump == NULL) {
373*0a6a1f1dSLionel Sambuc DPRINTF("no ump");
374d65f6f70SBen Gras return EIO;
375*0a6a1f1dSLionel Sambuc }
376d65f6f70SBen Gras args->fspec = NULL;
377d65f6f70SBen Gras *data_len = sizeof *args;
378d65f6f70SBen Gras return 0;
379d65f6f70SBen Gras }
380d65f6f70SBen Gras
381d65f6f70SBen Gras update = mp->mnt_flag & MNT_UPDATE;
382d65f6f70SBen Gras
383d65f6f70SBen Gras /* Check arguments */
384d65f6f70SBen Gras if (args->fspec != NULL) {
385d65f6f70SBen Gras /*
386d65f6f70SBen Gras * Look up the name and verify that it's sane.
387d65f6f70SBen Gras */
388d65f6f70SBen Gras error = namei_simple_user(args->fspec,
389d65f6f70SBen Gras NSM_FOLLOW_NOEMULROOT, &devvp);
390*0a6a1f1dSLionel Sambuc if (error != 0) {
391*0a6a1f1dSLionel Sambuc DPRINTF("namei_simple_user returned %d", error);
392*0a6a1f1dSLionel Sambuc return error;
393*0a6a1f1dSLionel Sambuc }
394d65f6f70SBen Gras
395d65f6f70SBen Gras if (!update) {
396d65f6f70SBen Gras /*
397d65f6f70SBen Gras * Be sure this is a valid block device
398d65f6f70SBen Gras */
399*0a6a1f1dSLionel Sambuc if (devvp->v_type != VBLK) {
400*0a6a1f1dSLionel Sambuc DPRINTF("non block device %d", devvp->v_type);
401d65f6f70SBen Gras error = ENOTBLK;
402*0a6a1f1dSLionel Sambuc } else if (bdevsw_lookup(devvp->v_rdev) == NULL) {
403*0a6a1f1dSLionel Sambuc DPRINTF("can't find block device 0x%jx",
404*0a6a1f1dSLionel Sambuc devvp->v_rdev);
405d65f6f70SBen Gras error = ENXIO;
406*0a6a1f1dSLionel Sambuc }
407d65f6f70SBen Gras } else {
408d65f6f70SBen Gras /*
409d65f6f70SBen Gras * Be sure we're still naming the same device
410d65f6f70SBen Gras * used for our initial mount
411d65f6f70SBen Gras */
412d65f6f70SBen Gras ump = VFSTOUFS(mp);
413d65f6f70SBen Gras if (devvp != ump->um_devvp) {
414*0a6a1f1dSLionel Sambuc if (devvp->v_rdev != ump->um_devvp->v_rdev) {
415*0a6a1f1dSLionel Sambuc DPRINTF("wrong device 0x%jx != 0x%jx",
416*0a6a1f1dSLionel Sambuc (uintmax_t)devvp->v_rdev,
417*0a6a1f1dSLionel Sambuc (uintmax_t)ump->um_devvp->v_rdev);
418d65f6f70SBen Gras error = EINVAL;
419*0a6a1f1dSLionel Sambuc } else {
420d65f6f70SBen Gras vrele(devvp);
421d65f6f70SBen Gras devvp = ump->um_devvp;
422d65f6f70SBen Gras vref(devvp);
423d65f6f70SBen Gras }
424d65f6f70SBen Gras }
425d65f6f70SBen Gras }
426d65f6f70SBen Gras } else {
427d65f6f70SBen Gras if (!update) {
428d65f6f70SBen Gras /* New mounts must have a filename for the device */
429*0a6a1f1dSLionel Sambuc DPRINTF("no filename for mount");
430*0a6a1f1dSLionel Sambuc return EINVAL;
431d65f6f70SBen Gras } else {
432d65f6f70SBen Gras /* Use the extant mount */
433d65f6f70SBen Gras ump = VFSTOUFS(mp);
434d65f6f70SBen Gras devvp = ump->um_devvp;
435d65f6f70SBen Gras vref(devvp);
436d65f6f70SBen Gras }
437d65f6f70SBen Gras }
438d65f6f70SBen Gras
439d65f6f70SBen Gras /*
440d65f6f70SBen Gras * If mount by non-root, then verify that user has necessary
441d65f6f70SBen Gras * permissions on the device.
442d65f6f70SBen Gras *
443d65f6f70SBen Gras * Permission to update a mount is checked higher, so here we presume
444d65f6f70SBen Gras * updating the mount is okay (for example, as far as securelevel goes)
445d65f6f70SBen Gras * which leaves us with the normal check.
446d65f6f70SBen Gras */
447d65f6f70SBen Gras if (error == 0) {
448d65f6f70SBen Gras accessmode = VREAD;
449d65f6f70SBen Gras if (update ?
450d65f6f70SBen Gras (mp->mnt_iflag & IMNT_WANTRDWR) != 0 :
451d65f6f70SBen Gras (mp->mnt_flag & MNT_RDONLY) == 0)
452d65f6f70SBen Gras accessmode |= VWRITE;
453d65f6f70SBen Gras vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
45484d9c625SLionel Sambuc error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
45584d9c625SLionel Sambuc KAUTH_REQ_SYSTEM_MOUNT_DEVICE, mp, devvp,
45684d9c625SLionel Sambuc KAUTH_ARG(accessmode));
457*0a6a1f1dSLionel Sambuc if (error) {
458*0a6a1f1dSLionel Sambuc DPRINTF("kauth returned %d", error);
459*0a6a1f1dSLionel Sambuc }
460d65f6f70SBen Gras VOP_UNLOCK(devvp);
461d65f6f70SBen Gras }
462d65f6f70SBen Gras
463d65f6f70SBen Gras if (error) {
464d65f6f70SBen Gras vrele(devvp);
465d65f6f70SBen Gras return (error);
466d65f6f70SBen Gras }
467d65f6f70SBen Gras
468d65f6f70SBen Gras #ifdef WAPBL
469d65f6f70SBen Gras /* WAPBL can only be enabled on a r/w mount. */
470d65f6f70SBen Gras if ((mp->mnt_flag & MNT_RDONLY) && !(mp->mnt_iflag & IMNT_WANTRDWR)) {
471d65f6f70SBen Gras mp->mnt_flag &= ~MNT_LOG;
472d65f6f70SBen Gras }
473d65f6f70SBen Gras #else /* !WAPBL */
474d65f6f70SBen Gras mp->mnt_flag &= ~MNT_LOG;
475d65f6f70SBen Gras #endif /* !WAPBL */
476d65f6f70SBen Gras
477d65f6f70SBen Gras if (!update) {
478d65f6f70SBen Gras int xflags;
479d65f6f70SBen Gras
480d65f6f70SBen Gras if (mp->mnt_flag & MNT_RDONLY)
481d65f6f70SBen Gras xflags = FREAD;
482d65f6f70SBen Gras else
483d65f6f70SBen Gras xflags = FREAD | FWRITE;
484d65f6f70SBen Gras vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
485d65f6f70SBen Gras error = VOP_OPEN(devvp, xflags, FSCRED);
486d65f6f70SBen Gras VOP_UNLOCK(devvp);
487*0a6a1f1dSLionel Sambuc if (error) {
488*0a6a1f1dSLionel Sambuc DPRINTF("VOP_OPEN returned %d", error);
489d65f6f70SBen Gras goto fail;
490*0a6a1f1dSLionel Sambuc }
491d65f6f70SBen Gras error = ffs_mountfs(devvp, mp, l);
492d65f6f70SBen Gras if (error) {
493*0a6a1f1dSLionel Sambuc DPRINTF("ffs_mountfs returned %d", error);
494d65f6f70SBen Gras vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
495d65f6f70SBen Gras (void)VOP_CLOSE(devvp, xflags, NOCRED);
496d65f6f70SBen Gras VOP_UNLOCK(devvp);
497d65f6f70SBen Gras goto fail;
498d65f6f70SBen Gras }
499d65f6f70SBen Gras
500d65f6f70SBen Gras ump = VFSTOUFS(mp);
501d65f6f70SBen Gras fs = ump->um_fs;
502d65f6f70SBen Gras } else {
503d65f6f70SBen Gras /*
504d65f6f70SBen Gras * Update the mount.
505d65f6f70SBen Gras */
506d65f6f70SBen Gras
507d65f6f70SBen Gras /*
508d65f6f70SBen Gras * The initial mount got a reference on this
509d65f6f70SBen Gras * device, so drop the one obtained via
510d65f6f70SBen Gras * namei(), above.
511d65f6f70SBen Gras */
512d65f6f70SBen Gras vrele(devvp);
513d65f6f70SBen Gras
514d65f6f70SBen Gras ump = VFSTOUFS(mp);
515d65f6f70SBen Gras fs = ump->um_fs;
516d65f6f70SBen Gras if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
517d65f6f70SBen Gras /*
518d65f6f70SBen Gras * Changing from r/w to r/o
519d65f6f70SBen Gras */
520d65f6f70SBen Gras flags = WRITECLOSE;
521d65f6f70SBen Gras if (mp->mnt_flag & MNT_FORCE)
522d65f6f70SBen Gras flags |= FORCECLOSE;
523d65f6f70SBen Gras error = ffs_flushfiles(mp, flags, l);
524d65f6f70SBen Gras if (error == 0)
525d65f6f70SBen Gras error = UFS_WAPBL_BEGIN(mp);
526d65f6f70SBen Gras if (error == 0 &&
527d65f6f70SBen Gras ffs_cgupdate(ump, MNT_WAIT) == 0 &&
528d65f6f70SBen Gras fs->fs_clean & FS_WASCLEAN) {
529d65f6f70SBen Gras if (mp->mnt_flag & MNT_SOFTDEP)
530d65f6f70SBen Gras fs->fs_flags &= ~FS_DOSOFTDEP;
531d65f6f70SBen Gras fs->fs_clean = FS_ISCLEAN;
532d65f6f70SBen Gras (void) ffs_sbupdate(ump, MNT_WAIT);
533d65f6f70SBen Gras }
534*0a6a1f1dSLionel Sambuc if (error) {
535*0a6a1f1dSLionel Sambuc DPRINTF("wapbl %d", error);
536*0a6a1f1dSLionel Sambuc return error;
537*0a6a1f1dSLionel Sambuc }
538d65f6f70SBen Gras UFS_WAPBL_END(mp);
539d65f6f70SBen Gras }
540d65f6f70SBen Gras
541d65f6f70SBen Gras #ifdef WAPBL
542d65f6f70SBen Gras if ((mp->mnt_flag & MNT_LOG) == 0) {
543d65f6f70SBen Gras error = ffs_wapbl_stop(mp, mp->mnt_flag & MNT_FORCE);
544*0a6a1f1dSLionel Sambuc if (error) {
545*0a6a1f1dSLionel Sambuc DPRINTF("ffs_wapbl_stop returned %d", error);
546d65f6f70SBen Gras return error;
547d65f6f70SBen Gras }
548*0a6a1f1dSLionel Sambuc }
549d65f6f70SBen Gras #endif /* WAPBL */
550d65f6f70SBen Gras
551d65f6f70SBen Gras if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
552d65f6f70SBen Gras /*
553d65f6f70SBen Gras * Finish change from r/w to r/o
554d65f6f70SBen Gras */
555d65f6f70SBen Gras fs->fs_ronly = 1;
556d65f6f70SBen Gras fs->fs_fmod = 0;
557d65f6f70SBen Gras }
558d65f6f70SBen Gras
559d65f6f70SBen Gras if (mp->mnt_flag & MNT_RELOAD) {
560d65f6f70SBen Gras error = ffs_reload(mp, l->l_cred, l);
561*0a6a1f1dSLionel Sambuc if (error) {
562*0a6a1f1dSLionel Sambuc DPRINTF("ffs_reload returned %d", error);
563*0a6a1f1dSLionel Sambuc return error;
564*0a6a1f1dSLionel Sambuc }
565d65f6f70SBen Gras }
566d65f6f70SBen Gras
567d65f6f70SBen Gras if (fs->fs_ronly && (mp->mnt_iflag & IMNT_WANTRDWR)) {
568d65f6f70SBen Gras /*
569d65f6f70SBen Gras * Changing from read-only to read/write
570d65f6f70SBen Gras */
571d65f6f70SBen Gras #ifndef QUOTA2
572d65f6f70SBen Gras if (fs->fs_flags & FS_DOQUOTA2) {
573d65f6f70SBen Gras ump->um_flags |= UFS_QUOTA2;
574d65f6f70SBen Gras uprintf("%s: options QUOTA2 not enabled%s\n",
575d65f6f70SBen Gras mp->mnt_stat.f_mntonname,
576d65f6f70SBen Gras (mp->mnt_flag & MNT_FORCE) ? "" :
577d65f6f70SBen Gras ", not mounting");
578*0a6a1f1dSLionel Sambuc DPRINTF("ffs_quota2 %d", EINVAL);
579d65f6f70SBen Gras return EINVAL;
580d65f6f70SBen Gras }
581d65f6f70SBen Gras #endif
582d65f6f70SBen Gras fs->fs_ronly = 0;
583d65f6f70SBen Gras fs->fs_clean <<= 1;
584d65f6f70SBen Gras fs->fs_fmod = 1;
585d65f6f70SBen Gras #ifdef WAPBL
586d65f6f70SBen Gras if (fs->fs_flags & FS_DOWAPBL) {
587*0a6a1f1dSLionel Sambuc const char *nm = mp->mnt_stat.f_mntonname;
588*0a6a1f1dSLionel Sambuc if (!mp->mnt_wapbl_replay) {
589*0a6a1f1dSLionel Sambuc printf("%s: log corrupted;"
590*0a6a1f1dSLionel Sambuc " replay cancelled\n", nm);
591*0a6a1f1dSLionel Sambuc return EFTYPE;
592*0a6a1f1dSLionel Sambuc }
593*0a6a1f1dSLionel Sambuc printf("%s: replaying log to disk\n", nm);
594d65f6f70SBen Gras error = wapbl_replay_write(mp->mnt_wapbl_replay,
595d65f6f70SBen Gras devvp);
596d65f6f70SBen Gras if (error) {
597*0a6a1f1dSLionel Sambuc DPRINTF("%s: wapbl_replay_write %d",
598*0a6a1f1dSLionel Sambuc nm, error);
599d65f6f70SBen Gras return error;
600d65f6f70SBen Gras }
601d65f6f70SBen Gras wapbl_replay_stop(mp->mnt_wapbl_replay);
602d65f6f70SBen Gras fs->fs_clean = FS_WASCLEAN;
603d65f6f70SBen Gras }
604d65f6f70SBen Gras #endif /* WAPBL */
605d65f6f70SBen Gras if (fs->fs_snapinum[0] != 0)
606d65f6f70SBen Gras ffs_snapshot_mount(mp);
607d65f6f70SBen Gras }
608d65f6f70SBen Gras
609d65f6f70SBen Gras #ifdef WAPBL
610d65f6f70SBen Gras error = ffs_wapbl_start(mp);
611*0a6a1f1dSLionel Sambuc if (error) {
612*0a6a1f1dSLionel Sambuc DPRINTF("ffs_wapbl_start returned %d", error);
613d65f6f70SBen Gras return error;
614*0a6a1f1dSLionel Sambuc }
615d65f6f70SBen Gras #endif /* WAPBL */
616d65f6f70SBen Gras
617d65f6f70SBen Gras #ifdef QUOTA2
618d65f6f70SBen Gras if (!fs->fs_ronly) {
619d65f6f70SBen Gras error = ffs_quota2_mount(mp);
620d65f6f70SBen Gras if (error) {
621*0a6a1f1dSLionel Sambuc DPRINTF("ffs_quota2_mount returned %d", error);
622d65f6f70SBen Gras return error;
623d65f6f70SBen Gras }
624d65f6f70SBen Gras }
625d65f6f70SBen Gras #endif
62684d9c625SLionel Sambuc
62784d9c625SLionel Sambuc if ((mp->mnt_flag & MNT_DISCARD) && !(ump->um_discarddata))
62884d9c625SLionel Sambuc ump->um_discarddata = ffs_discard_init(devvp, fs);
62984d9c625SLionel Sambuc
630d65f6f70SBen Gras if (args->fspec == NULL)
631d65f6f70SBen Gras return 0;
632d65f6f70SBen Gras }
633d65f6f70SBen Gras
634d65f6f70SBen Gras error = set_statvfs_info(path, UIO_USERSPACE, args->fspec,
635d65f6f70SBen Gras UIO_USERSPACE, mp->mnt_op->vfs_name, mp, l);
636d65f6f70SBen Gras if (error == 0)
637d65f6f70SBen Gras (void)strncpy(fs->fs_fsmnt, mp->mnt_stat.f_mntonname,
638d65f6f70SBen Gras sizeof(fs->fs_fsmnt));
639*0a6a1f1dSLionel Sambuc else {
640*0a6a1f1dSLionel Sambuc DPRINTF("set_statvfs_info returned %d", error);
641*0a6a1f1dSLionel Sambuc }
642d65f6f70SBen Gras fs->fs_flags &= ~FS_DOSOFTDEP;
643d65f6f70SBen Gras if (fs->fs_fmod != 0) { /* XXX */
644d65f6f70SBen Gras int err;
645d65f6f70SBen Gras
646d65f6f70SBen Gras fs->fs_fmod = 0;
647d65f6f70SBen Gras if (fs->fs_clean & FS_WASCLEAN)
648d65f6f70SBen Gras fs->fs_time = time_second;
649d65f6f70SBen Gras else {
650d65f6f70SBen Gras printf("%s: file system not clean (fs_clean=%#x); "
651d65f6f70SBen Gras "please fsck(8)\n", mp->mnt_stat.f_mntfromname,
652d65f6f70SBen Gras fs->fs_clean);
653d65f6f70SBen Gras printf("%s: lost blocks %" PRId64 " files %d\n",
654d65f6f70SBen Gras mp->mnt_stat.f_mntfromname, fs->fs_pendingblocks,
655d65f6f70SBen Gras fs->fs_pendinginodes);
656d65f6f70SBen Gras }
657d65f6f70SBen Gras err = UFS_WAPBL_BEGIN(mp);
658d65f6f70SBen Gras if (err == 0) {
659d65f6f70SBen Gras (void) ffs_cgupdate(ump, MNT_WAIT);
660d65f6f70SBen Gras UFS_WAPBL_END(mp);
661d65f6f70SBen Gras }
662d65f6f70SBen Gras }
663d65f6f70SBen Gras if ((mp->mnt_flag & MNT_SOFTDEP) != 0) {
664d65f6f70SBen Gras printf("%s: `-o softdep' is no longer supported, "
665d65f6f70SBen Gras "consider `-o log'\n", mp->mnt_stat.f_mntfromname);
666d65f6f70SBen Gras mp->mnt_flag &= ~MNT_SOFTDEP;
667d65f6f70SBen Gras }
668d65f6f70SBen Gras
669d65f6f70SBen Gras return (error);
670d65f6f70SBen Gras
671d65f6f70SBen Gras fail:
672d65f6f70SBen Gras vrele(devvp);
673d65f6f70SBen Gras return (error);
674d65f6f70SBen Gras }
675d65f6f70SBen Gras
676d65f6f70SBen Gras /*
677d65f6f70SBen Gras * Reload all incore data for a filesystem (used after running fsck on
678d65f6f70SBen Gras * the root filesystem and finding things to fix). The filesystem must
679d65f6f70SBen Gras * be mounted read-only.
680d65f6f70SBen Gras *
681d65f6f70SBen Gras * Things to do to update the mount:
682d65f6f70SBen Gras * 1) invalidate all cached meta-data.
683d65f6f70SBen Gras * 2) re-read superblock from disk.
684d65f6f70SBen Gras * 3) re-read summary information from disk.
685d65f6f70SBen Gras * 4) invalidate all inactive vnodes.
686d65f6f70SBen Gras * 5) invalidate all cached file data.
687d65f6f70SBen Gras * 6) re-read inode data for all active vnodes.
688d65f6f70SBen Gras */
689d65f6f70SBen Gras int
ffs_reload(struct mount * mp,kauth_cred_t cred,struct lwp * l)690d65f6f70SBen Gras ffs_reload(struct mount *mp, kauth_cred_t cred, struct lwp *l)
691d65f6f70SBen Gras {
692*0a6a1f1dSLionel Sambuc struct vnode *vp, *devvp;
693d65f6f70SBen Gras struct inode *ip;
694d65f6f70SBen Gras void *space;
695d65f6f70SBen Gras struct buf *bp;
696d65f6f70SBen Gras struct fs *fs, *newfs;
697d65f6f70SBen Gras int i, bsize, blks, error;
698*0a6a1f1dSLionel Sambuc int32_t *lp, fs_sbsize;
699d65f6f70SBen Gras struct ufsmount *ump;
700d65f6f70SBen Gras daddr_t sblockloc;
701*0a6a1f1dSLionel Sambuc struct vnode_iterator *marker;
702d65f6f70SBen Gras
703d65f6f70SBen Gras if ((mp->mnt_flag & MNT_RDONLY) == 0)
704d65f6f70SBen Gras return (EINVAL);
705d65f6f70SBen Gras
706d65f6f70SBen Gras ump = VFSTOUFS(mp);
707*0a6a1f1dSLionel Sambuc
708d65f6f70SBen Gras /*
709d65f6f70SBen Gras * Step 1: invalidate all cached meta-data.
710d65f6f70SBen Gras */
711d65f6f70SBen Gras devvp = ump->um_devvp;
712d65f6f70SBen Gras vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
713d65f6f70SBen Gras error = vinvalbuf(devvp, 0, cred, l, 0, 0);
714d65f6f70SBen Gras VOP_UNLOCK(devvp);
715d65f6f70SBen Gras if (error)
716d65f6f70SBen Gras panic("ffs_reload: dirty1");
717*0a6a1f1dSLionel Sambuc
718d65f6f70SBen Gras /*
719*0a6a1f1dSLionel Sambuc * Step 2: re-read superblock from disk. XXX: We don't handle
720*0a6a1f1dSLionel Sambuc * possibility that superblock moved. Which implies that we don't
721*0a6a1f1dSLionel Sambuc * want its size to change either.
722d65f6f70SBen Gras */
723d65f6f70SBen Gras fs = ump->um_fs;
724*0a6a1f1dSLionel Sambuc fs_sbsize = fs->fs_sbsize;
725*0a6a1f1dSLionel Sambuc error = bread(devvp, fs->fs_sblockloc / DEV_BSIZE, fs_sbsize,
726*0a6a1f1dSLionel Sambuc 0, &bp);
727*0a6a1f1dSLionel Sambuc if (error)
728d65f6f70SBen Gras return (error);
729*0a6a1f1dSLionel Sambuc newfs = kmem_alloc(fs_sbsize, KM_SLEEP);
730*0a6a1f1dSLionel Sambuc memcpy(newfs, bp->b_data, fs_sbsize);
731*0a6a1f1dSLionel Sambuc
732d65f6f70SBen Gras #ifdef FFS_EI
733d65f6f70SBen Gras if (ump->um_flags & UFS_NEEDSWAP) {
734d65f6f70SBen Gras ffs_sb_swap((struct fs *)bp->b_data, newfs);
735*0a6a1f1dSLionel Sambuc newfs->fs_flags |= FS_SWAPPED;
736d65f6f70SBen Gras } else
737d65f6f70SBen Gras #endif
738*0a6a1f1dSLionel Sambuc newfs->fs_flags &= ~FS_SWAPPED;
739*0a6a1f1dSLionel Sambuc
740d65f6f70SBen Gras brelse(bp, 0);
741*0a6a1f1dSLionel Sambuc
742*0a6a1f1dSLionel Sambuc if ((newfs->fs_magic != FS_UFS1_MAGIC) &&
743*0a6a1f1dSLionel Sambuc (newfs->fs_magic != FS_UFS2_MAGIC)) {
744*0a6a1f1dSLionel Sambuc kmem_free(newfs, fs_sbsize);
745d65f6f70SBen Gras return (EIO); /* XXX needs translation */
746d65f6f70SBen Gras }
747*0a6a1f1dSLionel Sambuc if (!ffs_superblock_validate(newfs)) {
748*0a6a1f1dSLionel Sambuc kmem_free(newfs, fs_sbsize);
749*0a6a1f1dSLionel Sambuc return (EINVAL);
750*0a6a1f1dSLionel Sambuc }
751*0a6a1f1dSLionel Sambuc
752*0a6a1f1dSLionel Sambuc /*
753*0a6a1f1dSLionel Sambuc * The current implementation doesn't handle the possibility that
754*0a6a1f1dSLionel Sambuc * these values may have changed.
755*0a6a1f1dSLionel Sambuc */
756*0a6a1f1dSLionel Sambuc if ((newfs->fs_sbsize != fs_sbsize) ||
757*0a6a1f1dSLionel Sambuc (newfs->fs_cssize != fs->fs_cssize) ||
758*0a6a1f1dSLionel Sambuc (newfs->fs_contigsumsize != fs->fs_contigsumsize) ||
759*0a6a1f1dSLionel Sambuc (newfs->fs_ncg != fs->fs_ncg)) {
760*0a6a1f1dSLionel Sambuc kmem_free(newfs, fs_sbsize);
761*0a6a1f1dSLionel Sambuc return (EINVAL);
762*0a6a1f1dSLionel Sambuc }
763*0a6a1f1dSLionel Sambuc
764d65f6f70SBen Gras /* Store off old fs_sblockloc for fs_oldfscompat_read. */
765d65f6f70SBen Gras sblockloc = fs->fs_sblockloc;
766d65f6f70SBen Gras /*
767d65f6f70SBen Gras * Copy pointer fields back into superblock before copying in XXX
768d65f6f70SBen Gras * new superblock. These should really be in the ufsmount. XXX
769d65f6f70SBen Gras * Note that important parameters (eg fs_ncg) are unchanged.
770d65f6f70SBen Gras */
771d65f6f70SBen Gras newfs->fs_csp = fs->fs_csp;
772d65f6f70SBen Gras newfs->fs_maxcluster = fs->fs_maxcluster;
773d65f6f70SBen Gras newfs->fs_contigdirs = fs->fs_contigdirs;
774d65f6f70SBen Gras newfs->fs_ronly = fs->fs_ronly;
775d65f6f70SBen Gras newfs->fs_active = fs->fs_active;
776*0a6a1f1dSLionel Sambuc memcpy(fs, newfs, (u_int)fs_sbsize);
777*0a6a1f1dSLionel Sambuc kmem_free(newfs, fs_sbsize);
778d65f6f70SBen Gras
779*0a6a1f1dSLionel Sambuc /*
780*0a6a1f1dSLionel Sambuc * Recheck for Apple UFS filesystem.
781*0a6a1f1dSLionel Sambuc */
782d65f6f70SBen Gras ump->um_flags &= ~UFS_ISAPPLEUFS;
783*0a6a1f1dSLionel Sambuc if (ffs_is_appleufs(devvp, fs)) {
784d65f6f70SBen Gras #ifdef APPLE_UFS
785d65f6f70SBen Gras ump->um_flags |= UFS_ISAPPLEUFS;
786d65f6f70SBen Gras #else
787*0a6a1f1dSLionel Sambuc DPRINTF("AppleUFS not supported");
788*0a6a1f1dSLionel Sambuc return (EIO); /* XXX: really? */
789d65f6f70SBen Gras #endif
790*0a6a1f1dSLionel Sambuc }
791d65f6f70SBen Gras
792d65f6f70SBen Gras if (UFS_MPISAPPLEUFS(ump)) {
793d65f6f70SBen Gras /* see comment about NeXT below */
794d65f6f70SBen Gras ump->um_maxsymlinklen = APPLEUFS_MAXSYMLINKLEN;
795d65f6f70SBen Gras ump->um_dirblksiz = APPLEUFS_DIRBLKSIZ;
796d65f6f70SBen Gras mp->mnt_iflag |= IMNT_DTYPE;
797d65f6f70SBen Gras } else {
798d65f6f70SBen Gras ump->um_maxsymlinklen = fs->fs_maxsymlinklen;
79984d9c625SLionel Sambuc ump->um_dirblksiz = UFS_DIRBLKSIZ;
800d65f6f70SBen Gras if (ump->um_maxsymlinklen > 0)
801d65f6f70SBen Gras mp->mnt_iflag |= IMNT_DTYPE;
802d65f6f70SBen Gras else
803d65f6f70SBen Gras mp->mnt_iflag &= ~IMNT_DTYPE;
804d65f6f70SBen Gras }
805d65f6f70SBen Gras ffs_oldfscompat_read(fs, ump, sblockloc);
806d65f6f70SBen Gras
807d65f6f70SBen Gras mutex_enter(&ump->um_lock);
808d65f6f70SBen Gras ump->um_maxfilesize = fs->fs_maxfilesize;
809d65f6f70SBen Gras if (fs->fs_flags & ~(FS_KNOWN_FLAGS | FS_INTERNAL)) {
810d65f6f70SBen Gras uprintf("%s: unknown ufs flags: 0x%08"PRIx32"%s\n",
811d65f6f70SBen Gras mp->mnt_stat.f_mntonname, fs->fs_flags,
812d65f6f70SBen Gras (mp->mnt_flag & MNT_FORCE) ? "" : ", not mounting");
813d65f6f70SBen Gras if ((mp->mnt_flag & MNT_FORCE) == 0) {
814d65f6f70SBen Gras mutex_exit(&ump->um_lock);
815d65f6f70SBen Gras return (EINVAL);
816d65f6f70SBen Gras }
817d65f6f70SBen Gras }
818d65f6f70SBen Gras if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
819d65f6f70SBen Gras fs->fs_pendingblocks = 0;
820d65f6f70SBen Gras fs->fs_pendinginodes = 0;
821d65f6f70SBen Gras }
822d65f6f70SBen Gras mutex_exit(&ump->um_lock);
823d65f6f70SBen Gras
824d65f6f70SBen Gras ffs_statvfs(mp, &mp->mnt_stat);
825d65f6f70SBen Gras /*
826d65f6f70SBen Gras * Step 3: re-read summary information from disk.
827d65f6f70SBen Gras */
828d65f6f70SBen Gras blks = howmany(fs->fs_cssize, fs->fs_fsize);
829d65f6f70SBen Gras space = fs->fs_csp;
830d65f6f70SBen Gras for (i = 0; i < blks; i += fs->fs_frag) {
831d65f6f70SBen Gras bsize = fs->fs_bsize;
832d65f6f70SBen Gras if (i + fs->fs_frag > blks)
833d65f6f70SBen Gras bsize = (blks - i) * fs->fs_fsize;
83484d9c625SLionel Sambuc error = bread(devvp, FFS_FSBTODB(fs, fs->fs_csaddr + i), bsize,
835*0a6a1f1dSLionel Sambuc 0, &bp);
836d65f6f70SBen Gras if (error) {
837d65f6f70SBen Gras return (error);
838d65f6f70SBen Gras }
839d65f6f70SBen Gras #ifdef FFS_EI
840d65f6f70SBen Gras if (UFS_FSNEEDSWAP(fs))
841d65f6f70SBen Gras ffs_csum_swap((struct csum *)bp->b_data,
842d65f6f70SBen Gras (struct csum *)space, bsize);
843d65f6f70SBen Gras else
844d65f6f70SBen Gras #endif
845d65f6f70SBen Gras memcpy(space, bp->b_data, (size_t)bsize);
846d65f6f70SBen Gras space = (char *)space + bsize;
847d65f6f70SBen Gras brelse(bp, 0);
848d65f6f70SBen Gras }
849d65f6f70SBen Gras /*
850d65f6f70SBen Gras * We no longer know anything about clusters per cylinder group.
851d65f6f70SBen Gras */
852d65f6f70SBen Gras if (fs->fs_contigsumsize > 0) {
853d65f6f70SBen Gras lp = fs->fs_maxcluster;
854d65f6f70SBen Gras for (i = 0; i < fs->fs_ncg; i++)
855d65f6f70SBen Gras *lp++ = fs->fs_contigsumsize;
856d65f6f70SBen Gras }
857d65f6f70SBen Gras
858*0a6a1f1dSLionel Sambuc vfs_vnode_iterator_init(mp, &marker);
859*0a6a1f1dSLionel Sambuc while ((vp = vfs_vnode_iterator_next(marker, NULL, NULL))) {
860d65f6f70SBen Gras /*
861d65f6f70SBen Gras * Step 4: invalidate all inactive vnodes.
862d65f6f70SBen Gras */
863*0a6a1f1dSLionel Sambuc if (vrecycle(vp))
864*0a6a1f1dSLionel Sambuc continue;
865d65f6f70SBen Gras /*
866d65f6f70SBen Gras * Step 5: invalidate all cached file data.
867d65f6f70SBen Gras */
868*0a6a1f1dSLionel Sambuc if (vn_lock(vp, LK_EXCLUSIVE)) {
869*0a6a1f1dSLionel Sambuc vrele(vp);
870*0a6a1f1dSLionel Sambuc continue;
871d65f6f70SBen Gras }
872d65f6f70SBen Gras if (vinvalbuf(vp, 0, cred, l, 0, 0))
873d65f6f70SBen Gras panic("ffs_reload: dirty2");
874d65f6f70SBen Gras /*
875d65f6f70SBen Gras * Step 6: re-read inode data for all active vnodes.
876d65f6f70SBen Gras */
877d65f6f70SBen Gras ip = VTOI(vp);
87884d9c625SLionel Sambuc error = bread(devvp, FFS_FSBTODB(fs, ino_to_fsba(fs, ip->i_number)),
879*0a6a1f1dSLionel Sambuc (int)fs->fs_bsize, 0, &bp);
880d65f6f70SBen Gras if (error) {
881d65f6f70SBen Gras vput(vp);
882d65f6f70SBen Gras break;
883d65f6f70SBen Gras }
884d65f6f70SBen Gras ffs_load_inode(bp, ip, fs, ip->i_number);
885d65f6f70SBen Gras brelse(bp, 0);
886d65f6f70SBen Gras vput(vp);
887d65f6f70SBen Gras }
888*0a6a1f1dSLionel Sambuc vfs_vnode_iterator_destroy(marker);
889d65f6f70SBen Gras return (error);
890d65f6f70SBen Gras }
891d65f6f70SBen Gras
892d65f6f70SBen Gras /*
893d65f6f70SBen Gras * Possible superblock locations ordered from most to least likely.
894d65f6f70SBen Gras */
895d65f6f70SBen Gras static const int sblock_try[] = SBLOCKSEARCH;
896d65f6f70SBen Gras
897*0a6a1f1dSLionel Sambuc
898*0a6a1f1dSLionel Sambuc static int
ffs_superblock_validate(struct fs * fs)899*0a6a1f1dSLionel Sambuc ffs_superblock_validate(struct fs *fs)
900*0a6a1f1dSLionel Sambuc {
901*0a6a1f1dSLionel Sambuc int32_t i, fs_bshift = 0, fs_fshift = 0, fs_fragshift = 0, fs_frag;
902*0a6a1f1dSLionel Sambuc int32_t fs_inopb, fs_cgsize;
903*0a6a1f1dSLionel Sambuc
904*0a6a1f1dSLionel Sambuc /* Check the superblock size */
905*0a6a1f1dSLionel Sambuc if (fs->fs_sbsize > SBLOCKSIZE || fs->fs_sbsize < sizeof(struct fs))
906*0a6a1f1dSLionel Sambuc return 0;
907*0a6a1f1dSLionel Sambuc
908*0a6a1f1dSLionel Sambuc /* Check the file system blocksize */
909*0a6a1f1dSLionel Sambuc if (fs->fs_bsize > MAXBSIZE || fs->fs_bsize < MINBSIZE)
910*0a6a1f1dSLionel Sambuc return 0;
911*0a6a1f1dSLionel Sambuc if (!powerof2(fs->fs_bsize))
912*0a6a1f1dSLionel Sambuc return 0;
913*0a6a1f1dSLionel Sambuc
914*0a6a1f1dSLionel Sambuc /* Check the size of frag blocks */
915*0a6a1f1dSLionel Sambuc if (!powerof2(fs->fs_fsize))
916*0a6a1f1dSLionel Sambuc return 0;
917*0a6a1f1dSLionel Sambuc if (fs->fs_fsize == 0)
918*0a6a1f1dSLionel Sambuc return 0;
919*0a6a1f1dSLionel Sambuc
920*0a6a1f1dSLionel Sambuc /*
921*0a6a1f1dSLionel Sambuc * XXX: these values are just zero-checked to prevent obvious
922*0a6a1f1dSLionel Sambuc * bugs. We need more strict checks.
923*0a6a1f1dSLionel Sambuc */
924*0a6a1f1dSLionel Sambuc if (fs->fs_size == 0)
925*0a6a1f1dSLionel Sambuc return 0;
926*0a6a1f1dSLionel Sambuc if (fs->fs_cssize == 0)
927*0a6a1f1dSLionel Sambuc return 0;
928*0a6a1f1dSLionel Sambuc if (fs->fs_ipg == 0)
929*0a6a1f1dSLionel Sambuc return 0;
930*0a6a1f1dSLionel Sambuc if (fs->fs_fpg == 0)
931*0a6a1f1dSLionel Sambuc return 0;
932*0a6a1f1dSLionel Sambuc if (fs->fs_ncg == 0)
933*0a6a1f1dSLionel Sambuc return 0;
934*0a6a1f1dSLionel Sambuc if (fs->fs_maxbpg == 0)
935*0a6a1f1dSLionel Sambuc return 0;
936*0a6a1f1dSLionel Sambuc
937*0a6a1f1dSLionel Sambuc /* Check the number of inodes per block */
938*0a6a1f1dSLionel Sambuc if (fs->fs_magic == FS_UFS1_MAGIC)
939*0a6a1f1dSLionel Sambuc fs_inopb = fs->fs_bsize / sizeof(struct ufs1_dinode);
940*0a6a1f1dSLionel Sambuc else /* fs->fs_magic == FS_UFS2_MAGIC */
941*0a6a1f1dSLionel Sambuc fs_inopb = fs->fs_bsize / sizeof(struct ufs2_dinode);
942*0a6a1f1dSLionel Sambuc if (fs->fs_inopb != fs_inopb)
943*0a6a1f1dSLionel Sambuc return 0;
944*0a6a1f1dSLionel Sambuc
945*0a6a1f1dSLionel Sambuc /* Block size cannot be smaller than fragment size */
946*0a6a1f1dSLionel Sambuc if (fs->fs_bsize < fs->fs_fsize)
947*0a6a1f1dSLionel Sambuc return 0;
948*0a6a1f1dSLionel Sambuc
949*0a6a1f1dSLionel Sambuc /* Compute fs_bshift and ensure it is consistent */
950*0a6a1f1dSLionel Sambuc for (i = fs->fs_bsize; i > 1; i >>= 1)
951*0a6a1f1dSLionel Sambuc fs_bshift++;
952*0a6a1f1dSLionel Sambuc if (fs->fs_bshift != fs_bshift)
953*0a6a1f1dSLionel Sambuc return 0;
954*0a6a1f1dSLionel Sambuc
955*0a6a1f1dSLionel Sambuc /* Compute fs_fshift and ensure it is consistent */
956*0a6a1f1dSLionel Sambuc for (i = fs->fs_fsize; i > 1; i >>= 1)
957*0a6a1f1dSLionel Sambuc fs_fshift++;
958*0a6a1f1dSLionel Sambuc if (fs->fs_fshift != fs_fshift)
959*0a6a1f1dSLionel Sambuc return 0;
960*0a6a1f1dSLionel Sambuc
961*0a6a1f1dSLionel Sambuc /* Compute fs_fragshift and ensure it is consistent */
962*0a6a1f1dSLionel Sambuc for (i = fs->fs_frag; i > 1; i >>= 1)
963*0a6a1f1dSLionel Sambuc fs_fragshift++;
964*0a6a1f1dSLionel Sambuc if (fs->fs_fragshift != fs_fragshift)
965*0a6a1f1dSLionel Sambuc return 0;
966*0a6a1f1dSLionel Sambuc
967*0a6a1f1dSLionel Sambuc /* Check the masks */
968*0a6a1f1dSLionel Sambuc if (fs->fs_bmask != ~(fs->fs_bsize - 1))
969*0a6a1f1dSLionel Sambuc return 0;
970*0a6a1f1dSLionel Sambuc if (fs->fs_fmask != ~(fs->fs_fsize - 1))
971*0a6a1f1dSLionel Sambuc return 0;
972*0a6a1f1dSLionel Sambuc
973*0a6a1f1dSLionel Sambuc /*
974*0a6a1f1dSLionel Sambuc * Now that the shifts and masks are sanitized, we can use the ffs_ API.
975*0a6a1f1dSLionel Sambuc */
976*0a6a1f1dSLionel Sambuc
977*0a6a1f1dSLionel Sambuc /* Check the number of frag blocks */
978*0a6a1f1dSLionel Sambuc if ((fs_frag = ffs_numfrags(fs, fs->fs_bsize)) > MAXFRAG)
979*0a6a1f1dSLionel Sambuc return 0;
980*0a6a1f1dSLionel Sambuc if (fs->fs_frag != fs_frag)
981*0a6a1f1dSLionel Sambuc return 0;
982*0a6a1f1dSLionel Sambuc
983*0a6a1f1dSLionel Sambuc /* Check the size of cylinder groups */
984*0a6a1f1dSLionel Sambuc fs_cgsize = ffs_fragroundup(fs, CGSIZE(fs));
985*0a6a1f1dSLionel Sambuc if (fs->fs_cgsize != fs_cgsize) {
986*0a6a1f1dSLionel Sambuc if (fs->fs_cgsize+1 == CGSIZE(fs)) {
987*0a6a1f1dSLionel Sambuc printf("CGSIZE(fs) miscalculated by one - this file "
988*0a6a1f1dSLionel Sambuc "system may have been created by\n"
989*0a6a1f1dSLionel Sambuc " an old (buggy) userland, see\n"
990*0a6a1f1dSLionel Sambuc " http://www.NetBSD.org/"
991*0a6a1f1dSLionel Sambuc "docs/ffsv1badsuperblock.html\n");
992*0a6a1f1dSLionel Sambuc } else {
993*0a6a1f1dSLionel Sambuc printf("ERROR: cylinder group size mismatch: "
994*0a6a1f1dSLionel Sambuc "fs_cgsize = 0x%zx, "
995*0a6a1f1dSLionel Sambuc "fs->fs_cgsize = 0x%zx, CGSIZE(fs) = 0x%zx\n",
996*0a6a1f1dSLionel Sambuc (size_t)fs_cgsize, (size_t)fs->fs_cgsize,
997*0a6a1f1dSLionel Sambuc (size_t)CGSIZE(fs));
998*0a6a1f1dSLionel Sambuc return 0;
999*0a6a1f1dSLionel Sambuc }
1000*0a6a1f1dSLionel Sambuc }
1001*0a6a1f1dSLionel Sambuc
1002*0a6a1f1dSLionel Sambuc return 1;
1003*0a6a1f1dSLionel Sambuc }
1004*0a6a1f1dSLionel Sambuc
1005*0a6a1f1dSLionel Sambuc static int
ffs_is_appleufs(struct vnode * devvp,struct fs * fs)1006*0a6a1f1dSLionel Sambuc ffs_is_appleufs(struct vnode *devvp, struct fs *fs)
1007*0a6a1f1dSLionel Sambuc {
1008*0a6a1f1dSLionel Sambuc struct dkwedge_info dkw;
1009*0a6a1f1dSLionel Sambuc int ret = 0;
1010*0a6a1f1dSLionel Sambuc
1011*0a6a1f1dSLionel Sambuc /*
1012*0a6a1f1dSLionel Sambuc * First check to see if this is tagged as an Apple UFS filesystem
1013*0a6a1f1dSLionel Sambuc * in the disklabel.
1014*0a6a1f1dSLionel Sambuc */
1015*0a6a1f1dSLionel Sambuc if (getdiskinfo(devvp, &dkw) == 0 &&
1016*0a6a1f1dSLionel Sambuc strcmp(dkw.dkw_ptype, DKW_PTYPE_APPLEUFS) == 0)
1017*0a6a1f1dSLionel Sambuc ret = 1;
1018*0a6a1f1dSLionel Sambuc #ifdef APPLE_UFS
1019*0a6a1f1dSLionel Sambuc else {
1020*0a6a1f1dSLionel Sambuc struct appleufslabel *applefs;
1021*0a6a1f1dSLionel Sambuc struct buf *bp;
1022*0a6a1f1dSLionel Sambuc daddr_t blkno = APPLEUFS_LABEL_OFFSET / DEV_BSIZE;
1023*0a6a1f1dSLionel Sambuc int error;
1024*0a6a1f1dSLionel Sambuc
1025*0a6a1f1dSLionel Sambuc /*
1026*0a6a1f1dSLionel Sambuc * Manually look for an Apple UFS label, and if a valid one
1027*0a6a1f1dSLionel Sambuc * is found, then treat it like an Apple UFS filesystem anyway.
1028*0a6a1f1dSLionel Sambuc */
1029*0a6a1f1dSLionel Sambuc error = bread(devvp, blkno, APPLEUFS_LABEL_SIZE, 0, &bp);
1030*0a6a1f1dSLionel Sambuc if (error) {
1031*0a6a1f1dSLionel Sambuc DPRINTF("bread@0x%jx returned %d", (intmax_t)blkno, error);
1032*0a6a1f1dSLionel Sambuc return 0;
1033*0a6a1f1dSLionel Sambuc }
1034*0a6a1f1dSLionel Sambuc applefs = (struct appleufslabel *)bp->b_data;
1035*0a6a1f1dSLionel Sambuc error = ffs_appleufs_validate(fs->fs_fsmnt, applefs, NULL);
1036*0a6a1f1dSLionel Sambuc if (error == 0)
1037*0a6a1f1dSLionel Sambuc ret = 1;
1038*0a6a1f1dSLionel Sambuc brelse(bp, 0);
1039*0a6a1f1dSLionel Sambuc }
1040*0a6a1f1dSLionel Sambuc #endif
1041*0a6a1f1dSLionel Sambuc
1042*0a6a1f1dSLionel Sambuc return ret;
1043*0a6a1f1dSLionel Sambuc }
1044*0a6a1f1dSLionel Sambuc
1045d65f6f70SBen Gras /*
1046d65f6f70SBen Gras * Common code for mount and mountroot
1047d65f6f70SBen Gras */
1048d65f6f70SBen Gras int
ffs_mountfs(struct vnode * devvp,struct mount * mp,struct lwp * l)1049d65f6f70SBen Gras ffs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
1050d65f6f70SBen Gras {
1051*0a6a1f1dSLionel Sambuc struct ufsmount *ump = NULL;
1052*0a6a1f1dSLionel Sambuc struct buf *bp = NULL;
1053*0a6a1f1dSLionel Sambuc struct fs *fs = NULL;
1054d65f6f70SBen Gras dev_t dev;
1055d65f6f70SBen Gras void *space;
1056*0a6a1f1dSLionel Sambuc daddr_t sblockloc = 0;
1057*0a6a1f1dSLionel Sambuc int blks, fstype = 0;
1058d65f6f70SBen Gras int error, i, bsize, ronly, bset = 0;
1059d65f6f70SBen Gras #ifdef FFS_EI
1060d65f6f70SBen Gras int needswap = 0; /* keep gcc happy */
1061d65f6f70SBen Gras #endif
1062d65f6f70SBen Gras int32_t *lp;
1063d65f6f70SBen Gras kauth_cred_t cred;
1064*0a6a1f1dSLionel Sambuc u_int32_t allocsbsize, fs_sbsize = 0;
1065d65f6f70SBen Gras
1066d65f6f70SBen Gras dev = devvp->v_rdev;
1067d65f6f70SBen Gras cred = l ? l->l_cred : NOCRED;
1068d65f6f70SBen Gras
1069d65f6f70SBen Gras /* Flush out any old buffers remaining from a previous use. */
1070d65f6f70SBen Gras vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
1071d65f6f70SBen Gras error = vinvalbuf(devvp, V_SAVE, cred, l, 0, 0);
1072d65f6f70SBen Gras VOP_UNLOCK(devvp);
1073*0a6a1f1dSLionel Sambuc if (error) {
1074*0a6a1f1dSLionel Sambuc DPRINTF("vinvalbuf returned %d", error);
1075*0a6a1f1dSLionel Sambuc return error;
1076*0a6a1f1dSLionel Sambuc }
1077d65f6f70SBen Gras
1078d65f6f70SBen Gras ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
1079d65f6f70SBen Gras
1080d65f6f70SBen Gras error = fstrans_mount(mp);
1081*0a6a1f1dSLionel Sambuc if (error) {
1082*0a6a1f1dSLionel Sambuc DPRINTF("fstrans_mount returned %d", error);
1083d65f6f70SBen Gras return error;
1084*0a6a1f1dSLionel Sambuc }
1085d65f6f70SBen Gras
108684d9c625SLionel Sambuc ump = kmem_zalloc(sizeof(*ump), KM_SLEEP);
1087d65f6f70SBen Gras mutex_init(&ump->um_lock, MUTEX_DEFAULT, IPL_NONE);
1088d65f6f70SBen Gras error = ffs_snapshot_init(ump);
1089*0a6a1f1dSLionel Sambuc if (error) {
1090*0a6a1f1dSLionel Sambuc DPRINTF("ffs_snapshot_init returned %d", error);
1091d65f6f70SBen Gras goto out;
1092*0a6a1f1dSLionel Sambuc }
1093d65f6f70SBen Gras ump->um_ops = &ffs_ufsops;
1094d65f6f70SBen Gras
1095d65f6f70SBen Gras #ifdef WAPBL
1096d65f6f70SBen Gras sbagain:
1097d65f6f70SBen Gras #endif
1098d65f6f70SBen Gras /*
1099d65f6f70SBen Gras * Try reading the superblock in each of its possible locations.
1100d65f6f70SBen Gras */
1101d65f6f70SBen Gras for (i = 0; ; i++) {
1102*0a6a1f1dSLionel Sambuc daddr_t fs_sblockloc;
1103*0a6a1f1dSLionel Sambuc
1104d65f6f70SBen Gras if (bp != NULL) {
1105d65f6f70SBen Gras brelse(bp, BC_NOCACHE);
1106d65f6f70SBen Gras bp = NULL;
1107d65f6f70SBen Gras }
1108d65f6f70SBen Gras if (sblock_try[i] == -1) {
1109*0a6a1f1dSLionel Sambuc DPRINTF("no superblock found");
1110d65f6f70SBen Gras error = EINVAL;
1111d65f6f70SBen Gras fs = NULL;
1112d65f6f70SBen Gras goto out;
1113d65f6f70SBen Gras }
1114*0a6a1f1dSLionel Sambuc
1115*0a6a1f1dSLionel Sambuc error = bread(devvp, sblock_try[i] / DEV_BSIZE, SBLOCKSIZE,
1116d65f6f70SBen Gras 0, &bp);
1117d65f6f70SBen Gras if (error) {
1118*0a6a1f1dSLionel Sambuc DPRINTF("bread@0x%x returned %d",
1119*0a6a1f1dSLionel Sambuc sblock_try[i] / DEV_BSIZE, error);
1120d65f6f70SBen Gras fs = NULL;
1121d65f6f70SBen Gras goto out;
1122d65f6f70SBen Gras }
1123d65f6f70SBen Gras fs = (struct fs *)bp->b_data;
1124*0a6a1f1dSLionel Sambuc
1125*0a6a1f1dSLionel Sambuc sblockloc = sblock_try[i];
1126*0a6a1f1dSLionel Sambuc DPRINTF("fs_magic 0x%x", fs->fs_magic);
1127*0a6a1f1dSLionel Sambuc
1128*0a6a1f1dSLionel Sambuc /*
1129*0a6a1f1dSLionel Sambuc * Swap: here, we swap fs->fs_sbsize in order to get the correct
1130*0a6a1f1dSLionel Sambuc * size to read the superblock. Once read, we swap the whole
1131*0a6a1f1dSLionel Sambuc * superblock structure.
1132*0a6a1f1dSLionel Sambuc */
1133d65f6f70SBen Gras if (fs->fs_magic == FS_UFS1_MAGIC) {
1134*0a6a1f1dSLionel Sambuc fs_sbsize = fs->fs_sbsize;
1135d65f6f70SBen Gras fstype = UFS1;
1136d65f6f70SBen Gras #ifdef FFS_EI
1137d65f6f70SBen Gras needswap = 0;
113884d9c625SLionel Sambuc } else if (fs->fs_magic == FS_UFS1_MAGIC_SWAPPED) {
1139*0a6a1f1dSLionel Sambuc fs_sbsize = bswap32(fs->fs_sbsize);
1140d65f6f70SBen Gras fstype = UFS1;
1141d65f6f70SBen Gras needswap = 1;
1142d65f6f70SBen Gras #endif
1143d65f6f70SBen Gras } else if (fs->fs_magic == FS_UFS2_MAGIC) {
1144*0a6a1f1dSLionel Sambuc fs_sbsize = fs->fs_sbsize;
1145d65f6f70SBen Gras fstype = UFS2;
1146d65f6f70SBen Gras #ifdef FFS_EI
1147d65f6f70SBen Gras needswap = 0;
114884d9c625SLionel Sambuc } else if (fs->fs_magic == FS_UFS2_MAGIC_SWAPPED) {
1149*0a6a1f1dSLionel Sambuc fs_sbsize = bswap32(fs->fs_sbsize);
1150d65f6f70SBen Gras fstype = UFS2;
1151d65f6f70SBen Gras needswap = 1;
1152d65f6f70SBen Gras #endif
1153d65f6f70SBen Gras } else
1154d65f6f70SBen Gras continue;
1155d65f6f70SBen Gras
1156d65f6f70SBen Gras /* fs->fs_sblockloc isn't defined for old filesystems */
1157d65f6f70SBen Gras if (fstype == UFS1 && !(fs->fs_old_flags & FS_FLAGS_UPDATED)) {
1158d65f6f70SBen Gras if (sblockloc == SBLOCK_UFS2)
1159d65f6f70SBen Gras /*
1160d65f6f70SBen Gras * This is likely to be the first alternate
1161d65f6f70SBen Gras * in a filesystem with 64k blocks.
1162d65f6f70SBen Gras * Don't use it.
1163d65f6f70SBen Gras */
1164d65f6f70SBen Gras continue;
1165*0a6a1f1dSLionel Sambuc fs_sblockloc = sblockloc;
1166d65f6f70SBen Gras } else {
1167*0a6a1f1dSLionel Sambuc fs_sblockloc = fs->fs_sblockloc;
1168d65f6f70SBen Gras #ifdef FFS_EI
1169d65f6f70SBen Gras if (needswap)
1170*0a6a1f1dSLionel Sambuc fs_sblockloc = bswap64(fs_sblockloc);
1171d65f6f70SBen Gras #endif
1172d65f6f70SBen Gras }
1173d65f6f70SBen Gras
1174d65f6f70SBen Gras /* Check we haven't found an alternate superblock */
1175*0a6a1f1dSLionel Sambuc if (fs_sblockloc != sblockloc)
1176d65f6f70SBen Gras continue;
1177d65f6f70SBen Gras
1178*0a6a1f1dSLionel Sambuc /* Check the superblock size */
1179*0a6a1f1dSLionel Sambuc if (fs_sbsize > SBLOCKSIZE || fs_sbsize < sizeof(struct fs))
1180d65f6f70SBen Gras continue;
1181*0a6a1f1dSLionel Sambuc fs = kmem_alloc((u_long)fs_sbsize, KM_SLEEP);
1182*0a6a1f1dSLionel Sambuc memcpy(fs, bp->b_data, fs_sbsize);
1183d65f6f70SBen Gras
1184*0a6a1f1dSLionel Sambuc /* Swap the whole superblock structure, if necessary. */
1185d65f6f70SBen Gras #ifdef FFS_EI
1186d65f6f70SBen Gras if (needswap) {
1187d65f6f70SBen Gras ffs_sb_swap((struct fs*)bp->b_data, fs);
1188d65f6f70SBen Gras fs->fs_flags |= FS_SWAPPED;
1189d65f6f70SBen Gras } else
1190d65f6f70SBen Gras #endif
1191d65f6f70SBen Gras fs->fs_flags &= ~FS_SWAPPED;
1192d65f6f70SBen Gras
1193*0a6a1f1dSLionel Sambuc /*
1194*0a6a1f1dSLionel Sambuc * Now that everything is swapped, the superblock is ready to
1195*0a6a1f1dSLionel Sambuc * be sanitized.
1196*0a6a1f1dSLionel Sambuc */
1197*0a6a1f1dSLionel Sambuc if (!ffs_superblock_validate(fs)) {
1198*0a6a1f1dSLionel Sambuc kmem_free(fs, fs_sbsize);
1199*0a6a1f1dSLionel Sambuc continue;
1200*0a6a1f1dSLionel Sambuc }
1201*0a6a1f1dSLionel Sambuc
1202*0a6a1f1dSLionel Sambuc /* Ok seems to be a good superblock */
1203*0a6a1f1dSLionel Sambuc break;
1204*0a6a1f1dSLionel Sambuc }
1205*0a6a1f1dSLionel Sambuc
1206*0a6a1f1dSLionel Sambuc ump->um_fs = fs;
1207*0a6a1f1dSLionel Sambuc
1208d65f6f70SBen Gras #ifdef WAPBL
1209d65f6f70SBen Gras if ((mp->mnt_wapbl_replay == 0) && (fs->fs_flags & FS_DOWAPBL)) {
1210d65f6f70SBen Gras error = ffs_wapbl_replay_start(mp, fs, devvp);
1211*0a6a1f1dSLionel Sambuc if (error && (mp->mnt_flag & MNT_FORCE) == 0) {
1212*0a6a1f1dSLionel Sambuc DPRINTF("ffs_wapbl_replay_start returned %d", error);
1213d65f6f70SBen Gras goto out;
1214*0a6a1f1dSLionel Sambuc }
1215d65f6f70SBen Gras if (!error) {
1216d65f6f70SBen Gras if (!ronly) {
1217d65f6f70SBen Gras /* XXX fsmnt may be stale. */
1218d65f6f70SBen Gras printf("%s: replaying log to disk\n",
1219d65f6f70SBen Gras fs->fs_fsmnt);
1220d65f6f70SBen Gras error = wapbl_replay_write(mp->mnt_wapbl_replay,
1221d65f6f70SBen Gras devvp);
1222*0a6a1f1dSLionel Sambuc if (error) {
1223*0a6a1f1dSLionel Sambuc DPRINTF("wapbl_replay_write returned %d",
1224*0a6a1f1dSLionel Sambuc error);
1225d65f6f70SBen Gras goto out;
1226*0a6a1f1dSLionel Sambuc }
1227d65f6f70SBen Gras wapbl_replay_stop(mp->mnt_wapbl_replay);
1228d65f6f70SBen Gras fs->fs_clean = FS_WASCLEAN;
1229d65f6f70SBen Gras } else {
1230d65f6f70SBen Gras /* XXX fsmnt may be stale */
1231d65f6f70SBen Gras printf("%s: replaying log to memory\n",
1232d65f6f70SBen Gras fs->fs_fsmnt);
1233d65f6f70SBen Gras }
1234d65f6f70SBen Gras
1235d65f6f70SBen Gras /* Force a re-read of the superblock */
1236d65f6f70SBen Gras brelse(bp, BC_INVAL);
1237d65f6f70SBen Gras bp = NULL;
1238*0a6a1f1dSLionel Sambuc kmem_free(fs, fs_sbsize);
1239d65f6f70SBen Gras fs = NULL;
1240d65f6f70SBen Gras goto sbagain;
1241d65f6f70SBen Gras }
1242d65f6f70SBen Gras }
1243d65f6f70SBen Gras #else /* !WAPBL */
1244d65f6f70SBen Gras if ((fs->fs_flags & FS_DOWAPBL) && (mp->mnt_flag & MNT_FORCE) == 0) {
1245d65f6f70SBen Gras error = EPERM;
1246*0a6a1f1dSLionel Sambuc DPRINTF("no force %d", error);
1247d65f6f70SBen Gras goto out;
1248d65f6f70SBen Gras }
1249d65f6f70SBen Gras #endif /* !WAPBL */
1250d65f6f70SBen Gras
1251d65f6f70SBen Gras ffs_oldfscompat_read(fs, ump, sblockloc);
1252d65f6f70SBen Gras ump->um_maxfilesize = fs->fs_maxfilesize;
1253d65f6f70SBen Gras
1254d65f6f70SBen Gras if (fs->fs_flags & ~(FS_KNOWN_FLAGS | FS_INTERNAL)) {
1255d65f6f70SBen Gras uprintf("%s: unknown ufs flags: 0x%08"PRIx32"%s\n",
1256d65f6f70SBen Gras mp->mnt_stat.f_mntonname, fs->fs_flags,
1257d65f6f70SBen Gras (mp->mnt_flag & MNT_FORCE) ? "" : ", not mounting");
1258d65f6f70SBen Gras if ((mp->mnt_flag & MNT_FORCE) == 0) {
1259d65f6f70SBen Gras error = EINVAL;
1260*0a6a1f1dSLionel Sambuc DPRINTF("no force %d", error);
1261d65f6f70SBen Gras goto out;
1262d65f6f70SBen Gras }
1263d65f6f70SBen Gras }
1264d65f6f70SBen Gras
1265d65f6f70SBen Gras if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
1266d65f6f70SBen Gras fs->fs_pendingblocks = 0;
1267d65f6f70SBen Gras fs->fs_pendinginodes = 0;
1268d65f6f70SBen Gras }
1269d65f6f70SBen Gras
1270d65f6f70SBen Gras ump->um_fstype = fstype;
1271d65f6f70SBen Gras if (fs->fs_sbsize < SBLOCKSIZE)
1272d65f6f70SBen Gras brelse(bp, BC_INVAL);
1273d65f6f70SBen Gras else
1274d65f6f70SBen Gras brelse(bp, 0);
1275d65f6f70SBen Gras bp = NULL;
1276d65f6f70SBen Gras
1277*0a6a1f1dSLionel Sambuc if (ffs_is_appleufs(devvp, fs)) {
1278d65f6f70SBen Gras #ifdef APPLE_UFS
1279d65f6f70SBen Gras ump->um_flags |= UFS_ISAPPLEUFS;
1280d65f6f70SBen Gras #else
1281*0a6a1f1dSLionel Sambuc DPRINTF("AppleUFS not supported");
1282d65f6f70SBen Gras error = EINVAL;
1283d65f6f70SBen Gras goto out;
1284d65f6f70SBen Gras #endif
1285*0a6a1f1dSLionel Sambuc }
1286d65f6f70SBen Gras
1287d65f6f70SBen Gras #if 0
1288d65f6f70SBen Gras /*
1289d65f6f70SBen Gras * XXX This code changes the behaviour of mounting dirty filesystems, to
1290d65f6f70SBen Gras * XXX require "mount -f ..." to mount them. This doesn't match what
1291d65f6f70SBen Gras * XXX mount(8) describes and is disabled for now.
1292d65f6f70SBen Gras */
1293d65f6f70SBen Gras /*
1294d65f6f70SBen Gras * If the file system is not clean, don't allow it to be mounted
1295d65f6f70SBen Gras * unless MNT_FORCE is specified. (Note: MNT_FORCE is always set
1296d65f6f70SBen Gras * for the root file system.)
1297d65f6f70SBen Gras */
1298d65f6f70SBen Gras if (fs->fs_flags & FS_DOWAPBL) {
1299d65f6f70SBen Gras /*
1300d65f6f70SBen Gras * wapbl normally expects to be FS_WASCLEAN when the FS_DOWAPBL
1301d65f6f70SBen Gras * bit is set, although there's a window in unmount where it
1302d65f6f70SBen Gras * could be FS_ISCLEAN
1303d65f6f70SBen Gras */
1304d65f6f70SBen Gras if ((mp->mnt_flag & MNT_FORCE) == 0 &&
1305d65f6f70SBen Gras (fs->fs_clean & (FS_WASCLEAN | FS_ISCLEAN)) == 0) {
1306d65f6f70SBen Gras error = EPERM;
1307d65f6f70SBen Gras goto out;
1308d65f6f70SBen Gras }
1309d65f6f70SBen Gras } else
1310d65f6f70SBen Gras if ((fs->fs_clean & FS_ISCLEAN) == 0 &&
1311d65f6f70SBen Gras (mp->mnt_flag & MNT_FORCE) == 0) {
1312d65f6f70SBen Gras error = EPERM;
1313d65f6f70SBen Gras goto out;
1314d65f6f70SBen Gras }
1315d65f6f70SBen Gras #endif
1316d65f6f70SBen Gras
1317d65f6f70SBen Gras /*
1318*0a6a1f1dSLionel Sambuc * Verify that we can access the last block in the fs
1319d65f6f70SBen Gras * if we're mounting read/write.
1320d65f6f70SBen Gras */
1321d65f6f70SBen Gras if (!ronly) {
1322*0a6a1f1dSLionel Sambuc error = bread(devvp, FFS_FSBTODB(fs, fs->fs_size - 1),
1323*0a6a1f1dSLionel Sambuc fs->fs_fsize, 0, &bp);
1324d65f6f70SBen Gras if (error) {
1325*0a6a1f1dSLionel Sambuc DPRINTF("bread@0x%jx returned %d",
1326*0a6a1f1dSLionel Sambuc (intmax_t)FFS_FSBTODB(fs, fs->fs_size - 1),
1327*0a6a1f1dSLionel Sambuc error);
1328*0a6a1f1dSLionel Sambuc bset = BC_INVAL;
1329*0a6a1f1dSLionel Sambuc goto out;
1330*0a6a1f1dSLionel Sambuc }
1331*0a6a1f1dSLionel Sambuc if (bp->b_bcount != fs->fs_fsize) {
1332*0a6a1f1dSLionel Sambuc DPRINTF("bcount %x != fsize %x", bp->b_bcount,
1333*0a6a1f1dSLionel Sambuc fs->fs_fsize);
1334*0a6a1f1dSLionel Sambuc error = EINVAL;
1335d65f6f70SBen Gras bset = BC_INVAL;
1336d65f6f70SBen Gras goto out;
1337d65f6f70SBen Gras }
1338d65f6f70SBen Gras brelse(bp, BC_INVAL);
1339d65f6f70SBen Gras bp = NULL;
1340d65f6f70SBen Gras }
1341d65f6f70SBen Gras
1342d65f6f70SBen Gras fs->fs_ronly = ronly;
1343d65f6f70SBen Gras /* Don't bump fs_clean if we're replaying journal */
1344*0a6a1f1dSLionel Sambuc if (!((fs->fs_flags & FS_DOWAPBL) && (fs->fs_clean & FS_WASCLEAN))) {
1345d65f6f70SBen Gras if (ronly == 0) {
1346d65f6f70SBen Gras fs->fs_clean <<= 1;
1347d65f6f70SBen Gras fs->fs_fmod = 1;
1348d65f6f70SBen Gras }
1349*0a6a1f1dSLionel Sambuc }
1350*0a6a1f1dSLionel Sambuc
1351d65f6f70SBen Gras bsize = fs->fs_cssize;
1352d65f6f70SBen Gras blks = howmany(bsize, fs->fs_fsize);
1353d65f6f70SBen Gras if (fs->fs_contigsumsize > 0)
1354d65f6f70SBen Gras bsize += fs->fs_ncg * sizeof(int32_t);
1355d65f6f70SBen Gras bsize += fs->fs_ncg * sizeof(*fs->fs_contigdirs);
135684d9c625SLionel Sambuc allocsbsize = bsize;
135784d9c625SLionel Sambuc space = kmem_alloc((u_long)allocsbsize, KM_SLEEP);
1358d65f6f70SBen Gras fs->fs_csp = space;
1359*0a6a1f1dSLionel Sambuc
1360d65f6f70SBen Gras for (i = 0; i < blks; i += fs->fs_frag) {
1361d65f6f70SBen Gras bsize = fs->fs_bsize;
1362d65f6f70SBen Gras if (i + fs->fs_frag > blks)
1363d65f6f70SBen Gras bsize = (blks - i) * fs->fs_fsize;
136484d9c625SLionel Sambuc error = bread(devvp, FFS_FSBTODB(fs, fs->fs_csaddr + i), bsize,
1365*0a6a1f1dSLionel Sambuc 0, &bp);
1366d65f6f70SBen Gras if (error) {
1367*0a6a1f1dSLionel Sambuc DPRINTF("bread@0x%jx %d",
1368*0a6a1f1dSLionel Sambuc (intmax_t)FFS_FSBTODB(fs, fs->fs_csaddr + i),
1369*0a6a1f1dSLionel Sambuc error);
1370*0a6a1f1dSLionel Sambuc goto out1;
1371d65f6f70SBen Gras }
1372d65f6f70SBen Gras #ifdef FFS_EI
1373d65f6f70SBen Gras if (needswap)
1374d65f6f70SBen Gras ffs_csum_swap((struct csum *)bp->b_data,
1375d65f6f70SBen Gras (struct csum *)space, bsize);
1376d65f6f70SBen Gras else
1377d65f6f70SBen Gras #endif
1378d65f6f70SBen Gras memcpy(space, bp->b_data, (u_int)bsize);
1379d65f6f70SBen Gras
1380d65f6f70SBen Gras space = (char *)space + bsize;
1381d65f6f70SBen Gras brelse(bp, 0);
1382d65f6f70SBen Gras bp = NULL;
1383d65f6f70SBen Gras }
1384d65f6f70SBen Gras if (fs->fs_contigsumsize > 0) {
1385d65f6f70SBen Gras fs->fs_maxcluster = lp = space;
1386d65f6f70SBen Gras for (i = 0; i < fs->fs_ncg; i++)
1387d65f6f70SBen Gras *lp++ = fs->fs_contigsumsize;
1388d65f6f70SBen Gras space = lp;
1389d65f6f70SBen Gras }
1390d65f6f70SBen Gras bsize = fs->fs_ncg * sizeof(*fs->fs_contigdirs);
1391d65f6f70SBen Gras fs->fs_contigdirs = space;
1392d65f6f70SBen Gras space = (char *)space + bsize;
1393d65f6f70SBen Gras memset(fs->fs_contigdirs, 0, bsize);
1394*0a6a1f1dSLionel Sambuc
1395d65f6f70SBen Gras /* Compatibility for old filesystems - XXX */
1396d65f6f70SBen Gras if (fs->fs_avgfilesize <= 0)
1397d65f6f70SBen Gras fs->fs_avgfilesize = AVFILESIZ;
1398d65f6f70SBen Gras if (fs->fs_avgfpdir <= 0)
1399d65f6f70SBen Gras fs->fs_avgfpdir = AFPDIR;
1400d65f6f70SBen Gras fs->fs_active = NULL;
1401*0a6a1f1dSLionel Sambuc
1402d65f6f70SBen Gras mp->mnt_data = ump;
1403d65f6f70SBen Gras mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)dev;
1404d65f6f70SBen Gras mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_FFS);
1405d65f6f70SBen Gras mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
1406d65f6f70SBen Gras mp->mnt_stat.f_namemax = FFS_MAXNAMLEN;
1407d65f6f70SBen Gras if (UFS_MPISAPPLEUFS(ump)) {
1408d65f6f70SBen Gras /* NeXT used to keep short symlinks in the inode even
1409d65f6f70SBen Gras * when using FS_42INODEFMT. In that case fs->fs_maxsymlinklen
1410d65f6f70SBen Gras * is probably -1, but we still need to be able to identify
1411d65f6f70SBen Gras * short symlinks.
1412d65f6f70SBen Gras */
1413d65f6f70SBen Gras ump->um_maxsymlinklen = APPLEUFS_MAXSYMLINKLEN;
1414d65f6f70SBen Gras ump->um_dirblksiz = APPLEUFS_DIRBLKSIZ;
1415d65f6f70SBen Gras mp->mnt_iflag |= IMNT_DTYPE;
1416d65f6f70SBen Gras } else {
1417d65f6f70SBen Gras ump->um_maxsymlinklen = fs->fs_maxsymlinklen;
141884d9c625SLionel Sambuc ump->um_dirblksiz = UFS_DIRBLKSIZ;
1419d65f6f70SBen Gras if (ump->um_maxsymlinklen > 0)
1420d65f6f70SBen Gras mp->mnt_iflag |= IMNT_DTYPE;
1421d65f6f70SBen Gras else
1422d65f6f70SBen Gras mp->mnt_iflag &= ~IMNT_DTYPE;
1423d65f6f70SBen Gras }
1424d65f6f70SBen Gras mp->mnt_fs_bshift = fs->fs_bshift;
1425d65f6f70SBen Gras mp->mnt_dev_bshift = DEV_BSHIFT; /* XXX */
1426d65f6f70SBen Gras mp->mnt_flag |= MNT_LOCAL;
1427d65f6f70SBen Gras mp->mnt_iflag |= IMNT_MPSAFE;
1428d65f6f70SBen Gras #ifdef FFS_EI
1429d65f6f70SBen Gras if (needswap)
1430d65f6f70SBen Gras ump->um_flags |= UFS_NEEDSWAP;
1431d65f6f70SBen Gras #endif
1432d65f6f70SBen Gras ump->um_mountp = mp;
1433d65f6f70SBen Gras ump->um_dev = dev;
1434d65f6f70SBen Gras ump->um_devvp = devvp;
1435d65f6f70SBen Gras ump->um_nindir = fs->fs_nindir;
1436d65f6f70SBen Gras ump->um_lognindir = ffs(fs->fs_nindir) - 1;
1437d65f6f70SBen Gras ump->um_bptrtodb = fs->fs_fshift - DEV_BSHIFT;
1438d65f6f70SBen Gras ump->um_seqinc = fs->fs_frag;
1439d65f6f70SBen Gras for (i = 0; i < MAXQUOTAS; i++)
1440d65f6f70SBen Gras ump->um_quotas[i] = NULLVP;
144184d9c625SLionel Sambuc spec_node_setmountedfs(devvp, mp);
1442d65f6f70SBen Gras if (ronly == 0 && fs->fs_snapinum[0] != 0)
1443d65f6f70SBen Gras ffs_snapshot_mount(mp);
1444d65f6f70SBen Gras #ifdef WAPBL
1445d65f6f70SBen Gras if (!ronly) {
1446d65f6f70SBen Gras KDASSERT(fs->fs_ronly == 0);
1447d65f6f70SBen Gras /*
1448d65f6f70SBen Gras * ffs_wapbl_start() needs mp->mnt_stat initialised if it
1449d65f6f70SBen Gras * needs to create a new log file in-filesystem.
1450d65f6f70SBen Gras */
1451*0a6a1f1dSLionel Sambuc error = ffs_statvfs(mp, &mp->mnt_stat);
1452*0a6a1f1dSLionel Sambuc if (error) {
1453*0a6a1f1dSLionel Sambuc DPRINTF("ffs_statvfs returned %d", error);
1454*0a6a1f1dSLionel Sambuc goto out1;
1455*0a6a1f1dSLionel Sambuc }
1456d65f6f70SBen Gras
1457d65f6f70SBen Gras error = ffs_wapbl_start(mp);
1458d65f6f70SBen Gras if (error) {
1459*0a6a1f1dSLionel Sambuc DPRINTF("ffs_wapbl_start returned %d", error);
1460*0a6a1f1dSLionel Sambuc goto out1;
1461d65f6f70SBen Gras }
1462d65f6f70SBen Gras }
1463d65f6f70SBen Gras #endif /* WAPBL */
1464d65f6f70SBen Gras if (ronly == 0) {
1465d65f6f70SBen Gras #ifdef QUOTA2
1466d65f6f70SBen Gras error = ffs_quota2_mount(mp);
1467d65f6f70SBen Gras if (error) {
1468*0a6a1f1dSLionel Sambuc DPRINTF("ffs_quota2_mount returned %d", error);
1469*0a6a1f1dSLionel Sambuc goto out1;
1470d65f6f70SBen Gras }
1471d65f6f70SBen Gras #else
1472d65f6f70SBen Gras if (fs->fs_flags & FS_DOQUOTA2) {
1473d65f6f70SBen Gras ump->um_flags |= UFS_QUOTA2;
1474d65f6f70SBen Gras uprintf("%s: options QUOTA2 not enabled%s\n",
1475d65f6f70SBen Gras mp->mnt_stat.f_mntonname,
1476d65f6f70SBen Gras (mp->mnt_flag & MNT_FORCE) ? "" : ", not mounting");
1477d65f6f70SBen Gras if ((mp->mnt_flag & MNT_FORCE) == 0) {
1478d65f6f70SBen Gras error = EINVAL;
1479*0a6a1f1dSLionel Sambuc DPRINTF("quota disabled %d", error);
1480*0a6a1f1dSLionel Sambuc goto out1;
1481d65f6f70SBen Gras }
1482d65f6f70SBen Gras }
1483d65f6f70SBen Gras #endif
1484d65f6f70SBen Gras }
1485d65f6f70SBen Gras
148684d9c625SLionel Sambuc if (mp->mnt_flag & MNT_DISCARD)
148784d9c625SLionel Sambuc ump->um_discarddata = ffs_discard_init(devvp, fs);
148884d9c625SLionel Sambuc
1489d65f6f70SBen Gras return (0);
1490*0a6a1f1dSLionel Sambuc out1:
1491*0a6a1f1dSLionel Sambuc kmem_free(fs->fs_csp, allocsbsize);
1492d65f6f70SBen Gras out:
1493d65f6f70SBen Gras #ifdef WAPBL
1494d65f6f70SBen Gras if (mp->mnt_wapbl_replay) {
1495d65f6f70SBen Gras wapbl_replay_stop(mp->mnt_wapbl_replay);
1496d65f6f70SBen Gras wapbl_replay_free(mp->mnt_wapbl_replay);
1497d65f6f70SBen Gras mp->mnt_wapbl_replay = 0;
1498d65f6f70SBen Gras }
1499d65f6f70SBen Gras #endif
1500d65f6f70SBen Gras
1501d65f6f70SBen Gras fstrans_unmount(mp);
1502d65f6f70SBen Gras if (fs)
150384d9c625SLionel Sambuc kmem_free(fs, fs->fs_sbsize);
150484d9c625SLionel Sambuc spec_node_setmountedfs(devvp, NULL);
1505d65f6f70SBen Gras if (bp)
1506d65f6f70SBen Gras brelse(bp, bset);
1507d65f6f70SBen Gras if (ump) {
1508d65f6f70SBen Gras if (ump->um_oldfscompat)
150984d9c625SLionel Sambuc kmem_free(ump->um_oldfscompat, 512 + 3*sizeof(int32_t));
1510d65f6f70SBen Gras mutex_destroy(&ump->um_lock);
151184d9c625SLionel Sambuc kmem_free(ump, sizeof(*ump));
1512d65f6f70SBen Gras mp->mnt_data = NULL;
1513d65f6f70SBen Gras }
1514d65f6f70SBen Gras return (error);
1515d65f6f70SBen Gras }
1516d65f6f70SBen Gras
1517d65f6f70SBen Gras /*
1518d65f6f70SBen Gras * Sanity checks for loading old filesystem superblocks.
1519d65f6f70SBen Gras * See ffs_oldfscompat_write below for unwound actions.
1520d65f6f70SBen Gras *
1521d65f6f70SBen Gras * XXX - Parts get retired eventually.
1522d65f6f70SBen Gras * Unfortunately new bits get added.
1523d65f6f70SBen Gras */
1524d65f6f70SBen Gras static void
ffs_oldfscompat_read(struct fs * fs,struct ufsmount * ump,daddr_t sblockloc)1525d65f6f70SBen Gras ffs_oldfscompat_read(struct fs *fs, struct ufsmount *ump, daddr_t sblockloc)
1526d65f6f70SBen Gras {
1527d65f6f70SBen Gras off_t maxfilesize;
1528d65f6f70SBen Gras int32_t *extrasave;
1529d65f6f70SBen Gras
1530d65f6f70SBen Gras if ((fs->fs_magic != FS_UFS1_MAGIC) ||
1531d65f6f70SBen Gras (fs->fs_old_flags & FS_FLAGS_UPDATED))
1532d65f6f70SBen Gras return;
1533d65f6f70SBen Gras
1534d65f6f70SBen Gras if (!ump->um_oldfscompat)
153584d9c625SLionel Sambuc ump->um_oldfscompat = kmem_alloc(512 + 3*sizeof(int32_t),
153684d9c625SLionel Sambuc KM_SLEEP);
1537d65f6f70SBen Gras
1538d65f6f70SBen Gras memcpy(ump->um_oldfscompat, &fs->fs_old_postbl_start, 512);
1539d65f6f70SBen Gras extrasave = ump->um_oldfscompat;
1540d65f6f70SBen Gras extrasave += 512/sizeof(int32_t);
1541d65f6f70SBen Gras extrasave[0] = fs->fs_old_npsect;
1542d65f6f70SBen Gras extrasave[1] = fs->fs_old_interleave;
1543d65f6f70SBen Gras extrasave[2] = fs->fs_old_trackskew;
1544d65f6f70SBen Gras
1545d65f6f70SBen Gras /* These fields will be overwritten by their
1546d65f6f70SBen Gras * original values in fs_oldfscompat_write, so it is harmless
1547d65f6f70SBen Gras * to modify them here.
1548d65f6f70SBen Gras */
1549d65f6f70SBen Gras fs->fs_cstotal.cs_ndir = fs->fs_old_cstotal.cs_ndir;
1550d65f6f70SBen Gras fs->fs_cstotal.cs_nbfree = fs->fs_old_cstotal.cs_nbfree;
1551d65f6f70SBen Gras fs->fs_cstotal.cs_nifree = fs->fs_old_cstotal.cs_nifree;
1552d65f6f70SBen Gras fs->fs_cstotal.cs_nffree = fs->fs_old_cstotal.cs_nffree;
1553d65f6f70SBen Gras
1554d65f6f70SBen Gras fs->fs_maxbsize = fs->fs_bsize;
1555d65f6f70SBen Gras fs->fs_time = fs->fs_old_time;
1556d65f6f70SBen Gras fs->fs_size = fs->fs_old_size;
1557d65f6f70SBen Gras fs->fs_dsize = fs->fs_old_dsize;
1558d65f6f70SBen Gras fs->fs_csaddr = fs->fs_old_csaddr;
1559d65f6f70SBen Gras fs->fs_sblockloc = sblockloc;
1560d65f6f70SBen Gras
1561d65f6f70SBen Gras fs->fs_flags = fs->fs_old_flags | (fs->fs_flags & FS_INTERNAL);
1562d65f6f70SBen Gras
1563d65f6f70SBen Gras if (fs->fs_old_postblformat == FS_42POSTBLFMT) {
1564d65f6f70SBen Gras fs->fs_old_nrpos = 8;
1565d65f6f70SBen Gras fs->fs_old_npsect = fs->fs_old_nsect;
1566d65f6f70SBen Gras fs->fs_old_interleave = 1;
1567d65f6f70SBen Gras fs->fs_old_trackskew = 0;
1568d65f6f70SBen Gras }
1569d65f6f70SBen Gras
1570d65f6f70SBen Gras if (fs->fs_old_inodefmt < FS_44INODEFMT) {
1571d65f6f70SBen Gras fs->fs_maxfilesize = (u_quad_t) 1LL << 39;
1572d65f6f70SBen Gras fs->fs_qbmask = ~fs->fs_bmask;
1573d65f6f70SBen Gras fs->fs_qfmask = ~fs->fs_fmask;
1574d65f6f70SBen Gras }
1575d65f6f70SBen Gras
1576d65f6f70SBen Gras maxfilesize = (u_int64_t)0x80000000 * fs->fs_bsize - 1;
1577d65f6f70SBen Gras if (fs->fs_maxfilesize > maxfilesize)
1578d65f6f70SBen Gras fs->fs_maxfilesize = maxfilesize;
1579d65f6f70SBen Gras
1580d65f6f70SBen Gras /* Compatibility for old filesystems */
1581d65f6f70SBen Gras if (fs->fs_avgfilesize <= 0)
1582d65f6f70SBen Gras fs->fs_avgfilesize = AVFILESIZ;
1583d65f6f70SBen Gras if (fs->fs_avgfpdir <= 0)
1584d65f6f70SBen Gras fs->fs_avgfpdir = AFPDIR;
1585d65f6f70SBen Gras
1586d65f6f70SBen Gras #if 0
1587d65f6f70SBen Gras if (bigcgs) {
1588d65f6f70SBen Gras fs->fs_save_cgsize = fs->fs_cgsize;
1589d65f6f70SBen Gras fs->fs_cgsize = fs->fs_bsize;
1590d65f6f70SBen Gras }
1591d65f6f70SBen Gras #endif
1592d65f6f70SBen Gras }
1593d65f6f70SBen Gras
1594d65f6f70SBen Gras /*
1595d65f6f70SBen Gras * Unwinding superblock updates for old filesystems.
1596d65f6f70SBen Gras * See ffs_oldfscompat_read above for details.
1597d65f6f70SBen Gras *
1598d65f6f70SBen Gras * XXX - Parts get retired eventually.
1599d65f6f70SBen Gras * Unfortunately new bits get added.
1600d65f6f70SBen Gras */
1601d65f6f70SBen Gras static void
ffs_oldfscompat_write(struct fs * fs,struct ufsmount * ump)1602d65f6f70SBen Gras ffs_oldfscompat_write(struct fs *fs, struct ufsmount *ump)
1603d65f6f70SBen Gras {
1604d65f6f70SBen Gras int32_t *extrasave;
1605d65f6f70SBen Gras
1606d65f6f70SBen Gras if ((fs->fs_magic != FS_UFS1_MAGIC) ||
1607d65f6f70SBen Gras (fs->fs_old_flags & FS_FLAGS_UPDATED))
1608d65f6f70SBen Gras return;
1609d65f6f70SBen Gras
1610d65f6f70SBen Gras fs->fs_old_time = fs->fs_time;
1611d65f6f70SBen Gras fs->fs_old_cstotal.cs_ndir = fs->fs_cstotal.cs_ndir;
1612d65f6f70SBen Gras fs->fs_old_cstotal.cs_nbfree = fs->fs_cstotal.cs_nbfree;
1613d65f6f70SBen Gras fs->fs_old_cstotal.cs_nifree = fs->fs_cstotal.cs_nifree;
1614d65f6f70SBen Gras fs->fs_old_cstotal.cs_nffree = fs->fs_cstotal.cs_nffree;
1615d65f6f70SBen Gras fs->fs_old_flags = fs->fs_flags;
1616d65f6f70SBen Gras
1617d65f6f70SBen Gras #if 0
1618d65f6f70SBen Gras if (bigcgs) {
1619d65f6f70SBen Gras fs->fs_cgsize = fs->fs_save_cgsize;
1620d65f6f70SBen Gras }
1621d65f6f70SBen Gras #endif
1622d65f6f70SBen Gras
1623d65f6f70SBen Gras memcpy(&fs->fs_old_postbl_start, ump->um_oldfscompat, 512);
1624d65f6f70SBen Gras extrasave = ump->um_oldfscompat;
1625d65f6f70SBen Gras extrasave += 512/sizeof(int32_t);
1626d65f6f70SBen Gras fs->fs_old_npsect = extrasave[0];
1627d65f6f70SBen Gras fs->fs_old_interleave = extrasave[1];
1628d65f6f70SBen Gras fs->fs_old_trackskew = extrasave[2];
1629d65f6f70SBen Gras
1630d65f6f70SBen Gras }
1631d65f6f70SBen Gras
1632d65f6f70SBen Gras /*
1633d65f6f70SBen Gras * unmount vfs operation
1634d65f6f70SBen Gras */
1635d65f6f70SBen Gras int
ffs_unmount(struct mount * mp,int mntflags)1636d65f6f70SBen Gras ffs_unmount(struct mount *mp, int mntflags)
1637d65f6f70SBen Gras {
1638d65f6f70SBen Gras struct lwp *l = curlwp;
1639d65f6f70SBen Gras struct ufsmount *ump = VFSTOUFS(mp);
1640d65f6f70SBen Gras struct fs *fs = ump->um_fs;
1641d65f6f70SBen Gras int error, flags;
164284d9c625SLionel Sambuc u_int32_t bsize;
1643d65f6f70SBen Gras #ifdef WAPBL
1644d65f6f70SBen Gras extern int doforce;
1645d65f6f70SBen Gras #endif
1646d65f6f70SBen Gras
164784d9c625SLionel Sambuc if (ump->um_discarddata) {
164884d9c625SLionel Sambuc ffs_discard_finish(ump->um_discarddata, mntflags);
164984d9c625SLionel Sambuc ump->um_discarddata = NULL;
165084d9c625SLionel Sambuc }
165184d9c625SLionel Sambuc
1652d65f6f70SBen Gras flags = 0;
1653d65f6f70SBen Gras if (mntflags & MNT_FORCE)
1654d65f6f70SBen Gras flags |= FORCECLOSE;
1655d65f6f70SBen Gras if ((error = ffs_flushfiles(mp, flags, l)) != 0)
1656d65f6f70SBen Gras return (error);
1657d65f6f70SBen Gras error = UFS_WAPBL_BEGIN(mp);
1658d65f6f70SBen Gras if (error == 0)
1659d65f6f70SBen Gras if (fs->fs_ronly == 0 &&
1660d65f6f70SBen Gras ffs_cgupdate(ump, MNT_WAIT) == 0 &&
1661d65f6f70SBen Gras fs->fs_clean & FS_WASCLEAN) {
1662d65f6f70SBen Gras fs->fs_clean = FS_ISCLEAN;
1663d65f6f70SBen Gras fs->fs_fmod = 0;
1664d65f6f70SBen Gras (void) ffs_sbupdate(ump, MNT_WAIT);
1665d65f6f70SBen Gras }
1666d65f6f70SBen Gras if (error == 0)
1667d65f6f70SBen Gras UFS_WAPBL_END(mp);
1668d65f6f70SBen Gras #ifdef WAPBL
1669d65f6f70SBen Gras KASSERT(!(mp->mnt_wapbl_replay && mp->mnt_wapbl));
1670d65f6f70SBen Gras if (mp->mnt_wapbl_replay) {
1671d65f6f70SBen Gras KDASSERT(fs->fs_ronly);
1672d65f6f70SBen Gras wapbl_replay_stop(mp->mnt_wapbl_replay);
1673d65f6f70SBen Gras wapbl_replay_free(mp->mnt_wapbl_replay);
1674d65f6f70SBen Gras mp->mnt_wapbl_replay = 0;
1675d65f6f70SBen Gras }
1676d65f6f70SBen Gras error = ffs_wapbl_stop(mp, doforce && (mntflags & MNT_FORCE));
1677d65f6f70SBen Gras if (error) {
1678d65f6f70SBen Gras return error;
1679d65f6f70SBen Gras }
1680d65f6f70SBen Gras #endif /* WAPBL */
1681d65f6f70SBen Gras
1682d65f6f70SBen Gras if (ump->um_devvp->v_type != VBAD)
168384d9c625SLionel Sambuc spec_node_setmountedfs(ump->um_devvp, NULL);
1684d65f6f70SBen Gras vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
1685d65f6f70SBen Gras (void)VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD | FWRITE,
1686d65f6f70SBen Gras NOCRED);
1687d65f6f70SBen Gras vput(ump->um_devvp);
168884d9c625SLionel Sambuc
168984d9c625SLionel Sambuc bsize = fs->fs_cssize;
169084d9c625SLionel Sambuc if (fs->fs_contigsumsize > 0)
169184d9c625SLionel Sambuc bsize += fs->fs_ncg * sizeof(int32_t);
169284d9c625SLionel Sambuc bsize += fs->fs_ncg * sizeof(*fs->fs_contigdirs);
169384d9c625SLionel Sambuc kmem_free(fs->fs_csp, bsize);
169484d9c625SLionel Sambuc
169584d9c625SLionel Sambuc kmem_free(fs, fs->fs_sbsize);
1696d65f6f70SBen Gras if (ump->um_oldfscompat != NULL)
169784d9c625SLionel Sambuc kmem_free(ump->um_oldfscompat, 512 + 3*sizeof(int32_t));
1698d65f6f70SBen Gras mutex_destroy(&ump->um_lock);
1699d65f6f70SBen Gras ffs_snapshot_fini(ump);
170084d9c625SLionel Sambuc kmem_free(ump, sizeof(*ump));
1701d65f6f70SBen Gras mp->mnt_data = NULL;
1702d65f6f70SBen Gras mp->mnt_flag &= ~MNT_LOCAL;
1703d65f6f70SBen Gras fstrans_unmount(mp);
1704d65f6f70SBen Gras return (0);
1705d65f6f70SBen Gras }
1706d65f6f70SBen Gras
1707d65f6f70SBen Gras /*
1708d65f6f70SBen Gras * Flush out all the files in a filesystem.
1709d65f6f70SBen Gras */
1710d65f6f70SBen Gras int
ffs_flushfiles(struct mount * mp,int flags,struct lwp * l)1711d65f6f70SBen Gras ffs_flushfiles(struct mount *mp, int flags, struct lwp *l)
1712d65f6f70SBen Gras {
1713d65f6f70SBen Gras extern int doforce;
1714d65f6f70SBen Gras struct ufsmount *ump;
1715d65f6f70SBen Gras int error;
1716d65f6f70SBen Gras
1717d65f6f70SBen Gras if (!doforce)
1718d65f6f70SBen Gras flags &= ~FORCECLOSE;
1719d65f6f70SBen Gras ump = VFSTOUFS(mp);
1720d65f6f70SBen Gras #ifdef QUOTA
1721d65f6f70SBen Gras if ((error = quota1_umount(mp, flags)) != 0)
1722d65f6f70SBen Gras return (error);
1723d65f6f70SBen Gras #endif
1724d65f6f70SBen Gras #ifdef QUOTA2
1725d65f6f70SBen Gras if ((error = quota2_umount(mp, flags)) != 0)
1726d65f6f70SBen Gras return (error);
1727d65f6f70SBen Gras #endif
172884d9c625SLionel Sambuc #ifdef UFS_EXTATTR
172984d9c625SLionel Sambuc if (ump->um_fstype == UFS1) {
173084d9c625SLionel Sambuc if (ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)
173184d9c625SLionel Sambuc ufs_extattr_stop(mp, l);
173284d9c625SLionel Sambuc if (ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED)
173384d9c625SLionel Sambuc ufs_extattr_uepm_destroy(&ump->um_extattr);
1734*0a6a1f1dSLionel Sambuc mp->mnt_flag &= ~MNT_EXTATTR;
173584d9c625SLionel Sambuc }
173684d9c625SLionel Sambuc #endif
1737d65f6f70SBen Gras if ((error = vflush(mp, 0, SKIPSYSTEM | flags)) != 0)
1738d65f6f70SBen Gras return (error);
1739d65f6f70SBen Gras ffs_snapshot_unmount(mp);
1740d65f6f70SBen Gras /*
1741d65f6f70SBen Gras * Flush all the files.
1742d65f6f70SBen Gras */
1743d65f6f70SBen Gras error = vflush(mp, NULLVP, flags);
1744d65f6f70SBen Gras if (error)
1745d65f6f70SBen Gras return (error);
1746d65f6f70SBen Gras /*
1747d65f6f70SBen Gras * Flush filesystem metadata.
1748d65f6f70SBen Gras */
1749d65f6f70SBen Gras vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
1750d65f6f70SBen Gras error = VOP_FSYNC(ump->um_devvp, l->l_cred, FSYNC_WAIT, 0, 0);
1751d65f6f70SBen Gras VOP_UNLOCK(ump->um_devvp);
1752d65f6f70SBen Gras if (flags & FORCECLOSE) /* XXXDBJ */
1753d65f6f70SBen Gras error = 0;
1754d65f6f70SBen Gras
1755d65f6f70SBen Gras #ifdef WAPBL
1756d65f6f70SBen Gras if (error)
1757d65f6f70SBen Gras return error;
1758d65f6f70SBen Gras if (mp->mnt_wapbl) {
1759d65f6f70SBen Gras error = wapbl_flush(mp->mnt_wapbl, 1);
1760d65f6f70SBen Gras if (flags & FORCECLOSE)
1761d65f6f70SBen Gras error = 0;
1762d65f6f70SBen Gras }
1763d65f6f70SBen Gras #endif
1764d65f6f70SBen Gras
1765d65f6f70SBen Gras return (error);
1766d65f6f70SBen Gras }
1767d65f6f70SBen Gras
1768d65f6f70SBen Gras /*
1769d65f6f70SBen Gras * Get file system statistics.
1770d65f6f70SBen Gras */
1771d65f6f70SBen Gras int
ffs_statvfs(struct mount * mp,struct statvfs * sbp)1772d65f6f70SBen Gras ffs_statvfs(struct mount *mp, struct statvfs *sbp)
1773d65f6f70SBen Gras {
1774d65f6f70SBen Gras struct ufsmount *ump;
1775d65f6f70SBen Gras struct fs *fs;
1776d65f6f70SBen Gras
1777d65f6f70SBen Gras ump = VFSTOUFS(mp);
1778d65f6f70SBen Gras fs = ump->um_fs;
1779d65f6f70SBen Gras mutex_enter(&ump->um_lock);
1780d65f6f70SBen Gras sbp->f_bsize = fs->fs_bsize;
1781d65f6f70SBen Gras sbp->f_frsize = fs->fs_fsize;
1782d65f6f70SBen Gras sbp->f_iosize = fs->fs_bsize;
1783d65f6f70SBen Gras sbp->f_blocks = fs->fs_dsize;
178484d9c625SLionel Sambuc sbp->f_bfree = ffs_blkstofrags(fs, fs->fs_cstotal.cs_nbfree) +
178584d9c625SLionel Sambuc fs->fs_cstotal.cs_nffree + FFS_DBTOFSB(fs, fs->fs_pendingblocks);
1786d65f6f70SBen Gras sbp->f_bresvd = ((u_int64_t) fs->fs_dsize * (u_int64_t)
1787d65f6f70SBen Gras fs->fs_minfree) / (u_int64_t) 100;
1788d65f6f70SBen Gras if (sbp->f_bfree > sbp->f_bresvd)
1789d65f6f70SBen Gras sbp->f_bavail = sbp->f_bfree - sbp->f_bresvd;
1790d65f6f70SBen Gras else
1791d65f6f70SBen Gras sbp->f_bavail = 0;
179284d9c625SLionel Sambuc sbp->f_files = fs->fs_ncg * fs->fs_ipg - UFS_ROOTINO;
1793d65f6f70SBen Gras sbp->f_ffree = fs->fs_cstotal.cs_nifree + fs->fs_pendinginodes;
1794d65f6f70SBen Gras sbp->f_favail = sbp->f_ffree;
1795d65f6f70SBen Gras sbp->f_fresvd = 0;
1796d65f6f70SBen Gras mutex_exit(&ump->um_lock);
1797d65f6f70SBen Gras copy_statvfs_info(sbp, mp);
1798d65f6f70SBen Gras
1799d65f6f70SBen Gras return (0);
1800d65f6f70SBen Gras }
1801d65f6f70SBen Gras
1802*0a6a1f1dSLionel Sambuc struct ffs_sync_ctx {
1803*0a6a1f1dSLionel Sambuc int waitfor;
1804d65f6f70SBen Gras bool is_suspending;
1805*0a6a1f1dSLionel Sambuc };
1806d65f6f70SBen Gras
1807*0a6a1f1dSLionel Sambuc static bool
ffs_sync_selector(void * cl,struct vnode * vp)1808*0a6a1f1dSLionel Sambuc ffs_sync_selector(void *cl, struct vnode *vp)
1809*0a6a1f1dSLionel Sambuc {
1810*0a6a1f1dSLionel Sambuc struct ffs_sync_ctx *c = cl;
1811*0a6a1f1dSLionel Sambuc struct inode *ip;
1812d65f6f70SBen Gras
1813d65f6f70SBen Gras ip = VTOI(vp);
1814d65f6f70SBen Gras /*
1815d65f6f70SBen Gras * Skip the vnode/inode if inaccessible.
1816d65f6f70SBen Gras */
1817*0a6a1f1dSLionel Sambuc if (ip == NULL || vp->v_type == VNON)
1818*0a6a1f1dSLionel Sambuc return false;
1819d65f6f70SBen Gras
1820d65f6f70SBen Gras /*
1821d65f6f70SBen Gras * We deliberately update inode times here. This will
1822d65f6f70SBen Gras * prevent a massive queue of updates accumulating, only
1823d65f6f70SBen Gras * to be handled by a call to unmount.
1824d65f6f70SBen Gras *
1825d65f6f70SBen Gras * XXX It would be better to have the syncer trickle these
1826d65f6f70SBen Gras * out. Adjustment needed to allow registering vnodes for
1827d65f6f70SBen Gras * sync when the vnode is clean, but the inode dirty. Or
1828d65f6f70SBen Gras * have ufs itself trickle out inode updates.
1829d65f6f70SBen Gras *
1830d65f6f70SBen Gras * If doing a lazy sync, we don't care about metadata or
1831d65f6f70SBen Gras * data updates, because they are handled by each vnode's
1832d65f6f70SBen Gras * synclist entry. In this case we are only interested in
1833d65f6f70SBen Gras * writing back modified inodes.
1834d65f6f70SBen Gras */
1835d65f6f70SBen Gras if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE |
1836d65f6f70SBen Gras IN_MODIFY | IN_MODIFIED | IN_ACCESSED)) == 0 &&
1837*0a6a1f1dSLionel Sambuc (c->waitfor == MNT_LAZY || (LIST_EMPTY(&vp->v_dirtyblkhd) &&
1838*0a6a1f1dSLionel Sambuc UVM_OBJ_IS_CLEAN(&vp->v_uobj))))
1839*0a6a1f1dSLionel Sambuc return false;
1840*0a6a1f1dSLionel Sambuc
1841*0a6a1f1dSLionel Sambuc if (vp->v_type == VBLK && c->is_suspending)
1842*0a6a1f1dSLionel Sambuc return false;
1843*0a6a1f1dSLionel Sambuc
1844*0a6a1f1dSLionel Sambuc return true;
1845d65f6f70SBen Gras }
1846*0a6a1f1dSLionel Sambuc
1847*0a6a1f1dSLionel Sambuc /*
1848*0a6a1f1dSLionel Sambuc * Go through the disk queues to initiate sandbagged IO;
1849*0a6a1f1dSLionel Sambuc * go through the inodes to write those that have been modified;
1850*0a6a1f1dSLionel Sambuc * initiate the writing of the super block if it has been modified.
1851*0a6a1f1dSLionel Sambuc *
1852*0a6a1f1dSLionel Sambuc * Note: we are always called with the filesystem marked `MPBUSY'.
1853*0a6a1f1dSLionel Sambuc */
1854*0a6a1f1dSLionel Sambuc int
ffs_sync(struct mount * mp,int waitfor,kauth_cred_t cred)1855*0a6a1f1dSLionel Sambuc ffs_sync(struct mount *mp, int waitfor, kauth_cred_t cred)
1856*0a6a1f1dSLionel Sambuc {
1857*0a6a1f1dSLionel Sambuc struct vnode *vp;
1858*0a6a1f1dSLionel Sambuc struct ufsmount *ump = VFSTOUFS(mp);
1859*0a6a1f1dSLionel Sambuc struct fs *fs;
1860*0a6a1f1dSLionel Sambuc struct vnode_iterator *marker;
1861*0a6a1f1dSLionel Sambuc int error, allerror = 0;
1862*0a6a1f1dSLionel Sambuc bool is_suspending;
1863*0a6a1f1dSLionel Sambuc struct ffs_sync_ctx ctx;
1864*0a6a1f1dSLionel Sambuc
1865*0a6a1f1dSLionel Sambuc fs = ump->um_fs;
1866*0a6a1f1dSLionel Sambuc if (fs->fs_fmod != 0 && fs->fs_ronly != 0) { /* XXX */
1867*0a6a1f1dSLionel Sambuc printf("fs = %s\n", fs->fs_fsmnt);
1868*0a6a1f1dSLionel Sambuc panic("update: rofs mod");
1869d65f6f70SBen Gras }
1870*0a6a1f1dSLionel Sambuc
1871*0a6a1f1dSLionel Sambuc fstrans_start(mp, FSTRANS_SHARED);
1872*0a6a1f1dSLionel Sambuc is_suspending = (fstrans_getstate(mp) == FSTRANS_SUSPENDING);
1873*0a6a1f1dSLionel Sambuc /*
1874*0a6a1f1dSLionel Sambuc * Write back each (modified) inode.
1875*0a6a1f1dSLionel Sambuc */
1876*0a6a1f1dSLionel Sambuc vfs_vnode_iterator_init(mp, &marker);
1877*0a6a1f1dSLionel Sambuc
1878*0a6a1f1dSLionel Sambuc ctx.waitfor = waitfor;
1879*0a6a1f1dSLionel Sambuc ctx.is_suspending = is_suspending;
1880*0a6a1f1dSLionel Sambuc while ((vp = vfs_vnode_iterator_next(marker, ffs_sync_selector, &ctx)))
1881*0a6a1f1dSLionel Sambuc {
1882*0a6a1f1dSLionel Sambuc error = vn_lock(vp, LK_EXCLUSIVE);
1883d65f6f70SBen Gras if (error) {
1884*0a6a1f1dSLionel Sambuc vrele(vp);
1885d65f6f70SBen Gras continue;
1886d65f6f70SBen Gras }
1887d65f6f70SBen Gras if (waitfor == MNT_LAZY) {
1888d65f6f70SBen Gras error = UFS_WAPBL_BEGIN(vp->v_mount);
1889d65f6f70SBen Gras if (!error) {
1890d65f6f70SBen Gras error = ffs_update(vp, NULL, NULL,
1891d65f6f70SBen Gras UPDATE_CLOSE);
1892d65f6f70SBen Gras UFS_WAPBL_END(vp->v_mount);
1893d65f6f70SBen Gras }
1894d65f6f70SBen Gras } else {
1895d65f6f70SBen Gras error = VOP_FSYNC(vp, cred, FSYNC_NOLOG |
1896d65f6f70SBen Gras (waitfor == MNT_WAIT ? FSYNC_WAIT : 0), 0, 0);
1897d65f6f70SBen Gras }
1898d65f6f70SBen Gras if (error)
1899d65f6f70SBen Gras allerror = error;
1900d65f6f70SBen Gras vput(vp);
1901d65f6f70SBen Gras }
1902*0a6a1f1dSLionel Sambuc vfs_vnode_iterator_destroy(marker);
1903*0a6a1f1dSLionel Sambuc
1904d65f6f70SBen Gras /*
1905d65f6f70SBen Gras * Force stale file system control information to be flushed.
1906d65f6f70SBen Gras */
1907d65f6f70SBen Gras if (waitfor != MNT_LAZY && (ump->um_devvp->v_numoutput > 0 ||
1908d65f6f70SBen Gras !LIST_EMPTY(&ump->um_devvp->v_dirtyblkhd))) {
1909d65f6f70SBen Gras vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
1910d65f6f70SBen Gras if ((error = VOP_FSYNC(ump->um_devvp, cred,
1911d65f6f70SBen Gras (waitfor == MNT_WAIT ? FSYNC_WAIT : 0) | FSYNC_NOLOG,
1912d65f6f70SBen Gras 0, 0)) != 0)
1913d65f6f70SBen Gras allerror = error;
1914d65f6f70SBen Gras VOP_UNLOCK(ump->um_devvp);
1915d65f6f70SBen Gras }
1916d65f6f70SBen Gras #if defined(QUOTA) || defined(QUOTA2)
1917d65f6f70SBen Gras qsync(mp);
1918d65f6f70SBen Gras #endif
1919d65f6f70SBen Gras /*
1920d65f6f70SBen Gras * Write back modified superblock.
1921d65f6f70SBen Gras */
1922d65f6f70SBen Gras if (fs->fs_fmod != 0) {
1923d65f6f70SBen Gras fs->fs_fmod = 0;
1924d65f6f70SBen Gras fs->fs_time = time_second;
1925d65f6f70SBen Gras error = UFS_WAPBL_BEGIN(mp);
1926d65f6f70SBen Gras if (error)
1927d65f6f70SBen Gras allerror = error;
1928d65f6f70SBen Gras else {
1929d65f6f70SBen Gras if ((error = ffs_cgupdate(ump, waitfor)))
1930d65f6f70SBen Gras allerror = error;
1931d65f6f70SBen Gras UFS_WAPBL_END(mp);
1932d65f6f70SBen Gras }
1933d65f6f70SBen Gras }
1934d65f6f70SBen Gras
1935d65f6f70SBen Gras #ifdef WAPBL
1936d65f6f70SBen Gras if (mp->mnt_wapbl) {
1937d65f6f70SBen Gras error = wapbl_flush(mp->mnt_wapbl, 0);
1938d65f6f70SBen Gras if (error)
1939d65f6f70SBen Gras allerror = error;
1940d65f6f70SBen Gras }
1941d65f6f70SBen Gras #endif
1942d65f6f70SBen Gras
1943d65f6f70SBen Gras fstrans_done(mp);
1944d65f6f70SBen Gras return (allerror);
1945d65f6f70SBen Gras }
1946d65f6f70SBen Gras
1947d65f6f70SBen Gras /*
1948*0a6a1f1dSLionel Sambuc * Load inode from disk and initialize vnode.
1949d65f6f70SBen Gras */
1950*0a6a1f1dSLionel Sambuc static int
ffs_init_vnode(struct ufsmount * ump,struct vnode * vp,ino_t ino)1951*0a6a1f1dSLionel Sambuc ffs_init_vnode(struct ufsmount *ump, struct vnode *vp, ino_t ino)
1952d65f6f70SBen Gras {
1953d65f6f70SBen Gras struct fs *fs;
1954d65f6f70SBen Gras struct inode *ip;
1955d65f6f70SBen Gras struct buf *bp;
1956d65f6f70SBen Gras int error;
1957d65f6f70SBen Gras
1958*0a6a1f1dSLionel Sambuc fs = ump->um_fs;
1959d65f6f70SBen Gras
1960*0a6a1f1dSLionel Sambuc /* Read in the disk contents for the inode. */
196184d9c625SLionel Sambuc error = bread(ump->um_devvp, FFS_FSBTODB(fs, ino_to_fsba(fs, ino)),
1962*0a6a1f1dSLionel Sambuc (int)fs->fs_bsize, 0, &bp);
1963*0a6a1f1dSLionel Sambuc if (error)
1964*0a6a1f1dSLionel Sambuc return error;
1965d65f6f70SBen Gras
1966*0a6a1f1dSLionel Sambuc /* Allocate and initialize inode. */
1967*0a6a1f1dSLionel Sambuc ip = pool_cache_get(ffs_inode_cache, PR_WAITOK);
1968*0a6a1f1dSLionel Sambuc memset(ip, 0, sizeof(struct inode));
1969*0a6a1f1dSLionel Sambuc ip->i_ump = ump;
1970*0a6a1f1dSLionel Sambuc ip->i_fs = fs;
1971*0a6a1f1dSLionel Sambuc ip->i_dev = ump->um_dev;
1972*0a6a1f1dSLionel Sambuc ip->i_number = ino;
1973*0a6a1f1dSLionel Sambuc if (ump->um_fstype == UFS1)
1974d65f6f70SBen Gras ip->i_din.ffs1_din = pool_cache_get(ffs_dinode1_cache,
1975d65f6f70SBen Gras PR_WAITOK);
1976d65f6f70SBen Gras else
1977d65f6f70SBen Gras ip->i_din.ffs2_din = pool_cache_get(ffs_dinode2_cache,
1978d65f6f70SBen Gras PR_WAITOK);
1979d65f6f70SBen Gras ffs_load_inode(bp, ip, fs, ino);
1980d65f6f70SBen Gras brelse(bp, 0);
1981*0a6a1f1dSLionel Sambuc ip->i_vnode = vp;
1982*0a6a1f1dSLionel Sambuc #if defined(QUOTA) || defined(QUOTA2)
1983*0a6a1f1dSLionel Sambuc ufsquota_init(ip);
1984*0a6a1f1dSLionel Sambuc #endif
1985*0a6a1f1dSLionel Sambuc
1986*0a6a1f1dSLionel Sambuc /* Initialise vnode with this inode. */
1987*0a6a1f1dSLionel Sambuc vp->v_tag = VT_UFS;
1988*0a6a1f1dSLionel Sambuc vp->v_op = ffs_vnodeop_p;
1989*0a6a1f1dSLionel Sambuc vp->v_vflag |= VV_LOCKSWORK;
1990*0a6a1f1dSLionel Sambuc vp->v_data = ip;
1991*0a6a1f1dSLionel Sambuc
1992*0a6a1f1dSLionel Sambuc /* Initialize genfs node. */
1993*0a6a1f1dSLionel Sambuc genfs_node_init(vp, &ffs_genfsops);
1994*0a6a1f1dSLionel Sambuc
1995*0a6a1f1dSLionel Sambuc return 0;
1996*0a6a1f1dSLionel Sambuc }
1997d65f6f70SBen Gras
1998d65f6f70SBen Gras /*
1999*0a6a1f1dSLionel Sambuc * Undo ffs_init_vnode().
2000d65f6f70SBen Gras */
2001*0a6a1f1dSLionel Sambuc static void
ffs_deinit_vnode(struct ufsmount * ump,struct vnode * vp)2002*0a6a1f1dSLionel Sambuc ffs_deinit_vnode(struct ufsmount *ump, struct vnode *vp)
2003*0a6a1f1dSLionel Sambuc {
2004*0a6a1f1dSLionel Sambuc struct inode *ip = VTOI(vp);
2005d65f6f70SBen Gras
2006*0a6a1f1dSLionel Sambuc if (ump->um_fstype == UFS1)
2007*0a6a1f1dSLionel Sambuc pool_cache_put(ffs_dinode1_cache, ip->i_din.ffs1_din);
2008*0a6a1f1dSLionel Sambuc else
2009*0a6a1f1dSLionel Sambuc pool_cache_put(ffs_dinode2_cache, ip->i_din.ffs2_din);
2010*0a6a1f1dSLionel Sambuc pool_cache_put(ffs_inode_cache, ip);
2011*0a6a1f1dSLionel Sambuc
2012*0a6a1f1dSLionel Sambuc genfs_node_destroy(vp);
2013*0a6a1f1dSLionel Sambuc vp->v_data = NULL;
2014*0a6a1f1dSLionel Sambuc }
2015*0a6a1f1dSLionel Sambuc
2016*0a6a1f1dSLionel Sambuc /*
2017*0a6a1f1dSLionel Sambuc * Read an inode from disk and initialize this vnode / inode pair.
2018*0a6a1f1dSLionel Sambuc * Caller assures no other thread will try to load this inode.
2019*0a6a1f1dSLionel Sambuc */
2020*0a6a1f1dSLionel Sambuc int
ffs_loadvnode(struct mount * mp,struct vnode * vp,const void * key,size_t key_len,const void ** new_key)2021*0a6a1f1dSLionel Sambuc ffs_loadvnode(struct mount *mp, struct vnode *vp,
2022*0a6a1f1dSLionel Sambuc const void *key, size_t key_len, const void **new_key)
2023*0a6a1f1dSLionel Sambuc {
2024*0a6a1f1dSLionel Sambuc ino_t ino;
2025*0a6a1f1dSLionel Sambuc struct fs *fs;
2026*0a6a1f1dSLionel Sambuc struct inode *ip;
2027*0a6a1f1dSLionel Sambuc struct ufsmount *ump;
2028*0a6a1f1dSLionel Sambuc int error;
2029*0a6a1f1dSLionel Sambuc
2030*0a6a1f1dSLionel Sambuc KASSERT(key_len == sizeof(ino));
2031*0a6a1f1dSLionel Sambuc memcpy(&ino, key, key_len);
2032*0a6a1f1dSLionel Sambuc ump = VFSTOUFS(mp);
2033*0a6a1f1dSLionel Sambuc fs = ump->um_fs;
2034*0a6a1f1dSLionel Sambuc
2035*0a6a1f1dSLionel Sambuc error = ffs_init_vnode(ump, vp, ino);
2036*0a6a1f1dSLionel Sambuc if (error)
2037*0a6a1f1dSLionel Sambuc return error;
2038*0a6a1f1dSLionel Sambuc
2039*0a6a1f1dSLionel Sambuc ip = VTOI(vp);
2040*0a6a1f1dSLionel Sambuc if (ip->i_mode == 0) {
2041*0a6a1f1dSLionel Sambuc ffs_deinit_vnode(ump, vp);
2042*0a6a1f1dSLionel Sambuc
2043*0a6a1f1dSLionel Sambuc return ENOENT;
2044*0a6a1f1dSLionel Sambuc }
2045*0a6a1f1dSLionel Sambuc
2046*0a6a1f1dSLionel Sambuc /* Initialize the vnode from the inode. */
2047d65f6f70SBen Gras ufs_vinit(mp, ffs_specop_p, ffs_fifoop_p, &vp);
2048d65f6f70SBen Gras
2049*0a6a1f1dSLionel Sambuc /* Finish inode initialization. */
2050d65f6f70SBen Gras ip->i_devvp = ump->um_devvp;
2051d65f6f70SBen Gras vref(ip->i_devvp);
2052d65f6f70SBen Gras
2053d65f6f70SBen Gras /*
2054d65f6f70SBen Gras * Ensure that uid and gid are correct. This is a temporary
2055d65f6f70SBen Gras * fix until fsck has been changed to do the update.
2056d65f6f70SBen Gras */
2057d65f6f70SBen Gras
2058d65f6f70SBen Gras if (fs->fs_old_inodefmt < FS_44INODEFMT) { /* XXX */
2059d65f6f70SBen Gras ip->i_uid = ip->i_ffs1_ouid; /* XXX */
2060d65f6f70SBen Gras ip->i_gid = ip->i_ffs1_ogid; /* XXX */
2061d65f6f70SBen Gras } /* XXX */
2062d65f6f70SBen Gras uvm_vnp_setsize(vp, ip->i_size);
2063*0a6a1f1dSLionel Sambuc *new_key = &ip->i_number;
2064*0a6a1f1dSLionel Sambuc return 0;
2065*0a6a1f1dSLionel Sambuc }
2066*0a6a1f1dSLionel Sambuc
2067*0a6a1f1dSLionel Sambuc /*
2068*0a6a1f1dSLionel Sambuc * Create a new inode on disk and initialize this vnode / inode pair.
2069*0a6a1f1dSLionel Sambuc */
2070*0a6a1f1dSLionel Sambuc int
ffs_newvnode(struct mount * mp,struct vnode * dvp,struct vnode * vp,struct vattr * vap,kauth_cred_t cred,size_t * key_len,const void ** new_key)2071*0a6a1f1dSLionel Sambuc ffs_newvnode(struct mount *mp, struct vnode *dvp, struct vnode *vp,
2072*0a6a1f1dSLionel Sambuc struct vattr *vap, kauth_cred_t cred,
2073*0a6a1f1dSLionel Sambuc size_t *key_len, const void **new_key)
2074*0a6a1f1dSLionel Sambuc {
2075*0a6a1f1dSLionel Sambuc ino_t ino;
2076*0a6a1f1dSLionel Sambuc struct fs *fs;
2077*0a6a1f1dSLionel Sambuc struct inode *ip;
2078*0a6a1f1dSLionel Sambuc struct timespec ts;
2079*0a6a1f1dSLionel Sambuc struct ufsmount *ump;
2080*0a6a1f1dSLionel Sambuc int error, mode;
2081*0a6a1f1dSLionel Sambuc
2082*0a6a1f1dSLionel Sambuc KASSERT(dvp->v_mount == mp);
2083*0a6a1f1dSLionel Sambuc KASSERT(vap->va_type != VNON);
2084*0a6a1f1dSLionel Sambuc
2085*0a6a1f1dSLionel Sambuc *key_len = sizeof(ino);
2086*0a6a1f1dSLionel Sambuc ump = VFSTOUFS(mp);
2087*0a6a1f1dSLionel Sambuc fs = ump->um_fs;
2088*0a6a1f1dSLionel Sambuc mode = MAKEIMODE(vap->va_type, vap->va_mode);
2089*0a6a1f1dSLionel Sambuc
2090*0a6a1f1dSLionel Sambuc /* Allocate fresh inode. */
2091*0a6a1f1dSLionel Sambuc error = ffs_valloc(dvp, mode, cred, &ino);
2092*0a6a1f1dSLionel Sambuc if (error)
2093*0a6a1f1dSLionel Sambuc return error;
2094*0a6a1f1dSLionel Sambuc
2095*0a6a1f1dSLionel Sambuc /* Attach inode to vnode. */
2096*0a6a1f1dSLionel Sambuc error = ffs_init_vnode(ump, vp, ino);
2097*0a6a1f1dSLionel Sambuc if (error) {
2098*0a6a1f1dSLionel Sambuc if (UFS_WAPBL_BEGIN(mp) == 0) {
2099*0a6a1f1dSLionel Sambuc ffs_vfree(dvp, ino, mode);
2100*0a6a1f1dSLionel Sambuc UFS_WAPBL_END(mp);
2101*0a6a1f1dSLionel Sambuc }
2102*0a6a1f1dSLionel Sambuc return error;
2103*0a6a1f1dSLionel Sambuc }
2104*0a6a1f1dSLionel Sambuc
2105*0a6a1f1dSLionel Sambuc ip = VTOI(vp);
2106*0a6a1f1dSLionel Sambuc if (ip->i_mode || DIP(ip, size) || DIP(ip, blocks)) {
2107*0a6a1f1dSLionel Sambuc printf("free ino %" PRId64 " on %s:\n", ino, fs->fs_fsmnt);
2108*0a6a1f1dSLionel Sambuc printf("dmode %x mode %x dgen %x gen %x\n",
2109*0a6a1f1dSLionel Sambuc DIP(ip, mode), ip->i_mode,
2110*0a6a1f1dSLionel Sambuc DIP(ip, gen), ip->i_gen);
2111*0a6a1f1dSLionel Sambuc printf("size %" PRIx64 " blocks %" PRIx64 "\n",
2112*0a6a1f1dSLionel Sambuc DIP(ip, size), DIP(ip, blocks));
2113*0a6a1f1dSLionel Sambuc panic("ffs_init_vnode: dup alloc");
2114*0a6a1f1dSLionel Sambuc }
2115*0a6a1f1dSLionel Sambuc
2116*0a6a1f1dSLionel Sambuc /* Set uid / gid. */
2117*0a6a1f1dSLionel Sambuc if (cred == NOCRED || cred == FSCRED) {
2118*0a6a1f1dSLionel Sambuc ip->i_gid = 0;
2119*0a6a1f1dSLionel Sambuc ip->i_uid = 0;
2120*0a6a1f1dSLionel Sambuc } else {
2121*0a6a1f1dSLionel Sambuc ip->i_gid = VTOI(dvp)->i_gid;
2122*0a6a1f1dSLionel Sambuc ip->i_uid = kauth_cred_geteuid(cred);
2123*0a6a1f1dSLionel Sambuc }
2124*0a6a1f1dSLionel Sambuc DIP_ASSIGN(ip, gid, ip->i_gid);
2125*0a6a1f1dSLionel Sambuc DIP_ASSIGN(ip, uid, ip->i_uid);
2126*0a6a1f1dSLionel Sambuc
2127*0a6a1f1dSLionel Sambuc #if defined(QUOTA) || defined(QUOTA2)
2128*0a6a1f1dSLionel Sambuc error = UFS_WAPBL_BEGIN(mp);
2129*0a6a1f1dSLionel Sambuc if (error) {
2130*0a6a1f1dSLionel Sambuc ffs_deinit_vnode(ump, vp);
2131*0a6a1f1dSLionel Sambuc
2132*0a6a1f1dSLionel Sambuc return error;
2133*0a6a1f1dSLionel Sambuc }
2134*0a6a1f1dSLionel Sambuc error = chkiq(ip, 1, cred, 0);
2135*0a6a1f1dSLionel Sambuc if (error) {
2136*0a6a1f1dSLionel Sambuc ffs_vfree(dvp, ino, mode);
2137*0a6a1f1dSLionel Sambuc UFS_WAPBL_END(mp);
2138*0a6a1f1dSLionel Sambuc ffs_deinit_vnode(ump, vp);
2139*0a6a1f1dSLionel Sambuc
2140*0a6a1f1dSLionel Sambuc return error;
2141*0a6a1f1dSLionel Sambuc }
2142*0a6a1f1dSLionel Sambuc UFS_WAPBL_END(mp);
2143*0a6a1f1dSLionel Sambuc #endif
2144*0a6a1f1dSLionel Sambuc
2145*0a6a1f1dSLionel Sambuc /* Set type and finalize. */
2146*0a6a1f1dSLionel Sambuc ip->i_flags = 0;
2147*0a6a1f1dSLionel Sambuc DIP_ASSIGN(ip, flags, 0);
2148*0a6a1f1dSLionel Sambuc ip->i_mode = mode;
2149*0a6a1f1dSLionel Sambuc DIP_ASSIGN(ip, mode, mode);
2150*0a6a1f1dSLionel Sambuc if (vap->va_rdev != VNOVAL) {
2151*0a6a1f1dSLionel Sambuc /*
2152*0a6a1f1dSLionel Sambuc * Want to be able to use this to make badblock
2153*0a6a1f1dSLionel Sambuc * inodes, so don't truncate the dev number.
2154*0a6a1f1dSLionel Sambuc */
2155*0a6a1f1dSLionel Sambuc if (ump->um_fstype == UFS1)
2156*0a6a1f1dSLionel Sambuc ip->i_ffs1_rdev = ufs_rw32(vap->va_rdev,
2157*0a6a1f1dSLionel Sambuc UFS_MPNEEDSWAP(ump));
2158*0a6a1f1dSLionel Sambuc else
2159*0a6a1f1dSLionel Sambuc ip->i_ffs2_rdev = ufs_rw64(vap->va_rdev,
2160*0a6a1f1dSLionel Sambuc UFS_MPNEEDSWAP(ump));
2161*0a6a1f1dSLionel Sambuc }
2162*0a6a1f1dSLionel Sambuc ufs_vinit(mp, ffs_specop_p, ffs_fifoop_p, &vp);
2163*0a6a1f1dSLionel Sambuc ip->i_devvp = ump->um_devvp;
2164*0a6a1f1dSLionel Sambuc vref(ip->i_devvp);
2165*0a6a1f1dSLionel Sambuc
2166*0a6a1f1dSLionel Sambuc /* Set up a new generation number for this inode. */
2167*0a6a1f1dSLionel Sambuc ip->i_gen++;
2168*0a6a1f1dSLionel Sambuc DIP_ASSIGN(ip, gen, ip->i_gen);
2169*0a6a1f1dSLionel Sambuc if (fs->fs_magic == FS_UFS2_MAGIC) {
2170*0a6a1f1dSLionel Sambuc vfs_timestamp(&ts);
2171*0a6a1f1dSLionel Sambuc ip->i_ffs2_birthtime = ts.tv_sec;
2172*0a6a1f1dSLionel Sambuc ip->i_ffs2_birthnsec = ts.tv_nsec;
2173*0a6a1f1dSLionel Sambuc }
2174*0a6a1f1dSLionel Sambuc
2175*0a6a1f1dSLionel Sambuc uvm_vnp_setsize(vp, ip->i_size);
2176*0a6a1f1dSLionel Sambuc *new_key = &ip->i_number;
2177*0a6a1f1dSLionel Sambuc return 0;
2178d65f6f70SBen Gras }
2179d65f6f70SBen Gras
2180d65f6f70SBen Gras /*
2181d65f6f70SBen Gras * File handle to vnode
2182d65f6f70SBen Gras *
2183d65f6f70SBen Gras * Have to be really careful about stale file handles:
2184d65f6f70SBen Gras * - check that the inode number is valid
2185d65f6f70SBen Gras * - call ffs_vget() to get the locked inode
2186d65f6f70SBen Gras * - check for an unallocated inode (i_mode == 0)
2187d65f6f70SBen Gras * - check that the given client host has export rights and return
2188d65f6f70SBen Gras * those rights via. exflagsp and credanonp
2189d65f6f70SBen Gras */
2190d65f6f70SBen Gras int
ffs_fhtovp(struct mount * mp,struct fid * fhp,struct vnode ** vpp)2191d65f6f70SBen Gras ffs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
2192d65f6f70SBen Gras {
2193d65f6f70SBen Gras struct ufid ufh;
2194d65f6f70SBen Gras struct fs *fs;
2195d65f6f70SBen Gras
2196d65f6f70SBen Gras if (fhp->fid_len != sizeof(struct ufid))
2197d65f6f70SBen Gras return EINVAL;
2198d65f6f70SBen Gras
2199d65f6f70SBen Gras memcpy(&ufh, fhp, sizeof(ufh));
2200d65f6f70SBen Gras fs = VFSTOUFS(mp)->um_fs;
220184d9c625SLionel Sambuc if (ufh.ufid_ino < UFS_ROOTINO ||
2202d65f6f70SBen Gras ufh.ufid_ino >= fs->fs_ncg * fs->fs_ipg)
2203d65f6f70SBen Gras return (ESTALE);
2204d65f6f70SBen Gras return (ufs_fhtovp(mp, &ufh, vpp));
2205d65f6f70SBen Gras }
2206d65f6f70SBen Gras
2207d65f6f70SBen Gras /*
2208d65f6f70SBen Gras * Vnode pointer to File handle
2209d65f6f70SBen Gras */
2210d65f6f70SBen Gras /* ARGSUSED */
2211d65f6f70SBen Gras int
ffs_vptofh(struct vnode * vp,struct fid * fhp,size_t * fh_size)2212d65f6f70SBen Gras ffs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size)
2213d65f6f70SBen Gras {
2214d65f6f70SBen Gras struct inode *ip;
2215d65f6f70SBen Gras struct ufid ufh;
2216d65f6f70SBen Gras
2217d65f6f70SBen Gras if (*fh_size < sizeof(struct ufid)) {
2218d65f6f70SBen Gras *fh_size = sizeof(struct ufid);
2219d65f6f70SBen Gras return E2BIG;
2220d65f6f70SBen Gras }
2221d65f6f70SBen Gras ip = VTOI(vp);
2222d65f6f70SBen Gras *fh_size = sizeof(struct ufid);
2223d65f6f70SBen Gras memset(&ufh, 0, sizeof(ufh));
2224d65f6f70SBen Gras ufh.ufid_len = sizeof(struct ufid);
2225d65f6f70SBen Gras ufh.ufid_ino = ip->i_number;
2226d65f6f70SBen Gras ufh.ufid_gen = ip->i_gen;
2227d65f6f70SBen Gras memcpy(fhp, &ufh, sizeof(ufh));
2228d65f6f70SBen Gras return (0);
2229d65f6f70SBen Gras }
2230d65f6f70SBen Gras
2231d65f6f70SBen Gras void
ffs_init(void)2232d65f6f70SBen Gras ffs_init(void)
2233d65f6f70SBen Gras {
2234d65f6f70SBen Gras if (ffs_initcount++ > 0)
2235d65f6f70SBen Gras return;
2236d65f6f70SBen Gras
2237d65f6f70SBen Gras ffs_inode_cache = pool_cache_init(sizeof(struct inode), 0, 0, 0,
2238d65f6f70SBen Gras "ffsino", NULL, IPL_NONE, NULL, NULL, NULL);
2239d65f6f70SBen Gras ffs_dinode1_cache = pool_cache_init(sizeof(struct ufs1_dinode), 0, 0, 0,
2240d65f6f70SBen Gras "ffsdino1", NULL, IPL_NONE, NULL, NULL, NULL);
2241d65f6f70SBen Gras ffs_dinode2_cache = pool_cache_init(sizeof(struct ufs2_dinode), 0, 0, 0,
2242d65f6f70SBen Gras "ffsdino2", NULL, IPL_NONE, NULL, NULL, NULL);
2243d65f6f70SBen Gras ufs_init();
2244d65f6f70SBen Gras }
2245d65f6f70SBen Gras
2246d65f6f70SBen Gras void
ffs_reinit(void)2247d65f6f70SBen Gras ffs_reinit(void)
2248d65f6f70SBen Gras {
2249d65f6f70SBen Gras ufs_reinit();
2250d65f6f70SBen Gras }
2251d65f6f70SBen Gras
2252d65f6f70SBen Gras void
ffs_done(void)2253d65f6f70SBen Gras ffs_done(void)
2254d65f6f70SBen Gras {
2255d65f6f70SBen Gras if (--ffs_initcount > 0)
2256d65f6f70SBen Gras return;
2257d65f6f70SBen Gras
2258d65f6f70SBen Gras ufs_done();
2259d65f6f70SBen Gras pool_cache_destroy(ffs_dinode2_cache);
2260d65f6f70SBen Gras pool_cache_destroy(ffs_dinode1_cache);
2261d65f6f70SBen Gras pool_cache_destroy(ffs_inode_cache);
2262d65f6f70SBen Gras }
2263d65f6f70SBen Gras
2264d65f6f70SBen Gras /*
2265d65f6f70SBen Gras * Write a superblock and associated information back to disk.
2266d65f6f70SBen Gras */
2267d65f6f70SBen Gras int
ffs_sbupdate(struct ufsmount * mp,int waitfor)2268d65f6f70SBen Gras ffs_sbupdate(struct ufsmount *mp, int waitfor)
2269d65f6f70SBen Gras {
2270d65f6f70SBen Gras struct fs *fs = mp->um_fs;
2271d65f6f70SBen Gras struct buf *bp;
2272*0a6a1f1dSLionel Sambuc int error;
2273d65f6f70SBen Gras u_int32_t saveflag;
2274d65f6f70SBen Gras
2275d65f6f70SBen Gras error = ffs_getblk(mp->um_devvp,
2276d65f6f70SBen Gras fs->fs_sblockloc / DEV_BSIZE, FFS_NOBLK,
2277d65f6f70SBen Gras fs->fs_sbsize, false, &bp);
2278d65f6f70SBen Gras if (error)
2279d65f6f70SBen Gras return error;
2280d65f6f70SBen Gras saveflag = fs->fs_flags & FS_INTERNAL;
2281d65f6f70SBen Gras fs->fs_flags &= ~FS_INTERNAL;
2282d65f6f70SBen Gras
2283d65f6f70SBen Gras memcpy(bp->b_data, fs, fs->fs_sbsize);
2284d65f6f70SBen Gras
2285d65f6f70SBen Gras ffs_oldfscompat_write((struct fs *)bp->b_data, mp);
2286d65f6f70SBen Gras #ifdef FFS_EI
2287d65f6f70SBen Gras if (mp->um_flags & UFS_NEEDSWAP)
2288d65f6f70SBen Gras ffs_sb_swap((struct fs *)bp->b_data, (struct fs *)bp->b_data);
2289d65f6f70SBen Gras #endif
2290d65f6f70SBen Gras fs->fs_flags |= saveflag;
2291d65f6f70SBen Gras
2292d65f6f70SBen Gras if (waitfor == MNT_WAIT)
2293d65f6f70SBen Gras error = bwrite(bp);
2294d65f6f70SBen Gras else
2295d65f6f70SBen Gras bawrite(bp);
2296d65f6f70SBen Gras return (error);
2297d65f6f70SBen Gras }
2298d65f6f70SBen Gras
2299d65f6f70SBen Gras int
ffs_cgupdate(struct ufsmount * mp,int waitfor)2300d65f6f70SBen Gras ffs_cgupdate(struct ufsmount *mp, int waitfor)
2301d65f6f70SBen Gras {
2302d65f6f70SBen Gras struct fs *fs = mp->um_fs;
2303d65f6f70SBen Gras struct buf *bp;
2304d65f6f70SBen Gras int blks;
2305d65f6f70SBen Gras void *space;
2306d65f6f70SBen Gras int i, size, error = 0, allerror = 0;
2307d65f6f70SBen Gras
2308d65f6f70SBen Gras allerror = ffs_sbupdate(mp, waitfor);
2309d65f6f70SBen Gras blks = howmany(fs->fs_cssize, fs->fs_fsize);
2310d65f6f70SBen Gras space = fs->fs_csp;
2311d65f6f70SBen Gras for (i = 0; i < blks; i += fs->fs_frag) {
2312d65f6f70SBen Gras size = fs->fs_bsize;
2313d65f6f70SBen Gras if (i + fs->fs_frag > blks)
2314d65f6f70SBen Gras size = (blks - i) * fs->fs_fsize;
231584d9c625SLionel Sambuc error = ffs_getblk(mp->um_devvp, FFS_FSBTODB(fs, fs->fs_csaddr + i),
2316d65f6f70SBen Gras FFS_NOBLK, size, false, &bp);
2317d65f6f70SBen Gras if (error)
2318d65f6f70SBen Gras break;
2319d65f6f70SBen Gras #ifdef FFS_EI
2320d65f6f70SBen Gras if (mp->um_flags & UFS_NEEDSWAP)
2321d65f6f70SBen Gras ffs_csum_swap((struct csum*)space,
2322d65f6f70SBen Gras (struct csum*)bp->b_data, size);
2323d65f6f70SBen Gras else
2324d65f6f70SBen Gras #endif
2325d65f6f70SBen Gras memcpy(bp->b_data, space, (u_int)size);
2326d65f6f70SBen Gras space = (char *)space + size;
2327d65f6f70SBen Gras if (waitfor == MNT_WAIT)
2328d65f6f70SBen Gras error = bwrite(bp);
2329d65f6f70SBen Gras else
2330d65f6f70SBen Gras bawrite(bp);
2331d65f6f70SBen Gras }
2332d65f6f70SBen Gras if (!allerror && error)
2333d65f6f70SBen Gras allerror = error;
2334d65f6f70SBen Gras return (allerror);
2335d65f6f70SBen Gras }
2336d65f6f70SBen Gras
2337d65f6f70SBen Gras int
ffs_extattrctl(struct mount * mp,int cmd,struct vnode * vp,int attrnamespace,const char * attrname)2338d65f6f70SBen Gras ffs_extattrctl(struct mount *mp, int cmd, struct vnode *vp,
2339d65f6f70SBen Gras int attrnamespace, const char *attrname)
2340d65f6f70SBen Gras {
2341d65f6f70SBen Gras #ifdef UFS_EXTATTR
2342d65f6f70SBen Gras /*
2343d65f6f70SBen Gras * File-backed extended attributes are only supported on UFS1.
2344d65f6f70SBen Gras * UFS2 has native extended attributes.
2345d65f6f70SBen Gras */
2346d65f6f70SBen Gras if (VFSTOUFS(mp)->um_fstype == UFS1)
2347d65f6f70SBen Gras return (ufs_extattrctl(mp, cmd, vp, attrnamespace, attrname));
2348d65f6f70SBen Gras #endif
2349d65f6f70SBen Gras return (vfs_stdextattrctl(mp, cmd, vp, attrnamespace, attrname));
2350d65f6f70SBen Gras }
2351d65f6f70SBen Gras
2352d65f6f70SBen Gras int
ffs_suspendctl(struct mount * mp,int cmd)2353d65f6f70SBen Gras ffs_suspendctl(struct mount *mp, int cmd)
2354d65f6f70SBen Gras {
2355d65f6f70SBen Gras int error;
2356d65f6f70SBen Gras struct lwp *l = curlwp;
2357d65f6f70SBen Gras
2358d65f6f70SBen Gras switch (cmd) {
2359d65f6f70SBen Gras case SUSPEND_SUSPEND:
2360d65f6f70SBen Gras if ((error = fstrans_setstate(mp, FSTRANS_SUSPENDING)) != 0)
2361d65f6f70SBen Gras return error;
2362d65f6f70SBen Gras error = ffs_sync(mp, MNT_WAIT, l->l_proc->p_cred);
2363d65f6f70SBen Gras if (error == 0)
2364d65f6f70SBen Gras error = fstrans_setstate(mp, FSTRANS_SUSPENDED);
2365d65f6f70SBen Gras #ifdef WAPBL
2366d65f6f70SBen Gras if (error == 0 && mp->mnt_wapbl)
2367d65f6f70SBen Gras error = wapbl_flush(mp->mnt_wapbl, 1);
2368d65f6f70SBen Gras #endif
2369d65f6f70SBen Gras if (error != 0) {
2370d65f6f70SBen Gras (void) fstrans_setstate(mp, FSTRANS_NORMAL);
2371d65f6f70SBen Gras return error;
2372d65f6f70SBen Gras }
2373d65f6f70SBen Gras return 0;
2374d65f6f70SBen Gras
2375d65f6f70SBen Gras case SUSPEND_RESUME:
2376d65f6f70SBen Gras return fstrans_setstate(mp, FSTRANS_NORMAL);
2377d65f6f70SBen Gras
2378d65f6f70SBen Gras default:
2379d65f6f70SBen Gras return EINVAL;
2380d65f6f70SBen Gras }
2381d65f6f70SBen Gras }
2382d65f6f70SBen Gras
2383d65f6f70SBen Gras /*
2384d65f6f70SBen Gras * Synch vnode for a mounted file system.
2385d65f6f70SBen Gras */
2386d65f6f70SBen Gras static int
ffs_vfs_fsync(vnode_t * vp,int flags)2387d65f6f70SBen Gras ffs_vfs_fsync(vnode_t *vp, int flags)
2388d65f6f70SBen Gras {
2389d65f6f70SBen Gras int error, i, pflags;
2390d65f6f70SBen Gras #ifdef WAPBL
2391d65f6f70SBen Gras struct mount *mp;
2392d65f6f70SBen Gras #endif
2393d65f6f70SBen Gras
2394d65f6f70SBen Gras KASSERT(vp->v_type == VBLK);
239584d9c625SLionel Sambuc KASSERT(spec_node_getmountedfs(vp) != NULL);
2396d65f6f70SBen Gras
2397d65f6f70SBen Gras /*
2398d65f6f70SBen Gras * Flush all dirty data associated with the vnode.
2399d65f6f70SBen Gras */
2400d65f6f70SBen Gras pflags = PGO_ALLPAGES | PGO_CLEANIT;
2401d65f6f70SBen Gras if ((flags & FSYNC_WAIT) != 0)
2402d65f6f70SBen Gras pflags |= PGO_SYNCIO;
2403d65f6f70SBen Gras mutex_enter(vp->v_interlock);
2404d65f6f70SBen Gras error = VOP_PUTPAGES(vp, 0, 0, pflags);
2405d65f6f70SBen Gras if (error)
2406d65f6f70SBen Gras return error;
2407d65f6f70SBen Gras
2408d65f6f70SBen Gras #ifdef WAPBL
240984d9c625SLionel Sambuc mp = spec_node_getmountedfs(vp);
2410d65f6f70SBen Gras if (mp && mp->mnt_wapbl) {
2411d65f6f70SBen Gras /*
2412d65f6f70SBen Gras * Don't bother writing out metadata if the syncer is
2413d65f6f70SBen Gras * making the request. We will let the sync vnode
2414d65f6f70SBen Gras * write it out in a single burst through a call to
2415d65f6f70SBen Gras * VFS_SYNC().
2416d65f6f70SBen Gras */
2417d65f6f70SBen Gras if ((flags & (FSYNC_DATAONLY | FSYNC_LAZY | FSYNC_NOLOG)) != 0)
2418d65f6f70SBen Gras return 0;
2419d65f6f70SBen Gras
2420d65f6f70SBen Gras /*
2421d65f6f70SBen Gras * Don't flush the log if the vnode being flushed
2422d65f6f70SBen Gras * contains no dirty buffers that could be in the log.
2423d65f6f70SBen Gras */
2424d65f6f70SBen Gras if (!LIST_EMPTY(&vp->v_dirtyblkhd)) {
2425d65f6f70SBen Gras error = wapbl_flush(mp->mnt_wapbl, 0);
2426d65f6f70SBen Gras if (error)
2427d65f6f70SBen Gras return error;
2428d65f6f70SBen Gras }
2429d65f6f70SBen Gras
2430d65f6f70SBen Gras if ((flags & FSYNC_WAIT) != 0) {
2431d65f6f70SBen Gras mutex_enter(vp->v_interlock);
2432d65f6f70SBen Gras while (vp->v_numoutput)
2433d65f6f70SBen Gras cv_wait(&vp->v_cv, vp->v_interlock);
2434d65f6f70SBen Gras mutex_exit(vp->v_interlock);
2435d65f6f70SBen Gras }
2436d65f6f70SBen Gras
2437d65f6f70SBen Gras return 0;
2438d65f6f70SBen Gras }
2439d65f6f70SBen Gras #endif /* WAPBL */
2440d65f6f70SBen Gras
244184d9c625SLionel Sambuc error = vflushbuf(vp, flags);
2442d65f6f70SBen Gras if (error == 0 && (flags & FSYNC_CACHE) != 0) {
2443d65f6f70SBen Gras i = 1;
2444d65f6f70SBen Gras (void)VOP_IOCTL(vp, DIOCCACHESYNC, &i, FWRITE,
2445d65f6f70SBen Gras kauth_cred_get());
2446d65f6f70SBen Gras }
2447d65f6f70SBen Gras
2448d65f6f70SBen Gras return error;
2449d65f6f70SBen Gras }
2450