1e09c00caSUlf Lilleengen /*-
2e09c00caSUlf Lilleengen * modified for EXT2FS support in Lites 1.1
3e09c00caSUlf Lilleengen *
4e09c00caSUlf Lilleengen * Aug 1995, Godmar Back (gback@cs.utah.edu)
5e09c00caSUlf Lilleengen * University of Utah, Department of Computer Science
6e09c00caSUlf Lilleengen */
7e09c00caSUlf Lilleengen /*-
851369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
951369649SPedro F. Giffuni *
10e09c00caSUlf Lilleengen * Copyright (c) 1989, 1991, 1993, 1994
11e09c00caSUlf Lilleengen * The Regents of the University of California. All rights reserved.
12e09c00caSUlf Lilleengen *
13e09c00caSUlf Lilleengen * Redistribution and use in source and binary forms, with or without
14e09c00caSUlf Lilleengen * modification, are permitted provided that the following conditions
15e09c00caSUlf Lilleengen * are met:
16e09c00caSUlf Lilleengen * 1. Redistributions of source code must retain the above copyright
17e09c00caSUlf Lilleengen * notice, this list of conditions and the following disclaimer.
18e09c00caSUlf Lilleengen * 2. Redistributions in binary form must reproduce the above copyright
19e09c00caSUlf Lilleengen * notice, this list of conditions and the following disclaimer in the
20e09c00caSUlf Lilleengen * documentation and/or other materials provided with the distribution.
21fca15474SPedro F. Giffuni * 3. Neither the name of the University nor the names of its contributors
22e09c00caSUlf Lilleengen * may be used to endorse or promote products derived from this software
23e09c00caSUlf Lilleengen * without specific prior written permission.
24e09c00caSUlf Lilleengen *
25e09c00caSUlf Lilleengen * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26e09c00caSUlf Lilleengen * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27e09c00caSUlf Lilleengen * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28e09c00caSUlf Lilleengen * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29e09c00caSUlf Lilleengen * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30e09c00caSUlf Lilleengen * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31e09c00caSUlf Lilleengen * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32e09c00caSUlf Lilleengen * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33e09c00caSUlf Lilleengen * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34e09c00caSUlf Lilleengen * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35e09c00caSUlf Lilleengen * SUCH DAMAGE.
36e09c00caSUlf Lilleengen */
37e09c00caSUlf Lilleengen
38e09c00caSUlf Lilleengen #include <sys/param.h>
39e09c00caSUlf Lilleengen #include <sys/systm.h>
40e09c00caSUlf Lilleengen #include <sys/namei.h>
41e09c00caSUlf Lilleengen #include <sys/priv.h>
42e09c00caSUlf Lilleengen #include <sys/proc.h>
43e09c00caSUlf Lilleengen #include <sys/kernel.h>
44e09c00caSUlf Lilleengen #include <sys/vnode.h>
45e09c00caSUlf Lilleengen #include <sys/mount.h>
46e09c00caSUlf Lilleengen #include <sys/bio.h>
47e09c00caSUlf Lilleengen #include <sys/buf.h>
48e09c00caSUlf Lilleengen #include <sys/conf.h>
49035e4e04SPedro F. Giffuni #include <sys/endian.h>
50e09c00caSUlf Lilleengen #include <sys/fcntl.h>
51e09c00caSUlf Lilleengen #include <sys/malloc.h>
52ebc94b66SFedor Uporov #include <sys/sdt.h>
53e09c00caSUlf Lilleengen #include <sys/stat.h>
54e09c00caSUlf Lilleengen #include <sys/mutex.h>
55e09c00caSUlf Lilleengen
56e09c00caSUlf Lilleengen #include <geom/geom.h>
57e09c00caSUlf Lilleengen #include <geom/geom_vfs.h>
58e09c00caSUlf Lilleengen
59e06e5241SFedor Uporov #include <fs/ext2fs/fs.h>
60e09c00caSUlf Lilleengen #include <fs/ext2fs/ext2_mount.h>
61e09c00caSUlf Lilleengen #include <fs/ext2fs/inode.h>
62e09c00caSUlf Lilleengen
63e09c00caSUlf Lilleengen #include <fs/ext2fs/ext2fs.h>
6445641afbSJohn Baldwin #include <fs/ext2fs/ext2_dinode.h>
6545641afbSJohn Baldwin #include <fs/ext2fs/ext2_extern.h>
66e06e5241SFedor Uporov #include <fs/ext2fs/ext2_extents.h>
67e06e5241SFedor Uporov
68ebc94b66SFedor Uporov SDT_PROVIDER_DECLARE(ext2fs);
69ebc94b66SFedor Uporov /*
70ebc94b66SFedor Uporov * ext2fs trace probe:
71ebc94b66SFedor Uporov * arg0: verbosity. Higher numbers give more verbose messages
72ebc94b66SFedor Uporov * arg1: Textual message
73ebc94b66SFedor Uporov */
74ebc94b66SFedor Uporov SDT_PROBE_DEFINE2(ext2fs, , vfsops, trace, "int", "char*");
75ebc94b66SFedor Uporov SDT_PROBE_DEFINE2(ext2fs, , vfsops, ext2_cg_validate_error, "char*", "int");
76ebc94b66SFedor Uporov SDT_PROBE_DEFINE1(ext2fs, , vfsops, ext2_compute_sb_data_error, "char*");
77ebc94b66SFedor Uporov
78e09c00caSUlf Lilleengen static int ext2_flushfiles(struct mount *mp, int flags, struct thread *td);
79e09c00caSUlf Lilleengen static int ext2_mountfs(struct vnode *, struct mount *);
80e09c00caSUlf Lilleengen static int ext2_reload(struct mount *mp, struct thread *td);
81e09c00caSUlf Lilleengen static int ext2_sbupdate(struct ext2mount *, int);
82e09c00caSUlf Lilleengen static int ext2_cgupdate(struct ext2mount *, int);
83e09c00caSUlf Lilleengen static vfs_unmount_t ext2_unmount;
84e09c00caSUlf Lilleengen static vfs_root_t ext2_root;
85e09c00caSUlf Lilleengen static vfs_statfs_t ext2_statfs;
86e09c00caSUlf Lilleengen static vfs_sync_t ext2_sync;
87e09c00caSUlf Lilleengen static vfs_vget_t ext2_vget;
88e09c00caSUlf Lilleengen static vfs_fhtovp_t ext2_fhtovp;
89e09c00caSUlf Lilleengen static vfs_mount_t ext2_mount;
90e09c00caSUlf Lilleengen
91e09c00caSUlf Lilleengen MALLOC_DEFINE(M_EXT2NODE, "ext2_node", "EXT2 vnode private part");
92e09c00caSUlf Lilleengen static MALLOC_DEFINE(M_EXT2MNT, "ext2_mount", "EXT2 mount structure");
93e09c00caSUlf Lilleengen
94e09c00caSUlf Lilleengen static struct vfsops ext2fs_vfsops = {
95e09c00caSUlf Lilleengen .vfs_fhtovp = ext2_fhtovp,
96e09c00caSUlf Lilleengen .vfs_mount = ext2_mount,
97e09c00caSUlf Lilleengen .vfs_root = ext2_root, /* root inode via vget */
98e09c00caSUlf Lilleengen .vfs_statfs = ext2_statfs,
99e09c00caSUlf Lilleengen .vfs_sync = ext2_sync,
100e09c00caSUlf Lilleengen .vfs_unmount = ext2_unmount,
101e09c00caSUlf Lilleengen .vfs_vget = ext2_vget,
102e09c00caSUlf Lilleengen };
103e09c00caSUlf Lilleengen
104e09c00caSUlf Lilleengen VFS_SET(ext2fs_vfsops, ext2fs, 0);
105e09c00caSUlf Lilleengen
106e09c00caSUlf Lilleengen static int ext2_check_sb_compat(struct ext2fs *es, struct cdev *dev,
107e09c00caSUlf Lilleengen int ronly);
1086e38bf94SFedor Uporov static int ext2_compute_sb_data(struct vnode * devvp,
109e09c00caSUlf Lilleengen struct ext2fs * es, struct m_ext2fs * fs);
110e09c00caSUlf Lilleengen
11184edda0aSJohn Baldwin static const char *ext2_opts[] = { "acls", "async", "noatime", "noclusterr",
11284edda0aSJohn Baldwin "noclusterw", "noexec", "export", "force", "from", "multilabel",
11384edda0aSJohn Baldwin "suiddir", "nosymfollow", "sync", "union", NULL };
114e09c00caSUlf Lilleengen
115e09c00caSUlf Lilleengen /*
116e09c00caSUlf Lilleengen * VFS Operations.
117e09c00caSUlf Lilleengen *
118e09c00caSUlf Lilleengen * mount system call
119e09c00caSUlf Lilleengen */
120e09c00caSUlf Lilleengen static int
ext2_mount(struct mount * mp)121e09c00caSUlf Lilleengen ext2_mount(struct mount *mp)
122e09c00caSUlf Lilleengen {
123e09c00caSUlf Lilleengen struct vfsoptlist *opts;
124e09c00caSUlf Lilleengen struct vnode *devvp;
125e09c00caSUlf Lilleengen struct thread *td;
126f7a3729cSKevin Lo struct ext2mount *ump = NULL;
127e09c00caSUlf Lilleengen struct m_ext2fs *fs;
128e09c00caSUlf Lilleengen struct nameidata nd, *ndp = &nd;
129e09c00caSUlf Lilleengen accmode_t accmode;
130e09c00caSUlf Lilleengen char *path, *fspec;
131e09c00caSUlf Lilleengen int error, flags, len;
132e09c00caSUlf Lilleengen
133e09c00caSUlf Lilleengen td = curthread;
134e09c00caSUlf Lilleengen opts = mp->mnt_optnew;
135e09c00caSUlf Lilleengen
136e09c00caSUlf Lilleengen if (vfs_filteropt(opts, ext2_opts))
137e09c00caSUlf Lilleengen return (EINVAL);
138e09c00caSUlf Lilleengen
139e09c00caSUlf Lilleengen vfs_getopt(opts, "fspath", (void **)&path, NULL);
140e09c00caSUlf Lilleengen /* Double-check the length of path.. */
141757224cbSPedro F. Giffuni if (strlen(path) >= MAXMNTLEN)
142e09c00caSUlf Lilleengen return (ENAMETOOLONG);
143e09c00caSUlf Lilleengen
144e09c00caSUlf Lilleengen fspec = NULL;
145e09c00caSUlf Lilleengen error = vfs_getopt(opts, "from", (void **)&fspec, &len);
146e09c00caSUlf Lilleengen if (!error && fspec[len - 1] != '\0')
147e09c00caSUlf Lilleengen return (EINVAL);
148e09c00caSUlf Lilleengen
149e09c00caSUlf Lilleengen /*
150e09c00caSUlf Lilleengen * If updating, check whether changing from read-only to
151e09c00caSUlf Lilleengen * read/write; if there is no device name, that's all we do.
152e09c00caSUlf Lilleengen */
153e09c00caSUlf Lilleengen if (mp->mnt_flag & MNT_UPDATE) {
154e09c00caSUlf Lilleengen ump = VFSTOEXT2(mp);
155e09c00caSUlf Lilleengen fs = ump->um_e2fs;
156e09c00caSUlf Lilleengen error = 0;
157e09c00caSUlf Lilleengen if (fs->e2fs_ronly == 0 &&
158e09c00caSUlf Lilleengen vfs_flagopt(opts, "ro", NULL, 0)) {
159e09c00caSUlf Lilleengen error = VFS_SYNC(mp, MNT_WAIT);
160e09c00caSUlf Lilleengen if (error)
161e09c00caSUlf Lilleengen return (error);
162e09c00caSUlf Lilleengen flags = WRITECLOSE;
163e09c00caSUlf Lilleengen if (mp->mnt_flag & MNT_FORCE)
164e09c00caSUlf Lilleengen flags |= FORCECLOSE;
165e09c00caSUlf Lilleengen error = ext2_flushfiles(mp, flags, td);
166c0f16c65SFedor Uporov if (error == 0 && fs->e2fs_wasvalid &&
167c0f16c65SFedor Uporov ext2_cgupdate(ump, MNT_WAIT) == 0) {
168cd3acfe7SFedor Uporov fs->e2fs->e2fs_state =
169cd3acfe7SFedor Uporov htole16((le16toh(fs->e2fs->e2fs_state) |
170cd3acfe7SFedor Uporov E2FS_ISCLEAN));
171e09c00caSUlf Lilleengen ext2_sbupdate(ump, MNT_WAIT);
172e09c00caSUlf Lilleengen }
173e09c00caSUlf Lilleengen fs->e2fs_ronly = 1;
174e09c00caSUlf Lilleengen vfs_flagopt(opts, "ro", &mp->mnt_flag, MNT_RDONLY);
175e09c00caSUlf Lilleengen g_topology_lock();
176e09c00caSUlf Lilleengen g_access(ump->um_cp, 0, -1, 0);
177e09c00caSUlf Lilleengen g_topology_unlock();
178e09c00caSUlf Lilleengen }
179e09c00caSUlf Lilleengen if (!error && (mp->mnt_flag & MNT_RELOAD))
180e09c00caSUlf Lilleengen error = ext2_reload(mp, td);
181e09c00caSUlf Lilleengen if (error)
182e09c00caSUlf Lilleengen return (error);
183e09c00caSUlf Lilleengen devvp = ump->um_devvp;
184e09c00caSUlf Lilleengen if (fs->e2fs_ronly && !vfs_flagopt(opts, "ro", NULL, 0)) {
185e09c00caSUlf Lilleengen if (ext2_check_sb_compat(fs->e2fs, devvp->v_rdev, 0))
186e09c00caSUlf Lilleengen return (EPERM);
187e09c00caSUlf Lilleengen
188e09c00caSUlf Lilleengen /*
189e09c00caSUlf Lilleengen * If upgrade to read-write by non-root, then verify
190e09c00caSUlf Lilleengen * that user has necessary permissions on the device.
191e09c00caSUlf Lilleengen */
192e09c00caSUlf Lilleengen vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
193e09c00caSUlf Lilleengen error = VOP_ACCESS(devvp, VREAD | VWRITE,
194e09c00caSUlf Lilleengen td->td_ucred, td);
195e09c00caSUlf Lilleengen if (error)
196e09c00caSUlf Lilleengen error = priv_check(td, PRIV_VFS_MOUNT_PERM);
197e09c00caSUlf Lilleengen if (error) {
198b249ce48SMateusz Guzik VOP_UNLOCK(devvp);
199e09c00caSUlf Lilleengen return (error);
200e09c00caSUlf Lilleengen }
201b249ce48SMateusz Guzik VOP_UNLOCK(devvp);
202e09c00caSUlf Lilleengen g_topology_lock();
203e09c00caSUlf Lilleengen error = g_access(ump->um_cp, 0, 1, 0);
204e09c00caSUlf Lilleengen g_topology_unlock();
205e09c00caSUlf Lilleengen if (error)
206e09c00caSUlf Lilleengen return (error);
207e09c00caSUlf Lilleengen
208cd3acfe7SFedor Uporov if ((le16toh(fs->e2fs->e2fs_state) & E2FS_ISCLEAN) == 0 ||
209cd3acfe7SFedor Uporov (le16toh(fs->e2fs->e2fs_state) & E2FS_ERRORS)) {
210e09c00caSUlf Lilleengen if (mp->mnt_flag & MNT_FORCE) {
211e09c00caSUlf Lilleengen printf(
212e09c00caSUlf Lilleengen "WARNING: %s was not properly dismounted\n", fs->e2fs_fsmnt);
213e09c00caSUlf Lilleengen } else {
214e09c00caSUlf Lilleengen printf(
215e09c00caSUlf Lilleengen "WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck\n",
216e09c00caSUlf Lilleengen fs->e2fs_fsmnt);
217e09c00caSUlf Lilleengen return (EPERM);
218e09c00caSUlf Lilleengen }
219e09c00caSUlf Lilleengen }
220cd3acfe7SFedor Uporov fs->e2fs->e2fs_state =
221cd3acfe7SFedor Uporov htole16(le16toh(fs->e2fs->e2fs_state) & ~E2FS_ISCLEAN);
222e09c00caSUlf Lilleengen (void)ext2_cgupdate(ump, MNT_WAIT);
223e09c00caSUlf Lilleengen fs->e2fs_ronly = 0;
224e09c00caSUlf Lilleengen MNT_ILOCK(mp);
225e09c00caSUlf Lilleengen mp->mnt_flag &= ~MNT_RDONLY;
226e09c00caSUlf Lilleengen MNT_IUNLOCK(mp);
227e09c00caSUlf Lilleengen }
228e09c00caSUlf Lilleengen if (vfs_flagopt(opts, "export", NULL, 0)) {
229e09c00caSUlf Lilleengen /* Process export requests in vfs_mount.c. */
230e09c00caSUlf Lilleengen return (error);
231e09c00caSUlf Lilleengen }
232e09c00caSUlf Lilleengen }
233e09c00caSUlf Lilleengen
234e09c00caSUlf Lilleengen /*
235e09c00caSUlf Lilleengen * Not an update, or updating the name: look up the name
236e09c00caSUlf Lilleengen * and verify that it refers to a sensible disk device.
237e09c00caSUlf Lilleengen */
238e09c00caSUlf Lilleengen if (fspec == NULL)
239e09c00caSUlf Lilleengen return (EINVAL);
2407e1d3eefSMateusz Guzik NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspec);
241e09c00caSUlf Lilleengen if ((error = namei(ndp)) != 0)
242e09c00caSUlf Lilleengen return (error);
243bb92cd7bSMateusz Guzik NDFREE_PNBUF(ndp);
244e09c00caSUlf Lilleengen devvp = ndp->ni_vp;
245e09c00caSUlf Lilleengen
2467ad2a82dSMateusz Guzik if (!vn_isdisk_error(devvp, &error)) {
247e09c00caSUlf Lilleengen vput(devvp);
248e09c00caSUlf Lilleengen return (error);
249e09c00caSUlf Lilleengen }
250e09c00caSUlf Lilleengen
251e09c00caSUlf Lilleengen /*
252e09c00caSUlf Lilleengen * If mount by non-root, then verify that user has necessary
253e09c00caSUlf Lilleengen * permissions on the device.
254e09c00caSUlf Lilleengen *
255e09c00caSUlf Lilleengen * XXXRW: VOP_ACCESS() enough?
256e09c00caSUlf Lilleengen */
257e09c00caSUlf Lilleengen accmode = VREAD;
258e09c00caSUlf Lilleengen if ((mp->mnt_flag & MNT_RDONLY) == 0)
259e09c00caSUlf Lilleengen accmode |= VWRITE;
260e09c00caSUlf Lilleengen error = VOP_ACCESS(devvp, accmode, td->td_ucred, td);
261e09c00caSUlf Lilleengen if (error)
262e09c00caSUlf Lilleengen error = priv_check(td, PRIV_VFS_MOUNT_PERM);
263e09c00caSUlf Lilleengen if (error) {
264e09c00caSUlf Lilleengen vput(devvp);
265e09c00caSUlf Lilleengen return (error);
266e09c00caSUlf Lilleengen }
267e09c00caSUlf Lilleengen
268e09c00caSUlf Lilleengen if ((mp->mnt_flag & MNT_UPDATE) == 0) {
269e09c00caSUlf Lilleengen error = ext2_mountfs(devvp, mp);
270e09c00caSUlf Lilleengen } else {
271e09c00caSUlf Lilleengen if (devvp != ump->um_devvp) {
272e09c00caSUlf Lilleengen vput(devvp);
273e09c00caSUlf Lilleengen return (EINVAL); /* needs translation */
274e09c00caSUlf Lilleengen } else
275e09c00caSUlf Lilleengen vput(devvp);
276e09c00caSUlf Lilleengen }
277e09c00caSUlf Lilleengen if (error) {
278e09c00caSUlf Lilleengen vrele(devvp);
279e09c00caSUlf Lilleengen return (error);
280e09c00caSUlf Lilleengen }
281e09c00caSUlf Lilleengen ump = VFSTOEXT2(mp);
282e09c00caSUlf Lilleengen fs = ump->um_e2fs;
283e09c00caSUlf Lilleengen
284e09c00caSUlf Lilleengen /*
285e09c00caSUlf Lilleengen * Note that this strncpy() is ok because of a check at the start
286e09c00caSUlf Lilleengen * of ext2_mount().
287e09c00caSUlf Lilleengen */
288e09c00caSUlf Lilleengen strncpy(fs->e2fs_fsmnt, path, MAXMNTLEN);
289e09c00caSUlf Lilleengen fs->e2fs_fsmnt[MAXMNTLEN - 1] = '\0';
290e09c00caSUlf Lilleengen vfs_mountedfrom(mp, fspec);
291e09c00caSUlf Lilleengen return (0);
292e09c00caSUlf Lilleengen }
293e09c00caSUlf Lilleengen
294e09c00caSUlf Lilleengen static int
ext2_check_sb_compat(struct ext2fs * es,struct cdev * dev,int ronly)295e09c00caSUlf Lilleengen ext2_check_sb_compat(struct ext2fs *es, struct cdev *dev, int ronly)
296e09c00caSUlf Lilleengen {
2973d851dbeSPedro F. Giffuni uint32_t i, mask;
298e09c00caSUlf Lilleengen
299cd3acfe7SFedor Uporov if (le16toh(es->e2fs_magic) != E2FS_MAGIC) {
300e09c00caSUlf Lilleengen printf("ext2fs: %s: wrong magic number %#x (expected %#x)\n",
301cd3acfe7SFedor Uporov devtoname(dev), le16toh(es->e2fs_magic), E2FS_MAGIC);
302e09c00caSUlf Lilleengen return (1);
303e09c00caSUlf Lilleengen }
304cd3acfe7SFedor Uporov if (le32toh(es->e2fs_rev) > E2FS_REV0) {
305cd3acfe7SFedor Uporov mask = le32toh(es->e2fs_features_incompat) & ~(EXT2F_INCOMPAT_SUPP);
3063d851dbeSPedro F. Giffuni if (mask) {
3073d851dbeSPedro F. Giffuni printf("WARNING: mount of %s denied due to "
3083d851dbeSPedro F. Giffuni "unsupported optional features:\n", devtoname(dev));
3093d851dbeSPedro F. Giffuni for (i = 0;
3103d851dbeSPedro F. Giffuni i < sizeof(incompat)/sizeof(struct ext2_feature);
3113d851dbeSPedro F. Giffuni i++)
3123d851dbeSPedro F. Giffuni if (mask & incompat[i].mask)
3133d851dbeSPedro F. Giffuni printf("%s ", incompat[i].name);
3143d851dbeSPedro F. Giffuni printf("\n");
315e09c00caSUlf Lilleengen return (1);
316e09c00caSUlf Lilleengen }
317cd3acfe7SFedor Uporov mask = le32toh(es->e2fs_features_rocompat) & ~EXT2F_ROCOMPAT_SUPP;
3183d851dbeSPedro F. Giffuni if (!ronly && mask) {
319e09c00caSUlf Lilleengen printf("WARNING: R/W mount of %s denied due to "
3203d851dbeSPedro F. Giffuni "unsupported optional features:\n", devtoname(dev));
3213d851dbeSPedro F. Giffuni for (i = 0;
3223d851dbeSPedro F. Giffuni i < sizeof(ro_compat)/sizeof(struct ext2_feature);
3233d851dbeSPedro F. Giffuni i++)
3243d851dbeSPedro F. Giffuni if (mask & ro_compat[i].mask)
3253d851dbeSPedro F. Giffuni printf("%s ", ro_compat[i].name);
3263d851dbeSPedro F. Giffuni printf("\n");
327e09c00caSUlf Lilleengen return (1);
328e09c00caSUlf Lilleengen }
329e09c00caSUlf Lilleengen }
330e09c00caSUlf Lilleengen return (0);
331e09c00caSUlf Lilleengen }
332e09c00caSUlf Lilleengen
333c0f16c65SFedor Uporov static e4fs_daddr_t
ext2_cg_location(struct m_ext2fs * fs,int number)3346e38bf94SFedor Uporov ext2_cg_location(struct m_ext2fs *fs, int number)
335c0f16c65SFedor Uporov {
336c0f16c65SFedor Uporov int cg, descpb, logical_sb, has_super = 0;
337c0f16c65SFedor Uporov
338c0f16c65SFedor Uporov /*
339c0f16c65SFedor Uporov * Adjust logical superblock block number.
340c0f16c65SFedor Uporov * Godmar thinks: if the blocksize is greater than 1024, then
341c0f16c65SFedor Uporov * the superblock is logically part of block zero.
342c0f16c65SFedor Uporov */
34350be18ccSFedor Uporov logical_sb = fs->e2fs_bsize > SBLOCKSIZE ? 0 : 1;
344c0f16c65SFedor Uporov
345c0f16c65SFedor Uporov if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_META_BG) ||
346cd3acfe7SFedor Uporov number < le32toh(fs->e2fs->e3fs_first_meta_bg))
347c0f16c65SFedor Uporov return (logical_sb + number + 1);
348c0f16c65SFedor Uporov
349c0f16c65SFedor Uporov if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT))
350c0f16c65SFedor Uporov descpb = fs->e2fs_bsize / sizeof(struct ext2_gd);
351c0f16c65SFedor Uporov else
352c0f16c65SFedor Uporov descpb = fs->e2fs_bsize / E2FS_REV0_GD_SIZE;
353c0f16c65SFedor Uporov
354c0f16c65SFedor Uporov cg = descpb * number;
355c0f16c65SFedor Uporov
356c0f16c65SFedor Uporov if (ext2_cg_has_sb(fs, cg))
357c0f16c65SFedor Uporov has_super = 1;
358c0f16c65SFedor Uporov
359c0f16c65SFedor Uporov return (has_super + cg * (e4fs_daddr_t)EXT2_BLOCKS_PER_GROUP(fs) +
360cd3acfe7SFedor Uporov le32toh(fs->e2fs->e2fs_first_dblock));
361c0f16c65SFedor Uporov }
362c0f16c65SFedor Uporov
3636e38bf94SFedor Uporov static int
ext2_cg_validate(struct m_ext2fs * fs)3646e38bf94SFedor Uporov ext2_cg_validate(struct m_ext2fs *fs)
3656e38bf94SFedor Uporov {
3666e38bf94SFedor Uporov uint64_t b_bitmap;
3676e38bf94SFedor Uporov uint64_t i_bitmap;
3686e38bf94SFedor Uporov uint64_t i_tables;
3696e38bf94SFedor Uporov uint64_t first_block, last_block, last_cg_block;
3706e38bf94SFedor Uporov struct ext2_gd *gd;
3716e38bf94SFedor Uporov unsigned int i, cg_count;
3726e38bf94SFedor Uporov
373cd3acfe7SFedor Uporov first_block = le32toh(fs->e2fs->e2fs_first_dblock);
3746e38bf94SFedor Uporov last_cg_block = ext2_cg_number_gdb(fs, 0);
3756e38bf94SFedor Uporov cg_count = fs->e2fs_gcount;
3766e38bf94SFedor Uporov
3776e38bf94SFedor Uporov for (i = 0; i < fs->e2fs_gcount; i++) {
3786e38bf94SFedor Uporov gd = &fs->e2fs_gd[i];
3796e38bf94SFedor Uporov
3806e38bf94SFedor Uporov if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_FLEX_BG) ||
3816e38bf94SFedor Uporov i == fs->e2fs_gcount - 1) {
3826e38bf94SFedor Uporov last_block = fs->e2fs_bcount - 1;
3836e38bf94SFedor Uporov } else {
3846e38bf94SFedor Uporov last_block = first_block +
3856e38bf94SFedor Uporov (EXT2_BLOCKS_PER_GROUP(fs) - 1);
3866e38bf94SFedor Uporov }
3876e38bf94SFedor Uporov
3886e38bf94SFedor Uporov if ((cg_count == fs->e2fs_gcount) &&
389cd3acfe7SFedor Uporov !(le16toh(gd->ext4bgd_flags) & EXT2_BG_INODE_ZEROED))
3906e38bf94SFedor Uporov cg_count = i;
3916e38bf94SFedor Uporov
3926e38bf94SFedor Uporov b_bitmap = e2fs_gd_get_b_bitmap(gd);
3936e38bf94SFedor Uporov if (b_bitmap == 0) {
394ebc94b66SFedor Uporov SDT_PROBE2(ext2fs, , vfsops, ext2_cg_validate_error,
395ebc94b66SFedor Uporov "block bitmap is zero", i);
3966e38bf94SFedor Uporov return (EINVAL);
3976e38bf94SFedor Uporov }
3986e38bf94SFedor Uporov if (b_bitmap <= last_cg_block) {
399ebc94b66SFedor Uporov SDT_PROBE2(ext2fs, , vfsops, ext2_cg_validate_error,
400ebc94b66SFedor Uporov "block bitmap overlaps gds", i);
4016e38bf94SFedor Uporov return (EINVAL);
4026e38bf94SFedor Uporov }
4036e38bf94SFedor Uporov if (b_bitmap < first_block || b_bitmap > last_block) {
404ebc94b66SFedor Uporov SDT_PROBE2(ext2fs, , vfsops, ext2_cg_validate_error,
405ebc94b66SFedor Uporov "block bitmap not in group", i);
4066e38bf94SFedor Uporov return (EINVAL);
4076e38bf94SFedor Uporov }
4086e38bf94SFedor Uporov
4096e38bf94SFedor Uporov i_bitmap = e2fs_gd_get_i_bitmap(gd);
4106e38bf94SFedor Uporov if (i_bitmap == 0) {
411ebc94b66SFedor Uporov SDT_PROBE2(ext2fs, , vfsops, ext2_cg_validate_error,
412ebc94b66SFedor Uporov "inode bitmap is zero", i);
4136e38bf94SFedor Uporov return (EINVAL);
4146e38bf94SFedor Uporov }
4156e38bf94SFedor Uporov if (i_bitmap <= last_cg_block) {
416ebc94b66SFedor Uporov SDT_PROBE2(ext2fs, , vfsops, ext2_cg_validate_error,
417ebc94b66SFedor Uporov "inode bitmap overlaps gds", i);
4186e38bf94SFedor Uporov return (EINVAL);
4196e38bf94SFedor Uporov }
4206e38bf94SFedor Uporov if (i_bitmap < first_block || i_bitmap > last_block) {
421ebc94b66SFedor Uporov SDT_PROBE2(ext2fs, , vfsops, ext2_cg_validate_error,
422ebc94b66SFedor Uporov "inode bitmap not in group blk", i);
4236e38bf94SFedor Uporov return (EINVAL);
4246e38bf94SFedor Uporov }
4256e38bf94SFedor Uporov
4266e38bf94SFedor Uporov i_tables = e2fs_gd_get_i_tables(gd);
4276e38bf94SFedor Uporov if (i_tables == 0) {
428ebc94b66SFedor Uporov SDT_PROBE2(ext2fs, , vfsops, ext2_cg_validate_error,
429ebc94b66SFedor Uporov "inode table is zero", i);
4306e38bf94SFedor Uporov return (EINVAL);
4316e38bf94SFedor Uporov }
4326e38bf94SFedor Uporov if (i_tables <= last_cg_block) {
433ebc94b66SFedor Uporov SDT_PROBE2(ext2fs, , vfsops, ext2_cg_validate_error,
43447f880ebSGordon Bergling "inode tables overlaps gds", i);
4356e38bf94SFedor Uporov return (EINVAL);
4366e38bf94SFedor Uporov }
4376e38bf94SFedor Uporov if (i_tables < first_block ||
4386e38bf94SFedor Uporov i_tables + fs->e2fs_itpg - 1 > last_block) {
439ebc94b66SFedor Uporov SDT_PROBE2(ext2fs, , vfsops, ext2_cg_validate_error,
440ebc94b66SFedor Uporov "inode tables not in group blk", i);
4416e38bf94SFedor Uporov return (EINVAL);
4426e38bf94SFedor Uporov }
4436e38bf94SFedor Uporov
4446e38bf94SFedor Uporov if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_FLEX_BG))
4456e38bf94SFedor Uporov first_block += EXT2_BLOCKS_PER_GROUP(fs);
4466e38bf94SFedor Uporov }
4476e38bf94SFedor Uporov
4486e38bf94SFedor Uporov return (0);
4496e38bf94SFedor Uporov }
4506e38bf94SFedor Uporov
451e09c00caSUlf Lilleengen /*
4522b3506d9SKevin Lo * This computes the fields of the m_ext2fs structure from the
4532b3506d9SKevin Lo * data in the ext2fs structure read in.
454e09c00caSUlf Lilleengen */
455e09c00caSUlf Lilleengen static int
ext2_compute_sb_data(struct vnode * devvp,struct ext2fs * es,struct m_ext2fs * fs)4566e38bf94SFedor Uporov ext2_compute_sb_data(struct vnode *devvp, struct ext2fs *es,
457e09c00caSUlf Lilleengen struct m_ext2fs *fs)
458e09c00caSUlf Lilleengen {
459e09c00caSUlf Lilleengen struct buf *bp;
4603acd9182SFedor Uporov uint32_t e2fs_descpb, e2fs_gdbcount_alloc;
4616e38bf94SFedor Uporov int i, j;
4626e38bf94SFedor Uporov int g_count = 0;
4636e38bf94SFedor Uporov int error;
464e09c00caSUlf Lilleengen
4656e38bf94SFedor Uporov /* Check checksum features */
4666e38bf94SFedor Uporov if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) &&
4676e38bf94SFedor Uporov EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
468ebc94b66SFedor Uporov SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error,
469ebc94b66SFedor Uporov "incorrect checksum features combination");
4706e38bf94SFedor Uporov return (EINVAL);
4713acd9182SFedor Uporov }
4726e38bf94SFedor Uporov
4736e38bf94SFedor Uporov /* Precompute checksum seed for all metadata */
4746e38bf94SFedor Uporov ext2_sb_csum_set_seed(fs);
4756e38bf94SFedor Uporov
4766e38bf94SFedor Uporov /* Verify sb csum if possible */
4776e38bf94SFedor Uporov if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
4786e38bf94SFedor Uporov error = ext2_sb_csum_verify(fs);
4796e38bf94SFedor Uporov if (error) {
4806e38bf94SFedor Uporov return (error);
4816e38bf94SFedor Uporov }
4826e38bf94SFedor Uporov }
4836e38bf94SFedor Uporov
4846e38bf94SFedor Uporov /* Check for block size = 1K|2K|4K */
485cd3acfe7SFedor Uporov if (le32toh(es->e2fs_log_bsize) > 2) {
486ebc94b66SFedor Uporov SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error,
487ebc94b66SFedor Uporov "bad block size");
4886e38bf94SFedor Uporov return (EINVAL);
4896e38bf94SFedor Uporov }
4906e38bf94SFedor Uporov
491cd3acfe7SFedor Uporov fs->e2fs_bshift = EXT2_MIN_BLOCK_LOG_SIZE + le32toh(es->e2fs_log_bsize);
4924e1e0e25SPedro F. Giffuni fs->e2fs_bsize = 1U << fs->e2fs_bshift;
493cd3acfe7SFedor Uporov fs->e2fs_fsbtodb = le32toh(es->e2fs_log_bsize) + 1;
494e09c00caSUlf Lilleengen fs->e2fs_qbmask = fs->e2fs_bsize - 1;
4956e38bf94SFedor Uporov
4966e38bf94SFedor Uporov /* Check for fragment size */
497cd3acfe7SFedor Uporov if (le32toh(es->e2fs_log_fsize) >
4986e38bf94SFedor Uporov (EXT2_MAX_FRAG_LOG_SIZE - EXT2_MIN_BLOCK_LOG_SIZE)) {
499ebc94b66SFedor Uporov SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error,
500ebc94b66SFedor Uporov "invalid log cluster size");
5016e38bf94SFedor Uporov return (EINVAL);
5026e38bf94SFedor Uporov }
5036e38bf94SFedor Uporov
504cd3acfe7SFedor Uporov fs->e2fs_fsize = EXT2_MIN_FRAG_SIZE << le32toh(es->e2fs_log_fsize);
5056e38bf94SFedor Uporov if (fs->e2fs_fsize != fs->e2fs_bsize) {
506ebc94b66SFedor Uporov SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error,
507ebc94b66SFedor Uporov "fragment size != block size");
5086e38bf94SFedor Uporov return (EINVAL);
5096e38bf94SFedor Uporov }
5106e38bf94SFedor Uporov
511e09c00caSUlf Lilleengen fs->e2fs_fpb = fs->e2fs_bsize / fs->e2fs_fsize;
5126e38bf94SFedor Uporov
5136e38bf94SFedor Uporov /* Check reserved gdt blocks for future filesystem expansion */
514cd3acfe7SFedor Uporov if (le16toh(es->e2fs_reserved_ngdb) > (fs->e2fs_bsize / 4)) {
515ebc94b66SFedor Uporov SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error,
516ebc94b66SFedor Uporov "number of reserved GDT blocks too large");
5176e38bf94SFedor Uporov return (EINVAL);
5186e38bf94SFedor Uporov }
5196e38bf94SFedor Uporov
520cd3acfe7SFedor Uporov if (le32toh(es->e2fs_rev) == E2FS_REV0) {
521e09c00caSUlf Lilleengen fs->e2fs_isize = E2FS_REV0_INODE_SIZE;
522e09c00caSUlf Lilleengen } else {
523cd3acfe7SFedor Uporov fs->e2fs_isize = le16toh(es->e2fs_inode_size);
524e09c00caSUlf Lilleengen
525e09c00caSUlf Lilleengen /*
5266e38bf94SFedor Uporov * Check first ino.
5276e38bf94SFedor Uporov */
528cd3acfe7SFedor Uporov if (le32toh(es->e2fs_first_ino) < EXT2_FIRSTINO) {
529ebc94b66SFedor Uporov SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error,
530ebc94b66SFedor Uporov "invalid first ino");
5316e38bf94SFedor Uporov return (EINVAL);
5326e38bf94SFedor Uporov }
5336e38bf94SFedor Uporov
5346e38bf94SFedor Uporov /*
535e09c00caSUlf Lilleengen * Simple sanity check for superblock inode size value.
536e09c00caSUlf Lilleengen */
537035e4e04SPedro F. Giffuni if (EXT2_INODE_SIZE(fs) < E2FS_REV0_INODE_SIZE ||
538035e4e04SPedro F. Giffuni EXT2_INODE_SIZE(fs) > fs->e2fs_bsize ||
539e09c00caSUlf Lilleengen (fs->e2fs_isize & (fs->e2fs_isize - 1)) != 0) {
540ebc94b66SFedor Uporov SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error,
541ebc94b66SFedor Uporov "invalid inode size");
542035e4e04SPedro F. Giffuni return (EINVAL);
543035e4e04SPedro F. Giffuni }
544512f29d1SFedor Uporov }
5456e38bf94SFedor Uporov
5466e38bf94SFedor Uporov /* Check group descriptors */
547d23db91eSPedro F. Giffuni if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT) &&
548cd3acfe7SFedor Uporov le16toh(es->e3fs_desc_size) != E2FS_64BIT_GD_SIZE) {
549ebc94b66SFedor Uporov SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error,
550ebc94b66SFedor Uporov "unsupported 64bit descriptor size");
551d23db91eSPedro F. Giffuni return (EINVAL);
552d23db91eSPedro F. Giffuni }
5536e38bf94SFedor Uporov
554cd3acfe7SFedor Uporov fs->e2fs_bpg = le32toh(es->e2fs_bpg);
555cd3acfe7SFedor Uporov fs->e2fs_fpg = le32toh(es->e2fs_fpg);
5566e38bf94SFedor Uporov if (fs->e2fs_bpg == 0 || fs->e2fs_fpg == 0) {
557ebc94b66SFedor Uporov SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error,
558ebc94b66SFedor Uporov "zero blocks/fragments per group");
559771ec59bSPedro F. Giffuni return (EINVAL);
5606ce04e59SFedor Uporov } else if (fs->e2fs_bpg != fs->e2fs_fpg) {
5616ce04e59SFedor Uporov SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error,
5626ce04e59SFedor Uporov "blocks per group not equal fragments per group");
5636ce04e59SFedor Uporov return (EINVAL);
564771ec59bSPedro F. Giffuni }
5656ce04e59SFedor Uporov
566c0f16c65SFedor Uporov if (fs->e2fs_bpg != fs->e2fs_bsize * 8) {
567ebc94b66SFedor Uporov SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error,
568ebc94b66SFedor Uporov "non-standard group size unsupported");
569c0f16c65SFedor Uporov return (EINVAL);
570c0f16c65SFedor Uporov }
571035e4e04SPedro F. Giffuni
572e09c00caSUlf Lilleengen fs->e2fs_ipb = fs->e2fs_bsize / EXT2_INODE_SIZE(fs);
5736e38bf94SFedor Uporov if (fs->e2fs_ipb == 0 ||
5746e38bf94SFedor Uporov fs->e2fs_ipb > fs->e2fs_bsize / E2FS_REV0_INODE_SIZE) {
575ebc94b66SFedor Uporov SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error,
576ebc94b66SFedor Uporov "bad inodes per block size");
577771ec59bSPedro F. Giffuni return (EINVAL);
578771ec59bSPedro F. Giffuni }
5796e38bf94SFedor Uporov
580cd3acfe7SFedor Uporov fs->e2fs_ipg = le32toh(es->e2fs_ipg);
5816e38bf94SFedor Uporov if (fs->e2fs_ipg < fs->e2fs_ipb || fs->e2fs_ipg > fs->e2fs_bsize * 8) {
582ebc94b66SFedor Uporov SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error,
583ebc94b66SFedor Uporov "invalid inodes per group");
584771ec59bSPedro F. Giffuni return (EINVAL);
585771ec59bSPedro F. Giffuni }
5866e38bf94SFedor Uporov
5876e38bf94SFedor Uporov fs->e2fs_itpg = fs->e2fs_ipg / fs->e2fs_ipb;
5886e38bf94SFedor Uporov
589cd3acfe7SFedor Uporov fs->e2fs_bcount = le32toh(es->e2fs_bcount);
590cd3acfe7SFedor Uporov fs->e2fs_rbcount = le32toh(es->e2fs_rbcount);
591cd3acfe7SFedor Uporov fs->e2fs_fbcount = le32toh(es->e2fs_fbcount);
5926e38bf94SFedor Uporov if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) {
593cd3acfe7SFedor Uporov fs->e2fs_bcount |= (uint64_t)(le32toh(es->e4fs_bcount_hi)) << 32;
594cd3acfe7SFedor Uporov fs->e2fs_rbcount |= (uint64_t)(le32toh(es->e4fs_rbcount_hi)) << 32;
595cd3acfe7SFedor Uporov fs->e2fs_fbcount |= (uint64_t)(le32toh(es->e4fs_fbcount_hi)) << 32;
5966e38bf94SFedor Uporov }
597771ec59bSPedro F. Giffuni if (fs->e2fs_rbcount > fs->e2fs_bcount ||
598771ec59bSPedro F. Giffuni fs->e2fs_fbcount > fs->e2fs_bcount) {
599ebc94b66SFedor Uporov SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error,
600ebc94b66SFedor Uporov "invalid block count");
601771ec59bSPedro F. Giffuni return (EINVAL);
602771ec59bSPedro F. Giffuni }
603cd3acfe7SFedor Uporov
604cd3acfe7SFedor Uporov fs->e2fs_ficount = le32toh(es->e2fs_ficount);
605cd3acfe7SFedor Uporov if (fs->e2fs_ficount > le32toh(es->e2fs_icount)) {
606cd3acfe7SFedor Uporov SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error,
607cd3acfe7SFedor Uporov "invalid number of free inodes");
608cd3acfe7SFedor Uporov return (EINVAL);
609cd3acfe7SFedor Uporov }
610cd3acfe7SFedor Uporov
6113dd3a395SNeel Chauhan if (le32toh(es->e2fs_first_dblock) != (fs->e2fs_bsize > 1024 ? 0 : 1) ||
6123dd3a395SNeel Chauhan le32toh(es->e2fs_first_dblock) >= fs->e2fs_bcount) {
613ebc94b66SFedor Uporov SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error,
614ebc94b66SFedor Uporov "first data block out of range");
6156e38bf94SFedor Uporov return (EINVAL);
6166e38bf94SFedor Uporov }
6176e38bf94SFedor Uporov
618cd3acfe7SFedor Uporov fs->e2fs_gcount = howmany(fs->e2fs_bcount -
619cd3acfe7SFedor Uporov le32toh(es->e2fs_first_dblock), EXT2_BLOCKS_PER_GROUP(fs));
6206e38bf94SFedor Uporov if (fs->e2fs_gcount > ((uint64_t)1 << 32) - EXT2_DESCS_PER_BLOCK(fs)) {
621ebc94b66SFedor Uporov SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error,
622ebc94b66SFedor Uporov "groups count too large");
6236e38bf94SFedor Uporov return (EINVAL);
6246e38bf94SFedor Uporov }
6256e38bf94SFedor Uporov
6266e38bf94SFedor Uporov /* Check for extra isize in big inodes. */
6276e38bf94SFedor Uporov if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_EXTRA_ISIZE) &&
6286e38bf94SFedor Uporov EXT2_INODE_SIZE(fs) < sizeof(struct ext2fs_dinode)) {
629ebc94b66SFedor Uporov SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error,
630ebc94b66SFedor Uporov "no space for extra inode timestamps");
6316e38bf94SFedor Uporov return (EINVAL);
6326e38bf94SFedor Uporov }
6336e38bf94SFedor Uporov
6346e38bf94SFedor Uporov /* s_resuid / s_resgid ? */
6356e38bf94SFedor Uporov
6363acd9182SFedor Uporov if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) {
6376e38bf94SFedor Uporov e2fs_descpb = fs->e2fs_bsize / E2FS_64BIT_GD_SIZE;
6383acd9182SFedor Uporov e2fs_gdbcount_alloc = howmany(fs->e2fs_gcount, e2fs_descpb);
6393acd9182SFedor Uporov } else {
6403acd9182SFedor Uporov e2fs_descpb = fs->e2fs_bsize / E2FS_REV0_GD_SIZE;
6413acd9182SFedor Uporov e2fs_gdbcount_alloc = howmany(fs->e2fs_gcount,
6423acd9182SFedor Uporov fs->e2fs_bsize / sizeof(struct ext2_gd));
6433acd9182SFedor Uporov }
6443acd9182SFedor Uporov fs->e2fs_gdbcount = howmany(fs->e2fs_gcount, e2fs_descpb);
645f9834d10SPedro F. Giffuni fs->e2fs_gd = malloc(e2fs_gdbcount_alloc * fs->e2fs_bsize,
6463acd9182SFedor Uporov M_EXT2MNT, M_WAITOK | M_ZERO);
647f9834d10SPedro F. Giffuni fs->e2fs_contigdirs = malloc(fs->e2fs_gcount *
648f3ee91edSPedro F. Giffuni sizeof(*fs->e2fs_contigdirs), M_EXT2MNT, M_WAITOK | M_ZERO);
649e09c00caSUlf Lilleengen
6503acd9182SFedor Uporov for (i = 0; i < fs->e2fs_gdbcount; i++) {
651e09c00caSUlf Lilleengen error = bread(devvp,
6526e38bf94SFedor Uporov fsbtodb(fs, ext2_cg_location(fs, i)),
653e09c00caSUlf Lilleengen fs->e2fs_bsize, NOCRED, &bp);
654e09c00caSUlf Lilleengen if (error) {
6559441309aSFedor Uporov /*
6569441309aSFedor Uporov * fs->e2fs_gd and fs->e2fs_contigdirs
6579441309aSFedor Uporov * will be freed later by the caller,
6589441309aSFedor Uporov * because this function could be called from
6599441309aSFedor Uporov * MNT_UPDATE path.
6609441309aSFedor Uporov */
661e09c00caSUlf Lilleengen return (error);
662e09c00caSUlf Lilleengen }
6633acd9182SFedor Uporov if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) {
6643acd9182SFedor Uporov memcpy(&fs->e2fs_gd[
665e09c00caSUlf Lilleengen i * fs->e2fs_bsize / sizeof(struct ext2_gd)],
6663acd9182SFedor Uporov bp->b_data, fs->e2fs_bsize);
6673acd9182SFedor Uporov } else {
6683acd9182SFedor Uporov for (j = 0; j < e2fs_descpb &&
6693acd9182SFedor Uporov g_count < fs->e2fs_gcount; j++, g_count++)
6703acd9182SFedor Uporov memcpy(&fs->e2fs_gd[g_count],
6713acd9182SFedor Uporov bp->b_data + j * E2FS_REV0_GD_SIZE,
6723acd9182SFedor Uporov E2FS_REV0_GD_SIZE);
6733acd9182SFedor Uporov }
674e09c00caSUlf Lilleengen brelse(bp);
675e09c00caSUlf Lilleengen bp = NULL;
676e09c00caSUlf Lilleengen }
6776e38bf94SFedor Uporov
6786e38bf94SFedor Uporov /* Validate cgs consistency */
6796e38bf94SFedor Uporov error = ext2_cg_validate(fs);
6806e38bf94SFedor Uporov if (error)
6816e38bf94SFedor Uporov return (error);
6826e38bf94SFedor Uporov
6836e38bf94SFedor Uporov /* Verfy cgs csum */
684512f29d1SFedor Uporov if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) ||
685512f29d1SFedor Uporov EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
686d23db91eSPedro F. Giffuni error = ext2_gd_csum_verify(fs, devvp->v_rdev);
687d23db91eSPedro F. Giffuni if (error)
688d23db91eSPedro F. Giffuni return (error);
689d23db91eSPedro F. Giffuni }
690f3ee91edSPedro F. Giffuni /* Initialization for the ext2 Orlov allocator variant. */
691e09c00caSUlf Lilleengen fs->e2fs_total_dir = 0;
692f3ee91edSPedro F. Giffuni for (i = 0; i < fs->e2fs_gcount; i++)
693512f29d1SFedor Uporov fs->e2fs_total_dir += e2fs_gd_get_ndirs(&fs->e2fs_gd[i]);
694f3ee91edSPedro F. Giffuni
695cd3acfe7SFedor Uporov if (le32toh(es->e2fs_rev) == E2FS_REV0 ||
696035e4e04SPedro F. Giffuni !EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_LARGEFILE))
697e09c00caSUlf Lilleengen fs->e2fs_maxfilesize = 0x7fffffff;
6989824e4adSPedro F. Giffuni else {
6999824e4adSPedro F. Giffuni fs->e2fs_maxfilesize = 0xffffffffffff;
7009824e4adSPedro F. Giffuni if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_HUGE_FILE))
701e09c00caSUlf Lilleengen fs->e2fs_maxfilesize = 0x7fffffffffffffff;
7029824e4adSPedro F. Giffuni }
703cd3acfe7SFedor Uporov if (le32toh(es->e4fs_flags) & E2FS_UNSIGNED_HASH) {
7049824e4adSPedro F. Giffuni fs->e2fs_uhash = 3;
705cd3acfe7SFedor Uporov } else if ((le32toh(es->e4fs_flags) & E2FS_SIGNED_HASH) == 0) {
7069824e4adSPedro F. Giffuni #ifdef __CHAR_UNSIGNED__
707cd3acfe7SFedor Uporov es->e4fs_flags = htole32(le32toh(es->e4fs_flags) | E2FS_UNSIGNED_HASH);
7089824e4adSPedro F. Giffuni fs->e2fs_uhash = 3;
7099824e4adSPedro F. Giffuni #else
710cd3acfe7SFedor Uporov es->e4fs_flags = htole32(le32toh(es->e4fs_flags) | E2FS_SIGNED_HASH);
7119824e4adSPedro F. Giffuni #endif
7129824e4adSPedro F. Giffuni }
713512f29d1SFedor Uporov if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
714512f29d1SFedor Uporov error = ext2_sb_csum_verify(fs);
7159824e4adSPedro F. Giffuni
716512f29d1SFedor Uporov return (error);
717e09c00caSUlf Lilleengen }
718e09c00caSUlf Lilleengen
719e09c00caSUlf Lilleengen /*
720e09c00caSUlf Lilleengen * Reload all incore data for a filesystem (used after running fsck on
721e09c00caSUlf Lilleengen * the root filesystem and finding things to fix). The filesystem must
722e09c00caSUlf Lilleengen * be mounted read-only.
723e09c00caSUlf Lilleengen *
724e09c00caSUlf Lilleengen * Things to do to update the mount:
725e09c00caSUlf Lilleengen * 1) invalidate all cached meta-data.
726e09c00caSUlf Lilleengen * 2) re-read superblock from disk.
7275b63c125SPedro F. Giffuni * 3) invalidate all cluster summary information.
728e09c00caSUlf Lilleengen * 4) invalidate all inactive vnodes.
729e09c00caSUlf Lilleengen * 5) invalidate all cached file data.
730e09c00caSUlf Lilleengen * 6) re-read inode data for all active vnodes.
731e09c00caSUlf Lilleengen * XXX we are missing some steps, in particular # 3, this has to be reviewed.
732e09c00caSUlf Lilleengen */
733e09c00caSUlf Lilleengen static int
ext2_reload(struct mount * mp,struct thread * td)734e09c00caSUlf Lilleengen ext2_reload(struct mount *mp, struct thread *td)
735e09c00caSUlf Lilleengen {
736e09c00caSUlf Lilleengen struct vnode *vp, *mvp, *devvp;
737e09c00caSUlf Lilleengen struct inode *ip;
738e09c00caSUlf Lilleengen struct buf *bp;
739e09c00caSUlf Lilleengen struct ext2fs *es;
740e09c00caSUlf Lilleengen struct m_ext2fs *fs;
7415b63c125SPedro F. Giffuni struct csum *sump;
7425b63c125SPedro F. Giffuni int error, i;
7435b63c125SPedro F. Giffuni int32_t *lp;
744e09c00caSUlf Lilleengen
745e09c00caSUlf Lilleengen if ((mp->mnt_flag & MNT_RDONLY) == 0)
746e09c00caSUlf Lilleengen return (EINVAL);
747e09c00caSUlf Lilleengen /*
748e09c00caSUlf Lilleengen * Step 1: invalidate all cached meta-data.
749e09c00caSUlf Lilleengen */
750e09c00caSUlf Lilleengen devvp = VFSTOEXT2(mp)->um_devvp;
751e09c00caSUlf Lilleengen vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
752e09c00caSUlf Lilleengen if (vinvalbuf(devvp, 0, 0, 0) != 0)
753e09c00caSUlf Lilleengen panic("ext2_reload: dirty1");
754b249ce48SMateusz Guzik VOP_UNLOCK(devvp);
755e09c00caSUlf Lilleengen
756e09c00caSUlf Lilleengen /*
757e09c00caSUlf Lilleengen * Step 2: re-read superblock from disk.
758e09c00caSUlf Lilleengen * constants have been adjusted for ext2
759e09c00caSUlf Lilleengen */
76050be18ccSFedor Uporov if ((error = bread(devvp, SBLOCK, SBLOCKBLKSIZE, NOCRED, &bp)) != 0)
761e09c00caSUlf Lilleengen return (error);
76250be18ccSFedor Uporov es = (struct ext2fs *)((char *)bp->b_data + SBLOCKOFFSET);
763e09c00caSUlf Lilleengen if (ext2_check_sb_compat(es, devvp->v_rdev, 0) != 0) {
764e09c00caSUlf Lilleengen brelse(bp);
765e09c00caSUlf Lilleengen return (EIO); /* XXX needs translation */
766e09c00caSUlf Lilleengen }
767e09c00caSUlf Lilleengen fs = VFSTOEXT2(mp)->um_e2fs;
768e09c00caSUlf Lilleengen bcopy(bp->b_data, fs->e2fs, sizeof(struct ext2fs));
769e09c00caSUlf Lilleengen
7706e38bf94SFedor Uporov if ((error = ext2_compute_sb_data(devvp, es, fs)) != 0) {
771e09c00caSUlf Lilleengen brelse(bp);
772e09c00caSUlf Lilleengen return (error);
773e09c00caSUlf Lilleengen }
77450be18ccSFedor Uporov
775e09c00caSUlf Lilleengen brelse(bp);
776e09c00caSUlf Lilleengen
7775b63c125SPedro F. Giffuni /*
7785b63c125SPedro F. Giffuni * Step 3: invalidate all cluster summary information.
7795b63c125SPedro F. Giffuni */
7805b63c125SPedro F. Giffuni if (fs->e2fs_contigsumsize > 0) {
7815b63c125SPedro F. Giffuni lp = fs->e2fs_maxcluster;
7825b63c125SPedro F. Giffuni sump = fs->e2fs_clustersum;
7835b63c125SPedro F. Giffuni for (i = 0; i < fs->e2fs_gcount; i++, sump++) {
7845b63c125SPedro F. Giffuni *lp++ = fs->e2fs_contigsumsize;
7855b63c125SPedro F. Giffuni sump->cs_init = 0;
7865b63c125SPedro F. Giffuni bzero(sump->cs_sum, fs->e2fs_contigsumsize + 1);
7875b63c125SPedro F. Giffuni }
7885b63c125SPedro F. Giffuni }
7895b63c125SPedro F. Giffuni
790e09c00caSUlf Lilleengen loop:
79171469bb3SKirk McKusick MNT_VNODE_FOREACH_ALL(vp, mp, mvp) {
792e09c00caSUlf Lilleengen /*
793e09c00caSUlf Lilleengen * Step 4: invalidate all cached file data.
794e09c00caSUlf Lilleengen */
795a92a971bSMateusz Guzik if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK)) {
79671469bb3SKirk McKusick MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
797e09c00caSUlf Lilleengen goto loop;
798e09c00caSUlf Lilleengen }
799e09c00caSUlf Lilleengen if (vinvalbuf(vp, 0, 0, 0))
800e09c00caSUlf Lilleengen panic("ext2_reload: dirty2");
801e09c00caSUlf Lilleengen
802e09c00caSUlf Lilleengen /*
803e09c00caSUlf Lilleengen * Step 5: re-read inode data for all active vnodes.
804e09c00caSUlf Lilleengen */
805e09c00caSUlf Lilleengen ip = VTOI(vp);
806e09c00caSUlf Lilleengen error = bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
807e09c00caSUlf Lilleengen (int)fs->e2fs_bsize, NOCRED, &bp);
808e09c00caSUlf Lilleengen if (error) {
809b935e867SMateusz Guzik vput(vp);
81071469bb3SKirk McKusick MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
811e09c00caSUlf Lilleengen return (error);
812e09c00caSUlf Lilleengen }
813daa2d62dSFedor Uporov
814daa2d62dSFedor Uporov error = ext2_ei2i((struct ext2fs_dinode *)((char *)bp->b_data +
815e09c00caSUlf Lilleengen EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number)), ip);
816daa2d62dSFedor Uporov
817e09c00caSUlf Lilleengen brelse(bp);
818b935e867SMateusz Guzik vput(vp);
819daa2d62dSFedor Uporov
820daa2d62dSFedor Uporov if (error) {
821daa2d62dSFedor Uporov MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
822daa2d62dSFedor Uporov return (error);
823daa2d62dSFedor Uporov }
824e09c00caSUlf Lilleengen }
825e09c00caSUlf Lilleengen return (0);
826e09c00caSUlf Lilleengen }
827e09c00caSUlf Lilleengen
828e09c00caSUlf Lilleengen /*
829e09c00caSUlf Lilleengen * Common code for mount and mountroot.
830e09c00caSUlf Lilleengen */
831e09c00caSUlf Lilleengen static int
ext2_mountfs(struct vnode * devvp,struct mount * mp)832e09c00caSUlf Lilleengen ext2_mountfs(struct vnode *devvp, struct mount *mp)
833e09c00caSUlf Lilleengen {
834e09c00caSUlf Lilleengen struct ext2mount *ump;
835e09c00caSUlf Lilleengen struct buf *bp;
836e09c00caSUlf Lilleengen struct m_ext2fs *fs;
837e09c00caSUlf Lilleengen struct ext2fs *es;
838e09c00caSUlf Lilleengen struct cdev *dev = devvp->v_rdev;
839e09c00caSUlf Lilleengen struct g_consumer *cp;
840e09c00caSUlf Lilleengen struct bufobj *bo;
8415b63c125SPedro F. Giffuni struct csum *sump;
842e09c00caSUlf Lilleengen int error;
843e09c00caSUlf Lilleengen int ronly;
844bb9535bbSPedro F. Giffuni int i;
845bb9535bbSPedro F. Giffuni u_long size;
8465b63c125SPedro F. Giffuni int32_t *lp;
8471a125d6dSPedro F. Giffuni int32_t e2fs_maxcontig;
848e09c00caSUlf Lilleengen
84950be18ccSFedor Uporov bp = NULL;
85050be18ccSFedor Uporov ump = NULL;
85150be18ccSFedor Uporov
852e09c00caSUlf Lilleengen ronly = vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0);
853e09c00caSUlf Lilleengen /* XXX: use VOP_ACESS to check FS perms */
854e09c00caSUlf Lilleengen g_topology_lock();
855e09c00caSUlf Lilleengen error = g_vfs_open(devvp, &cp, "ext2fs", ronly ? 0 : 1);
856e09c00caSUlf Lilleengen g_topology_unlock();
857b249ce48SMateusz Guzik VOP_UNLOCK(devvp);
858e09c00caSUlf Lilleengen if (error)
859e09c00caSUlf Lilleengen return (error);
860e09c00caSUlf Lilleengen
86150be18ccSFedor Uporov if (PAGE_SIZE != SBLOCKBLKSIZE) {
86250be18ccSFedor Uporov printf("WARNING: Unsupported page size %d\n", PAGE_SIZE);
86350be18ccSFedor Uporov error = EINVAL;
86450be18ccSFedor Uporov goto out;
86550be18ccSFedor Uporov }
86650be18ccSFedor Uporov if (cp->provider->sectorsize > PAGE_SIZE) {
86750be18ccSFedor Uporov printf("WARNING: Device sectorsize(%d) is more than %d\n",
86850be18ccSFedor Uporov cp->provider->sectorsize, PAGE_SIZE);
86950be18ccSFedor Uporov error = EINVAL;
87050be18ccSFedor Uporov goto out;
871e09c00caSUlf Lilleengen }
872e09c00caSUlf Lilleengen
873e09c00caSUlf Lilleengen bo = &devvp->v_bufobj;
874e09c00caSUlf Lilleengen bo->bo_private = cp;
875e09c00caSUlf Lilleengen bo->bo_ops = g_vfs_bufops;
876e09c00caSUlf Lilleengen if (devvp->v_rdev->si_iosize_max != 0)
877e09c00caSUlf Lilleengen mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max;
878cd853791SKonstantin Belousov if (mp->mnt_iosize_max > maxphys)
879cd853791SKonstantin Belousov mp->mnt_iosize_max = maxphys;
88050be18ccSFedor Uporov if ((error = bread(devvp, SBLOCK, SBLOCKBLKSIZE, NOCRED, &bp)) != 0)
881e09c00caSUlf Lilleengen goto out;
88250be18ccSFedor Uporov es = (struct ext2fs *)((char *)bp->b_data + SBLOCKOFFSET);
883e09c00caSUlf Lilleengen if (ext2_check_sb_compat(es, dev, ronly) != 0) {
884e09c00caSUlf Lilleengen error = EINVAL; /* XXX needs translation */
885e09c00caSUlf Lilleengen goto out;
886e09c00caSUlf Lilleengen }
887cd3acfe7SFedor Uporov if ((le16toh(es->e2fs_state) & E2FS_ISCLEAN) == 0 ||
888cd3acfe7SFedor Uporov (le16toh(es->e2fs_state) & E2FS_ERRORS)) {
889e09c00caSUlf Lilleengen if (ronly || (mp->mnt_flag & MNT_FORCE)) {
890e09c00caSUlf Lilleengen printf(
891e09c00caSUlf Lilleengen "WARNING: Filesystem was not properly dismounted\n");
892e09c00caSUlf Lilleengen } else {
893e09c00caSUlf Lilleengen printf(
894e09c00caSUlf Lilleengen "WARNING: R/W mount denied. Filesystem is not clean - run fsck\n");
895e09c00caSUlf Lilleengen error = EPERM;
896e09c00caSUlf Lilleengen goto out;
897e09c00caSUlf Lilleengen }
898e09c00caSUlf Lilleengen }
8995ed5554fSPedro F. Giffuni ump = malloc(sizeof(*ump), M_EXT2MNT, M_WAITOK | M_ZERO);
900e09c00caSUlf Lilleengen
901e09c00caSUlf Lilleengen /*
902e09c00caSUlf Lilleengen * I don't know whether this is the right strategy. Note that
9032b3506d9SKevin Lo * we dynamically allocate both an m_ext2fs and an ext2fs
904e09c00caSUlf Lilleengen * while Linux keeps the super block in a locked buffer.
905e09c00caSUlf Lilleengen */
906e09c00caSUlf Lilleengen ump->um_e2fs = malloc(sizeof(struct m_ext2fs),
907daf884faSPedro F. Giffuni M_EXT2MNT, M_WAITOK | M_ZERO);
908e09c00caSUlf Lilleengen ump->um_e2fs->e2fs = malloc(sizeof(struct ext2fs),
909e09c00caSUlf Lilleengen M_EXT2MNT, M_WAITOK);
910e09c00caSUlf Lilleengen mtx_init(EXT2_MTX(ump), "EXT2FS", "EXT2FS Lock", MTX_DEF);
911e09c00caSUlf Lilleengen bcopy(es, ump->um_e2fs->e2fs, (u_int)sizeof(struct ext2fs));
9126e38bf94SFedor Uporov if ((error = ext2_compute_sb_data(devvp, ump->um_e2fs->e2fs, ump->um_e2fs)))
913e09c00caSUlf Lilleengen goto out;
914e09c00caSUlf Lilleengen
9155b63c125SPedro F. Giffuni /*
9165b63c125SPedro F. Giffuni * Calculate the maximum contiguous blocks and size of cluster summary
9175ed5554fSPedro F. Giffuni * array. In FFS this is done by newfs; however, the superblock
9185ed5554fSPedro F. Giffuni * in ext2fs doesn't have these variables, so we can calculate
9195b63c125SPedro F. Giffuni * them here.
9205b63c125SPedro F. Giffuni */
921cd853791SKonstantin Belousov e2fs_maxcontig = MAX(1, maxphys / ump->um_e2fs->e2fs_bsize);
9221a125d6dSPedro F. Giffuni ump->um_e2fs->e2fs_contigsumsize = MIN(e2fs_maxcontig, EXT2_MAXCONTIG);
923f784da88SKonstantin Belousov ump->um_e2fs->e2fs_maxsymlinklen = EXT2_MAXSYMLINKLEN;
9245b63c125SPedro F. Giffuni if (ump->um_e2fs->e2fs_contigsumsize > 0) {
9255b63c125SPedro F. Giffuni size = ump->um_e2fs->e2fs_gcount * sizeof(int32_t);
9265b63c125SPedro F. Giffuni ump->um_e2fs->e2fs_maxcluster = malloc(size, M_EXT2MNT, M_WAITOK);
9275b63c125SPedro F. Giffuni size = ump->um_e2fs->e2fs_gcount * sizeof(struct csum);
9285b63c125SPedro F. Giffuni ump->um_e2fs->e2fs_clustersum = malloc(size, M_EXT2MNT, M_WAITOK);
9295b63c125SPedro F. Giffuni lp = ump->um_e2fs->e2fs_maxcluster;
9305b63c125SPedro F. Giffuni sump = ump->um_e2fs->e2fs_clustersum;
9315b63c125SPedro F. Giffuni for (i = 0; i < ump->um_e2fs->e2fs_gcount; i++, sump++) {
9325b63c125SPedro F. Giffuni *lp++ = ump->um_e2fs->e2fs_contigsumsize;
9335b63c125SPedro F. Giffuni sump->cs_init = 0;
934f9834d10SPedro F. Giffuni sump->cs_sum = malloc((ump->um_e2fs->e2fs_contigsumsize + 1) *
9355b63c125SPedro F. Giffuni sizeof(int32_t), M_EXT2MNT, M_WAITOK | M_ZERO);
9365b63c125SPedro F. Giffuni }
9375b63c125SPedro F. Giffuni }
9385b63c125SPedro F. Giffuni
939e09c00caSUlf Lilleengen brelse(bp);
940e09c00caSUlf Lilleengen bp = NULL;
941e09c00caSUlf Lilleengen fs = ump->um_e2fs;
942e09c00caSUlf Lilleengen fs->e2fs_ronly = ronly; /* ronly is set according to mnt_flags */
943e09c00caSUlf Lilleengen
944e09c00caSUlf Lilleengen /*
945e09c00caSUlf Lilleengen * If the fs is not mounted read-only, make sure the super block is
946e09c00caSUlf Lilleengen * always written back on a sync().
947e09c00caSUlf Lilleengen */
948cd3acfe7SFedor Uporov fs->e2fs_wasvalid = le16toh(fs->e2fs->e2fs_state) & E2FS_ISCLEAN ? 1 : 0;
949e09c00caSUlf Lilleengen if (ronly == 0) {
950cd3acfe7SFedor Uporov fs->e2fs_fmod = 1; /* mark it modified and set fs invalid */
951cd3acfe7SFedor Uporov fs->e2fs->e2fs_state =
952cd3acfe7SFedor Uporov htole16(le16toh(fs->e2fs->e2fs_state) & ~E2FS_ISCLEAN);
953e09c00caSUlf Lilleengen }
954e09c00caSUlf Lilleengen mp->mnt_data = ump;
955e09c00caSUlf Lilleengen mp->mnt_stat.f_fsid.val[0] = dev2udev(dev);
956e09c00caSUlf Lilleengen mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
957e09c00caSUlf Lilleengen MNT_ILOCK(mp);
958e09c00caSUlf Lilleengen mp->mnt_flag |= MNT_LOCAL;
959e09c00caSUlf Lilleengen MNT_IUNLOCK(mp);
960e09c00caSUlf Lilleengen ump->um_mountp = mp;
961e09c00caSUlf Lilleengen ump->um_dev = dev;
962e09c00caSUlf Lilleengen ump->um_devvp = devvp;
963e09c00caSUlf Lilleengen ump->um_bo = &devvp->v_bufobj;
964e09c00caSUlf Lilleengen ump->um_cp = cp;
965e09c00caSUlf Lilleengen
966e09c00caSUlf Lilleengen /*
967e09c00caSUlf Lilleengen * Setting those two parameters allowed us to use
968e09c00caSUlf Lilleengen * ufs_bmap w/o changse!
969e09c00caSUlf Lilleengen */
970e09c00caSUlf Lilleengen ump->um_nindir = EXT2_ADDR_PER_BLOCK(fs);
971cd3acfe7SFedor Uporov ump->um_bptrtodb = le32toh(fs->e2fs->e2fs_log_bsize) + 1;
972e09c00caSUlf Lilleengen ump->um_seqinc = EXT2_FRAGS_PER_BLOCK(fs);
973e09c00caSUlf Lilleengen if (ronly == 0)
974e09c00caSUlf Lilleengen ext2_sbupdate(ump, MNT_WAIT);
975e09c00caSUlf Lilleengen /*
976e09c00caSUlf Lilleengen * Initialize filesystem stat information in mount struct.
977e09c00caSUlf Lilleengen */
978e09c00caSUlf Lilleengen MNT_ILOCK(mp);
979dda11d4aSRick Macklem mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED |
980dda11d4aSRick Macklem MNTK_USES_BCACHE;
981e09c00caSUlf Lilleengen MNT_IUNLOCK(mp);
982e09c00caSUlf Lilleengen return (0);
983e09c00caSUlf Lilleengen out:
984e09c00caSUlf Lilleengen if (bp)
985e09c00caSUlf Lilleengen brelse(bp);
986e09c00caSUlf Lilleengen if (cp != NULL) {
987e09c00caSUlf Lilleengen g_topology_lock();
988e09c00caSUlf Lilleengen g_vfs_close(cp);
989e09c00caSUlf Lilleengen g_topology_unlock();
990e09c00caSUlf Lilleengen }
991e09c00caSUlf Lilleengen if (ump) {
992e09c00caSUlf Lilleengen mtx_destroy(EXT2_MTX(ump));
993e09c00caSUlf Lilleengen free(ump->um_e2fs->e2fs_gd, M_EXT2MNT);
994e09c00caSUlf Lilleengen free(ump->um_e2fs->e2fs_contigdirs, M_EXT2MNT);
995e09c00caSUlf Lilleengen free(ump->um_e2fs->e2fs, M_EXT2MNT);
996e09c00caSUlf Lilleengen free(ump->um_e2fs, M_EXT2MNT);
997e09c00caSUlf Lilleengen free(ump, M_EXT2MNT);
998e09c00caSUlf Lilleengen mp->mnt_data = NULL;
999e09c00caSUlf Lilleengen }
1000e09c00caSUlf Lilleengen return (error);
1001e09c00caSUlf Lilleengen }
1002e09c00caSUlf Lilleengen
1003e09c00caSUlf Lilleengen /*
1004e09c00caSUlf Lilleengen * Unmount system call.
1005e09c00caSUlf Lilleengen */
1006e09c00caSUlf Lilleengen static int
ext2_unmount(struct mount * mp,int mntflags)1007e09c00caSUlf Lilleengen ext2_unmount(struct mount *mp, int mntflags)
1008e09c00caSUlf Lilleengen {
1009e09c00caSUlf Lilleengen struct ext2mount *ump;
1010e09c00caSUlf Lilleengen struct m_ext2fs *fs;
10115b63c125SPedro F. Giffuni struct csum *sump;
10125b63c125SPedro F. Giffuni int error, flags, i, ronly;
1013e09c00caSUlf Lilleengen
1014e09c00caSUlf Lilleengen flags = 0;
1015e09c00caSUlf Lilleengen if (mntflags & MNT_FORCE) {
1016e09c00caSUlf Lilleengen if (mp->mnt_flag & MNT_ROOTFS)
1017e09c00caSUlf Lilleengen return (EINVAL);
1018e09c00caSUlf Lilleengen flags |= FORCECLOSE;
1019e09c00caSUlf Lilleengen }
1020e09c00caSUlf Lilleengen if ((error = ext2_flushfiles(mp, flags, curthread)) != 0)
1021e09c00caSUlf Lilleengen return (error);
1022e09c00caSUlf Lilleengen ump = VFSTOEXT2(mp);
1023e09c00caSUlf Lilleengen fs = ump->um_e2fs;
1024e09c00caSUlf Lilleengen ronly = fs->e2fs_ronly;
1025e09c00caSUlf Lilleengen if (ronly == 0 && ext2_cgupdate(ump, MNT_WAIT) == 0) {
1026e09c00caSUlf Lilleengen if (fs->e2fs_wasvalid)
1027cd3acfe7SFedor Uporov fs->e2fs->e2fs_state =
1028cd3acfe7SFedor Uporov htole16(le16toh(fs->e2fs->e2fs_state) | E2FS_ISCLEAN);
1029e09c00caSUlf Lilleengen ext2_sbupdate(ump, MNT_WAIT);
1030e09c00caSUlf Lilleengen }
1031e09c00caSUlf Lilleengen
1032e09c00caSUlf Lilleengen g_topology_lock();
1033e09c00caSUlf Lilleengen g_vfs_close(ump->um_cp);
1034e09c00caSUlf Lilleengen g_topology_unlock();
1035e09c00caSUlf Lilleengen vrele(ump->um_devvp);
10365b63c125SPedro F. Giffuni sump = fs->e2fs_clustersum;
10375b63c125SPedro F. Giffuni for (i = 0; i < fs->e2fs_gcount; i++, sump++)
10385b63c125SPedro F. Giffuni free(sump->cs_sum, M_EXT2MNT);
10395b63c125SPedro F. Giffuni free(fs->e2fs_clustersum, M_EXT2MNT);
10405b63c125SPedro F. Giffuni free(fs->e2fs_maxcluster, M_EXT2MNT);
1041e09c00caSUlf Lilleengen free(fs->e2fs_gd, M_EXT2MNT);
1042e09c00caSUlf Lilleengen free(fs->e2fs_contigdirs, M_EXT2MNT);
1043e09c00caSUlf Lilleengen free(fs->e2fs, M_EXT2MNT);
1044e09c00caSUlf Lilleengen free(fs, M_EXT2MNT);
1045e09c00caSUlf Lilleengen free(ump, M_EXT2MNT);
1046e09c00caSUlf Lilleengen mp->mnt_data = NULL;
1047e09c00caSUlf Lilleengen return (error);
1048e09c00caSUlf Lilleengen }
1049e09c00caSUlf Lilleengen
1050e09c00caSUlf Lilleengen /*
1051e09c00caSUlf Lilleengen * Flush out all the files in a filesystem.
1052e09c00caSUlf Lilleengen */
1053e09c00caSUlf Lilleengen static int
ext2_flushfiles(struct mount * mp,int flags,struct thread * td)1054e09c00caSUlf Lilleengen ext2_flushfiles(struct mount *mp, int flags, struct thread *td)
1055e09c00caSUlf Lilleengen {
1056e09c00caSUlf Lilleengen int error;
1057e09c00caSUlf Lilleengen
1058e09c00caSUlf Lilleengen error = vflush(mp, 0, flags, td);
1059e09c00caSUlf Lilleengen return (error);
1060e09c00caSUlf Lilleengen }
1061bf9a211dSPedro F. Giffuni
1062e09c00caSUlf Lilleengen /*
1063e09c00caSUlf Lilleengen * Get filesystem statistics.
1064e09c00caSUlf Lilleengen */
1065e09c00caSUlf Lilleengen int
ext2_statfs(struct mount * mp,struct statfs * sbp)1066e09c00caSUlf Lilleengen ext2_statfs(struct mount *mp, struct statfs *sbp)
1067e09c00caSUlf Lilleengen {
1068e09c00caSUlf Lilleengen struct ext2mount *ump;
1069e09c00caSUlf Lilleengen struct m_ext2fs *fs;
1070e09c00caSUlf Lilleengen uint32_t overhead, overhead_per_group, ngdb;
1071e09c00caSUlf Lilleengen int i, ngroups;
1072e09c00caSUlf Lilleengen
1073e09c00caSUlf Lilleengen ump = VFSTOEXT2(mp);
1074e09c00caSUlf Lilleengen fs = ump->um_e2fs;
1075cd3acfe7SFedor Uporov if (le16toh(fs->e2fs->e2fs_magic) != E2FS_MAGIC)
1076757224cbSPedro F. Giffuni panic("ext2_statfs");
1077e09c00caSUlf Lilleengen
1078e09c00caSUlf Lilleengen /*
1079e09c00caSUlf Lilleengen * Compute the overhead (FS structures)
1080e09c00caSUlf Lilleengen */
1081e09c00caSUlf Lilleengen overhead_per_group =
1082e09c00caSUlf Lilleengen 1 /* block bitmap */ +
1083e09c00caSUlf Lilleengen 1 /* inode bitmap */ +
1084e09c00caSUlf Lilleengen fs->e2fs_itpg;
1085cd3acfe7SFedor Uporov overhead = le32toh(fs->e2fs->e2fs_first_dblock) +
1086e09c00caSUlf Lilleengen fs->e2fs_gcount * overhead_per_group;
1087cd3acfe7SFedor Uporov if (le32toh(fs->e2fs->e2fs_rev) > E2FS_REV0 &&
1088cd3acfe7SFedor Uporov le32toh(fs->e2fs->e2fs_features_rocompat) & EXT2F_ROCOMPAT_SPARSESUPER) {
1089e09c00caSUlf Lilleengen for (i = 0, ngroups = 0; i < fs->e2fs_gcount; i++) {
1090d23db91eSPedro F. Giffuni if (ext2_cg_has_sb(fs, i))
1091e09c00caSUlf Lilleengen ngroups++;
1092e09c00caSUlf Lilleengen }
1093e09c00caSUlf Lilleengen } else {
1094e09c00caSUlf Lilleengen ngroups = fs->e2fs_gcount;
1095e09c00caSUlf Lilleengen }
1096e09c00caSUlf Lilleengen ngdb = fs->e2fs_gdbcount;
1097cd3acfe7SFedor Uporov if (le32toh(fs->e2fs->e2fs_rev) > E2FS_REV0 &&
1098cd3acfe7SFedor Uporov le32toh(fs->e2fs->e2fs_features_compat) & EXT2F_COMPAT_RESIZE)
1099cd3acfe7SFedor Uporov ngdb += le16toh(fs->e2fs->e2fs_reserved_ngdb);
1100e09c00caSUlf Lilleengen overhead += ngroups * (1 /* superblock */ + ngdb);
1101e09c00caSUlf Lilleengen
1102e09c00caSUlf Lilleengen sbp->f_bsize = EXT2_FRAG_SIZE(fs);
1103e09c00caSUlf Lilleengen sbp->f_iosize = EXT2_BLOCK_SIZE(fs);
11043acd9182SFedor Uporov sbp->f_blocks = fs->e2fs_bcount - overhead;
11053acd9182SFedor Uporov sbp->f_bfree = fs->e2fs_fbcount;
11063acd9182SFedor Uporov sbp->f_bavail = sbp->f_bfree - fs->e2fs_rbcount;
1107cd3acfe7SFedor Uporov sbp->f_files = le32toh(fs->e2fs->e2fs_icount);
1108cd3acfe7SFedor Uporov sbp->f_ffree = fs->e2fs_ficount;
1109e09c00caSUlf Lilleengen return (0);
1110e09c00caSUlf Lilleengen }
1111e09c00caSUlf Lilleengen
1112e09c00caSUlf Lilleengen /*
1113e09c00caSUlf Lilleengen * Go through the disk queues to initiate sandbagged IO;
1114e09c00caSUlf Lilleengen * go through the inodes to write those that have been modified;
1115e09c00caSUlf Lilleengen * initiate the writing of the super block if it has been modified.
1116e09c00caSUlf Lilleengen *
1117e09c00caSUlf Lilleengen * Note: we are always called with the filesystem marked `MPBUSY'.
1118e09c00caSUlf Lilleengen */
1119e09c00caSUlf Lilleengen static int
ext2_sync(struct mount * mp,int waitfor)1120e09c00caSUlf Lilleengen ext2_sync(struct mount *mp, int waitfor)
1121e09c00caSUlf Lilleengen {
1122e09c00caSUlf Lilleengen struct vnode *mvp, *vp;
1123e09c00caSUlf Lilleengen struct thread *td;
1124e09c00caSUlf Lilleengen struct inode *ip;
1125e09c00caSUlf Lilleengen struct ext2mount *ump = VFSTOEXT2(mp);
1126e09c00caSUlf Lilleengen struct m_ext2fs *fs;
1127e09c00caSUlf Lilleengen int error, allerror = 0;
1128e09c00caSUlf Lilleengen
1129e09c00caSUlf Lilleengen td = curthread;
1130e09c00caSUlf Lilleengen fs = ump->um_e2fs;
1131e09c00caSUlf Lilleengen if (fs->e2fs_fmod != 0 && fs->e2fs_ronly != 0) { /* XXX */
1132ebc94b66SFedor Uporov panic("ext2_sync: rofs mod fs=%s", fs->e2fs_fsmnt);
1133e09c00caSUlf Lilleengen }
1134e09c00caSUlf Lilleengen
1135e09c00caSUlf Lilleengen /*
1136e09c00caSUlf Lilleengen * Write back each (modified) inode.
1137e09c00caSUlf Lilleengen */
1138e09c00caSUlf Lilleengen loop:
113971469bb3SKirk McKusick MNT_VNODE_FOREACH_ALL(vp, mp, mvp) {
114071469bb3SKirk McKusick if (vp->v_type == VNON) {
1141e09c00caSUlf Lilleengen VI_UNLOCK(vp);
1142e09c00caSUlf Lilleengen continue;
1143e09c00caSUlf Lilleengen }
1144e09c00caSUlf Lilleengen ip = VTOI(vp);
1145e09c00caSUlf Lilleengen if ((ip->i_flag &
1146e09c00caSUlf Lilleengen (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
1147e09c00caSUlf Lilleengen (vp->v_bufobj.bo_dirty.bv_cnt == 0 ||
1148e09c00caSUlf Lilleengen waitfor == MNT_LAZY)) {
1149e09c00caSUlf Lilleengen VI_UNLOCK(vp);
1150e09c00caSUlf Lilleengen continue;
1151e09c00caSUlf Lilleengen }
1152a92a971bSMateusz Guzik error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK);
1153e09c00caSUlf Lilleengen if (error) {
1154e09c00caSUlf Lilleengen if (error == ENOENT) {
115571469bb3SKirk McKusick MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
1156e09c00caSUlf Lilleengen goto loop;
1157e09c00caSUlf Lilleengen }
1158e09c00caSUlf Lilleengen continue;
1159e09c00caSUlf Lilleengen }
1160e09c00caSUlf Lilleengen if ((error = VOP_FSYNC(vp, waitfor, td)) != 0)
1161e09c00caSUlf Lilleengen allerror = error;
1162b935e867SMateusz Guzik vput(vp);
1163e09c00caSUlf Lilleengen }
1164e09c00caSUlf Lilleengen
1165e09c00caSUlf Lilleengen /*
1166e09c00caSUlf Lilleengen * Force stale filesystem control information to be flushed.
1167e09c00caSUlf Lilleengen */
1168e09c00caSUlf Lilleengen if (waitfor != MNT_LAZY) {
1169e09c00caSUlf Lilleengen vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
1170e09c00caSUlf Lilleengen if ((error = VOP_FSYNC(ump->um_devvp, waitfor, td)) != 0)
1171e09c00caSUlf Lilleengen allerror = error;
1172b249ce48SMateusz Guzik VOP_UNLOCK(ump->um_devvp);
1173e09c00caSUlf Lilleengen }
1174e09c00caSUlf Lilleengen
1175e09c00caSUlf Lilleengen /*
1176e09c00caSUlf Lilleengen * Write back modified superblock.
1177e09c00caSUlf Lilleengen */
1178e09c00caSUlf Lilleengen if (fs->e2fs_fmod != 0) {
1179e09c00caSUlf Lilleengen fs->e2fs_fmod = 0;
1180cd3acfe7SFedor Uporov fs->e2fs->e2fs_wtime = htole32(time_second);
1181e09c00caSUlf Lilleengen if ((error = ext2_cgupdate(ump, waitfor)) != 0)
1182e09c00caSUlf Lilleengen allerror = error;
1183e09c00caSUlf Lilleengen }
1184e09c00caSUlf Lilleengen return (allerror);
1185e09c00caSUlf Lilleengen }
1186e09c00caSUlf Lilleengen
1187e09c00caSUlf Lilleengen /*
1188e09c00caSUlf Lilleengen * Look up an EXT2FS dinode number to find its incore vnode, otherwise read it
1189e09c00caSUlf Lilleengen * in from disk. If it is in core, wait for the lock bit to clear, then
1190e09c00caSUlf Lilleengen * return the inode locked. Detection and handling of mount points must be
1191e09c00caSUlf Lilleengen * done by the calling routine.
1192e09c00caSUlf Lilleengen */
1193e09c00caSUlf Lilleengen static int
ext2_vget(struct mount * mp,ino_t ino,int flags,struct vnode ** vpp)1194e09c00caSUlf Lilleengen ext2_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp)
1195e09c00caSUlf Lilleengen {
1196e09c00caSUlf Lilleengen struct m_ext2fs *fs;
1197e09c00caSUlf Lilleengen struct inode *ip;
1198e09c00caSUlf Lilleengen struct ext2mount *ump;
1199e09c00caSUlf Lilleengen struct buf *bp;
1200e09c00caSUlf Lilleengen struct vnode *vp;
1201e09c00caSUlf Lilleengen struct thread *td;
1202736da517SFedor Uporov unsigned int i, used_blocks;
1203736da517SFedor Uporov int error;
1204e09c00caSUlf Lilleengen
1205e09c00caSUlf Lilleengen td = curthread;
1206e09c00caSUlf Lilleengen error = vfs_hash_get(mp, ino, flags, td, vpp, NULL, NULL);
1207e09c00caSUlf Lilleengen if (error || *vpp != NULL)
1208e09c00caSUlf Lilleengen return (error);
1209e09c00caSUlf Lilleengen
1210e09c00caSUlf Lilleengen ump = VFSTOEXT2(mp);
1211e09c00caSUlf Lilleengen ip = malloc(sizeof(struct inode), M_EXT2NODE, M_WAITOK | M_ZERO);
1212e09c00caSUlf Lilleengen
1213e09c00caSUlf Lilleengen /* Allocate a new vnode/inode. */
1214e09c00caSUlf Lilleengen if ((error = getnewvnode("ext2fs", mp, &ext2_vnodeops, &vp)) != 0) {
1215e09c00caSUlf Lilleengen *vpp = NULL;
1216e09c00caSUlf Lilleengen free(ip, M_EXT2NODE);
1217e09c00caSUlf Lilleengen return (error);
1218e09c00caSUlf Lilleengen }
1219e09c00caSUlf Lilleengen vp->v_data = ip;
1220e09c00caSUlf Lilleengen ip->i_vnode = vp;
1221e09c00caSUlf Lilleengen ip->i_e2fs = fs = ump->um_e2fs;
1222e09c00caSUlf Lilleengen ip->i_ump = ump;
1223e09c00caSUlf Lilleengen ip->i_number = ino;
12242bfd8992SKonstantin Belousov cluster_init_vn(&ip->i_clusterw);
1225e09c00caSUlf Lilleengen
1226e09c00caSUlf Lilleengen lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL);
1227e09c00caSUlf Lilleengen error = insmntque(vp, mp);
1228e09c00caSUlf Lilleengen if (error != 0) {
1229e09c00caSUlf Lilleengen free(ip, M_EXT2NODE);
1230e09c00caSUlf Lilleengen *vpp = NULL;
1231e09c00caSUlf Lilleengen return (error);
1232e09c00caSUlf Lilleengen }
1233e09c00caSUlf Lilleengen error = vfs_hash_insert(vp, ino, flags, td, vpp, NULL, NULL);
1234e09c00caSUlf Lilleengen if (error || *vpp != NULL)
1235e09c00caSUlf Lilleengen return (error);
1236e09c00caSUlf Lilleengen
1237e09c00caSUlf Lilleengen /* Read in the disk contents for the inode, copy into the inode. */
1238e09c00caSUlf Lilleengen if ((error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
1239e09c00caSUlf Lilleengen (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
1240e09c00caSUlf Lilleengen /*
1241e09c00caSUlf Lilleengen * The inode does not contain anything useful, so it would
1242e09c00caSUlf Lilleengen * be misleading to leave it on its hash chain. With mode
1243e09c00caSUlf Lilleengen * still zero, it will be unlinked and returned to the free
1244e09c00caSUlf Lilleengen * list by vput().
1245e09c00caSUlf Lilleengen */
1246e09c00caSUlf Lilleengen brelse(bp);
1247e09c00caSUlf Lilleengen vput(vp);
1248e09c00caSUlf Lilleengen *vpp = NULL;
1249e09c00caSUlf Lilleengen return (error);
1250e09c00caSUlf Lilleengen }
1251e09c00caSUlf Lilleengen /* convert ext2 inode to dinode */
1252512f29d1SFedor Uporov error = ext2_ei2i((struct ext2fs_dinode *)((char *)bp->b_data +
1253512f29d1SFedor Uporov EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ino)), ip);
1254512f29d1SFedor Uporov if (error) {
1255512f29d1SFedor Uporov brelse(bp);
1256512f29d1SFedor Uporov vput(vp);
1257512f29d1SFedor Uporov *vpp = NULL;
1258512f29d1SFedor Uporov return (error);
1259512f29d1SFedor Uporov }
1260e09c00caSUlf Lilleengen ip->i_block_group = ino_to_cg(fs, ino);
1261e09c00caSUlf Lilleengen ip->i_next_alloc_block = 0;
1262e09c00caSUlf Lilleengen ip->i_next_alloc_goal = 0;
1263e09c00caSUlf Lilleengen
1264e09c00caSUlf Lilleengen /*
1265e09c00caSUlf Lilleengen * Now we want to make sure that block pointers for unused
1266e09c00caSUlf Lilleengen * blocks are zeroed out - ext2_balloc depends on this
1267e09c00caSUlf Lilleengen * although for regular files and directories only
1268d7511a40SPedro F. Giffuni *
1269ad3d96a7SPedro F. Giffuni * If IN_E4EXTENTS is enabled, unused blocks are not zeroed
1270a7710d51SPedro F. Giffuni * out because we could corrupt the extent tree.
1271e09c00caSUlf Lilleengen */
1272ad3d96a7SPedro F. Giffuni if (!(ip->i_flag & IN_E4EXTENTS) &&
1273d7511a40SPedro F. Giffuni (S_ISDIR(ip->i_mode) || S_ISREG(ip->i_mode))) {
1274ee7ae58aSPedro F. Giffuni used_blocks = howmany(ip->i_size, fs->e2fs_bsize);
1275e09c00caSUlf Lilleengen for (i = used_blocks; i < EXT2_NDIR_BLOCKS; i++)
1276e09c00caSUlf Lilleengen ip->i_db[i] = 0;
1277e09c00caSUlf Lilleengen }
12785679656eSFedor Uporov
12795679656eSFedor Uporov bqrelse(bp);
12805679656eSFedor Uporov
1281ebc94b66SFedor Uporov #ifdef EXT2FS_PRINT_EXTENTS
1282e09c00caSUlf Lilleengen ext2_print_inode(ip);
12835679656eSFedor Uporov error = ext4_ext_walk(ip);
12845679656eSFedor Uporov if (error) {
12855679656eSFedor Uporov vput(vp);
12865679656eSFedor Uporov *vpp = NULL;
12875679656eSFedor Uporov return (error);
12885679656eSFedor Uporov }
128933587684SPedro F. Giffuni #endif
1290e09c00caSUlf Lilleengen
1291e09c00caSUlf Lilleengen /*
1292e09c00caSUlf Lilleengen * Initialize the vnode from the inode, check for aliases.
1293e09c00caSUlf Lilleengen * Note that the underlying vnode may have changed.
1294e09c00caSUlf Lilleengen */
1295e09c00caSUlf Lilleengen if ((error = ext2_vinit(mp, &ext2_fifoops, &vp)) != 0) {
1296e09c00caSUlf Lilleengen vput(vp);
1297e09c00caSUlf Lilleengen *vpp = NULL;
1298e09c00caSUlf Lilleengen return (error);
1299e09c00caSUlf Lilleengen }
1300e09c00caSUlf Lilleengen
1301e09c00caSUlf Lilleengen /*
1302007c6207SJohn Baldwin * Finish inode initialization.
1303e09c00caSUlf Lilleengen */
1304e09c00caSUlf Lilleengen
1305829f0bcbSMateusz Guzik vn_set_state(vp, VSTATE_CONSTRUCTED);
1306e09c00caSUlf Lilleengen *vpp = vp;
1307e09c00caSUlf Lilleengen return (0);
1308e09c00caSUlf Lilleengen }
1309e09c00caSUlf Lilleengen
1310e09c00caSUlf Lilleengen /*
1311e09c00caSUlf Lilleengen * File handle to vnode
1312e09c00caSUlf Lilleengen *
1313e09c00caSUlf Lilleengen * Have to be really careful about stale file handles:
1314e09c00caSUlf Lilleengen * - check that the inode number is valid
1315e09c00caSUlf Lilleengen * - call ext2_vget() to get the locked inode
1316e09c00caSUlf Lilleengen * - check for an unallocated inode (i_mode == 0)
1317e09c00caSUlf Lilleengen * - check that the given client host has export rights and return
1318e09c00caSUlf Lilleengen * those rights via. exflagsp and credanonp
1319e09c00caSUlf Lilleengen */
1320e09c00caSUlf Lilleengen static int
ext2_fhtovp(struct mount * mp,struct fid * fhp,int flags,struct vnode ** vpp)1321694a586aSRick Macklem ext2_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp)
1322e09c00caSUlf Lilleengen {
1323e09c00caSUlf Lilleengen struct inode *ip;
1324e09c00caSUlf Lilleengen struct ufid *ufhp;
1325e09c00caSUlf Lilleengen struct vnode *nvp;
1326e09c00caSUlf Lilleengen struct m_ext2fs *fs;
1327e09c00caSUlf Lilleengen int error;
1328e09c00caSUlf Lilleengen
1329e09c00caSUlf Lilleengen ufhp = (struct ufid *)fhp;
1330e09c00caSUlf Lilleengen fs = VFSTOEXT2(mp)->um_e2fs;
1331bbfe24fbSJohn Baldwin if (ufhp->ufid_ino < EXT2_ROOTINO ||
1332cd3acfe7SFedor Uporov ufhp->ufid_ino > fs->e2fs_gcount * fs->e2fs_ipg)
1333e09c00caSUlf Lilleengen return (ESTALE);
1334e09c00caSUlf Lilleengen
1335e09c00caSUlf Lilleengen error = VFS_VGET(mp, ufhp->ufid_ino, LK_EXCLUSIVE, &nvp);
1336e09c00caSUlf Lilleengen if (error) {
1337e09c00caSUlf Lilleengen *vpp = NULLVP;
1338e09c00caSUlf Lilleengen return (error);
1339e09c00caSUlf Lilleengen }
1340e09c00caSUlf Lilleengen ip = VTOI(nvp);
1341e09c00caSUlf Lilleengen if (ip->i_mode == 0 ||
1342e09c00caSUlf Lilleengen ip->i_gen != ufhp->ufid_gen || ip->i_nlink <= 0) {
1343e09c00caSUlf Lilleengen vput(nvp);
1344e09c00caSUlf Lilleengen *vpp = NULLVP;
1345e09c00caSUlf Lilleengen return (ESTALE);
1346e09c00caSUlf Lilleengen }
1347e09c00caSUlf Lilleengen *vpp = nvp;
1348*56a8aca8SPawel Jakub Dawidek vnode_create_vobject(*vpp, ip->i_size, curthread);
1349e09c00caSUlf Lilleengen return (0);
1350e09c00caSUlf Lilleengen }
1351e09c00caSUlf Lilleengen
1352e09c00caSUlf Lilleengen /*
1353e09c00caSUlf Lilleengen * Write a superblock and associated information back to disk.
1354e09c00caSUlf Lilleengen */
1355e09c00caSUlf Lilleengen static int
ext2_sbupdate(struct ext2mount * mp,int waitfor)1356e09c00caSUlf Lilleengen ext2_sbupdate(struct ext2mount *mp, int waitfor)
1357e09c00caSUlf Lilleengen {
1358e09c00caSUlf Lilleengen struct m_ext2fs *fs = mp->um_e2fs;
1359e09c00caSUlf Lilleengen struct ext2fs *es = fs->e2fs;
1360e09c00caSUlf Lilleengen struct buf *bp;
1361e09c00caSUlf Lilleengen int error = 0;
1362e09c00caSUlf Lilleengen
1363cd3acfe7SFedor Uporov es->e2fs_bcount = htole32(fs->e2fs_bcount & 0xffffffff);
1364cd3acfe7SFedor Uporov es->e2fs_rbcount = htole32(fs->e2fs_rbcount & 0xffffffff);
1365cd3acfe7SFedor Uporov es->e2fs_fbcount = htole32(fs->e2fs_fbcount & 0xffffffff);
13663acd9182SFedor Uporov if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) {
1367cd3acfe7SFedor Uporov es->e4fs_bcount_hi = htole32(fs->e2fs_bcount >> 32);
1368cd3acfe7SFedor Uporov es->e4fs_rbcount_hi = htole32(fs->e2fs_rbcount >> 32);
1369cd3acfe7SFedor Uporov es->e4fs_fbcount_hi = htole32(fs->e2fs_fbcount >> 32);
13703acd9182SFedor Uporov }
13713acd9182SFedor Uporov
1372cd3acfe7SFedor Uporov es->e2fs_ficount = htole32(fs->e2fs_ficount);
1373cd3acfe7SFedor Uporov
1374512f29d1SFedor Uporov if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
1375512f29d1SFedor Uporov ext2_sb_csum_set(fs);
1376512f29d1SFedor Uporov
137750be18ccSFedor Uporov error = bread(mp->um_devvp, SBLOCK, SBLOCKBLKSIZE, NOCRED, &bp);
137850be18ccSFedor Uporov if (error != 0)
137950be18ccSFedor Uporov return (error);
138050be18ccSFedor Uporov
138150be18ccSFedor Uporov memcpy((char *)bp->b_data + SBLOCKOFFSET, (caddr_t)es,
138250be18ccSFedor Uporov (u_int)sizeof(struct ext2fs));
1383e09c00caSUlf Lilleengen if (waitfor == MNT_WAIT)
1384e09c00caSUlf Lilleengen error = bwrite(bp);
1385e09c00caSUlf Lilleengen else
1386e09c00caSUlf Lilleengen bawrite(bp);
1387e09c00caSUlf Lilleengen
1388e09c00caSUlf Lilleengen /*
1389e09c00caSUlf Lilleengen * The buffers for group descriptors, inode bitmaps and block bitmaps
1390e09c00caSUlf Lilleengen * are not busy at this point and are (hopefully) written by the
1391e09c00caSUlf Lilleengen * usual sync mechanism. No need to write them here.
1392e09c00caSUlf Lilleengen */
1393e09c00caSUlf Lilleengen return (error);
1394e09c00caSUlf Lilleengen }
1395e09c00caSUlf Lilleengen int
ext2_cgupdate(struct ext2mount * mp,int waitfor)1396e09c00caSUlf Lilleengen ext2_cgupdate(struct ext2mount *mp, int waitfor)
1397e09c00caSUlf Lilleengen {
1398e09c00caSUlf Lilleengen struct m_ext2fs *fs = mp->um_e2fs;
1399e09c00caSUlf Lilleengen struct buf *bp;
14003acd9182SFedor Uporov int i, j, g_count = 0, error = 0, allerror = 0;
1401e09c00caSUlf Lilleengen
1402e09c00caSUlf Lilleengen allerror = ext2_sbupdate(mp, waitfor);
1403d23db91eSPedro F. Giffuni
1404d23db91eSPedro F. Giffuni /* Update gd csums */
1405512f29d1SFedor Uporov if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) ||
1406512f29d1SFedor Uporov EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM))
1407d23db91eSPedro F. Giffuni ext2_gd_csum_set(fs);
1408d23db91eSPedro F. Giffuni
1409e09c00caSUlf Lilleengen for (i = 0; i < fs->e2fs_gdbcount; i++) {
1410e09c00caSUlf Lilleengen bp = getblk(mp->um_devvp, fsbtodb(fs,
14116e38bf94SFedor Uporov ext2_cg_location(fs, i)),
1412c0f16c65SFedor Uporov fs->e2fs_bsize, 0, 0, 0);
14133acd9182SFedor Uporov if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) {
14143acd9182SFedor Uporov memcpy(bp->b_data, &fs->e2fs_gd[
1415e09c00caSUlf Lilleengen i * fs->e2fs_bsize / sizeof(struct ext2_gd)],
14163acd9182SFedor Uporov fs->e2fs_bsize);
14173acd9182SFedor Uporov } else {
14183acd9182SFedor Uporov for (j = 0; j < fs->e2fs_bsize / E2FS_REV0_GD_SIZE &&
14193acd9182SFedor Uporov g_count < fs->e2fs_gcount; j++, g_count++)
14203acd9182SFedor Uporov memcpy(bp->b_data + j * E2FS_REV0_GD_SIZE,
14213acd9182SFedor Uporov &fs->e2fs_gd[g_count], E2FS_REV0_GD_SIZE);
14223acd9182SFedor Uporov }
1423e09c00caSUlf Lilleengen if (waitfor == MNT_WAIT)
1424e09c00caSUlf Lilleengen error = bwrite(bp);
1425e09c00caSUlf Lilleengen else
1426e09c00caSUlf Lilleengen bawrite(bp);
1427e09c00caSUlf Lilleengen }
1428e09c00caSUlf Lilleengen
1429e09c00caSUlf Lilleengen if (!allerror && error)
1430e09c00caSUlf Lilleengen allerror = error;
1431e09c00caSUlf Lilleengen return (allerror);
1432e09c00caSUlf Lilleengen }
1433bf9a211dSPedro F. Giffuni
1434e09c00caSUlf Lilleengen /*
1435e09c00caSUlf Lilleengen * Return the root of a filesystem.
1436e09c00caSUlf Lilleengen */
1437e09c00caSUlf Lilleengen static int
ext2_root(struct mount * mp,int flags,struct vnode ** vpp)1438e09c00caSUlf Lilleengen ext2_root(struct mount *mp, int flags, struct vnode **vpp)
1439e09c00caSUlf Lilleengen {
1440e09c00caSUlf Lilleengen struct vnode *nvp;
1441e09c00caSUlf Lilleengen int error;
1442e09c00caSUlf Lilleengen
1443bbfe24fbSJohn Baldwin error = VFS_VGET(mp, EXT2_ROOTINO, LK_EXCLUSIVE, &nvp);
1444e09c00caSUlf Lilleengen if (error)
1445e09c00caSUlf Lilleengen return (error);
1446e09c00caSUlf Lilleengen *vpp = nvp;
1447e09c00caSUlf Lilleengen return (0);
1448e09c00caSUlf Lilleengen }
1449