1/*	$NetBSD: ext2fs_vfsops.c,v 1.162 2011/11/14 18:35:14 hannken Exp $	*/
2
3/*
4 * Copyright (c) 1989, 1991, 1993, 1994
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 *	@(#)ffs_vfsops.c	8.14 (Berkeley) 11/28/94
32 * Modified for ext2fs by Manuel Bouyer.
33 */
34
35/*
36 * Copyright (c) 1997 Manuel Bouyer.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 *    notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 *    notice, this list of conditions and the following disclaimer in the
45 *    documentation and/or other materials provided with the distribution.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
48 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
49 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
50 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
51 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
52 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
53 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
54 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
55 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
56 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57 *
58 *	@(#)ffs_vfsops.c	8.14 (Berkeley) 11/28/94
59 * Modified for ext2fs by Manuel Bouyer.
60 */
61
62#include <sys/cdefs.h>
63__KERNEL_RCSID(0, "$NetBSD: ext2fs_vfsops.c,v 1.162 2011/11/14 18:35:14 hannken Exp $");
64
65#if defined(_KERNEL_OPT)
66#include "opt_compat_netbsd.h"
67#endif
68
69#include <sys/param.h>
70#include <sys/systm.h>
71#include <sys/sysctl.h>
72#include <sys/namei.h>
73#include <sys/proc.h>
74#include <sys/kernel.h>
75#include <sys/vnode.h>
76#include <sys/socket.h>
77#include <sys/mount.h>
78#include <sys/buf.h>
79#include <sys/device.h>
80#include <sys/mbuf.h>
81#include <sys/file.h>
82#include <sys/disklabel.h>
83#include <sys/ioctl.h>
84#include <sys/errno.h>
85#include <sys/malloc.h>
86#include <sys/pool.h>
87#include <sys/lock.h>
88#include <sys/conf.h>
89#include <sys/kauth.h>
90#include <sys/module.h>
91
92#include <miscfs/genfs/genfs.h>
93#include <miscfs/specfs/specdev.h>
94
95#include <ufs/ufs/quota.h>
96#include <ufs/ufs/ufsmount.h>
97#include <ufs/ufs/inode.h>
98#include <ufs/ufs/dir.h>
99#include <ufs/ufs/ufs_extern.h>
100
101#include <ufs/ext2fs/ext2fs.h>
102#include <ufs/ext2fs/ext2fs_dir.h>
103#include <ufs/ext2fs/ext2fs_extern.h>
104
105MODULE(MODULE_CLASS_VFS, ext2fs, "ffs");
106
107int ext2fs_sbupdate(struct ufsmount *, int);
108static int ext2fs_checksb(struct ext2fs *, int);
109
110static struct sysctllog *ext2fs_sysctl_log;
111
112extern const struct vnodeopv_desc ext2fs_vnodeop_opv_desc;
113extern const struct vnodeopv_desc ext2fs_specop_opv_desc;
114extern const struct vnodeopv_desc ext2fs_fifoop_opv_desc;
115
116const struct vnodeopv_desc * const ext2fs_vnodeopv_descs[] = {
117	&ext2fs_vnodeop_opv_desc,
118	&ext2fs_specop_opv_desc,
119	&ext2fs_fifoop_opv_desc,
120	NULL,
121};
122
123struct vfsops ext2fs_vfsops = {
124	MOUNT_EXT2FS,
125	sizeof (struct ufs_args),
126	ext2fs_mount,
127	ufs_start,
128	ext2fs_unmount,
129	ufs_root,
130	ufs_quotactl,
131	ext2fs_statvfs,
132	ext2fs_sync,
133	ext2fs_vget,
134	ext2fs_fhtovp,
135	ext2fs_vptofh,
136	ext2fs_init,
137	ext2fs_reinit,
138	ext2fs_done,
139	ext2fs_mountroot,
140	(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
141	vfs_stdextattrctl,
142	(void *)eopnotsupp,	/* vfs_suspendctl */
143	genfs_renamelock_enter,
144	genfs_renamelock_exit,
145	(void *)eopnotsupp,
146	ext2fs_vnodeopv_descs,
147	0,
148	{ NULL, NULL },
149};
150
151static const struct genfs_ops ext2fs_genfsops = {
152	.gop_size = genfs_size,
153	.gop_alloc = ext2fs_gop_alloc,
154	.gop_write = genfs_gop_write,
155	.gop_markupdate = ufs_gop_markupdate,
156};
157
158static const struct ufs_ops ext2fs_ufsops = {
159	.uo_itimes = ext2fs_itimes,
160	.uo_update = ext2fs_update,
161	.uo_vfree = ext2fs_vfree,
162	.uo_unmark_vnode = (void (*)(vnode_t *))nullop,
163};
164
165/* Fill in the inode uid/gid from ext2 halves.  */
166void
167ext2fs_set_inode_guid(struct inode *ip)
168{
169
170	ip->i_gid = ip->i_e2fs_gid;
171	ip->i_uid = ip->i_e2fs_uid;
172	if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0) {
173		ip->i_gid |= ip->i_e2fs_gid_high << 16;
174		ip->i_uid |= ip->i_e2fs_uid_high << 16;
175	}
176}
177
178static int
179ext2fs_modcmd(modcmd_t cmd, void *arg)
180{
181	int error;
182
183	switch (cmd) {
184	case MODULE_CMD_INIT:
185		error = vfs_attach(&ext2fs_vfsops);
186		if (error != 0)
187			break;
188		sysctl_createv(&ext2fs_sysctl_log, 0, NULL, NULL,
189			       CTLFLAG_PERMANENT,
190			       CTLTYPE_NODE, "vfs", NULL,
191			       NULL, 0, NULL, 0,
192			       CTL_VFS, CTL_EOL);
193		sysctl_createv(&ext2fs_sysctl_log, 0, NULL, NULL,
194			       CTLFLAG_PERMANENT,
195			       CTLTYPE_NODE, "ext2fs",
196			       SYSCTL_DESCR("Linux EXT2FS file system"),
197			       NULL, 0, NULL, 0,
198			       CTL_VFS, 17, CTL_EOL);
199		/*
200		 * XXX the "17" above could be dynamic, thereby eliminating
201		 * one more instance of the "number to vfs" mapping problem,
202		 * but "17" is the order as taken from sys/mount.h
203		 */
204		break;
205	case MODULE_CMD_FINI:
206		error = vfs_detach(&ext2fs_vfsops);
207		if (error != 0)
208			break;
209		sysctl_teardown(&ext2fs_sysctl_log);
210		break;
211	default:
212		error = ENOTTY;
213		break;
214	}
215
216	return (error);
217}
218
219/*
220 * XXX Same structure as FFS inodes?  Should we share a common pool?
221 */
222struct pool ext2fs_inode_pool;
223struct pool ext2fs_dinode_pool;
224
225extern u_long ext2gennumber;
226
227void
228ext2fs_init(void)
229{
230
231	pool_init(&ext2fs_inode_pool, sizeof(struct inode), 0, 0, 0,
232	    "ext2fsinopl", &pool_allocator_nointr, IPL_NONE);
233	pool_init(&ext2fs_dinode_pool, sizeof(struct ext2fs_dinode), 0, 0, 0,
234	    "ext2dinopl", &pool_allocator_nointr, IPL_NONE);
235	ufs_init();
236}
237
238void
239ext2fs_reinit(void)
240{
241	ufs_reinit();
242}
243
244void
245ext2fs_done(void)
246{
247
248	ufs_done();
249	pool_destroy(&ext2fs_inode_pool);
250	pool_destroy(&ext2fs_dinode_pool);
251}
252
253/*
254 * Called by main() when ext2fs is going to be mounted as root.
255 *
256 * Name is updated by mount(8) after booting.
257 */
258#define ROOTNAME	"root_device"
259
260int
261ext2fs_mountroot(void)
262{
263	extern struct vnode *rootvp;
264	struct m_ext2fs *fs;
265	struct mount *mp;
266	struct ufsmount *ump;
267	int error;
268
269	if (device_class(root_device) != DV_DISK)
270		return (ENODEV);
271
272	if ((error = vfs_rootmountalloc(MOUNT_EXT2FS, "root_device", &mp))) {
273		vrele(rootvp);
274		return (error);
275	}
276
277	if ((error = ext2fs_mountfs(rootvp, mp)) != 0) {
278		vfs_unbusy(mp, false, NULL);
279		vfs_destroy(mp);
280		return (error);
281	}
282	mutex_enter(&mountlist_lock);
283	CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
284	mutex_exit(&mountlist_lock);
285	ump = VFSTOUFS(mp);
286	fs = ump->um_e2fs;
287	memset(fs->e2fs_fsmnt, 0, sizeof(fs->e2fs_fsmnt));
288	(void) copystr(mp->mnt_stat.f_mntonname, fs->e2fs_fsmnt,
289	    sizeof(fs->e2fs_fsmnt) - 1, 0);
290	if (fs->e2fs.e2fs_rev > E2FS_REV0) {
291		memset(fs->e2fs.e2fs_fsmnt, 0, sizeof(fs->e2fs.e2fs_fsmnt));
292		(void) copystr(mp->mnt_stat.f_mntonname, fs->e2fs.e2fs_fsmnt,
293		    sizeof(fs->e2fs.e2fs_fsmnt) - 1, 0);
294	}
295	(void)ext2fs_statvfs(mp, &mp->mnt_stat);
296	vfs_unbusy(mp, false, NULL);
297	setrootfstime((time_t)fs->e2fs.e2fs_wtime);
298	return (0);
299}
300
301/*
302 * VFS Operations.
303 *
304 * mount system call
305 */
306int
307ext2fs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
308{
309	struct lwp *l = curlwp;
310	struct vnode *devvp;
311	struct ufs_args *args = data;
312	struct ufsmount *ump = NULL;
313	struct m_ext2fs *fs;
314	size_t size;
315	int error = 0, flags, update;
316	mode_t accessmode;
317
318	if (args == NULL)
319		return EINVAL;
320	if (*data_len < sizeof *args)
321		return EINVAL;
322
323	if (mp->mnt_flag & MNT_GETARGS) {
324		ump = VFSTOUFS(mp);
325		if (ump == NULL)
326			return EIO;
327		memset(args, 0, sizeof *args);
328		args->fspec = NULL;
329		*data_len = sizeof *args;
330		return 0;
331	}
332
333	update = mp->mnt_flag & MNT_UPDATE;
334
335	/* Check arguments */
336	if (args->fspec != NULL) {
337		/*
338		 * Look up the name and verify that it's sane.
339		 */
340		error = namei_simple_user(args->fspec,
341					NSM_FOLLOW_NOEMULROOT, &devvp);
342		if (error != 0)
343			return (error);
344
345		if (!update) {
346			/*
347			 * Be sure this is a valid block device
348			 */
349			if (devvp->v_type != VBLK)
350				error = ENOTBLK;
351			else if (bdevsw_lookup(devvp->v_rdev) == NULL)
352				error = ENXIO;
353		} else {
354		        /*
355			 * Be sure we're still naming the same device
356			 * used for our initial mount
357			 */
358			ump = VFSTOUFS(mp);
359			if (devvp != ump->um_devvp) {
360				if (devvp->v_rdev != ump->um_devvp->v_rdev)
361					error = EINVAL;
362				else {
363					vrele(devvp);
364					devvp = ump->um_devvp;
365					vref(devvp);
366				}
367			}
368		}
369	} else {
370		if (!update) {
371			/* New mounts must have a filename for the device */
372			return (EINVAL);
373		} else {
374			ump = VFSTOUFS(mp);
375			devvp = ump->um_devvp;
376			vref(devvp);
377		}
378	}
379
380	/*
381	 * If mount by non-root, then verify that user has necessary
382	 * permissions on the device.
383	 *
384	 * Permission to update a mount is checked higher, so here we presume
385	 * updating the mount is okay (for example, as far as securelevel goes)
386	 * which leaves us with the normal check.
387	 */
388	if (error == 0) {
389		accessmode = VREAD;
390		if (update ?
391		    (mp->mnt_iflag & IMNT_WANTRDWR) != 0 :
392		    (mp->mnt_flag & MNT_RDONLY) == 0)
393			accessmode |= VWRITE;
394		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
395		error = genfs_can_mount(devvp, accessmode, l->l_cred);
396		VOP_UNLOCK(devvp);
397	}
398
399	if (error) {
400		vrele(devvp);
401		return (error);
402	}
403
404	if (!update) {
405		int xflags;
406
407		if (mp->mnt_flag & MNT_RDONLY)
408			xflags = FREAD;
409		else
410			xflags = FREAD|FWRITE;
411		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
412		error = VOP_OPEN(devvp, xflags, FSCRED);
413		VOP_UNLOCK(devvp);
414		if (error)
415			goto fail;
416		error = ext2fs_mountfs(devvp, mp);
417		if (error) {
418			vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
419			(void)VOP_CLOSE(devvp, xflags, NOCRED);
420			VOP_UNLOCK(devvp);
421			goto fail;
422		}
423
424		ump = VFSTOUFS(mp);
425		fs = ump->um_e2fs;
426	} else {
427		/*
428		 * Update the mount.
429		 */
430
431		/*
432		 * The initial mount got a reference on this
433		 * device, so drop the one obtained via
434		 * namei(), above.
435		 */
436		vrele(devvp);
437
438		ump = VFSTOUFS(mp);
439		fs = ump->um_e2fs;
440		if (fs->e2fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
441			/*
442			 * Changing from r/w to r/o
443			 */
444			flags = WRITECLOSE;
445			if (mp->mnt_flag & MNT_FORCE)
446				flags |= FORCECLOSE;
447			error = ext2fs_flushfiles(mp, flags);
448			if (error == 0 &&
449			    ext2fs_cgupdate(ump, MNT_WAIT) == 0 &&
450			    (fs->e2fs.e2fs_state & E2FS_ERRORS) == 0) {
451				fs->e2fs.e2fs_state = E2FS_ISCLEAN;
452				(void) ext2fs_sbupdate(ump, MNT_WAIT);
453			}
454			if (error)
455				return (error);
456			fs->e2fs_ronly = 1;
457		}
458
459		if (mp->mnt_flag & MNT_RELOAD) {
460			error = ext2fs_reload(mp, l->l_cred, l);
461			if (error)
462				return (error);
463		}
464
465		if (fs->e2fs_ronly && (mp->mnt_iflag & IMNT_WANTRDWR)) {
466			/*
467			 * Changing from read-only to read/write
468			 */
469			fs->e2fs_ronly = 0;
470			if (fs->e2fs.e2fs_state == E2FS_ISCLEAN)
471				fs->e2fs.e2fs_state = 0;
472			else
473				fs->e2fs.e2fs_state = E2FS_ERRORS;
474			fs->e2fs_fmod = 1;
475		}
476		if (args->fspec == NULL)
477			return 0;
478	}
479
480	error = set_statvfs_info(path, UIO_USERSPACE, args->fspec,
481	    UIO_USERSPACE, mp->mnt_op->vfs_name, mp, l);
482	(void) copystr(mp->mnt_stat.f_mntonname, fs->e2fs_fsmnt,
483	    sizeof(fs->e2fs_fsmnt) - 1, &size);
484	memset(fs->e2fs_fsmnt + size, 0, sizeof(fs->e2fs_fsmnt) - size);
485	if (fs->e2fs.e2fs_rev > E2FS_REV0) {
486		(void) copystr(mp->mnt_stat.f_mntonname, fs->e2fs.e2fs_fsmnt,
487		    sizeof(fs->e2fs.e2fs_fsmnt) - 1, &size);
488		memset(fs->e2fs.e2fs_fsmnt, 0,
489		    sizeof(fs->e2fs.e2fs_fsmnt) - size);
490	}
491	if (fs->e2fs_fmod != 0) {	/* XXX */
492		fs->e2fs_fmod = 0;
493		if (fs->e2fs.e2fs_state == 0)
494			fs->e2fs.e2fs_wtime = time_second;
495		else
496			printf("%s: file system not clean; please fsck(8)\n",
497				mp->mnt_stat.f_mntfromname);
498		(void) ext2fs_cgupdate(ump, MNT_WAIT);
499	}
500	return (error);
501
502fail:
503	vrele(devvp);
504	return (error);
505}
506
507/*
508 * Reload all incore data for a filesystem (used after running fsck on
509 * the root filesystem and finding things to fix). The filesystem must
510 * be mounted read-only.
511 *
512 * Things to do to update the mount:
513 *	1) invalidate all cached meta-data.
514 *	2) re-read superblock from disk.
515 *	3) re-read summary information from disk.
516 *	4) invalidate all inactive vnodes.
517 *	5) invalidate all cached file data.
518 *	6) re-read inode data for all active vnodes.
519 */
520int
521ext2fs_reload(struct mount *mp, kauth_cred_t cred, struct lwp *l)
522{
523	struct vnode *vp, *mvp, *devvp;
524	struct inode *ip;
525	struct buf *bp;
526	struct m_ext2fs *fs;
527	struct ext2fs *newfs;
528	int i, error;
529	void *cp;
530	struct ufsmount *ump;
531
532	if ((mp->mnt_flag & MNT_RDONLY) == 0)
533		return (EINVAL);
534
535	ump = VFSTOUFS(mp);
536	/*
537	 * Step 1: invalidate all cached meta-data.
538	 */
539	devvp = ump->um_devvp;
540	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
541	error = vinvalbuf(devvp, 0, cred, l, 0, 0);
542	VOP_UNLOCK(devvp);
543	if (error)
544		panic("ext2fs_reload: dirty1");
545	/*
546	 * Step 2: re-read superblock from disk.
547	 */
548	error = bread(devvp, SBLOCK, SBSIZE, NOCRED, 0, &bp);
549	if (error) {
550		brelse(bp, 0);
551		return (error);
552	}
553	newfs = (struct ext2fs *)bp->b_data;
554	error = ext2fs_checksb(newfs, (mp->mnt_flag & MNT_RDONLY) != 0);
555	if (error) {
556		brelse(bp, 0);
557		return (error);
558	}
559
560	fs = ump->um_e2fs;
561	/*
562	 * copy in new superblock, and compute in-memory values
563	 */
564	e2fs_sbload(newfs, &fs->e2fs);
565	fs->e2fs_ncg =
566	    howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock,
567	    fs->e2fs.e2fs_bpg);
568	fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + LOG_MINBSIZE - DEV_BSHIFT;
569	fs->e2fs_bsize = MINBSIZE << fs->e2fs.e2fs_log_bsize;
570	fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize;
571	fs->e2fs_qbmask = fs->e2fs_bsize - 1;
572	fs->e2fs_bmask = ~fs->e2fs_qbmask;
573	fs->e2fs_ngdb =
574	    howmany(fs->e2fs_ncg, fs->e2fs_bsize / sizeof(struct ext2_gd));
575	fs->e2fs_ipb = fs->e2fs_bsize / EXT2_DINODE_SIZE(fs);
576	fs->e2fs_itpg = fs->e2fs.e2fs_ipg / fs->e2fs_ipb;
577	brelse(bp, 0);
578
579	/*
580	 * Step 3: re-read summary information from disk.
581	 */
582
583	for (i = 0; i < fs->e2fs_ngdb; i++) {
584		error = bread(devvp ,
585		    fsbtodb(fs, fs->e2fs.e2fs_first_dblock +
586		    1 /* superblock */ + i),
587		    fs->e2fs_bsize, NOCRED, 0, &bp);
588		if (error) {
589			brelse(bp, 0);
590			return (error);
591		}
592		e2fs_cgload((struct ext2_gd *)bp->b_data,
593		    &fs->e2fs_gd[i * fs->e2fs_bsize / sizeof(struct ext2_gd)],
594		    fs->e2fs_bsize);
595		brelse(bp, 0);
596	}
597
598	/* Allocate a marker vnode. */
599	mvp = vnalloc(mp);
600	/*
601	 * NOTE: not using the TAILQ_FOREACH here since in this loop vgone()
602	 * and vclean() can be called indirectly
603	 */
604	mutex_enter(&mntvnode_lock);
605loop:
606	for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) {
607		vmark(mvp, vp);
608		if (vp->v_mount != mp || vismarker(vp))
609			continue;
610		/*
611		 * Step 4: invalidate all inactive vnodes.
612		 */
613		if (vrecycle(vp, &mntvnode_lock, l)) {
614			mutex_enter(&mntvnode_lock);
615			(void)vunmark(mvp);
616			goto loop;
617		}
618		/*
619		 * Step 5: invalidate all cached file data.
620		 */
621		mutex_enter(vp->v_interlock);
622		mutex_exit(&mntvnode_lock);
623		if (vget(vp, LK_EXCLUSIVE)) {
624			mutex_enter(&mntvnode_lock);
625			(void)vunmark(mvp);
626			goto loop;
627		}
628		if (vinvalbuf(vp, 0, cred, l, 0, 0))
629			panic("ext2fs_reload: dirty2");
630		/*
631		 * Step 6: re-read inode data for all active vnodes.
632		 */
633		ip = VTOI(vp);
634		error = bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
635		    (int)fs->e2fs_bsize, NOCRED, 0, &bp);
636		if (error) {
637			vput(vp);
638			mutex_enter(&mntvnode_lock);
639			(void)vunmark(mvp);
640			break;
641		}
642		cp = (char *)bp->b_data +
643		    (ino_to_fsbo(fs, ip->i_number) * EXT2_DINODE_SIZE(fs));
644		e2fs_iload((struct ext2fs_dinode *)cp, ip->i_din.e2fs_din);
645		ext2fs_set_inode_guid(ip);
646		brelse(bp, 0);
647		vput(vp);
648		mutex_enter(&mntvnode_lock);
649	}
650	mutex_exit(&mntvnode_lock);
651	vnfree(mvp);
652	return (error);
653}
654
655/*
656 * Common code for mount and mountroot
657 */
658int
659ext2fs_mountfs(struct vnode *devvp, struct mount *mp)
660{
661	struct lwp *l = curlwp;
662	struct ufsmount *ump;
663	struct buf *bp;
664	struct ext2fs *fs;
665	struct m_ext2fs *m_fs;
666	dev_t dev;
667	int error, i, ronly;
668	kauth_cred_t cred;
669	struct proc *p;
670
671	dev = devvp->v_rdev;
672	p = l ? l->l_proc : NULL;
673	cred = l ? l->l_cred : NOCRED;
674
675	/* Flush out any old buffers remaining from a previous use. */
676	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
677	error = vinvalbuf(devvp, V_SAVE, cred, l, 0, 0);
678	VOP_UNLOCK(devvp);
679	if (error)
680		return (error);
681
682	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
683
684	bp = NULL;
685	ump = NULL;
686
687#ifdef DEBUG_EXT2
688	printf("ext2 sb size: %zu\n", sizeof(struct ext2fs));
689#endif
690	error = bread(devvp, SBLOCK, SBSIZE, cred, 0, &bp);
691	if (error)
692		goto out;
693	fs = (struct ext2fs *)bp->b_data;
694	error = ext2fs_checksb(fs, ronly);
695	if (error)
696		goto out;
697	ump = malloc(sizeof(*ump), M_UFSMNT, M_WAITOK);
698	memset(ump, 0, sizeof(*ump));
699	ump->um_fstype = UFS1;
700	ump->um_ops = &ext2fs_ufsops;
701	ump->um_e2fs = malloc(sizeof(struct m_ext2fs), M_UFSMNT, M_WAITOK);
702	memset(ump->um_e2fs, 0, sizeof(struct m_ext2fs));
703	e2fs_sbload((struct ext2fs *)bp->b_data, &ump->um_e2fs->e2fs);
704	brelse(bp, 0);
705	bp = NULL;
706	m_fs = ump->um_e2fs;
707	m_fs->e2fs_ronly = ronly;
708
709#ifdef DEBUG_EXT2
710	printf("ext2 ino size %zu\n", EXT2_DINODE_SIZE(m_fs));
711#endif
712	if (ronly == 0) {
713		if (m_fs->e2fs.e2fs_state == E2FS_ISCLEAN)
714			m_fs->e2fs.e2fs_state = 0;
715		else
716			m_fs->e2fs.e2fs_state = E2FS_ERRORS;
717		m_fs->e2fs_fmod = 1;
718	}
719
720	/* compute dynamic sb infos */
721	m_fs->e2fs_ncg =
722	    howmany(m_fs->e2fs.e2fs_bcount - m_fs->e2fs.e2fs_first_dblock,
723	    m_fs->e2fs.e2fs_bpg);
724	m_fs->e2fs_fsbtodb = m_fs->e2fs.e2fs_log_bsize + LOG_MINBSIZE - DEV_BSHIFT;
725	m_fs->e2fs_bsize = MINBSIZE << m_fs->e2fs.e2fs_log_bsize;
726	m_fs->e2fs_bshift = LOG_MINBSIZE + m_fs->e2fs.e2fs_log_bsize;
727	m_fs->e2fs_qbmask = m_fs->e2fs_bsize - 1;
728	m_fs->e2fs_bmask = ~m_fs->e2fs_qbmask;
729	m_fs->e2fs_ngdb =
730	    howmany(m_fs->e2fs_ncg, m_fs->e2fs_bsize / sizeof(struct ext2_gd));
731	m_fs->e2fs_ipb = m_fs->e2fs_bsize / EXT2_DINODE_SIZE(m_fs);
732	m_fs->e2fs_itpg = m_fs->e2fs.e2fs_ipg / m_fs->e2fs_ipb;
733
734	m_fs->e2fs_gd = malloc(m_fs->e2fs_ngdb * m_fs->e2fs_bsize,
735	    M_UFSMNT, M_WAITOK);
736	for (i = 0; i < m_fs->e2fs_ngdb; i++) {
737		error = bread(devvp ,
738		    fsbtodb(m_fs, m_fs->e2fs.e2fs_first_dblock +
739		    1 /* superblock */ + i),
740		    m_fs->e2fs_bsize, NOCRED, 0, &bp);
741		if (error) {
742			free(m_fs->e2fs_gd, M_UFSMNT);
743			goto out;
744		}
745		e2fs_cgload((struct ext2_gd *)bp->b_data,
746		    &m_fs->e2fs_gd[
747			i * m_fs->e2fs_bsize / sizeof(struct ext2_gd)],
748		    m_fs->e2fs_bsize);
749		brelse(bp, 0);
750		bp = NULL;
751	}
752
753	mp->mnt_data = ump;
754	mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)dev;
755	mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_EXT2FS);
756	mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
757	mp->mnt_stat.f_namemax = EXT2FS_MAXNAMLEN;
758	mp->mnt_flag |= MNT_LOCAL;
759	mp->mnt_dev_bshift = DEV_BSHIFT;	/* XXX */
760	mp->mnt_fs_bshift = m_fs->e2fs_bshift;
761	mp->mnt_iflag |= IMNT_DTYPE;
762	ump->um_flags = 0;
763	ump->um_mountp = mp;
764	ump->um_dev = dev;
765	ump->um_devvp = devvp;
766	ump->um_nindir = NINDIR(m_fs);
767	ump->um_lognindir = ffs(NINDIR(m_fs)) - 1;
768	ump->um_bptrtodb = m_fs->e2fs_fsbtodb;
769	ump->um_seqinc = 1; /* no frags */
770	ump->um_maxsymlinklen = EXT2_MAXSYMLINKLEN;
771	ump->um_dirblksiz = m_fs->e2fs_bsize;
772	ump->um_maxfilesize = ((uint64_t)0x80000000 * m_fs->e2fs_bsize - 1);
773	devvp->v_specmountpoint = mp;
774	return (0);
775
776out:
777	KASSERT(bp != NULL);
778	brelse(bp, 0);
779	if (ump) {
780		free(ump->um_e2fs, M_UFSMNT);
781		free(ump, M_UFSMNT);
782		mp->mnt_data = NULL;
783	}
784	return (error);
785}
786
787/*
788 * unmount system call
789 */
790int
791ext2fs_unmount(struct mount *mp, int mntflags)
792{
793	struct ufsmount *ump;
794	struct m_ext2fs *fs;
795	int error, flags;
796
797	flags = 0;
798	if (mntflags & MNT_FORCE)
799		flags |= FORCECLOSE;
800	if ((error = ext2fs_flushfiles(mp, flags)) != 0)
801		return (error);
802	ump = VFSTOUFS(mp);
803	fs = ump->um_e2fs;
804	if (fs->e2fs_ronly == 0 &&
805		ext2fs_cgupdate(ump, MNT_WAIT) == 0 &&
806		(fs->e2fs.e2fs_state & E2FS_ERRORS) == 0) {
807		fs->e2fs.e2fs_state = E2FS_ISCLEAN;
808		(void) ext2fs_sbupdate(ump, MNT_WAIT);
809	}
810	if (ump->um_devvp->v_type != VBAD)
811		ump->um_devvp->v_specmountpoint = NULL;
812	vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
813	error = VOP_CLOSE(ump->um_devvp, fs->e2fs_ronly ? FREAD : FREAD|FWRITE,
814	    NOCRED);
815	vput(ump->um_devvp);
816	free(fs->e2fs_gd, M_UFSMNT);
817	free(fs, M_UFSMNT);
818	free(ump, M_UFSMNT);
819	mp->mnt_data = NULL;
820	mp->mnt_flag &= ~MNT_LOCAL;
821	return (error);
822}
823
824/*
825 * Flush out all the files in a filesystem.
826 */
827int
828ext2fs_flushfiles(struct mount *mp, int flags)
829{
830	extern int doforce;
831	int error;
832
833	if (!doforce)
834		flags &= ~FORCECLOSE;
835	error = vflush(mp, NULLVP, flags);
836	return (error);
837}
838
839/*
840 * Get file system statistics.
841 */
842int
843ext2fs_statvfs(struct mount *mp, struct statvfs *sbp)
844{
845	struct ufsmount *ump;
846	struct m_ext2fs *fs;
847	uint32_t overhead, overhead_per_group, ngdb;
848	int i, ngroups;
849
850	ump = VFSTOUFS(mp);
851	fs = ump->um_e2fs;
852	if (fs->e2fs.e2fs_magic != E2FS_MAGIC)
853		panic("ext2fs_statvfs");
854
855	/*
856	 * Compute the overhead (FS structures)
857	 */
858	overhead_per_group =
859	    1 /* block bitmap */ +
860	    1 /* inode bitmap */ +
861	    fs->e2fs_itpg;
862	overhead = fs->e2fs.e2fs_first_dblock +
863	    fs->e2fs_ncg * overhead_per_group;
864	if (fs->e2fs.e2fs_rev > E2FS_REV0 &&
865	    fs->e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_SPARSESUPER) {
866		for (i = 0, ngroups = 0; i < fs->e2fs_ncg; i++) {
867			if (cg_has_sb(i))
868				ngroups++;
869		}
870	} else {
871		ngroups = fs->e2fs_ncg;
872	}
873	ngdb = fs->e2fs_ngdb;
874	if (fs->e2fs.e2fs_rev > E2FS_REV0 &&
875	    fs->e2fs.e2fs_features_compat & EXT2F_COMPAT_RESIZE)
876		ngdb += fs->e2fs.e2fs_reserved_ngdb;
877	overhead += ngroups * (1 /* superblock */ + ngdb);
878
879	sbp->f_bsize = fs->e2fs_bsize;
880	sbp->f_frsize = MINBSIZE << fs->e2fs.e2fs_fsize;
881	sbp->f_iosize = fs->e2fs_bsize;
882	sbp->f_blocks = fs->e2fs.e2fs_bcount - overhead;
883	sbp->f_bfree = fs->e2fs.e2fs_fbcount;
884	sbp->f_bresvd = fs->e2fs.e2fs_rbcount;
885	if (sbp->f_bfree > sbp->f_bresvd)
886		sbp->f_bavail = sbp->f_bfree - sbp->f_bresvd;
887	else
888		sbp->f_bavail = 0;
889	sbp->f_files =  fs->e2fs.e2fs_icount;
890	sbp->f_ffree = fs->e2fs.e2fs_ficount;
891	sbp->f_favail = fs->e2fs.e2fs_ficount;
892	sbp->f_fresvd = 0;
893	copy_statvfs_info(sbp, mp);
894	return (0);
895}
896
897/*
898 * Go through the disk queues to initiate sandbagged IO;
899 * go through the inodes to write those that have been modified;
900 * initiate the writing of the super block if it has been modified.
901 *
902 * Note: we are always called with the filesystem marked `MPBUSY'.
903 */
904int
905ext2fs_sync(struct mount *mp, int waitfor, kauth_cred_t cred)
906{
907	struct vnode *vp, *mvp;
908	struct inode *ip;
909	struct ufsmount *ump = VFSTOUFS(mp);
910	struct m_ext2fs *fs;
911	int error, allerror = 0;
912
913	fs = ump->um_e2fs;
914	if (fs->e2fs_fmod != 0 && fs->e2fs_ronly != 0) {	/* XXX */
915		printf("fs = %s\n", fs->e2fs_fsmnt);
916		panic("update: rofs mod");
917	}
918
919	/* Allocate a marker vnode. */
920	mvp = vnalloc(mp);
921
922	/*
923	 * Write back each (modified) inode.
924	 */
925	mutex_enter(&mntvnode_lock);
926loop:
927	/*
928	 * NOTE: not using the TAILQ_FOREACH here since in this loop vgone()
929	 * and vclean() can be called indirectly
930	 */
931	for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) {
932		vmark(mvp, vp);
933		if (vp->v_mount != mp || vismarker(vp))
934			continue;
935		mutex_enter(vp->v_interlock);
936		ip = VTOI(vp);
937		if (ip == NULL || (vp->v_iflag & (VI_XLOCK|VI_CLEAN)) != 0 ||
938		    vp->v_type == VNON ||
939		    ((ip->i_flag &
940		      (IN_CHANGE | IN_UPDATE | IN_MODIFIED)) == 0 &&
941		     LIST_EMPTY(&vp->v_dirtyblkhd) &&
942		     UVM_OBJ_IS_CLEAN(&vp->v_uobj)))
943		{
944			mutex_exit(vp->v_interlock);
945			continue;
946		}
947		mutex_exit(&mntvnode_lock);
948		error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT);
949		if (error) {
950			mutex_enter(&mntvnode_lock);
951			if (error == ENOENT) {
952				mutex_enter(&mntvnode_lock);
953				(void)vunmark(mvp);
954				goto loop;
955			}
956			continue;
957		}
958		if (vp->v_type == VREG && waitfor == MNT_LAZY)
959			error = ext2fs_update(vp, NULL, NULL, 0);
960		else
961			error = VOP_FSYNC(vp, cred,
962			    waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0);
963		if (error)
964			allerror = error;
965		vput(vp);
966		mutex_enter(&mntvnode_lock);
967	}
968	mutex_exit(&mntvnode_lock);
969	vnfree(mvp);
970	/*
971	 * Force stale file system control information to be flushed.
972	 */
973	if (waitfor != MNT_LAZY) {
974		vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
975		if ((error = VOP_FSYNC(ump->um_devvp, cred,
976		    waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0)) != 0)
977			allerror = error;
978		VOP_UNLOCK(ump->um_devvp);
979	}
980	/*
981	 * Write back modified superblock.
982	 */
983	if (fs->e2fs_fmod != 0) {
984		fs->e2fs_fmod = 0;
985		fs->e2fs.e2fs_wtime = time_second;
986		if ((error = ext2fs_cgupdate(ump, waitfor)))
987			allerror = error;
988	}
989	return (allerror);
990}
991
992/*
993 * Look up a EXT2FS dinode number to find its incore vnode, otherwise read it
994 * in from disk.  If it is in core, wait for the lock bit to clear, then
995 * return the inode locked.  Detection and handling of mount points must be
996 * done by the calling routine.
997 */
998int
999ext2fs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
1000{
1001	struct m_ext2fs *fs;
1002	struct inode *ip;
1003	struct ufsmount *ump;
1004	struct buf *bp;
1005	struct vnode *vp;
1006	dev_t dev;
1007	int error;
1008	void *cp;
1009
1010	ump = VFSTOUFS(mp);
1011	dev = ump->um_dev;
1012retry:
1013	if ((*vpp = ufs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL)
1014		return (0);
1015
1016	/* Allocate a new vnode/inode. */
1017	error = getnewvnode(VT_EXT2FS, mp, ext2fs_vnodeop_p, NULL, &vp);
1018	if (error) {
1019		*vpp = NULL;
1020		return (error);
1021	}
1022	ip = pool_get(&ext2fs_inode_pool, PR_WAITOK);
1023
1024	mutex_enter(&ufs_hashlock);
1025	if ((*vpp = ufs_ihashget(dev, ino, 0)) != NULL) {
1026		mutex_exit(&ufs_hashlock);
1027		ungetnewvnode(vp);
1028		pool_put(&ext2fs_inode_pool, ip);
1029		goto retry;
1030	}
1031
1032	vp->v_vflag |= VV_LOCKSWORK;
1033
1034	memset(ip, 0, sizeof(struct inode));
1035	vp->v_data = ip;
1036	ip->i_vnode = vp;
1037	ip->i_ump = ump;
1038	ip->i_e2fs = fs = ump->um_e2fs;
1039	ip->i_dev = dev;
1040	ip->i_number = ino;
1041	ip->i_e2fs_last_lblk = 0;
1042	ip->i_e2fs_last_blk = 0;
1043	genfs_node_init(vp, &ext2fs_genfsops);
1044
1045	/*
1046	 * Put it onto its hash chain and lock it so that other requests for
1047	 * this inode will block if they arrive while we are sleeping waiting
1048	 * for old data structures to be purged or for the contents of the
1049	 * disk portion of this inode to be read.
1050	 */
1051
1052	ufs_ihashins(ip);
1053	mutex_exit(&ufs_hashlock);
1054
1055	/* Read in the disk contents for the inode, copy into the inode. */
1056	error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
1057	    (int)fs->e2fs_bsize, NOCRED, 0, &bp);
1058	if (error) {
1059
1060		/*
1061		 * The inode does not contain anything useful, so it would
1062		 * be misleading to leave it on its hash chain. With mode
1063		 * still zero, it will be unlinked and returned to the free
1064		 * list by vput().
1065		 */
1066
1067		vput(vp);
1068		brelse(bp, 0);
1069		*vpp = NULL;
1070		return (error);
1071	}
1072	cp = (char *)bp->b_data + (ino_to_fsbo(fs, ino) * EXT2_DINODE_SIZE(fs));
1073	ip->i_din.e2fs_din = pool_get(&ext2fs_dinode_pool, PR_WAITOK);
1074	e2fs_iload((struct ext2fs_dinode *)cp, ip->i_din.e2fs_din);
1075	ext2fs_set_inode_guid(ip);
1076	brelse(bp, 0);
1077
1078	/* If the inode was deleted, reset all fields */
1079	if (ip->i_e2fs_dtime != 0) {
1080		ip->i_e2fs_mode = ip->i_e2fs_nblock = 0;
1081		(void)ext2fs_setsize(ip, 0);
1082		memset(ip->i_e2fs_blocks, 0, sizeof(ip->i_e2fs_blocks));
1083	}
1084
1085	/*
1086	 * Initialize the vnode from the inode, check for aliases.
1087	 */
1088
1089	error = ext2fs_vinit(mp, ext2fs_specop_p, ext2fs_fifoop_p, &vp);
1090	if (error) {
1091		vput(vp);
1092		*vpp = NULL;
1093		return (error);
1094	}
1095	/*
1096	 * Finish inode initialization now that aliasing has been resolved.
1097	 */
1098
1099	ip->i_devvp = ump->um_devvp;
1100	vref(ip->i_devvp);
1101
1102	/*
1103	 * Set up a generation number for this inode if it does not
1104	 * already have one. This should only happen on old filesystems.
1105	 */
1106
1107	if (ip->i_e2fs_gen == 0) {
1108		if (++ext2gennumber < (u_long)time_second)
1109			ext2gennumber = time_second;
1110		ip->i_e2fs_gen = ext2gennumber;
1111		if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
1112			ip->i_flag |= IN_MODIFIED;
1113	}
1114	uvm_vnp_setsize(vp, ext2fs_size(ip));
1115	*vpp = vp;
1116	return (0);
1117}
1118
1119/*
1120 * File handle to vnode
1121 *
1122 * Have to be really careful about stale file handles:
1123 * - check that the inode number is valid
1124 * - call ext2fs_vget() to get the locked inode
1125 * - check for an unallocated inode (i_mode == 0)
1126 */
1127int
1128ext2fs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
1129{
1130	struct inode *ip;
1131	struct vnode *nvp;
1132	int error;
1133	struct ufid ufh;
1134	struct m_ext2fs *fs;
1135
1136	if (fhp->fid_len != sizeof(struct ufid))
1137		return EINVAL;
1138
1139	memcpy(&ufh, fhp, sizeof(struct ufid));
1140	fs = VFSTOUFS(mp)->um_e2fs;
1141	if ((ufh.ufid_ino < EXT2_FIRSTINO && ufh.ufid_ino != EXT2_ROOTINO) ||
1142		ufh.ufid_ino >= fs->e2fs_ncg * fs->e2fs.e2fs_ipg)
1143		return (ESTALE);
1144
1145	if ((error = VFS_VGET(mp, ufh.ufid_ino, &nvp)) != 0) {
1146		*vpp = NULLVP;
1147		return (error);
1148	}
1149	ip = VTOI(nvp);
1150	if (ip->i_e2fs_mode == 0 || ip->i_e2fs_dtime != 0 ||
1151		ip->i_e2fs_gen != ufh.ufid_gen) {
1152		vput(nvp);
1153		*vpp = NULLVP;
1154		return (ESTALE);
1155	}
1156	*vpp = nvp;
1157	return (0);
1158}
1159
1160/*
1161 * Vnode pointer to File handle
1162 */
1163/* ARGSUSED */
1164int
1165ext2fs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size)
1166{
1167	struct inode *ip;
1168	struct ufid ufh;
1169
1170	if (*fh_size < sizeof(struct ufid)) {
1171		*fh_size = sizeof(struct ufid);
1172		return E2BIG;
1173	}
1174	*fh_size = sizeof(struct ufid);
1175
1176	ip = VTOI(vp);
1177	memset(&ufh, 0, sizeof(ufh));
1178	ufh.ufid_len = sizeof(struct ufid);
1179	ufh.ufid_ino = ip->i_number;
1180	ufh.ufid_gen = ip->i_e2fs_gen;
1181	memcpy(fhp, &ufh, sizeof(ufh));
1182	return (0);
1183}
1184
1185/*
1186 * Write a superblock and associated information back to disk.
1187 */
1188int
1189ext2fs_sbupdate(struct ufsmount *mp, int waitfor)
1190{
1191	struct m_ext2fs *fs = mp->um_e2fs;
1192	struct buf *bp;
1193	int error = 0;
1194
1195	bp = getblk(mp->um_devvp, SBLOCK, SBSIZE, 0, 0);
1196	e2fs_sbsave(&fs->e2fs, (struct ext2fs*)bp->b_data);
1197	if (waitfor == MNT_WAIT)
1198		error = bwrite(bp);
1199	else
1200		bawrite(bp);
1201	return (error);
1202}
1203
1204int
1205ext2fs_cgupdate(struct ufsmount *mp, int waitfor)
1206{
1207	struct m_ext2fs *fs = mp->um_e2fs;
1208	struct buf *bp;
1209	int i, error = 0, allerror = 0;
1210
1211	allerror = ext2fs_sbupdate(mp, waitfor);
1212	for (i = 0; i < fs->e2fs_ngdb; i++) {
1213		bp = getblk(mp->um_devvp, fsbtodb(fs,
1214		    fs->e2fs.e2fs_first_dblock +
1215		    1 /* superblock */ + i), fs->e2fs_bsize, 0, 0);
1216		e2fs_cgsave(&fs->e2fs_gd[
1217		    i * fs->e2fs_bsize / sizeof(struct ext2_gd)],
1218		    (struct ext2_gd *)bp->b_data, fs->e2fs_bsize);
1219		if (waitfor == MNT_WAIT)
1220			error = bwrite(bp);
1221		else
1222			bawrite(bp);
1223	}
1224
1225	if (!allerror && error)
1226		allerror = error;
1227	return (allerror);
1228}
1229
1230static int
1231ext2fs_checksb(struct ext2fs *fs, int ronly)
1232{
1233
1234	if (fs2h16(fs->e2fs_magic) != E2FS_MAGIC) {
1235		return (EINVAL);		/* XXX needs translation */
1236	}
1237	if (fs2h32(fs->e2fs_rev) > E2FS_REV1) {
1238#ifdef DIAGNOSTIC
1239		printf("Ext2 fs: unsupported revision number: %x\n",
1240		    fs2h32(fs->e2fs_rev));
1241#endif
1242		return (EINVAL);		/* XXX needs translation */
1243	}
1244	if (fs2h32(fs->e2fs_log_bsize) > 2) { /* block size = 1024|2048|4096 */
1245#ifdef DIAGNOSTIC
1246		printf("Ext2 fs: bad block size: %d "
1247		    "(expected <= 2 for ext2 fs)\n",
1248		    fs2h32(fs->e2fs_log_bsize));
1249#endif
1250		return (EINVAL);	   /* XXX needs translation */
1251	}
1252	if (fs2h32(fs->e2fs_rev) > E2FS_REV0) {
1253		if (fs2h32(fs->e2fs_first_ino) != EXT2_FIRSTINO) {
1254			printf("Ext2 fs: unsupported first inode position\n");
1255			return (EINVAL);      /* XXX needs translation */
1256		}
1257		if (fs2h32(fs->e2fs_features_incompat) &
1258		    ~EXT2F_INCOMPAT_SUPP) {
1259			printf("Ext2 fs: unsupported optional feature\n");
1260			return (EINVAL);      /* XXX needs translation */
1261		}
1262		if (!ronly && fs2h32(fs->e2fs_features_rocompat) &
1263		    ~EXT2F_ROCOMPAT_SUPP) {
1264			return (EROFS);      /* XXX needs translation */
1265		}
1266	}
1267	return (0);
1268}
1269